aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Chloe Calvarin <ccalvarin@google.com>2016-11-22 21:58:50 +0000
committerGravatar Dmitry Lomov <dslomov@google.com>2016-11-23 08:51:00 +0000
commit78f1c853e17909b001ac5d61469fd436d50fab34 (patch)
treee3c3f1595aad1c2014066ae05673237f548f0b4f
parentc944c4d9fc5cbad830b69383a76ffff463088c7e (diff)
Adds logging functionality to the bazel client, which will be activated in a later change.
-- MOS_MIGRATED_REVID=139951184
-rw-r--r--src/main/cpp/BUILD1
-rw-r--r--src/main/cpp/blaze.cc7
-rw-r--r--src/main/cpp/blaze.h4
-rw-r--r--src/main/cpp/main.cc3
-rw-r--r--src/main/cpp/option_processor.cc2
-rw-r--r--src/main/cpp/util/BUILD18
-rw-r--r--src/main/cpp/util/bazel_log_handler.cc95
-rw-r--r--src/main/cpp/util/bazel_log_handler.h51
-rw-r--r--src/main/cpp/util/errors.h2
-rw-r--r--src/main/cpp/util/logging.cc91
-rw-r--r--src/main/cpp/util/logging.h158
-rw-r--r--src/test/cpp/util/BUILD10
-rw-r--r--src/test/cpp/util/logging_test.cc70
13 files changed, 509 insertions, 3 deletions
diff --git a/src/main/cpp/BUILD b/src/main/cpp/BUILD
index e88611b87a..9a6df3643e 100644
--- a/src/main/cpp/BUILD
+++ b/src/main/cpp/BUILD
@@ -105,6 +105,7 @@ cc_binary(
":blaze_abrupt_exit",
":blaze_util",
"//src/main/cpp/util",
+ "//src/main/cpp/util:logging",
"//src/main/cpp/util:strings",
"//src/main/protobuf:command_server_cc_proto",
"//third_party/ijar:zip",
diff --git a/src/main/cpp/blaze.cc b/src/main/cpp/blaze.cc
index abb16ecd64..819d3e0ca5 100644
--- a/src/main/cpp/blaze.cc
+++ b/src/main/cpp/blaze.cc
@@ -65,6 +65,7 @@
#include "src/main/cpp/util/exit_code.h"
#include "src/main/cpp/util/file.h"
#include "src/main/cpp/util/file_platform.h"
+#include "src/main/cpp/util/logging.h"
#include "src/main/cpp/util/numbers.h"
#include "src/main/cpp/util/port.h"
#include "src/main/cpp/util/strings.h"
@@ -1275,6 +1276,7 @@ static void ComputeBaseDirectories(const string &self_path) {
ExcludePathFromBackup(output_base);
globals->options->output_base = MakeCanonical(output_base);
+
globals->lockfile = globals->options->output_base + "/lock";
globals->jvm_log_file = globals->options->output_base + "/server/jvm.out";
}
@@ -1356,7 +1358,10 @@ static void CheckBinaryPath(const string& argv0) {
// code to a file. In case the server becomes unresonsive or terminates
// unexpectedly (in a way that isn't already handled), we can observe the file,
// if it exists. (If it doesn't, then we know something went horribly wrong.)
-int Main(int argc, const char *argv[], OptionProcessor *option_processor) {
+int Main(int argc, const char *argv[], OptionProcessor *option_processor,
+ std::unique_ptr<blaze_util::LogHandler> log_handler) {
+ // Logging must be set first to assure no log statements are missed.
+ blaze_util::SetLogHandler(std::move(log_handler));
globals = new GlobalVariables(option_processor);
SetupStreams();
diff --git a/src/main/cpp/blaze.h b/src/main/cpp/blaze.h
index 25f484e34f..82a63bb38f 100644
--- a/src/main/cpp/blaze.h
+++ b/src/main/cpp/blaze.h
@@ -15,10 +15,12 @@
#define BAZEL_SRC_MAIN_CPP_BLAZE_H_
#include "src/main/cpp/option_processor.h"
+#include "src/main/cpp/util/logging.h"
namespace blaze {
-int Main(int argc, const char *argv[], OptionProcessor* option_processor);
+int Main(int argc, const char* argv[], OptionProcessor* option_processor,
+ std::unique_ptr<blaze_util::LogHandler> log_handler);
} // namespace blaze
diff --git a/src/main/cpp/main.cc b/src/main/cpp/main.cc
index 02b771465b..2a1928704a 100644
--- a/src/main/cpp/main.cc
+++ b/src/main/cpp/main.cc
@@ -22,5 +22,6 @@ int main(int argc, const char *argv[]) {
std::unique_ptr<blaze::StartupOptions> startup_options(
new blaze::StartupOptions());
return blaze::Main(argc, argv,
- new blaze::OptionProcessor(std::move(startup_options)));
+ new blaze::OptionProcessor(std::move(startup_options)),
+ nullptr /* TODO(b/32939567): Enable Bazel logging. */);
}
diff --git a/src/main/cpp/option_processor.cc b/src/main/cpp/option_processor.cc
index f7340db783..e3224a2ac6 100644
--- a/src/main/cpp/option_processor.cc
+++ b/src/main/cpp/option_processor.cc
@@ -26,6 +26,7 @@
#include "src/main/cpp/blaze_util_platform.h"
#include "src/main/cpp/util/file.h"
#include "src/main/cpp/util/file_platform.h"
+#include "src/main/cpp/util/logging.h"
#include "src/main/cpp/util/strings.h"
#include "src/main/cpp/workspace_layout.h"
@@ -71,6 +72,7 @@ blaze_exit_code::ExitCode OptionProcessor::RcFile::Parse(
list<string>* import_stack,
string* error) {
string filename(filename_ref); // file
+ BAZEL_LOG(INFO) << "Parsing the RcFile " << filename;
string contents;
if (!ReadFile(filename, &contents)) {
// We checked for file readability before, so this is unexpected.
diff --git a/src/main/cpp/util/BUILD b/src/main/cpp/util/BUILD
index ae75b941bc..bf62eff841 100644
--- a/src/main/cpp/util/BUILD
+++ b/src/main/cpp/util/BUILD
@@ -69,6 +69,24 @@ cc_library(
)
cc_library(
+ name = "logging",
+ srcs = ["logging.cc"],
+ hdrs = ["logging.h"],
+ visibility = ["//visibility:public"],
+)
+
+cc_library(
+ name = "bazel_log_handler",
+ srcs = ["bazel_log_handler.cc"],
+ hdrs = ["bazel_log_handler.h"],
+ visibility = ["//visibility:public"],
+ deps = [
+ ":file",
+ ":logging",
+ ],
+)
+
+cc_library(
name = "md5",
srcs = ["md5.cc"],
hdrs = ["md5.h"],
diff --git a/src/main/cpp/util/bazel_log_handler.cc b/src/main/cpp/util/bazel_log_handler.cc
new file mode 100644
index 0000000000..458ffc4bdb
--- /dev/null
+++ b/src/main/cpp/util/bazel_log_handler.cc
@@ -0,0 +1,95 @@
+// Copyright 2016 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/main/cpp/util/bazel_log_handler.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <fstream>
+#include <iostream>
+#include <sstream>
+
+#include "src/main/cpp/util/file.h"
+#include "src/main/cpp/util/logging.h"
+
+namespace blaze_util {
+
+BazelLogHandler::BazelLogHandler()
+ : output_dir_set_attempted_(false),
+ buffer_stream_(new std::stringstream()),
+ logfile_stream_(nullptr) {}
+
+BazelLogHandler::~BazelLogHandler() {
+ // If we never wrote the logs to a file, dump the buffer to stderr,
+ // otherwise, flush the stream.
+ if (logfile_stream_ != nullptr) {
+ logfile_stream_->flush();
+ } else if (buffer_stream_ != nullptr) {
+ std::cerr << buffer_stream_->rdbuf();
+ } else {
+ std::cerr << "Illegal state - neither a logfile nor a logbuffer "
+ << "existed at program end." << std::endl;
+ }
+}
+
+void BazelLogHandler::HandleMessage(LogLevel level, const std::string& filename,
+ int line, const std::string& message) {
+ // Select the appropriate stream to log to.
+ std::ostream* log_stream;
+ if (logfile_stream_ != nullptr) {
+ log_stream = logfile_stream_.get();
+ } else {
+ log_stream = buffer_stream_.get();
+ }
+ *log_stream << "[bazel " << LogLevelName(level) << " " << filename << ":"
+ << line << "] " << message << "\n";
+
+ // If we have a fatal message, we should abort and leave a stack trace -
+ // normal exit behavior will be lost, so print this log message out to
+ // stderr and avoid loosing the information.
+ if (level == LOGLEVEL_FATAL) {
+ std::cerr << "[bazel " << LogLevelName(level) << " " << filename << ":"
+ << line << "] " << message << "\n";
+ std::abort();
+ }
+}
+
+void BazelLogHandler::SetOutputDir(const std::string& new_output_dir) {
+ // Disallow second calls to this, we only intend this to support setting
+ // output_base once it is created, not changing the log location.
+ BAZEL_CHECK(!output_dir_set_attempted_)
+ << "Tried to SetOutputDir a second time, to " << new_output_dir;
+ output_dir_set_attempted_ = true;
+
+ // Create a log file in the newly available directory, and flush the
+ // buffer to it.
+ const std::string logfile = JoinPath(new_output_dir, "bazel_client.log");
+ logfile_stream_ = std::unique_ptr<std::ofstream>(
+ new std::ofstream(logfile, std::fstream::out));
+ if (logfile_stream_->fail()) {
+ // If opening the stream failed, continue buffering and have the logs
+ // dump to stderr at shutdown.
+ logfile_stream_ = std::move(nullptr);
+ BAZEL_LOG(ERROR) << "Opening the log file failed, in directory "
+ << new_output_dir;
+ } else {
+ // Transfer the contents of the buffer to the logfile's stream before
+ // replacing it.
+ *logfile_stream_ << buffer_stream_->rdbuf();
+ buffer_stream_ = std::move(nullptr);
+ logfile_stream_->flush();
+ }
+}
+
+} // namespace blaze_util
diff --git a/src/main/cpp/util/bazel_log_handler.h b/src/main/cpp/util/bazel_log_handler.h
new file mode 100644
index 0000000000..e9a09ae86c
--- /dev/null
+++ b/src/main/cpp/util/bazel_log_handler.h
@@ -0,0 +1,51 @@
+// Copyright 2016 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef BAZEL_SRC_MAIN_CPP_BAZEL_LOG_HANDLER_H_
+#define BAZEL_SRC_MAIN_CPP_BAZEL_LOG_HANDLER_H_
+
+#include <iostream>
+
+#include "src/main/cpp/util/logging.h"
+
+namespace blaze_util {
+
+// Handles logging for the Bazel client.
+// In order to have the logfile in output_base, which does not exist or is
+// unknown at the time of the client's creation, logs are buffered until
+// SetOutputDir is called. At that point, all past log statements are dumped
+// in the appropriate file, and all following statements are logged directly.
+class BazelLogHandler : public blaze_util::LogHandler {
+ public:
+ BazelLogHandler();
+ ~BazelLogHandler() override;
+
+ void HandleMessage(blaze_util::LogLevel level, const std::string& filename,
+ int line, const std::string& message) override;
+
+ // Sets the output directory of the logfile.
+ // Can only be called once - all logs before this call will be buffered and
+ // dumped to the logfile once this is called. If this is never called, or if
+ // creating the logfile failed, the buffered logs will be dumped to stderr at
+ // destruction.
+ void SetOutputDir(const std::string& new_output_dir) override;
+
+ private:
+ bool output_dir_set_attempted_;
+ std::unique_ptr<std::stringstream> buffer_stream_;
+ std::unique_ptr<std::ofstream> logfile_stream_;
+};
+} // namespace blaze_util
+
+#endif // BAZEL_SRC_MAIN_CPP_BAZEL_LOG_HANDLER_H_
diff --git a/src/main/cpp/util/errors.h b/src/main/cpp/util/errors.h
index 1e991d2a52..84de39d715 100644
--- a/src/main/cpp/util/errors.h
+++ b/src/main/cpp/util/errors.h
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
+// TODO(b/32967056) die() and pdie() are really error statements with an exit;
+// these can be removed now that logging exists.
#ifndef BAZEL_SRC_MAIN_CPP_UTIL_ERRORS_H_
#define BAZEL_SRC_MAIN_CPP_UTIL_ERRORS_H_
diff --git a/src/main/cpp/util/logging.cc b/src/main/cpp/util/logging.cc
new file mode 100644
index 0000000000..7d0bd0bfd0
--- /dev/null
+++ b/src/main/cpp/util/logging.cc
@@ -0,0 +1,91 @@
+// Copyright 2016 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This file is based off the logging work by the protobuf team
+#include "src/main/cpp/util/logging.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <iostream>
+#include <memory>
+
+namespace blaze_util {
+
+const char* LogLevelName(LogLevel level) {
+ static const char* level_names[] = {"INFO", "WARNING", "ERROR", "FATAL"};
+ BAZEL_CHECK(static_cast<int>(level) < 4)
+ << "LogLevelName: level out of range, there are only 4 levels.";
+ return level_names[level];
+}
+
+namespace internal {
+
+static std::unique_ptr<LogHandler> log_handler_(nullptr);
+
+LogMessage::LogMessage(LogLevel level, const std::string& filename, int line)
+ : level_(level), filename_(filename), line_(line) {}
+
+#undef DECLARE_STREAM_OPERATOR
+#define DECLARE_STREAM_OPERATOR(TYPE) \
+ LogMessage& LogMessage::operator<<(TYPE value) { \
+ message_ << value; \
+ return *this; \
+ }
+
+DECLARE_STREAM_OPERATOR(const std::string&)
+DECLARE_STREAM_OPERATOR(const char*)
+DECLARE_STREAM_OPERATOR(char)
+DECLARE_STREAM_OPERATOR(bool)
+DECLARE_STREAM_OPERATOR(short)
+DECLARE_STREAM_OPERATOR(int)
+DECLARE_STREAM_OPERATOR(unsigned int)
+DECLARE_STREAM_OPERATOR(long)
+DECLARE_STREAM_OPERATOR(unsigned long)
+DECLARE_STREAM_OPERATOR(long long)
+DECLARE_STREAM_OPERATOR(unsigned long long)
+DECLARE_STREAM_OPERATOR(float)
+DECLARE_STREAM_OPERATOR(double)
+DECLARE_STREAM_OPERATOR(long double)
+DECLARE_STREAM_OPERATOR(void*)
+#undef DECLARE_STREAM_OPERATOR
+
+void LogMessage::Finish() {
+ std::string message(message_.str());
+ if (log_handler_ != nullptr) {
+ log_handler_->HandleMessage(level_, filename_, line_, message);
+ } else if (level_ == LOGLEVEL_FATAL) {
+ // Expect the log_handler_ to handle FATAL calls, but we should still fail
+ // as expected even if no log_handler_ is defined. For ease of debugging,
+ // we also print out the error statement.
+ std::cerr << filename_ << ":" << line_ << " FATAL: " << message
+ << std::endl;
+ std::abort();
+ }
+}
+
+void LogFinisher::operator=(LogMessage& other) { other.Finish(); }
+
+} // namespace internal
+
+void SetLogHandler(std::unique_ptr<LogHandler> new_handler) {
+ internal::log_handler_ = std::move(new_handler);
+}
+
+void SetLogfileDirectory(const std::string& output_dir) {
+ if (internal::log_handler_ != nullptr) {
+ internal::log_handler_->SetOutputDir(output_dir);
+ }
+}
+
+} // namespace blaze_util
diff --git a/src/main/cpp/util/logging.h b/src/main/cpp/util/logging.h
new file mode 100644
index 0000000000..506ed59eb7
--- /dev/null
+++ b/src/main/cpp/util/logging.h
@@ -0,0 +1,158 @@
+// Copyright 2016 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#ifndef BAZEL_SRC_MAIN_CPP_LOGGING_H_
+#define BAZEL_SRC_MAIN_CPP_LOGGING_H_
+
+#include <memory>
+#include <sstream>
+#include <string>
+
+// This file is based off the logging work by the protobuf team in
+// stubs/logging.h,
+//
+// Users of this logging library should use BAZEL_LOG(level) << ""; format,
+// and specify how they wish to handle the output of the log messages by
+// creating a LogHandler to pass to SetLogHandler().
+namespace blaze_util {
+
+enum LogLevel {
+ LOGLEVEL_INFO,
+ LOGLEVEL_WARNING,
+ LOGLEVEL_ERROR,
+ LOGLEVEL_FATAL,
+
+#ifdef NDEBUG
+ LOGLEVEL_DFATAL = LOGLEVEL_ERROR
+#else
+ LOGLEVEL_DFATAL = LOGLEVEL_FATAL
+#endif
+};
+
+// Returns a string representation of the log level.
+const char* LogLevelName(LogLevel level);
+
+namespace internal {
+
+class LogFinisher;
+class LogMessage {
+ public:
+ LogMessage(LogLevel level, const std::string& filename, int line);
+
+ LogMessage& operator<<(const std::string& value);
+ LogMessage& operator<<(const char* value);
+ LogMessage& operator<<(char value);
+ LogMessage& operator<<(bool value);
+ LogMessage& operator<<(short value);
+ LogMessage& operator<<(int value);
+ LogMessage& operator<<(unsigned int value);
+ LogMessage& operator<<(long value);
+ LogMessage& operator<<(unsigned long value);
+ LogMessage& operator<<(long long value);
+ LogMessage& operator<<(unsigned long long value);
+ LogMessage& operator<<(float value);
+ LogMessage& operator<<(double value);
+ LogMessage& operator<<(long double value);
+ LogMessage& operator<<(void* value);
+
+ private:
+ friend class LogFinisher;
+ void Finish();
+
+ LogLevel level_;
+ const std::string& filename_;
+ int line_;
+ std::stringstream message_;
+};
+
+// Used to make the entire "LOG(BLAH) << etc." expression have a void return
+// type and print a newline after each message.
+class LogFinisher {
+ public:
+ void operator=(LogMessage& other);
+};
+
+template <typename T>
+bool IsOk(T status) {
+ return status.ok();
+}
+template <>
+inline bool IsOk(bool status) {
+ return status;
+}
+
+} // namespace internal
+
+#define BAZEL_LOG(LEVEL) \
+ ::blaze_util::internal::LogFinisher() = ::blaze_util::internal::LogMessage( \
+ ::blaze_util::LOGLEVEL_##LEVEL, __FILE__, __LINE__)
+#define BAZEL_LOG_IF(LEVEL, CONDITION) !(CONDITION) ? (void)0 : BAZEL_LOG(LEVEL)
+
+#define BAZEL_CHECK(EXPRESSION) \
+ BAZEL_LOG_IF(FATAL, !(EXPRESSION)) << "CHECK failed: " #EXPRESSION ": "
+#define BAZEL_CHECK_OK(A) BAZEL_CHECK(::blaze_util::internal::IsOk(A))
+#define BAZEL_CHECK_EQ(A, B) BAZEL_CHECK((A) == (B))
+#define BAZEL_CHECK_NE(A, B) BAZEL_CHECK((A) != (B))
+#define BAZEL_CHECK_LT(A, B) BAZEL_CHECK((A) < (B))
+#define BAZEL_CHECK_LE(A, B) BAZEL_CHECK((A) <= (B))
+#define BAZEL_CHECK_GT(A, B) BAZEL_CHECK((A) > (B))
+#define BAZEL_CHECK_GE(A, B) BAZEL_CHECK((A) >= (B))
+
+#ifdef NDEBUG
+
+#define BAZEL_DLOG(LEVEL) BAZEL_LOG_IF(LEVEL, false)
+
+#define BAZEL_DCHECK(EXPRESSION) \
+ while (false) BAZEL_CHECK(EXPRESSION)
+#define BAZEL_DCHECK_OK(E) BAZEL_DCHECK(::blaze::internal::IsOk(E))
+#define BAZEL_DCHECK_EQ(A, B) BAZEL_DCHECK((A) == (B))
+#define BAZEL_DCHECK_NE(A, B) BAZEL_DCHECK((A) != (B))
+#define BAZEL_DCHECK_LT(A, B) BAZEL_DCHECK((A) < (B))
+#define BAZEL_DCHECK_LE(A, B) BAZEL_DCHECK((A) <= (B))
+#define BAZEL_DCHECK_GT(A, B) BAZEL_DCHECK((A) > (B))
+#define BAZEL_DCHECK_GE(A, B) BAZEL_DCHECK((A) >= (B))
+
+#else // NDEBUG
+
+#define BAZEL_DLOG BAZEL_LOG
+
+#define BAZEL_DCHECK BAZEL_CHECK
+#define BAZEL_DCHECK_OK BAZEL_CHECK_OK
+#define BAZEL_DCHECK_EQ BAZEL_CHECK_EQ
+#define BAZEL_DCHECK_NE BAZEL_CHECK_NE
+#define BAZEL_DCHECK_LT BAZEL_CHECK_LT
+#define BAZEL_DCHECK_LE BAZEL_CHECK_LE
+#define BAZEL_DCHECK_GT BAZEL_CHECK_GT
+#define BAZEL_DCHECK_GE BAZEL_CHECK_GE
+
+#endif // !NDEBUG
+
+class LogHandler {
+ public:
+ virtual ~LogHandler() {}
+ virtual void HandleMessage(LogLevel level, const std::string& filename,
+ int line, const std::string& message) = 0;
+ virtual void SetOutputDir(const std::string& output_base) = 0;
+};
+
+// Sets the log handler that routes all log messages.
+// SetLogHandler is not thread-safe. You should only call it
+// at initialization time, and probably not from library code.
+void SetLogHandler(std::unique_ptr<LogHandler> new_handler);
+
+// Sets the current handler's output directory, given that the Handler cares.
+void SetLogfileDirectory(const std::string& output_dir);
+
+} // namespace blaze_util
+
+#endif // BAZEL_SRC_MAIN_CPP_LOGGING_H_
diff --git a/src/test/cpp/util/BUILD b/src/test/cpp/util/BUILD
index 60c057b3f4..033fca6268 100644
--- a/src/test/cpp/util/BUILD
+++ b/src/test/cpp/util/BUILD
@@ -32,6 +32,16 @@ cc_test(
)
cc_test(
+ name = "logging_test",
+ srcs = ["logging_test.cc"],
+ deps = [
+ "//src/main/cpp/util:bazel_log_handler",
+ "//src/main/cpp/util:logging",
+ "//third_party:gtest",
+ ],
+)
+
+cc_test(
name = "numbers_test",
srcs = ["numbers_test.cc"],
deps = [
diff --git a/src/test/cpp/util/logging_test.cc b/src/test/cpp/util/logging_test.cc
new file mode 100644
index 0000000000..1f7c6cd585
--- /dev/null
+++ b/src/test/cpp/util/logging_test.cc
@@ -0,0 +1,70 @@
+// Copyright 2016 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include <iostream>
+#include <memory>
+#include <string>
+
+#include "src/main/cpp/util/bazel_log_handler.h"
+#include "src/main/cpp/util/logging.h"
+#include "gtest/gtest.h"
+
+namespace blaze_util {
+
+TEST(LoggingTest, BazelLogHandlerDumpsToCerrAtFail) {
+ // Set up logging and be prepared to capture stderr at destruction.
+ testing::internal::CaptureStderr();
+ std::unique_ptr<blaze_util::BazelLogHandler> handler(
+ new blaze_util::BazelLogHandler());
+ blaze_util::SetLogHandler(std::move(handler));
+
+ // Log something.
+ std::string teststring = "test that the log messages get dumped to stderr";
+ BAZEL_LOG(INFO) << teststring;
+
+ // Check that stderr isn't getting anything yet.
+ std::string nothing = testing::internal::GetCapturedStderr();
+ ASSERT_TRUE(nothing.find(teststring) == std::string::npos);
+ testing::internal::CaptureStderr();
+
+ // Destruct the log handler and get the stderr remains.
+ blaze_util::SetLogHandler(nullptr);
+ std::string output = testing::internal::GetCapturedStderr();
+ ASSERT_TRUE(output.find(teststring) != std::string::npos);
+}
+
+TEST(LoggingTest, LogLevelNamesMatch) {
+ EXPECT_STREQ("INFO", LogLevelName(LOGLEVEL_INFO));
+ EXPECT_STREQ("WARNING", LogLevelName(LOGLEVEL_WARNING));
+ EXPECT_STREQ("ERROR", LogLevelName(LOGLEVEL_ERROR));
+ EXPECT_STREQ("FATAL", LogLevelName(LOGLEVEL_FATAL));
+}
+
+TEST(LoggingTest, ImpossibleFile) {
+ // Set up to capture logging to stderr.
+ testing::internal::CaptureStderr();
+ std::unique_ptr<blaze_util::BazelLogHandler> handler(
+ new blaze_util::BazelLogHandler());
+ blaze_util::SetLogHandler(std::move(handler));
+
+ // Deliberately try to log to an impossible location, check that we error out.
+ blaze_util::SetLogfileDirectory("/this/doesnt/exist");
+
+ // Cause the logs to be flushed, and capture them.
+ blaze_util::SetLogHandler(nullptr);
+ std::string output = testing::internal::GetCapturedStderr();
+ ASSERT_TRUE(output.find("ERROR") != std::string::npos);
+ ASSERT_TRUE(output.find("/this/doesnt/exist") != std::string::npos);
+}
+
+} // namespace blaze_util