diff --git a/src/log_proxy.c b/src/log_proxy.c index 5627384..8b84c9c 100644 --- a/src/log_proxy.c +++ b/src/log_proxy.c @@ -114,7 +114,7 @@ static void every_second() { // another program rotated our log file // => let's reinit the output channel destroy_output_channel(); - init_output_channel(log_file, use_locks, TRUE, chmod_str, chown_str, chgrp_str); + init_output_channel(log_file, use_locks, TRUE, chmod_str, chown_str, chgrp_str, timestamp_prefix); unlock_control_file(fd); return; } @@ -141,7 +141,7 @@ static void every_second() { } if (rotate_res == TRUE) { destroy_output_channel(); - init_output_channel(log_file, use_locks, TRUE, chmod_str, chown_str, chgrp_str); + init_output_channel(log_file, use_locks, TRUE, chmod_str, chown_str, chgrp_str, timestamp_prefix); } } unlock_control_file(fd); @@ -202,7 +202,7 @@ void init_or_reinit_output_channel(const gchar *lg_file, gboolean us_locks) { exit(2); } destroy_output_channel(); - init_output_channel(lg_file, us_locks, FALSE, chmod_str, chown_str, chgrp_str); + init_output_channel(lg_file, us_locks, FALSE, chmod_str, chown_str, chgrp_str, timestamp_prefix); unlock_control_file(lock_fd); } @@ -212,7 +212,7 @@ int main(int argc, char *argv[]) setlocale(LC_ALL, ""); context = g_option_context_new("LOGFILE - log proxy"); g_option_context_add_main_entries(context, entries, NULL); - gchar *description = "Optional environment variables to override defaults: \n LOGPROXY_ROTATION_SIZE\n LOGPROXY_ROTATION_TIME\n LOGPROXY_ROTATION_SUFFIX\n LOGPROXY_LOG_DIRECTORY\n LOGPROXY_ROTATED_FILES\n\nExample for rotation-size option:\n- If log_proxy is run with the option --rotation-size on the command line, rotation-size will take the provided value\n- If the option --rotation-size is not provided on command line :\n - If the environment variable LOGPROXY_ROTATION_SIZE is set, rotation-size will take this value\n - If the environment variable LOGPROXY_ROTATION_SIZE is not set, rotation-size will take the default value 104857600\n"; + gchar *description = "Optional environment variables to override defaults: \n LOGPROXY_ROTATION_SIZE\n LOGPROXY_ROTATION_TIME\n LOGPROXY_ROTATION_SUFFIX\n LOGPROXY_LOG_DIRECTORY\n LOGPROXY_ROTATED_FILES\n LOGPROXY_TIMESTAMPS\n\nExample for rotation-size option:\n- If log_proxy is run with the option --rotation-size on the command line, rotation-size will take the provided value\n- If the option --rotation-size is not provided on command line :\n - If the environment variable LOGPROXY_ROTATION_SIZE is set, rotation-size will take this value\n - If the environment variable LOGPROXY_ROTATION_SIZE is not set, rotation-size will take the default value 104857600\n"; g_option_context_set_description(context, description); if (!g_option_context_parse(context, &argc, &argv, NULL)) { g_print("%s", g_option_context_get_help(context, TRUE, NULL)); diff --git a/src/log_proxy_wrapper.c b/src/log_proxy_wrapper.c index 4c83753..286086c 100644 --- a/src/log_proxy_wrapper.c +++ b/src/log_proxy_wrapper.c @@ -64,7 +64,7 @@ void spawn_logproxy_async(const gchar *fifo_path, const gchar *log_path) { if (use_locks) { use_locks_str = "--use-locks"; } - gchar *cli = g_strdup_printf("log_proxy -s %li -t %li -S \"%s\" -d \"%s\" -n %i %s -r -f \"%s\" \"%s\"", rotation_size, rotation_time, rotation_suffix, log_directory, rotated_files, use_locks_str, fifo_path, log_path); + gchar *cli = g_strdup_printf("log_proxy -s %li -t %li -S \"%s\" -d \"%s\" -T \"%s\" -n %i %s -r -f \"%s\" \"%s\"", rotation_size, rotation_time, rotation_suffix, log_directory, timestamp_prefix, rotated_files, use_locks_str, fifo_path, log_path); gboolean spawn_res = g_spawn_command_line_async(cli, NULL); if (spawn_res == FALSE) { g_critical("can't spawn %s => exit", cli); diff --git a/src/options.h b/src/options.h index b68fc26..f6b7465 100644 --- a/src/options.h +++ b/src/options.h @@ -10,6 +10,7 @@ static gchar *log_file = NULL; static glong rotation_size = -1; static glong rotation_time = -1; static gchar *rotation_suffix = NULL; +static gchar *timestamp_prefix = NULL; static gchar *log_directory = NULL; static gchar *chmod_str = NULL; static gchar *chown_str = NULL; @@ -70,6 +71,16 @@ void set_default_values_from_env() } } + if ( timestamp_prefix == NULL ) { + env_val = g_getenv("LOGPROXY_TIMESTAMPS"); + if ( env_val != NULL ) { + timestamp_prefix = (gchar *)env_val; + } + } + if ( timestamp_prefix != NULL && strlen(timestamp_prefix) == 0 ) { + timestamp_prefix = NULL; + } + if ( log_directory == NULL ) { env_val = g_getenv("LOGPROXY_LOG_DIRECTORY"); if ( env_val != NULL ) { @@ -94,6 +105,7 @@ static GOptionEntry entries[] = { { "rotation-suffix", 'S', 0, G_OPTION_ARG_STRING, &rotation_suffix, "strftime based suffix to append to rotated log files (default: content of environment variable LOGPROXY_ROTATION_SUFFIX or .%%Y%%m%%d%%H%%M%%S)", NULL }, { "log-directory", 'd', 0, G_OPTION_ARG_STRING, &log_directory, "directory to store log files (default: content of environment variable LOGPROXY_LOG_DIRECTORY or current directory), directory is created if missing", NULL }, { "rotated-files", 'n', 0, G_OPTION_ARG_INT, &rotated_files, "maximum number of rotated files to keep including main one (0 => no cleaning, default: content of environment variable LOGPROXY_ROTATED_FILES or 5)", NULL }, + { "timestamps", 'T', 0, G_OPTION_ARG_STRING, ×tamp_prefix, "strftime prefix to prepend to every output line (default: content of environment variable LOGPROXY_TIMESTAMPS or none)", NULL }, { "chmod", 'c', 0, G_OPTION_ARG_STRING, &chmod_str, "if set, chmod the logfile to this value, '0700' for example (default: content of environment variable LOGPROXY_CHMOD or NULL)", NULL }, { "chown", 'o', 0, G_OPTION_ARG_STRING, &chown_str, "if set, try (if you don't have sufficient privileges, it will fail silently) to change the owner of the logfile to the given user value", NULL }, { "chgrp", 'g', 0, G_OPTION_ARG_STRING, &chgrp_str, "if set, try (if you don't have sufficient privileges, it will fail silently) to change the group of the logfile to the given group value", NULL }, diff --git a/src/out.c b/src/out.c index afdbd14..d31e019 100644 --- a/src/out.c +++ b/src/out.c @@ -14,6 +14,7 @@ static GIOChannel *_out_channel = NULL; static gboolean _use_locks = FALSE; static gchar *_log_file = NULL; static glong _log_file_initial_timestamp = 0; +static gchar *_timestamp_prefix = NULL; glong get_output_channel_age() { g_assert(_log_file_initial_timestamp > 0); @@ -29,8 +30,9 @@ void destroy_output_channel() { g_free(_log_file); } -void init_output_channel(const gchar *log_file, gboolean use_locks, gboolean force_control_file, const gchar *chmod_str, const gchar *chown_str, const gchar *chgrp_str) { +void init_output_channel(const gchar *log_file, gboolean use_locks, gboolean force_control_file, const gchar *chmod_str, const gchar *chown_str, const gchar *chgrp_str, const gchar *timestamp_prefix) { _log_file = g_strdup(log_file); + _timestamp_prefix = g_strdup(timestamp_prefix); _use_locks = use_locks; create_empty(_log_file); _log_file_initial_timestamp = -1; @@ -91,6 +93,7 @@ gboolean write_output_channel(GString *buffer) { GIOStatus write_status; GError *error = NULL; gsize written; + gsize written_timestamp = 0; while (TRUE) { if (_use_locks) { int res = flock(g_io_channel_unix_get_fd(_out_channel), LOCK_EX); @@ -98,6 +101,19 @@ gboolean write_output_channel(GString *buffer) { continue; } } + + if ( _timestamp_prefix != NULL && written_timestamp == 0 ) { + gchar *timestamp = compute_timestamp_prefix(_timestamp_prefix); + if ( timestamp != NULL ) { + write_status = g_io_channel_write_chars(_out_channel, timestamp, + strlen(timestamp), &written_timestamp, &error); + g_free(timestamp); + if (write_status == G_IO_STATUS_AGAIN) { + continue; + } + } + } + write_status = g_io_channel_write_chars(_out_channel, buffer->str, buffer->len, &written, &error); if (_use_locks) { diff --git a/src/out.h b/src/out.h index 0a803e8..242e70c 100644 --- a/src/out.h +++ b/src/out.h @@ -3,7 +3,7 @@ #include -void init_output_channel(const gchar *log_file, gboolean use_locks, gboolean force_control_file, const gchar *chmod_str, const gchar *chown_str, const gchar *chgrp_str); +void init_output_channel(const gchar *log_file, gboolean use_locks, gboolean force_control_file, const gchar *chmod_str, const gchar *chown_str, const gchar *chgrp_str, const gchar *timestamp_prefix); void destroy_output_channel(); gboolean write_output_channel(GString *buffer); glong get_output_channel_age(); diff --git a/src/util.c b/src/util.c index 0189441..da2cc4e 100644 --- a/src/util.c +++ b/src/util.c @@ -115,6 +115,26 @@ gchar *compute_strftime_suffix(const gchar *str, const gchar *strftime_suffix) { return g_strdup_printf("%s%s", str, outstr); } +/** + * Format current timestamp prefix to prepend to a log line. + * + * @param strftime_prefix format with strftime placeholders to expand with current time. + * @return newly allocated string (free it with g_free) with the current timestamp prefix. + */ +gchar *compute_timestamp_prefix(const gchar *strftime_prefix) { + time_t t; + struct tm *tmp; + t = time(NULL); + tmp = localtime(&t); + g_assert(tmp != NULL); + char outstr[100]; + if (strftime(outstr, sizeof(outstr), strftime_prefix, tmp) == 0) { + g_critical("problem with strftime on %s", strftime_prefix); + return NULL; + } + return g_strdup(outstr); +} + /** * Compute absolute file path from directory path and file name * diff --git a/src/util.h b/src/util.h index 0310eb4..f961052 100644 --- a/src/util.h +++ b/src/util.h @@ -7,6 +7,7 @@ glong get_file_size(const gchar *file_path); glong get_current_timestamp(); gchar *compute_strftime_suffix(const gchar *str, const gchar *strftime_suffix); +gchar *compute_timestamp_prefix(const gchar *strftime_prefix); gchar *get_unique_hexa_identifier(); glong get_file_inode(const gchar *file_path); glong get_fd_inode(int fd);