Ignore:
File:
1 edited

Legend:

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

    r849bebe4 rebcb05a  
    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 /** Id of the first log we create at logger. */
    46 static sysarg_t default_log_id;
     43/** Serialization mutex for logging functions. */
     44static FIBRIL_MUTEX_INITIALIZE(log_serializer);
    4745
    48 /** Log messages are printed under this name. */
     46/** Current log level. */
     47static log_level_t log_level;
     48
     49static FILE *log_stream;
     50
    4951static const char *log_prog_name;
    5052
    51 /** Names of individual log levels. */
     53/** Prefixes for individual logging levels. */
    5254static const char *log_level_names[] = {
    53         "fatal",
    54         "error",
    55         "warn",
    56         "note",
    57         "debug",
    58         "debug2",
    59         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"
    6061};
    6162
    62 /** IPC session with the logger service. */
    63 static async_sess_t *logger_session;
     63/** Initialize the logging system.
     64 *
     65 * @param prog_name     Program name, will be printed as part of message
     66 * @param level         Minimum message level to print
     67 */
     68int log_init(const char *prog_name, log_level_t level)
     69{
     70        assert(level < LVL_LIMIT);
     71        log_level = level;
    6472
    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  */
    76 static 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) {
     73        log_stream = stdout;
     74        log_prog_name = str_dup(prog_name);
     75        if (log_prog_name == NULL)
    8076                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  */
    115 const 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  */
    129 int 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;
    15477
    15578        return EOK;
    15679}
    15780
    158 /** Initialize the logging system.
    159  *
    160  * @param prog_name Program name, will be printed as part of message
    161  */
    162 int 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(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 
    175         return EOK;
    176 }
    177 
    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  */
    187 log_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 
    21181/** Write an entry to the log.
    21282 *
    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).
     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).
    21987 */
    220 void log_msg(log_t ctx, log_level_t level, const char *fmt, ...)
     88void log_msg(log_level_t level, const char *fmt, ...)
    22189{
    22290        va_list args;
    22391
    22492        va_start(args, fmt);
    225         log_msgv(ctx, level, fmt, args);
     93        log_msgv(level, fmt, args);
    22694        va_end(args);
    22795}
     
    22997/** Write an entry to the log (va_list variant).
    23098 *
    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.
     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)
    235103 */
    236 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)
    237105{
    238106        assert(level < LVL_LIMIT);
    239107
    240         char *message_buffer = malloc(MESSAGE_BUFFER_SIZE);
    241         if (message_buffer == NULL)
    242                 return;
     108        /* Higher number means higher verbosity. */
     109        if (level <= log_level) {
     110                fibril_mutex_lock(&log_serializer);
    243111
    244         vsnprintf(message_buffer, MESSAGE_BUFFER_SIZE, fmt, args);
    245         logger_message(logger_session, ctx, level, message_buffer);
    246         free(message_buffer);
     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        }
    247120}
    248121
Note: See TracChangeset for help on using the changeset viewer.