From b54e9b8992aeb3abad7cf4b9fb4e600aef0b6f85 Mon Sep 17 00:00:00 2001 From: Luca Ferrari Date: Wed, 9 Feb 2022 05:41:51 -0500 Subject: [PATCH 1/4] [#45] Log rotation support. This is a possible implementation of log rotation. The idea is to have the following configuration option: - log_rotation_size expresses the bytes of max size for a file before its rotation; - log_rotation_age expresses the seconds since the last rotation. In order to allow log rotation, log_path must allow for strftime(3) format strings. Moreover, there is the need for a set of utility functions to quickly open and rotate the log file. The truncation is performed via the already existing log_mode configuration option. The parsing of log_roation_size accepts a number (bytes) and a few suffixes, like 'M' for megabytes. Similarly, log_rotation_age accepts a number (seconds) and a few suffixes like 'd' for days. Only one suffix is supported at a time. If the logging is done to console or in general not to a file, the rotation is disabled. There is a global variable within logginc.g that keeps track about the current filename as "expanded" from strftime, so that when a rotation is required, the file can be flushed and closed and a new one can be opened. Close #45 --- doc/CONFIGURATION.md | 4 +- src/include/logging.h | 19 +++ src/include/pgagroal.h | 3 + src/libpgagroal/configuration.c | 201 +++++++++++++++++++++++++++ src/libpgagroal/logging.c | 238 ++++++++++++++++++++++++++++---- 5 files changed, 434 insertions(+), 31 deletions(-) diff --git a/doc/CONFIGURATION.md b/doc/CONFIGURATION.md index 39ad7350..dc17f891 100644 --- a/doc/CONFIGURATION.md +++ b/doc/CONFIGURATION.md @@ -30,7 +30,9 @@ See a [sample](./etc/pgagroal/pgagroal.conf) configuration for running `pgagroal | log_type | console | String | No | The logging type (console, file, syslog) | | log_level | info | String | No | The logging level (fatal, error, warn, info, debug1, ..., debug5) | | log_path | pgagroal.log | String | No | The log file location | -| log_mode | append | String | No | Append to or create the log file (append, create) | +| log_rotation_age | -1 | String | No | The age that will trigger a log file rotation. If expressed as a positive number, is managed as minutes. Supports suffixes: 'H' (hours), 'D' (days), 'W' (weeks), 'M' (months) and 'Y' (years) | +| log_rotation_size | -1 | String | No | The size of the log file that will trigger a log rotation. Supports suffixes: 'B' (bytes), the default if omitted, 'K' (kilobytes), 'M' (megabytes), 'G' (gigabytes). | +| log_mode | append | String | No | Append to or create the log file (append, create). The create option truncates an already existing file. | | log_connections | `off` | Bool | No | Log connects | | log_disconnections | `off` | Bool | No | Log disconnects | | blocking_timeout | 30 | Int | No | The number of seconds the process will be blocking for a connection (disable = 0) | diff --git a/src/include/logging.h b/src/include/logging.h index ffd1bbf3..626076e8 100644 --- a/src/include/logging.h +++ b/src/include/logging.h @@ -52,6 +52,9 @@ extern "C" { #define PGAGROAL_LOGGING_MODE_CREATE 0 #define PGAGROAL_LOGGING_MODE_APPEND 1 +#define PGAGROAL_LOGGING_ROTATION_DISABLED -1 + + #define pgagroal_log_trace(...) pgagroal_log_line(PGAGROAL_LOGGING_LEVEL_DEBUG5, __FILE__, __LINE__, __VA_ARGS__) #define pgagroal_log_debug(...) pgagroal_log_line(PGAGROAL_LOGGING_LEVEL_DEBUG1, __FILE__, __LINE__, __VA_ARGS__) #define pgagroal_log_info(...) pgagroal_log_line(PGAGROAL_LOGGING_LEVEL_INFO, __FILE__, __LINE__, __VA_ARGS__) @@ -86,6 +89,22 @@ pgagroal_log_line(int level, char *file, int line, char *fmt, ...); void pgagroal_log_mem(void* data, size_t size); + +bool +log_rotation_enabled(void); + +void +log_rotation_disable(void); + +bool +log_rotation_required(void); + +bool +log_rotation_set_next_rotation_age(void); + +int +log_file_open(void); + #ifdef __cplusplus } #endif diff --git a/src/include/pgagroal.h b/src/include/pgagroal.h index c51cf8a4..25803631 100644 --- a/src/include/pgagroal.h +++ b/src/include/pgagroal.h @@ -304,6 +304,9 @@ struct configuration bool log_disconnections; /**< Log disconnects */ int log_mode; /**< The logging mode */ atomic_schar log_lock; /**< The logging lock */ + int log_rotation_size; /**< bytes to force log rotation */ + int log_rotation_age; /**< minutes for log rotation */ + bool log_truncate; /**< Truncate an existing log on rotation */ bool authquery; /**< Is authentication query enabled */ diff --git a/src/libpgagroal/configuration.c b/src/libpgagroal/configuration.c index 5e68ebac..b48ed1e8 100644 --- a/src/libpgagroal/configuration.c +++ b/src/libpgagroal/configuration.c @@ -49,6 +49,7 @@ #ifdef HAVE_LINUX #include #endif +#include #define LINE_LENGTH 512 @@ -58,6 +59,8 @@ static int as_bool(char* str, bool* b); static int as_logging_type(char* str); static int as_logging_level(char* str); static int as_logging_mode(char* str); +static int as_logging_rotation_size(char* str, int* size); +static int as_logging_rotation_age(char* str, int* age); static int as_validation(char* str); static int as_pipeline(char* str); static int as_hugepage(char* str); @@ -594,6 +597,36 @@ pgagroal_read_configuration(void* shm, char* filename) unknown = true; } } + else if (!strcmp(key, "log_rotation_size")) + { + if (!strcmp(section, "pgagroal")) + { + if (as_logging_rotation_size(value, &config->log_rotation_size)) + { + unknown = true; + } + } + else + { + unknown = true; + } + + } + else if (!strcmp(key, "log_rotation_age")) + { + if (!strcmp(section, "pgagroal")) + { + if (as_logging_rotation_age(value, &config->log_rotation_age)) + { + unknown = true; + } + } + else + { + unknown = true; + } + + } else if (!strcmp(key, "log_connections")) { if (!strcmp(section, "pgagroal")) @@ -2749,3 +2782,171 @@ is_empty_string(char* s) return true; } + + +/** + * Parses a string to see if it contains + * a valid value for log rotation size. + * Returns 0 if parsing ok, 1 otherwise. + * + * Valid strings have one of the suffixes: + * - k for kilobytes + * - m for megabytes + * - g for gigabytes + * + * The default is expressed always as kilobytes. The functions sets the + * rotation size in kilobytes. + */ +static int +as_logging_rotation_size(char* str, int* size) +{ + int multiplier = 1; + int index; + char value[MISC_LENGTH]; + bool multiplier_set = false; + + if (is_empty_string(str)) + { + *size = PGAGROAL_LOGGING_ROTATION_DISABLED; + return 0; + } + + index = 0; + for (int i = 0; i < strlen(str); i++) + { + if (isdigit(str[i])) + { + value[index++] = str[i]; + } + else if (isalpha(str[i]) && multiplier_set) + { + *size = PGAGROAL_LOGGING_ROTATION_DISABLED; + return 1; + } + else if (isalpha(str[i]) && ! multiplier_set) + { + + if (str[i] == 'M' || str[i] == 'm') + { + multiplier = 1024 * 1024; + multiplier_set = true; + } + else if(str[i] == 'G' || str[i] == 'g') + { + multiplier = 1024 * 1024 * 1024; + multiplier_set = true; + } + else if(str[i] == 'K' || str[i] == 'k') + { + multiplier = 1024; + multiplier_set = true; + } + else if(str[i] == 'B' || str[i] == 'b') + { + multiplier = 1; + multiplier_set = true; + } + } + else + // ignore alien chars + continue; + } + + value[index] = '\0'; + if (!as_int(value, size)) + { + *size = *size * multiplier; + return 0; + } + else + { + *size = PGAGROAL_LOGGING_ROTATION_DISABLED; + return 1; + } + +} + + +/** + * Parses the log_rotation_age string. + * The string accepts + * - h for hours + * - d for days + * - w for weeks + * - m for months + * - y for years + * + * The default is expressed in minutes. + * The function sets the number of rotationg age as minutes. + * Returns 1 for errors, 0 for correct parsing. + */ +static int +as_logging_rotation_age(char* str, int* age) +{ + int multiplier = 1; + int index; + char value[MISC_LENGTH]; + bool multiplier_set = false; + + if (is_empty_string(str)) + { + *age = PGAGROAL_LOGGING_ROTATION_DISABLED; + return 0; + } + + index = 0; + for (int i = 0; i < strlen(str); i++) + { + if (isdigit(str[i])) + { + value[index++] = str[i]; + } + else if (isalpha(str[i]) && multiplier_set) + { + *age = PGAGROAL_LOGGING_ROTATION_DISABLED; + return 1; + } + else if (isalpha(str[i]) && ! multiplier_set) + { + if (str[i] == 'h' || str[i] == 'H') + { + multiplier = 60; + multiplier_set = true; + } + else if (str[i] == 'd' || str[i] == 'D') + { + multiplier = 24 * 60; + multiplier_set = true; + } + else if (str[i] == 'w' || str[i] == 'W') + { + multiplier = 24 * 60 * 7; + multiplier_set = true; + } + else if (str[i] == 'm' || str[i] == 'M') + { + multiplier = 24 * 60 * 7 * 31; + multiplier_set = true; + } + else if (str[i] == 'y' || str[i] == 'Y') + { + multiplier = 24 * 60 * 365; + multiplier_set = true; + } + } + else + continue; + } + + value[index] = '\0'; + if (!as_int(value, age)) + { + *age = *age * multiplier; + return 0; + } + else + { + *age = PGAGROAL_LOGGING_ROTATION_DISABLED; + return 1; + } +} diff --git a/src/libpgagroal/logging.c b/src/libpgagroal/logging.c index 97d08a5d..0ec21c70 100644 --- a/src/libpgagroal/logging.c +++ b/src/libpgagroal/logging.c @@ -36,11 +36,20 @@ #include #include #include +#include +#include +#include +#include +#include #define LINE_LENGTH 32 FILE *log_file; +time_t next_log_rotation_age; /* number of seconds at which the next location will happen */ + +char current_log_path[MAX_PATH]; /* the current log file */ + static const char* levels[] = { "TRACE", @@ -61,6 +70,120 @@ static const char* colors[] = "\x1b[35m" }; + +/** + * Utility function to understand if log rotation + * is enabled or not. + * Returns `true` if the rotation is enabled. + */ +bool +log_rotation_enabled(void) +{ + struct configuration* config; + config = (struct configuration*)shmem; + + // disable log rotation in the case + // logging is not to a file + if (config->log_type != PGAGROAL_LOGGING_TYPE_FILE) + { + return false; + } + + // log rotation is enabled if either log_rotation_age or + // log_rotation_size is enabled + return config->log_rotation_age != PGAGROAL_LOGGING_ROTATION_DISABLED + || config->log_rotation_size != PGAGROAL_LOGGING_ROTATION_DISABLED; +} + +/** + * Forces a disabling of the log rotation. + * Useful when the system cannot determine how to rotate logs. + */ +void +log_rotation_disable(void) +{ + struct configuration* config; + config = (struct configuration*)shmem; + + config->log_rotation_age = PGAGROAL_LOGGING_ROTATION_DISABLED; + config->log_rotation_size = PGAGROAL_LOGGING_ROTATION_DISABLED; + next_log_rotation_age = 0; +} + +/** + * Checks if there are the requirements to perform a log rotation. + * It returns true in either the case of the size exceeded or + * the age exceeded. The age is contained into a global + * variable 'next_log_rotation_age' that express the number + * of seconds at which the next rotation will be performed. + */ +bool +log_rotation_required(void) +{ + struct stat log_stat; + struct configuration* config; + + config = (struct configuration*)shmem; + + if (!log_rotation_enabled()) + { + return false; + } + + if (stat(current_log_path, &log_stat)) + { + return false; + } + + if (config->log_rotation_size > 0 && log_stat.st_size >= config->log_rotation_size) + { + return true; + } + + if (config->log_rotation_age > 0 && next_log_rotation_age > 0 && next_log_rotation_age >= log_stat.st_ctime) + { + return true; + } + + return false; +} + +/** + * Function to compute the next instant at which a log rotation + * will happen. It computes only if the logging is to a file + * and only if the configuration tells to compute the rotation + * age. + * Returns true on success. + */ +bool +log_rotation_set_next_rotation_age(void) +{ + struct configuration* config; + time_t now; + + config = (struct configuration*)shmem; + + if (config->log_type == PGAGROAL_LOGGING_TYPE_FILE && config->log_rotation_age > 0) + { + now = time( NULL ); + if (!now) + { + config->log_rotation_age = PGAGROAL_LOGGING_ROTATION_DISABLED; + return false; + } + + next_log_rotation_age = now + config->log_rotation_age * 60; + return true; + } + else + { + config->log_rotation_age = PGAGROAL_LOGGING_ROTATION_DISABLED; + return false; + } + +} + + /** * */ @@ -73,35 +196,19 @@ pgagroal_init_logging(void) if (config->log_type == PGAGROAL_LOGGING_TYPE_FILE) { - if (strlen(config->log_path) > 0) - { - if (config->log_mode == PGAGROAL_LOGGING_MODE_APPEND) - { - log_file = fopen(config->log_path, "a"); - } - else - { - log_file = fopen(config->log_path, "w"); - } - } - else - { - if (config->log_mode == PGAGROAL_LOGGING_MODE_APPEND) - { - log_file = fopen("pgagroal.log", "a"); - } - else - { - log_file = fopen("pgagroal.log", "w"); - } - } + log_file_open(); if (!log_file) { printf("Failed to open log file %s due to %s\n", strlen(config->log_path) > 0 ? config->log_path : "pgagroal.log", strerror(errno)); errno = 0; + log_rotation_disable(); return 1; } + else + { + log_rotation_set_next_rotation_age(); + } } return 0; @@ -119,14 +226,7 @@ pgagroal_start_logging(void) if (config->log_type == PGAGROAL_LOGGING_TYPE_FILE) { - if (strlen(config->log_path) > 0) - { - log_file = fopen(config->log_path, "a"); - } - else - { - log_file = fopen("pgagroal.log", "a"); - } + log_file_open(); if (!log_file) { @@ -143,6 +243,79 @@ pgagroal_start_logging(void) return 0; } +/** + * Opens the log file defined in the configuration. + * Works only for a real log file, i.e., the configuration + * must be set up to log to a file, not console. + * + * The function considers the settings in the configuration + * to determine the mode (append, create) and the filename + * to open. + * + * It sets the global variable 'log_file'. + * + * Returns 0 on success, 1 on error. + */ +int +log_file_open(void) +{ + struct configuration* config; + time_t htime; + struct tm *tm; + + config = (struct configuration*)shmem; + + if (config->log_type == PGAGROAL_LOGGING_TYPE_FILE) + { + htime = time( NULL ); + if (!htime) + { + log_file = NULL; + return 1; + } + + tm = localtime(&htime); + if (tm == NULL ) + { + log_file = NULL; + return 1; + } + + if (strftime(current_log_path, sizeof(current_log_path), config->log_path, tm) <= 0 ) + { + // cannot parse the format string, fallback to default logging + memcpy(current_log_path, "pgagroal.log", strlen("pgagroal.log")); + log_rotation_disable(); + } + + log_file = fopen(current_log_path, + config->log_mode == PGAGROAL_LOGGING_MODE_APPEND ? "a" : "w"); + return 0; + } + + return 1; +} + +/** + * Performs a log file rotation. + * It flushes and closes the current log file, + * then re-opens it. + * + * DO NOT LOG WITHIN THIS FUNCTION as long as this + * is invoked by log_line + */ +void +log_file_rotate(void) +{ + if (log_rotation_enabled()) + { + fflush(log_file); + fclose(log_file); + log_file_open(); + } +} + + /** * */ @@ -229,6 +402,11 @@ pgagroal_log_line(int level, char *file, int line, char *fmt, ...) vfprintf(log_file, fmt, vl); fprintf(log_file, "\n"); fflush(log_file); + + if (log_rotation_required()) + { + log_file_rotate(); + } } else if (config->log_type == PGAGROAL_LOGGING_TYPE_SYSLOG) { From 6845c2cb39713c23880904305db05292dab887c4 Mon Sep 17 00:00:00 2001 From: Luca Ferrari Date: Thu, 24 Feb 2022 05:22:22 -0500 Subject: [PATCH 2/4] Force log rotation disabled when logging to console. Ensure that the log rotation will always be disabled if the system is configured to log to something different than a file. Improvements on log rotation. log_rotation_age is now expressed as seconds. Avoid re-creating the log file when init + start are called in sequence. --- doc/CONFIGURATION.md | 2 +- src/libpgagroal/configuration.c | 26 +++++++++++------------ src/libpgagroal/logging.c | 37 +++++++++++++++++++++++++-------- 3 files changed, 42 insertions(+), 23 deletions(-) diff --git a/doc/CONFIGURATION.md b/doc/CONFIGURATION.md index dc17f891..e28427d2 100644 --- a/doc/CONFIGURATION.md +++ b/doc/CONFIGURATION.md @@ -30,7 +30,7 @@ See a [sample](./etc/pgagroal/pgagroal.conf) configuration for running `pgagroal | log_type | console | String | No | The logging type (console, file, syslog) | | log_level | info | String | No | The logging level (fatal, error, warn, info, debug1, ..., debug5) | | log_path | pgagroal.log | String | No | The log file location | -| log_rotation_age | -1 | String | No | The age that will trigger a log file rotation. If expressed as a positive number, is managed as minutes. Supports suffixes: 'H' (hours), 'D' (days), 'W' (weeks), 'M' (months) and 'Y' (years) | +| log_rotation_age | -1 | String | No | The age that will trigger a log file rotation. If expressed as a positive number, is managed as seconds. Supports suffixes: 'S' (seconds, the default), 'M' (minutes), 'H' (hours), 'D' (days), 'W' (weeks) | | log_rotation_size | -1 | String | No | The size of the log file that will trigger a log rotation. Supports suffixes: 'B' (bytes), the default if omitted, 'K' (kilobytes), 'M' (megabytes), 'G' (gigabytes). | | log_mode | append | String | No | Append to or create the log file (append, create). The create option truncates an already existing file. | | log_connections | `off` | Bool | No | Log connects | diff --git a/src/libpgagroal/configuration.c b/src/libpgagroal/configuration.c index b48ed1e8..2bfbeff2 100644 --- a/src/libpgagroal/configuration.c +++ b/src/libpgagroal/configuration.c @@ -2870,13 +2870,13 @@ as_logging_rotation_size(char* str, int* size) /** * Parses the log_rotation_age string. * The string accepts + * - s for seconds + * - m for minutes * - h for hours * - d for days * - w for weeks - * - m for months - * - y for years * - * The default is expressed in minutes. + * The default is expressed in seconds. * The function sets the number of rotationg age as minutes. * Returns 1 for errors, 0 for correct parsing. */ @@ -2908,29 +2908,29 @@ as_logging_rotation_age(char* str, int* age) } else if (isalpha(str[i]) && ! multiplier_set) { - if (str[i] == 'h' || str[i] == 'H') + if (str[i] == 's' || str[i] == 'S') { - multiplier = 60; + multiplier = 1; multiplier_set = true; } - else if (str[i] == 'd' || str[i] == 'D') + else if (str[i] == 'm' || str[i] == 'M') { - multiplier = 24 * 60; + multiplier = 60; multiplier_set = true; } - else if (str[i] == 'w' || str[i] == 'W') + else if (str[i] == 'h' || str[i] == 'H') { - multiplier = 24 * 60 * 7; + multiplier = 3600; multiplier_set = true; } - else if (str[i] == 'm' || str[i] == 'M') + else if (str[i] == 'd' || str[i] == 'D') { - multiplier = 24 * 60 * 7 * 31; + multiplier = 24 * 3600; multiplier_set = true; } - else if (str[i] == 'y' || str[i] == 'Y') + else if (str[i] == 'w' || str[i] == 'W') { - multiplier = 24 * 60 * 365; + multiplier = 24 * 3600 * 7; multiplier_set = true; } } diff --git a/src/libpgagroal/logging.c b/src/libpgagroal/logging.c index 0ec21c70..b2f0dc1e 100644 --- a/src/libpgagroal/logging.c +++ b/src/libpgagroal/logging.c @@ -86,6 +86,7 @@ log_rotation_enabled(void) // logging is not to a file if (config->log_type != PGAGROAL_LOGGING_TYPE_FILE) { + log_rotation_disable(); return false; } @@ -140,7 +141,7 @@ log_rotation_required(void) return true; } - if (config->log_rotation_age > 0 && next_log_rotation_age > 0 && next_log_rotation_age >= log_stat.st_ctime) + if (config->log_rotation_age > 0 && next_log_rotation_age > 0 && next_log_rotation_age <= log_stat.st_ctime) { return true; } @@ -165,14 +166,14 @@ log_rotation_set_next_rotation_age(void) if (config->log_type == PGAGROAL_LOGGING_TYPE_FILE && config->log_rotation_age > 0) { - now = time( NULL ); + now = time(NULL); if (!now) { config->log_rotation_age = PGAGROAL_LOGGING_ROTATION_DISABLED; return false; } - next_log_rotation_age = now + config->log_rotation_age * 60; + next_log_rotation_age = now + config->log_rotation_age; return true; } else @@ -205,10 +206,6 @@ pgagroal_init_logging(void) log_rotation_disable(); return 1; } - else - { - log_rotation_set_next_rotation_age(); - } } return 0; @@ -224,7 +221,7 @@ pgagroal_start_logging(void) config = (struct configuration*)shmem; - if (config->log_type == PGAGROAL_LOGGING_TYPE_FILE) + if (config->log_type == PGAGROAL_LOGGING_TYPE_FILE && !log_file) { log_file_open(); @@ -254,6 +251,13 @@ pgagroal_start_logging(void) * * It sets the global variable 'log_file'. * + * If it succeed in opening the log file, it calls + * the log_rotation_set_next_rotation_age() function to + * determine the next instant at which the log file + * must be rotated. Calling such function is safe + * because if the log rotation is disabled, the function + * does nothing. + * * Returns 0 on success, 1 on error. */ int @@ -290,6 +294,20 @@ log_file_open(void) log_file = fopen(current_log_path, config->log_mode == PGAGROAL_LOGGING_MODE_APPEND ? "a" : "w"); + + if (!log_file) + return 1; + + log_rotation_set_next_rotation_age(); + /* printf("\n\nLog file %s initialized %d, rotation %sable (every %d bytes or %d seconds or so, next estimated at %ld epoch, now is %d)\n\n", + current_log_path, + config->log_level, + log_rotation_enabled() ? "en" : "dis", + config->log_rotation_size, + config->log_rotation_age, + (long) next_log_rotation_age, + (long) htime); + */ return 0; } @@ -405,7 +423,8 @@ pgagroal_log_line(int level, char *file, int line, char *fmt, ...) if (log_rotation_required()) { - log_file_rotate(); + printf("\nLOG ROTATION\n\n"); + log_file_rotate(); } } else if (config->log_type == PGAGROAL_LOGGING_TYPE_SYSLOG) From a3d5fd5aad64daede1130220affd6330431a2aab Mon Sep 17 00:00:00 2001 From: Luca Ferrari Date: Thu, 24 Feb 2022 10:59:48 -0500 Subject: [PATCH 3/4] [#44] Support for custom log line prefix. This introduces the configuration parameter `log_line_prefix` that accepts a strftime(3) valid string that is parsed and stored at the very first log entry in the configuration structure (`config->log_line_prefix`). Logging to a file and to the console is done using such prefix via strftime. Documentation updated. Close #44 --- doc/CONFIGURATION.md | 3 ++- src/include/logging.h | 1 + src/include/pgagroal.h | 2 +- src/libpgagroal/configuration.c | 16 ++++++++++++++++ src/libpgagroal/logging.c | 25 ++++++++++--------------- 5 files changed, 30 insertions(+), 17 deletions(-) diff --git a/doc/CONFIGURATION.md b/doc/CONFIGURATION.md index e28427d2..490d99ae 100644 --- a/doc/CONFIGURATION.md +++ b/doc/CONFIGURATION.md @@ -29,7 +29,8 @@ See a [sample](./etc/pgagroal/pgagroal.conf) configuration for running `pgagroal | management | 0 | Int | No | The remote management port (disable = 0) | | log_type | console | String | No | The logging type (console, file, syslog) | | log_level | info | String | No | The logging level (fatal, error, warn, info, debug1, ..., debug5) | -| log_path | pgagroal.log | String | No | The log file location | +| log_line_prefix | %Y-%m-%d %H:%M:%S | String | No | A prefix to place on every log entry, accepts escape sequences that strftime(3) can parse. No spaces between the string parts are allowed. | +| log_path | pgagroal.log | String | No | The log file location. Can include escape sequences that strftime(3) accepts, e.g., pgagroal-%Y-%m-%d-%H-%M-%S.log | | log_rotation_age | -1 | String | No | The age that will trigger a log file rotation. If expressed as a positive number, is managed as seconds. Supports suffixes: 'S' (seconds, the default), 'M' (minutes), 'H' (hours), 'D' (days), 'W' (weeks) | | log_rotation_size | -1 | String | No | The size of the log file that will trigger a log rotation. Supports suffixes: 'B' (bytes), the default if omitted, 'K' (kilobytes), 'M' (megabytes), 'G' (gigabytes). | | log_mode | append | String | No | Append to or create the log file (append, create). The create option truncates an already existing file. | diff --git a/src/include/logging.h b/src/include/logging.h index 626076e8..5a80de9d 100644 --- a/src/include/logging.h +++ b/src/include/logging.h @@ -54,6 +54,7 @@ extern "C" { #define PGAGROAL_LOGGING_ROTATION_DISABLED -1 +#define PGAGROAL_LOGGING_DEFAULT_LOG_LINE_PREFIX "%Y-%m-%d %H:%M:%S" #define pgagroal_log_trace(...) pgagroal_log_line(PGAGROAL_LOGGING_LEVEL_DEBUG5, __FILE__, __LINE__, __VA_ARGS__) #define pgagroal_log_debug(...) pgagroal_log_line(PGAGROAL_LOGGING_LEVEL_DEBUG1, __FILE__, __LINE__, __VA_ARGS__) diff --git a/src/include/pgagroal.h b/src/include/pgagroal.h index 25803631..81362ea4 100644 --- a/src/include/pgagroal.h +++ b/src/include/pgagroal.h @@ -306,7 +306,7 @@ struct configuration atomic_schar log_lock; /**< The logging lock */ int log_rotation_size; /**< bytes to force log rotation */ int log_rotation_age; /**< minutes for log rotation */ - bool log_truncate; /**< Truncate an existing log on rotation */ + char log_line_prefix[MISC_LENGTH]; /**< The logging prefix */ bool authquery; /**< Is authentication query enabled */ diff --git a/src/libpgagroal/configuration.c b/src/libpgagroal/configuration.c index 2bfbeff2..59ce242d 100644 --- a/src/libpgagroal/configuration.c +++ b/src/libpgagroal/configuration.c @@ -626,6 +626,22 @@ pgagroal_read_configuration(void* shm, char* filename) unknown = true; } + } + else if (!strcmp(key, "log_line_prefix")) + { + if (!strcmp(section, "pgagroal")) + { + max = strlen(value); + if (max > MISC_LENGTH - 1) + max = MISC_LENGTH - 1; + + memcpy(config->log_line_prefix, value, max); + } + else + { + unknown = true; + } + } else if (!strcmp(key, "log_connections")) { diff --git a/src/libpgagroal/logging.c b/src/libpgagroal/logging.c index b2f0dc1e..5d71499b 100644 --- a/src/libpgagroal/logging.c +++ b/src/libpgagroal/logging.c @@ -86,8 +86,8 @@ log_rotation_enabled(void) // logging is not to a file if (config->log_type != PGAGROAL_LOGGING_TYPE_FILE) { - log_rotation_disable(); - return false; + log_rotation_disable(); + return false; } // log rotation is enabled if either log_rotation_age or @@ -203,7 +203,7 @@ pgagroal_init_logging(void) { printf("Failed to open log file %s due to %s\n", strlen(config->log_path) > 0 ? config->log_path : "pgagroal.log", strerror(errno)); errno = 0; - log_rotation_disable(); + log_rotation_disable(); return 1; } } @@ -299,15 +299,6 @@ log_file_open(void) return 1; log_rotation_set_next_rotation_age(); - /* printf("\n\nLog file %s initialized %d, rotation %sable (every %d bytes or %d seconds or so, next estimated at %ld epoch, now is %d)\n\n", - current_log_path, - config->log_level, - log_rotation_enabled() ? "en" : "dis", - config->log_rotation_size, - config->log_rotation_age, - (long) next_log_rotation_age, - (long) htime); - */ return 0; } @@ -400,11 +391,16 @@ pgagroal_log_line(int level, char *file, int line, char *fmt, ...) filename = file; } + if (config->log_line_prefix == NULL || strlen(config->log_line_prefix) == 0) + { + memcpy(config->log_line_prefix,PGAGROAL_LOGGING_DEFAULT_LOG_LINE_PREFIX,strlen(PGAGROAL_LOGGING_DEFAULT_LOG_LINE_PREFIX)); + } + va_start(vl, fmt); if (config->log_type == PGAGROAL_LOGGING_TYPE_CONSOLE) { - buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm)] = '\0'; + buf[strftime(buf, sizeof(buf), config->log_line_prefix, tm)] = '\0'; fprintf(stdout, "%s %s%-5s\x1b[0m \x1b[90m%s:%d\x1b[0m ", buf, colors[level - 1], levels[level - 1], filename, line); @@ -414,7 +410,7 @@ pgagroal_log_line(int level, char *file, int line, char *fmt, ...) } else if (config->log_type == PGAGROAL_LOGGING_TYPE_FILE) { - buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm)] = '\0'; + buf[strftime(buf, sizeof(buf), config->log_line_prefix, tm)] = '\0'; fprintf(log_file, "%s %-5s %s:%d ", buf, levels[level - 1], filename, line); vfprintf(log_file, fmt, vl); @@ -423,7 +419,6 @@ pgagroal_log_line(int level, char *file, int line, char *fmt, ...) if (log_rotation_required()) { - printf("\nLOG ROTATION\n\n"); log_file_rotate(); } } From 882e013051cce6b40f99688f47ab94cc6ba484f2 Mon Sep 17 00:00:00 2001 From: Luca Ferrari Date: Thu, 24 Feb 2022 12:01:46 -0500 Subject: [PATCH 4/4] Utabify --- src/libpgagroal/configuration.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libpgagroal/configuration.c b/src/libpgagroal/configuration.c index 59ce242d..824bf07a 100644 --- a/src/libpgagroal/configuration.c +++ b/src/libpgagroal/configuration.c @@ -627,15 +627,15 @@ pgagroal_read_configuration(void* shm, char* filename) } } - else if (!strcmp(key, "log_line_prefix")) + else if (!strcmp(key, "log_line_prefix")) { if (!strcmp(section, "pgagroal")) { max = strlen(value); - if (max > MISC_LENGTH - 1) - max = MISC_LENGTH - 1; + if (max > MISC_LENGTH - 1) + max = MISC_LENGTH - 1; - memcpy(config->log_line_prefix, value, max); + memcpy(config->log_line_prefix, value, max); } else {