blob: aa0e2da72730451b22c1caec98aa96ae8c301595 [file] [log] [blame]
// 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 <iostream>
#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_USER,
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(LogLevel level, const std::string& filename, int line,
int exit_code);
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();
const LogLevel level_;
const std::string& filename_;
const int line_;
// Only used for FATAL log messages.
const int exit_code_;
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_DIE(EXIT_CODE) \
::blaze_util::internal::LogFinisher() = ::blaze_util::internal::LogMessage( \
::blaze_util::LOGLEVEL_FATAL, __FILE__, __LINE__, EXIT_CODE)
#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
// How much to print on the terminal.
enum LoggingDetail {
LOGGINGDETAIL_QUIET, // Only errors
LOGGINGDETAIL_USER, // Messages intended for the user (level USER and above)
LOGGINGDETAIL_DEBUG // Debug logging
};
class LogHandler {
public:
virtual ~LogHandler() {}
virtual void HandleMessage(LogLevel level, const std::string& filename,
int line, const std::string& message,
int exit_code) = 0;
// See ::SetLoggingDetail()
virtual void SetLoggingDetail(LoggingDetail detail,
std::ostream* debug_stream) = 0;
// See ::CloseLogging()
virtual void Close() = 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 logging detail for the currently set log handler. Prints the log
// messages to `debug_stream` if not null. It doesn't affect non-debug messages
// and is only used for testing.
void SetLoggingDetail(LoggingDetail detail, std::ostream* debug_stream);
// Closes the logging. Buffers are flushed and no more log messages will be
// printed.
void CloseLogging();
} // namespace blaze_util
#endif // BAZEL_SRC_MAIN_CPP_LOGGING_H_