cwist
Modern C web framework with libttak runtime
Loading...
Searching...
No Matches
logger.c
Go to the documentation of this file.
1
4#define _POSIX_C_SOURCE 200809L
7#include "log_async.h"
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <time.h>
12#include <unistd.h>
13
14static const char *level_strings[] = {"DEBUG", "INFO", "WARN", "ERROR"};
15static const char *level_colors[] = {"\033[36m", "\033[32m", "\033[33m", "\033[31m"};
16static const char *color_reset = "\033[0m";
17
22static FILE *level_file(cwist_log_level_t level) {
23 return level >= CWIST_LOG_WARN ? stderr : stdout;
24}
25
34 if (!log) return NULL;
35 log->name = cwist_strdup(name ? name : "cwist");
36 if (!log->name) {
37 cwist_free(log);
38 return NULL;
39 }
40 log->level = CWIST_LOG_INFO;
41 log->use_colors = true;
42 return log;
43}
44
49 if (!log) return;
50 cwist_free(log->name);
51 cwist_free(log);
52}
53
59 if (log) log->level = level;
60}
61
66void cwist_logger_set_colors(cwist_logger *log, bool enabled) {
67 if (log) log->use_colors = enabled;
68}
69
78static void logger_vlog(cwist_logger *log, cwist_log_level_t level, const char *fmt, va_list args) {
79 if (!log || level < log->level || (unsigned)level > CWIST_LOG_ERROR) return;
80 FILE *out = level_file(level);
81 /* localtime_r() takes glibc's timezone lock on every call, which is the
82 * most expensive part of a log line once many threads log at once. The
83 * stamp only changes once a second, so each thread keeps its last one. */
85 static _Thread_local char time_buf[32];
87 if (now != cached_sec) {
88 struct tm tm_info;
89 strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", localtime_r(&now, &tm_info));
91 }
92
93 /* Format the whole line first, so it is written with one call (or queued
94 * for the async writer) instead of a prefix, a message and a newline. */
95 char stack_buf[1024];
96 char *line = stack_buf;
97 const char *color = log->use_colors ? level_colors[level] : "";
98 const char *reset = log->use_colors ? color_reset : "";
99 /* With colors off, color and reset are "" and the line reads
100 * "[time] [LEVEL] name: ", as before. */
101 int prefix = snprintf(NULL, 0, "%s[%s]%s [%s] %s: ", color, time_buf, reset,
102 level_strings[level], log->name);
105 int body = vsnprintf(NULL, 0, fmt, measure);
107 if (prefix < 0 || body < 0) return;
108 size_t len = (size_t)prefix + (size_t)body + 1; /* + newline */
109 if (len + 1 > sizeof(stack_buf)) {
110 line = cwist_alloc(len + 1);
111 if (!line) return;
112 }
113 snprintf(line, len + 1, "%s[%s]%s [%s] %s: ", color, time_buf, reset, level_strings[level],
114 log->name);
115 vsnprintf(line + prefix, len + 1 - (size_t)prefix, fmt, args);
116 line[len - 1] = '\n';
117 line[len] = '\0';
118
119 if (!cwist_log_async_submit(fileno(out), line, len)) {
120 /* Sync fallback: no per-line fflush. stdio batches lines in its
121 * buffer (block-buffered on pipes and files, line-buffered on a TTY),
122 * so delivery is not immediate. Call cwist_log_async_start() for
123 * immediate per-line delivery. */
124 fwrite(line, 1, len, out);
125 }
126 if (line != stack_buf) cwist_free(line);
127}
128
143void cwist_logger_log(cwist_logger *log, cwist_log_level_t level, const char *fmt, ...) {
145 va_start(args, fmt);
146 logger_vlog(log, level, fmt, args);
147 va_end(args);
148}
149
154void cwist_logger_debug(cwist_logger *log, const char *fmt, ...) {
156 va_start(args, fmt);
157 logger_vlog(log, CWIST_LOG_DEBUG, fmt, args);
158 va_end(args);
159}
160
165void cwist_logger_info(cwist_logger *log, const char *fmt, ...) {
167 va_start(args, fmt);
168 logger_vlog(log, CWIST_LOG_INFO, fmt, args);
169 va_end(args);
170}
171
176void cwist_logger_warn(cwist_logger *log, const char *fmt, ...) {
178 va_start(args, fmt);
179 logger_vlog(log, CWIST_LOG_WARN, fmt, args);
180 va_end(args);
181}
182
187void cwist_logger_error(cwist_logger *log, const char *fmt, ...) {
189 va_start(args, fmt);
190 logger_vlog(log, CWIST_LOG_ERROR, fmt, args);
191 va_end(args);
192}
Memory allocation wrappers backed by libttak.
void cwist_free(void *ptr)
Free memory obtained via cwist_alloc/cwist_strdup/etc.
Definition alloc.c:52
char * cwist_strdup(const char *src)
Duplicate a string using libttak-backed storage.
Definition alloc.c:32
void * cwist_alloc(size_t size)
Allocate zeroed memory tracked by libttak.
Definition alloc.c:17
#define CWIST_LOG_ERROR(fmt,...)
Definition log.h:57
#define CWIST_LOG_INFO(fmt,...)
Definition log.h:55
#define CWIST_LOG_WARN(fmt,...)
Definition log.h:56
#define CWIST_LOG_DEBUG(fmt,...)
Definition log.h:58
bool cwist_log_async_submit(int fd, const char *line, size_t len)
Queue one complete line for fd (STDOUT_FILENO or STDERR_FILENO).
Definition log_async.c:263
Internal hook from the log call sites into the async log writer.
void cwist_logger_warn(cwist_logger *log, const char *fmt,...)
Logs a formatted message at WARN level on stderr.
Definition logger.c:176
cwist_logger * cwist_logger_create(const char *name)
Creates a logger instance.
Definition logger.c:32
void cwist_logger_error(cwist_logger *log, const char *fmt,...)
Logs a formatted message at ERROR level on stderr.
Definition logger.c:187
void cwist_logger_log(cwist_logger *log, cwist_log_level_t level, const char *fmt,...)
Logs a formatted message at the given level.
Definition logger.c:143
void cwist_logger_set_colors(cwist_logger *log, bool enabled)
Enables or disables ANSI color output in log lines.
Definition logger.c:66
void cwist_logger_info(cwist_logger *log, const char *fmt,...)
Logs a formatted message at INFO level on stdout.
Definition logger.c:165
void cwist_logger_set_level(cwist_logger *log, cwist_log_level_t level)
Sets the minimum log level that will be emitted.
Definition logger.c:58
void cwist_logger_destroy(cwist_logger *log)
Destroys a logger instance and frees its name.
Definition logger.c:48
void cwist_logger_debug(cwist_logger *log, const char *fmt,...)
Logs a formatted message at DEBUG level on stdout.
Definition logger.c:154
Application-level structured logging.
cwist_log_level_t
Definition logger.h:13
size_t cap
Definition otel.c:56
cwist_log_level_t level
Definition logger.h:22
bool use_colors
Definition logger.h:23
char * name
Definition logger.h:21