From df2582990d727558708ceb9b1c6b3fc3cef1a0f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Mon, 2 Dec 2024 09:07:05 +0200 Subject: [PATCH] MDEV-33763 : Buffered error logging for Server error log New read-only system variables (set at startup, need --log-error): * log_error_file_buffer_size: error log buffer size, default 0 (off) * log_error_file_rotate_size: rotate the error log above this size, default 1073741824 * log_error_file_rotations: number of rotated files kept, default 0 Changes: * Write the error log through the logger service, which batches writes in an in-memory buffer, when log_error_file_buffer_size is set. * print_buffer_to_file() uses one static buffer, allocated on first use (MAX_LOG_BUFFER_SIZE+1), grown as needed and freed at shutdown. * vprint_msg_to_log() writes lines longer than 1024 bytes in full, up to 1 MB. * Galera messages use the same error log path. Debug messages are written only if wsrep_debug is set. * Add mtr tests for the three variables, buffered logging, rotation and long lines. Assisted-by: https://mariadb.org/governance/governance-ai-policy/ --- include/m_ctype.h | 3 +- include/mysql/plugin_audit.h.pp | 8 + include/mysql/plugin_auth.h.pp | 8 + include/mysql/plugin_data_type.h.pp | 8 + include/mysql/plugin_encryption.h.pp | 8 + include/mysql/plugin_ftparser.h.pp | 8 + include/mysql/plugin_function.h.pp | 8 + include/mysql/plugin_password_validation.h.pp | 8 + include/mysql/service_logger.h | 28 ++- mysql-test/main/log_error_buffered.opt | 1 + mysql-test/main/log_error_buffered.result | 10 ++ mysql-test/main/log_error_buffered.test | 30 ++++ mysql-test/main/log_error_long_line.result | 2 + mysql-test/main/log_error_long_line.test | 25 +++ mysql-test/main/log_error_rotate.opt | 3 + mysql-test/main/log_error_rotate.result | 9 + mysql-test/main/log_error_rotate.test | 31 ++++ mysql-test/main/mysqld--help.result | 10 ++ .../r/log_error_file_buffer_size_basic.result | 26 +++ .../r/log_error_file_rotate_size_basic.result | 26 +++ .../r/log_error_file_rotations_basic.result | 26 +++ .../r/sysvars_server_notembedded.result | 30 ++++ .../t/log_error_file_buffer_size_basic.test | 20 +++ .../t/log_error_file_rotate_size_basic.test | 20 +++ .../t/log_error_file_rotations_basic.test | 20 +++ mysys/file_logger.c | 52 ++++++ sql/log.cc | 164 ++++++++++++++++-- sql/log.h | 2 + sql/mysqld.cc | 19 +- sql/mysqld.h | 6 + sql/privilege.h | 3 + sql/signal_handler.cc | 7 +- sql/sql_parse.cc | 3 +- sql/sql_plugin_services.inl | 2 + sql/sys_vars.cc | 28 ++- 35 files changed, 630 insertions(+), 32 deletions(-) create mode 100644 mysql-test/main/log_error_buffered.opt create mode 100644 mysql-test/main/log_error_buffered.result create mode 100644 mysql-test/main/log_error_buffered.test create mode 100644 mysql-test/main/log_error_long_line.result create mode 100644 mysql-test/main/log_error_long_line.test create mode 100644 mysql-test/main/log_error_rotate.opt create mode 100644 mysql-test/main/log_error_rotate.result create mode 100644 mysql-test/main/log_error_rotate.test create mode 100644 mysql-test/suite/sys_vars/r/log_error_file_buffer_size_basic.result create mode 100644 mysql-test/suite/sys_vars/r/log_error_file_rotate_size_basic.result create mode 100644 mysql-test/suite/sys_vars/r/log_error_file_rotations_basic.result create mode 100644 mysql-test/suite/sys_vars/t/log_error_file_buffer_size_basic.test create mode 100644 mysql-test/suite/sys_vars/t/log_error_file_rotate_size_basic.test create mode 100644 mysql-test/suite/sys_vars/t/log_error_file_rotations_basic.test diff --git a/include/m_ctype.h b/include/m_ctype.h index d8e11012d5e..db9d82918d5 100644 --- a/include/m_ctype.h +++ b/include/m_ctype.h @@ -29,7 +29,8 @@ enum loglevel { ERROR_LEVEL= 0, WARNING_LEVEL= 1, - INFORMATION_LEVEL= 2 + INFORMATION_LEVEL= 2, + DEBUG_LEVEL= 3 }; #ifdef __cplusplus diff --git a/include/mysql/plugin_audit.h.pp b/include/mysql/plugin_audit.h.pp index d0be440ecf7..7bc154e0482 100644 --- a/include/mysql/plugin_audit.h.pp +++ b/include/mysql/plugin_audit.h.pp @@ -129,6 +129,10 @@ extern struct logger_service_st { LOGGER_HANDLE* (*open)(const char *path, unsigned long long size_limit, unsigned int rotations, size_t buffer_size); + LOGGER_HANDLE* (*init)(FILE *file, + const char *path, + unsigned long long size_limit, + unsigned int rotations, size_t buffer_size); int (*close)(LOGGER_HANDLE *log); int (*vprintf)(LOGGER_HANDLE *log, const char *fmt, va_list argptr) __attribute__((format(printf, 2, 0))); @@ -146,6 +150,10 @@ extern struct logger_service_st { LOGGER_HANDLE *logger_open(const char *path, unsigned long long size_limit, unsigned int rotations, size_t buffer_size); + LOGGER_HANDLE *logger_init(FILE *file, + const char* path, + unsigned long long size_limit, + unsigned int rotations, size_t buffer_size); int logger_close(LOGGER_HANDLE *log); int logger_vprintf(LOGGER_HANDLE *log, const char *fmt, va_list argptr) __attribute__((format(printf, 2, 0))); diff --git a/include/mysql/plugin_auth.h.pp b/include/mysql/plugin_auth.h.pp index 6a68eb9723f..9b706bcea7b 100644 --- a/include/mysql/plugin_auth.h.pp +++ b/include/mysql/plugin_auth.h.pp @@ -129,6 +129,10 @@ extern struct logger_service_st { LOGGER_HANDLE* (*open)(const char *path, unsigned long long size_limit, unsigned int rotations, size_t buffer_size); + LOGGER_HANDLE* (*init)(FILE *file, + const char *path, + unsigned long long size_limit, + unsigned int rotations, size_t buffer_size); int (*close)(LOGGER_HANDLE *log); int (*vprintf)(LOGGER_HANDLE *log, const char *fmt, va_list argptr) __attribute__((format(printf, 2, 0))); @@ -146,6 +150,10 @@ extern struct logger_service_st { LOGGER_HANDLE *logger_open(const char *path, unsigned long long size_limit, unsigned int rotations, size_t buffer_size); + LOGGER_HANDLE *logger_init(FILE *file, + const char* path, + unsigned long long size_limit, + unsigned int rotations, size_t buffer_size); int logger_close(LOGGER_HANDLE *log); int logger_vprintf(LOGGER_HANDLE *log, const char *fmt, va_list argptr) __attribute__((format(printf, 2, 0))); diff --git a/include/mysql/plugin_data_type.h.pp b/include/mysql/plugin_data_type.h.pp index 5b4d8b153e9..72243262519 100644 --- a/include/mysql/plugin_data_type.h.pp +++ b/include/mysql/plugin_data_type.h.pp @@ -129,6 +129,10 @@ extern struct logger_service_st { LOGGER_HANDLE* (*open)(const char *path, unsigned long long size_limit, unsigned int rotations, size_t buffer_size); + LOGGER_HANDLE* (*init)(FILE *file, + const char* path, + unsigned long long size_limit, + unsigned int rotations, size_t buffer_size); int (*close)(LOGGER_HANDLE *log); int (*vprintf)(LOGGER_HANDLE *log, const char *fmt, va_list argptr) __attribute__((format(printf, 2, 0))); @@ -146,6 +150,10 @@ extern struct logger_service_st { LOGGER_HANDLE *logger_open(const char *path, unsigned long long size_limit, unsigned int rotations, size_t buffer_size); + LOGGER_HANDLE *logger_init(FILE *file, + const char* path, + unsigned long long size_limit, + unsigned int rotations, size_t buffer_size); int logger_close(LOGGER_HANDLE *log); int logger_vprintf(LOGGER_HANDLE *log, const char *fmt, va_list argptr) __attribute__((format(printf, 2, 0))); diff --git a/include/mysql/plugin_encryption.h.pp b/include/mysql/plugin_encryption.h.pp index 9eefb757cb7..36461bdb6b2 100644 --- a/include/mysql/plugin_encryption.h.pp +++ b/include/mysql/plugin_encryption.h.pp @@ -129,6 +129,10 @@ extern struct logger_service_st { LOGGER_HANDLE* (*open)(const char *path, unsigned long long size_limit, unsigned int rotations, size_t buffer_size); + LOGGER_HANDLE* (*init)(FILE *file, + const char *path, + unsigned long long size_limit, + unsigned int rotations, size_t buffer_size); int (*close)(LOGGER_HANDLE *log); int (*vprintf)(LOGGER_HANDLE *log, const char *fmt, va_list argptr) __attribute__((format(printf, 2, 0))); @@ -146,6 +150,10 @@ extern struct logger_service_st { LOGGER_HANDLE *logger_open(const char *path, unsigned long long size_limit, unsigned int rotations, size_t buffer_size); + LOGGER_HANDLE *logger_init(FILE *file, + const char* path, + unsigned long long size_limit, + unsigned int rotations, size_t buffer_size); int logger_close(LOGGER_HANDLE *log); int logger_vprintf(LOGGER_HANDLE *log, const char *fmt, va_list argptr) __attribute__((format(printf, 2, 0))); diff --git a/include/mysql/plugin_ftparser.h.pp b/include/mysql/plugin_ftparser.h.pp index cead92423a5..e8e94bc0f91 100644 --- a/include/mysql/plugin_ftparser.h.pp +++ b/include/mysql/plugin_ftparser.h.pp @@ -129,6 +129,10 @@ extern struct logger_service_st { LOGGER_HANDLE* (*open)(const char *path, unsigned long long size_limit, unsigned int rotations, size_t buffer_size); + LOGGER_HANDLE* (*init)(FILE *file, + const char *path, + unsigned long long size_limit, + unsigned int rotations, size_t buffer_size); int (*close)(LOGGER_HANDLE *log); int (*vprintf)(LOGGER_HANDLE *log, const char *fmt, va_list argptr) __attribute__((format(printf, 2, 0))); @@ -146,6 +150,10 @@ extern struct logger_service_st { LOGGER_HANDLE *logger_open(const char *path, unsigned long long size_limit, unsigned int rotations, size_t buffer_size); + LOGGER_HANDLE *logger_init(FILE *file, + const char* path, + unsigned long long size_limit, + unsigned int rotations, size_t buffer_size); int logger_close(LOGGER_HANDLE *log); int logger_vprintf(LOGGER_HANDLE *log, const char *fmt, va_list argptr) __attribute__((format(printf, 2, 0))); diff --git a/include/mysql/plugin_function.h.pp b/include/mysql/plugin_function.h.pp index c6cfc6a35ce..8ac3e848cc1 100644 --- a/include/mysql/plugin_function.h.pp +++ b/include/mysql/plugin_function.h.pp @@ -129,6 +129,10 @@ extern struct logger_service_st { LOGGER_HANDLE* (*open)(const char *path, unsigned long long size_limit, unsigned int rotations, size_t buffer_size); + LOGGER_HANDLE* (*init)(FILE *file, + const char *path, + unsigned long long size_limit, + unsigned int rotations, size_t buffer_size); int (*close)(LOGGER_HANDLE *log); int (*vprintf)(LOGGER_HANDLE *log, const char *fmt, va_list argptr) __attribute__((format(printf, 2, 0))); @@ -146,6 +150,10 @@ extern struct logger_service_st { LOGGER_HANDLE *logger_open(const char *path, unsigned long long size_limit, unsigned int rotations, size_t buffer_size); + LOGGER_HANDLE *logger_init(FILE *file, + const char* path, + unsigned long long size_limit, + unsigned int rotations, size_t buffer_size); int logger_close(LOGGER_HANDLE *log); int logger_vprintf(LOGGER_HANDLE *log, const char *fmt, va_list argptr) __attribute__((format(printf, 2, 0))); diff --git a/include/mysql/plugin_password_validation.h.pp b/include/mysql/plugin_password_validation.h.pp index c7d00ec2e6a..24a9bb3c7f4 100644 --- a/include/mysql/plugin_password_validation.h.pp +++ b/include/mysql/plugin_password_validation.h.pp @@ -129,6 +129,10 @@ extern struct logger_service_st { LOGGER_HANDLE* (*open)(const char *path, unsigned long long size_limit, unsigned int rotations, size_t buffer_size); + LOGGER_HANDLE* (*init)(FILE *file, + const char *path, + unsigned long long size_limit, + unsigned int rotations, size_t buffer_size); int (*close)(LOGGER_HANDLE *log); int (*vprintf)(LOGGER_HANDLE *log, const char *fmt, va_list argptr) __attribute__((format(printf, 2, 0))); @@ -146,6 +150,10 @@ extern struct logger_service_st { LOGGER_HANDLE *logger_open(const char *path, unsigned long long size_limit, unsigned int rotations, size_t buffer_size); + LOGGER_HANDLE *logger_init(FILE *file, + const char* path, + unsigned long long size_limit, + unsigned int rotations, size_t buffer_size); int logger_close(LOGGER_HANDLE *log); int logger_vprintf(LOGGER_HANDLE *log, const char *fmt, va_list argptr) __attribute__((format(printf, 2, 0))); diff --git a/include/mysql/service_logger.h b/include/mysql/service_logger.h index d11dd4291ae..07f2bb4253a 100644 --- a/include/mysql/service_logger.h +++ b/include/mysql/service_logger.h @@ -18,6 +18,7 @@ #ifndef MYSQL_ABI_CHECK #include +#include #endif #include @@ -25,17 +26,22 @@ @file logger service - Log file with rotation implementation. + Log file with buffered writing and rotation implementation. - This service implements logging with possible rotation - of the log files. Interface intentionally tries to be similar to FILE* - related functions. + This service implements logging with possible buffered writing + and rotation of the log files. Interface intentionally tries to + be similar to FILE* related functions. So that one can open the log with logger_open(), specifying - the limit on the logfile size and the rotations number. + the limit on the logfile size, possible buffer size and the + rotations number. + + If buffer size is given, messages are written to buffer. + If size of messages in buffer grow over the specified + limit, they are written to logfile. Then it's possible to write messages to the log with - logger_printf or logger_vprintf functions. + logger_printf, logger_vprintf or logger_write functions. As the size of the logfile grows over the specified limit, it is renamed to 'logfile.1'. The former 'logfile.1' becomes @@ -65,6 +71,10 @@ extern struct logger_service_st { LOGGER_HANDLE* (*open)(const char *path, unsigned long long size_limit, unsigned int rotations, size_t buffer_size); + LOGGER_HANDLE* (*init)(FILE *file, + const char *path, + unsigned long long size_limit, + unsigned int rotations, size_t buffer_size); int (*close)(LOGGER_HANDLE *log); int (*vprintf)(LOGGER_HANDLE *log, const char *fmt, va_list argptr) ATTRIBUTE_FORMAT_FPTR(printf, 2, 0); @@ -84,6 +94,8 @@ extern struct logger_service_st { #define logger_init_mutexes logger_service->logger_init_mutexes #define logger_open(path, size_limit, rotations, buffer_size) \ (logger_service->open(path, size_limit, rotations, buffer_size)) +#define logger_init(file, path, size_limit, rotations, buffer_size) \ + (logger_service->init(file, path, size_limit, rotations, buffer_size)) #define logger_close(log) (logger_service->close(log)) #define logger_rotate(log) (logger_service->rotate(log)) #define logger_vprintf(log, fmt, argptr) (logger_service->\ @@ -104,6 +116,10 @@ extern struct logger_service_st { LOGGER_HANDLE *logger_open(const char *path, unsigned long long size_limit, unsigned int rotations, size_t buffer_size); + LOGGER_HANDLE *logger_init(FILE *file, + const char* path, + unsigned long long size_limit, + unsigned int rotations, size_t buffer_size); int logger_close(LOGGER_HANDLE *log); int logger_vprintf(LOGGER_HANDLE *log, const char *fmt, va_list argptr) ATTRIBUTE_FORMAT(printf, 2, 0); diff --git a/mysql-test/main/log_error_buffered.opt b/mysql-test/main/log_error_buffered.opt new file mode 100644 index 00000000000..ce3930bb707 --- /dev/null +++ b/mysql-test/main/log_error_buffered.opt @@ -0,0 +1 @@ +--log-error-file-buffer-size=1024 diff --git a/mysql-test/main/log_error_buffered.result b/mysql-test/main/log_error_buffered.result new file mode 100644 index 00000000000..d3bab538f39 --- /dev/null +++ b/mysql-test/main/log_error_buffered.result @@ -0,0 +1,10 @@ +call mtr.add_suppression("Access denied for user"); +SELECT @@global.log_error_file_buffer_size; +@@global.log_error_file_buffer_size +1024 +SET @old_log_warnings= @@global.log_warnings; +SET GLOBAL log_warnings= 2; +connection default; +SET GLOBAL log_warnings= @old_log_warnings; +# restart +FOUND 1 /\[Warning\] Access denied for user 'no_such_user_39'/ in mysqld.1.err diff --git a/mysql-test/main/log_error_buffered.test b/mysql-test/main/log_error_buffered.test new file mode 100644 index 00000000000..53b09e99039 --- /dev/null +++ b/mysql-test/main/log_error_buffered.test @@ -0,0 +1,30 @@ +--source include/not_embedded.inc + +call mtr.add_suppression("Access denied for user"); + +SELECT @@global.log_error_file_buffer_size; + +SET @old_log_warnings= @@global.log_warnings; +SET GLOBAL log_warnings= 2; + +--disable_query_log +--disable_result_log +--let $i= 0 +while ($i < 40) +{ + --error ER_ACCESS_DENIED_ERROR + --connect (con_bad_$i,localhost,no_such_user_$i,wrong_password,test) + --inc $i +} +--enable_result_log +--enable_query_log +--connection default + +SET GLOBAL log_warnings= @old_log_warnings; + +# Shutdown flushes the buffered log +--source include/restart_mysqld.inc + +--let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let SEARCH_PATTERN= \[Warning\] Access denied for user 'no_such_user_39' +--source include/search_pattern_in_file.inc diff --git a/mysql-test/main/log_error_long_line.result b/mysql-test/main/log_error_long_line.result new file mode 100644 index 00000000000..14c7bfd0eed --- /dev/null +++ b/mysql-test/main/log_error_long_line.result @@ -0,0 +1,2 @@ +FOUND 1 /Unknown/unsupported storage engine: a{3000}/ in log_error_long_line.err +FOUND 1 /Unknown/unsupported storage engine: a{3000}/ in log_error_long_line.err diff --git a/mysql-test/main/log_error_long_line.test b/mysql-test/main/log_error_long_line.test new file mode 100644 index 00000000000..51965dcd609 --- /dev/null +++ b/mysql-test/main/log_error_long_line.test @@ -0,0 +1,25 @@ +--source include/not_embedded.inc + +# +# Error log lines longer than 1024 bytes are written in full, both with +# and without buffered error logging. +# +--let $name= `SELECT REPEAT('a', 3000)` +--let $datadir= $MYSQLTEST_VARDIR/tmp/log_error_long_line_data +--let $log= $MYSQLTEST_VARDIR/tmp/log_error_long_line.err +--mkdir $datadir + +--let $i= 0 +while ($i < 2) +{ + --let $buffer_size= `SELECT $i * 1024` + --error 0,1,2 + --exec $MYSQLD --no-defaults --datadir=$datadir --skip-networking --socket=$MYSQLTEST_VARDIR/tmp/log_error_long_line.sock --log-error=$log --log-error-file-buffer-size=$buffer_size --default-storage-engine=$name + --let SEARCH_FILE= $log + --let SEARCH_PATTERN= Unknown/unsupported storage engine: a{3000} + --source include/search_pattern_in_file.inc + --remove_file $log + --inc $i +} + +--rmdir $datadir diff --git a/mysql-test/main/log_error_rotate.opt b/mysql-test/main/log_error_rotate.opt new file mode 100644 index 00000000000..938d37bdb72 --- /dev/null +++ b/mysql-test/main/log_error_rotate.opt @@ -0,0 +1,3 @@ +--log-error-file-buffer-size=1024 +--log-error-file-rotate-size=4096 +--log-error-file-rotations=2 diff --git a/mysql-test/main/log_error_rotate.result b/mysql-test/main/log_error_rotate.result new file mode 100644 index 00000000000..e5d8f847114 --- /dev/null +++ b/mysql-test/main/log_error_rotate.result @@ -0,0 +1,9 @@ +call mtr.add_suppression("Access denied for user"); +SELECT @@global.log_error_file_buffer_size, @@global.log_error_file_rotate_size, @@global.log_error_file_rotations; +@@global.log_error_file_buffer_size @@global.log_error_file_rotate_size @@global.log_error_file_rotations +1024 4096 2 +SET @old_log_warnings= @@global.log_warnings; +SET GLOBAL log_warnings= 2; +connection default; +SET GLOBAL log_warnings= @old_log_warnings; +# restart diff --git a/mysql-test/main/log_error_rotate.test b/mysql-test/main/log_error_rotate.test new file mode 100644 index 00000000000..a968c2dc1d4 --- /dev/null +++ b/mysql-test/main/log_error_rotate.test @@ -0,0 +1,31 @@ +--source include/not_embedded.inc + +call mtr.add_suppression("Access denied for user"); + +SELECT @@global.log_error_file_buffer_size, @@global.log_error_file_rotate_size, @@global.log_error_file_rotations; + +SET @old_log_warnings= @@global.log_warnings; +SET GLOBAL log_warnings= 2; + +--disable_query_log +--disable_result_log +--let $i= 0 +while ($i < 120) +{ + --error ER_ACCESS_DENIED_ERROR + --connect (con_bad_$i,localhost,no_such_user_$i,wrong_password,test) + --inc $i +} +--enable_result_log +--enable_query_log +--connection default + +SET GLOBAL log_warnings= @old_log_warnings; + +# Shutdown flushes the buffered log +--source include/restart_mysqld.inc + +--file_exists $MYSQLTEST_VARDIR/log/mysqld.1.err.1 +--file_exists $MYSQLTEST_VARDIR/log/mysqld.1.err.2 +--error 1 +--file_exists $MYSQLTEST_VARDIR/log/mysqld.1.err.3 diff --git a/mysql-test/main/mysqld--help.result b/mysql-test/main/mysqld--help.result index 82a85e0faae..8238a793d3d 100644 --- a/mysql-test/main/mysqld--help.result +++ b/mysql-test/main/mysqld--help.result @@ -558,6 +558,13 @@ The following specify which files/extra groups are read (specified before remain --log-error[=name] Log errors to file (instead of stdout). If file name is not specified then 'datadir'/'log-basename'.err or the 'pid-file' path with extension .err is used + --log-error-file-buffer-size=# + Size of error log file buffer to make error logging + faster. Can be set only at startup and requires log-error + --log-error-file-rotate-size=# + Rotate the error log when it grows larger than that + --log-error-file-rotations=# + Number of rotations before old error log is removed --log-isam[=name] Log all MyISAM changes to file --log-output=name How logs should be written. Any combination of: NONE, FILE, TABLE, or ALL to set all combinations @@ -1873,6 +1880,9 @@ log-bin-trust-function-creators FALSE log-ddl-recovery ddl_recovery.log log-disabled-statements sp log-error +log-error-file-buffer-size 0 +log-error-file-rotate-size 1073741824 +log-error-file-rotations 0 log-isam myisam.log log-output FILE log-queries-not-using-indexes FALSE diff --git a/mysql-test/suite/sys_vars/r/log_error_file_buffer_size_basic.result b/mysql-test/suite/sys_vars/r/log_error_file_buffer_size_basic.result new file mode 100644 index 00000000000..2a2b1bca067 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/log_error_file_buffer_size_basic.result @@ -0,0 +1,26 @@ +select @@global.log_error_file_buffer_size; +@@global.log_error_file_buffer_size +0 +select @@session.log_error_file_buffer_size; +ERROR HY000: Variable 'log_error_file_buffer_size' is a GLOBAL variable +show global variables like 'log_error_file_buffer_size'; +Variable_name Value +log_error_file_buffer_size 0 +show session variables like 'log_error_file_buffer_size'; +Variable_name Value +log_error_file_buffer_size 0 +select variable_name from information_schema.global_variables where variable_name='log_error_file_buffer_size'; +variable_name +LOG_ERROR_FILE_BUFFER_SIZE +select variable_name from information_schema.session_variables where variable_name='log_error_file_buffer_size'; +variable_name +LOG_ERROR_FILE_BUFFER_SIZE +set session log_error_file_buffer_size=1; +ERROR HY000: Variable 'log_error_file_buffer_size' is a read only variable +set global log_error_file_buffer_size=1; +ERROR HY000: Variable 'log_error_file_buffer_size' is a read only variable +set global log_error_file_buffer_size=default; +ERROR HY000: Variable 'log_error_file_buffer_size' is a read only variable +select @@global.log_error_file_buffer_size; +@@global.log_error_file_buffer_size +0 diff --git a/mysql-test/suite/sys_vars/r/log_error_file_rotate_size_basic.result b/mysql-test/suite/sys_vars/r/log_error_file_rotate_size_basic.result new file mode 100644 index 00000000000..b91e0eed16d --- /dev/null +++ b/mysql-test/suite/sys_vars/r/log_error_file_rotate_size_basic.result @@ -0,0 +1,26 @@ +select @@global.log_error_file_rotate_size; +@@global.log_error_file_rotate_size +1073741824 +select @@session.log_error_file_rotate_size; +ERROR HY000: Variable 'log_error_file_rotate_size' is a GLOBAL variable +show global variables like 'log_error_file_rotate_size'; +Variable_name Value +log_error_file_rotate_size 1073741824 +show session variables like 'log_error_file_rotate_size'; +Variable_name Value +log_error_file_rotate_size 1073741824 +select variable_name from information_schema.global_variables where variable_name='log_error_file_rotate_size'; +variable_name +LOG_ERROR_FILE_ROTATE_SIZE +select variable_name from information_schema.session_variables where variable_name='log_error_file_rotate_size'; +variable_name +LOG_ERROR_FILE_ROTATE_SIZE +set session log_error_file_rotate_size=1; +ERROR HY000: Variable 'log_error_file_rotate_size' is a read only variable +set global log_error_file_rotate_size=1; +ERROR HY000: Variable 'log_error_file_rotate_size' is a read only variable +set global log_error_file_rotate_size=default; +ERROR HY000: Variable 'log_error_file_rotate_size' is a read only variable +select @@global.log_error_file_rotate_size; +@@global.log_error_file_rotate_size +1073741824 diff --git a/mysql-test/suite/sys_vars/r/log_error_file_rotations_basic.result b/mysql-test/suite/sys_vars/r/log_error_file_rotations_basic.result new file mode 100644 index 00000000000..2cc9ca959bd --- /dev/null +++ b/mysql-test/suite/sys_vars/r/log_error_file_rotations_basic.result @@ -0,0 +1,26 @@ +select @@global.log_error_file_rotations; +@@global.log_error_file_rotations +0 +select @@session.log_error_file_rotations; +ERROR HY000: Variable 'log_error_file_rotations' is a GLOBAL variable +show global variables like 'log_error_file_rotations'; +Variable_name Value +log_error_file_rotations 0 +show session variables like 'log_error_file_rotations'; +Variable_name Value +log_error_file_rotations 0 +select variable_name from information_schema.global_variables where variable_name='log_error_file_rotations'; +variable_name +LOG_ERROR_FILE_ROTATIONS +select variable_name from information_schema.session_variables where variable_name='log_error_file_rotations'; +variable_name +LOG_ERROR_FILE_ROTATIONS +set session log_error_file_rotations=1; +ERROR HY000: Variable 'log_error_file_rotations' is a read only variable +set global log_error_file_rotations=1; +ERROR HY000: Variable 'log_error_file_rotations' is a read only variable +set global log_error_file_rotations=default; +ERROR HY000: Variable 'log_error_file_rotations' is a read only variable +select @@global.log_error_file_rotations; +@@global.log_error_file_rotations +0 diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index 87972c6c877..09574f477ca 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -1932,6 +1932,36 @@ NUMERIC_BLOCK_SIZE NULL ENUM_VALUE_LIST NULL READ_ONLY YES COMMAND_LINE_ARGUMENT OPTIONAL +VARIABLE_NAME LOG_ERROR_FILE_BUFFER_SIZE +VARIABLE_SCOPE GLOBAL +VARIABLE_TYPE BIGINT UNSIGNED +VARIABLE_COMMENT Size of error log file buffer to make error logging faster. Can be set only at startup and requires log-error +NUMERIC_MIN_VALUE 0 +NUMERIC_MAX_VALUE 18446744073709551615 +NUMERIC_BLOCK_SIZE 1 +ENUM_VALUE_LIST NULL +READ_ONLY YES +COMMAND_LINE_ARGUMENT REQUIRED +VARIABLE_NAME LOG_ERROR_FILE_ROTATE_SIZE +VARIABLE_SCOPE GLOBAL +VARIABLE_TYPE BIGINT UNSIGNED +VARIABLE_COMMENT Rotate the error log when it grows larger than that +NUMERIC_MIN_VALUE 1 +NUMERIC_MAX_VALUE 18446744073709551615 +NUMERIC_BLOCK_SIZE 1 +ENUM_VALUE_LIST NULL +READ_ONLY YES +COMMAND_LINE_ARGUMENT REQUIRED +VARIABLE_NAME LOG_ERROR_FILE_ROTATIONS +VARIABLE_SCOPE GLOBAL +VARIABLE_TYPE BIGINT UNSIGNED +VARIABLE_COMMENT Number of rotations before old error log is removed +NUMERIC_MIN_VALUE 0 +NUMERIC_MAX_VALUE 999 +NUMERIC_BLOCK_SIZE 1 +ENUM_VALUE_LIST NULL +READ_ONLY YES +COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME LOG_OUTPUT VARIABLE_SCOPE GLOBAL VARIABLE_TYPE SET diff --git a/mysql-test/suite/sys_vars/t/log_error_file_buffer_size_basic.test b/mysql-test/suite/sys_vars/t/log_error_file_buffer_size_basic.test new file mode 100644 index 00000000000..586f6f1237a --- /dev/null +++ b/mysql-test/suite/sys_vars/t/log_error_file_buffer_size_basic.test @@ -0,0 +1,20 @@ +--source include/not_embedded.inc + +# +# Read-only global variable, set at startup only +# +select @@global.log_error_file_buffer_size; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +select @@session.log_error_file_buffer_size; +show global variables like 'log_error_file_buffer_size'; +show session variables like 'log_error_file_buffer_size'; +select variable_name from information_schema.global_variables where variable_name='log_error_file_buffer_size'; +select variable_name from information_schema.session_variables where variable_name='log_error_file_buffer_size'; + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +set session log_error_file_buffer_size=1; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +set global log_error_file_buffer_size=1; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +set global log_error_file_buffer_size=default; +select @@global.log_error_file_buffer_size; diff --git a/mysql-test/suite/sys_vars/t/log_error_file_rotate_size_basic.test b/mysql-test/suite/sys_vars/t/log_error_file_rotate_size_basic.test new file mode 100644 index 00000000000..b16d2e097c6 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/log_error_file_rotate_size_basic.test @@ -0,0 +1,20 @@ +--source include/not_embedded.inc + +# +# Read-only global variable, set at startup only +# +select @@global.log_error_file_rotate_size; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +select @@session.log_error_file_rotate_size; +show global variables like 'log_error_file_rotate_size'; +show session variables like 'log_error_file_rotate_size'; +select variable_name from information_schema.global_variables where variable_name='log_error_file_rotate_size'; +select variable_name from information_schema.session_variables where variable_name='log_error_file_rotate_size'; + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +set session log_error_file_rotate_size=1; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +set global log_error_file_rotate_size=1; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +set global log_error_file_rotate_size=default; +select @@global.log_error_file_rotate_size; diff --git a/mysql-test/suite/sys_vars/t/log_error_file_rotations_basic.test b/mysql-test/suite/sys_vars/t/log_error_file_rotations_basic.test new file mode 100644 index 00000000000..81635f73033 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/log_error_file_rotations_basic.test @@ -0,0 +1,20 @@ +--source include/not_embedded.inc + +# +# Read-only global variable, set at startup only +# +select @@global.log_error_file_rotations; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +select @@session.log_error_file_rotations; +show global variables like 'log_error_file_rotations'; +show session variables like 'log_error_file_rotations'; +select variable_name from information_schema.global_variables where variable_name='log_error_file_rotations'; +select variable_name from information_schema.session_variables where variable_name='log_error_file_rotations'; + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +set session log_error_file_rotations=1; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +set global log_error_file_rotations=1; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +set global log_error_file_rotations=default; +select @@global.log_error_file_rotations; diff --git a/mysys/file_logger.c b/mysys/file_logger.c index 572bf7ff6c2..8dfaa31b70b 100644 --- a/mysys/file_logger.c +++ b/mysys/file_logger.c @@ -20,6 +20,7 @@ #include #include #include +#include #endif /*FLOGGER_SKIP_INCLUDES*/ #ifdef HAVE_PSI_INTERFACE @@ -106,6 +107,57 @@ LOGGER_HANDLE *logger_open(const char *path, return l_perm; } +LOGGER_HANDLE *logger_init(FILE *file, + const char *path, + unsigned long long size_limit, + unsigned int rotations, size_t buffer_size) +{ + LOGGER_HANDLE *l_perm= NULL; + size_t path_len= strlen(path); + int fd= fileno(file); + /* + I don't think we ever need more rotations, + but if it's so, the rotation procedure should be adapted to it. + */ + if (rotations > 999) + return 0; + + if (buffer_size > 0 && buffer_size < 1024) + buffer_size= 1024; + + if (rotations > 0 && size_limit < buffer_size) + buffer_size= size_limit; + + if (path_len+n_dig(rotations)+1 > FN_REFLEN) + { + errno= ENAMETOOLONG; + /* File path too long */ + return 0; + } + + if (!(l_perm= (LOGGER_HANDLE *) my_malloc(PSI_INSTRUMENT_ME, + sizeof(LOGGER_HANDLE), MYF(0)))) + return 0; /* End of memory */ + + l_perm->rotations= rotations; + l_perm->size_limit= size_limit; + strncpy(l_perm->path, path, path_len); + l_perm->path_len= path_len; + + mysql_mutex_init(key_LOCK_logger_service, &l_perm->lock, + MY_MUTEX_INIT_FAST); + + l_perm->buffer_size= buffer_size; + l_perm->filesize= my_seek(fd, 0L, MY_SEEK_END, MYF(0)); + l_perm->file= fd; + + if (l_perm->buffer_size) + init_io_cache(&l_perm->cache, fd, l_perm->buffer_size, + WRITE_CACHE, l_perm->filesize, FALSE, MYF(MY_WME | MY_NABP)); + + return l_perm; +} + int logger_close(LOGGER_HANDLE *log) { int result; diff --git a/sql/log.cc b/sql/log.cc index 387795e30fc..0a97e54997d 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -68,6 +68,7 @@ #ifdef WITH_WSREP #include "wsrep_trans_observer.h" #include "wsrep_status.h" +#include "wsrep_var.h" #endif /* WITH_WSREP */ #ifdef HAVE_REPLICATION @@ -77,7 +78,9 @@ #endif /* max size of the log message */ -#define MAX_LOG_BUFFER_SIZE 1024 +#define MAX_LOG_BUFFER_SIZE 4096 +/* Longest message written to the error log */ +#define MAX_LOG_MESSAGE_SIZE (1024*1024) #define MAX_TIME_SIZE 32 #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") @@ -420,11 +423,12 @@ Silence_log_table_errors::handle_condition(THD *, return TRUE; } -sql_print_message_func sql_print_message_handlers[3] = +sql_print_message_func sql_print_message_handlers[4] = { sql_print_information, sql_print_warning, - sql_print_error + sql_print_error, + sql_print_debug }; @@ -11909,6 +11913,23 @@ static void print_buffer_to_nt_eventlog(enum loglevel level, char *buff, } while (0) #endif +/* + Message buffer of print_buffer_to_file(). Protected by LOCK_error_log. + Allocated on first use with MAX_LOG_BUFFER_SIZE+1 bytes, grown by + MAX_LOG_BUFFER_SIZE when a message does not fit and freed at + shutdown by free_error_log_buffer(). +*/ +static char *error_log_buf= NULL; +static size_t error_log_buf_size= 0; + +/** Free the message buffer. Called at shutdown, when no thread logs. */ +void free_error_log_buffer() +{ + my_free(error_log_buf); + error_log_buf= NULL; + error_log_buf_size= 0; +} + static void print_buffer_to_file(enum loglevel level, const char *buffer, size_t length) { @@ -11918,6 +11939,7 @@ static void print_buffer_to_file(enum loglevel level, const char *buffer, THD *thd= 0; size_t tag_length= 0; char tag[NAME_LEN]; + DBUG_ENTER("print_buffer_to_file"); DBUG_PRINT("enter",("buffer: %s", buffer)); @@ -11942,20 +11964,85 @@ static void print_buffer_to_file(enum loglevel level, const char *buffer, localtime_r(&skr, &tm_tmp); start=&tm_tmp; - fprintf_stderr( "%d-%02d-%02d %2d:%02d:%02d %lu [%s] %.*s%.*s\n", - start->tm_year + 1900, - start->tm_mon+1, - start->tm_mday, - start->tm_hour, - start->tm_min, - start->tm_sec, - (unsigned long) (thd ? thd->thread_id : 0), - (level == ERROR_LEVEL ? "ERROR" : level == WARNING_LEVEL ? - "Warning" : "Note"), - (int) tag_length, tag, - (int) length, buffer); + assert(level <= DEBUG_LEVEL); + const char* level_msg[] = + { "ERROR", "Warning", "Note", "Debug" }; - fflush(stderr); + if (!error_log_buf) + { + if (!(error_log_buf= (char*) my_malloc(PSI_NOT_INSTRUMENTED, + MAX_LOG_BUFFER_SIZE + 1, MYF(0)))) + { + /* No memory for the buffer, write the bare message */ + fprintf(stderr, "%.*s\n", (int) length, buffer); + fflush(stderr); + mysql_mutex_unlock(&LOCK_error_log); + DBUG_VOID_RETURN; + } + error_log_buf_size= MAX_LOG_BUFFER_SIZE + 1; + } + + size_t len= 0; + for (int pass= 0; pass < 2; pass++) + { + int res= snprintf(error_log_buf, error_log_buf_size, + "%d-%02d-%02d %2d:%02d:%02d %lu [%s] %.*s%.*s\n", + start->tm_year + 1900, + start->tm_mon+1, + start->tm_mday, + start->tm_hour, + start->tm_min, + start->tm_sec, + (unsigned long) (thd ? thd->thread_id : 0), + level_msg[level], + (int) tag_length, tag, + (int) length, buffer); + if (res < 0) + { + mysql_mutex_unlock(&LOCK_error_log); + DBUG_VOID_RETURN; + } + len= (size_t) res; + if (len < error_log_buf_size) + break; + /* Message did not fit: grow once in MAX_LOG_BUFFER_SIZE steps */ + size_t new_size= error_log_buf_size; + while (new_size <= len) + new_size+= MAX_LOG_BUFFER_SIZE; + char *new_buf= pass ? NULL + : (char*) my_realloc(PSI_NOT_INSTRUMENTED, + error_log_buf, new_size, MYF(0)); + if (!new_buf) + { + /* Write the truncated message, keep the line ending */ + len= error_log_buf_size - 1; + error_log_buf[len - 1]= '\n'; + break; + } + error_log_buf= new_buf; + error_log_buf_size= new_size; + } + + // For wsrep write msg by default if level is not debug + // and debug messages only if wsrep_debug is configured. + // Non wsrep write msg + bool write_msg= IF_WSREP((level < DEBUG_LEVEL || + (level == DEBUG_LEVEL && wsrep_debug)), + 1); + + if (write_msg) + { + if (error_logger) + { + // Use buffered error log writing + logger_write(error_logger, error_log_buf, len); + } + else + { + fwrite(error_log_buf, 1, len, stderr); + fflush(stderr); + } + } #ifdef WITH_WSREP if (level <= WARNING_LEVEL) @@ -11989,21 +12076,60 @@ static void print_buffer_to_file(enum loglevel level, const char *buffer, */ int vprint_msg_to_log(enum loglevel level, const char *format, va_list args) { - char buff[1024]; + char stack_buff[1024]; + char *buff= stack_buff; + size_t buff_size= sizeof(stack_buff); size_t length; + va_list args_copy; DBUG_ENTER("vprint_msg_to_log"); - length= my_vsnprintf(buff, sizeof(buff), format, args); + va_copy(args_copy, args); + length= my_vsnprintf(buff, buff_size, format, args); + + /* + my_vsnprintf() truncates, so a result that fills the buffer may be cut. + Format again into a larger buffer, up to MAX_LOG_MESSAGE_SIZE. + */ + while (length >= buff_size - 1 && buff_size < MAX_LOG_MESSAGE_SIZE) + { + size_t new_size= MY_MIN(buff_size * 4, MAX_LOG_MESSAGE_SIZE); + char *new_buff= (char*) my_malloc(PSI_NOT_INSTRUMENTED, new_size, MYF(0)); + va_list retry_args; + if (!new_buff) + break; + if (buff != stack_buff) + my_free(buff); + buff= new_buff; + buff_size= new_size; + va_copy(retry_args, args_copy); + length= my_vsnprintf(buff, buff_size, format, retry_args); + va_end(retry_args); + } + va_end(args_copy); + print_buffer_to_file(level, buff, length); #ifdef _WIN32 - print_buffer_to_nt_eventlog(level, buff, length, sizeof(buff)); + print_buffer_to_nt_eventlog(level, buff, length, buff_size); #endif + if (buff != stack_buff) + my_free(buff); DBUG_RETURN(0); } #endif /* EMBEDDED_LIBRARY */ +void sql_print_debug(const char *format, ...) +{ + va_list args; + DBUG_ENTER("sql_print_debug"); + + va_start(args, format); + error_log_print(DEBUG_LEVEL, format, args); + va_end(args); + + DBUG_VOID_RETURN; +} void sql_print_error(const char *format, ...) { diff --git a/sql/log.h b/sql/log.h index e0d3d37c3bb..30c939d707c 100644 --- a/sql/log.h +++ b/sql/log.h @@ -1443,6 +1443,8 @@ void sql_print_error(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2); void sql_print_warning(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2); void sql_print_information(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2); +void sql_print_debug(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2); + void sql_print_information_v(const char *format, va_list ap) ATTRIBUTE_FORMAT(printf, 1, 0); typedef void (*sql_print_message_func)(const char *format, ...) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 07a597b3e11..671f91b94e4 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -402,6 +402,11 @@ ulong slow_start_timeout; static MEM_ROOT startup_root; MEM_ROOT read_only_root; +ulonglong log_error_file_buffer_size=0; +ulong log_error_file_rotations=0; +ulong log_error_file_rotate_size=0; +LOGGER_HANDLE *error_logger=nullptr; + /** @brief 'grant_option' is used to indicate if privileges needs to be checked, in which case the lock, LOCK_grant, is used @@ -1344,9 +1349,10 @@ void Buffered_log::print() case WARNING_LEVEL: sql_print_warning("Buffered warning: %s", m_message.c_ptr_safe()); break; + case DEBUG_LEVEL: case INFORMATION_LEVEL: /* - Messages printed as "information" still end up in the mysqld *error* log, + Messages printed as "information" or "debug" still end up in the mysqld *error* log, but with a [Note] tag instead of an [ERROR] tag. While this is probably fine for a human reading the log, it is upsetting existing automated scripts used to parse logs, @@ -2082,6 +2088,8 @@ static void clean_up(bool print_message, bool use_dummy_thd) free_error_messages(); /* Tell main we are ready */ logger.cleanup_end(); + if (error_logger) + logger_close(error_logger); sys_var_end(); free_charsets(); @@ -2194,6 +2202,7 @@ static void clean_up_mutexes() mysql_mutex_destroy(&LOCK_slave_deadlock_handler); mysql_cond_destroy(&COND_slave_deadlock_handler); #ifndef EMBEDDED_LIBRARY + free_error_log_buffer(); mysql_mutex_destroy(&LOCK_error_log); #endif DBUG_VOID_RETURN; @@ -5139,6 +5148,14 @@ static int init_server_components() error_handler_hook= my_message_sql; proc_info_hook= set_thd_stage_info; + if (opt_error_log && log_error_file_buffer_size) + { + error_logger= logger_init(stderr, log_error_file, + log_error_file_rotate_size, + log_error_file_rotations, + log_error_file_buffer_size); + } + /* Set up hook to handle disk full */ my_sleep_for_space= mariadb_sleep_for_space; diff --git a/sql/mysqld.h b/sql/mysqld.h index f04d2bacaa5..0c44ab12bd4 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -177,6 +177,12 @@ extern char *opt_logname, *opt_slow_logname, *opt_bin_logname, extern char *opt_binlog_index_name; extern my_bool opt_binlog_legacy_event_pos; +extern ulonglong log_error_file_buffer_size; +extern ulong log_error_file_rotations; +extern ulong log_error_file_rotate_size; +extern LOGGER_HANDLE *error_logger; +extern void free_error_log_buffer(); + /* System Versioning begin */ enum vers_system_time_t { diff --git a/sql/privilege.h b/sql/privilege.h index 9cf1450d99f..6cabbd4d5e0 100644 --- a/sql/privilege.h +++ b/sql/privilege.h @@ -669,6 +669,9 @@ constexpr privilege_t PRIV_STMT_SHOW_ENGINE_STATUS= PROCESS_ACL; constexpr privilege_t PRIV_STMT_SHOW_ENGINE_MUTEX= PROCESS_ACL; constexpr privilege_t PRIV_STMT_SHOW_PROCESSLIST= PROCESS_ACL; +/* Privileges related to error log */ +constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_LOG_ERROR_FILE_BUFFER_SIZE= + SUPER_ACL; /* access_t represents effective privileges at a given scope. diff --git a/sql/signal_handler.cc b/sql/signal_handler.cc index 8f03b7306c6..dbf0786d9e8 100644 --- a/sql/signal_handler.cc +++ b/sql/signal_handler.cc @@ -36,7 +36,7 @@ #else #define SIGNAL_FMT "signal %d" #endif - +#include "mysql/service_logger.h" #if defined(__APPLE__) || defined(__FreeBSD__) #include @@ -166,6 +166,11 @@ extern "C" sig_handler handle_fatal_signal(int sig) */ #endif +#ifdef WITH_WSREP + if (error_logger) + logger_close(error_logger); +#endif + if (segfaulted) { my_safe_printf_stderr("Fatal " SIGNAL_FMT " while backtracing\n", sig); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 6a1f53f7ba1..f608ac00677 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1677,7 +1677,8 @@ dispatch_command_return dispatch_command(enum enum_server_command command, if (WSREP(thd) && thd->wsrep_next_trx_id() == WSREP_UNDEFINED_TRX_ID) { thd->set_wsrep_next_trx_id(thd->query_id); - WSREP_DEBUG("assigned new next trx id: %" PRIu64, thd->wsrep_next_trx_id()); + WSREP_DEBUG("Thread %llu assigned new next trx id: %" PRIu64, + thd_get_thread_id(thd),thd->wsrep_next_trx_id()); } #endif /* WITH_WSREP */ diff --git a/sql/sql_plugin_services.inl b/sql/sql_plugin_services.inl index e88b834136f..634d9f4d74e 100644 --- a/sql/sql_plugin_services.inl +++ b/sql/sql_plugin_services.inl @@ -20,6 +20,7 @@ #include #include #include +#include struct st_service_ref { const char *name; @@ -112,6 +113,7 @@ static struct my_md5_service_st my_md5_handler = { static struct logger_service_st logger_service_handler= { logger_init_mutexes, logger_open, + logger_init, logger_close, logger_vprintf, logger_printf, diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 7e321359b1c..2fd8b6eb159 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -36,6 +36,7 @@ #include "sql_class.h" // set_var.h: THD #include "sys_vars.inl" #include "my_sys.h" +#include "mysqld.h" // log_error #include "events.h" #include "slave.h" @@ -70,7 +71,7 @@ #include "repl_failsafe.h" #ifdef WITH_WSREP #include "wsrep_mysqld.h" -#endif +#endif /* WITH_WSREP */ #define PCRE2_STATIC 1 /* Important on Windows */ #include "pcre2.h" /* pcre2 header file */ @@ -1657,6 +1658,28 @@ static Sys_var_charptr_fscs Sys_log_error( CMD_LINE(OPT_ARG, OPT_LOG_ERROR), DEFAULT(disabled_my_option)); +static Sys_var_on_access_global +Sys_log_error_file_buffer_size( + "log_error_file_buffer_size", + "Size of error log file buffer to make error logging faster. " + "Can be set only at startup and requires log-error", + READ_ONLY GLOBAL_VAR(log_error_file_buffer_size), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, SIZE_T_MAX), + DEFAULT(0), BLOCK_SIZE(1)); + +static Sys_var_ulong Sys_log_error_file_rotations( + "log_error_file_rotations", + "Number of rotations before old error log is removed", + READ_ONLY GLOBAL_VAR(log_error_file_rotations), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 999), DEFAULT(0), BLOCK_SIZE(1)); + +static Sys_var_ulong Sys_log_error_file_rotate_size( + "log_error_file_rotate_size", + "Rotate the error log when it grows larger than that", + READ_ONLY GLOBAL_VAR(log_error_file_rotate_size), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(1, SIZE_T_MAX), + DEFAULT(1024*1024*1024), BLOCK_SIZE(1)); + static Sys_var_bit Sys_log_queries_not_using_indexes( "log_queries_not_using_indexes", "Log queries that are executed without benefit of any index to the " @@ -5484,7 +5507,7 @@ Sys_proxy_protocol_networks( ON_CHECK(check_proxy_protocol_networks), ON_UPDATE(fix_proxy_protocol_networks)); -static bool check_log_path(sys_var *self, THD *thd, set_var *var) +bool check_log_path(sys_var *self, THD *thd, set_var *var) { if (!var->value) return false; // DEFAULT is ok @@ -6820,7 +6843,6 @@ static Sys_var_charptr_fscs Sys_wsrep_sst_tmp_dir( "wsrep_sst_tmp_dir", "Path to SST temp root directory", READ_ONLY GLOBAL_VAR(wsrep_sst_tmp_dir), CMD_LINE(REQUIRED_ARG), DEFAULT(0), NO_MUTEX_GUARD, NOT_IN_BINLOG); - #endif /* WITH_WSREP */ static bool fix_host_cache_size(sys_var *, THD *, enum_var_type)