LCOV - code coverage report
Current view: top level - src - log.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 40 69 58.0 %
Date: 2025-11-26 02:09:04 Functions: 6 12 50.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2020 rxi
       3             :  *
       4             :  * Permission is hereby granted, free of charge, to any person obtaining a copy
       5             :  * of this software and associated documentation files (the "Software"), to
       6             :  * deal in the Software without restriction, including without limitation the
       7             :  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
       8             :  * sell copies of the Software, and to permit persons to whom the Software is
       9             :  * furnished to do so, subject to the following conditions:
      10             :  *
      11             :  * The above copyright notice and this permission notice shall be included in
      12             :  * all copies or substantial portions of the Software.
      13             :  *
      14             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17             :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      19             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
      20             :  * IN THE SOFTWARE.
      21             :  */
      22             : 
      23             : #include "log.h"
      24             : #include <math.h>
      25             : #include <sys/time.h>
      26             : 
      27             : #define MAX_CALLBACKS 32
      28             : 
      29             : typedef struct {
      30             :   log_LogFn fn;
      31             :   void *udata;
      32             :   int level;
      33             : } Callback;
      34             : 
      35             : static struct {
      36             :   void *udata;
      37             :   log_LockFn lock;
      38             :   int level;
      39             :   bool quiet;
      40             :   Callback callbacks[MAX_CALLBACKS];
      41             : } L;
      42             : 
      43             : 
      44             : static const char *level_strings[] = {
      45             :   "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE"
      46             : };
      47             : 
      48             : 
      49             : #ifdef LOG_USE_COLOR
      50             : static const char *level_colors[] = {
      51             :   "\x1b[35m", "\x1b[31m", "\x1b[33m", "\x1b[32m", "\x1b[36m", "\x1b[94m"
      52             : };
      53             : #endif
      54             : 
      55             : 
      56        2032 : static void stdout_callback(log_Event *ev) {
      57             :   char buf[20];
      58             :   struct timeval t;
      59             :   int msec;
      60        2032 :   buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0';
      61        2032 :   gettimeofday(&t, NULL);
      62        2032 :   msec = lrint(t.tv_usec/1000.0); 
      63             :   char buffer[24];
      64        2032 :   snprintf(buffer, sizeof(buffer), "%s.%03d", buf, msec);
      65             : #ifdef LOG_USE_COLOR
      66             :   fprintf(
      67             :     ev->udata, "%s %s%-5s\x1b[0m \x1b[90m%s %s:%d:\x1b[0m ",
      68             :     buffer, level_colors[ev->level], level_strings[ev->level], "netio",
      69             :     ev->file, ev->line);
      70             : #else
      71        2032 :   fprintf(
      72        2032 :     ev->udata, "%s %-5s%s %s:%d: ",
      73        2032 :     buffer, level_strings[ev->level], "netio", ev->file, ev->line);
      74             : #endif
      75        2032 :   vfprintf(ev->udata, ev->fmt, ev->ap);
      76        2032 :   fprintf(ev->udata, "\n");
      77        2032 :   fflush(ev->udata);
      78        2032 : }
      79             : 
      80             : 
      81           0 : static void file_callback(log_Event *ev) {
      82             :   char buf[64];
      83           0 :   buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0';
      84           0 :   fprintf(
      85           0 :     ev->udata, "%s %-5s %s:%d: ",
      86           0 :     buf, level_strings[ev->level], ev->file, ev->line);
      87           0 :   vfprintf(ev->udata, ev->fmt, ev->ap);
      88           0 :   fprintf(ev->udata, "\n");
      89           0 :   fflush(ev->udata);
      90           0 : }
      91             : 
      92             : 
      93        2071 : static void lock(void)   {
      94        2071 :   if (L.lock) { L.lock(true, L.udata); }
      95        2071 : }
      96             : 
      97             : 
      98        2071 : static void unlock(void) {
      99        2071 :   if (L.lock) { L.lock(false, L.udata); }
     100        2071 : }
     101             : 
     102             : 
     103           0 : const char* log_level_string(int level) {
     104           0 :   return level_strings[level];
     105             : }
     106             : 
     107             : 
     108           0 : void log_set_lock(log_LockFn fn, void *udata) {
     109           0 :   L.lock = fn;
     110           0 :   L.udata = udata;
     111           0 : }
     112             : 
     113             : 
     114          96 : void log_set_level(int level) {
     115          96 :   L.level = level;
     116          96 : }
     117             : 
     118             : 
     119           0 : void log_set_quiet(bool enable) {
     120           0 :   L.quiet = enable;
     121           0 : }
     122             : 
     123             : 
     124           0 : int log_add_callback(log_LogFn fn, void *udata, int level) {
     125           0 :   for (int i = 0; i < MAX_CALLBACKS; i++) {
     126           0 :     if (!L.callbacks[i].fn) {
     127           0 :       L.callbacks[i] = (Callback) { fn, udata, level };
     128             :       return 0;
     129             :     }
     130             :   }
     131             :   return -1;
     132             : }
     133             : 
     134             : 
     135           0 : int log_add_fp(FILE *fp, int level) {
     136           0 :   return log_add_callback(file_callback, fp, level);
     137             : }
     138             : 
     139             : 
     140        2032 : static void init_event(log_Event *ev, void *udata) {
     141        2032 :   if (!ev->time) {
     142        2032 :     time_t t = time(NULL);
     143        2031 :     ev->time = localtime(&t);
     144             :   }
     145        2032 :   ev->udata = udata;
     146        2032 : }
     147             : 
     148             : 
     149        2071 : void log_log(int level, const char *file, int line, const char *fmt, ...) {
     150        2071 :   log_Event ev = {
     151             :     .fmt   = fmt,
     152             :     .file  = file,
     153             :     .line  = line,
     154             :     .level = level,
     155             :   };
     156             : 
     157        2071 :   lock();
     158             : 
     159        2071 :   if (!L.quiet && level <= L.level) {
     160        2032 :     if ( level <= LOG_WARN){
     161         280 :       init_event(&ev, stderr);
     162             :     } else {
     163        1752 :       init_event(&ev, stdout);
     164             :     }
     165        2032 :     va_start(ev.ap, fmt);
     166        2032 :     stdout_callback(&ev);
     167        2032 :     va_end(ev.ap);
     168             :   }
     169             : 
     170        2071 :   for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) {
     171             :     Callback *cb = &L.callbacks[i];
     172           0 :     if (level <= cb->level) {
     173           0 :       init_event(&ev, cb->udata);
     174           0 :       va_start(ev.ap, fmt);
     175           0 :       cb->fn(&ev);
     176           0 :       va_end(ev.ap);
     177             :     }
     178             :   }
     179             : 
     180        2071 :   unlock();
     181        2071 : }

Generated by: LCOV version 1.0