Ignore:
File:
1 edited

Legend:

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

    rbc0ccab r9d58539  
    3838#include <stdlib.h>
    3939#include <stdio.h>
    40 #include <async.h>
     40
    4141#include <io/log.h>
    42 #include <ipc/logger.h>
    43 #include <ns.h>
    4442
    45 static sysarg_t default_log_id;
     43/** Serialization mutex for logging functions. */
     44static FIBRIL_MUTEX_INITIALIZE(log_serializer);
    4645
    47 /** Log messages are printed under this name. */
     46/** Current log level. */
     47static log_level_t log_level;
     48
     49static FILE *log_stream;
     50
    4851static const char *log_prog_name;
    4952
     53/** Prefixes for individual logging levels. */
    5054static const char *log_level_names[] = {
    51         "fatal",
    52         "error",
    53         "warn",
    54         "note",
    55         "debug",
    56         "debug2",
    57         NULL
     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"
    5861};
    59 
    60 /** IPC session with the logger service. */
    61 static async_sess_t *logger_session;
    62 
    63 /** Maximum length of a single log message (in bytes). */
    64 #define MESSAGE_BUFFER_SIZE 4096
    65 
    66 static 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 
    100 const 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 
    108 int 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 }
    13662
    13763/** Initialize the logging system.
    13864 *
    13965 * @param prog_name     Program name, will be printed as part of message
     66 * @param level         Minimum message level to print
    14067 */
    141 int log_init(const char *prog_name)
     68int log_init(const char *prog_name, log_level_t level)
    14269{
     70        assert(level < LVL_LIMIT);
     71        log_level = level;
     72
     73        log_stream = stdout;
    14374        log_prog_name = str_dup(prog_name);
    14475        if (log_prog_name == NULL)
    14576                return ENOMEM;
    14677
    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 
    15478        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  */
    166 log_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);
    18879}
    18980
     
    19586 * @param fmt           Format string (no traling newline).
    19687 */
    197 void log_msg(log_t ctx, log_level_t level, const char *fmt, ...)
     88void log_msg(log_level_t level, const char *fmt, ...)
    19889{
    19990        va_list args;
    20091
    20192        va_start(args, fmt);
    202         log_msgv(ctx, level, fmt, args);
     93        log_msgv(level, fmt, args);
    20394        va_end(args);
    20495}
     
    211102 * @param fmt           Format string (no trailing newline)
    212103 */
    213 void log_msgv(log_t ctx, log_level_t level, const char *fmt, va_list args)
     104void log_msgv(log_level_t level, const char *fmt, va_list args)
    214105{
    215106        assert(level < LVL_LIMIT);
    216107
    217         char *message_buffer = malloc(MESSAGE_BUFFER_SIZE);
    218         if (message_buffer == NULL) {
    219                 return;
     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);
    220119        }
    221 
    222         vsnprintf(message_buffer, MESSAGE_BUFFER_SIZE, fmt, args);
    223         logger_message(logger_session, ctx, level, message_buffer);
    224120}
    225121
Note: See TracChangeset for help on using the changeset viewer.