Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
n_log.c
Go to the documentation of this file.
1
8#include "nilorea/n_common.h"
9#include "nilorea/n_log.h"
10
11#include <pthread.h>
12#include <string.h>
13#include <inttypes.h>
14#include <sys/types.h>
15#include <sys/stat.h>
16#include <fcntl.h>
17
18#ifndef __windows__
19#include <syslog.h>
20#else
21#include <time.h>
22#include <windows.h>
23#endif
24
26
27#define COLOR_RESET "\033[0m"
28#define COLOR_RED "\033[31m"
29#define COLOR_GREEN "\033[32m"
30#define COLOR_YELLOW "\033[33m"
31#define COLOR_BLUE "\033[34m"
32#define COLOR_MAGENTA "\033[35m"
33#define COLOR_CYAN "\033[36m"
34#define COLOR_WHITE "\033[37m"
35
37typedef struct LOG_LEVELS {
39 char* c_name;
41 int c_val;
43 char* w_name;
44
46
49 {
50 {"EMERG", LOG_EMERG, "ERROR"},
51 {"ALERT", LOG_ALERT, "ERROR"},
52 {"CRITICAL", LOG_CRIT, "ERROR"},
53 {"ERR", LOG_ERR, "ERROR"},
54 {"WARNING", LOG_WARNING, "WARNING"},
55 {"NOTICE", LOG_NOTICE, "SUCCESS"},
56 {"INFO", LOG_INFO, "INFORMATION"},
57 {"DEBUG", LOG_DEBUG, "INFORMATION"},
58 {NULL, -1, NULL}};
59
61static int LOG_LEVEL = LOG_NULL;
62
64static int LOG_TYPE = LOG_STDERR;
65
67static FILE* log_file = NULL;
68
70char* proc_name = NULL;
71
77char* open_sysjrnl(char* identity) {
78 __n_assert(identity, return NULL);
79#ifndef __windows__
80 /* LOG_CONS: log to console if no syslog available
81 * LOG_PID: add pid of calling process to log
82 * Local use 7 : compat with older logging systems
83 */
84 openlog(identity, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL7);
85#endif
86 proc_name = strdup(identity);
87 return proc_name;
88} /* open_sysjrnl */
89
93void close_sysjrnl(void) {
94#ifndef __windows__
95 closelog();
96#endif
98} /* close_sysjrnl */
99
104void set_log_level(const int log_level) {
105 if (log_level == LOG_FILE) {
107 return;
108 }
109 if (log_level == LOG_STDERR) {
111 return;
112 }
113 if (log_level == LOG_SYSJRNL) {
115 return;
116 }
118#ifdef __windows__
119 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
120 if (hOut != INVALID_HANDLE_VALUE) {
121 DWORD dwMode = 0;
122 if (GetConsoleMode(hOut, &dwMode)) {
123 dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
124 if (SetConsoleMode(hOut, dwMode)) {
125 // color support is enabled
127 }
128 }
129 }
130#else
131 // Probably a terminal, may support colors
132 if (isatty(fileno(stdout))) {
134 }
135#endif
136} /* set_log_level() */
137
142int get_log_level(void) {
143 return LOG_LEVEL;
144} /* get_log_level() */
145
151int set_log_file(char* file) {
152 __n_assert(file, return FALSE);
153
154 if (log_file) {
155 fclose(log_file);
156 log_file = NULL;
157 }
158
159 int fd = open(file, O_CREAT | O_APPEND | O_WRONLY, 0600); // rw------- permissions
160 __n_assert(fd != -1, n_log(LOG_ERR, "couldn't create %s with 0600 permission", _str(file)); return FALSE);
161
162 log_file = fdopen(fd, "a");
163 __n_assert(log_file, close(fd); n_log(LOG_ERR, "fdopen returned an invalid file descriptor pointer for %s:%d", _str(file), fd); return FALSE);
164
166
167 return TRUE;
168} /* set_log_file */
169
174FILE* get_log_file(void) {
175 return log_file;
176} /*get_log_level() */
177
178#ifndef _vscprintf
185int _vscprintf_so(const char* format, va_list pargs) {
186 int retval;
187 va_list argcopy;
188 va_copy(argcopy, pargs);
189 retval = vsnprintf(NULL, 0, format, argcopy);
190 va_end(argcopy);
191 return retval;
192}
193#endif
194
195#ifndef vasprintf
203int vasprintf(char** strp, const char* fmt, va_list ap) {
204 long long int len = _vscprintf_so(fmt, ap);
205 if (len == -1)
206 return -1;
207 char* str = NULL;
208 Malloc(str, char, (size_t)len + 1 + sizeof(void*)); // len + EndOfString + padding
209 if (!str)
210 return -1;
211 int r = vsnprintf(str, (size_t)(len + 1), fmt, ap); /* "secure" version of vsprintf */
212 if (r == -1)
213 return free(str), -1;
214 *strp = str;
215 return r;
216}
217#endif
218
219#ifndef asprintf
227int asprintf(char* strp[], const char* fmt, ...) {
228 va_list ap;
229 va_start(ap, fmt);
230 int r = vasprintf(strp, fmt, ap);
231 va_end(ap);
232 return r;
233}
234#endif
235
244void _n_log(int level, const char* file, const char* func, int line, const char* format, ...) {
245 FILE* out = NULL;
246
247 if (level == LOG_NULL)
248 return;
249
250 if (!log_file)
251 out = stderr;
252 else
253 out = log_file;
254
255 int log_level = get_log_level();
256
257 if (level <= log_level) {
258 va_list args;
259 char* syslogbuffer = NULL;
260 char* eventbuffer = NULL;
261#ifdef __windows__
262 size_t needed = 0;
263 char* name = "NULL";
264 if (proc_name)
265 name = proc_name;
266#endif
267
268 const char* color = "";
269 const char* color_reset = "";
270
272 color_reset = COLOR_RESET;
273 switch (level) {
274 case LOG_EMERG:
275 color = COLOR_RED;
276 break;
277 case LOG_ALERT:
278 color = COLOR_MAGENTA;
279 break;
280 case LOG_CRIT:
281 color = COLOR_RED;
282 break;
283 case LOG_ERR:
284 color = COLOR_RED;
285 break;
286 case LOG_WARNING:
287 color = COLOR_YELLOW;
288 break;
289 case LOG_NOTICE:
290 color = COLOR_GREEN;
291 break;
292 case LOG_INFO:
293 color = COLOR_CYAN;
294 break;
295 case LOG_DEBUG:
296 color = COLOR_BLUE;
297 break;
298 default:
299 color = COLOR_WHITE;
300 break;
301 }
302 }
303 switch (LOG_TYPE) {
304 case LOG_SYSJRNL:
305 va_start(args, format);
306 vasprintf(&syslogbuffer, format, args);
307 va_end(args);
308#ifdef __windows__
309 needed = (unsigned long long)snprintf(NULL, 0, "start /B EventCreate /t %s /id 666 /l APPLICATION /so %s /d \"%s\" > NUL 2>&1", prioritynames[level].w_name, name, syslogbuffer);
310 Malloc(eventbuffer, char, needed + 4);
311 sprintf(eventbuffer, "start /B EventCreate /t %s /id 666 /l APPLICATION /so %s /d \"%s\" > NUL 2>&1", prioritynames[level].w_name, name, syslogbuffer);
312 system(eventbuffer);
313#else
314 syslog(level, "%s->%s:%d %s", file, func, line, syslogbuffer);
315#endif
316 FreeNoLog(syslogbuffer);
317 FreeNoLog(eventbuffer);
318 break;
319 default:
320 fprintf(out, "%s%s:%jd:%s->%s:%d ", color, prioritynames[level].c_name, (intmax_t)time(NULL), file, func, line);
321 va_start(args, format);
322 vfprintf(out, format, args);
323 va_end(args);
324 fprintf(out, "%s\n", color_reset);
325 break;
326 }
327 fflush(out);
328 }
329} /* _n_log( ... ) */
330
338int open_safe_logging(TS_LOG** log, char* pathname, char* opt) {
339 if (!log) {
340 n_log(LOG_ERR, "Invalid log pointer (NULL)");
341 return FALSE;
342 }
343
344 if (*log) {
345 if ((*log)->file) {
346 n_log(LOG_ERR, "Log file '%s' already open", _str(pathname));
347 return -1000; // already open
348 }
349 n_log(LOG_ERR, "Log struct already allocated without file");
350 return FALSE;
351 }
352
353 if (!pathname || !opt) {
354 n_log(LOG_ERR, "Invalid pathname or mode (pathname=%s, opt=%s)", _str(pathname), _str(opt));
355 return FALSE;
356 }
357
358 Malloc((*log), TS_LOG, 1);
359 if (!(*log)) {
360 n_log(LOG_ERR, "Failed to allocate TS_LOG structure");
361 return FALSE;
362 }
363
364 pthread_mutex_init(&(*log)->LOG_MUTEX, NULL);
365
366 int flags = 0;
367 if (strcmp(opt, "a") == 0 || strcmp(opt, "a+") == 0) {
368 flags = O_CREAT | O_APPEND | O_WRONLY;
369 } else if (strcmp(opt, "w") == 0 || strcmp(opt, "w+") == 0) {
370 flags = O_CREAT | O_TRUNC | O_WRONLY;
371 } else {
372 n_log(LOG_ERR, "Unsupported open mode '%s' for pathname '%s'", _str(opt), _str(pathname));
373 free(*log);
374 *log = NULL;
375 return FALSE;
376 }
377
378 int fd = open(pathname, flags, 0600); // rw-------
379 if (fd == -1) {
380 n_log(LOG_ERR, "Failed to open '%s' with 0600 permissions", _str(pathname));
381 free(*log);
382 *log = NULL;
383 return FALSE;
384 }
385
386 (*log)->file = fdopen(fd, opt);
387 if (!(*log)->file) {
388 n_log(LOG_ERR, "fdopen failed for '%s' (fd=%d, mode='%s')", _str(pathname), fd, _str(opt));
389 close(fd);
390 free(*log);
391 *log = NULL;
392 return FALSE;
393 }
394
395 return TRUE;
396} /* open_safe_logging */
397
404int write_safe_log(TS_LOG* log, char* pat, ...) {
405 /* argument list */
406 va_list arg;
407 char str[2048] = "";
408
409 if (!log)
410 return FALSE;
411
412 va_start(arg, pat);
413
414 vsnprintf(str, sizeof(str), pat, arg);
415
416 va_end(arg);
417
418 pthread_mutex_lock(&log->LOG_MUTEX);
419 fprintf(log->file, "%s", str);
420 fflush(log->file);
421 pthread_mutex_unlock(&log->LOG_MUTEX);
422
423 return TRUE;
424
425} /* write_safe_log( ... ) */
426
433 if (!log)
434 return FALSE;
435
436 pthread_mutex_lock(&log->LOG_MUTEX);
437 fflush(log->file);
438 pthread_mutex_unlock(&log->LOG_MUTEX);
439
440 pthread_mutex_destroy(&log->LOG_MUTEX);
441
442 fclose(log->file);
443
444 return TRUE;
445
446} /* close_safe_logging( ...) */
int log_level
Definition ex_fluid.c:43
#define FreeNoLog(__ptr)
Free Handler without log.
Definition n_common.h:249
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
Definition n_common.h:185
#define __n_assert(__ptr, __ret)
macro to assert things
Definition n_common.h:256
#define _str(__PTR)
define true
Definition n_common.h:174
pthread_mutex_t LOG_MUTEX
mutex for thread-safe writting
Definition n_log.h:78
FILE * file
File handler.
Definition n_log.h:80
#define LOG_ALERT
action must be taken immediately
Definition n_log.h:53
#define LOG_SYSJRNL
to sysjrnl
Definition n_log.h:33
FILE * get_log_file(void)
return the current log_file
Definition n_log.c:174
int write_safe_log(TS_LOG *log, char *pat,...)
write to a thread-safe logging file
Definition n_log.c:404
int open_safe_logging(TS_LOG **log, char *pathname, char *opt)
Open a thread-safe logging file.
Definition n_log.c:338
#define LOG_EMERG
system is unusable
Definition n_log.h:51
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:70
char * open_sysjrnl(char *identity)
Open connection to syslog or create internals for event log.
Definition n_log.c:77
#define LOG_FILE
internal, logging to file
Definition n_log.h:29
void close_sysjrnl(void)
Close syslog connection or clean internals for event log.
Definition n_log.c:93
#define LOG_DEBUG
debug-level messages
Definition n_log.h:65
#define LOG_ERR
error conditions
Definition n_log.h:57
#define LOG_STDERR
internal, default LOG_TYPE
Definition n_log.h:31
#define LOG_CRIT
critical conditions
Definition n_log.h:55
int close_safe_logging(TS_LOG *log)
close a thread-safe logging file
Definition n_log.c:432
int set_log_file(char *file)
Set the logging to a file instead of stderr.
Definition n_log.c:151
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL )
Definition n_log.c:104
#define LOG_NOTICE
normal but significant condition
Definition n_log.h:61
#define LOG_WARNING
warning conditions
Definition n_log.h:59
#define LOG_NULL
no log output
Definition n_log.h:27
#define LOG_INFO
informational
Definition n_log.h:63
void _n_log(int level, const char *file, const char *func, int line, const char *format,...)
Logging function.
Definition n_log.c:244
int get_log_level(void)
Get the global log level value.
Definition n_log.c:142
ThreadSafe LOGging structure.
Definition n_log.h:76
Common headers and low-level functions & define.
#define COLOR_RESET
Definition n_log.c:27
static LOG_LEVELS prioritynames[]
array of log levels
Definition n_log.c:48
#define COLOR_BLUE
Definition n_log.c:31
char * proc_name
static proc name, for windows event log
Definition n_log.c:70
int c_val
numeric value of log type
Definition n_log.c:41
static int LOG_LEVEL
static global maximum wanted log level value
Definition n_log.c:61
#define COLOR_YELLOW
Definition n_log.c:30
static int LOG_TYPE
static global logging type ( STDERR, FILE, SYSJRNL )
Definition n_log.c:64
int vasprintf(char **strp, const char *fmt, va_list ap)
snprintf from a va_list, helper for asprintf
Definition n_log.c:203
int asprintf(char *strp[], const char *fmt,...)
snprintf from a va_list
Definition n_log.c:227
static int terminal_support_colors
Definition n_log.c:25
#define COLOR_CYAN
Definition n_log.c:33
#define COLOR_MAGENTA
Definition n_log.c:32
#define COLOR_WHITE
Definition n_log.c:34
static FILE * log_file
static FILE handling if logging to file is enabled
Definition n_log.c:67
char * w_name
event log value
Definition n_log.c:43
char * c_name
string of log type
Definition n_log.c:39
#define COLOR_RED
Definition n_log.c:28
#define COLOR_GREEN
Definition n_log.c:29
int _vscprintf_so(const char *format, va_list pargs)
compute the size of a string made with format 'fmt' and arguments in the va_list 'ap',...
Definition n_log.c:185
internal struct to handle log types
Definition n_log.c:37
Generic log system.