Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/io/log.c

    rebcb05a r849bebe4  
    3838#include <stdlib.h>
    3939#include <stdio.h>
    40 
     40#include <async.h>
    4141#include <io/log.h>
    42 
    43 /** Serialization mutex for logging functions. */
    44 static FIBRIL_MUTEX_INITIALIZE(log_serializer);
    45 
    46 /** Current log level. */
    47 static log_level_t log_level;
    48 
    49 static FILE *log_stream;
    50 
     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. */
    5149static const char *log_prog_name;
    5250
    53 /** Prefixes for individual logging levels. */
     51/** Names of individual log levels. */
    5452static const char *log_level_names[] = {
    55         [LVL_FATAL] = "Fatal error",
    56         [LVL_ERROR] = "Error",
    57         [LVL_WARN] = "Warning",
    58         [LVL_NOTE] = "Note",
    59         [LVL_DEBUG] = "Debug",
    60         [LVL_DEBUG2] = "Debug2"
     53        "fatal",
     54        "error",
     55        "warn",
     56        "note",
     57        "debug",
     58        "debug2",
     59        NULL
    6160};
    6261
     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        sysarg_t 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
    63158/** Initialize the logging system.
    64159 *
    65  * @param prog_name     Program name, will be printed as part of message
    66  * @param level         Minimum message level to print
    67  */
    68 int log_init(const char *prog_name, log_level_t level)
    69 {
    70         assert(level < LVL_LIMIT);
    71         log_level = level;
    72 
    73         log_stream = stdout;
     160 * @param prog_name Program name, will be printed as part of message
     161 */
     162int log_init(const char *prog_name)
     163{
    74164        log_prog_name = str_dup(prog_name);
    75165        if (log_prog_name == NULL)
    76166                return ENOMEM;
    77167
     168        logger_session = service_connect_blocking(EXCHANGE_SERIALIZE, SERVICE_LOGGER, LOGGER_INTERFACE_WRITER, 0);
     169        if (logger_session == NULL) {
     170                return ENOMEM;
     171        }
     172
     173        default_log_id = log_create(prog_name, LOG_NO_PARENT);
     174
    78175        return EOK;
    79176}
    80177
     178/** Create a new (sub-) log.
     179 *
     180 * This function always returns a valid log_t. In case of errors,
     181 * @c parent is returned and errors are silently ignored.
     182 *
     183 * @param name Log name under which message will be reported (appended to parents name).
     184 * @param parent Parent log.
     185 * @return Opaque identifier of the newly created log.
     186 */
     187log_t log_create(const char *name, log_t parent)
     188{
     189        async_exch_t *exchange = async_exchange_begin(logger_session);
     190        if (exchange == NULL)
     191                return parent;
     192
     193        if (parent == LOG_DEFAULT)
     194                parent = default_log_id;
     195
     196        ipc_call_t answer;
     197        aid_t reg_msg = async_send_1(exchange, LOGGER_WRITER_CREATE_LOG,
     198            parent, &answer);
     199        int rc = async_data_write_start(exchange, name, str_size(name));
     200        sysarg_t reg_msg_rc;
     201        async_wait_for(reg_msg, &reg_msg_rc);
     202
     203        async_exchange_end(exchange);
     204
     205        if ((rc != EOK) || (reg_msg_rc != EOK))
     206                return parent;
     207
     208        return IPC_GET_ARG1(answer);
     209}
     210
    81211/** Write an entry to the log.
    82212 *
    83  * @param level         Message verbosity level. Message is only printed
    84  *                      if verbosity is less than or equal to current
    85  *                      reporting level.
    86  * @param fmt           Format string (no traling newline).
    87  */
    88 void log_msg(log_level_t level, const char *fmt, ...)
     213 * The message is printed only if the verbosity level is less than or
     214 * equal to currently set reporting level of the log.
     215 *
     216 * @param ctx Log to use (use LOG_DEFAULT if you have no idea what it means).
     217 * @param level Severity level of the message.
     218 * @param fmt Format string in printf-like format (without trailing newline).
     219 */
     220void log_msg(log_t ctx, log_level_t level, const char *fmt, ...)
    89221{
    90222        va_list args;
    91223
    92224        va_start(args, fmt);
    93         log_msgv(level, fmt, args);
     225        log_msgv(ctx, level, fmt, args);
    94226        va_end(args);
    95227}
     
    97229/** Write an entry to the log (va_list variant).
    98230 *
    99  * @param level         Message verbosity level. Message is only printed
    100  *                      if verbosity is less than or equal to current
    101  *                      reporting level.
    102  * @param fmt           Format string (no trailing newline)
    103  */
    104 void log_msgv(log_level_t level, const char *fmt, va_list args)
     231 * @param ctx Log to use (use LOG_DEFAULT if you have no idea what it means).
     232 * @param level Severity level of the message.
     233 * @param fmt Format string in printf-like format (without trailing newline).
     234 * @param args Arguments.
     235 */
     236void log_msgv(log_t ctx, log_level_t level, const char *fmt, va_list args)
    105237{
    106238        assert(level < LVL_LIMIT);
    107239
    108         /* Higher number means higher verbosity. */
    109         if (level <= log_level) {
    110                 fibril_mutex_lock(&log_serializer);
    111 
    112                 fprintf(log_stream, "%s: %s: ", log_prog_name,
    113                     log_level_names[level]);
    114                 vfprintf(log_stream, fmt, args);
    115                 fputc('\n', log_stream);
    116                 fflush(log_stream);
    117 
    118                 fibril_mutex_unlock(&log_serializer);
    119         }
     240        char *message_buffer = malloc(MESSAGE_BUFFER_SIZE);
     241        if (message_buffer == NULL)
     242                return;
     243
     244        vsnprintf(message_buffer, MESSAGE_BUFFER_SIZE, fmt, args);
     245        logger_message(logger_session, ctx, level, message_buffer);
     246        free(message_buffer);
    120247}
    121248
Note: See TracChangeset for help on using the changeset viewer.