Skip to content

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

custom_sink.cc
#include <glog/logging.h>

#include <algorithm>
#include <cstddef>
#include <iostream>
#include <iterator>

namespace {

struct MyLogSink : google::LogSink {  
  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);  

  LOG(INFO) << "logging to MySink";

  google::RemoveLogSink(&sink);  

  // We can directly log to a sink without registering it
  LOG_TO_SINK(&sink, INFO) << "direct logging";  
  LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, INFO)
      << "direct logging but not to file";
}

Running the above example as GLOG_log_dir=. ./custom_sink_example will produce

Custom sink output
INFO custom_sink.cc:63 logging to MySink
INFO custom_sink.cc:68 direct logging
INFO custom_sink.cc:69 direct logging but not to file 

and the corresponding log file will contain

Log file generated with the custom sink
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