1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00

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/
This commit is contained in:
Jan Lindström
2024-12-02 09:07:05 +02:00
committed by Jan Lindström
parent 934108aab5
commit df2582990d
35 changed files with 630 additions and 32 deletions

View File

@@ -29,7 +29,8 @@
enum loglevel {
ERROR_LEVEL= 0,
WARNING_LEVEL= 1,
INFORMATION_LEVEL= 2
INFORMATION_LEVEL= 2,
DEBUG_LEVEL= 3
};
#ifdef __cplusplus

View File

@@ -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)));

View File

@@ -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)));

View File

@@ -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)));

View File

@@ -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)));

View File

@@ -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)));

View File

@@ -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)));

View File

@@ -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)));

View File

@@ -18,6 +18,7 @@
#ifndef MYSQL_ABI_CHECK
#include <stdarg.h>
#include <stdio.h>
#endif
#include <my_attribute.h>
@@ -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);

View File

@@ -0,0 +1 @@
--log-error-file-buffer-size=1024

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,3 @@
--log-error-file-buffer-size=1024
--log-error-file-rotate-size=4096
--log-error-file-rotations=2

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -20,6 +20,7 @@
#include <m_string.h>
#include <mysql/service_logger.h>
#include <my_pthread.h>
#include <stdio.h>
#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;

View File

@@ -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, ...)
{

View File

@@ -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, ...)

View File

@@ -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;

View File

@@ -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
{

View File

@@ -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.

View File

@@ -36,7 +36,7 @@
#else
#define SIGNAL_FMT "signal %d"
#endif
#include "mysql/service_logger.h"
#if defined(__APPLE__) || defined(__FreeBSD__)
#include <sys/sysctl.h>
@@ -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);

View File

@@ -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 */

View File

@@ -20,6 +20,7 @@
#include <mysql/service_thd_mdl.h>
#include <mysql/service_print_check_msg.h>
#include <mysql/service_thd.h>
#include <mysql/service_logger.h>
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,

View File

@@ -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_var_ulonglong, PRIV_SET_SYSTEM_GLOBAL_VAR_LOG_ERROR_FILE_BUFFER_SIZE>
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)