master
c 151 lines 5.78 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "nd_log-internals.h"
4
5 static bool needs_quotes_for_logfmt(const char *s)
6 {
7 static bool safe_for_logfmt[256] = {
8 [' '] = true, ['!'] = true, ['"'] = false, ['#'] = true, ['$'] = true, ['%'] = true, ['&'] = true,
9 ['\''] = true, ['('] = true, [')'] = true, ['*'] = true, ['+'] = true, [','] = true, ['-'] = true,
10 ['.'] = true, ['/'] = true, ['0'] = true, ['1'] = true, ['2'] = true, ['3'] = true, ['4'] = true,
11 ['5'] = true, ['6'] = true, ['7'] = true, ['8'] = true, ['9'] = true, [':'] = true, [';'] = true,
12 ['<'] = true, ['='] = true, ['>'] = true, ['?'] = true, ['@'] = true, ['A'] = true, ['B'] = true,
13 ['C'] = true, ['D'] = true, ['E'] = true, ['F'] = true, ['G'] = true, ['H'] = true, ['I'] = true,
14 ['J'] = true, ['K'] = true, ['L'] = true, ['M'] = true, ['N'] = true, ['O'] = true, ['P'] = true,
15 ['Q'] = true, ['R'] = true, ['S'] = true, ['T'] = true, ['U'] = true, ['V'] = true, ['W'] = true,
16 ['X'] = true, ['Y'] = true, ['Z'] = true, ['['] = true, ['\\'] = false, [']'] = true, ['^'] = true,
17 ['_'] = true, ['`'] = true, ['a'] = true, ['b'] = true, ['c'] = true, ['d'] = true, ['e'] = true,
18 ['f'] = true, ['g'] = true, ['h'] = true, ['i'] = true, ['j'] = true, ['k'] = true, ['l'] = true,
19 ['m'] = true, ['n'] = true, ['o'] = true, ['p'] = true, ['q'] = true, ['r'] = true, ['s'] = true,
20 ['t'] = true, ['u'] = true, ['v'] = true, ['w'] = true, ['x'] = true, ['y'] = true, ['z'] = true,
21 ['{'] = true, ['|'] = true, ['}'] = true, ['~'] = true, [0x7f] = true,
22 };
23
24 if(!*s)
25 return true;
26
27 while(*s) {
28 if(*s == '=' || isspace((uint8_t)*s) || !safe_for_logfmt[(uint8_t)*s])
29 return true;
30
31 s++;
32 }
33
34 return false;
35 }
36
37 static void string_to_logfmt(BUFFER *wb, const char *s)
38 {
39 bool spaces = needs_quotes_for_logfmt(s);
40
41 if(spaces)
42 buffer_fast_strcat(wb, "\"", 1);
43
44 buffer_json_strcat(wb, s);
45
46 if(spaces)
47 buffer_fast_strcat(wb, "\"", 1);
48 }
49
50 void nd_logger_logfmt(BUFFER *wb, struct log_field *fields, size_t fields_max) {
51
52 // --- FIELD_PARSER_VERSIONS ---
53 //
54 // IMPORTANT:
55 // THERE ARE 6 VERSIONS OF THIS CODE
56 //
57 // 1. journal (direct socket API),
58 // 2. journal (libsystemd API),
59 // 3. logfmt,
60 // 4. json,
61 // 5. convert to uint64
62 // 6. convert to int64
63 //
64 // UPDATE ALL OF THEM FOR NEW FEATURES OR FIXES
65
66 CLEAN_BUFFER *tmp = NULL;
67
68 for (size_t i = 0; i < fields_max; i++) {
69 if (!fields[i].entry.set || !fields[i].logfmt)
70 continue;
71
72 const char *key = fields[i].logfmt;
73
74 if(fields[i].logfmt_annotator) {
75 const char *s = fields[i].logfmt_annotator(&fields[i]);
76 if(!s) continue;
77
78 if(buffer_strlen(wb))
79 buffer_fast_strcat(wb, " ", 1);
80
81 buffer_strcat(wb, key);
82 buffer_fast_strcat(wb, "=", 1);
83 string_to_logfmt(wb, s);
84 }
85 else {
86 if(buffer_strlen(wb))
87 buffer_fast_strcat(wb, " ", 1);
88
89 switch(fields[i].entry.type) {
90 case NDFT_TXT:
91 if(*fields[i].entry.txt) {
92 buffer_strcat(wb, key);
93 buffer_fast_strcat(wb, "=", 1);
94 string_to_logfmt(wb, fields[i].entry.txt);
95 }
96 break;
97 case NDFT_STR:
98 buffer_strcat(wb, key);
99 buffer_fast_strcat(wb, "=", 1);
100 string_to_logfmt(wb, string2str(fields[i].entry.str));
101 break;
102 case NDFT_BFR:
103 if(buffer_strlen(fields[i].entry.bfr)) {
104 buffer_strcat(wb, key);
105 buffer_fast_strcat(wb, "=", 1);
106 string_to_logfmt(wb, buffer_tostring(fields[i].entry.bfr));
107 }
108 break;
109 case NDFT_U64:
110 buffer_strcat(wb, key);
111 buffer_fast_strcat(wb, "=", 1);
112 buffer_print_uint64(wb, fields[i].entry.u64);
113 break;
114 case NDFT_I64:
115 buffer_strcat(wb, key);
116 buffer_fast_strcat(wb, "=", 1);
117 buffer_print_int64(wb, fields[i].entry.i64);
118 break;
119 case NDFT_DBL:
120 buffer_strcat(wb, key);
121 buffer_fast_strcat(wb, "=", 1);
122 buffer_print_netdata_double(wb, fields[i].entry.dbl);
123 break;
124 case NDFT_UUID:
125 if(!uuid_is_null(*fields[i].entry.uuid)) {
126 char u[UUID_COMPACT_STR_LEN];
127 uuid_unparse_lower_compact(*fields[i].entry.uuid, u);
128 buffer_strcat(wb, key);
129 buffer_fast_strcat(wb, "=", 1);
130 buffer_fast_strcat(wb, u, sizeof(u) - 1);
131 }
132 break;
133 case NDFT_CALLBACK: {
134 if(!tmp)
135 tmp = buffer_create(1024, NULL);
136 else
137 buffer_flush(tmp);
138 if(fields[i].entry.cb.formatter(tmp, fields[i].entry.cb.formatter_data)) {
139 buffer_strcat(wb, key);
140 buffer_fast_strcat(wb, "=", 1);
141 string_to_logfmt(wb, buffer_tostring(tmp));
142 }
143 }
144 break;
145 default:
146 buffer_strcat(wb, "UNHANDLED");
147 break;
148 }
149 }
150 }
151 }