/* Copyright (c) 2020, 2024, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is designed to work with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have either included with the program or referenced in the documentation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /** @file sql/server_component/log_sink_perfschema.h This file contains a) The API for the reading of previously written error logs. (These functions will in turn use a parse-function defined in a log-sink. Whichever log-sink that has a parse-function is listed first in @@global.log_error_services will be used; that service will decide what log-file to read (i.e. its name) and how to parse it. We initially support the reading of JSON- formatted error log files and of the traditional MySQL error log files.) This lets us restore error log information from previous runs when the server starts. These functions are called from mysqld.cc at start-up. b) The log-sink that adds errors logged at run-time to the ring-buffer (to be called from @see log_line_submit() during normal operation, i.e. when loadable log-components are available, connections are accepted, and so on). */ #ifndef LOG_SINK_PERFSCHEMA_H #define LOG_SINK_PERFSCHEMA_H #include "log_builtins_internal.h" #include "my_thread_local.h" // my_thread_id /* "MY-123456" - 6 digits, "MY-", '\0' */ #define LOG_SINK_PFS_ERROR_CODE_LENGTH 10 /* Currently one of "Repl"/"InnoDB"/"Server" + '\0' */ #define LOG_SINK_PFS_SUBSYS_LENGTH 7 typedef struct _log_sink_pfs_event { /** Column ERROR_LOG_TIMESTAMP. Logger should forcibly make these unique. */ ulonglong m_timestamp; /** Column ERROR_LOG_THREAD. */ ulonglong m_thread_id; // PFS_key_thread_id uses ulonglong, not my_thread_id /** Column ERROR_LOG_PRIO. */ ulong m_prio; /** Column ERROR_LOG_ERROR_CODE. */ char m_error_code[LOG_SINK_PFS_ERROR_CODE_LENGTH]; uint m_error_code_length; /** Column ERROR_LOG_SUBSYS. */ char m_subsys[LOG_SINK_PFS_SUBSYS_LENGTH]; uint m_subsys_length; /** Column ERROR_LOG_MESSAGE. */ uint m_message_length; ///< actual length, not counting trailing '\0' } log_sink_pfs_event; /* We make these public for SHOW STATUS. Everybody else should use the getter functions. The timestamp is made available to allow for easy checks whether log entries were added since the interested part last polled. The timestamp is provided as a unique value with microsecond precision for that use; to view it in a more human-friendly format, use SELECT FROM_UNIXTIME(variable_value/1000000) FROM global_status WHERE variable_name="Error_log_latest_write"; Thus if you expect to check for new events with some regularity, you could start off with SELECT 0 INTO @error_log_last_poll; and then poll using something like SELECT logged,prio,error_code,subsystem,data FROM performance_schema.error_log WHERE logged>@error_log_last_poll; SELECT FROM_UNIXTIME(variable_value/1000000) FROM global_status WHERE variable_name="Error_log_latest_write" INTO @error_log_last_poll; (Ideally though you'd update @error_log_last_poll from the 'logged' field (that is, the timestamp) of the last new row you received.) */ extern ulong log_sink_pfs_buffered_bytes; ///< bytes in use (now) extern ulong log_sink_pfs_buffered_events; ///< events in buffer (now) extern ulong log_sink_pfs_expired_events; ///< number of expired entries (ever) extern ulong log_sink_pfs_longest_event; ///< longest event seen (ever) extern ulonglong log_sink_pfs_latest_timestamp; ///< timestamp of most recent write // The public interface to reading the error-log from the ring-buffer: /// Acquire a read-lock on the ring-buffer. void log_sink_pfs_read_start(); /// Release read-lock on ring-buffer. void log_sink_pfs_read_end(); /** Get number of events currently in ring-buffer. Caller should hold THR_LOCK_log_perschema when reading this. @returns number of events current in ring-buffer (0..) */ size_t log_sink_pfs_event_count(); /** Get oldest event still in ring-buffer. Caller should hold read-lock on THR_LOCK_log_perfschema when calling this. @returns nullptr No events in buffer @returns otherwise Address of oldest event in ring-buffer */ log_sink_pfs_event *log_sink_pfs_event_first(); log_sink_pfs_event *log_sink_pfs_event_next(log_sink_pfs_event *e); log_sink_pfs_event *log_sink_pfs_event_valid(log_sink_pfs_event *e, ulonglong logged); // The public interface to restoring the error-log to the ring-buffer: /** Set up ring-buffer for error-log. @returns 0 Success - buffer was allocated. @returns !=0 Failure - buffer was not allocated. */ int log_error_read_log_init(); /** Release error log ring-buffer. @returns 0 Success - buffer was released, or did not exist in the first place. */ int log_error_read_log_exit(); log_service_error log_error_read_log(const char *log_name); log_service_error log_sink_pfs_event_add(log_sink_pfs_event *e, const char *blob_src); int log_sink_perfschema(void *instance [[maybe_unused]], log_line *ll); #endif /* LOG_SINK_PERFSCHEMA_H */