Logging in C with support for monoid logging
logging jsonl monoid c
0

Configure Feed

Select the types of activity you want to include in your feed.

clog / src / clog.c
4.0 kB 137 lines
1#include "clog.h" 2#include "dynarr.h" 3#include <stdio.h> 4#include <stdlib.h> 5#include <string.h> 6#include <time.h> 7 8static ClogFmt g_fmt = CLOG_FMT_JSONL; 9 10/// Set the global output format. Defaults to CLOG_FMT_JSONL. 11void clog_set_fmt(ClogFmt fmt) { g_fmt = fmt; } 12 13/* --- helpers ------------------------------------------------------------ */ 14 15static const char *level_str(ClogLevel level) { 16 switch (level) { 17 case CLOG_INF: return "INF"; 18 case CLOG_DBG: return "DBG"; 19 case CLOG_WRN: return "WRN"; 20 case CLOG_ERR: return "ERR"; 21 default: return "???"; 22 } 23} 24 25static const char *level_color(ClogLevel level) { 26 switch (level) { 27 case CLOG_INF: return "\033[36m"; /* cyan */ 28 case CLOG_DBG: return "\033[37m"; /* white */ 29 case CLOG_WRN: return "\033[33m"; /* yellow */ 30 case CLOG_ERR: return "\033[1;31m"; /* bold red */ 31 default: return ""; 32 } 33} 34 35/// Fill ts[26] with the current local time in ANSI C format, newline stripped. 36static void get_ts(char ts[26]) { 37 time_t t = time(NULL); 38 const char *s = ctime(&t); 39 strncpy(ts, s, 25); 40 ts[25] = '\0'; 41 if (ts[24] == '\n') ts[24] = '\0'; 42} 43 44/// Write a JSON-escaped string to stdout without surrounding quotes. 45static void write_json_str(const char *s) { 46 for (; *s; s++) { 47 switch (*s) { 48 case '"': fputs("\\\"", stdout); break; 49 case '\\': fputs("\\\\", stdout); break; 50 case '\n': fputs("\\n", stdout); break; 51 case '\r': fputs("\\r", stdout); break; 52 case '\t': fputs("\\t", stdout); break; 53 default: 54 if ((unsigned char)*s < 0x20) { 55 printf("\\u%04x", (unsigned char)*s); 56 } else { 57 putchar(*s); 58 } 59 } 60 } 61} 62 63/// Print a single ClogEntry to stdout using the active format. 64static void print_entry(const ClogEntry *e) { 65 const char *lvl = level_str(e->level); 66 switch (g_fmt) { 67 case CLOG_FMT_JSONL: 68 printf("{\"ts\":\""); 69 write_json_str(e->ts); 70 printf("\",\"level\":\"%s\",\"file\":\"", lvl); 71 write_json_str(e->file); 72 printf("\",\"line\":%u,\"func\":\"", e->line); 73 write_json_str(e->func); 74 printf("\",\"msg\":\""); 75 write_json_str(e->msg); 76 printf("\"}\n"); 77 break; 78 case CLOG_FMT_TEXT: 79 printf("%s:%u:%s %s %s %s\n", e->file, e->line, e->func, e->ts, lvl, e->msg); 80 break; 81 case CLOG_FMT_TEXT_COLOR: 82 printf("%s:%u:%s %s %s%s\033[0m %s\n", e->file, e->line, e->func, e->ts, level_color(e->level), lvl, e->msg); 83 break; 84 default: 85 fprintf(stderr, "Incorrect CLog format has been set: %d\n", g_fmt); 86 exit(EXIT_FAILURE); 87 } 88} 89 90/// Build a ClogEntry from the given fields, capturing the current timestamp. 91static ClogEntry make_entry(ClogLevel level, const char *file, unsigned int line, const char *func, const char *msg) { 92 ClogEntry e; 93 e.level = level; 94 get_ts(e.ts); 95 e.file = file; 96 e.line = line; 97 e.func = func; 98 strncpy(e.msg, msg, CLOG_MSG_MAX - 1); 99 e.msg[CLOG_MSG_MAX - 1] = '\0'; 100 return e; 101} 102 103/* --- lifecycle ---------------------------------------------------------- */ 104 105/// Allocate and return a new empty CLog (dynamic array of ClogEntry). 106CLog clog_log_init(void) { 107 return da_new(ClogEntry); 108} 109 110/// Free a CLog and all its entries. 111void clog_log_free(CLog log) { 112 da_free(log); 113} 114 115/// Print all entries in log to stdout using the active format. 116void clog_log_print(const CLog log) { 117 size_t n = da_length(log); 118 for (size_t i = 0; i < n; i++) { 119 print_entry(&log[i]); 120 } 121} 122 123/* --- write -------------------------------------------------------------- */ 124 125/// Immediately print a log entry to stdout. Called via the clog() macro. 126void _clog_write_imm(ClogLevel level, const char *file, unsigned int line, const char *func, const char *msg) { 127 ClogEntry e = make_entry(level, file, line, func, msg); 128 print_entry(&e); 129} 130 131/// Append a log entry to a CLog. Called via the clogm() macro. 132void _clog_write_log(CLog *log, ClogLevel level, const char *file, unsigned int line, const char *func, const char *msg) { 133 ClogEntry e = make_entry(level, file, line, func, msg); 134 CLog arr = *log; 135 da_append(arr, e); 136 *log = arr; 137}