in src/logging/zlog/src/zlog.c [236:395]
void zlog_log(enum ZLOG_SEVERITY msg_level, const char* func, unsigned int line, const char* fmt, ...)
{
const bool console_log_needed =
(log_setting.console_logging_mode != ZLOG_CLM_DISABLED) && (msg_level >= log_setting.console_level);
const bool file_log_needed = zlog_is_file_log_open() && (msg_level >= log_setting.file_level);
if (!console_log_needed && !file_log_needed)
{
// If we're not logging to console or file, there's nothing to do.
return;
}
char prelude_buffer[PRELUDE_BUFFER_SIZE];
prelude_buffer[0] = '\0';
struct timespec curtime;
ADUCPAL_clock_gettime(CLOCK_REALTIME, &curtime);
const time_t seconds = curtime.tv_sec;
struct tm gmtval;
struct tm* tmval = ADUCPAL_gmtime_r(&seconds, &gmtval);
if (tmval != NULL)
{
// % 100 below to ensure the values fit in 2-digits template.
int ret = snprintf(
prelude_buffer,
PRELUDE_BUFFER_SIZE,
PRELUDE_FORMAT,
tmval->tm_year + 1900,
tmval->tm_mon + 1,
tmval->tm_mday % 100,
tmval->tm_hour % 100,
tmval->tm_min % 100,
tmval->tm_sec % 100,
(int)(curtime.tv_nsec / 100000),
ADUCPAL_getpid(),
(pid_t)ADUCPAL_syscall(SYS_gettid) /* cannot call gettid() directly */
);
if (ret < 0)
{
return;
}
}
char va_buffer[LOG_CONTENT_BUFFER_SIZE];
va_list va;
va_start(va, fmt);
int full_log_len_ret = vsnprintf(va_buffer, sizeof(va_buffer) / sizeof(va_buffer[0]), fmt, va);
//
// If value is velow zero we've encountered some fatal error in vsnprintf
//
if (full_log_len_ret < 0)
{
return;
}
size_t full_log_len = (size_t)full_log_len_ret;
// A return value of size or more means that the output was truncated.
bool log_truncated = full_log_len >= (sizeof(va_buffer) / sizeof(va_buffer[0]));
va_end(va);
if (console_log_needed)
{
// Output to console
const char* color_prefix;
const char* color_suffix;
if (log_setting.console_logging_mode != ZLOG_CLM_ENABLED_TTYCOLOR)
{
color_prefix = "";
color_suffix = "";
}
else
{
// Use Bold Red for error, Bold Yellow for warn.
color_prefix = (msg_level == ZLOG_ERROR) ? "\033[1;31m" : (msg_level == ZLOG_WARN) ? "\033[1;33m" : "";
color_suffix = "\033[m";
}
FILE* output = msg_level == ZLOG_ERROR ? stderr : stdout;
if (log_truncated)
{
// va_buffer contains truncated log. Let's use vfprintf to directly
// print log to console instead.
fprintf(output, "%s %s[%c]%s ", prelude_buffer, color_prefix, level_names[msg_level], color_suffix);
va_start(va, fmt);
(void)vfprintf(output, fmt, va);
va_end(va);
fprintf(output, " [%s:%u]\n", func, line);
fflush(output);
}
else
{
fprintf(
msg_level == ZLOG_ERROR ? stderr : stdout,
"%s %s[%c]%s %s [%s:%u]\n",
prelude_buffer,
color_prefix,
level_names[msg_level],
color_suffix,
va_buffer,
func,
line);
}
}
if (file_log_needed)
{
if ((full_log_len + RESERVED_INFO_SIZE) < ZLOG_BUFFER_LINE_MAXCHARS)
{
// The log can fit in one line. Just add to zlog buffer.
char* buffer = zlog_lock_and_get_buffer();
(void)snprintf(
buffer,
ZLOG_BUFFER_LINE_MAXCHARS,
LOG_FORMAT,
prelude_buffer,
level_names[msg_level],
va_buffer,
func,
line);
zlog_finish_buffer_and_unlock();
}
else
{
// The log is too long, let's flush the buffer then write to log file directly.
_zlog_buffer_lock();
_zlog_flush_buffer();
_zlog_roll_over_if_file_size_too_large(
full_log_len + sizeof(MULTILINE_BEGIN_FORMAT) + sizeof(MULTILINE_END_FORMAT)
+ (PRELUDE_BUFFER_SIZE + MAX_FUNCTION_NAME) * 2);
fprintf(zlog_fout, MULTILINE_BEGIN_FORMAT, prelude_buffer, level_names[msg_level], func, line);
va_start(va, fmt);
(void)vfprintf(zlog_fout, fmt, va);
va_end(va);
fprintf(zlog_fout, MULTILINE_END_FORMAT, prelude_buffer, level_names[msg_level], func, line);
fflush(zlog_fout);
_zlog_buffer_unlock();
}
}
if (msg_level == ZLOG_ERROR || (seconds - zlog_last_flushed) >= ZLOG_FLUSH_INTERVAL_SEC)
{
zlog_flush_buffer();
zlog_last_flushed = seconds;
}
}