10
10
#include < binlog/EventFilter.hpp>
11
11
12
12
// Logging macros. These will call `logger()` to get a Logger instance, picking up any `logger`
13
- // defined in the current scope. A default `codeql::logger()` is provided, otherwise domain-specific
14
- // loggers can be added as class fields called `logger` (as `Logger::operator()()` returns itself).
15
- // Domain specific loggers are set up with a name that appears in the log and can be used to filter
16
- // debug levels (see `Logger`). If working in the global namespace, the default logger can be used
17
- // by defining `auto& logger = codeql::logger();`
13
+ // defined in the current scope. Domain-specific loggers can be added or used by either:
14
+ // * providing a class field called `logger` (as `Logger::operator()()` returns itself)
15
+ // * declaring a local `logger` variable (to be used for one-time execution like code in `main`)
16
+ // * declaring a `Logger& logger()` function returning a reference to a static local variable
17
+ // * passing a logger around using a `Logger& logger` function parameter
18
+ // They are created with a name that appears in the logs and can be used to filter debug levels (see
19
+ // `Logger`).
18
20
#define LOG_CRITICAL (...) LOG_IMPL(codeql::Log::Level::critical, __VA_ARGS__)
19
21
#define LOG_ERROR (...) LOG_IMPL(codeql::Log::Level::error, __VA_ARGS__)
20
22
#define LOG_WARNING (...) LOG_IMPL(codeql::Log::Level::warning, __VA_ARGS__)
@@ -68,7 +70,52 @@ class Log {
68
70
public:
69
71
using Level = binlog::Severity;
70
72
73
+ // Internal data required to build `Logger` instances
74
+ struct LoggerConfiguration {
75
+ binlog::Session& session;
76
+ std::string fullyQualifiedName;
77
+ Level level;
78
+ };
79
+
80
+ // Configure logging. This consists in
81
+ // * using environment variable `CODEQL_EXTRACTOR_SWIFT_LOG_DIR` to choose where to dump the log
82
+ // file(s). Log files will go to a subdirectory thereof named after `root`
83
+ // * using environment variable `CODEQL_EXTRACTOR_SWIFT_LOG_LEVELS` to configure levels for
84
+ // loggers and outputs. This must have the form of a comma separated `spec:level` list, where
85
+ // `spec` is either a glob pattern (made up of alphanumeric, `/`, `*` and `.` characters) for
86
+ // matching logger names or one of `out:bin`, `out:text` or `out:console`.
87
+ // Output default levels can be seen in the corresponding initializers below. By default, all
88
+ // loggers are configured with the lowest output level
89
+ static void configure (std::string_view root) { instance ().configureImpl (root); }
90
+
91
+ // Flush logs to the designated outputs
92
+ static void flush () { instance ().flushImpl (); }
93
+
94
+ // create `Logger` configuration, used internally by `Logger`'s constructor
95
+ static LoggerConfiguration getLoggerConfiguration (std::string_view name) {
96
+ return instance ().getLoggerConfigurationImpl (name);
97
+ }
98
+
71
99
private:
100
+ static constexpr const char * format = " %u %S [%n] %m (%G:%L)\n " ;
101
+
102
+ Log () = default ;
103
+
104
+ static Log& instance () {
105
+ static Log ret;
106
+ return ret;
107
+ }
108
+
109
+ static class Logger & logger ();
110
+
111
+ void configureImpl (std::string_view root);
112
+ void flushImpl ();
113
+ LoggerConfiguration getLoggerConfigurationImpl (std::string_view name);
114
+
115
+ // make `session.consume(*this)` work, which requires access to `write`
116
+ friend binlog::Session;
117
+ Log& write (const char * buffer, std::streamsize size);
118
+
72
119
// Output filtered according to a configured log level
73
120
template <typename Output>
74
121
struct FilteredOutput {
@@ -93,72 +140,39 @@ class Log {
93
140
using LevelRule = std::pair<std::regex, Level>;
94
141
using LevelRules = std::vector<LevelRule>;
95
142
96
- static constexpr const char * format = " %u %S [%n] %m (%G:%L)\n " ;
97
-
98
143
binlog::Session session;
99
144
std::ofstream textFile;
100
145
FilteredOutput<std::ofstream> binary{Level::no_logs};
101
146
FilteredOutput<binlog::TextOutputStream> text{Level::info, textFile, format};
102
147
FilteredOutput<binlog::TextOutputStream> console{Level::warning, std::cerr, format};
103
148
LevelRules sourceRules;
104
149
std::string rootName;
105
-
106
- Log () = default ;
107
-
108
- static Log& instance () {
109
- static Log ret;
110
- return ret;
111
- }
112
-
113
- friend class Logger ;
114
- friend binlog::Session;
115
-
116
- Level getLevelForSource (std::string_view name) const ;
117
- Log& write (const char * buffer, std::streamsize size);
118
- static class Logger & logger ();
119
-
120
- public:
121
- // Configure logging. This consists in
122
- // * setting up a default logger with `root` as name
123
- // * using environment variable `CODEQL_EXTRACTOR_SWIFT_LOG_DIR` to choose where to dump the log
124
- // file(s). Log files will go to a subdirectory thereof named after `root`
125
- // * using environment variable `CODEQL_EXTRACTOR_SWIFT_LOG_LEVELS` to configure levels for
126
- // loggers and outputs. This must have the form of a comma separated `spec:level` list, where
127
- // `spec` is either a glob pattern (made up of alphanumeric, `/`, `*` and `.` characters) for
128
- // matching logger names or one of `out:bin`, `out:text` or `out:console`.
129
- // Output default levels can be seen in the corresponding initializers above. By default, all
130
- // loggers are configured with the lowest output level
131
- static void configure (std::string_view root);
132
-
133
- // Flush logs to the designated outputs
134
- static void flush ();
135
150
};
136
151
137
152
// This class represent a named domain-specific logger, responsible for pushing logs using the
138
153
// underlying `binlog::SessionWriter` class. This has a configured log level, so that logs on this
139
154
// `Logger` with a level lower than the configured one are no-ops.
140
155
class Logger {
141
- binlog::SessionWriter w{Log::instance ().session };
142
- Log::Level level_{Log::Level::no_logs};
143
-
144
- void setName (std::string name);
145
-
146
- friend Logger& logger ();
147
- // constructor for the default `Logger`
148
- explicit Logger () { setName (Log::instance ().rootName ); }
149
-
150
156
public:
151
- explicit Logger (const std::string& name) { setName (Log::instance (). rootName + ' / ' + name); }
157
+ explicit Logger (const std::string& name) : Logger (Log::getLoggerConfiguration( name)) { }
152
158
153
159
binlog::SessionWriter& writer () { return w; }
154
160
Log::Level level () const { return level_; }
155
161
156
162
// make defining a `Logger logger` field be equivalent to providing a `Logger& logger()` function
157
163
// in order to be picked up by logging macros
158
164
Logger& operator ()() { return *this ; }
159
- };
160
165
161
- // default logger
162
- Logger& logger ();
166
+ private:
167
+ static constexpr size_t queueSize = 1 << 20 ; // default taken from binlog
168
+
169
+ explicit Logger (Log::LoggerConfiguration&& configuration)
170
+ : w{configuration.session , queueSize, /* id */ 0 ,
171
+ std::move (configuration.fullyQualifiedName )},
172
+ level_{configuration.level } {}
173
+
174
+ binlog::SessionWriter w;
175
+ Log::Level level_;
176
+ };
163
177
164
178
} // namespace codeql
0 commit comments