Changeset 54a0070 in mainline for uspace/lib


Ignore:
Timestamp:
2012-09-10T09:54:09Z (13 years ago)
Author:
Vojtech Horky <vojtechhorky@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
40b5421
Parents:
1dbd189 (diff), 42bde6a (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge from lp:~vojtech-horky/helenos/logging

All logging is controlled by the logger service.

The API allows to create hierarchical logs and each log_msg()
must specify which log to use.

It is possible to change reported log level at runtime via
logset utility or at boot time through GRUB parameters.

Location:
uspace/lib
Files:
3 added
8 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/Makefile

    r1dbd189 r54a0070  
    101101        generic/io/printf.c \
    102102        generic/io/log.c \
     103        generic/io/logctl.c \
    103104        generic/io/klog.c \
    104105        generic/io/snprintf.c \
  • uspace/lib/c/generic/io/log.c

    r1dbd189 r54a0070  
    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
     245        vsnprintf(message_buffer, MESSAGE_BUFFER_SIZE, fmt, args);
     246        logger_message(logger_session, ctx, level, message_buffer);
    120247}
    121248
  • uspace/lib/c/include/io/log.h

    r1dbd189 r54a0070  
    3636
    3737#include <stdarg.h>
     38#include <inttypes.h>
    3839#include <io/verify.h>
    3940
     41/** Log message level. */
    4042typedef enum {
     43        /** Fatal error, program is not able to recover at all. */
    4144        LVL_FATAL,
     45        /** Serious error but the program can recover from it. */
    4246        LVL_ERROR,
     47        /** Easily recoverable problem. */
    4348        LVL_WARN,
     49        /** Information message that ought to be printed by default. */
    4450        LVL_NOTE,
     51        /** Debugging purpose message. */
    4552        LVL_DEBUG,
     53        /** More detailed debugging message. */
    4654        LVL_DEBUG2,
    4755       
     
    5058} log_level_t;
    5159
    52 extern int log_init(const char *, log_level_t);
    53 extern void log_msg(log_level_t, const char *, ...)
    54     PRINTF_ATTRIBUTE(2, 3);
    55 extern void log_msgv(log_level_t, const char *, va_list);
     60/** Log itself (logging target). */
     61typedef sysarg_t log_t;
     62/** Formatting directive for printing log_t. */
     63#define PRIlogctx PRIxn
     64
     65/** Default log (target). */
     66#define LOG_DEFAULT ((log_t) -1)
     67
     68/** Use when creating new top-level log. */
     69#define LOG_NO_PARENT ((log_t) 0)
     70
     71extern const char *log_level_str(log_level_t);
     72extern int log_level_from_str(const char *, log_level_t *);
     73
     74extern int log_init(const char *);
     75extern log_t log_create(const char *, log_t);
     76
     77extern void log_msg(log_t, log_level_t, const char *, ...)
     78    PRINTF_ATTRIBUTE(3, 4);
     79extern void log_msgv(log_t, log_level_t, const char *, va_list);
    5680
    5781#endif
  • uspace/lib/c/include/ipc/services.h

    r1dbd189 r54a0070  
    4545        SERVICE_VFS        = FOURCC('v', 'f', 's', ' '),
    4646        SERVICE_LOC        = FOURCC('l', 'o', 'c', ' '),
     47        SERVICE_LOGGER     = FOURCC('l', 'o', 'g', 'g'),
    4748        SERVICE_DEVMAN     = FOURCC('d', 'e', 'v', 'n'),
    4849        SERVICE_IRC        = FOURCC('i', 'r', 'c', ' '),
  • uspace/lib/drv/generic/log.c

    r1dbd189 r54a0070  
    3838 *
    3939 * @param drv_name Driver name, will be printed as part of message
    40  * @param level    Minimum message level to print
    4140 *
    4241 */
    43 int ddf_log_init(const char *drv_name, log_level_t level)
     42int ddf_log_init(const char *drv_name)
    4443{
    45         return log_init(drv_name, level);
     44        return log_init(drv_name);
    4645}
    4746
     
    5958       
    6059        va_start(args, fmt);
    61         log_msgv(level, fmt, args);
     60        log_msgv(LOG_DEFAULT, level, fmt, args);
    6261        va_end(args);
    6362}
  • uspace/lib/drv/include/ddf/log.h

    r1dbd189 r54a0070  
    3737#include <io/verify.h>
    3838
    39 extern int ddf_log_init(const char *, log_level_t);
     39extern int ddf_log_init(const char *);
    4040extern void ddf_msg(log_level_t, const char *, ...)
    4141    PRINTF_ATTRIBUTE(2, 3);
  • uspace/lib/usb/include/usb/debug.h

    r1dbd189 r54a0070  
    3838#include <inttypes.h>
    3939#include <usb/usb.h>
     40#include <io/log.h>
    4041#include <assert.h>
    4142
     
    4344    const uint8_t *, size_t);
    4445
    45 /** Logging level. */
    46 typedef enum {
    47         /** Fatal, unrecoverable, error.
    48          * Such error prevents the driver from working at all.
    49          */
    50         USB_LOG_LEVEL_FATAL,
     46#define USB_LOG_LEVEL_FATAL LVL_FATAL
     47#define USB_LOG_LEVEL_ERROR LVL_ERROR
     48#define USB_LOG_LEVEL_WARNING LVL_WARN
     49#define USB_LOG_LEVEL_INFO LVL_NOTE
     50#define USB_LOG_LEVEL_DEBUG LVL_DEBUG
     51#define USB_LOG_LEVEL_DEBUG2 LVL_DEBUG2
    5152
    52         /** Serious but recoverable error
    53          * Shall be used for errors fatal for single device but not for
    54          * driver itself.
    55          */
    56         USB_LOG_LEVEL_ERROR,
    57 
    58         /** Warning.
    59          * Problems from which the driver is able to recover gracefully.
    60          */
    61         USB_LOG_LEVEL_WARNING,
    62 
    63         /** Information message.
    64          * This should be the last level that is printed by default to
    65          * the screen.
    66          * Typical usage is to inform that new device was found and what
    67          * are its capabilities.
    68          * Do not use for repetitive actions (such as device polling).
    69          */
    70         USB_LOG_LEVEL_INFO,
    71 
    72         /** Debugging message. */
    73         USB_LOG_LEVEL_DEBUG,
    74 
    75         /** More detailed debugging message. */
    76         USB_LOG_LEVEL_DEBUG2,
    77 
    78         /** Terminating constant for logging levels. */
    79         USB_LOG_LEVEL_MAX
    80 } usb_log_level_t;
    81 
    82 /** Default log level. */
    83 #ifdef CONFIG_USB_VERBOSE
    84         #define USB_LOG_LEVEL_DEFAULT USB_LOG_LEVEL_DEBUG
    85 #else
    86         #define USB_LOG_LEVEL_DEFAULT USB_LOG_LEVEL_INFO
    87 #endif
    88 
    89 void usb_log_enable(usb_log_level_t, const char *);
    90 
    91 void usb_log_printf(usb_log_level_t, const char *, ...)
    92         PRINTF_ATTRIBUTE(2, 3);
     53#define usb_log_printf(level, format, ...) \
     54        log_msg(LOG_DEFAULT, level, format, ##__VA_ARGS__)
    9355
    9456/** Log fatal error. */
  • uspace/lib/usb/src/debug.c

    r1dbd189 r54a0070  
    4040#include <ddf/log.h>
    4141#include <usb/debug.h>
    42 
    43 /** Level of logging messages. */
    44 static usb_log_level_t log_level = USB_LOG_LEVEL_WARNING;
    45 
    46 /** Prefix for logging messages. */
    47 static const char *log_prefix = "usb";
    48 
    49 /** Serialization mutex for logging functions. */
    50 static FIBRIL_MUTEX_INITIALIZE(log_serializer);
    51 
    52 /** File where to store the log. */
    53 static FILE *log_stream = NULL;
    54 
    55 
    56 /** Enable logging.
    57  *
    58  * @param level Maximal enabled level (including this one).
    59  * @param message_prefix Prefix for each printed message.
    60  */
    61 void usb_log_enable(usb_log_level_t level, const char *message_prefix)
    62 {
    63         log_prefix = message_prefix;
    64         log_level = level;
    65         if (log_stream == NULL) {
    66                 char *fname;
    67                 int rc = asprintf(&fname, "/log/%s", message_prefix);
    68                 if (rc > 0) {
    69                         log_stream = fopen(fname, "w");
    70                         if (log_stream != NULL)
    71                                 setvbuf(log_stream, NULL, _IOFBF, BUFSIZ);
    72                        
    73                         free(fname);
    74                 }
    75         }
    76 }
    77 
    78 /** Get log level name prefix.
    79  *
    80  * @param level Log level.
    81  * @return String prefix for the message.
    82  */
    83 static const char *log_level_name(usb_log_level_t level)
    84 {
    85         switch (level) {
    86                 case USB_LOG_LEVEL_FATAL:
    87                         return " FATAL";
    88                 case USB_LOG_LEVEL_ERROR:
    89                         return " ERROR";
    90                 case USB_LOG_LEVEL_WARNING:
    91                         return " WARN";
    92                 case USB_LOG_LEVEL_INFO:
    93                         return " info";
    94                 default:
    95                         return "";
    96         }
    97 }
    98 
    99 /** Print logging message.
    100  *
    101  * @param level Verbosity level of the message.
    102  * @param format Formatting directive.
    103  */
    104 void usb_log_printf(usb_log_level_t level, const char *format, ...)
    105 {
    106         FILE *screen_stream = NULL;
    107         switch (level) {
    108                 case USB_LOG_LEVEL_FATAL:
    109                 case USB_LOG_LEVEL_ERROR:
    110                         screen_stream = stderr;
    111                         break;
    112                 default:
    113                         screen_stream = stdout;
    114                         break;
    115         }
    116         assert(screen_stream != NULL);
    117 
    118         va_list args;
    119 
    120         /*
    121          * Serialize access to log files.
    122          * Print to screen only messages with higher level than the one
    123          * specified during logging initialization.
    124          * Print also to file, to it print one more (lower) level as well.
    125          */
    126         fibril_mutex_lock(&log_serializer);
    127 
    128         const char *level_name = log_level_name(level);
    129 
    130         if ((log_stream != NULL) && (level <= log_level + 1)) {
    131                 va_start(args, format);
    132 
    133                 fprintf(log_stream, "[%s]%s: ", log_prefix, level_name);
    134                 vfprintf(log_stream, format, args);
    135                 fflush(log_stream);
    136 
    137                 va_end(args);
    138         }
    139 
    140         if (level <= log_level) {
    141                 va_start(args, format);
    142 
    143                 fprintf(screen_stream, "[%s]%s: ", log_prefix, level_name);
    144                 vfprintf(screen_stream, format, args);
    145                 fflush(screen_stream);
    146 
    147                 va_end(args);
    148         }
    149 
    150         fibril_mutex_unlock(&log_serializer);
    151 }
    152 
    15342
    15443#define REMAINDER_STR_FMT " (%zu)..."
Note: See TracChangeset for help on using the changeset viewer.