Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
n_log.c
Go to the documentation of this file.
1
7#include "nilorea/n_common.h"
8#include "nilorea/n_log.h"
9
10#include <pthread.h>
11#include <string.h>
12#include <inttypes.h>
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <fcntl.h>
16
17#ifndef __windows__
18#include <syslog.h>
19#else
20#include <time.h>
21#endif
22
24typedef struct LOG_LEVELS {
26 char* c_name;
28 int c_val;
30 char* w_name;
31
33
36 {
37 {"EMERG", LOG_EMERG, "ERROR"},
38 {"ALERT", LOG_ALERT, "ERROR"},
39 {"CRITICAL", LOG_CRIT, "ERROR"},
40 {"ERR", LOG_ERR, "ERROR"},
41 {"WARNING", LOG_WARNING, "WARNING"},
42 {"NOTICE", LOG_NOTICE, "SUCCESS"},
43 {"INFO", LOG_INFO, "INFORMATION"},
44 {"DEBUG", LOG_DEBUG, "INFORMATION"},
45 {NULL, -1, NULL}};
46
48static int LOG_LEVEL = LOG_NULL;
49
51static int LOG_TYPE = LOG_STDERR;
52
54static FILE* log_file = NULL;
55
57char* proc_name = NULL;
58
64char* open_sysjrnl(char* identity) {
65 __n_assert(identity, return NULL);
66#ifndef __windows__
67 /* LOG_CONS: log to console if no syslog available
68 * LOG_PID: add pid of calling process to log
69 * Local use 7 : compat with older logging systems
70 */
71 openlog(identity, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL7);
72#endif
73 proc_name = strdup(identity);
74 return proc_name;
75} /* open_sysjrnl */
76
80void close_sysjrnl(void) {
81#ifndef __windows__
82 closelog();
83#endif
85} /* close_sysjrnl */
86
91void set_log_level(const int log_level) {
92 if (log_level == LOG_FILE) {
94 return;
95 }
96 if (log_level == LOG_STDERR) {
98 return;
99 }
100 if (log_level == LOG_SYSJRNL) {
102 return;
103 }
104 LOG_LEVEL = log_level;
105} /* set_log_level() */
106
111int get_log_level(void) {
112 return LOG_LEVEL;
113} /* get_log_level() */
114
120int set_log_file(char* file) {
121 __n_assert(file, return FALSE);
122
123 if (log_file) {
124 fclose(log_file);
125 log_file = NULL;
126 }
127
128 int fd = open(file, O_CREAT | O_APPEND | O_WRONLY, 0600); // rw------- permissions
129 __n_assert(fd != -1, n_log(LOG_ERR, "couldn't create %s with 0600 permission", _str(file)); return FALSE);
130
131 log_file = fdopen(fd, "a");
132 __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);
133
135
136 return TRUE;
137} /* set_log_file */
138
143FILE* get_log_file(void) {
144 return log_file;
145} /*get_log_level() */
146
147#ifndef _vscprintf
154int _vscprintf_so(const char* format, va_list pargs) {
155 int retval;
156 va_list argcopy;
157 va_copy(argcopy, pargs);
158 retval = vsnprintf(NULL, 0, format, argcopy);
159 va_end(argcopy);
160 return retval;
161}
162#endif
163
164#ifndef vasprintf
172int vasprintf(char** strp, const char* fmt, va_list ap) {
173 long long int len = _vscprintf_so(fmt, ap);
174 if (len == -1)
175 return -1;
176 char* str = NULL;
177 Malloc(str, char, (size_t)len + 1 + sizeof(void*)); // len + EndOfString + padding
178 if (!str)
179 return -1;
180 int r = vsnprintf(str, (size_t)(len + 1), fmt, ap); /* "secure" version of vsprintf */
181 if (r == -1)
182 return free(str), -1;
183 *strp = str;
184 return r;
185}
186#endif
187
188#ifndef asprintf
196int asprintf(char* strp[], const char* fmt, ...) {
197 va_list ap;
198 va_start(ap, fmt);
199 int r = vasprintf(strp, fmt, ap);
200 va_end(ap);
201 return r;
202}
203#endif
204
213void _n_log(int level, const char* file, const char* func, int line, const char* format, ...) {
214 FILE* out = NULL;
215
216 if (level == LOG_NULL)
217 return;
218
219 if (!log_file)
220 out = stderr;
221 else
222 out = log_file;
223
224 int log_level = get_log_level();
225
226 if (level <= log_level) {
227 va_list args;
228 char* syslogbuffer = NULL;
229 char* eventbuffer = NULL;
230#ifdef __windows__
231 size_t needed = 0;
232 char* name = "NULL";
233 if (proc_name)
234 name = proc_name;
235#endif
236
237 switch (LOG_TYPE) {
238 case LOG_SYSJRNL:
239 va_start(args, format);
240 vasprintf(&syslogbuffer, format, args);
241 va_end(args);
242#ifdef __windows__
243 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);
244 Malloc(eventbuffer, char, needed + 4);
245 sprintf(eventbuffer, "start /B EventCreate /t %s /id 666 /l APPLICATION /so %s /d \"%s\" > NUL 2>&1", prioritynames[level].w_name, name, syslogbuffer);
246 system(eventbuffer);
247#else
248 syslog(level, "%s->%s:%d %s", file, func, line, syslogbuffer);
249#endif
250 FreeNoLog(syslogbuffer);
251 FreeNoLog(eventbuffer);
252 break;
253 default:
254 fprintf(out, "%s:%jd:%s->%s:%d ", prioritynames[level].c_name, (intmax_t)time(NULL), file, func, line);
255 va_start(args, format);
256 vfprintf(out, format, args);
257 va_end(args);
258 fprintf(out, "\n");
259 break;
260 }
261 fflush(out);
262 }
263} /* _n_log( ... ) */
264
272int open_safe_logging(TS_LOG** log, char* pathname, char* opt) {
273 if (!log) {
274 n_log(LOG_ERR, "Invalid log pointer (NULL)");
275 return FALSE;
276 }
277
278 if (*log) {
279 if ((*log)->file) {
280 n_log(LOG_ERR, "Log file '%s' already open", _str(pathname));
281 return -1000; // already open
282 }
283 n_log(LOG_ERR, "Log struct already allocated without file");
284 return FALSE;
285 }
286
287 if (!pathname || !opt) {
288 n_log(LOG_ERR, "Invalid pathname or mode (pathname=%s, opt=%s)", _str(pathname), _str(opt));
289 return FALSE;
290 }
291
292 Malloc((*log), TS_LOG, 1);
293 if (!(*log)) {
294 n_log(LOG_ERR, "Failed to allocate TS_LOG structure");
295 return FALSE;
296 }
297
298 pthread_mutex_init(&(*log)->LOG_MUTEX, NULL);
299
300 int flags = 0;
301 if (strcmp(opt, "a") == 0 || strcmp(opt, "a+") == 0) {
302 flags = O_CREAT | O_APPEND | O_WRONLY;
303 } else if (strcmp(opt, "w") == 0 || strcmp(opt, "w+") == 0) {
304 flags = O_CREAT | O_TRUNC | O_WRONLY;
305 } else {
306 n_log(LOG_ERR, "Unsupported open mode '%s' for pathname '%s'", _str(opt), _str(pathname));
307 free(*log);
308 *log = NULL;
309 return FALSE;
310 }
311
312 int fd = open(pathname, flags, 0600); // rw-------
313 if (fd == -1) {
314 n_log(LOG_ERR, "Failed to open '%s' with 0600 permissions", _str(pathname));
315 free(*log);
316 *log = NULL;
317 return FALSE;
318 }
319
320 (*log)->file = fdopen(fd, opt);
321 if (!(*log)->file) {
322 n_log(LOG_ERR, "fdopen failed for '%s' (fd=%d, mode='%s')", _str(pathname), fd, _str(opt));
323 close(fd);
324 free(*log);
325 *log = NULL;
326 return FALSE;
327 }
328
329 return TRUE;
330} /* open_safe_logging */
331
338int write_safe_log(TS_LOG* log, char* pat, ...) {
339 /* argument list */
340 va_list arg;
341 char str[2048] = "";
342
343 if (!log)
344 return FALSE;
345
346 va_start(arg, pat);
347
348 vsnprintf(str, sizeof(str), pat, arg);
349
350 va_end(arg);
351
352 pthread_mutex_lock(&log->LOG_MUTEX);
353 fprintf(log->file, "%s", str);
354 fflush(log->file);
355 pthread_mutex_unlock(&log->LOG_MUTEX);
356
357 return TRUE;
358
359} /* write_safe_log( ... ) */
360
367 if (!log)
368 return FALSE;
369
370 pthread_mutex_lock(&log->LOG_MUTEX);
371 fflush(log->file);
372 pthread_mutex_unlock(&log->LOG_MUTEX);
373
374 pthread_mutex_destroy(&log->LOG_MUTEX);
375
376 fclose(log->file);
377
378 return TRUE;
379
380} /* close_safe_logging( ...) */
#define FreeNoLog(__ptr)
Free Handler without log.
Definition n_common.h:251
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
Definition n_common.h:187
#define __n_assert(__ptr, __ret)
macro to assert things
Definition n_common.h:258
#define _str(__PTR)
define true
Definition n_common.h:176
pthread_mutex_t LOG_MUTEX
mutex for thread-safe writting
Definition n_log.h:77
FILE * file
File handler.
Definition n_log.h:79
#define LOG_ALERT
action must be taken immediately
Definition n_log.h:52
#define LOG_SYSJRNL
to sysjrnl
Definition n_log.h:32
FILE * get_log_file(void)
return the current log_file
Definition n_log.c:143
int write_safe_log(TS_LOG *log, char *pat,...)
write to a thread-safe logging file
Definition n_log.c:338
int open_safe_logging(TS_LOG **log, char *pathname, char *opt)
Open a thread-safe logging file.
Definition n_log.c:272
#define LOG_EMERG
system is unusable
Definition n_log.h:50
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:69
char * open_sysjrnl(char *identity)
Open connection to syslog or create internals for event log.
Definition n_log.c:64
#define LOG_FILE
internal, logging to file
Definition n_log.h:28
void close_sysjrnl(void)
Close syslog connection or clean internals for event log.
Definition n_log.c:80
#define LOG_DEBUG
debug-level messages
Definition n_log.h:64
#define LOG_ERR
error conditions
Definition n_log.h:56
#define LOG_STDERR
internal, default LOG_TYPE
Definition n_log.h:30
#define LOG_CRIT
critical conditions
Definition n_log.h:54
int close_safe_logging(TS_LOG *log)
close a thread-safe logging file
Definition n_log.c:366
int set_log_file(char *file)
Set the logging to a file instead of stderr.
Definition n_log.c:120
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL )
Definition n_log.c:91
#define LOG_NOTICE
normal but significant condition
Definition n_log.h:60
#define LOG_WARNING
warning conditions
Definition n_log.h:58
#define LOG_NULL
no log output
Definition n_log.h:26
#define LOG_INFO
informational
Definition n_log.h:62
void _n_log(int level, const char *file, const char *func, int line, const char *format,...)
Logging function.
Definition n_log.c:213
int get_log_level(void)
Get the global log level value.
Definition n_log.c:111
ThreadSafe LOGging structure.
Definition n_log.h:75
Common headers and low-level functions & define.
static LOG_LEVELS prioritynames[]
array of log levels
Definition n_log.c:35
char * proc_name
static proc name, for windows event log
Definition n_log.c:57
int c_val
numeric value of log type
Definition n_log.c:28
static int LOG_LEVEL
static global maximum wanted log level value
Definition n_log.c:48
static int LOG_TYPE
static global logging type ( STDERR, FILE, SYSJRNL )
Definition n_log.c:51
int vasprintf(char **strp, const char *fmt, va_list ap)
snprintf from a va_list, helper for asprintf
Definition n_log.c:172
int asprintf(char *strp[], const char *fmt,...)
snprintf from a va_list
Definition n_log.c:196
static FILE * log_file
static FILE handling if logging to file is enabled
Definition n_log.c:54
char * w_name
event log value
Definition n_log.c:30
char * c_name
string of log type
Definition n_log.c:26
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:154
internal struct to handle log types
Definition n_log.c:24
Generic log system.