Tests: Fix: Use '.logfile' instead of '.log' for test app output
[lttng-tools.git] / src / bin / lttng / loglevel.cpp
1 /*
2 * Copyright (C) 2021 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8 #include "loglevel.hpp"
9
10 #include <ctype.h>
11 #include <string.h>
12 #include <strings.h>
13
14 namespace {
15 struct loglevel_name_value {
16 const char *name;
17 int value;
18 };
19 } /* namespace */
20
21 static const struct loglevel_name_value loglevel_values[] = {
22 { .name = "EMERG", .value = LTTNG_LOGLEVEL_EMERG },
23 { .name = "TRACE_EMERG", .value = LTTNG_LOGLEVEL_EMERG },
24 { .name = "ALERT", .value = LTTNG_LOGLEVEL_ALERT },
25 { .name = "TRACE_ALERT", .value = LTTNG_LOGLEVEL_ALERT },
26 { .name = "CRIT", .value = LTTNG_LOGLEVEL_CRIT },
27 { .name = "TRACE_CRIT", .value = LTTNG_LOGLEVEL_CRIT },
28 { .name = "ERR", .value = LTTNG_LOGLEVEL_ERR },
29 { .name = "TRACE_ERR", .value = LTTNG_LOGLEVEL_ERR },
30 { .name = "WARNING", .value = LTTNG_LOGLEVEL_WARNING },
31 { .name = "TRACE_WARNING", .value = LTTNG_LOGLEVEL_WARNING },
32 { .name = "NOTICE", .value = LTTNG_LOGLEVEL_NOTICE },
33 { .name = "TRACE_NOTICE", .value = LTTNG_LOGLEVEL_NOTICE },
34 { .name = "INFO", .value = LTTNG_LOGLEVEL_INFO },
35 { .name = "TRACE_INFO", .value = LTTNG_LOGLEVEL_INFO },
36 { .name = "DEBUG_SYSTEM", .value = LTTNG_LOGLEVEL_DEBUG_SYSTEM },
37 { .name = "TRACE_DEBUG_SYSTEM", .value = LTTNG_LOGLEVEL_DEBUG_SYSTEM },
38 { .name = "SYSTEM", .value = LTTNG_LOGLEVEL_DEBUG_SYSTEM },
39 { .name = "DEBUG_PROGRAM", .value = LTTNG_LOGLEVEL_DEBUG_PROGRAM },
40 { .name = "TRACE_DEBUG_PROGRAM", .value = LTTNG_LOGLEVEL_DEBUG_PROGRAM },
41 { .name = "PROGRAM", .value = LTTNG_LOGLEVEL_DEBUG_PROGRAM },
42 { .name = "DEBUG_PROCESS", .value = LTTNG_LOGLEVEL_DEBUG_PROCESS },
43 { .name = "TRACE_DEBUG_PROCESS", .value = LTTNG_LOGLEVEL_DEBUG_PROCESS },
44 { .name = "PROCESS", .value = LTTNG_LOGLEVEL_DEBUG_PROCESS },
45 { .name = "DEBUG_MODULE", .value = LTTNG_LOGLEVEL_DEBUG_MODULE },
46 { .name = "TRACE_DEBUG_MODULE", .value = LTTNG_LOGLEVEL_DEBUG_MODULE },
47 { .name = "MODULE", .value = LTTNG_LOGLEVEL_DEBUG_MODULE },
48 { .name = "DEBUG_UNIT", .value = LTTNG_LOGLEVEL_DEBUG_UNIT },
49 { .name = "TRACE_DEBUG_UNIT", .value = LTTNG_LOGLEVEL_DEBUG_UNIT },
50 { .name = "UNIT", .value = LTTNG_LOGLEVEL_DEBUG_UNIT },
51 { .name = "DEBUG_FUNCTION", .value = LTTNG_LOGLEVEL_DEBUG_FUNCTION },
52 { .name = "TRACE_DEBUG_FUNCTION", .value = LTTNG_LOGLEVEL_DEBUG_FUNCTION },
53 { .name = "FUNCTION", .value = LTTNG_LOGLEVEL_DEBUG_FUNCTION },
54 { .name = "DEBUG_LINE", .value = LTTNG_LOGLEVEL_DEBUG_LINE },
55 { .name = "TRACE_DEBUG_LINE", .value = LTTNG_LOGLEVEL_DEBUG_LINE },
56 { .name = "LINE", .value = LTTNG_LOGLEVEL_DEBUG_LINE },
57 { .name = "DEBUG", .value = LTTNG_LOGLEVEL_DEBUG },
58 { .name = "TRACE_DEBUG", .value = LTTNG_LOGLEVEL_DEBUG },
59 };
60
61 static const struct loglevel_name_value loglevel_log4j_values[] = {
62 { .name = "OFF", .value = LTTNG_LOGLEVEL_LOG4J_OFF },
63 { .name = "LOG4J_OFF", .value = LTTNG_LOGLEVEL_LOG4J_OFF },
64 { .name = "FATAL", .value = LTTNG_LOGLEVEL_LOG4J_FATAL },
65 { .name = "LOG4J_FATAL", .value = LTTNG_LOGLEVEL_LOG4J_FATAL },
66 { .name = "ERROR", .value = LTTNG_LOGLEVEL_LOG4J_ERROR },
67 { .name = "LOG4J_ERROR", .value = LTTNG_LOGLEVEL_LOG4J_ERROR },
68 { .name = "WARN", .value = LTTNG_LOGLEVEL_LOG4J_WARN },
69 { .name = "LOG4J_WARN", .value = LTTNG_LOGLEVEL_LOG4J_WARN },
70 { .name = "INFO", .value = LTTNG_LOGLEVEL_LOG4J_INFO },
71 { .name = "LOG4J_INFO", .value = LTTNG_LOGLEVEL_LOG4J_INFO },
72 { .name = "DEBUG", .value = LTTNG_LOGLEVEL_LOG4J_DEBUG },
73 { .name = "LOG4J_DEBUG", .value = LTTNG_LOGLEVEL_LOG4J_DEBUG },
74 { .name = "TRACE", .value = LTTNG_LOGLEVEL_LOG4J_TRACE },
75 { .name = "LOG4J_TRACE", .value = LTTNG_LOGLEVEL_LOG4J_TRACE },
76 { .name = "ALL", .value = LTTNG_LOGLEVEL_LOG4J_ALL },
77 { .name = "LOG4J_ALL", .value = LTTNG_LOGLEVEL_LOG4J_ALL },
78 };
79
80 static const struct loglevel_name_value loglevel_log4j2_values[] = {
81 { .name = "OFF", .value = LTTNG_LOGLEVEL_LOG4J2_OFF },
82 { .name = "LOG4J2_OFF", .value = LTTNG_LOGLEVEL_LOG4J2_OFF },
83 { .name = "FATAL", .value = LTTNG_LOGLEVEL_LOG4J2_FATAL },
84 { .name = "LOG4J2_FATAL", .value = LTTNG_LOGLEVEL_LOG4J2_FATAL },
85 { .name = "ERROR", .value = LTTNG_LOGLEVEL_LOG4J2_ERROR },
86 { .name = "LOG4J2_ERROR", .value = LTTNG_LOGLEVEL_LOG4J2_ERROR },
87 { .name = "WARN", .value = LTTNG_LOGLEVEL_LOG4J2_WARN },
88 { .name = "LOG4J2_WARN", .value = LTTNG_LOGLEVEL_LOG4J2_WARN },
89 { .name = "INFO", .value = LTTNG_LOGLEVEL_LOG4J2_INFO },
90 { .name = "LOG4J2_INFO", .value = LTTNG_LOGLEVEL_LOG4J2_INFO },
91 { .name = "DEBUG", .value = LTTNG_LOGLEVEL_LOG4J2_DEBUG },
92 { .name = "LOG4J2_DEBUG", .value = LTTNG_LOGLEVEL_LOG4J2_DEBUG },
93 { .name = "TRACE", .value = LTTNG_LOGLEVEL_LOG4J2_TRACE },
94 { .name = "LOG4J2_TRACE", .value = LTTNG_LOGLEVEL_LOG4J2_TRACE },
95 { .name = "ALL", .value = LTTNG_LOGLEVEL_LOG4J2_ALL },
96 { .name = "LOG4J2_ALL", .value = LTTNG_LOGLEVEL_LOG4J2_ALL },
97 };
98
99 static const struct loglevel_name_value loglevel_jul_values[] = {
100 { .name = "OFF", .value = LTTNG_LOGLEVEL_JUL_OFF },
101 { .name = "JUL_OFF", .value = LTTNG_LOGLEVEL_JUL_OFF },
102 { .name = "SEVERE", .value = LTTNG_LOGLEVEL_JUL_SEVERE },
103 { .name = "JUL_SEVERE", .value = LTTNG_LOGLEVEL_JUL_SEVERE },
104 { .name = "WARNING", .value = LTTNG_LOGLEVEL_JUL_WARNING },
105 { .name = "JUL_WARNING", .value = LTTNG_LOGLEVEL_JUL_WARNING },
106 { .name = "INFO", .value = LTTNG_LOGLEVEL_JUL_INFO },
107 { .name = "JUL_INFO", .value = LTTNG_LOGLEVEL_JUL_INFO },
108 { .name = "CONFIG", .value = LTTNG_LOGLEVEL_JUL_CONFIG },
109 { .name = "JUL_CONFIG", .value = LTTNG_LOGLEVEL_JUL_CONFIG },
110 { .name = "FINE", .value = LTTNG_LOGLEVEL_JUL_FINE },
111 { .name = "JUL_FINE", .value = LTTNG_LOGLEVEL_JUL_FINE },
112 { .name = "FINER", .value = LTTNG_LOGLEVEL_JUL_FINER },
113 { .name = "JUL_FINER", .value = LTTNG_LOGLEVEL_JUL_FINER },
114 { .name = "FINEST", .value = LTTNG_LOGLEVEL_JUL_FINEST },
115 { .name = "JUL_FINEST", .value = LTTNG_LOGLEVEL_JUL_FINEST },
116 { .name = "ALL", .value = LTTNG_LOGLEVEL_JUL_ALL },
117 { .name = "JUL_ALL", .value = LTTNG_LOGLEVEL_JUL_ALL },
118 };
119
120 static const struct loglevel_name_value loglevel_python_values[] = {
121 { .name = "CRITICAL", .value = LTTNG_LOGLEVEL_PYTHON_CRITICAL },
122 { .name = "PYTHON_CRITICAL", .value = LTTNG_LOGLEVEL_PYTHON_CRITICAL },
123 { .name = "ERROR", .value = LTTNG_LOGLEVEL_PYTHON_ERROR },
124 { .name = "PYTHON_ERROR", .value = LTTNG_LOGLEVEL_PYTHON_ERROR },
125 { .name = "WARNING", .value = LTTNG_LOGLEVEL_PYTHON_WARNING },
126 { .name = "PYTHON_WARNING", .value = LTTNG_LOGLEVEL_PYTHON_WARNING },
127 { .name = "INFO", .value = LTTNG_LOGLEVEL_PYTHON_INFO },
128 { .name = "PYTHON_INFO", .value = LTTNG_LOGLEVEL_PYTHON_INFO },
129 { .name = "DEBUG", .value = LTTNG_LOGLEVEL_PYTHON_DEBUG },
130 { .name = "PYTNON_DEBUG", .value = LTTNG_LOGLEVEL_PYTHON_DEBUG },
131 { .name = "NOTSET", .value = LTTNG_LOGLEVEL_PYTHON_NOTSET },
132 { .name = "PYTHON_NOTSET", .value = LTTNG_LOGLEVEL_PYTHON_NOTSET },
133 };
134
135 static bool string_equal_insensitive(const char *a, const char *b)
136 {
137 return strcasecmp(a, b) == 0;
138 }
139
140 static int lookup_value_from_name(const struct loglevel_name_value values[],
141 size_t values_count,
142 const char *name)
143 {
144 size_t i;
145 int ret = -1;
146
147 if (!name) {
148 goto end;
149 }
150
151 for (i = 0; i < values_count; i++) {
152 if (string_equal_insensitive(values[i].name, name)) {
153 /* Match found. */
154 ret = values[i].value;
155 goto end;
156 }
157 }
158
159 end:
160 return ret;
161 }
162
163 static bool loglevel_parse_range_string_common(const char *str,
164 const struct loglevel_name_value *nvs,
165 size_t nvs_count,
166 int default_most_severe,
167 int *least_severe,
168 int *most_severe)
169 {
170 bool ret;
171 int i;
172 const struct loglevel_name_value *nv;
173
174 /*
175 * Look for a valid loglevel name value at the beginning of 'str'.
176 */
177 for (i = 0; i < nvs_count; i++) {
178 nv = &nvs[i];
179
180 if (strncmp(str, nv->name, strlen(nv->name)) == 0) {
181 break;
182 }
183 }
184
185 /*
186 * Found no valid loglevel name value at the beginning of 'str'.
187 */
188 if (i == nvs_count) {
189 goto error;
190 }
191
192 /*
193 * Record the least_severe value and skip over the loglevel name found
194 * previously.
195 */
196 *least_severe = nv->value;
197 str += strlen(nv->name);
198
199 /*
200 * If we are at the end of 'str', only one loglevel name was specified,
201 * it is also the most_severe.
202 */
203 if (*str == '\0') {
204 *most_severe = nv->value;
205 ret = true;
206 goto end;
207 }
208
209 /*
210 * Invalid 'str', no loglevel name separator.
211 */
212 if (strncmp(str, "..", strlen("..")) != 0) {
213 goto error;
214 }
215
216 str += strlen("..");
217
218 /*
219 * If we are at the end of 'str' after the separator, set the default
220 * most_severe value for the domain as the most_severe.
221 */
222 if (*str == '\0') {
223 *most_severe = default_most_severe;
224 ret = true;
225 goto end;
226 }
227
228 /*
229 * Look for a valid loglevel name value after the separator in 'str'.
230 */
231 for (i = 0; i < nvs_count; i++) {
232 nv = &nvs[i];
233
234 if (strcmp(str, nv->name) == 0) {
235 break;
236 }
237 }
238
239 /*
240 * Found no valid loglevel name value after the separator.
241 */
242 if (i == nvs_count) {
243 goto error;
244 }
245
246 /*
247 * Record the most_severe value for the loglevel found in 'str'.
248 */
249 *most_severe = nv->value;
250
251 ret = true;
252 goto end;
253
254 error:
255 ret = false;
256
257 end:
258 return ret;
259 }
260
261 int loglevel_name_to_value(const char *name, enum lttng_loglevel *loglevel)
262 {
263 int ret = lookup_value_from_name(loglevel_values, ARRAY_SIZE(loglevel_values), name);
264
265 if (ret >= 0) {
266 *loglevel = (typeof(*loglevel)) ret;
267 ret = 0;
268 }
269
270 return ret;
271 }
272
273 bool loglevel_parse_range_string(const char *str,
274 enum lttng_loglevel *least_severe,
275 enum lttng_loglevel *most_severe)
276 {
277 int least_severe_int, most_severe_int;
278 const bool ret = loglevel_parse_range_string_common(str,
279 loglevel_values,
280 ARRAY_SIZE(loglevel_values),
281 LTTNG_LOGLEVEL_EMERG,
282 &least_severe_int,
283 &most_severe_int);
284
285 *least_severe = (lttng_loglevel) least_severe_int;
286 *most_severe = (lttng_loglevel) most_severe_int;
287
288 return ret;
289 }
290
291 int loglevel_log4j_name_to_value(const char *name, enum lttng_loglevel_log4j *loglevel)
292 {
293 int ret = lookup_value_from_name(
294 loglevel_log4j_values, ARRAY_SIZE(loglevel_log4j_values), name);
295
296 if (ret >= 0) {
297 *loglevel = (typeof(*loglevel)) ret;
298 ret = 0;
299 }
300
301 return ret;
302 }
303
304 bool loglevel_log4j_parse_range_string(const char *str,
305 enum lttng_loglevel_log4j *least_severe,
306 enum lttng_loglevel_log4j *most_severe)
307 {
308 int least_severe_int, most_severe_int;
309 const bool ret = loglevel_parse_range_string_common(str,
310 loglevel_log4j_values,
311 ARRAY_SIZE(loglevel_log4j_values),
312 LTTNG_LOGLEVEL_LOG4J_FATAL,
313 &least_severe_int,
314 &most_severe_int);
315
316 *least_severe = (lttng_loglevel_log4j) least_severe_int;
317 *most_severe = (lttng_loglevel_log4j) most_severe_int;
318
319 return ret;
320 }
321
322 int loglevel_log4j2_name_to_value(const char *name, enum lttng_loglevel_log4j2 *loglevel)
323 {
324 int ret = lookup_value_from_name(
325 loglevel_log4j2_values, ARRAY_SIZE(loglevel_log4j2_values), name);
326
327 if (ret >= 0) {
328 *loglevel = (typeof(*loglevel)) ret;
329 ret = 0;
330 }
331
332 return ret;
333 }
334
335 bool loglevel_log4j2_parse_range_string(const char *str,
336 enum lttng_loglevel_log4j2 *least_severe,
337 enum lttng_loglevel_log4j2 *most_severe)
338 {
339 int least_severe_int, most_severe_int;
340 bool ret = loglevel_parse_range_string_common(str,
341 loglevel_log4j2_values,
342 ARRAY_SIZE(loglevel_log4j2_values),
343 LTTNG_LOGLEVEL_LOG4J2_FATAL,
344 &least_severe_int,
345 &most_severe_int);
346
347 *least_severe = (lttng_loglevel_log4j2) least_severe_int;
348 *most_severe = (lttng_loglevel_log4j2) most_severe_int;
349
350 return ret;
351 }
352
353 int loglevel_jul_name_to_value(const char *name, enum lttng_loglevel_jul *loglevel)
354 {
355 int ret =
356 lookup_value_from_name(loglevel_jul_values, ARRAY_SIZE(loglevel_jul_values), name);
357
358 if (ret >= 0) {
359 *loglevel = (typeof(*loglevel)) ret;
360 ret = 0;
361 }
362
363 return ret;
364 }
365
366 bool loglevel_jul_parse_range_string(const char *str,
367 enum lttng_loglevel_jul *least_severe,
368 enum lttng_loglevel_jul *most_severe)
369 {
370 int least_severe_int, most_severe_int;
371 const bool ret = loglevel_parse_range_string_common(str,
372 loglevel_jul_values,
373 ARRAY_SIZE(loglevel_jul_values),
374 LTTNG_LOGLEVEL_JUL_SEVERE,
375 &least_severe_int,
376 &most_severe_int);
377
378 *least_severe = (lttng_loglevel_jul) least_severe_int;
379 *most_severe = (lttng_loglevel_jul) most_severe_int;
380
381 return ret;
382 }
383
384 int loglevel_python_name_to_value(const char *name, enum lttng_loglevel_python *loglevel)
385 {
386 int ret = lookup_value_from_name(
387 loglevel_python_values, ARRAY_SIZE(loglevel_python_values), name);
388
389 if (ret >= 0) {
390 *loglevel = (typeof(*loglevel)) ret;
391 ret = 0;
392 }
393
394 return ret;
395 }
396
397 bool loglevel_python_parse_range_string(const char *str,
398 enum lttng_loglevel_python *least_severe,
399 enum lttng_loglevel_python *most_severe)
400 {
401 int least_severe_int, most_severe_int;
402 const bool ret = loglevel_parse_range_string_common(str,
403 loglevel_python_values,
404 ARRAY_SIZE(loglevel_python_values),
405 LTTNG_LOGLEVEL_PYTHON_CRITICAL,
406 &least_severe_int,
407 &most_severe_int);
408
409 *least_severe = (lttng_loglevel_python) least_severe_int;
410 *most_severe = (lttng_loglevel_python) most_severe_int;
411
412 return ret;
413 }
414
415 static const char *
416 lookup_name_from_value(const struct loglevel_name_value values[], size_t values_count, int loglevel)
417 {
418 size_t i;
419 const char *name = nullptr;
420
421 for (i = 0; i < values_count; i++) {
422 if (values[i].value == loglevel) {
423 /* Match found. */
424 name = values[i].name;
425 goto end;
426 }
427 }
428
429 end:
430 return name;
431 }
432
433 const char *loglevel_value_to_name(int loglevel)
434 {
435 return lookup_name_from_value(loglevel_values, ARRAY_SIZE(loglevel_values), loglevel);
436 }
437
438 const char *loglevel_log4j_value_to_name(int loglevel)
439 {
440 return lookup_name_from_value(
441 loglevel_log4j_values, ARRAY_SIZE(loglevel_log4j_values), loglevel);
442 }
443
444 const char *loglevel_log4j2_value_to_name(int loglevel)
445 {
446 return lookup_name_from_value(
447 loglevel_log4j2_values, ARRAY_SIZE(loglevel_log4j2_values), loglevel);
448 }
449
450 const char *loglevel_jul_value_to_name(int loglevel)
451 {
452 return lookup_name_from_value(
453 loglevel_jul_values, ARRAY_SIZE(loglevel_jul_values), loglevel);
454 }
455
456 const char *loglevel_python_value_to_name(int loglevel)
457 {
458 return lookup_name_from_value(
459 loglevel_python_values, ARRAY_SIZE(loglevel_python_values), loglevel);
460 }
This page took 0.046631 seconds and 5 git commands to generate.