#ifndef UC_LOGGING_H_ #define UC_LOGGING_H_ /** Logging functions. * All logging functions except uc_log_init are thread safe, * so logging can be performed from any thread after the logging * system have been initialized. * * The logging system has the concept of 'modules'. Modules are defined * by the application, and would match the logical parts of an application. * uc_log_init() tells the logging library about these modules, and would normally * be used like: * * enum { * POLLER, * DB, * IO *}; * * struct uc_log_module modules[] = { * { * .id = POLLER, * .short_name = "POLLER", * .long_name = "Poller thread", * .log_level = UC_LL_DEBUG, * }, * { * .id = DB, * .short_name = "DB", * .long_name = "Database handler", * .log_level == UC_LL_DEBUG * }, * { * .id = IO, * .short_name = "IO", * .long_name = "I/O worker", * .log_level == UC_LL_DEBUG * } * }; * struct uc_log_modules m = { * .mods = modules, * .cnt = ARRAY_SIZE(modules) * }; * * uc_log_init(&m); * * So the application defines 3 modules logging * will be categorized by. * Note that the values (the enum in this case) * defining all the .id memmbers of uc_log_module * must start at 0 and be concecutive. * * Now, the database code in the application can do * logging as e.g. * * UC_LOGF(UC_LL_INFO, DB, "connecting to server %s\n", ip); * * And the resulting log line will include the short_name * modules[DB].short_name * * Log levels of the messages logged are checked first * by the log_level of the uc_log_destination, and then * by the log_level of the module for that destination. * * Thus for a message to actually be logged the level * must be above the overall log level for the destination and * the log level of the module. */ #ifdef __cplusplus extern "C" { #endif /** The log levels defined by ucore logging * UC_LL_NONE must not be used in logging statements - but * can be used to suppress all logging for a destination or module*/ enum UC_LOG_LEVEL { UC_LL_DEBUG = 1, UC_LL_INFO = 3, UC_LL_WARNING = 5, UC_LL_ERROR = 7, UC_LL_NONE = 9, }; /** A destination for the logging messages*/ enum UC_LOG_DESTINATION { /** Logs using the unix syslog system */ UC_LDEST_SYSLOG, /** Prints log messages to stderr. */ UC_LDEST_STDERR, /** Prints log messages to a file */ UC_LDEST_FILE, }; /** A module of a program, that will perform logging. * This is used group logging from parts of a larger program, * and allow the log message to identigy which module the * log message originates from */ struct uc_log_module { /** The id of the log module. * This is the id one specifies in the various log * functions/macros. * Within the struct uc_log_modules, this id must start * at 0 and be incremented consecutively, being equal * to the index within struct uc_log_modules.mods */ int id; /** A short name for the module. * This will appear in log messages */ const char *short_name; /** A longer description for the log module*/ const char *long_name; /** The log level of this module. Only * log statements with a level >= the log_level * are actually logged, but the log_level of a destination * can restrict the logging further*/ int log_level; }; /* A collection of struct uc_log_module */ struct uc_log_modules { /* Pointer to the first element of the array */ struct uc_log_module *mods; /** The number of elements in the mods array. */ int cnt; }; struct uc_log_destination; /* Returns a string representation of the log level. * * @param ll The log level * @return String representation of the log level. (This will be a string literal) */ const char *uc_ll_2_str(enum UC_LOG_LEVEL l); /* creates a new uc_log_destination for printing on stderr. * * @param log_level log level of this destination. only log messages * with a log level >= the log level of the destination are actually logged. * @param log_location whether to log info about the source file and line number * in a log message. * * @return An opaque uc_log_destination that can be added as a destination to * the ucore logging system */ struct uc_log_destination *uc_log_new_stderr(int log_level, int log_location); /* creates a new uc_log_destination for logging to syslog * * @param ident The ident as used in the syslog openlog() funcion * @param facility The facility as used in the syslog openlog() function() * @param log_level log level of this destination. only log messages * with a log level >= the log level of the destination are actually logged. * @param log_location whether to log info about the source file and line number * in a log message. * @return An opaque uc_log_destination that can be added as a destination to * the ucore logging system */ struct uc_log_destination *uc_log_new_syslog(const char *ident, int facility, int log_level, int log_location); /* creates a new uc_log_destination for printing on stderr. * * @param log_level log level of this destination. only log messages * with a log level >= the log level of the destination are actually logged. * @param log_location whether to log info about the source file and line number * in a log message. * @param return An opaque uc_log_destination that can be added as a destination to * the ucore logging system */ struct uc_log_destination *uc_log_new_file(const char *filename, int log_level, int log_location); /** Add a uc_log_destination to the logging system. * * @param dest The uc_log_destination to add. */ void uc_log_add_destination(struct uc_log_destination *dest); /** Remove a log destination. * Note that this does not free the destination, it can be readded later. * For file destination, the log file is NOT closed. * * @param dest The uc_log_destination to remove. */ void uc_log_remove_destination(struct uc_log_destination *dest); /** Change the log level of a destination.. * * @param dest destination for which to set the log level * @param level The new log level */ void uc_log_destination_set_loglevel(struct uc_log_destination *dest, enum UC_LOG_LEVEL level); /** Change whether to log the location (file/line no.) of logging * output on a destination, * * @param dest log destination to change * @param log_location 1=log the locaton, 0=don't log the location */ void uc_log_destination_set_log_location(struct uc_log_destination *dest, int log_location); /** Remove and free a destination. * This frees the memory allocated to the destination. For * UC_LDEST_FILE the log file is closed. * * If the destination is not already removed, it will be removed first, * there's no need to call uc_log_remove_destination first. * The destination cannot be used again after this function has been called. * * @param dest The destination to delete. */ void uc_log_delete_destination(struct uc_log_destination *dest); /** Set the log level for a particular module on this destination * * @param dest destination to chang * @param moudle the module id to change * @param log_level new log level to set for the module */ void uc_log_destination_set_module_loglevel( struct uc_log_destination *dest, int module, enum UC_LOG_LEVEL log_level ); /** Set the log mask for the given destination. * The log_mask is a string specifying the log levels for * the modules logged by this destination. * The log_level of the destination itself takes priority * over the log_level of the modules. * The format of the log_mask string is. * * SHORT_NAME_1=LEVEL:SHORT_NAME_2=LEVEL:SHORT_NAME_N=LEVEL * * The SHORT_NAME_N is the .short_name within a struct uc_log_module * LEVEL is one of DEBUG,INFO, WARNING or ERROR * Example: * DB=DEBUG:IO=ERROR:POLLER=INFO * * Modules not mentioned in the string retain their default value. * No whitespaces must be specifed before/after the : or = character * * @param dest destination to set the log mask on * @parama log_mask the log mask as described above to set. */ void uc_log_destination_set_mask( struct uc_log_destination *dest, const char *log_mask ); /** Closes and re-opens all the UC_LDEST_FILE log destinations. * Intended for use when a log file is rotated externally. * * @param return 0 on success, non-zero if an error occured when re-opening a file. */ int uc_log_reopen_files(void); /** Init the logging system. This function must be called before performing any other * logging action. * * @param user_struct containing an array of all the modules defined by the application. */ void uc_log_init(struct uc_log_modules *user_modules); void uc_logf(int log_level, int module, int raw, const char *file, int line, const char *fmt, ...) __attribute__((format(printf, 6, 7))); #ifdef DEBUG # define UC_DEBUGF(mod, fmt, ...)\ uc_logf(UC_LL_DEBUG, mod,0 , __FILE__, __LINE__, fmt, ## __VA_ARGS__) # define UC_DEBUGFR(mod, fmt, ...)\ uc_logf(UC_LL_DEBUG, mod,1 , __FILE__, __LINE__, fmt, ## __VA_ARGS__) #else # define UC_DEBUGF(mod, fmt, ...) # define UC_DEBUGFR(mod, fmt, ...) #endif /** Main macro that should be used for logging. * * For log messages with UC_LL_DEBUG, the UC_DEBUGF() macro can be used, * UC_DEBUGF will only be compiled in if the DEBUG macro is defined * * @param lvl log level of this log message * @param mod module id of this log messagex. * @param fmt printf style format string * @param ... printf style arguments */ #define UC_LOGF(lvl, mod, fmt, ...) \ uc_logf(lvl, mod, 0, __FILE__, __LINE__, fmt, ## __VA_ARGS__) /** Raw logging ,Like UC_LOGF, but only prints the supplied * data, not timestamp, log level etc. */ #define UC_LOGFR(lvl, mod, fmt, ...) \ uc_logf(lvl, mod, 1, __FILE__, __LINE__, fmt, ## __VA_ARGS__) #ifdef __cplusplus } #endif #endif