#pragma once #include #include namespace DB { /** Allow to store structured log in system table. * * Logging is asynchronous. Data is put into queue from where it will be read by separate thread. * That thread inserts log into a table with no more than specified periodicity. */ /** Structure of log, template parameter. * Structure could change on server version update. * If on first write, existing table has different structure, * then it get renamed (put aside) and new table is created. */ /* Example: struct LogElement { /// default constructor must be available /// fields static std::string name(); static NamesAndTypesList getNamesAndTypes(); static NamesAndAliases getNamesAndAliases(); static const char * getCustomColumnList(); void appendToBlock(MutableColumns & columns) const; }; */ class QueryLog; class QueryThreadLog; class PartLog; class TextLog; class TraceLog; class CrashLog; class MetricLog; class AsynchronousMetricLog; class OpenTelemetrySpanLog; class QueryViewsLog; class ZooKeeperLog; class SessionLog; class TransactionsInfoLog; class ProcessorsProfileLog; class FilesystemCacheLog; class FilesystemReadPrefetchesLog; class AsynchronousInsertLog; /// System logs should be destroyed in destructor of the last Context and before tables, /// because SystemLog destruction makes insert query while flushing data into underlying tables struct SystemLogs { SystemLogs(ContextPtr global_context, const Poco::Util::AbstractConfiguration & config); ~SystemLogs(); void shutdown(); std::shared_ptr query_log; /// Used to log queries. std::shared_ptr query_thread_log; /// Used to log query threads. std::shared_ptr part_log; /// Used to log operations with parts std::shared_ptr trace_log; /// Used to log traces from query profiler std::shared_ptr crash_log; /// Used to log server crashes. std::shared_ptr text_log; /// Used to log all text messages. std::shared_ptr metric_log; /// Used to log all metrics. std::shared_ptr filesystem_cache_log; std::shared_ptr filesystem_read_prefetches_log; /// Metrics from system.asynchronous_metrics. std::shared_ptr asynchronous_metric_log; /// OpenTelemetry trace spans. std::shared_ptr opentelemetry_span_log; /// Used to log queries of materialized and live views std::shared_ptr query_views_log; /// Used to log all actions of ZooKeeper client std::shared_ptr zookeeper_log; /// Login, LogOut and Login failure events std::shared_ptr session_log; /// Events related to transactions std::shared_ptr transactions_info_log; /// Used to log processors profiling std::shared_ptr processors_profile_log; std::shared_ptr asynchronous_insert_log; std::vector logs; }; template class SystemLog : public ISystemLog, private boost::noncopyable, WithContext { public: using Self = SystemLog; /** Parameter: table name where to write log. * If table is not exists, then it get created with specified engine. * If it already exists, then its structure is checked to be compatible with structure of log record. * If it is compatible, then existing table will be used. * If not - then existing table will be renamed to same name but with suffix '_N' at end, * where N - is a minimal number from 1, for that table with corresponding name doesn't exist yet; * and new table get created - as if previous table was not exist. */ SystemLog( ContextPtr context_, const String & database_name_, const String & table_name_, const String & storage_def_, size_t flush_interval_milliseconds_, std::shared_ptr> queue_ = nullptr); void startup() override; /** Append a record into log. * Writing to table will be done asynchronously and in case of failure, record could be lost. */ void add(const LogElement & element); void shutdown() override; String getName() const override { return LogElement::name(); } static const char * getDefaultOrderBy() { return "event_date, event_time"; } /// Flush data in the buffer to disk. Block the thread until the data is stored on disk. void flush(bool force) override; /// Non-blocking flush data in the buffer to disk. void notifyFlush(bool force); void stopFlushThread() override; protected: Poco::Logger * log; using ISystemLog::is_shutdown; using ISystemLog::saving_thread; private: /* Saving thread data */ const StorageID table_id; const String storage_def; String create_query; String old_create_query; bool is_prepared = false; std::shared_ptr> queue; /** Creates new table if it does not exist. * Renames old table if its structure is not suitable. * This cannot be done in constructor to avoid deadlock while renaming a table under locked Context when SystemLog object is created. */ void prepareTable() override; void savingThreadFunction() override; /// flushImpl can be executed only in saving_thread. void flushImpl(const std::vector & to_flush, uint64_t to_flush_end); ASTPtr getCreateTableQuery(); }; }