Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configuration option to output logs in logfmt #1014

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,15 @@ configEnum propagation_error_behavior_enum[] = {{"ignore", PROPAGATION_ERR_BEHAV
{"panic-on-replicas", PROPAGATION_ERR_BEHAVIOR_PANIC_ON_REPLICAS},
{NULL, 0}};

configEnum log_format_enum[] = {{"default", LOG_FORMAT_DEFAULT},
{"logfmt", LOG_FORMAT_LOGFMT},
{NULL, 0}};

configEnum log_timestamp_format_enum[] = {{"default", LOG_TIMESTAMP_DEFAULT},
{"iso8601", LOG_TIMESTAMP_ISO8601},
{"unix",LOG_TIMESTAMP_UNIX},
{NULL, 0}};

/* Output buffer limits presets. */
clientBufferLimitsConfig clientBufferLimitsDefaults[CLIENT_TYPE_OBUF_COUNT] = {
{0, 0, 0}, /* normal */
Expand Down Expand Up @@ -3161,6 +3170,8 @@ standardConfig static_configs[] = {
createEnumConfig("propagation-error-behavior", NULL, MODIFIABLE_CONFIG, propagation_error_behavior_enum, server.propagation_error_behavior, PROPAGATION_ERR_BEHAVIOR_IGNORE, NULL, NULL),
createEnumConfig("shutdown-on-sigint", NULL, MODIFIABLE_CONFIG | MULTI_ARG_CONFIG, shutdown_on_sig_enum, server.shutdown_on_sigint, 0, isValidShutdownOnSigFlags, NULL),
createEnumConfig("shutdown-on-sigterm", NULL, MODIFIABLE_CONFIG | MULTI_ARG_CONFIG, shutdown_on_sig_enum, server.shutdown_on_sigterm, 0, isValidShutdownOnSigFlags, NULL),
createEnumConfig("log-format", NULL, MODIFIABLE_CONFIG, log_format_enum, server.log_format, LOG_FORMAT_DEFAULT, NULL, NULL),
createEnumConfig("log-timestamp-format", NULL, MODIFIABLE_CONFIG, log_timestamp_format_enum, server.log_timestamp_format, LOG_TIMESTAMP_DEFAULT, NULL, NULL),

/* Integer configs */
createIntConfig("databases", NULL, IMMUTABLE_CONFIG, 1, INT_MAX, server.dbnum, 16, INTEGER_CONFIG, NULL, NULL),
Expand Down
68 changes: 61 additions & 7 deletions src/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,35 @@ const char *replstateToString(int replstate);
* function of the server may be called from other threads. */
void nolocks_localtime(struct tm *tmp, time_t t, time_t tz, int dst);

/* Formats the timezone offset into a string.
*
* Assumes:
* - size of `buf` is 7 or larger
* - `timezone` is valid, within the range of [-50400, +43200].
* - `daylight_active` indicates whether dst is active (1) or not (0). */

void format_timezone(char *buf, int timezone, int daylight_active) {
// Adjust the timezone for daylight saving, if active
int total_offset = (-1)*timezone + 3600*daylight_active;
int hours = abs(total_offset / 3600);
int minutes = abs(total_offset % 3600) / 60;
buf[0] = total_offset >= 0 ? '+' : '-';
buf[1] = '0' + hours / 10;
buf[2] = '0' + hours % 10;
buf[3] = ':';
buf[4] = '0' + minutes / 10;
buf[5] = '0' + minutes % 10;
buf[6] = '\0';
}

/* Low level logging. To use only for very big messages, otherwise
* serverLog() is to prefer. */
void serverLogRaw(int level, const char *msg) {
const int syslogLevelMap[] = {LOG_DEBUG, LOG_INFO, LOG_NOTICE, LOG_WARNING};
const char *c = ".-*#";
const char* verbose_level[] = {"debug", "info", "notice", "warning"};
const char* roles[] = {"sentinel", "RDB/AOF", "replica", "master"};
const char* role_chars = "XCSM";
FILE *fp;
char buf[64];
int rawmode = (level & LL_RAW);
Expand All @@ -133,23 +157,53 @@ void serverLogRaw(int level, const char *msg) {
} else {
int off;
struct timeval tv;
int role_char;
pid_t pid = getpid();
int daylight_active = atomic_load_explicit(&server.daylight_active, memory_order_relaxed);

gettimeofday(&tv, NULL);
struct tm tm;
nolocks_localtime(&tm, tv.tv_sec, server.timezone, daylight_active);
off = strftime(buf, sizeof(buf), "%d %b %Y %H:%M:%S.", &tm);
snprintf(buf + off, sizeof(buf) - off, "%03d", (int)tv.tv_usec / 1000);
switch(server.log_timestamp_format) {
case LOG_TIMESTAMP_DEFAULT:
off = strftime(buf,sizeof(buf),"%d %b %Y %H:%M:%S.",&tm);
snprintf(buf+off,sizeof(buf)-off,"%03d",(int)tv.tv_usec/1000);
break;

case LOG_TIMESTAMP_ISO8601:
off = strftime(buf,sizeof(buf),"%Y-%m-%dT%H:%M:%S.",&tm);
char tzbuf[7];
format_timezone(tzbuf, server.timezone, server.daylight_active);
snprintf(buf + off, sizeof(buf) - off, "%03d%s",
(int)tv.tv_usec/1000, tzbuf);
break;

case LOG_TIMESTAMP_UNIX:
snprintf(buf,sizeof(buf),"%ld",tv.tv_sec);
break;
default:
break;
}
int role_index;
if (server.sentinel_mode) {
role_char = 'X'; /* Sentinel. */
role_index = 0; /* Sentinel. */
} else if (pid != server.pid) {
role_char = 'C'; /* RDB / AOF writing child. */
role_index = 1; /* RDB / AOF writing child. */
} else {
role_char = (server.primary_host ? 'S' : 'M'); /* replica or Primary. */
role_index = (server.primary_host ? 2 : 3); /* Slave or Master. */
}
switch (server.log_format) {
case LOG_FORMAT_LOGFMT: {
fprintf(fp, "pid=%d role=%s timestamp=\"%s\" level=%s message=\"%s\"\n",
(int)getpid(),roles[role_index],buf,verbose_level[level],msg);
break;
}

default: {
fprintf(fp,"%d:%c %s %c %s\n",
(int)getpid(),role_chars[role_index], buf,c[level],msg);
break;
}
}
fprintf(fp, "%d:%c %s %c %s\n", (int)getpid(), role_char, buf, c[level], msg);
}
fflush(fp);

Expand Down
14 changes: 14 additions & 0 deletions src/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,18 @@ typedef enum {
#define PAUSE_ACTION_EVICT (1 << 3)
#define PAUSE_ACTION_REPLICA (1 << 4) /* pause replica traffic */

/* Sets log format */
typedef enum {
LOG_FORMAT_DEFAULT = 0,
LOG_FORMAT_LOGFMT
} log_format_type;

/* Sets log timestamp format */
/* Also update LOG_TIMESTAMP_FORMATS */
#define LOG_TIMESTAMP_DEFAULT 0
#define LOG_TIMESTAMP_ISO8601 1
#define LOG_TIMESTAMP_UNIX 2

/* common sets of actions to pause/unpause */
#define PAUSE_ACTIONS_CLIENT_WRITE_SET \
(PAUSE_ACTION_CLIENT_WRITE | PAUSE_ACTION_EXPIRE | PAUSE_ACTION_EVICT | PAUSE_ACTION_REPLICA)
Expand Down Expand Up @@ -1998,6 +2010,8 @@ struct valkeyServer {
int memcheck_enabled; /* Enable memory check on crash. */
int use_exit_on_panic; /* Use exit() on panic and assert rather than
* abort(). useful for Valgrind. */
int log_format; /* Print log in specific format */
int log_timestamp_format; /* Timestamp format in log */
/* Shutdown */
int shutdown_timeout; /* Graceful shutdown time limit in seconds. */
int shutdown_on_sigint; /* Shutdown flags configured for SIGINT. */
Expand Down