Ignore:
File:
1 edited

Legend:

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

    r9d58539 rbc0ccab  
    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
     45static sysarg_t default_log_id;
     46
     47/** Log messages are printed under this name. */
    5148static const char *log_prog_name;
    5249
    53 /** Prefixes for individual logging levels. */
    5450static 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"
     51        "fatal",
     52        "error",
     53        "warn",
     54        "note",
     55        "debug",
     56        "debug2",
     57        NULL
    6158};
    6259
     60/** IPC session with the logger service. */
     61static async_sess_t *logger_session;
     62
     63/** Maximum length of a single log message (in bytes). */
     64#define MESSAGE_BUFFER_SIZE 4096
     65
     66static int logger_message(async_sess_t *session, log_t log, log_level_t level, char *message)
     67{
     68        async_exch_t *exchange = async_exchange_begin(session);
     69        if (exchange == NULL) {
     70                return ENOMEM;
     71        }
     72        if (log == LOG_DEFAULT)
     73                log = default_log_id;
     74
     75        // FIXME: remove when all USB drivers use libc logging explicitly
     76        str_rtrim(message, '\n');
     77
     78        aid_t reg_msg = async_send_2(exchange, LOGGER_WRITER_MESSAGE,
     79            log, level, NULL);
     80        int rc = async_data_write_start(exchange, message, str_size(message));
     81        sysarg_t reg_msg_rc;
     82        async_wait_for(reg_msg, &reg_msg_rc);
     83
     84        async_exchange_end(exchange);
     85
     86        /*
     87         * Getting ENAK means no-one wants our message. That is not an
     88         * error at all.
     89         */
     90        if (rc == ENAK)
     91                rc = EOK;
     92
     93        if (rc != EOK) {
     94                return rc;
     95        }
     96
     97        return reg_msg_rc;
     98}
     99
     100const char *log_level_str(log_level_t level)
     101{
     102        if (level >= LVL_LIMIT)
     103                return "unknown";
     104        else
     105                return log_level_names[level];
     106}
     107
     108int log_level_from_str(const char *name, log_level_t *level_out)
     109{
     110        log_level_t level = LVL_FATAL;
     111
     112        while (log_level_names[level] != NULL) {
     113                if (str_cmp(name, log_level_names[level]) == 0) {
     114                        if (level_out != NULL)
     115                                *level_out = level;
     116                        return EOK;
     117                }
     118                level++;
     119        }
     120
     121        /* Maybe user specified number directly. */
     122        char *end_ptr;
     123        int level_int = strtol(name, &end_ptr, 0);
     124        if ((end_ptr == name) || (str_length(end_ptr) != 0))
     125                return EINVAL;
     126        if (level_int < 0)
     127                return ERANGE;
     128        if (level_int >= (int) LVL_LIMIT)
     129                return ERANGE;
     130
     131        if (level_out != NULL)
     132                *level_out = (log_level_t) level_int;
     133
     134        return EOK;
     135}
     136
    63137/** Initialize the logging system.
    64138 *
    65139 * @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;
     140 */
     141int log_init(const char *prog_name)
     142{
    74143        log_prog_name = str_dup(prog_name);
    75144        if (log_prog_name == NULL)
    76145                return ENOMEM;
    77146
     147        logger_session = service_connect_blocking(EXCHANGE_SERIALIZE, SERVICE_LOGGER, LOGGER_INTERFACE_WRITER, 0);
     148        if (logger_session == NULL) {
     149                return ENOMEM;
     150        }
     151
     152        default_log_id = log_create(prog_name, LOG_NO_PARENT);
     153
    78154        return EOK;
     155}
     156
     157/** Create a new (sub-) log.
     158 *
     159 * This function always returns a valid log_t. In case of errors,
     160 * @c parent is returned and errors are silently ignored.
     161 *
     162 * @param name Log name under which message will be reported (appended to parents name).
     163 * @param parent Parent log.
     164 * @return Opaque identifier of the newly created log.
     165 */
     166log_t log_create(const char *name, log_t parent)
     167{
     168        async_exch_t *exchange = async_exchange_begin(logger_session);
     169        if (exchange == NULL)
     170                return parent;
     171
     172        if (parent == LOG_DEFAULT)
     173                parent = default_log_id;
     174
     175        ipc_call_t answer;
     176        aid_t reg_msg = async_send_1(exchange, LOGGER_WRITER_CREATE_LOG,
     177            parent, &answer);
     178        int rc = async_data_write_start(exchange, name, str_size(name));
     179        sysarg_t reg_msg_rc;
     180        async_wait_for(reg_msg, &reg_msg_rc);
     181
     182        async_exchange_end(exchange);
     183
     184        if ((rc != EOK) || (reg_msg_rc != EOK))
     185                return parent;
     186
     187        return IPC_GET_ARG1(answer);
    79188}
    80189
     
    86195 * @param fmt           Format string (no traling newline).
    87196 */
    88 void log_msg(log_level_t level, const char *fmt, ...)
     197void log_msg(log_t ctx, log_level_t level, const char *fmt, ...)
    89198{
    90199        va_list args;
    91200
    92201        va_start(args, fmt);
    93         log_msgv(level, fmt, args);
     202        log_msgv(ctx, level, fmt, args);
    94203        va_end(args);
    95204}
     
    102211 * @param fmt           Format string (no trailing newline)
    103212 */
    104 void log_msgv(log_level_t level, const char *fmt, va_list args)
     213void log_msgv(log_t ctx, log_level_t level, const char *fmt, va_list args)
    105214{
    106215        assert(level < LVL_LIMIT);
    107216
    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         }
     217        char *message_buffer = malloc(MESSAGE_BUFFER_SIZE);
     218        if (message_buffer == NULL) {
     219                return;
     220        }
     221
     222        vsnprintf(message_buffer, MESSAGE_BUFFER_SIZE, fmt, args);
     223        logger_message(logger_session, ctx, level, message_buffer);
    120224}
    121225
Note: See TracChangeset for help on using the changeset viewer.