/** * get_local_timezone_ofs: * @when: time in UTC * * Return the zone offset (measured in seconds) of @when expressed in local * time. The function also takes care about daylight saving. **/ long get_local_timezone_ofs(time_t when) { #ifdef HAVE_STRUCT_TM_TM_GMTOFF struct tm ltm; cached_localtime(&when, <m); return ltm.tm_gmtoff; #else struct tm gtm; struct tm ltm; long tzoff; cached_localtime(&when, <m); cached_gmtime(&when, >m); tzoff = (ltm.tm_hour - gtm.tm_hour) * 3600; tzoff += (ltm.tm_min - gtm.tm_min) * 60; tzoff += ltm.tm_sec - gtm.tm_sec; if (tzoff > 0 && (ltm.tm_year < gtm.tm_year || ltm.tm_mon < gtm.tm_mon || ltm.tm_mday < gtm.tm_mday)) tzoff -= 86400; else if (tzoff < 0 && (ltm.tm_year > gtm.tm_year || ltm.tm_mon > gtm.tm_mon || ltm.tm_mday > gtm.tm_mday)) tzoff += 86400; return tzoff; #endif /* HAVE_STRUCT_TM_TM_GMTOFF */ }
/** * log_stamp_format: * @stamp: Timestamp to format * @target: Target storage for formatted timestamp * @ts_format: Specifies basic timestamp format (TS_FMT_BSD, TS_FMT_ISO) * @zone_offset: Specifies custom zone offset if @tz_convert == TZ_CNV_CUSTOM * * Emits the formatted version of @stamp into @target as specified by * @ts_format and @tz_convert. **/ void log_stamp_append_format(const LogStamp *stamp, GString *target, gint ts_format, glong zone_offset, gint frac_digits) { glong target_zone_offset = 0; struct tm *tm, tm_storage; char buf[8]; time_t t; if (zone_offset != -1) target_zone_offset = zone_offset; else target_zone_offset = stamp->zone_offset; t = stamp->tv_sec + target_zone_offset; cached_gmtime(&t, &tm_storage); tm = &tm_storage; switch (ts_format) { case TS_FMT_BSD: g_string_append(target, month_names_abbrev[tm->tm_mon]); g_string_append_c(target, ' '); format_uint32_padded(target, 2, ' ', 10, tm->tm_mday); g_string_append_c(target, ' '); format_uint32_padded(target, 2, '0', 10, tm->tm_hour); g_string_append_c(target, ':'); format_uint32_padded(target, 2, '0', 10, tm->tm_min); g_string_append_c(target, ':'); format_uint32_padded(target, 2, '0', 10, tm->tm_sec); log_stamp_append_frac_digits(stamp, target, frac_digits); break; case TS_FMT_ISO: format_uint32_padded(target, 0, 0, 10, tm->tm_year + 1900); g_string_append_c(target, '-'); format_uint32_padded(target, 2, '0', 10, tm->tm_mon + 1); g_string_append_c(target, '-'); format_uint32_padded(target, 2, '0', 10, tm->tm_mday); g_string_append_c(target, 'T'); format_uint32_padded(target, 2, '0', 10, tm->tm_hour); g_string_append_c(target, ':'); format_uint32_padded(target, 2, '0', 10, tm->tm_min); g_string_append_c(target, ':'); format_uint32_padded(target, 2, '0', 10, tm->tm_sec); log_stamp_append_frac_digits(stamp, target, frac_digits); format_zone_info(buf, sizeof(buf), target_zone_offset); g_string_append(target, buf); break; case TS_FMT_FULL: format_uint32_padded(target, 0, 0, 10, tm->tm_year + 1900); g_string_append_c(target, ' '); g_string_append(target, month_names_abbrev[tm->tm_mon]); g_string_append_c(target, ' '); format_uint32_padded(target, 2, ' ', 10, tm->tm_mday); g_string_append_c(target, ' '); format_uint32_padded(target, 2, '0', 10, tm->tm_hour); g_string_append_c(target, ':'); format_uint32_padded(target, 2, '0', 10, tm->tm_min); g_string_append_c(target, ':'); format_uint32_padded(target, 2, '0', 10, tm->tm_sec); log_stamp_append_frac_digits(stamp, target, frac_digits); break; case TS_FMT_UNIX: format_uint32_padded(target, 0, 0, 10, (int) stamp->tv_sec); log_stamp_append_frac_digits(stamp, target, frac_digits); break; default: g_assert_not_reached(); break; } }
gboolean log_macro_expand(GString *result, gint id, gboolean escape, LogTemplateOptions *opts, gint tz, gint32 seq_num, const gchar *context_id, LogMessage *msg) { static LogTemplateOptions default_opts = { TRUE, TS_FMT_BSD, 0, { NULL, NULL }, { NULL, NULL } }; if (!opts) opts = &default_opts; switch (id) { case M_FACILITY: { /* facility */ const char *n; n = syslog_name_lookup_name_by_value(msg->pri & LOG_FACMASK, sl_facilities); if (n) { g_string_append(result, n); } else { format_uint32_padded(result, 0, 0, 16, (msg->pri & LOG_FACMASK) >> 3); } break; } case M_FACILITY_NUM: { format_uint32_padded(result, 0, 0, 10, (msg->pri & LOG_FACMASK) >> 3); break; } case M_LEVEL: { /* level */ const char *n; n = syslog_name_lookup_name_by_value(msg->pri & LOG_PRIMASK, sl_levels); if (n) { g_string_append(result, n); } else { format_uint32_padded(result, 0, 0, 10, msg->pri & LOG_PRIMASK); } break; } case M_LEVEL_NUM: { format_uint32_padded(result, 0, 0, 10, msg->pri & LOG_PRIMASK); break; } case M_TAG: { format_uint32_padded(result, 2, '0', 16, msg->pri); break; } case M_TAGS: { log_msg_print_tags(msg, result); break; } case M_BSDTAG: { format_uint32_padded(result, 0, 0, 10, (msg->pri & LOG_PRIMASK)); g_string_append_c(result, (((msg->pri & LOG_FACMASK) >> 3) + 'A')); break; } case M_PRI: { format_uint32_padded(result, 0, 0, 10, msg->pri); break; } case M_HOST: { if (msg->flags & LF_CHAINED_HOSTNAME) { /* host */ const gchar *p1, *p2; int remaining, length; gssize host_len; const gchar *host = log_msg_get_value(msg, LM_V_HOST, &host_len); p1 = memchr(host, '@', host_len); if (p1) p1++; else p1 = host; remaining = host_len - (p1 - host); p2 = memchr(p1, '/', remaining); length = p2 ? p2 - p1 : host_len - (p1 - host); result_append(result, p1, length, escape); } else { result_append_value(result, msg, LM_V_HOST, escape); } break; } case M_SDATA: if (escape) { GString *sdstr = g_string_sized_new(0); log_msg_append_format_sdata(msg, sdstr, seq_num); result_append(result, sdstr->str, sdstr->len, TRUE); g_string_free(sdstr, TRUE); } else { log_msg_append_format_sdata(msg, result, seq_num); } break; case M_MSGHDR: if ((msg->flags & LF_LEGACY_MSGHDR)) { /* fast path for now, as most messages come from legacy devices */ result_append_value(result, msg, LM_V_LEGACY_MSGHDR, escape); } else { /* message, complete with program name and pid */ gssize len; len = result->len; result_append_value(result, msg, LM_V_PROGRAM, escape); if (len != result->len) { const gchar *pid = log_msg_get_value(msg, LM_V_PID, &len); if (len > 0) { result_append(result, "[", 1, FALSE); result_append(result, pid, len, escape); result_append(result, "]", 1, FALSE); } result_append(result, ": ", 2, FALSE); } } break; case M_MESSAGE: if (cfg_is_config_version_older(configuration, 0x0300)) log_macro_expand(result, M_MSGHDR, escape, opts, tz, seq_num, context_id, msg); result_append_value(result, msg, LM_V_MESSAGE, escape); break; case M_SOURCE_IP: { gchar *ip; if (msg->saddr && (g_sockaddr_inet_check(msg->saddr) || #if ENABLE_IPV6 g_sockaddr_inet6_check(msg->saddr)) #else 0) #endif ) { gchar buf[MAX_SOCKADDR_STRING]; g_sockaddr_format(msg->saddr, buf, sizeof(buf), GSA_ADDRESS_ONLY); ip = buf; } else { ip = "127.0.0.1"; } result_append(result, ip, strlen(ip), escape); break; } case M_SEQNUM: { if (seq_num) { format_uint32_padded(result, 0, 0, 10, seq_num); } break; } case M_CONTEXT_ID: { if (context_id) { result_append(result, context_id, strlen(context_id), escape); } break; } case M_LOGHOST: { gsize hname_len; const gchar *hname = get_local_hostname(&hname_len); result_append(result, hname, hname_len, escape); break; } case M_SYSUPTIME: { GTimeVal ct; g_get_current_time(&ct); format_uint64_padded(result, 0, 0, 10, g_time_val_diff(&ct, &app_uptime) / 1000 / 10); break; } default: { /* year, month, day */ struct tm *tm, tm_storage; gchar buf[64]; gint length; time_t t; LogStamp *stamp, sstamp; glong zone_ofs; guint tmp_hour; if (id >= M_TIME_FIRST && id <= M_TIME_LAST) { stamp = &msg->timestamps[LM_TS_STAMP]; } else if (id >= M_TIME_FIRST + M_RECVD_OFS && id <= M_TIME_LAST + M_RECVD_OFS) { id -= M_RECVD_OFS; stamp = &msg->timestamps[LM_TS_RECVD]; } else if (id >= M_TIME_FIRST + M_STAMP_OFS && id <= M_TIME_LAST + M_STAMP_OFS) { id -= M_STAMP_OFS; stamp = &msg->timestamps[LM_TS_STAMP]; } else if (id >= M_TIME_FIRST + M_CSTAMP_OFS && id <= M_TIME_LAST + M_CSTAMP_OFS) { GTimeVal tv; id -= M_CSTAMP_OFS; cached_g_current_time(&tv); sstamp.tv_sec = tv.tv_sec; sstamp.tv_usec = tv.tv_usec; sstamp.zone_offset = -1; stamp = &sstamp; } else { g_assert_not_reached(); break; } /* try to use the following zone values in order: * destination specific timezone, if one is specified * message specific timezone, if one is specified * local timezone */ zone_ofs = (opts->time_zone_info[tz] != NULL ? time_zone_info_get_offset(opts->time_zone_info[tz], stamp->tv_sec) : stamp->zone_offset); if (zone_ofs == -1) zone_ofs = stamp->zone_offset; t = stamp->tv_sec + zone_ofs; cached_gmtime(&t, &tm_storage); tm = &tm_storage; switch (id) { case M_WEEK_DAY_ABBREV: g_string_append_len(result, weekday_names_abbrev[tm->tm_wday], 3); break; case M_WEEK_DAY_NAME: g_string_append(result, weekday_names[tm->tm_wday]); break; case M_WEEK_DAY: format_uint32_padded(result, 0, 0, 10, tm->tm_wday + 1); break; case M_WEEK: format_uint32_padded(result, 2, '0', 10, (tm->tm_yday - (tm->tm_wday - 1 + 7) % 7 + 7) / 7); break; case M_YEAR: format_uint32_padded(result, 4, '0', 10, tm->tm_year + 1900); break; case M_YEAR_DAY: format_uint32_padded(result, 3, '0', 10, tm->tm_yday + 1); break; case M_MONTH: format_uint32_padded(result, 2, '0', 10, tm->tm_mon + 1); break; case M_MONTH_WEEK: format_uint32_padded(result, 0, 0, 10, ((tm->tm_mday / 7) + ((tm->tm_wday > 0) && ((tm->tm_mday % 7) >= tm->tm_wday)))); break; case M_MONTH_ABBREV: g_string_append_len(result, month_names_abbrev[tm->tm_mon], 3); break; case M_MONTH_NAME: g_string_append(result, month_names[tm->tm_mon]); break; case M_DAY: format_uint32_padded(result, 2, '0', 10, tm->tm_mday); break; case M_HOUR: format_uint32_padded(result, 2, '0', 10, tm->tm_hour); break; case M_HOUR12: if (tm->tm_hour < 12) tmp_hour = tm->tm_hour; else tmp_hour = tm->tm_hour - 12; if (tmp_hour == 0) tmp_hour = 12; format_uint32_padded(result, 2, '0', 10, tmp_hour); break; case M_MIN: format_uint32_padded(result, 2, '0', 10, tm->tm_min); break; case M_SEC: format_uint32_padded(result, 2, '0', 10, tm->tm_sec); break; case M_MSEC: format_uint32_padded(result, 3, '0', 10, stamp->tv_usec/1000); break; case M_USEC: format_uint32_padded(result, 6, '0', 10, stamp->tv_usec); break; case M_AMPM: g_string_append(result, tm->tm_hour < 12 ? "AM" : "PM"); break; case M_DATE: case M_STAMP: case M_ISODATE: case M_FULLDATE: case M_UNIXTIME: { gint format = id == M_DATE ? TS_FMT_BSD : id == M_ISODATE ? TS_FMT_ISO : id == M_FULLDATE ? TS_FMT_FULL : id == M_UNIXTIME ? TS_FMT_UNIX : opts->ts_format; log_stamp_append_format(stamp, result, format, zone_ofs, opts->frac_digits); break; } case M_TZ: case M_TZOFFSET: length = format_zone_info(buf, sizeof(buf), zone_ofs); g_string_append_len(result, buf, length); break; } break; } }