Skip to content
This repository was archived by the owner on Dec 8, 2021. It is now read-only.

Commit bc0d111

Browse files
authored
feat: logging can be enabled via env var (#181)
Users can now enable logging to `std::clog` without any code changes or recompiling their code simply by setting the "GOOGLE_CLOUD_CPP_ENABLE_CLOG" environment variable before running their program. This env var is currently being inspected and set in some of our other code, such as https://github.com/googleapis/google-cloud-cpp-spanner/blob/20e2f9b011e3747fe5a8b8dc284245c11ff354b6/google/cloud/spanner/connection_options.cc#L68, and we should remove that after this change is merged.
1 parent c1a0fa6 commit bc0d111

File tree

6 files changed

+50
-34
lines changed

6 files changed

+50
-34
lines changed

google/cloud/connection_options.cc

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,6 @@ TracingOptions DefaultTracingOptions() {
4242
return TracingOptions{}.SetOptions(*tracing_options);
4343
}
4444

45-
void DefaultLogging() {
46-
if (google::cloud::internal::GetEnv("GOOGLE_CLOUD_CPP_ENABLE_CLOG")
47-
.has_value()) {
48-
google::cloud::LogSink::EnableStdClog();
49-
}
50-
}
51-
5245
std::unique_ptr<BackgroundThreads> DefaultBackgroundThreads() {
5346
return google::cloud::internal::make_unique<
5447
AutomaticallyCreatedBackgroundThreads>();

google/cloud/connection_options.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ inline namespace GOOGLE_CLOUD_CPP_NS {
3131
namespace internal {
3232
std::set<std::string> DefaultTracingComponents();
3333
TracingOptions DefaultTracingOptions();
34-
void DefaultLogging();
3534
std::unique_ptr<BackgroundThreads> DefaultBackgroundThreads();
3635
} // namespace internal
3736

@@ -53,9 +52,7 @@ class ConnectionOptions {
5352
tracing_components_(internal::DefaultTracingComponents()),
5453
tracing_options_(internal::DefaultTracingOptions()),
5554
user_agent_prefix_(ConnectionTraits::user_agent_prefix()),
56-
background_threads_factory_(internal::DefaultBackgroundThreads) {
57-
internal::DefaultLogging();
58-
}
55+
background_threads_factory_(internal::DefaultBackgroundThreads) {}
5956

6057
/// Change the gRPC credentials value.
6158
ConnectionOptions& set_credentials(

google/cloud/connection_options_test.cc

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -233,25 +233,6 @@ TEST(ConnectionOptionsTest, DefaultTracingOptionsWithValue) {
233233
EXPECT_EQ(42, actual.truncate_string_field_longer_than());
234234
}
235235

236-
TEST(ConnectionOptionsTest, DefaultLoggingNoEnvironment) {
237-
EnvironmentVariableRestore restore("GOOGLE_CLOUD_CPP_ENABLE_CLOG");
238-
LogSink::Instance().ClearBackends();
239-
internal::UnsetEnv("GOOGLE_CLOUD_CPP_ENABLE_CLOG");
240-
internal::DefaultLogging();
241-
EXPECT_EQ(0, LogSink::Instance().BackendCount());
242-
}
243-
244-
TEST(ConnectionOptionsTest, DefaultLoggingWithValue) {
245-
EnvironmentVariableRestore restore("GOOGLE_CLOUD_CPP_ENABLE_CLOG");
246-
LogSink::Instance().ClearBackends();
247-
EXPECT_EQ(0, LogSink::Instance().BackendCount());
248-
internal::SetEnv("GOOGLE_CLOUD_CPP_ENABLE_CLOG", "any-value");
249-
internal::DefaultLogging();
250-
EXPECT_EQ(1, LogSink::Instance().BackendCount());
251-
LogSink::DisableStdClog();
252-
EXPECT_EQ(0, LogSink::Instance().BackendCount());
253-
}
254-
255236
TEST(ConnectionOptionsTest, DefaultBackgroundThreads) {
256237
auto actual = internal::DefaultBackgroundThreads();
257238
EXPECT_TRUE(actual);

google/cloud/log.cc

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
// limitations under the License.
1414

1515
#include "google/cloud/log.h"
16+
#include "google/cloud/internal/getenv.h"
1617

1718
namespace google {
1819
namespace cloud {
@@ -45,8 +46,14 @@ LogSink::LogSink()
4546
clog_backend_id_(0) {}
4647

4748
LogSink& LogSink::Instance() {
48-
static LogSink instance;
49-
return instance;
49+
static auto* const kInstance = [] {
50+
auto* p = new LogSink;
51+
if (internal::GetEnv("GOOGLE_CLOUD_CPP_ENABLE_CLOG").has_value()) {
52+
p->EnableStdClogImpl();
53+
}
54+
return p;
55+
}();
56+
return *kInstance;
5057
}
5158

5259
long LogSink::AddBackend(std::shared_ptr<LogBackend> backend) {

google/cloud/log.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@
5757
* }
5858
* @endcode
5959
*
60+
* Alternatively, the application can enable logging to `std::clog` without any
61+
* code changes or recompiling by setting the "GOOGLE_CLOUD_CPP_ENABLE_CLOG"
62+
* environment variable before the program starts. The existence of this
63+
* variable is all that matters; the value is ignored.
64+
*
6065
* Note that while `std::clog` is buffered, the framework will flush any log
6166
* message at severity `WARNING` or higher.
6267
*
@@ -297,7 +302,12 @@ class LogSink {
297302

298303
void Log(LogRecord log_record);
299304

300-
/// Enable `std::clog` on `LogSink::Instance()`.
305+
/**
306+
* Enable `std::clog` on `LogSink::Instance()`.
307+
*
308+
* This is also enabled if the "GOOGLE_CLOUD_CPP_ENABLE_CLOG" environment
309+
* variable is set.
310+
*/
301311
static void EnableStdClog() { Instance().EnableStdClogImpl(); }
302312

303313
/// Disable `std::clog` on `LogSink::Instance()`.

google/cloud/log_test.cc

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,19 @@
1313
// limitations under the License.
1414

1515
#include "google/cloud/log.h"
16+
#include "google/cloud/internal/setenv.h"
17+
#include "google/cloud/testing_util/environment_variable_restore.h"
1618
#include <gmock/gmock.h>
1719

1820
namespace google {
1921
namespace cloud {
2022
inline namespace GOOGLE_CLOUD_CPP_NS {
2123
namespace {
2224

23-
using namespace ::testing;
25+
using ::testing::_;
26+
using ::testing::ExitedWithCode;
27+
using ::testing::HasSubstr;
28+
using ::testing::Invoke;
2429

2530
TEST(LogSeverityTest, Streaming) {
2631
std::ostringstream os;
@@ -140,6 +145,29 @@ TEST(LogSinkTest, ClogMultiple) {
140145
EXPECT_EQ(0, LogSink::Instance().BackendCount());
141146
}
142147

148+
TEST(LogSinkTest, ClogEnvironment) {
149+
// We set the death test style to "threadsafe", which causes the
150+
// ASSERT_EXIT() call to re-exec the test binary before executing the given
151+
// statement. This makes the death test thread-safe and it also ensures that
152+
// the LogSink singleton instance will be reconstructed in the child and will
153+
// see the environment variable. See also:
154+
// https://github.com/google/googletest/blob/master/googletest/docs/advanced.md#death-test-styles
155+
auto old_style = testing::FLAGS_gtest_death_test_style;
156+
testing::FLAGS_gtest_death_test_style = "threadsafe";
157+
158+
testing_util::EnvironmentVariableRestore restore(
159+
"GOOGLE_CLOUD_CPP_ENABLE_CLOG");
160+
internal::SetEnv("GOOGLE_CLOUD_CPP_ENABLE_CLOG", "anyvalue");
161+
162+
auto f = [] {
163+
GCP_LOG(INFO) << "testing clog";
164+
std::exit(42);
165+
};
166+
ASSERT_EXIT(f(), ExitedWithCode(42), HasSubstr("testing clog"));
167+
168+
testing::FLAGS_gtest_death_test_style = old_style;
169+
}
170+
143171
namespace {
144172
/// A class to count calls to IOStream operator.
145173
struct IOStreamCounter {

0 commit comments

Comments
 (0)