Abseil Common Libraries (C++) (grcp 依赖)
https://abseil.io/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
435 lines
20 KiB
435 lines
20 KiB
// 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, there are two |
|
// options: `AbslStringify()` or `std::ostream& operator<<(std::ostream&, ...)`. |
|
// It is recommended that users make their types loggable through |
|
// `AbslStringify()` as it is a universal stringification extension that also |
|
// enables `absl::StrFormat` and `absl::StrCat` support. If both |
|
// `AbslStringify()` and `std::ostream& operator<<(std::ostream&, ...)` are |
|
// defined, `AbslStringify()` will be used. |
|
// |
|
// To use the `AbslStringify()` API, define a friend function template in your |
|
// type's namespace with the following signature: |
|
// |
|
// template <typename Sink> |
|
// void AbslStringify(Sink& sink, const UserDefinedType& value); |
|
// |
|
// `Sink` has the same interface as `absl::FormatSink`, but without |
|
// `PutPaddedString()`. |
|
// |
|
// Example: |
|
// |
|
// struct Point { |
|
// template <typename Sink> |
|
// friend void AbslStringify(Sink& sink, const Point& p) { |
|
// absl::Format(&sink, "(%v, %v)", p.x, p.y); |
|
// } |
|
// |
|
// int x; |
|
// int y; |
|
// }; |
|
// |
|
// To use `std::ostream& operator<<(std::ostream&, ...)`, define |
|
// `std::ostream& operator<<(std::ostream&, ...)` in your type's namespace (for |
|
// ADL) just as you would to stream it to `std::cout`. |
|
// |
|
// Currently `AbslStringify()` ignores output manipulators but this is not |
|
// guaranteed behavior and may be subject to change in the future. If you would |
|
// like guaranteed behavior regarding output manipulators, please use |
|
// `std::ostream& operator<<(std::ostream&, ...)` to make custom types loggable |
|
// instead. |
|
// |
|
// 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"; |
|
#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 |
|
|
|
// `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_
|
|
|