1 /*
2 * Copyright (c) 2018 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #undef _POSIX_C_SOURCE
8 #define _POSIX_C_SOURCE 200809L
9 #include <zephyr/logging/log_output.h>
10 #include <zephyr/logging/log_ctrl.h>
11 #include <zephyr/logging/log_output_custom.h>
12 #include <zephyr/logging/log.h>
13 #include <zephyr/sys/__assert.h>
14 #include <zephyr/sys/cbprintf.h>
15 #include <ctype.h>
16 #include <time.h>
17 #include <stdio.h>
18 #include <stdbool.h>
19
20 #define LOG_COLOR_CODE_DEFAULT "\x1B[0m"
21 #define LOG_COLOR_CODE_RED "\x1B[1;31m"
22 #define LOG_COLOR_CODE_GREEN "\x1B[1;32m"
23 #define LOG_COLOR_CODE_YELLOW "\x1B[1;33m"
24 #define LOG_COLOR_CODE_BLUE "\x1B[1;34m"
25
26 #define HEXDUMP_BYTES_IN_LINE 16
27
28 #define DROPPED_COLOR_PREFIX \
29 COND_CODE_1(CONFIG_LOG_BACKEND_SHOW_COLOR, (LOG_COLOR_CODE_RED), ())
30
31 #define DROPPED_COLOR_POSTFIX \
32 COND_CODE_1(CONFIG_LOG_BACKEND_SHOW_COLOR, (LOG_COLOR_CODE_DEFAULT), ())
33
34 static const char *const severity[] = {
35 NULL,
36 "err",
37 "wrn",
38 "inf",
39 "dbg"
40 };
41
42 static const char *const colors[] = {
43 NULL,
44 IS_ENABLED(CONFIG_LOG_BACKEND_SHOW_COLOR) ? LOG_COLOR_CODE_RED : NULL, /* err */
45 IS_ENABLED(CONFIG_LOG_BACKEND_SHOW_COLOR) ? LOG_COLOR_CODE_YELLOW : NULL, /* warn */
46 IS_ENABLED(CONFIG_LOG_INFO_COLOR_GREEN) ? LOG_COLOR_CODE_GREEN : NULL, /* info */
47 IS_ENABLED(CONFIG_LOG_DBG_COLOR_BLUE) ? LOG_COLOR_CODE_BLUE : NULL, /* dbg */
48 };
49
50 static uint32_t freq;
51 static log_timestamp_t timestamp_div;
52
53 /* The RFC 5424 allows very flexible mapping and suggest the value 0 being the
54 * highest severity and 7 to be the lowest (debugging level) severity.
55 *
56 * 0 Emergency System is unusable
57 * 1 Alert Action must be taken immediately
58 * 2 Critical Critical conditions
59 * 3 Error Error conditions
60 * 4 Warning Warning conditions
61 * 5 Notice Normal but significant condition
62 * 6 Informational Informational messages
63 * 7 Debug Debug-level messages
64 */
level_to_rfc5424_severity(uint32_t level)65 static int level_to_rfc5424_severity(uint32_t level)
66 {
67 uint8_t ret;
68
69 switch (level) {
70 case LOG_LEVEL_NONE:
71 ret = 7U;
72 break;
73 case LOG_LEVEL_ERR:
74 ret = 3U;
75 break;
76 case LOG_LEVEL_WRN:
77 ret = 4U;
78 break;
79 case LOG_LEVEL_INF:
80 ret = 6U;
81 break;
82 case LOG_LEVEL_DBG:
83 ret = 7U;
84 break;
85 default:
86 ret = 7U;
87 break;
88 }
89
90 return ret;
91 }
92
out_func(int c,void * ctx)93 static int out_func(int c, void *ctx)
94 {
95 const struct log_output *out_ctx = (const struct log_output *)ctx;
96 int idx;
97
98 if (IS_ENABLED(CONFIG_LOG_MODE_IMMEDIATE)) {
99 /* Backend must be thread safe in synchronous operation. */
100 /* Need that step for big endian */
101 char x = (char)c;
102
103 out_ctx->func((uint8_t *)&x, 1, out_ctx->control_block->ctx);
104 return 0;
105 }
106
107 if (out_ctx->control_block->offset == out_ctx->size) {
108 log_output_flush(out_ctx);
109 }
110
111 idx = atomic_inc(&out_ctx->control_block->offset);
112 out_ctx->buf[idx] = (uint8_t)c;
113
114 __ASSERT_NO_MSG(out_ctx->control_block->offset <= out_ctx->size);
115
116 return 0;
117 }
118
cr_out_func(int c,void * ctx)119 static int cr_out_func(int c, void *ctx)
120 {
121 if (c == '\n') {
122 out_func((int)'\r', ctx);
123 }
124 out_func(c, ctx);
125
126 return 0;
127 }
128
print_formatted(const struct log_output * output,const char * fmt,...)129 static int print_formatted(const struct log_output *output,
130 const char *fmt, ...)
131 {
132 va_list args;
133 int length = 0;
134
135 va_start(args, fmt);
136 length = cbvprintf(out_func, (void *)output, fmt, args);
137 va_end(args);
138
139 return length;
140 }
141
timestamp_print(const struct log_output * output,uint32_t flags,log_timestamp_t timestamp)142 static int timestamp_print(const struct log_output *output,
143 uint32_t flags, log_timestamp_t timestamp)
144 {
145 int length;
146 bool format =
147 (flags & LOG_OUTPUT_FLAG_FORMAT_TIMESTAMP) |
148 (flags & LOG_OUTPUT_FLAG_FORMAT_SYSLOG) |
149 IS_ENABLED(CONFIG_LOG_OUTPUT_FORMAT_LINUX_TIMESTAMP) |
150 IS_ENABLED(CONFIG_LOG_OUTPUT_FORMAT_CUSTOM_TIMESTAMP);
151
152
153 if (!format) {
154 #ifndef CONFIG_LOG_TIMESTAMP_64BIT
155 length = print_formatted(output, "[%08lu] ", timestamp);
156 #else
157 length = print_formatted(output, "[%016llu] ", timestamp);
158 #endif
159 } else if (freq != 0U) {
160 #ifndef CONFIG_LOG_TIMESTAMP_64BIT
161 uint32_t total_seconds;
162 #else
163 uint64_t total_seconds;
164 #endif
165 uint32_t remainder;
166 uint32_t ms;
167 uint32_t us;
168
169 timestamp /= timestamp_div;
170 total_seconds = timestamp / freq;
171
172 remainder = timestamp % freq;
173 ms = (remainder * 1000U) / freq;
174 us = (1000 * (remainder * 1000U - (ms * freq))) / freq;
175
176 if (IS_ENABLED(CONFIG_LOG_BACKEND_NET) && flags & LOG_OUTPUT_FLAG_FORMAT_SYSLOG) {
177 #if defined(CONFIG_POSIX_C_LANG_SUPPORT_R)
178 struct tm tm_timestamp = {0};
179 time_t time_seconds = total_seconds;
180
181 gmtime_r(&time_seconds, &tm_timestamp);
182 #if defined(CONFIG_REQUIRES_FULL_LIBC)
183 char time_str[sizeof("1970-01-01T00:00:00")];
184
185 strftime(time_str, sizeof(time_str), "%FT%T", &tm_timestamp);
186
187 length = print_formatted(output, "%s.%06uZ ",
188 time_str, ms * 1000U + us);
189 #else /* CONFIG_REQUIRES_FULL_LIBC */
190 length = print_formatted(output,
191 "%04u-%02u-%02uT%02u:%02u:%02u.%06uZ ",
192 tm_timestamp.tm_year + 1900, tm_timestamp.tm_mon + 1,
193 tm_timestamp.tm_mday, tm_timestamp.tm_hour,
194 tm_timestamp.tm_min, tm_timestamp.tm_sec,
195 ms * 1000U + us);
196 #endif /* CONFIG_REQUIRES_FULL_LIBC */
197 #endif /* CONFIG_POSIX_C_LANG_SUPPORT_R */
198 } else if (IS_ENABLED(CONFIG_LOG_OUTPUT_FORMAT_CUSTOM_TIMESTAMP)) {
199 length = log_custom_timestamp_print(output, timestamp, print_formatted);
200 } else {
201 if (IS_ENABLED(CONFIG_LOG_OUTPUT_FORMAT_LINUX_TIMESTAMP)) {
202 length = print_formatted(output,
203 #if defined(CONFIG_LOG_TIMESTAMP_64BIT)
204 "[%5llu.%06d] ",
205 #else
206 "[%5lu.%06d] ",
207 #endif
208 total_seconds, ms * 1000U + us);
209 #if defined(CONFIG_POSIX_C_LANG_SUPPORT_R)
210 } else if (IS_ENABLED(CONFIG_LOG_OUTPUT_FORMAT_DATE_TIMESTAMP)) {
211 struct tm tm_timestamp = {0};
212 time_t time_seconds = total_seconds;
213
214 gmtime_r(&time_seconds, &tm_timestamp);
215 #if defined(CONFIG_REQUIRES_FULL_LIBC)
216 char time_str[sizeof("1970-01-01 00:00:00")];
217
218 strftime(time_str, sizeof(time_str), "%F %T", &tm_timestamp);
219
220 length = print_formatted(output, "[%s.%03u,%03u] ", time_str, ms,
221 us);
222 #else /* CONFIG_REQUIRES_FULL_LIBC */
223 length = print_formatted(
224 output, "[%04u-%02u-%02u %02u:%02u:%02u.%03u,%03u] ",
225 tm_timestamp.tm_year + 1900, tm_timestamp.tm_mon + 1,
226 tm_timestamp.tm_mday, tm_timestamp.tm_hour,
227 tm_timestamp.tm_min, tm_timestamp.tm_sec,
228 ms, us);
229 #endif /* CONFIG_REQUIRES_FULL_LIBC */
230 } else if (IS_ENABLED(CONFIG_LOG_OUTPUT_FORMAT_ISO8601_TIMESTAMP)) {
231 struct tm tm_timestamp = {0};
232 time_t time_seconds = total_seconds;
233
234 gmtime_r(&time_seconds, &tm_timestamp);
235 #if defined(CONFIG_REQUIRES_FULL_LIBC)
236 char time_str[sizeof("1970-01-01T00:00:00")];
237
238 strftime(time_str, sizeof(time_str), "%FT%T", &tm_timestamp);
239
240 length = print_formatted(output, "[%s,%06uZ] ", time_str,
241 ms * 1000U + us);
242 #else /* CONFIG_REQUIRES_FULL_LIBC */
243 length = print_formatted(output,
244 "[%04u-%02u-%02uT%02u:%02u:%02u,%06uZ] ",
245 tm_timestamp.tm_year + 1900,
246 tm_timestamp.tm_mon + 1,
247 tm_timestamp.tm_mday, tm_timestamp.tm_hour,
248 tm_timestamp.tm_min, tm_timestamp.tm_sec,
249 ms * 1000U + us);
250 #endif /* CONFIG_REQUIRES_FULL_LIBC */
251 #endif /* CONFIG_POSIX_C_LANG_SUPPORT_R */
252 } else {
253 uint32_t seconds;
254 uint32_t hours;
255 uint32_t mins;
256
257 seconds = total_seconds;
258 hours = seconds / 3600U;
259 seconds -= hours * 3600U;
260 mins = seconds / 60U;
261 seconds -= mins * 60U;
262 length = print_formatted(output,
263 "[%02u:%02u:%02u.%03u,%03u] ",
264 hours, mins, seconds, ms, us);
265 }
266 }
267 } else {
268 length = 0;
269 }
270
271 return length;
272 }
273
color_print(const struct log_output * output,bool color,bool start,uint32_t level)274 static void color_print(const struct log_output *output,
275 bool color, bool start, uint32_t level)
276 {
277 if (color) {
278 const char *log_color = start && (colors[level] != NULL) ?
279 colors[level] : LOG_COLOR_CODE_DEFAULT;
280 print_formatted(output, "%s", log_color);
281 }
282 }
283
color_prefix(const struct log_output * output,bool color,uint32_t level)284 static void color_prefix(const struct log_output *output,
285 bool color, uint32_t level)
286 {
287 color_print(output, color, true, level);
288 }
289
color_postfix(const struct log_output * output,bool color,uint32_t level)290 static void color_postfix(const struct log_output *output,
291 bool color, uint32_t level)
292 {
293 color_print(output, color, false, level);
294 }
295
296
ids_print(const struct log_output * output,bool level_on,bool func_on,bool thread_on,const char * domain,const char * source,k_tid_t tid,uint32_t level)297 static int ids_print(const struct log_output *output,
298 bool level_on,
299 bool func_on,
300 bool thread_on,
301 const char *domain,
302 const char *source,
303 k_tid_t tid,
304 uint32_t level)
305 {
306 int total = 0;
307
308 if (level_on) {
309 total += print_formatted(output, "<%s> ", severity[level]);
310 }
311
312 if (IS_ENABLED(CONFIG_LOG_THREAD_ID_PREFIX) && thread_on) {
313 if (IS_ENABLED(CONFIG_THREAD_NAME)) {
314 total += print_formatted(output, "[%s] ",
315 tid == NULL ? "irq" : k_thread_name_get(tid));
316 } else {
317 total += print_formatted(output, "[%p] ", tid);
318 }
319 }
320
321 if (domain) {
322 total += print_formatted(output, "%s/", domain);
323 }
324
325 if (source) {
326 total += print_formatted(output,
327 (func_on &&
328 ((1 << level) & LOG_FUNCTION_PREFIX_MASK)) ?
329 "%s." : "%s: ",
330 source);
331 }
332
333 return total;
334 }
335
newline_print(const struct log_output * ctx,uint32_t flags)336 static void newline_print(const struct log_output *ctx, uint32_t flags)
337 {
338 if (IS_ENABLED(CONFIG_LOG_BACKEND_NET) &&
339 flags & LOG_OUTPUT_FLAG_FORMAT_SYSLOG) {
340 return;
341 }
342
343 if ((flags & LOG_OUTPUT_FLAG_CRLF_NONE) != 0U) {
344 return;
345 }
346
347 if ((flags & LOG_OUTPUT_FLAG_CRLF_LFONLY) != 0U) {
348 print_formatted(ctx, "\n");
349 } else {
350 print_formatted(ctx, "\r\n");
351 }
352 }
353
hexdump_line_print(const struct log_output * output,const uint8_t * data,uint32_t length,int prefix_offset,uint32_t flags)354 static void hexdump_line_print(const struct log_output *output,
355 const uint8_t *data, uint32_t length,
356 int prefix_offset, uint32_t flags)
357 {
358 newline_print(output, flags);
359
360 for (int i = 0; i < prefix_offset; i++) {
361 print_formatted(output, " ");
362 }
363
364 for (int i = 0; i < HEXDUMP_BYTES_IN_LINE; i++) {
365 if (i > 0 && !(i % 8)) {
366 print_formatted(output, " ");
367 }
368
369 if (i < length) {
370 print_formatted(output, "%02x ", data[i]);
371 } else {
372 print_formatted(output, " ");
373 }
374 }
375
376 print_formatted(output, "|");
377
378 for (int i = 0; i < HEXDUMP_BYTES_IN_LINE; i++) {
379 if (i > 0 && !(i % 8)) {
380 print_formatted(output, " ");
381 }
382
383 if (i < length) {
384 unsigned char c = (unsigned char)data[i];
385
386 print_formatted(output, "%c",
387 isprint((int)c) != 0 ? c : '.');
388 } else {
389 print_formatted(output, " ");
390 }
391 }
392 }
393
log_msg_hexdump(const struct log_output * output,uint8_t * data,uint32_t len,int prefix_offset,uint32_t flags)394 static void log_msg_hexdump(const struct log_output *output,
395 uint8_t *data, uint32_t len,
396 int prefix_offset, uint32_t flags)
397 {
398 size_t length;
399
400 do {
401 length = MIN(len, HEXDUMP_BYTES_IN_LINE);
402
403 hexdump_line_print(output, data, length,
404 prefix_offset, flags);
405 data += length;
406 len -= length;
407 } while (len);
408 }
409
410 #if defined(CONFIG_LOG_BACKEND_NET_RFC5424_SDATA_SEQID)
get_sequence_id(void)411 static int32_t get_sequence_id(void)
412 {
413 static int32_t id;
414
415 if (++id < 0) {
416 id = 1;
417 }
418
419 return id;
420 }
421 #endif
422
423 #if defined(CONFIG_LOG_BACKEND_NET_RFC5424_SDATA_TZKNOWN)
is_tzknown(void)424 static bool is_tzknown(void)
425 {
426 /* TODO: use proper implementation */
427 return false;
428 }
429 #endif
430
431 #if defined(CONFIG_LOG_BACKEND_NET_RFC5424_SDATA_ISSYNCED)
is_synced(void)432 static bool is_synced(void)
433 {
434 /* TODO: use proper implementation */
435 return IS_ENABLED(CONFIG_SNTP);
436 }
437 #endif
438
syslog_print(const struct log_output * output,bool level_on,bool func_on,bool * thread_on,const char * domain,const char * source,k_tid_t tid,uint32_t level,uint32_t length)439 static int syslog_print(const struct log_output *output,
440 bool level_on,
441 bool func_on,
442 bool *thread_on,
443 const char *domain,
444 const char *source,
445 k_tid_t tid,
446 uint32_t level,
447 uint32_t length)
448 {
449 uint32_t len = length;
450
451 /* The syslog output format is:
452 * HOSTNAME SP APP-NAME SP PROCID SP MSGID SP STRUCTURED-DATA
453 */
454
455 /* First HOSTNAME */
456 len += print_formatted(output, "%s ",
457 output->control_block->hostname ?
458 output->control_block->hostname :
459 "zephyr");
460
461 /* Then APP-NAME. We use the thread name here. It should not
462 * contain any space characters.
463 */
464 if (*thread_on) {
465 if (IS_ENABLED(CONFIG_THREAD_NAME)) {
466 if (strstr(k_thread_name_get(tid), " ") != NULL) {
467 goto do_not_print_name;
468 }
469
470 len += print_formatted(output, "%s ",
471 tid == NULL ?
472 "irq" :
473 k_thread_name_get(tid));
474 } else {
475 do_not_print_name:
476 len += print_formatted(output, "%p ", tid);
477 }
478
479 /* Do not print thread id in the message as it was already
480 * printed above.
481 */
482 *thread_on = false;
483 } else {
484 /* No APP-NAME */
485 len += print_formatted(output, "- ");
486 }
487
488 if (!IS_ENABLED(CONFIG_LOG_BACKEND_NET_RFC5424_STRUCTURED_DATA)) {
489 /* No PROCID, MSGID or STRUCTURED-DATA */
490 len += print_formatted(output, "- - - ");
491
492 return len;
493 }
494
495
496 #if defined(CONFIG_LOG_BACKEND_NET_RFC5424_SDATA_SOFTWARE) || \
497 defined(CONFIG_LOG_BACKEND_NET_RFC5424_SDATA_SOFTWARE_VERSION)
498 #define STRUCTURED_DATA_ORIGIN_START "[origin"
499 #define STRUCTURED_DATA_ORIGIN_SW " software=\"%s\""
500 #define STRUCTURED_DATA_ORIGIN_SW_VERSION " swVersion=\"%u\""
501 #define STRUCTURED_DATA_ORIGIN_END "]"
502 #define STRUCTURED_DATA_ORIGIN \
503 STRUCTURED_DATA_ORIGIN_START \
504 COND_CODE_1(CONFIG_LOG_BACKEND_NET_RFC5424_SDATA_SOFTWARE, \
505 (STRUCTURED_DATA_ORIGIN_SW), ("%s")) \
506 COND_CODE_1(CONFIG_LOG_BACKEND_NET_RFC5424_SDATA_SOFTWARE_VERSION,\
507 (STRUCTURED_DATA_ORIGIN_SW_VERSION), ("%s")) \
508 STRUCTURED_DATA_ORIGIN_END
509 #else
510 #define STRUCTURED_DATA_ORIGIN "%s%s"
511 #endif
512
513 #if defined(CONFIG_LOG_BACKEND_NET_RFC5424_SDATA_SEQID) || \
514 defined(CONFIG_LOG_BACKEND_NET_RFC5424_SDATA_UPTIME)
515 #define STRUCTURED_DATA_META_START "[meta"
516 #define STRUCTURED_DATA_META_SEQID " sequenceId=\"%d\""
517 #define STRUCTURED_DATA_META_UPTIME " sysUpTime=\"%d\""
518 #define STRUCTURED_DATA_META_END "]"
519 #define STRUCTURED_DATA_META \
520 STRUCTURED_DATA_META_START \
521 COND_CODE_1(CONFIG_LOG_BACKEND_NET_RFC5424_SDATA_SEQID, \
522 (STRUCTURED_DATA_META_SEQID), ("%s")) \
523 COND_CODE_1(CONFIG_LOG_BACKEND_NET_RFC5424_SDATA_UPTIME, \
524 (STRUCTURED_DATA_META_UPTIME), ("%s")) \
525 STRUCTURED_DATA_META_END
526 #else
527 #define STRUCTURED_DATA_META "%s%s"
528 #endif
529
530 #if defined(CONFIG_LOG_BACKEND_NET_RFC5424_SDATA_TZKNOWN) || \
531 defined(CONFIG_LOG_BACKEND_NET_RFC5424_SDATA_ISSYNCED)
532 #define STRUCTURED_DATA_TIMEQUALITY_START "[timeQuality"
533 #define STRUCTURED_DATA_TIMEQUALITY_TZKNOWN " tzKnown=\"%d\""
534 #define STRUCTURED_DATA_TIMEQUALITY_ISSYNCED " isSynced=\"%d\""
535 #define STRUCTURED_DATA_TIMEQUALITY_END "]"
536 #define STRUCTURED_DATA_TIMEQUALITY \
537 STRUCTURED_DATA_TIMEQUALITY_START \
538 COND_CODE_1(CONFIG_LOG_BACKEND_NET_RFC5424_SDATA_TZKNOWN, \
539 (STRUCTURED_DATA_TIMEQUALITY_TZKNOWN), ("%s")) \
540 COND_CODE_1(CONFIG_LOG_BACKEND_NET_RFC5424_SDATA_ISSYNCED, \
541 (STRUCTURED_DATA_TIMEQUALITY_ISSYNCED), ("%s")) \
542 STRUCTURED_DATA_TIMEQUALITY_END
543 #else
544 #define STRUCTURED_DATA_TIMEQUALITY "%s%s"
545 #endif
546
547 /* No PROCID or MSGID, but there is structured data.
548 */
549 len += print_formatted(output,
550 "- - "
551 STRUCTURED_DATA_META
552 STRUCTURED_DATA_ORIGIN
553 STRUCTURED_DATA_TIMEQUALITY,
554 COND_CODE_1(CONFIG_LOG_BACKEND_NET_RFC5424_SDATA_SEQID,
555 (get_sequence_id()), ("")),
556 COND_CODE_1(CONFIG_LOG_BACKEND_NET_RFC5424_SDATA_UPTIME,
557 /* in hundredths of a sec */
558 (k_uptime_get_32() / 10), ("")),
559 COND_CODE_1(CONFIG_LOG_BACKEND_NET_RFC5424_SDATA_SOFTWARE,
560 (CONFIG_LOG_BACKEND_NET_RFC5424_SDATA_SOFTWARE_VALUE),
561 ("")),
562 COND_CODE_1(CONFIG_LOG_BACKEND_NET_RFC5424_SDATA_SOFTWARE_VERSION,
563 (sys_kernel_version_get()), ("")),
564 COND_CODE_1(CONFIG_LOG_BACKEND_NET_RFC5424_SDATA_TZKNOWN,
565 (is_tzknown()), ("")),
566 COND_CODE_1(CONFIG_LOG_BACKEND_NET_RFC5424_SDATA_ISSYNCED,
567 (is_synced()), (""))
568 );
569
570 return len;
571 }
572
prefix_print(const struct log_output * output,uint32_t flags,bool func_on,log_timestamp_t timestamp,const char * domain,const char * source,k_tid_t tid,uint8_t level)573 static uint32_t prefix_print(const struct log_output *output,
574 uint32_t flags,
575 bool func_on,
576 log_timestamp_t timestamp,
577 const char *domain,
578 const char *source,
579 k_tid_t tid,
580 uint8_t level)
581 {
582 __ASSERT_NO_MSG(level <= LOG_LEVEL_DBG);
583 uint32_t length = 0U;
584
585 bool stamp = flags & LOG_OUTPUT_FLAG_TIMESTAMP;
586 bool colors_on = flags & LOG_OUTPUT_FLAG_COLORS;
587 bool level_on = flags & LOG_OUTPUT_FLAG_LEVEL;
588 bool thread_on = IS_ENABLED(CONFIG_LOG_THREAD_ID_PREFIX) &&
589 (flags & LOG_OUTPUT_FLAG_THREAD);
590 bool source_off = flags & LOG_OUTPUT_FLAG_SKIP_SOURCE;
591 const char *tag = IS_ENABLED(CONFIG_LOG) ? z_log_get_tag() : NULL;
592
593 if (IS_ENABLED(CONFIG_LOG_BACKEND_NET) &&
594 flags & LOG_OUTPUT_FLAG_FORMAT_SYSLOG) {
595 /* TODO: As there is no way to figure out the
596 * facility at this point, use a pre-defined value.
597 * Change this to use the real facility of the
598 * logging call when that info is available.
599 */
600 static const int facility = 16; /* local0 */
601
602 length += print_formatted(
603 output,
604 /* <PRI>VERSION */
605 "<%d>1 ",
606 facility * 8 +
607 level_to_rfc5424_severity(level));
608 }
609
610 if (tag) {
611 length += print_formatted(output, "%s ", tag);
612 }
613
614 if (stamp) {
615 length += timestamp_print(output, flags, timestamp);
616 }
617
618 if (IS_ENABLED(CONFIG_LOG_BACKEND_NET) &&
619 flags & LOG_OUTPUT_FLAG_FORMAT_SYSLOG) {
620 length += syslog_print(output, level_on, func_on, &thread_on, domain,
621 source_off ? NULL : source, tid, level, length);
622 } else {
623 color_prefix(output, colors_on, level);
624 }
625
626 length += ids_print(output, level_on, func_on, thread_on, domain,
627 source_off ? NULL : source, tid, level);
628
629 return length;
630 }
631
postfix_print(const struct log_output * output,uint32_t flags,uint8_t level)632 static void postfix_print(const struct log_output *output,
633 uint32_t flags, uint8_t level)
634 {
635 color_postfix(output, (flags & LOG_OUTPUT_FLAG_COLORS),
636 level);
637 newline_print(output, flags);
638 }
639
log_output_process(const struct log_output * output,log_timestamp_t timestamp,const char * domain,const char * source,k_tid_t tid,uint8_t level,const uint8_t * package,const uint8_t * data,size_t data_len,uint32_t flags)640 void log_output_process(const struct log_output *output,
641 log_timestamp_t timestamp,
642 const char *domain,
643 const char *source,
644 k_tid_t tid,
645 uint8_t level,
646 const uint8_t *package,
647 const uint8_t *data,
648 size_t data_len,
649 uint32_t flags)
650 {
651 bool raw_string = (level == LOG_LEVEL_INTERNAL_RAW_STRING);
652 uint32_t prefix_offset;
653 cbprintf_cb cb;
654
655 if (!raw_string) {
656 prefix_offset = prefix_print(output, flags, 0, timestamp,
657 domain, source, tid, level);
658 cb = out_func;
659 } else {
660 prefix_offset = 0;
661 /* source set to 1 indicates raw string and contrary to printk
662 * case it should not append anything to the output (printk is
663 * appending <CR> to the new line character).
664 */
665 cb = ((uintptr_t)source == 1) ? out_func : cr_out_func;
666 }
667
668 if (package) {
669 int err = cbpprintf(cb, (void *)output, (void *)package);
670
671 (void)err;
672 __ASSERT_NO_MSG(err >= 0);
673 }
674
675 if (data_len) {
676 log_msg_hexdump(output, (uint8_t *)data, data_len, prefix_offset, flags);
677 }
678
679 if (!raw_string) {
680 postfix_print(output, flags, level);
681 }
682
683 log_output_flush(output);
684 }
685
log_output_msg_process(const struct log_output * output,struct log_msg * msg,uint32_t flags)686 void log_output_msg_process(const struct log_output *output,
687 struct log_msg *msg, uint32_t flags)
688 {
689 log_timestamp_t timestamp = log_msg_get_timestamp(msg);
690 uint8_t level = log_msg_get_level(msg);
691 uint8_t domain_id = log_msg_get_domain(msg);
692 int16_t source_id = log_msg_get_source_id(msg);
693
694 const char *sname = source_id >= 0 ? log_source_name_get(domain_id, source_id) : NULL;
695 size_t plen, dlen;
696 uint8_t *package = log_msg_get_package(msg, &plen);
697 uint8_t *data = log_msg_get_data(msg, &dlen);
698
699 log_output_process(output, timestamp, NULL, sname, (k_tid_t)log_msg_get_tid(msg), level,
700 plen > 0 ? package : NULL, data, dlen, flags);
701 }
702
log_output_dropped_process(const struct log_output * output,uint32_t cnt)703 void log_output_dropped_process(const struct log_output *output, uint32_t cnt)
704 {
705 char buf[5];
706 int len;
707 static const char prefix[] = DROPPED_COLOR_PREFIX "--- ";
708 static const char postfix[] =
709 " messages dropped ---\r\n" DROPPED_COLOR_POSTFIX;
710 log_output_func_t outf = output->func;
711
712 cnt = MIN(cnt, 9999);
713 len = snprintk(buf, sizeof(buf), "%d", cnt);
714
715 log_output_write(outf, (uint8_t *)prefix, sizeof(prefix) - 1, output->control_block->ctx);
716 log_output_write(outf, buf, len, output->control_block->ctx);
717 log_output_write(outf, (uint8_t *)postfix, sizeof(postfix) - 1, output->control_block->ctx);
718 }
719
log_output_timestamp_freq_set(uint32_t frequency)720 void log_output_timestamp_freq_set(uint32_t frequency)
721 {
722 timestamp_div = 1U;
723 /* There is no point to have frequency higher than 1MHz (ns are not
724 * printed) and too high frequency leads to overflows in calculations.
725 */
726 while (frequency > 1000000) {
727 frequency /= 2U;
728 timestamp_div *= 2U;
729 }
730
731 freq = frequency;
732 }
733
log_output_timestamp_to_us(log_timestamp_t timestamp)734 uint64_t log_output_timestamp_to_us(log_timestamp_t timestamp)
735 {
736 timestamp /= timestamp_div;
737
738 return ((uint64_t) timestamp * 1000000U) / freq;
739 }
740