Colorize a log message for terminal output.
Only applies colors if output is going to a TTY (not piped/redirected). Only colorizes text that is not already colored (in reset state).
513 {
514 if (!message) {
515 return message;
516 }
517
518
519
521
522 if (!should_colorize) {
523 return message;
524 }
525
526
527 static char buffers[4][4096];
528 static int buffer_index = 0;
529
530 char *output = buffers[buffer_index];
531 buffer_index = (buffer_index + 1) % 4;
532
533 size_t out_pos = 0;
534 const size_t max_size = sizeof(buffers[0]);
535
536
537 for (size_t i = 0; message[i] != '\0' && out_pos < max_size - 100; i++) {
538 size_t end_pos = 0;
539
540
542
543
544 size_t key_end = 0, value_start = 0, value_end = 0;
545 if (can_colorize && is_key_value_pair(message, i, &key_end, &value_start, &value_end)) {
546 size_t key_len = key_end - i;
547 size_t value_len = value_end - value_start;
548
549
550 char key_buf[256];
551 safe_snprintf(key_buf,
sizeof(key_buf),
"%.*s", (
int)key_len, message + i);
552
553
554 char value_buf[512];
555 safe_snprintf(value_buf,
sizeof(value_buf),
"%.*s", (
int)value_len, message + value_start);
556
557
558 const char *colored_key =
colored_string(LOG_COLOR_FATAL, key_buf);
559 size_t colored_key_len = strlen(colored_key);
560
561
562
563 if (out_pos + colored_key_len + 1 + value_len + 100 < max_size) {
564 memcpy(output + out_pos, colored_key, colored_key_len);
565 out_pos += colored_key_len;
566
567
568 output[out_pos++] = '=';
569
570
571 log_color_t value_color = get_value_color(value_buf);
572 const char *colored_value =
colored_string(value_color, value_buf);
573 size_t colored_value_len = strlen(colored_value);
574 if (out_pos + colored_value_len < max_size) {
575 memcpy(output + out_pos, colored_value, colored_value_len);
576 out_pos += colored_value_len;
577 }
578 }
579 i = value_end - 1;
580 continue;
581 }
582
583
584 if (can_colorize && is_numeric_pattern(message, i, &end_pos)) {
585 size_t pattern_len = end_pos - i;
586 char pattern_buf[256];
587 safe_snprintf(pattern_buf,
sizeof(pattern_buf),
"%.*s", (
int)pattern_len, message + i);
588
589 const char *colored =
colored_string(LOG_COLOR_GREY, pattern_buf);
590 size_t colored_len = strlen(colored);
591 if (out_pos + colored_len < max_size) {
592 memcpy(output + out_pos, colored, colored_len);
593 out_pos += colored_len;
594 }
595 i = end_pos - 1;
596 continue;
597 }
598
599
600 if (can_colorize && is_file_path(message, i, &end_pos)) {
601 size_t path_len = end_pos - i;
602 char path_buf[512];
603 safe_snprintf(path_buf,
sizeof(path_buf),
"%.*s", (
int)path_len, message + i);
604
606 size_t colored_len = strlen(colored);
607 if (out_pos + colored_len < max_size) {
608 memcpy(output + out_pos, colored, colored_len);
609 out_pos += colored_len;
610 }
611 i = end_pos - 1;
612 continue;
613 }
614
615
616 if (can_colorize && is_env_var(message, i, &end_pos)) {
617 size_t var_len = end_pos - i;
618 char var_buf[256];
619 safe_snprintf(var_buf,
sizeof(var_buf),
"%.*s", (
int)var_len, message + i);
620
622 size_t colored_len = strlen(colored);
623 if (out_pos + colored_len < max_size) {
624 memcpy(output + out_pos, colored, colored_len);
625 out_pos += colored_len;
626 }
627 i = end_pos - 1;
628 continue;
629 }
630
631
632 if (can_colorize && is_url(message, i, &end_pos)) {
633 size_t url_len = end_pos - i;
634 char url_buf[2048];
635 safe_snprintf(url_buf,
sizeof(url_buf),
"%.*s", (
int)url_len, message + i);
636
638 size_t colored_len = strlen(colored);
639 if (out_pos + colored_len < max_size) {
640 memcpy(output + out_pos, colored, colored_len);
641 out_pos += colored_len;
642 }
643 i = end_pos - 1;
644 continue;
645 }
646
647
648 if (out_pos < max_size - 1) {
649 output[out_pos++] = message[i];
650 }
651 }
652
653 output[out_pos] = '\0';
654 return output;
655}
bool ansi_is_already_colorized(const char *message, size_t pos)
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)