Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ go_plugin::log::InstallAbslBridge(); // LOG(WARNING) now reaches the host as a
Abseil has no debug or trace severity of its own — they exist only as `VLOG` verbosities — so the bridge maps `VLOG(1)`
to debug and `VLOG(2)` and above to trace, and it stops Abseil writing its own copy of each line to standard error.

`go_plugin::log::SetAbslLevel(level)` sets the least severe level a plugin logs at, through Abseil as much as through
`Write`: Abseil's minimum severity, and the `VLOG` verbosity that the same mapping gives debug and trace. It is for a
plugin whose host moves its level while it runs.

To add another backend, translate its records into `go_plugin::log::Submit` and add a target beside the Abseil one;
nothing in the core changes.

Expand Down
10 changes: 10 additions & 0 deletions include/go_plugin/log_absl.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include "go_plugin/log.hpp"

namespace go_plugin::log {

struct AbslBridgeOptions {
Expand Down Expand Up @@ -29,4 +31,12 @@ struct AbslBridgeOptions {
*/
void InstallAbslBridge(const AbslBridgeOptions& options = {});

/**
* Sets the least severe level a plugin logs at, through Abseil as much as
* through Write: Abseil's minimum severity, and the VLOG verbosity that debug
* and trace map to under InstallAbslBridge's options. For a plugin whose host
* moves its level while it runs.
*/
void SetAbslLevel(Level min);

} // namespace go_plugin::log
21 changes: 21 additions & 0 deletions src/log_absl.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "go_plugin/log_absl.hpp"

#include <atomic>
#include <mutex>
#include <string>

Expand All @@ -15,6 +16,8 @@
namespace go_plugin::log {
namespace {

std::atomic<int> g_trace_from_verbosity{AbslBridgeOptions{}.trace_from_verbosity};

Level LevelFor(const absl::LogEntry& entry, const AbslBridgeOptions& options) {
// A VLOG is filed at info severity; its verbosity is the only thing that
// separates it from an ordinary info line.
Expand Down Expand Up @@ -64,6 +67,7 @@ class Bridge final : public absl::LogSink {
void InstallAbslBridge(const AbslBridgeOptions& options) {
static std::once_flag once;
std::call_once(once, [&options] {
g_trace_from_verbosity.store(options.trace_from_verbosity, std::memory_order_relaxed);
// Never destroyed: Abseil holds the pointer for the life of the process
// and a LOG(FATAL) unwinds nothing.
static Bridge bridge(options);
Expand All @@ -75,4 +79,21 @@ void InstallAbslBridge(const AbslBridgeOptions& options) {
});
}

void SetAbslLevel(Level min) {
SetLevel(min);

const int trace_from = g_trace_from_verbosity.load(std::memory_order_relaxed);
int verbosity = 0;
absl::LogSeverityAtLeast severity = absl::LogSeverityAtLeast::kInfo;
switch (min) {
case Level::Trace: verbosity = trace_from; break;
case Level::Debug: verbosity = trace_from - 1; break;
case Level::Info: break;
case Level::Warn: severity = absl::LogSeverityAtLeast::kWarning; break;
case Level::Error: severity = absl::LogSeverityAtLeast::kError; break;
}
absl::SetGlobalVLogLevel(verbosity);
absl::SetMinLogLevel(severity);
}

} // namespace go_plugin::log
24 changes: 24 additions & 0 deletions tests/test_log_absl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,27 @@ TEST_F(AbslBridge, CarriesTheCaller) {
ASSERT_EQ(Lines().size(), 1u);
EXPECT_NE(Lines()[0].find(R"("caller":"test_log_absl.cpp:)"), std::string::npos) << Lines()[0];
}

// One level moves Abseil as a whole: its VLOG verbosities by the bridge's own
// mapping of debug and trace, and its severities.
TEST_F(AbslBridge, SetAbslLevelDecidesWhatAbseilLogs) {
go_plugin::log::SetAbslLevel(go_plugin::log::Level::Debug);
VLOG(1) << "debug line";
VLOG(2) << "trace line";
ASSERT_EQ(Lines().size(), 1u);
EXPECT_NE(Lines()[0].find("debug line"), std::string::npos);

Lines().clear();
go_plugin::log::SetAbslLevel(go_plugin::log::Level::Trace);
VLOG(2) << "trace line";
EXPECT_EQ(Lines().size(), 1u);

Lines().clear();
go_plugin::log::SetAbslLevel(go_plugin::log::Level::Warn);
VLOG(1) << "debug line";
LOG(INFO) << "info line";
LOG(WARNING) << "warning line";
ASSERT_EQ(Lines().size(), 1u);
EXPECT_NE(Lines()[0].find("warning line"), std::string::npos);
EXPECT_EQ(go_plugin::log::GetLevel(), go_plugin::log::Level::Warn);
}
Loading