blob: dff3d021e6085b026a17b3177b5c60b1d821f384 [file] [log] [blame]
// Copyright 2014 The Android Open Source Project
//
// 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.
#pragma once
#include <errno.h> // for errno
#include <stdio.h> // for size_t, EOF
#include <string.h> // for strcmp
#include <iostream> // for ostream, operator<<
#include <string_view>
#include <vector> // for vector
#include "aemu/base/logging/LogSeverity.h" // for LogSeverity, EMULATOR_...
namespace android {
namespace base {
// Returns the minimal log level.
::LogSeverity getMinLogLevel();
void setMinLogLevel(::LogSeverity level);
class LogFormatter;
void setLogFormatter(LogFormatter* fmt);
// Convert a log level name (e.g. 'INFO') into the equivalent
// ::android::base LOG_<name> constant.
#define LOG_SEVERITY_FROM(x) EMULATOR_LOG_##x
// Helper macro used to test if logging for a given log level is
// currently enabled. |severity| must be a log level without the LOG_
// prefix, as in:
//
// if (LOG_IS_ON(INFO)) {
// ... do additionnal logging
// }
//
#define LOG_IS_ON(severity) \
(LOG_SEVERITY_FROM(severity) >= ::android::base::getMinLogLevel())
// For performance reasons, it's important to avoid constructing a
// LogMessage instance every time a LOG() or CHECK() statement is
// encountered at runtime, i.e. these objects should only be constructed
// when absolutely necessary, which means:
// - For LOG() statements, when the corresponding log level is enabled.
// - For CHECK(), when the tested expression doesn't hold.
//
// At the same time, we really want to use expressions like:
// LOG(severity) << some_stuff << some_more_stuff;
//
// This means LOG(severity) should expand to something that can take
// << operators on its right hand side. This is achieved with the
// ternary '? :', as implemented by this helper macro.
//
// Unfortunately, a simple thing like:
//
// !(condition) ? (void)0 : (expr)
//
// will not work, because the compiler complains loudly with:
//
// error: second operand to the conditional operator is of type 'void',
// but the third operand is neither a throw-expression nor of type 'void'
#define LOG_LAZY_EVAL(condition, expr) \
!(condition) ? (void)0 : ::android::base::LogStreamVoidify() & (expr)
// Send a message to the log if |severity| is higher or equal to the current
// logging severity level. This macro expands to an expression that acts as
// an input stream for strings, ints and floating point values, as well as
// LogString instances. Usage example:
//
// LOG(INFO) << "Starting flux capacitor";
// fluxCapacitor::start();
// LOG(INFO) << "Flux capacitor started";
//
// Note that the macro implementation is optimized to avoid doing any work
// if the severity level is disabled.
//
// It's possible to do conditional logging with LOG_IF()
#define LOG(severity) \
LOG_LAZY_EVAL(LOG_IS_ON(severity), LOG_MESSAGE_STREAM_COMPACT(severity))
// A variant of LOG() that only performs logging if a specific condition
// is encountered. Note that |condition| is only evaluated if |severity|
// is high enough. Usage example:
//
// LOG(INFO) << "Starting fuel injector";
// fuelInjector::start();
// LOG(INFO) << "Fuel injection started";
// LOG_IF(INFO, fuelInjector::hasOptimalLevel())
// << "Fuel injection at optimal level";
//
#define LOG_IF(severity, condition) \
LOG_LAZY_EVAL(LOG_IS_ON(severity) && (condition), \
LOG_MESSAGE_STREAM_COMPACT(severity))
// A variant of LOG() that avoids printing debug information such as file/line
// information, for user-visible output.
#define QLOG(severity) \
LOG_LAZY_EVAL(LOG_IS_ON(severity), QLOG_MESSAGE_STREAM_COMPACT(severity))
// A variant of LOG_IF() that avoids printing debug information such as
// file/line information, for user-visible output.
#define QLOG_IF(severity, condition) \
LOG_LAZY_EVAL(LOG_IS_ON(severity) && (condition), \
QLOG_MESSAGE_STREAM_COMPACT(severity))
// A variant of LOG() that integrates with the utils/debug.h verbose tags,
// enabling statements to only appear on the console if the "-debug-<tag>"
// command line parameter is provided. Example:
//
// VLOG(virtualscene) << "Starting scene.";
//
// Which would only be visible if -debug-virtualscene or -debug-all is passed
// as a command line parameter.
//
// When logging is enabled, VLOG statements are logged at the INFO severity.
#define VLOG(tag) \
LOG_LAZY_EVAL(VERBOSE_CHECK(tag), LOG_MESSAGE_STREAM_COMPACT(INFO))
// A variant of LOG() that also appends the string message corresponding
// to the current value of 'errno' just before the macro is called. This
// also preserves the value of 'errno' so it can be tested after the
// macro call (i.e. any error during log output does not interfere).
#define PLOG(severity) \
LOG_LAZY_EVAL(LOG_IS_ON(severity), PLOG_MESSAGE_STREAM_COMPACT(severity))
// A variant of LOG_IF() that also appends the string message corresponding
// to the current value of 'errno' just before the macro is called. This
// also preserves the value of 'errno' so it can be tested after the
// macro call (i.e. any error during log output does not interfere).
#define PLOG_IF(severity, condition) \
LOG_LAZY_EVAL(LOG_IS_ON(severity) && (condition), \
PLOG_MESSAGE_STREAM_COMPACT(severity))
// Evaluate |condition|, and if it fails, log a fatal message.
// This is a better version of assert(), in the future, this will
// also break directly into the debugger for debug builds.
//
// Usage is similar to LOG(FATAL), e.g.:
//
// CHECK(some_condition) << "Something really bad happened!";
//
#define CHECK(condition) \
LOG_IF(FATAL, !(condition)) << "Check failed: " #condition ". "
// A variant of CHECK() that also appends the errno message string at
// the end of the log message before exiting the process.
#define PCHECK(condition) \
PLOG_IF(FATAL, !(condition)) << "Check failed: " #condition ". "
// Define ENABLE_DLOG to 1 here if DLOG() statements should be compiled
// as normal LOG() ones in the final binary. If 0, the statements will not
// be compiled.
#ifndef ENABLE_DLOG
#if defined(NDEBUG)
#define ENABLE_DLOG 0
#else
#define ENABLE_DLOG 1
#endif
#endif
// ENABLE_DCHECK controls how DCHECK() statements are compiled:
// 0 - DCHECK() are not compiled in the binary at all.
// 1 - DCHECK() are compiled, but are not performed at runtime, unless
// the DCHECK level has been increased explicitely.
// 2 - DCHECK() are always compiled as CHECK() in the final binary.
#ifndef ENABLE_DCHECK
#if defined(NDEBUG)
#define ENABLE_DCHECK 1
#else
#define ENABLE_DCHECK 2
#endif
#endif
// DLOG_IS_ON(severity) is used to indicate whether DLOG() should print
// something for the current level.
#if ENABLE_DLOG
#define DLOG_IS_ON(severity) LOG_IS_ON(severity)
#else
// NOTE: The compile-time constant ensures that the DLOG() statements are
// not compiled in the final binary.
#define DLOG_IS_ON(severity) false
#endif
// DCHECK_IS_ON() is used to indicate whether DCHECK() should do anything.
#if ENABLE_DCHECK == 0
// NOTE: Compile-time constant ensures the DCHECK() statements are
// not compiled in the final binary.
#define DCHECK_IS_ON() false
#elif ENABLE_DCHECK == 1
#define DCHECK_IS_ON() ::android::base::dcheckIsEnabled()
#else
#define DCHECK_IS_ON() true
#endif
// A function that returns true iff DCHECK() should actually do any checking.
bool dcheckIsEnabled();
// Change the DCHECK() level to either false or true. Should only be called
// early, e.g. after parsing command-line arguments. Returns previous value.
bool setDcheckLevel(bool enabled);
// DLOG() is like LOG() for debug builds, and doesn't do anything for
// release one. This is useful to add log messages that you don't want
// to see in the final binaries, but are useful during testing.
#define DLOG(severity) DLOG_IF(severity, true)
// DLOG_IF() is like DLOG() for debug builds, and doesn't do anything for
// release one. See DLOG() comments.
#define DLOG_IF(severity, condition) \
LOG_LAZY_EVAL(DLOG_IS_ON(severity) && (condition), \
LOG_MESSAGE_STREAM_COMPACT(severity))
// DCHECK(condition) is used to perform CHECK() in debug builds, or if
// the program called setDcheckLevel(true) previously. Note that it is
// also possible to completely remove them from the final binary by
// using the compiler flag -DENABLE_DCHECK=0
#define DCHECK(condition) \
LOG_IF(FATAL, DCHECK_IS_ON() && !(condition)) \
<< "Check failed: " #condition ". "
// DPLOG() is like DLOG() that also appends the string message corresponding
// to the current value of 'errno' just before the macro is called. This
// also preserves the value of 'errno' so it can be tested after the
// macro call (i.e. any error during log output does not interfere).
#define DPLOG(severity) DPLOG_IF(severity, true)
// DPLOG_IF() tests whether |condition| is true before calling
// DPLOG(severity)
#define DPLOG_IF(severity, condition) \
LOG_LAZY_EVAL(DLOG_IS_ON(severity) && (condition), \
PLOG_MESSAGE_STREAM_COMPACT(severity))
// Convenience class used hold a formatted string for logging reasons.
// Usage example:
//
// LOG(INFO) << LogString("There are %d items in this set", count);
//
class LogString {
public:
LogString(const char* fmt, ...);
const char* string() const { return mString.data(); }
private:
std::vector<char> mString;
};
// Helper structure used to group the parameters of a LOG() or CHECK()
// statement.
struct LogParams {
LogParams() {}
LogParams(const char* a_file,
int a_lineno,
LogSeverity a_severity,
bool quiet = false)
: file(a_file), lineno(a_lineno), severity(a_severity), quiet(quiet) {}
friend bool operator==(const LogParams& s1, const LogParams& s2) {
return s1.lineno == s2.lineno && s1.severity == s2.severity &&
s1.quiet == s2.quiet &&
((s1.file == nullptr && s2.file == nullptr) || // both null..
(s1.file != nullptr && s2.file != nullptr &&
(s1.file == s2.file ||
strcmp(s1.file, s2.file) == 0)) // or the same
);
}
const char* file = nullptr;
int lineno = -1;
LogSeverity severity = LOG_SEVERITY_FROM(DEBUG);
bool quiet = false;
};
class LogstreamBuf : public std::streambuf {
public:
LogstreamBuf();
size_t size();
char* str();
protected:
int overflow(int c) override;
private:
std::vector<char> mLongString;
char mStr[256];
};
// Helper class used to implement an input stream similar to std::istream
// where it's possible to inject strings, integers, floats and LogString
// instances with the << operator.
//
// This also takes a source file, line number and severity to avoid
// storing these in the stack of the functions were LOG() and CHECK()
// statements are called.
class LogStream {
public:
LogStream(const char* file, int lineno, LogSeverity severity, bool quiet);
~LogStream() = default;
template <typename T>
std::ostream& operator<<(const T& t) {
return mStream << t;
}
const char* str() { return mStreamBuf.str(); }
const size_t size() { return mStreamBuf.size(); }
const LogParams& params() const { return mParams; }
private:
LogParams mParams;
LogstreamBuf mStreamBuf;
std::ostream mStream;
};
// Add your own types when needed:
std::ostream& operator<<(std::ostream& stream,
const android::base::LogString& str);
std::ostream& operator<<(std::ostream& stream, const std::string_view& str);
// Helper class used to avoid compiler errors, see LOG_LAZY_EVAL for
// more information.
class LogStreamVoidify {
public:
LogStreamVoidify() {}
// This has to be an operator with a precedence lower than << but
// higher than ?:
void operator&(std::ostream&) {}
};
// This represents an log message. At creation time, provide the name of
// the current file, the source line number and a severity.
// You can them stream stuff into it with <<. For example:
//
// LogMessage(__FILE__, __LINE__, LOG_INFO) << "Hello World!\n";
//
// When destroyed, the message sends the final output to the appropriate
// log (e.g. stderr by default).
class LogMessage {
public:
// To suppress printing file/line, set quiet = true.
LogMessage(const char* file,
int line,
LogSeverity severity,
bool quiet = false);
~LogMessage();
LogStream& stream() const { return *mStream; }
protected:
// Avoid that each LOG() statement
LogStream* mStream;
};
// Helper macros to avoid too much typing. This creates a new LogMessage
// instance with the appropriate file source path, file source line and
// severity.
#define LOG_MESSAGE_COMPACT(severity) \
::android::base::LogMessage(__FILE__, __LINE__, LOG_SEVERITY_FROM(severity))
#define LOG_MESSAGE_STREAM_COMPACT(severity) \
LOG_MESSAGE_COMPACT(severity).stream()
// A variant of LogMessage for outputting user-visible messages to the console,
// without debug information.
#define QLOG_MESSAGE_COMPACT(severity) \
::android::base::LogMessage(__FILE__, __LINE__, \
LOG_SEVERITY_FROM(severity), true)
#define QLOG_MESSAGE_STREAM_COMPACT(severity) \
QLOG_MESSAGE_COMPACT(severity).stream()
// A variant of LogMessage that saves the errno value on creation,
// then restores it on destruction, as well as append a strerror()
// error message to the log before sending it for output. Used by
// the PLOG() implementation(s).
//
// This cannot be a sub-class of LogMessage because the destructor needs
// to restore the saved errno message after sending the message to the
// LogOutput and deleting the stream.
class ErrnoLogMessage {
public:
ErrnoLogMessage(const char* file,
int line,
LogSeverity severity,
int errnoCode);
~ErrnoLogMessage();
LogStream& stream() const { return *mStream; }
private:
LogStream* mStream;
int mErrno;
};
// Helper macros to avoid too much typing.
#define PLOG_MESSAGE_COMPACT(severity) \
::android::base::ErrnoLogMessage(__FILE__, __LINE__, \
LOG_SEVERITY_FROM(severity), errno)
#define PLOG_MESSAGE_STREAM_COMPACT(severity) \
PLOG_MESSAGE_COMPACT(severity).stream()
namespace testing {
// Abstract interface to the output where the log messages are sent.
// IMPORTANT: Only use this for unit testing the log facility.
class LogOutput {
public:
LogOutput() {}
virtual ~LogOutput() {}
// Send a full log message to the output. Not zero terminated, and
// Does not have a trailing \n which can be added by the implementation
// when writing the message to a file.
// Note: if |severity| is LOG_FATAL, this should also terminate the
// process.
virtual void logMessage(const LogParams& params,
const char* message,
size_t message_len) = 0;
// Set a new log output, and return pointer to the previous
// implementation, which will be NULL for the default one.
// |newOutput| is either NULL (which means the default), or a
// custom instance of LogOutput.
static LogOutput* setNewOutput(LogOutput* newOutput);
};
} // namespace testing
} // namespace base
} // namespace android