457 {
458 if (!format || !buf || buf_size == 0) {
459 return -1;
460 }
461
462 int total_written = 0;
463 char *p = buf;
464 size_t remaining = buf_size - 1;
465
466 (void)timestamp;
467
468 for (size_t i = 0; i < format->spec_count; i++) {
469 const log_format_spec_t *spec = &format->specs[i];
470 int written = 0;
471
472 switch (spec->type) {
473 case LOG_FORMAT_LITERAL:
474 written =
safe_snprintf(p, remaining + 1,
"%s", spec->literal ? spec->literal :
"");
475 break;
476
477 case LOG_FORMAT_TIME:
478
479 if (spec->literal) {
481 if (written <= 0) {
482 log_debug("time_format_now failed for format: %s", spec->literal);
483 written = 0;
484 }
485 }
486 break;
487
488 case LOG_FORMAT_LEVEL:
489
490 written =
safe_snprintf(p, remaining + 1,
"%s", get_level_string(level));
491 break;
492
493 case LOG_FORMAT_LEVEL_ALIGNED:
494
496 break;
497
498 case LOG_FORMAT_FILE:
499 if (file) {
501 }
502 break;
503
504 case LOG_FORMAT_FILE_RELATIVE:
505 if (file) {
508 }
509 break;
510
511 case LOG_FORMAT_LINE:
512 if (line > 0) {
514 }
515 break;
516
517 case LOG_FORMAT_FUNC:
518 if (func) {
520 }
521 break;
522
523 case LOG_FORMAT_TID:
524 written =
safe_snprintf(p, remaining + 1,
"%llu", (
unsigned long long)tid);
525 break;
526
527 case LOG_FORMAT_MICROSECONDS: {
528
529 long nanoseconds = (long)(time_nanoseconds % NS_PER_SEC_INT);
530 long microseconds = nanoseconds / 1000;
531 if (microseconds < 0)
532 microseconds = 0;
533 if (microseconds > 999999)
534 microseconds = 999999;
535 written =
safe_snprintf(p, remaining + 1,
"%06ld", microseconds);
536 break;
537 }
538
539 case LOG_FORMAT_NANOSECONDS: {
540
541 long nanoseconds = (long)(time_nanoseconds % NS_PER_SEC_INT);
542 if (nanoseconds < 0)
543 nanoseconds = 0;
544 if (nanoseconds > 999999999)
545 nanoseconds = 999999999;
546 written =
safe_snprintf(p, remaining + 1,
"%09ld", nanoseconds);
547 break;
548 }
549
550 case LOG_FORMAT_STRFTIME_CODE: {
551
552
553 if (spec->literal) {
554
555 size_t fmt_len = spec->literal_len + 1;
556 char *format_str = SAFE_MALLOC(fmt_len + 1, char *);
557 if (format_str) {
558 format_str[0] = '%';
559 memcpy(format_str + 1, spec->literal, spec->literal_len);
560 format_str[fmt_len] = '\0';
562 if (written <= 0) {
563 log_debug("time_format_now failed for format code: %s", format_str);
564 written = 0;
565 }
566 SAFE_FREE(format_str);
567 }
568 }
569 break;
570 }
571
572 case LOG_FORMAT_MESSAGE:
573 if (message) {
575 }
576 break;
577
578 case LOG_FORMAT_COLORED_MESSAGE: {
579
580 if (message) {
582 written =
safe_snprintf(p, remaining + 1,
"%s", colorized_msg);
583 }
584 break;
585 }
586
587 case LOG_FORMAT_COLORLOG_LEVEL:
588
589 (void)use_colors;
590 written = 0;
591 break;
592
593 case LOG_FORMAT_COLOR: {
594
595
596
597 if (!spec->literal || spec->literal_len == 0) {
598 written = 0;
599 break;
600 }
601
602
603 const char *comma_pos = strchr(spec->literal, ',');
604 if (!comma_pos) {
605
606 log_debug("log_template_apply: %%color format missing comma in: %s", spec->literal);
607 written = 0;
608 break;
609 }
610
611
612 size_t level_len = comma_pos - spec->literal;
613 char level_name[32];
614 if (level_len >= sizeof(level_name)) {
615
616 written = 0;
617 break;
618 }
619 memcpy(level_name, spec->literal, level_len);
620 level_name[level_len] = '\0';
621
622
623 log_color_t color = parse_color_level(level_name, level);
624
625
626 const char *content_start = comma_pos + 1;
627 while (*content_start == ' ' || *content_start == '\t') {
628 content_start++;
629 }
630
631
632 char content_buf[512];
633 int content_len = render_format_content(content_start, content_buf, sizeof(content_buf), level, timestamp, file,
634 line, func, tid, message, use_colors, time_nanoseconds);
635
636 if (content_len < 0 || content_len >= (int)sizeof(content_buf)) {
637 written = 0;
638 break;
639 }
640
641
643
644
645 written =
safe_snprintf(p, remaining + 1,
"%s", colored_content);
646 break;
647 }
648
649 case LOG_FORMAT_NEWLINE:
650
651#ifdef _WIN32
653#else
655#endif
656 break;
657
658 default:
659 break;
660 }
661
662 if (written < 0) {
663
664 return -1;
665 }
666
667 if ((size_t)written > remaining) {
668
669 log_debug("log_template_apply: buffer overflow prevented");
670 return -1;
671 }
672
673 p += written;
674 remaining -= written;
675 total_written += written;
676 }
677
678 *p = '\0';
679 return total_written;
680}
const char * colorize_log_message(const char *message)
Colorize a log message for terminal output.
const char * get_level_string_padded(log_level_t level)
Get padded level string for consistent alignment.
const char * extract_project_relative_path(const char *file)
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Safe formatted string printing to buffer.
const char * colored_string(log_color_t color, const char *text)
int time_format_now(const char *format_str, char *buf, size_t buf_size)