/src/open62541/plugins/ua_log_stdout.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 2016-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer) |
5 | | * Copyright 2017 (c) Thomas Stalder, Blue Time Concept SA |
6 | | */ |
7 | | |
8 | | #include <open62541/plugin/log_stdout.h> |
9 | | #include <open62541/types.h> |
10 | | |
11 | | #include <stdio.h> |
12 | | |
13 | | #include "mp_printf.h" |
14 | | |
15 | | /* ANSI escape sequences for color output taken from here: |
16 | | * https://stackoverflow.com/questions/3219393/stdlib-and-colored-output-in-c*/ |
17 | | |
18 | | #ifdef UA_ARCHITECTURE_POSIX |
19 | | # define ANSI_COLOR_RED "\x1b[31m" |
20 | | # define ANSI_COLOR_GREEN "\x1b[32m" |
21 | | # define ANSI_COLOR_YELLOW "\x1b[33m" |
22 | | # define ANSI_COLOR_BLUE "\x1b[34m" |
23 | | # define ANSI_COLOR_MAGENTA "\x1b[35m" |
24 | | # define ANSI_COLOR_CYAN "\x1b[36m" |
25 | | # define ANSI_COLOR_RESET "\x1b[0m" |
26 | | #else |
27 | | # define ANSI_COLOR_RED "" |
28 | | # define ANSI_COLOR_GREEN "" |
29 | | # define ANSI_COLOR_YELLOW "" |
30 | | # define ANSI_COLOR_BLUE "" |
31 | | # define ANSI_COLOR_MAGENTA "" |
32 | | # define ANSI_COLOR_CYAN "" |
33 | | # define ANSI_COLOR_RESET "" |
34 | | #endif |
35 | | |
36 | | static |
37 | | const char *logLevelNames[6] = {"trace", "debug", |
38 | | ANSI_COLOR_GREEN "info", |
39 | | ANSI_COLOR_YELLOW "warn", |
40 | | ANSI_COLOR_RED "error", |
41 | | ANSI_COLOR_MAGENTA "fatal"}; |
42 | | static const char * |
43 | | logCategoryNames[UA_LOGCATEGORIES] = |
44 | | {"network", "channel", "session", "server", "client", |
45 | | "userland", "security", "eventloop", "pubsub", "discovery"}; |
46 | | |
47 | | /* Protect crosstalk during logging via global lock. Use a spinlock as we cannot |
48 | | * statically initialize a global lock across all platforms. */ |
49 | | #if UA_MULTITHREADING >= 100 |
50 | | void *logSpinLock = NULL; |
51 | 0 | static UA_INLINE void spinLock(void) { |
52 | 0 | while(UA_atomic_cmpxchg(&logSpinLock, NULL, (void*)0x1) != NULL) {} |
53 | 0 | } |
54 | 0 | static UA_INLINE void spinUnLock(void) { |
55 | 0 | UA_atomic_xchg(&logSpinLock, NULL); |
56 | 0 | } |
57 | | #endif |
58 | | |
59 | | #ifdef __clang__ |
60 | | __attribute__((__format__(__printf__, 4 , 0))) |
61 | | #endif |
62 | | static void |
63 | | UA_Log_Stdout_log(void *context, UA_LogLevel level, UA_LogCategory category, |
64 | 0 | const char *msg, va_list args) { |
65 | | /* MinLevel encoded in the context pointer */ |
66 | 0 | UA_LogLevel minLevel = (UA_LogLevel)(uintptr_t)context; |
67 | 0 | if(minLevel > level) |
68 | 0 | return; |
69 | | |
70 | 0 | UA_Int64 tOffset = UA_DateTime_localTimeUtcOffset(); |
71 | 0 | UA_DateTimeStruct dts = UA_DateTime_toStruct(UA_DateTime_now() + tOffset); |
72 | |
|
73 | 0 | int logLevelSlot = ((int)level / 100) - 1; |
74 | 0 | if(logLevelSlot < 0 || logLevelSlot > 5) |
75 | 0 | logLevelSlot = 5; /* Set to fatal if the level is outside the range */ |
76 | | |
77 | | /* Lock */ |
78 | 0 | #if UA_MULTITHREADING >= 100 |
79 | 0 | spinLock(); |
80 | 0 | #endif |
81 | |
|
82 | 0 | #define STDOUT_LOGBUFSIZE 512 |
83 | 0 | char logbuf[STDOUT_LOGBUFSIZE]; |
84 | | |
85 | | /* Log */ |
86 | 0 | printf("[%04u-%02u-%02u %02u:%02u:%02u.%03u (UTC%+05d)] %s/%s" ANSI_COLOR_RESET "\t", |
87 | 0 | dts.year, dts.month, dts.day, dts.hour, dts.min, dts.sec, dts.milliSec, |
88 | 0 | (int)(tOffset / UA_DATETIME_SEC / 36), logLevelNames[logLevelSlot], |
89 | 0 | logCategoryNames[category]); |
90 | 0 | mp_vsnprintf(logbuf, STDOUT_LOGBUFSIZE, msg, args); |
91 | 0 | printf("%s\n", logbuf); |
92 | 0 | fflush(stdout); |
93 | | |
94 | | /* Unlock */ |
95 | 0 | #if UA_MULTITHREADING >= 100 |
96 | 0 | spinUnLock(); |
97 | 0 | #endif |
98 | 0 | } |
99 | | |
100 | | static void |
101 | 225 | UA_Log_Stdout_clear(UA_Logger *logger) { |
102 | 225 | UA_free(logger); |
103 | 225 | } |
104 | | |
105 | | const UA_Logger UA_Log_Stdout_ = {UA_Log_Stdout_log, NULL, NULL}; |
106 | | const UA_Logger *UA_Log_Stdout = &UA_Log_Stdout_; |
107 | | |
108 | | UA_Logger |
109 | 225 | UA_Log_Stdout_withLevel(UA_LogLevel minlevel) { |
110 | 225 | UA_Logger logger = |
111 | 225 | {UA_Log_Stdout_log, (void*)(uintptr_t)minlevel, NULL}; |
112 | 225 | return logger; |
113 | 225 | } |
114 | | |
115 | | UA_Logger * |
116 | 225 | UA_Log_Stdout_new(UA_LogLevel minlevel) { |
117 | 225 | UA_Logger *logger = (UA_Logger*)UA_malloc(sizeof(UA_Logger)); |
118 | 225 | if(!logger) |
119 | 0 | return NULL; |
120 | 225 | *logger = UA_Log_Stdout_withLevel(minlevel); |
121 | 225 | logger->clear = UA_Log_Stdout_clear; |
122 | 225 | return logger; |
123 | 225 | } |