diff options
Diffstat (limited to 'absl/log/log.h')
-rw-r--r-- | absl/log/log.h | 439 |
1 files changed, 439 insertions, 0 deletions
diff --git a/absl/log/log.h b/absl/log/log.h new file mode 100644 index 00000000..13c4938f --- /dev/null +++ b/absl/log/log.h @@ -0,0 +1,439 @@ +// Copyright 2022 The Abseil Authors. +// +// 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 +// +// https://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. +// +// ----------------------------------------------------------------------------- +// File: log/log.h +// ----------------------------------------------------------------------------- +// +// This header declares a family of LOG macros. +// +// Basic invocation looks like this: +// +// LOG(INFO) << "Found " << num_cookies << " cookies"; +// +// Most `LOG` macros take a severity level argument. The severity levels are +// `INFO`, `WARNING`, `ERROR`, and `FATAL`. They are defined +// in absl/base/log_severity.h. +// * The `FATAL` severity level terminates the program with a stack trace after +// logging its message. Error handlers registered with `RunOnFailure` +// (process_state.h) are run, but exit handlers registered with `atexit(3)` +// are not. +// * The `QFATAL` pseudo-severity level is equivalent to `FATAL` but triggers +// quieter termination messages, e.g. without a full stack trace, and skips +// running registered error handlers. +// Some preprocessor shenanigans are used to ensure that e.g. `LOG(INFO)` has +// the same meaning even if a local symbol or preprocessor macro named `INFO` is +// defined. To specify a severity level using an expression instead of a +// literal, use `LEVEL(expr)`. +// Example: +// +// LOG(LEVEL(stale ? absl::LogSeverity::kWarning : absl::LogSeverity::kInfo)) +// << "Cookies are " << days << " days old"; + +// `LOG` macros evaluate to an unterminated statement. The value at the end of +// the statement supports some chainable methods: +// +// * .AtLocation(absl::string_view file, int line) +// .AtLocation(absl::SourceLocation loc) +// Overrides the location inferred from the callsite. The string pointed to +// by `file` must be valid until the end of the statement. +// * .NoPrefix() +// Omits the prefix from this line. The prefix includes metadata about the +// logged data such as source code location and timestamp. +// * .WithTimestamp(absl::Time timestamp) +// Uses the specified timestamp instead of one collected at the time of +// execution. +// * .WithThreadID(absl::LogEntry::tid_t tid) +// Uses the specified thread ID instead of one collected at the time of +// execution. +// * .WithMetadataFrom(const absl::LogEntry &entry) +// Copies all metadata (but no data) from the specified `absl::LogEntry`. +// This can be used to change the severity of a message, but it has some +// limitations: +// * `ABSL_MIN_LOG_LEVEL` is evaluated against the severity passed into +// `LOG` (or the implicit `FATAL` level of `CHECK`). +// * `LOG(FATAL)` and `CHECK` terminate the process unconditionally, even if +// the severity is changed later. +// `.WithMetadataFrom(entry)` should almost always be used in combination +// with `LOG(LEVEL(entry.log_severity()))`. +// * .WithPerror() +// Appends to the logged message a colon, a space, a textual description of +// the current value of `errno` (as by `strerror(3)`), and the numerical +// value of `errno`. +// * .ToSinkAlso(absl::LogSink* sink) +// Sends this message to `*sink` in addition to whatever other sinks it +// would otherwise have been sent to. `sink` must not be null. +// * .ToSinkOnly(absl::LogSink* sink) +// Sends this message to `*sink` and no others. `sink` must not be null. +// +// No interfaces in this header are async-signal-safe; their use in signal +// handlers is unsupported and may deadlock your program or eat your lunch. +// +// Many logging statements are inherently conditional. For example, +// `LOG_IF(INFO, !foo)` does nothing if `foo` is true. Even seemingly +// unconditional statements like `LOG(INFO)` might be disabled at +// compile-time to minimize binary size or for security reasons. +// +// * Except for the condition in a `CHECK` or `QCHECK` statement, programs must +// not rely on evaluation of expressions anywhere in logging statements for +// correctness. For example, this is ok: +// +// CHECK((fp = fopen("config.ini", "r")) != nullptr); +// +// But this is probably not ok: +// +// LOG(INFO) << "Server status: " << StartServerAndReturnStatusString(); +// +// The example below is bad too; the `i++` in the `LOG_IF` condition might +// not be evaluated, resulting in an infinite loop: +// +// for (int i = 0; i < 1000000;) +// LOG_IF(INFO, i++ % 1000 == 0) << "Still working..."; +// +// * Except where otherwise noted, conditions which cause a statement not to log +// also cause expressions not to be evaluated. Programs may rely on this for +// performance reasons, e.g. by streaming the result of an expensive function +// call into a `DLOG` or `LOG_EVERY_N` statement. +// * Care has been taken to ensure that expressions are parsed by the compiler +// even if they are never evaluated. This means that syntax errors will be +// caught and variables will be considered used for the purposes of +// unused-variable diagnostics. For example, this statement won't compile +// even if `INFO`-level logging has been compiled out: +// +// int number_of_cakes = 40; +// LOG(INFO) << "Number of cakes: " << number_of_cake; // Note the typo! +// +// Similarly, this won't produce unused-variable compiler diagnostics even +// if `INFO`-level logging is compiled out: +// +// { +// char fox_line1[] = "Hatee-hatee-hatee-ho!"; +// LOG_IF(ERROR, false) << "The fox says " << fox_line1; +// char fox_line2[] = "A-oo-oo-oo-ooo!"; +// LOG(INFO) << "The fox also says " << fox_line2; +// } +// +// This error-checking is not perfect; for example, symbols that have been +// declared but not defined may not produce link errors if used in logging +// statements that compile away. +// +// Expressions streamed into these macros are formatted using `operator<<` just +// as they would be if streamed into a `std::ostream`, however it should be +// noted that their actual type is unspecified. +// +// To implement a custom formatting operator for a type you own, define +// `std::ostream& operator<<(std::ostream&, ...)` in your type's namespace (for +// ADL) just as you would to stream it to `std::cout`. +// +// Those macros that support streaming honor output manipulators and `fmtflag` +// changes that output data (e.g. `std::ends`) or control formatting of data +// (e.g. `std::hex` and `std::fixed`), however flushing such a stream is +// ignored. The message produced by a log statement is sent to registered +// `absl::LogSink` instances at the end of the statement; those sinks are +// responsible for their own flushing (e.g. to disk) semantics. +// +// Flag settings are not carried over from one `LOG` statement to the next; this +// is a bit different than e.g. `std::cout`: +// +// LOG(INFO) << std::hex << 0xdeadbeef; // logs "0xdeadbeef" +// LOG(INFO) << 0xdeadbeef; // logs "3735928559" + +#ifndef ABSL_LOG_LOG_H_ +#define ABSL_LOG_LOG_H_ + +#include "absl/log/internal/conditions.h" +#include "absl/log/internal/log_message.h" +#include "absl/log/internal/strip.h" + +// LOG() +// +// `LOG` takes a single argument which is a severity level. Data streamed in +// comprise the logged message. +// Example: +// +// LOG(INFO) << "Found " << num_cookies << " cookies"; +#define LOG(severity) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATELESS, true) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() + +// PLOG() +// +// `PLOG` behaves like `LOG` except that a description of the current state of +// `errno` is appended to the streamed message. +#define PLOG(severity) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATELESS, true) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() \ + .WithPerror() + +// DLOG() +// +// `DLOG` behaves like `LOG` in debug mode (i.e. `#ifndef NDEBUG`). Otherwise +// it compiles away and does nothing. Note that `DLOG(FATAL)` does not +// terminate the program if `NDEBUG` is defined. +#ifndef NDEBUG +#define DLOG(severity) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATELESS, true) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() +#else +#define DLOG(severity) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATELESS, false) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() +#endif + +// `LOG_IF` and friends add a second argument which specifies a condition. If +// the condition is false, nothing is logged. +// Example: +// +// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; +// +// There is no `VLOG_IF` because the order of evaluation of the arguments is +// ambiguous and the alternate spelling with an `if`-statement is trivial. +#define LOG_IF(severity, condition) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATELESS, condition) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() +#define PLOG_IF(severity, condition) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATELESS, condition) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() \ + .WithPerror() + +#ifndef NDEBUG +#define DLOG_IF(severity, condition) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATELESS, condition) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() +#else +#define DLOG_IF(severity, condition) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATELESS, false && (condition)) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() +#endif + +// LOG_EVERY_N +// +// An instance of `LOG_EVERY_N` increments a hidden zero-initialized counter +// every time execution passes through it and logs the specified message when +// the counter's value is a multiple of `n`, doing nothing otherwise. Each +// instance has its own counter. The counter's value can be logged by streaming +// the symbol `COUNTER`. `LOG_EVERY_N` is thread-safe. +// Example: +// +// LOG_EVERY_N(WARNING, 1000) << "Got a packet with a bad CRC (" << COUNTER +// << " total)"; +#define LOG_EVERY_N(severity, n) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATEFUL, true)(EveryN, n) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() + +// LOG_FIRST_N +// +// `LOG_FIRST_N` behaves like `LOG_EVERY_N` except that the specified message is +// logged when the counter's value is less than `n`. `LOG_FIRST_N` is +// thread-safe. +#define LOG_FIRST_N(severity, n) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATEFUL, true)(FirstN, n) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() + +// LOG_EVERY_POW_2 +// +// `LOG_EVERY_POW_2` behaves like `LOG_EVERY_N` except that the specified +// message is logged when the counter's value is a power of 2. +// `LOG_EVERY_POW_2` is thread-safe. +#define LOG_EVERY_POW_2(severity) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATEFUL, true)(EveryPow2) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() + +// LOG_EVERY_N_SEC +// +// An instance of `LOG_EVERY_N_SEC` uses a hidden state variable to log the +// specified message at most once every `n_seconds`. A hidden counter of +// executions (whether a message is logged or not) is also maintained and can be +// logged by streaming the symbol `COUNTER`. `LOG_EVERY_N_SEC` is thread-safe. +// Example: +// +// LOG_EVERY_N_SEC(INFO, 2.5) << "Got " << COUNTER << " cookies so far"; +#define LOG_EVERY_N_SEC(severity, n_seconds) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATEFUL, true)(EveryNSec, n_seconds) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() + +#define PLOG_EVERY_N(severity, n) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATEFUL, true)(EveryN, n) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() \ + .WithPerror() + +#define PLOG_FIRST_N(severity, n) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATEFUL, true)(FirstN, n) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() \ + .WithPerror() + +#define PLOG_EVERY_POW_2(severity) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATEFUL, true)(EveryPow2) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() \ + .WithPerror() + +#define PLOG_EVERY_N_SEC(severity, n_seconds) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATEFUL, true)(EveryNSec, n_seconds) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() \ + .WithPerror() + +#ifndef NDEBUG +#define DLOG_EVERY_N(severity, n) \ + ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, true) \ + (EveryN, n) ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() + +#define DLOG_FIRST_N(severity, n) \ + ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, true) \ + (FirstN, n) ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() + +#define DLOG_EVERY_POW_2(severity) \ + ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, true) \ + (EveryPow2) ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() + +#define DLOG_EVERY_N_SEC(severity, n_seconds) \ + ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, true) \ + (EveryNSec, n_seconds) ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() + +#else // def NDEBUG +#define DLOG_EVERY_N(severity, n) \ + ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, false) \ + (EveryN, n) ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() + +#define DLOG_FIRST_N(severity, n) \ + ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, false) \ + (FirstN, n) ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() + +#define DLOG_EVERY_POW_2(severity) \ + ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, false) \ + (EveryPow2) ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() + +#define DLOG_EVERY_N_SEC(severity, n_seconds) \ + ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, false) \ + (EveryNSec, n_seconds) ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() +#endif // def NDEBUG + +#define VLOG_EVERY_N(verbose_level, n) \ + for (int absl_logging_internal_verbose_level = (verbose_level), \ + absl_logging_internal_log_loop = 1; \ + absl_logging_internal_log_loop; absl_logging_internal_log_loop = 0) \ + ABSL_LOG_INTERNAL_CONDITION_INFO( \ + STATEFUL, VLOG_IS_ON(absl_logging_internal_verbose_level)) \ + (EveryN, n) ABSL_LOGGING_INTERNAL_LOG_INFO.InternalStream().WithVerbosity( \ + absl_logging_internal_verbose_level) + +#define VLOG_FIRST_N(verbose_level, n) \ + for (int absl_logging_internal_verbose_level = (verbose_level), \ + absl_logging_internal_log_loop = 1; \ + absl_logging_internal_log_loop; absl_logging_internal_log_loop = 0) \ + ABSL_LOG_INTERNAL_CONDITION_INFO( \ + STATEFUL, VLOG_IS_ON(absl_logging_internal_verbose_level)) \ + (FirstN, n) ABSL_LOGGING_INTERNAL_LOG_INFO.InternalStream().WithVerbosity( \ + absl_logging_internal_verbose_level) + +#define VLOG_EVERY_POW_2(verbose_level) \ + for (int absl_logging_internal_verbose_level = (verbose_level), \ + absl_logging_internal_log_loop = 1; \ + absl_logging_internal_log_loop; absl_logging_internal_log_loop = 0) \ + ABSL_LOG_INTERNAL_CONDITION_INFO( \ + STATEFUL, VLOG_IS_ON(absl_logging_internal_verbose_level)) \ + (EveryPow2) ABSL_LOGGING_INTERNAL_LOG_INFO.InternalStream().WithVerbosity( \ + absl_logging_internal_verbose_level) + +#define VLOG_EVERY_N_SEC(verbose_level, n_seconds) \ + for (int absl_logging_internal_verbose_level = (verbose_level), \ + absl_logging_internal_log_loop = 1; \ + absl_logging_internal_log_loop; absl_logging_internal_log_loop = 0) \ + ABSL_LOG_INTERNAL_CONDITION_INFO( \ + STATEFUL, VLOG_IS_ON(absl_logging_internal_verbose_level)) \ + (EveryNSec, n_seconds) ABSL_LOGGING_INTERNAL_LOG_INFO.InternalStream() \ + .WithVerbosity(absl_logging_internal_verbose_level) + +// `LOG_IF_EVERY_N` and friends behave as the corresponding `LOG_EVERY_N` +// but neither increment a counter nor log a message if condition is false (as +// `LOG_IF`). +// Example: +// +// LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << COUNTER +// << "th big cookie"; +#define LOG_IF_EVERY_N(severity, condition, n) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATEFUL, condition)(EveryN, n) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() + +#define LOG_IF_FIRST_N(severity, condition, n) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATEFUL, condition)(FirstN, n) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() + +#define LOG_IF_EVERY_POW_2(severity, condition) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATEFUL, condition)(EveryPow2) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() + +#define LOG_IF_EVERY_N_SEC(severity, condition, n_seconds) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATEFUL, condition)(EveryNSec, \ + n_seconds) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() + +#define PLOG_IF_EVERY_N(severity, condition, n) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATEFUL, condition)(EveryN, n) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() \ + .WithPerror() + +#define PLOG_IF_FIRST_N(severity, condition, n) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATEFUL, condition)(FirstN, n) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() \ + .WithPerror() + +#define PLOG_IF_EVERY_POW_2(severity, condition) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATEFUL, condition)(EveryPow2) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() \ + .WithPerror() + +#define PLOG_IF_EVERY_N_SEC(severity, condition, n_seconds) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATEFUL, condition)(EveryNSec, \ + n_seconds) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() \ + .WithPerror() + +#ifndef NDEBUG +#define DLOG_IF_EVERY_N(severity, condition, n) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATEFUL, condition)(EveryN, n) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() + +#define DLOG_IF_FIRST_N(severity, condition, n) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATEFUL, condition)(FirstN, n) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() + +#define DLOG_IF_EVERY_POW_2(severity, condition) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATEFUL, condition)(EveryPow2) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() + +#define DLOG_IF_EVERY_N_SEC(severity, condition, n_seconds) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATEFUL, condition)(EveryNSec, \ + n_seconds) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() + +#else // def NDEBUG +#define DLOG_IF_EVERY_N(severity, condition, n) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATEFUL, false && (condition))( \ + EveryN, n) ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() + +#define DLOG_IF_FIRST_N(severity, condition, n) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATEFUL, false && (condition))( \ + FirstN, n) ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() + +#define DLOG_IF_EVERY_POW_2(severity, condition) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATEFUL, false && (condition))( \ + EveryPow2) ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() + +#define DLOG_IF_EVERY_N_SEC(severity, condition, n_seconds) \ + ABSL_LOG_INTERNAL_CONDITION_##severity(STATEFUL, false && (condition))( \ + EveryNSec, n_seconds) \ + ABSL_LOGGING_INTERNAL_LOG_##severity.InternalStream() +#endif // def NDEBUG + +#endif // ABSL_LOG_LOG_H_ |