Introduction to the lightweight C language open source log library log.c - realizing different levels and parameterized log printing

Preface

  • There is no ready-made log library in C language. If you want to record logs, you need to encapsulate a log library yourself. If you want to implement log level and parameter printing, it is still troublesome. I happened to find a C language open source log library on github, which can realize log level printing, parameter printing, and also record the date and line number. The most important thing is that the code is very Less, only more than 100 lines, which can be directly included in our own project code without any dependencies.

Source code address

Introduction to use

  • Simply download log.c and log.h from the project directory and include them in the project code. There are no other dependencies.
  • The log levels from low to high are as follows:LOG_TRACELOG_DEBUGLOG_INFOLOG_WARNLOG_ERRORLOG_FATAL
  • If the log level is set to LOG_TRACE, all levels of logs will be printed. If the log level is set to LOG_WARN, only logs of LOG_WARN and higher levels (i.e. LOG_ERROR and LOG_FATAL) will be printed.

Demo

  • test code
    •   #include "log.h"
        #include <stdio.h>
      
        int main() {
              
              
            FILE *fp = fopen("log.txt", "a+");
            if(fp == NULL){
              
              
                    printf("create log file failed.\n");
                    return -1;
            }
      
            //设置日志级别(在终端打印)
            log_set_level(LOG_TRACE);
      
            //设置日志级别(在文件中打印)
            log_add_fp(fp, LOG_INFO);
      
      
            log_trace("start trace.");
            log_debug("start debug.");
            log_info("start info.");
            log_warn("start warn.");
            log_error("start error.");
            log_fatal("start fatal");
      
            // 支持参数打印
            log_info("number is %d, string is %s", 10010, "helloword");
      
            fclose(fp);
        }
      
  • Demonstration effect
    Insert image description here

Source code

  • If there is any problem accessing github, I have posted the source code below.
  • log.h
    •   #ifndef LOG_H
        #define LOG_H
      
        #include <stdio.h>
        #include <stdarg.h>
        #include <stdbool.h>
        #include <time.h>
      
        #define LOG_VERSION "0.1.0"
      
        typedef struct {
              
              
            va_list ap;
            const char *fmt;
            const char *file;
            struct tm *time;
            void *udata;
            int line;
            int level;
        } log_Event;
      
        typedef void (*log_LogFn)(log_Event *ev);
        typedef void (*log_LockFn)(bool lock, void *udata);
      
        enum {
              
               LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL };
      
        #define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__)
        #define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
        #define log_info(...)  log_log(LOG_INFO,  __FILE__, __LINE__, __VA_ARGS__)
        #define log_warn(...)  log_log(LOG_WARN,  __FILE__, __LINE__, __VA_ARGS__)
        #define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__)
        #define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__)
      
        const char* log_level_string(int level);
        void log_set_lock(log_LockFn fn, void *udata);
        void log_set_level(int level);
        void log_set_quiet(bool enable);
        int log_add_callback(log_LogFn fn, void *udata, int level);
        int log_add_fp(FILE *fp, int level);
      
        void log_log(int level, const char *file, int line, const char *fmt, ...);
      
        #endif
      
  • log.c
    •   #include "log.h"
        #define MAX_CALLBACKS 32
      
        typedef struct {
              
              
            log_LogFn fn;
            void *udata;
            int level;
        } Callback;
      
        static struct {
              
              
            void *udata;
            log_LockFn lock;
            int level;
            bool quiet;
            Callback callbacks[MAX_CALLBACKS];
        } L;
      
      
        static const char *level_strings[] = {
              
              "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"};
      
        #ifdef LOG_USE_COLOR
        static const char *level_colors[] = {
              
              "\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m"};
        #endif
      
      
        static void stdout_callback(log_Event *ev) {
              
              
            char buf[16];
            buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0';
            #ifdef LOG_USE_COLOR
                fprintf(ev->udata, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", buf, level_colors[ev->level], level_strings[ev->level], ev->file, ev->line);
            #else
                fprintf(ev->udata, "%s %-5s %s:%d: ", buf, level_strings[ev->level], ev->file, ev->line);
            #endif
            vfprintf(ev->udata, ev->fmt, ev->ap);
            fprintf(ev->udata, "\n");
            fflush(ev->udata);
        }
      
        static void file_callback(log_Event *ev) {
              
              
            char buf[64];
            buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0';
            fprintf(ev->udata, "%s %-5s %s:%d: ", buf, level_strings[ev->level], ev->file, ev->line);
            vfprintf(ev->udata, ev->fmt, ev->ap);
            fprintf(ev->udata, "\n");
            fflush(ev->udata);
        }
      
        static void lock(void)   {
              
               
            if (L.lock) {
              
               
                L.lock(true, L.udata); 
            }
        }
      
        static void unlock(void) {
              
              
            if (L.lock) {
              
               
                L.lock(false, L.udata); 
            }
        }
      
        const char* log_level_string(int level) {
              
               
            return level_strings[level];
        }
      
        void log_set_lock(log_LockFn fn, void *udata) {
              
              
            L.lock = fn;
            L.udata = udata;
        }
      
        void log_set_level(int level) {
              
              
            L.level = level;
        }
      
      
        void log_set_quiet(bool enable) {
              
              
            L.quiet = enable;
        }
      
      
        int log_add_callback(log_LogFn fn, void *udata, int level) {
              
              
            for (int i = 0; i < MAX_CALLBACKS; i++) {
              
              
                if (!L.callbacks[i].fn) {
              
              
                    L.callbacks[i] = (Callback) {
              
               fn, udata, level };
                    return 0;
                }
            }
            return -1;
        }
      
      
        int log_add_fp(FILE *fp, int level) {
              
              
            return log_add_callback(file_callback, fp, level);
        }
      
      
        static void init_event(log_Event *ev, void *udata) {
              
              
            if (!ev->time) {
              
              
                time_t t = time(NULL);
                ev->time = localtime(&t);
            }
            ev->udata = udata;
        }
      
      
        void log_log(int level, const char *file, int line, const char *fmt, ...) {
              
              
            log_Event ev = {
              
              
                .fmt   = fmt,
                .file  = file,
                .line  = line,
                .level = level,
            };
      
            lock();
      
            if (!L.quiet && level >= L.level) {
              
              
                init_event(&ev, stderr);
                va_start(ev.ap, fmt);
                stdout_callback(&ev);
                va_end(ev.ap);
            }
      
            for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) {
              
              
                Callback *cb = &L.callbacks[i];
                if (level >= cb->level) {
              
              
                    init_event(&ev, cb->udata);
                    va_start(ev.ap, fmt);
                    cb->fn(&ev);
                    va_end(ev.ap);
                }
            }
      
            unlock();
        }
      

Guess you like

Origin blog.csdn.net/new9232/article/details/132992574