source: mainline/uspace/lib/c/generic/io/log.c@ f72ae3b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f72ae3b was f72ae3b, checked in by Vojtech Horky <vojtechhorky@…>, 13 years ago

log_create returns parent in case of errors

  • Property mode set to 100644
File size: 7.2 KB
RevLine 
[9b415c9]1/*
2 * Copyright (c) 2011 Vojtech Horky
3 * Copyright (c) 2011 Jiri Svoboda
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup libc
31 * @{
32 */
33
34#include <assert.h>
35#include <errno.h>
36#include <fibril_synch.h>
[fc51296]37#include <stdarg.h>
[9b415c9]38#include <stdlib.h>
39#include <stdio.h>
[1f2dd20]40#include <async.h>
[9b415c9]41#include <io/log.h>
[1f2dd20]42#include <ipc/logger.h>
43#include <ns.h>
[9b415c9]44
[2bf781a]45typedef struct {
46 char *name;
47 sysarg_t top_log_id;
48 sysarg_t log_id;
49} log_info_t;
50
51static log_info_t default_log = {
52 .name = NULL,
53 .top_log_id = 0,
54 .log_id = 0
55};
56
57static sysarg_t default_top_log_id;
58
[1f2dd20]59/** Log messages are printed under this name. */
60static const char *log_prog_name;
[9b415c9]61
[1c67b41]62static const char *log_level_names[] = {
63 "fatal",
64 "error",
65 "warn",
66 "note",
67 "debug",
[eab3d04]68 "debug2",
69 NULL
[1c67b41]70};
71
[1f2dd20]72/** IPC session with the logger service. */
73static async_sess_t *logger_session;
[9b415c9]74
[1f2dd20]75/** Maximum length of a single log message (in bytes). */
76#define MESSAGE_BUFFER_SIZE 4096
[9b415c9]77
[cba45af]78
[1f2dd20]79static int logger_register(async_sess_t *session, const char *prog_name)
80{
81 async_exch_t *exchange = async_exchange_begin(session);
82 if (exchange == NULL) {
83 return ENOMEM;
84 }
85
[cba45af]86 ipc_call_t answer;
87 aid_t reg_msg = async_send_0(exchange, LOGGER_WRITER_CREATE_TOPLEVEL_LOG, &answer);
[1f2dd20]88 int rc = async_data_write_start(exchange, prog_name, str_size(prog_name));
89 sysarg_t reg_msg_rc;
90 async_wait_for(reg_msg, &reg_msg_rc);
91
92 async_exchange_end(exchange);
93
94 if (rc != EOK) {
95 return rc;
96 }
97
[cba45af]98 if (reg_msg_rc != EOK)
99 return reg_msg_rc;
100
[2bf781a]101 default_top_log_id = IPC_GET_ARG1(answer);
102 default_log.top_log_id = default_top_log_id;
[cba45af]103
104 return EOK;
[1f2dd20]105}
106
[d6ddeb7]107static int logger_message(async_sess_t *session, log_t ctx, log_level_t level, const char *message)
[1f2dd20]108{
109 async_exch_t *exchange = async_exchange_begin(session);
110 if (exchange == NULL) {
111 return ENOMEM;
112 }
[2bf781a]113 log_info_t *log_info = ctx != 0 ? (log_info_t *) ctx : &default_log;
[1f2dd20]114
[cba45af]115 aid_t reg_msg = async_send_3(exchange, LOGGER_WRITER_MESSAGE,
[2bf781a]116 log_info->top_log_id, log_info->log_id, level, NULL);
[1f2dd20]117 int rc = async_data_write_start(exchange, message, str_size(message));
118 sysarg_t reg_msg_rc;
119 async_wait_for(reg_msg, &reg_msg_rc);
120
121 async_exchange_end(exchange);
[9b415c9]122
[f6bc83a]123 /*
124 * Getting ENAK means no-one wants our message. That is not an
125 * error at all.
126 */
127 if (rc == ENAK)
128 rc = EOK;
129
[1f2dd20]130 if (rc != EOK) {
131 return rc;
132 }
133
134 return reg_msg_rc;
135}
[9b415c9]136
[1c67b41]137const char *log_level_str(log_level_t level)
138{
139 if (level >= LVL_LIMIT)
140 return "unknown";
141 else
142 return log_level_names[level];
143}
144
[eab3d04]145int log_level_from_str(const char *name, log_level_t *level_out)
146{
147 log_level_t level = LVL_FATAL;
148
149 while (log_level_names[level] != NULL) {
150 if (str_cmp(name, log_level_names[level]) == 0) {
151 if (level_out != NULL)
152 *level_out = level;
153 return EOK;
154 }
155 level++;
156 }
157
158 /* Maybe user specified number directly. */
159 char *end_ptr;
160 int level_int = strtol(name, &end_ptr, 0);
161 if ((end_ptr == name) || (str_length(end_ptr) != 0))
162 return EINVAL;
163 if (level_int < 0)
164 return ERANGE;
165 if (level_int >= (int) LVL_LIMIT)
166 return ERANGE;
167
168 if (level_out != NULL)
169 *level_out = (log_level_t) level_int;
170
171 return EOK;
172}
173
[9b415c9]174/** Initialize the logging system.
175 *
176 * @param prog_name Program name, will be printed as part of message
177 * @param level Minimum message level to print
178 */
179int log_init(const char *prog_name, log_level_t level)
180{
181 assert(level < LVL_LIMIT);
182
183 log_prog_name = str_dup(prog_name);
184 if (log_prog_name == NULL)
185 return ENOMEM;
186
[1f2dd20]187 logger_session = service_connect_blocking(EXCHANGE_SERIALIZE, SERVICE_LOGGER, LOGGER_INTERFACE_SINK, 0);
188 if (logger_session == NULL) {
189 return ENOMEM;
190 }
191
192 int rc = logger_register(logger_session, log_prog_name);
193
194 return rc;
[9b415c9]195}
196
[f72ae3b]197/** Create a new (sub-) log.
[793cce15]198 *
[f72ae3b]199 * This function always returns a valid log_t. In case of errors,
200 * @c parent is returned and errors are silently ignored.
201 *
202 * @param name Log name under which message will be reported (appended to parents name).
203 * @param parent Parent log.
204 * @return Opaque identifier of the newly created log.
[793cce15]205 */
[2bf781a]206log_t log_create(const char *name, log_t parent)
[793cce15]207{
[2bf781a]208 log_info_t *info = malloc(sizeof(log_info_t));
209 if (info == NULL)
210 return LOG_DEFAULT;
[f72ae3b]211 info->name = NULL;
[2bf781a]212
213 if (parent == LOG_DEFAULT) {
214 info->name = str_dup(name);
[f72ae3b]215 if (info->name == NULL)
216 goto error;
[2bf781a]217 info->top_log_id = default_top_log_id;
218 } else {
219 log_info_t *parent_info = (log_info_t *) parent;
220 int rc = asprintf(&info->name, "%s/%s",
221 parent_info->name, name);
[f72ae3b]222 if (rc < 0)
223 goto error;
[2bf781a]224 info->top_log_id = parent_info->top_log_id;
225 }
226
[793cce15]227 async_exch_t *exchange = async_exchange_begin(logger_session);
228 if (exchange == NULL)
[2bf781a]229 goto error;
[793cce15]230
231 ipc_call_t answer;
[2bf781a]232 aid_t reg_msg = async_send_1(exchange, LOGGER_WRITER_CREATE_SUB_LOG,
233 info->top_log_id, &answer);
234 int rc = async_data_write_start(exchange, info->name, str_size(info->name));
[793cce15]235 sysarg_t reg_msg_rc;
236 async_wait_for(reg_msg, &reg_msg_rc);
237
238 async_exchange_end(exchange);
239
240 if ((rc != EOK) || (reg_msg_rc != EOK))
[2bf781a]241 goto error;
242
243 info->log_id = IPC_GET_ARG1(answer);
244 return (sysarg_t) info;
[793cce15]245
[2bf781a]246error:
247 free(info->name);
248 free(info);
[f72ae3b]249 return parent;
[793cce15]250}
251
[9b415c9]252/** Write an entry to the log.
253 *
254 * @param level Message verbosity level. Message is only printed
255 * if verbosity is less than or equal to current
256 * reporting level.
[ebcb05a]257 * @param fmt Format string (no traling newline).
[9b415c9]258 */
[d6ddeb7]259void log_log_msg(log_t ctx, log_level_t level, const char *fmt, ...)
[9b415c9]260{
261 va_list args;
262
[fc51296]263 va_start(args, fmt);
[d6ddeb7]264 log_log_msgv(ctx, level, fmt, args);
[fc51296]265 va_end(args);
266}
267
268/** Write an entry to the log (va_list variant).
269 *
270 * @param level Message verbosity level. Message is only printed
271 * if verbosity is less than or equal to current
272 * reporting level.
[ebcb05a]273 * @param fmt Format string (no trailing newline)
[fc51296]274 */
[d6ddeb7]275void log_log_msgv(log_t ctx, log_level_t level, const char *fmt, va_list args)
[fc51296]276{
[9b415c9]277 assert(level < LVL_LIMIT);
278
[1f2dd20]279 char *message_buffer = malloc(MESSAGE_BUFFER_SIZE);
280 if (message_buffer == NULL) {
281 return;
[9b415c9]282 }
[1f2dd20]283
284 vsnprintf(message_buffer, MESSAGE_BUFFER_SIZE, fmt, args);
[793cce15]285 logger_message(logger_session, ctx, level, message_buffer);
[9b415c9]286}
287
288/** @}
289 */
Note: See TracBrowser for help on using the repository browser.