343 lines
11 KiB
C
343 lines
11 KiB
C
#ifndef UC_LOGGING_H_
|
|
#define UC_LOGGING_H_
|
|
#include "utils.h"
|
|
|
|
/** @file
|
|
* Application logging framework.
|
|
* 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 UCLogModule 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 UCLogModules 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 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 UCLogModule {
|
|
/** The id of the log module.
|
|
* This is the id one specifies in the various log
|
|
* functions/macros.
|
|
* Within the struct UCLogModules, this id must start
|
|
* at 0 and be incremented consecutively, being equal
|
|
* to the index within struct UCLogModules.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*/
|
|
enum UC_LOG_LEVEL log_level;
|
|
};
|
|
|
|
/* A collection of struct UCLogModule */
|
|
struct UCLogModules {
|
|
/* Pointer to the first element of the array */
|
|
struct UCLogModule *mods;
|
|
/** The number of elements in the mods array. */
|
|
int cnt;
|
|
};
|
|
|
|
struct UCLogDestination;
|
|
|
|
enum UC_LOG_ROTATE_POLICY {
|
|
/** Don't rotate. Default setting*/
|
|
UC_LOG_ROTATE_NONE,
|
|
/** Create a new log file every 'size' bytes */
|
|
UC_LOG_ROTATE_SIZE
|
|
};
|
|
|
|
/** Log rotate settings that can be set on a UC_LDEST_FILE destination
|
|
* The default is to not rotate log files.
|
|
* The current log file wil always be the specified file name,
|
|
* For UC_LOG_ROTATE_SIZE the current file will be renamed when it exceeds
|
|
* the specified max_size with a .number suffix (e.g .0 , .1 , .2 and so on),
|
|
* up to num_files are kept and a new log file is created.
|
|
*/
|
|
struct UCLogRotateSettings {
|
|
/** Policy */
|
|
enum UC_LOG_ROTATE_POLICY policy;
|
|
|
|
/** For UC_LOG_ROTATE_SIZE policy */
|
|
struct {
|
|
/** Max size of an individual log file */
|
|
size_t max_size;
|
|
/** Max number of extra log files to keep in addition
|
|
* to the current log file.
|
|
* Is forced to be at least 1*/
|
|
unsigned int num_files;
|
|
} size_settings;
|
|
};
|
|
|
|
|
|
/* 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 UCLogDestination *uc_log_new_stderr(enum UC_LOG_LEVEL 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 UCLogDestination *uc_log_new_syslog(const char *ident, int facility, enum UC_LOG_LEVEL 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 UCLogDestination *uc_log_new_file(const char *filename, enum UC_LOG_LEVEL 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 UCLogDestination *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 UCLogDestination *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 UCLogDestination *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 UCLogDestination *dest, int log_location);
|
|
|
|
/** Sets the log rotation settings.
|
|
* Does nothing if the destination is not a UC_LDEST_FILE, or the policy is invalid.
|
|
* The default is to not do log rotation
|
|
*
|
|
* @param dest log destination to change
|
|
* @param settings new policy to set
|
|
*/
|
|
void uc_log_destination_set_rotate_policy(struct UCLogDestination *dest,
|
|
const struct UCLogRotateSettings *settings);
|
|
|
|
/** 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 UCLogDestination *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 UCLogDestination *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 UCLogModule
|
|
* LEVEL is one of DEBUG, INFO, WARNING, ERROR or NONE
|
|
* 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 UCLogDestination *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 UCLogModules *user_modules);
|
|
|
|
void uc_logf(enum UC_LOG_LEVEL log_level, int module, int raw,
|
|
const char *location, const char *fmt, ...)
|
|
__attribute__((format(printf, 5, 6)));
|
|
|
|
// only compile in UC_DEBUG log calls in debug mode, but allow the user
|
|
// to override that by defining UC_DEBUG_ALWAYS
|
|
#if defined(DEBUG) || defined(UC_DEBUG_ALWAYS)
|
|
# define UC_DEBUGF(mod, fmt, ...)\
|
|
uc_logf(UC_LL_DEBUG, mod,0 , UC_SRC_LOCATION, fmt "\n", ## __VA_ARGS__)
|
|
# define UC_DEBUGFR(mod, fmt, ...)\
|
|
uc_logf(UC_LL_DEBUG, mod,1 , UC_SRC_LOCATION, fmt "\n", ## __VA_ARGS__)
|
|
#else
|
|
# define UC_DEBUGF(mod, fmt, ...) do {} while (0)
|
|
# define UC_DEBUGFR(mod, fmt, ...) do {} while (0)
|
|
#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
|
|
* fmt must be a string literal, and a newline will be added
|
|
*
|
|
* @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, UC_SRC_LOCATION, fmt "\n", ## __VA_ARGS__)
|
|
|
|
|
|
/** Raw logging ,Like UC_LOGF, but only prints the supplied
|
|
* data, not timestamp, log level, newline, etc.
|
|
*/
|
|
#define UC_LOGFR(lvl, mod, fmt, ...) \
|
|
uc_logf(lvl, mod, 1, UC_SRC_LOCATION, fmt, ## __VA_ARGS__)
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
|