123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- #include "monolog.h"
- #include "dynar.h"
- #include <string.h>
- struct Monologger {
- struct MonologLoggerInterface logger;
- void * data;
- int index;
- };
- struct Monolevel {
- char * name;
- int enabled;
- };
- struct Monolog {
- Dynar * loggers;
- Dynar * levels;
- int last_logger;
- };
- static struct Monolog monolog_struct = { NULL, NULL, 0 };
- static struct Monolog * monolog = &monolog_struct;
- void monolog_done() {
- int index;
- if (monolog->loggers) {
- /* clean up all loggers */
- for (index = 0; index < dynar_size(monolog->loggers); index ++) {
- monolog_remove_logger(index);
- }
-
- dynar_free(monolog->loggers);
- monolog->loggers = NULL;
- }
-
- if (monolog->levels) {
- dynar_free(monolog->levels);
- monolog->levels = NULL;
- }
- monolog->last_logger = 0;
- }
- /* Compares loggers with each other for sorting. This is qsort compatible. */
- static int monolog_compare_loggers(void * p1, void * p2) {
- struct Monologger * me = *((struct Monologger **) p1);
- struct Monologger * you = *((struct Monologger **) p2);
- if (!me) return -1;
- if (!you) return 1;
- if (!me->logger.log) return -1;
- if (!you->logger.log) return 1;
- /* Compare index if no nulls. */
- if (me->index < you->index) return -1;
- if (me->index > you->index) return 1;
- return 0;
- }
- /* Compares loglevels with each other for sorting. This is qsort compatible. */
- static int monolog_compare_loglevels(const void * p1, const void * p2) {
- const struct Monolevel * me = p1;
- const struct Monolevel * you = p2;
- if(!me) return -1;
- if(!you) return 1;
- if(!me->name) return -1;
- if(!you->name) return 1;
- /* Compare name if no nulls. */
- return strcmp(me->name, you->name);
- return 0;
- }
- #define MONOLOG_START_LEVELS 32
- #define MONOLOG_START_LOGGERS 32
- static int monolog_get_loggers_max() {
- return dynar_size(monolog->loggers);
- }
- static struct Monologger * monolog_get_logger(int index) {
- return dynar_getdata(monolog->loggers, index);
- }
- static int monolog_get_unused_logger() {
- int index;
- for (index = 0 ; index < dynar_size(monolog->loggers); index++) {
- struct Monologger * logger = monolog_get_logger(index);
- if (!logger->logger.log) {
- return index;
- }
- }
- return -1;
- }
- static struct Monologger *
- monolog_set_logger(int index, void *data, struct MonologLoggerInterface * ifa) {
- struct Monologger * logger = monolog_get_logger(index);
- if(!logger) return NULL;
- logger->index = index;
- logger->data = data;
- logger->logger = (*ifa);
- return logger;
- }
- static struct Monolevel * monolog_get_level(int index) {
- return dynar_getdata(monolog->levels, index);
- }
- static int monolog_get_unused_level() {
- int index;
- for (index = 0 ; index < dynar_size(monolog->levels); index++) {
- struct Monolevel * level = monolog_get_level(index);
- if (!level->name) {
- return index;
- }
- }
- return -1;
- }
- static struct Monolevel *
- monolog_set_level (int index, char * name, int enabled) {
- struct Monolevel * level = monolog_get_level(index);
- if (!level) return NULL;
- level->name = name;
- level->enabled = enabled;
- return level;
- }
- int monolog_init() {
- int index;
- monolog->loggers = dynar_new(MONOLOG_START_LEVELS, sizeof(struct Monologger));
- if(!monolog->loggers) {
- return FALSE;
- }
-
- monolog->levels = dynar_new(MONOLOG_START_LOGGERS, sizeof(struct Monolevel));
- if(!monolog->levels) {
- monolog_done();
- return FALSE;
- }
- for (index = 0; index < dynar_amount(monolog->loggers) ; index++ ) {
- struct MonologLoggerInterface ifa = { NULL, NULL };
- monolog_set_logger(index, NULL, &ifa);
- }
-
- for (index = 0; index < dynar_amount(monolog->levels) ; index++ ) {
- monolog_set_level(index, NULL, FALSE);
- }
-
- return TRUE;
- }
- /** Adds a loger. Returns negative or error zero or positive (the index of the logger)
- * on success. */
- int monolog_add_logger(void * data, struct MonologLoggerInterface * logger) {
- int logindex;
- if (monolog->last_logger >= dynar_amount(monolog->loggers)) {
- if (!dynar_grow(monolog->loggers, MONOLOG_START_LOGGERS)) {
- return -1;
- }
- }
- logindex = monolog_get_unused_logger();
- if (logindex < 0) {
- return -2;
- }
- monolog_set_logger(logindex, data, logger);
- return logindex;
- }
- int monolog_remove_logger(int index) {
- struct MonologLoggerInterface ifa = { NULL, NULL };
- struct Monologger * logger = monolog_get_logger(index);
- /* Call logger's destructor if needed. */
- if (logger->logger.free) {
- logger->logger.free(logger->data);
- }
- monolog_set_logger(index, NULL, &ifa);
- return index;
- }
- struct Monolevel * monolog_find_level_by_name(char * name) {
- struct Monolevel key;
- key.name = name;
- key.enabled = 123;
- return dynar_bsearch(monolog->levels, &key, monolog_compare_loglevels);
- }
- int monolog_setup_level(char * name, int enabled) {
- struct Monolevel * level;
- int levelindex;
- level = monolog_find_level_by_name(name);
- if (!level) {
- levelindex = monolog_get_unused_level();
- if (levelindex < 0) return -1;
- level = monolog_get_level(levelindex);
- }
- level->name = name;
- level->enabled = enabled;
- dynar_qsort(monolog->levels, monolog_compare_loglevels);
- return 1;
- }
- int monolog_enable_level(char * name) {
- return monolog_setup_level(name, TRUE);
- }
- int monolog_disable_level(char * name) {
- return monolog_setup_level(name, FALSE);
- }
- int monolog_log_va(char * file, int line, char * name, char * format, va_list args) {
- int index;
- va_list args_copy;
- struct Monolevel * level = monolog_find_level_by_name(name);
- if ((!level) || (!level->enabled)) {
- return -1;
- }
-
- for (index = 0; index < dynar_size(monolog->loggers); index++) {
- struct Monologger * logger = monolog_get_logger(index);
- if (logger && logger->logger.log) {
- va_copy(args_copy, args);
- logger->logger.log(file, line, level->name, logger->data, format, args_copy);
- va_end(args_copy);
- }
- }
- return 0;
- }
- int monolog_log(char * file, int line, char * level, char * format, ...) {
- int result;
- va_list args;
- va_start(args, format);
- result = monolog_log_va(file, line, level, format, args);
- va_end(args);
- return result;
- }
- /* Log function for logger that logs to stdout. */
- int monolog_stdout_logger
- (char * file, int line, char * level, void * data, char * format, va_list args)
- {
- (void) data;
- printf("%s: %s: %d: ", level, file, line);
- return vprintf(format, args);
- }
- /* Log function for logger that logs to stderr. */
- int monolog_stderr_logger
- (char * file, int line, char * level, void * data, char * format, va_list args)
- {
- (void) data;
- fprintf(stderr, "%s: %s: %d: ", level, file, line);
- return vfprintf(stderr, format, args);
- }
- /** Log function for logger that logs to a FILE. */
- int monolog_file_logger
- (char * file, int line, char * level, void * data, char * format, va_list args) {
- FILE * fout = data;
- int res;
- if (fout) {
- fprintf(fout, "%s: %s: %d: ", level, file, line);
- res = vfprintf(fout, format, args);
- fflush(fout);
- return res;
- }
- return -1;
- }
- /** Free function for logger that logs to a FILE. */
- void monolog_file_free(void * data) {
- FILE * fout = data;
- if (fout) {
- fclose(fout);
- }
- }
|