/src/open62541/plugins/ua_log_syslog.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* This work is licensed under a Creative Commons CCZero 1.0 Universal License. |
2 | | * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. |
3 | | * |
4 | | * Copyright 2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer) |
5 | | */ |
6 | | |
7 | | #include <open62541/plugin/log_syslog.h> |
8 | | #include <open62541/types.h> |
9 | | |
10 | | #if defined(__linux__) || defined(__unix__) |
11 | | |
12 | | #include <syslog.h> |
13 | | #include <stdio.h> |
14 | | #include "mp_printf.h" |
15 | | |
16 | | const char *syslogLevelNames[6] = {"trace", "debug", "info", |
17 | | "warn", "error", "fatal"}; |
18 | | const char *syslogCategoryNames[UA_LOGCATEGORIES] = |
19 | | {"network", "channel", "session", "server", "client", |
20 | | "userland", "security", "eventloop", "pubsub", "discovery"}; |
21 | | |
22 | | #ifdef __clang__ |
23 | | __attribute__((__format__(__printf__, 4 , 0))) |
24 | | #endif |
25 | | static void |
26 | | UA_Log_Syslog_log(void *context, UA_LogLevel level, UA_LogCategory category, |
27 | 0 | const char *msg, va_list args) { |
28 | | /* Assume that context is casted to UA_LogLevel */ |
29 | 0 | if(context != NULL && (UA_LogLevel)(uintptr_t)context > level) |
30 | 0 | return; |
31 | | |
32 | 0 | int priority = LOG_INFO; |
33 | 0 | switch(level) { |
34 | 0 | case UA_LOGLEVEL_DEBUG: |
35 | 0 | priority = LOG_DEBUG; |
36 | 0 | break; |
37 | 0 | case UA_LOGLEVEL_INFO: |
38 | 0 | priority = LOG_INFO; |
39 | 0 | break; |
40 | 0 | case UA_LOGLEVEL_WARNING: |
41 | 0 | priority = LOG_WARNING; |
42 | 0 | break; |
43 | 0 | case UA_LOGLEVEL_ERROR: |
44 | 0 | priority = LOG_ERR; |
45 | 0 | break; |
46 | 0 | case UA_LOGLEVEL_FATAL: |
47 | 0 | priority = LOG_CRIT; |
48 | 0 | break; |
49 | 0 | case UA_LOGLEVEL_TRACE: |
50 | 0 | default: |
51 | 0 | return; |
52 | 0 | } |
53 | | |
54 | 0 | int logLevelSlot = ((int)level / 100) - 1; |
55 | 0 | if(logLevelSlot < 0 || logLevelSlot > 5) |
56 | 0 | logLevelSlot = 5; /* Set to fatal if the level is outside the range */ |
57 | |
|
58 | 0 | #define LOGBUFSIZE 512 |
59 | 0 | char logbuf[LOGBUFSIZE]; |
60 | 0 | int pos = mp_snprintf(logbuf, LOGBUFSIZE, "[%s/%s] ", |
61 | 0 | syslogLevelNames[logLevelSlot], |
62 | 0 | syslogCategoryNames[category]); |
63 | 0 | if(pos < 0) { |
64 | 0 | syslog(LOG_WARNING, "Log message too long for syslog"); |
65 | 0 | return; |
66 | 0 | } |
67 | 0 | pos = vsnprintf(&logbuf[pos], LOGBUFSIZE - (size_t)pos, msg, args); |
68 | 0 | if(pos < 0) { |
69 | 0 | syslog(LOG_WARNING, "Log message too long for syslog"); |
70 | 0 | return; |
71 | 0 | } |
72 | | |
73 | 0 | syslog(priority, "%s", logbuf); |
74 | 0 | } |
75 | | |
76 | | static void |
77 | 0 | UA_Log_Syslog_clear(UA_Logger *logger) { |
78 | | /* closelog is optional. We don't use it as several loggers might be |
79 | | * instantiated in parallel. */ |
80 | | /* closelog(); */ |
81 | 0 | UA_free(logger); |
82 | 0 | } |
83 | | |
84 | | UA_Logger |
85 | 0 | UA_Log_Syslog(void) { |
86 | 0 | return UA_Log_Syslog_withLevel(UA_LOGLEVEL_TRACE); |
87 | 0 | } |
88 | | |
89 | | UA_Logger |
90 | 0 | UA_Log_Syslog_withLevel(UA_LogLevel minlevel) { |
91 | 0 | UA_Logger logger = {UA_Log_Syslog_log, (void*)(uintptr_t)minlevel, NULL}; |
92 | 0 | return logger; |
93 | 0 | } |
94 | | |
95 | | UA_Logger * |
96 | 0 | UA_Log_Syslog_new(UA_LogLevel minlevel) { |
97 | 0 | UA_Logger *logger = (UA_Logger*)UA_malloc(sizeof(UA_Logger)); |
98 | 0 | if(!logger) |
99 | 0 | return NULL; |
100 | 0 | *logger = UA_Log_Syslog_withLevel(minlevel); |
101 | 0 | logger->clear = UA_Log_Syslog_clear; |
102 | 0 | return logger; |
103 | 0 | } |
104 | | |
105 | | #endif |