userver: userver/logging/component.hpp Source File
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
component.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/logging/component.hpp
4/// @brief @copybrief components::Logging
5
6#include <string>
7#include <unordered_map>
8
9#include <userver/components/component_fwd.hpp>
10#include <userver/components/raw_component_base.hpp>
11#include <userver/concurrent/async_event_source.hpp>
12#include <userver/os_signals/component.hpp>
13
14#include <userver/rcu/rcu_map.hpp>
15#include <userver/utils/fast_pimpl.hpp>
16#include <userver/utils/periodic_task.hpp>
17#include <userver/utils/statistics/entry.hpp>
18#include <userver/utils/statistics/writer.hpp>
19
20#include "logger.hpp"
21
22USERVER_NAMESPACE_BEGIN
23
24namespace logging::impl {
25class TpLogger;
26class TcpSocketSink;
27} // namespace logging::impl
28
29namespace components {
30
31// clang-format off
32
33/// @ingroup userver_components
34///
35/// @brief %Logging component
36///
37/// Allows to configure the default logger and/or additional loggers for your
38/// needs.
39///
40/// ## Static options:
41/// Name | Description | Default value
42/// ---- | ----------- | -------------
43/// `fs-task-processor` | task processor for disk I/O operations | engine::current_task::GetBlockingTaskProcessor()
44/// `loggers.<logger-name>.file_path` | path to the log file | -
45/// `loggers.<logger-name>.level` | log verbosity | `info`
46/// `loggers.<logger-name>.format` | log output format, one of `tskv`, `ltsv`, `json`, `json_yadeploy` | `tskv`
47/// `loggers.<logger-name>.flush_level` | messages of this and higher levels get flushed to the file immediately | `warning`
48/// `loggers.<logger-name>.message_queue_size` | the size of internal message queue, must be a power of 2 | 65536
49/// `loggers.<logger-name>.overflow_behavior` | message handling policy while the queue is full: `discard` drops messages, `block` waits until message gets into the queue | `discard`
50/// `loggers.<logger-name>.testsuite-capture` | if exists, setups additional TCP log sink for testing purposes | {}
51/// `loggers.<logger-name>.fs-task-processor` | task processor for disk I/O operations for this logger | top-level `fs-task-processor` option
52///
53/// `default` logger is the one used for `LOG_*`.
54///
55/// ### Logs output
56/// You can specify where logs are written in the `file_path` option:
57/// - Use <tt>file_path: '@stdout'</tt> to write your logs to standard output stream;
58/// - Use <tt>file_path: '@stderr'</tt> to write your logs to standard error stream;
59/// - Use <tt>file_path: '@null'</tt> to suppress sending of logs;
60/// - Use <tt>file_path: /absolute/path/to/log/file.log</tt> to write your logs to file. Use USR1 signal or @ref server::handlers::OnLogRotate to reopen files after log rotation;
61/// - Use <tt>file_path: 'unix:/absolute/path/to/logs.sock'</tt> to write your logs to unix socket. Socket must be created before the service starts and closed by listener after service is shut down.
62///
63/// For sending logs directly to an otlp (opentelemetry) sink, see @ref opentelemetry.
64///
65/// Customization of log sinks beyond the ones listed above is not supported at the moment.
66///
67/// ### Logs format
68/// You can specify in what format logs are written in the `format` option:
69/// - Use `format: tskv` for traditional optimized userver-flavoured TSKV representation. See @ref utils::encoding::TskvParser for the exact format specification;
70/// - Use `format: ltsv` for the same format, with `:` instead of `=` for key-value separator;
71/// - Use `format: raw` for TSKV logs with timestamp and other default tags stripped, useful for @ref custom_loggers "custom loggers";
72/// - Use `format: json` for JSON logs. @ref logging::JsonString can be used with this format for rich hierarchical log tags;
73/// - Use `format: json_yadeploy` for JSON logs with a slightly different structure.
74///
75/// When sending logs using @ref opentelemetry, logs are written to otlp protobuf messages.
76///
77/// Customization of log formats beyond the ones listed above is not supported at the moment.
78///
79/// ### testsuite-capture options:
80/// Name | Description | Default value
81/// ---- | ----------- | -------------
82/// `loggers.<logger-name>.testsuite-capture.host` | testsuite hostname, e.g. `localhost` | -
83/// `loggers.<logger-name>.testsuite-capture.host` | testsuite port | -
84///
85/// ## Static configuration examples:
86///
87/// Writing logs to stderr:
88///
89/// @snippet core/functional_tests/basic_chaos/static_config.yaml logging
90///
91/// Advanced configuration showing options for access logs and a custom opentracing logger:
92///
93/// @snippet components/common_component_list_test.cpp Sample logging component config
94
95// clang-format on
96
97class Logging final : public RawComponentBase {
98public:
99 /// @ingroup userver_component_names
100 /// @brief The default name of components::Logging component
101 static constexpr std::string_view kName = "logging";
102
103 /// The component constructor
104 Logging(const ComponentConfig&, const ComponentContext&);
105 ~Logging() override;
106
107 /// @brief Returns a logger by its name
108 /// @param name Name of the logger
109 /// @returns Pointer to the Logger instance
110 /// @throws std::runtime_error if logger with this name is not registered
111 logging::LoggerPtr GetLogger(const std::string& name);
112
113 /// @brief Returns a text logger by its name
114 /// @param name Name of the logger
115 /// @returns Pointer to the Logger instance
116 /// @throws std::runtime_error if logger with this name is not registered
117 /// @throws std::runtime_error if logger is not a text logger
118 logging::TextLoggerPtr GetTextLogger(const std::string& name);
119
120 /// @brief Sets a logger
121 /// @param name Name of the logger
122 /// @param logger Logger to set
123 void SetLogger(const std::string& name, logging::LoggerPtr logger);
124
125 /// @brief Returns a logger by its name
126 /// @param name Name of the logger
127 /// @returns Pointer to the Logger instance, or `nullptr` if not registered
128 logging::LoggerPtr GetLoggerOptional(const std::string& name);
129
130 void StartSocketLoggingDebug(const std::optional<logging::Level>& log_level);
131 void StopSocketLoggingDebug(const std::optional<logging::Level>& log_level);
132
133 /// Reopens log files after rotation
135 void TryReopenFiles();
136
137 void WriteStatistics(utils::statistics::Writer& writer) const;
138
139 static yaml_config::Schema GetStaticConfigSchema();
140
141private:
142 void Init(const ComponentConfig&, const ComponentContext&);
143 void Stop() noexcept;
144
145 void FlushLogs();
146
147 engine::TaskProcessor& fs_task_processor_;
148 std::unordered_map<std::string, std::shared_ptr<logging::impl::TpLogger>> loggers_;
149 rcu::RcuMap<std::string, logging::LoggerPtr> extra_loggers_;
150 utils::PeriodicTask flush_task_;
151 logging::impl::TcpSocketSink* socket_sink_{nullptr};
152 utils::statistics::MetricsStoragePtr metrics_storage_;
153
154 // Subscriptions must be the last fields.
155 os_signals::Subscriber signal_subscriber_;
156 utils::statistics::Entry statistics_holder_;
157};
158
159template <>
160inline constexpr bool kHasValidate<Logging> = true;
161
162} // namespace components
163
164USERVER_NAMESPACE_END