Custom Sinks¶
Under certain circumstances, it is useful to send the log output to a
destination other than a file, stderr
and/or stdout
. In case, the library
provides the google::LogSink
interface whose implementations can be used
to write the log output to arbitrary locations.
Basic Interface¶
The sink interface is defined as follows:
class LogSink {
public:
virtual void send(LogSeverity severity, const char* full_filename,
const char* base_filename, int line,
const LogMessageTime& time, const char* message,
size_t message_len);
};
The user must implement google::LogSink::send
, which is called by the
library every time a message is logged.
Possible deadlock due to nested logging
This method can't use LOG()
or CHECK()
as logging system mutex(s) are
held during this call.
Registering Log Sinks¶
To use the custom sink and instance of the above interface implementation must
be registered using google::AddLogSink
which expects a pointer to the
google::LogSink
instance. To unregister use google::RemoveLogSink
. Both
functions are thread-safe.
LogSink
ownership
The google::LogSink
instance must not be destroyed until the referencing
pointer is unregistered.
Direct Logging¶
Instead of registering the sink, we can directly use to log messages. While LOG_TO_SINK(sink, severity)
allows to log both to the sink and to a global log
registry, e.g., a file, LOG_TO_SINK_BUT_NOT_TO_LOGFILE(sink, severity)
will avoid the latter.
Using a custom sink
#include <glog/logging.h>
#include <algorithm>
#include <cstddef>
#include <iostream>
#include <iterator>
namespace {
struct MyLogSink : google::LogSink { // (1)!
void send(google::LogSeverity severity, const char* /*full_filename*/,
const char* base_filename, int line,
const google::LogMessageTime& /*time*/, const char* message,
std::size_t message_len) override {
std::cout << google::GetLogSeverityName(severity) << ' ' << base_filename
<< ':' << line << ' ';
std::copy_n(message, message_len,
std::ostreambuf_iterator<char>{std::cout});
std::cout << '\n';
}
};
} // namespace
int main(int /*argc*/, char** argv) {
google::InitGoogleLogging(argv[0]);
MyLogSink sink;
google::AddLogSink(&sink); // (2)!
LOG(INFO) << "logging to MySink";
google::RemoveLogSink(&sink); // (3)!
// We can directly log to a sink without registering it
LOG_TO_SINK(&sink, INFO) << "direct logging"; // (4)!
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, INFO)
<< "direct logging but not to file";
}
MySink
implements a custom sink that sends log messages tostd::cout
.- The custom sink must be registered to for use with existing logging macros.
- Once the custom sink is no longer needed we remove it from the registry.
- A sink does not need to be registered globally. However, then, messages must be logged using dedicated macros.
Running the above example as GLOG_log_dir=. ./custom_sink_example
will produce
- This line is not present in the log file because we used
LOG_TO_SINK_BUT_NOT_TO_LOGFILE
to log the message.
and the corresponding log file will contain
Log file created at: 2024/06/11 13:24:27
Running on machine: pc
Running duration (h:mm:ss): 0:00:00
Log line format: [IWEF]yyyymmdd hh:mm:ss.uuuuuu threadid file:line] msg
I20240611 13:24:27.476620 126237946035776 custom_sink.cc:63] logging to MySink
I20240611 13:24:27.476796 126237946035776 custom_sink.cc:68] direct logging