Coverage Report

Created: 2025-07-01 07:01

/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
}