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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 36f0738 was 25a179e, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

IPC return values are always errno constants. Adjust types to reflect that.

In principle, IPC server is not allowed to return non-errno values via
the "main" return value, because kernel interprets it (e.g. EHANGUP).
It's still possible to return arbitrary additional return values alongside EOK,
which are not interpreted in normal communication.

  • Property mode set to 100644
File size: 6.7 KB
Line 
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>
37#include <stdarg.h>
38#include <stdlib.h>
39#include <stdio.h>
40#include <async.h>
41#include <io/log.h>
42#include <ipc/logger.h>
43#include <ns.h>
44
45/** Id of the first log we create at logger. */
46static sysarg_t default_log_id;
47
48/** Log messages are printed under this name. */
49static const char *log_prog_name;
50
51/** Names of individual log levels. */
52static const char *log_level_names[] = {
53 "fatal",
54 "error",
55 "warn",
56 "note",
57 "debug",
58 "debug2",
59 NULL
60};
61
62/** IPC session with the logger service. */
63static async_sess_t *logger_session;
64
65/** Maximum length of a single log message (in bytes). */
66#define MESSAGE_BUFFER_SIZE 4096
67
68/** Send formatted message to the logger service.
69 *
70 * @param session Initialized IPC session with the logger.
71 * @param log Log to use.
72 * @param level Verbosity level of the message.
73 * @param message The actual message.
74 * @return Error code of the conversion or EOK on success.
75 */
76static int logger_message(async_sess_t *session, log_t log, log_level_t level, char *message)
77{
78 async_exch_t *exchange = async_exchange_begin(session);
79 if (exchange == NULL) {
80 return ENOMEM;
81 }
82 if (log == LOG_DEFAULT)
83 log = default_log_id;
84
85 // FIXME: remove when all USB drivers use libc logging explicitly
86 str_rtrim(message, '\n');
87
88 aid_t reg_msg = async_send_2(exchange, LOGGER_WRITER_MESSAGE,
89 log, level, NULL);
90 int rc = async_data_write_start(exchange, message, str_size(message));
91 int reg_msg_rc;
92 async_wait_for(reg_msg, &reg_msg_rc);
93
94 async_exchange_end(exchange);
95
96 /*
97 * Getting ENAK means no-one wants our message. That is not an
98 * error at all.
99 */
100 if (rc == ENAK)
101 rc = EOK;
102
103 if (rc != EOK) {
104 return rc;
105 }
106
107 return reg_msg_rc;
108}
109
110/** Get name of the log level.
111 *
112 * @param level The log level.
113 * @return String name or "unknown".
114 */
115const char *log_level_str(log_level_t level)
116{
117 if (level >= LVL_LIMIT)
118 return "unknown";
119 else
120 return log_level_names[level];
121}
122
123/** Convert log level name to the enum.
124 *
125 * @param[in] name Log level name or log level number.
126 * @param[out] level_out Where to store the result (set to NULL to ignore).
127 * @return Error code of the conversion or EOK on success.
128 */
129int log_level_from_str(const char *name, log_level_t *level_out)
130{
131 log_level_t level = LVL_FATAL;
132
133 while (log_level_names[level] != NULL) {
134 if (str_cmp(name, log_level_names[level]) == 0) {
135 if (level_out != NULL)
136 *level_out = level;
137 return EOK;
138 }
139 level++;
140 }
141
142 /* Maybe user specified number directly. */
143 char *end_ptr;
144 int level_int = strtol(name, &end_ptr, 0);
145 if ((end_ptr == name) || (str_length(end_ptr) != 0))
146 return EINVAL;
147 if (level_int < 0)
148 return ERANGE;
149 if (level_int >= (int) LVL_LIMIT)
150 return ERANGE;
151
152 if (level_out != NULL)
153 *level_out = (log_level_t) level_int;
154
155 return EOK;
156}
157
158/** Initialize the logging system.
159 *
160 * @param prog_name Program name, will be printed as part of message
161 */
162int log_init(const char *prog_name)
163{
164 log_prog_name = str_dup(prog_name);
165 if (log_prog_name == NULL)
166 return ENOMEM;
167
168 logger_session = service_connect_blocking(SERVICE_LOGGER,
169 INTERFACE_LOGGER_WRITER, 0);
170 if (logger_session == NULL) {
171 return ENOMEM;
172 }
173
174 default_log_id = log_create(prog_name, LOG_NO_PARENT);
175
176 return EOK;
177}
178
179/** Create a new (sub-) log.
180 *
181 * This function always returns a valid log_t. In case of errors,
182 * @c parent is returned and errors are silently ignored.
183 *
184 * @param name Log name under which message will be reported (appended to parents name).
185 * @param parent Parent log.
186 * @return Opaque identifier of the newly created log.
187 */
188log_t log_create(const char *name, log_t parent)
189{
190 async_exch_t *exchange = async_exchange_begin(logger_session);
191 if (exchange == NULL)
192 return parent;
193
194 if (parent == LOG_DEFAULT)
195 parent = default_log_id;
196
197 ipc_call_t answer;
198 aid_t reg_msg = async_send_1(exchange, LOGGER_WRITER_CREATE_LOG,
199 parent, &answer);
200 int rc = async_data_write_start(exchange, name, str_size(name));
201 int reg_msg_rc;
202 async_wait_for(reg_msg, &reg_msg_rc);
203
204 async_exchange_end(exchange);
205
206 if ((rc != EOK) || (reg_msg_rc != EOK))
207 return parent;
208
209 return IPC_GET_ARG1(answer);
210}
211
212/** Write an entry to the log.
213 *
214 * The message is printed only if the verbosity level is less than or
215 * equal to currently set reporting level of the log.
216 *
217 * @param ctx Log to use (use LOG_DEFAULT if you have no idea what it means).
218 * @param level Severity level of the message.
219 * @param fmt Format string in printf-like format (without trailing newline).
220 */
221void log_msg(log_t ctx, log_level_t level, const char *fmt, ...)
222{
223 va_list args;
224
225 va_start(args, fmt);
226 log_msgv(ctx, level, fmt, args);
227 va_end(args);
228}
229
230/** Write an entry to the log (va_list variant).
231 *
232 * @param ctx Log to use (use LOG_DEFAULT if you have no idea what it means).
233 * @param level Severity level of the message.
234 * @param fmt Format string in printf-like format (without trailing newline).
235 * @param args Arguments.
236 */
237void log_msgv(log_t ctx, log_level_t level, const char *fmt, va_list args)
238{
239 assert(level < LVL_LIMIT);
240
241 char *message_buffer = malloc(MESSAGE_BUFFER_SIZE);
242 if (message_buffer == NULL)
243 return;
244
245 vsnprintf(message_buffer, MESSAGE_BUFFER_SIZE, fmt, args);
246 logger_message(logger_session, ctx, level, message_buffer);
247 free(message_buffer);
248}
249
250/** @}
251 */
Note: See TracBrowser for help on using the repository browser.