Coverage Report

Created: 2026-09-27 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541_15/plugins/ua_log_stdout.c
Line
Count
Source
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
     "application", "security", "eventloop", "pubsub", "discovery"};
46
47
static const char *
48
272
logCategoryName(UA_LogCategory category) {
49
272
    if((UA_UInt32)category >= UA_LOGCATEGORIES)
50
0
        return "unknown";
51
272
    return logCategoryNames[category];
52
272
}
53
54
/* Protect crosstalk during logging via global lock. Use a spinlock as we cannot
55
 * statically initialize a global lock across all platforms. */
56
#if UA_MULTITHREADING >= 100
57
static void *logSpinLock = NULL;
58
272
static UA_INLINE void spinLock(void) {
59
272
    while(UA_atomic_cmpxchg(&logSpinLock, NULL, (void*)0x1) != NULL) {}
60
272
}
61
536
static UA_INLINE void spinUnLock(void) {
62
536
    UA_atomic_xchg(&logSpinLock, NULL);
63
536
}
64
#endif
65
66
#ifdef __clang__
67
__attribute__((__format__(__printf__, 4 , 0)))
68
#endif
69
static void
70
UA_Log_Stdout_log(void *context, UA_LogLevel level, UA_LogCategory category,
71
536
                  const char *msg, va_list args) {
72
    /* MinLevel encoded in the context pointer */
73
536
    UA_LogLevel minLevel = (UA_LogLevel)(uintptr_t)context;
74
536
    if(minLevel > level)
75
0
        return;
76
77
536
    UA_Int64 tOffset = UA_DateTime_localTimeUtcOffset();
78
536
    UA_DateTimeStruct dts = UA_DateTime_toStruct(UA_DateTime_now() + tOffset);
79
80
536
    int logLevelSlot = ((int)level / 100) - 1;
81
536
    if(logLevelSlot < 0 || logLevelSlot > 5)
82
0
        logLevelSlot = 5; /* Set to fatal if the level is outside the range */
83
84
    /* Lock */
85
536
#if UA_MULTITHREADING >= 100
86
536
    spinLock();
87
536
#endif
88
89
536
#define STDOUT_LOGBUFSIZE 512
90
536
    char logbuf[STDOUT_LOGBUFSIZE];
91
92
    /* Log */
93
536
    printf("[%04u-%02u-%02u %02u:%02u:%02u.%03u (UTC%+05d)] %s/%s" ANSI_COLOR_RESET "\t",
94
536
           dts.year, dts.month, dts.day, dts.hour, dts.min, dts.sec, dts.milliSec,
95
536
           (int)(tOffset / UA_DATETIME_SEC / 36), logLevelNames[logLevelSlot],
96
536
           logCategoryName(category));
97
536
    mp_vsnprintf(logbuf, STDOUT_LOGBUFSIZE, msg, args);
98
536
    printf("%s\n", logbuf);
99
536
    fflush(stdout);
100
101
    /* Unlock */
102
536
#if UA_MULTITHREADING >= 100
103
536
    spinUnLock();
104
536
#endif
105
536
}
106
107
static void
108
20.6k
UA_Log_Stdout_clear(UA_Logger *logger) {
109
20.6k
    UA_free(logger);
110
20.6k
}
111
112
const UA_Logger UA_Log_Stdout_ = {UA_Log_Stdout_log, NULL, NULL};
113
const UA_Logger *UA_Log_Stdout = &UA_Log_Stdout_;
114
115
UA_Logger
116
20.6k
UA_Log_Stdout_withLevel(UA_LogLevel minlevel) {
117
20.6k
    UA_Logger logger =
118
20.6k
        {UA_Log_Stdout_log, (void*)(uintptr_t)minlevel, NULL};
119
20.6k
    return logger;
120
20.6k
}
121
122
UA_Logger *
123
20.6k
UA_Log_Stdout_new(UA_LogLevel minlevel) {
124
20.6k
    UA_Logger *logger = (UA_Logger*)UA_malloc(sizeof(UA_Logger));
125
20.6k
    if(!logger)
126
0
        return NULL;
127
20.6k
    *logger = UA_Log_Stdout_withLevel(minlevel);
128
20.6k
    logger->clear = UA_Log_Stdout_clear;
129
20.6k
    return logger;
130
20.6k
}