LCOV - code coverage report
Current view: top level - netio-next/src - log.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 46 76 60.5 %
Date: 2025-08-12 04:15:35 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       14615 : static void stdout_callback(log_Event *ev) {
      57       14615 :   char buf[20];
      58       14615 :   struct timeval t;
      59       14615 :   int msec;
      60       14615 :   buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0';
      61       14615 :   gettimeofday(&t, NULL);
      62       14615 :   msec = lrint(t.tv_usec/1000.0); 
      63       14615 :   char buffer[24];
      64       14615 :   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       14615 :   fprintf(
      72       14615 :     ev->udata, "%s %-5s%s %s:%d: ",
      73       14615 :     buffer, level_strings[ev->level], "netio", ev->file, ev->line);
      74             : #endif
      75       14615 :   vfprintf(ev->udata, ev->fmt, ev->ap);
      76       14615 :   fprintf(ev->udata, "\n");
      77       14615 :   fflush(ev->udata);
      78       14615 : }
      79             : 
      80             : 
      81           0 : static void file_callback(log_Event *ev) {
      82           0 :   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       14832 : static void lock(void)   {
      94       14832 :   if (L.lock) { L.lock(true, L.udata); }
      95       14832 : }
      96             : 
      97             : 
      98       14832 : static void unlock(void) {
      99       14832 :   if (L.lock) { L.lock(false, L.udata); }
     100       14832 : }
     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         963 : void log_set_level(int level) {
     115         963 :   L.level = level;
     116         963 : }
     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           0 :       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       14614 : static void init_event(log_Event *ev, void *udata) {
     141       14614 :   if (!ev->time) {
     142       14614 :     time_t t = time(NULL);
     143       14615 :     ev->time = localtime(&t);
     144             :   }
     145       14615 :   ev->udata = udata;
     146       14615 : }
     147             : 
     148             : 
     149       14832 : void log_log(int level, const char *file, int line, const char *fmt, ...) {
     150       14832 :   log_Event ev = {
     151             :     .fmt   = fmt,
     152             :     .file  = file,
     153             :     .line  = line,
     154             :     .level = level,
     155             :   };
     156             : 
     157       14832 :   lock();
     158             : 
     159       14832 :   if (!L.quiet && level <= L.level) {
     160       14614 :     if ( level <= LOG_WARN){
     161        1080 :       init_event(&ev, stderr);
     162             :     } else {
     163       13534 :       init_event(&ev, stdout);
     164             :     }
     165       14615 :     va_start(ev.ap, fmt);
     166       14615 :     stdout_callback(&ev);
     167       14615 :     va_end(ev.ap);
     168             :   }
     169             : 
     170       14833 :   for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) {
     171           1 :     Callback *cb = &L.callbacks[i];
     172           1 :     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       14832 :   unlock();
     181       14832 : }

Generated by: LCOV version 1.0