You need to sign in or sign up before continuing.
Commit 92fdbfb3 by Gennadiy Rozental Committed by Copybara-Service

Release the Abseil Logging library

PiperOrigin-RevId: 470080638
Change-Id: I8d9ddfabc7704c383ed5a73abf0411f4c58a4bf7
parent 54022b0d
...@@ -22,6 +22,7 @@ add_subdirectory(debugging) ...@@ -22,6 +22,7 @@ add_subdirectory(debugging)
add_subdirectory(flags) add_subdirectory(flags)
add_subdirectory(functional) add_subdirectory(functional)
add_subdirectory(hash) add_subdirectory(hash)
add_subdirectory(log)
add_subdirectory(memory) add_subdirectory(memory)
add_subdirectory(meta) add_subdirectory(meta)
add_subdirectory(numeric) add_subdirectory(numeric)
......
...@@ -53,6 +53,7 @@ cc_library( ...@@ -53,6 +53,7 @@ cc_library(
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [ visibility = [
"//absl/flags:__pkg__", "//absl/flags:__pkg__",
"//absl/log:__pkg__",
], ],
deps = [ deps = [
":path_util", ":path_util",
......
// 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/check.h
// -----------------------------------------------------------------------------
//
// This header declares a family of `CHECK` macros.
//
// `CHECK` macros terminate the program with a fatal error if the specified
// condition is not true.
//
// Except for those whose names begin with `DCHECK`, these macros are not
// controlled by `NDEBUG` (cf. `assert`), so the check will be executed
// regardless of compilation mode. `CHECK` and friends are thus useful for
// confirming invariants in situations where continuing to run would be worse
// than terminating, e.g., due to risk of data corruption or security
// compromise. It is also more robust and portable to deliberately terminate
// at a particular place with a useful message and backtrace than to assume some
// ultimately unspecified and unreliable crashing behavior (such as a
// "segmentation fault").
#ifndef ABSL_LOG_CHECK_H_
#define ABSL_LOG_CHECK_H_
#include "absl/base/optimization.h"
#include "absl/log/internal/check_op.h" // IWYU pragma: export
#include "absl/log/internal/conditions.h" // IWYU pragma: export
#include "absl/log/internal/log_message.h" // IWYU pragma: export
#include "absl/log/internal/strip.h" // IWYU pragma: export
// CHECK()
//
// `CHECK` terminates the program with a fatal error if `condition` is not true.
//
// The message may include additional information such as stack traces, when
// available.
//
// Example:
//
// CHECK(!cheese.empty()) << "Out of Cheese";
//
// Might produce a message like:
//
// Check failed: !cheese.empty() Out of Cheese
#define CHECK(condition) \
ABSL_LOG_INTERNAL_CONDITION_FATAL(STATELESS, \
ABSL_PREDICT_FALSE(!(condition))) \
ABSL_LOG_INTERNAL_CHECK(#condition).InternalStream()
// QCHECK()
//
// `QCHECK` behaves like `CHECK` but does not print a full stack trace and does
// not run registered error handlers (as `QFATAL`). It is useful when the
// problem is definitely unrelated to program flow, e.g. when validating user
// input.
#define QCHECK(condition) \
ABSL_LOG_INTERNAL_CONDITION_QFATAL(STATELESS, \
ABSL_PREDICT_FALSE(!(condition))) \
ABSL_LOG_INTERNAL_QCHECK(#condition).InternalStream()
// PCHECK()
//
// `PCHECK` behaves like `CHECK` but appends a description of the current state
// of `errno` to the failure message.
//
// Example:
//
// int fd = open("/var/empty/missing", O_RDONLY);
// PCHECK(fd != -1) << "posix is difficult";
//
// Might produce a message like:
//
// Check failed: fd != -1 posix is difficult: No such file or directory [2]
#define PCHECK(condition) CHECK(condition).WithPerror()
// DCHECK()
//
// `DCHECK` behaves like `CHECK` in debug mode and does nothing otherwise (as
// `DLOG`). Unlike with `CHECK` (but as with `assert`), it is not safe to rely
// on evaluation of `condition`: when `NDEBUG` is enabled, DCHECK does not
// evaluate the condition.
#ifndef NDEBUG
#define DCHECK(condition) CHECK(condition)
#else
#define DCHECK(condition) CHECK(true || (condition))
#endif
// `CHECK_EQ` and friends are syntactic sugar for `CHECK(x == y)` that
// automatically output the expression being tested and the evaluated values on
// either side.
//
// Example:
//
// int x = 3, y = 5;
// CHECK_EQ(2 * x, y) << "oops!";
//
// Might produce a message like:
//
// Check failed: 2 * x == y (6 vs. 5) oops!
//
// The values must implement the appropriate comparison operator as well as
// `operator<<(std::ostream&, ...)`. Care is taken to ensure that each
// argument is evaluated exactly once, and that anything which is legal to pass
// as a function argument is legal here. In particular, the arguments may be
// temporary expressions which will end up being destroyed at the end of the
// statement,
//
// Example:
//
// CHECK_EQ(std::string("abc")[1], 'b');
//
// WARNING: Passing `NULL` as an argument to `CHECK_EQ` and similar macros does
// not compile. Use `nullptr` instead.
#define CHECK_EQ(val1, val2) \
ABSL_LOG_INTERNAL_CHECK_OP(Check_EQ, ==, val1, val2)
#define CHECK_NE(val1, val2) \
ABSL_LOG_INTERNAL_CHECK_OP(Check_NE, !=, val1, val2)
#define CHECK_LE(val1, val2) \
ABSL_LOG_INTERNAL_CHECK_OP(Check_LE, <=, val1, val2)
#define CHECK_LT(val1, val2) ABSL_LOG_INTERNAL_CHECK_OP(Check_LT, <, val1, val2)
#define CHECK_GE(val1, val2) \
ABSL_LOG_INTERNAL_CHECK_OP(Check_GE, >=, val1, val2)
#define CHECK_GT(val1, val2) ABSL_LOG_INTERNAL_CHECK_OP(Check_GT, >, val1, val2)
#define QCHECK_EQ(val1, val2) \
ABSL_LOG_INTERNAL_QCHECK_OP(Check_EQ, ==, val1, val2)
#define QCHECK_NE(val1, val2) \
ABSL_LOG_INTERNAL_QCHECK_OP(Check_NE, !=, val1, val2)
#define QCHECK_LE(val1, val2) \
ABSL_LOG_INTERNAL_QCHECK_OP(Check_LE, <=, val1, val2)
#define QCHECK_LT(val1, val2) \
ABSL_LOG_INTERNAL_QCHECK_OP(Check_LT, <, val1, val2)
#define QCHECK_GE(val1, val2) \
ABSL_LOG_INTERNAL_QCHECK_OP(Check_GE, >=, val1, val2)
#define QCHECK_GT(val1, val2) \
ABSL_LOG_INTERNAL_QCHECK_OP(Check_GT, >, val1, val2)
#ifndef NDEBUG
#define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2)
#define DCHECK_NE(val1, val2) CHECK_NE(val1, val2)
#define DCHECK_LE(val1, val2) CHECK_LE(val1, val2)
#define DCHECK_LT(val1, val2) CHECK_LT(val1, val2)
#define DCHECK_GE(val1, val2) CHECK_GE(val1, val2)
#define DCHECK_GT(val1, val2) CHECK_GT(val1, val2)
#else // ndef NDEBUG
#define DCHECK_EQ(val1, val2) ABSL_LOG_INTERNAL_DCHECK_NOP(val1, val2)
#define DCHECK_NE(val1, val2) ABSL_LOG_INTERNAL_DCHECK_NOP(val1, val2)
#define DCHECK_LE(val1, val2) ABSL_LOG_INTERNAL_DCHECK_NOP(val1, val2)
#define DCHECK_LT(val1, val2) ABSL_LOG_INTERNAL_DCHECK_NOP(val1, val2)
#define DCHECK_GE(val1, val2) ABSL_LOG_INTERNAL_DCHECK_NOP(val1, val2)
#define DCHECK_GT(val1, val2) ABSL_LOG_INTERNAL_DCHECK_NOP(val1, val2)
#endif // def NDEBUG
// `CHECK_OK` and friends validate that the provided `absl::Status` or
// `absl::StatusOr<T>` is OK. If it isn't, they print a failure message that
// includes the actual status.
//
// As with all `DCHECK` variants, `DCHECK_OK` has no effect (not even
// evaluating its argument) if `NDEBUG` is enabled.
//
// Example:
//
// CHECK_OK(FunctionReturnsStatus(x, y, z)) << "oops!";
//
// Might produce a message like:
//
// Check failed: FunctionReturnsStatus(x, y, z) is OK (ABORTED: timeout) oops!
#define CHECK_OK(status) ABSL_LOG_INTERNAL_CHECK_OK(status)
#define QCHECK_OK(status) ABSL_LOG_INTERNAL_QCHECK_OK(status)
#ifndef NDEBUG
#define DCHECK_OK(status) ABSL_LOG_INTERNAL_CHECK_OK(status)
#else
#define DCHECK_OK(status) ABSL_LOG_INTERNAL_DCHECK_NOP(status, nullptr)
#endif
// `CHECK_STREQ` and friends provide `CHECK_EQ` functionality for C strings,
// i.e., nul-terminated char arrays. The `CASE` versions are case-insensitive.
//
// Example:
//
// CHECK_STREQ(argv[0], "./skynet");
//
// Note that both arguments may be temporary strings which are destroyed by the
// compiler at the end of the current full expression.
//
// Example:
//
// CHECK_STREQ(Foo().c_str(), Bar().c_str());
#define CHECK_STREQ(s1, s2) \
ABSL_LOG_INTERNAL_CHECK_STROP(strcmp, ==, true, s1, s2)
#define CHECK_STRNE(s1, s2) \
ABSL_LOG_INTERNAL_CHECK_STROP(strcmp, !=, false, s1, s2)
#define CHECK_STRCASEEQ(s1, s2) \
ABSL_LOG_INTERNAL_CHECK_STROP(strcasecmp, ==, true, s1, s2)
#define CHECK_STRCASENE(s1, s2) \
ABSL_LOG_INTERNAL_CHECK_STROP(strcasecmp, !=, false, s1, s2)
#define QCHECK_STREQ(s1, s2) \
ABSL_LOG_INTERNAL_QCHECK_STROP(strcmp, ==, true, s1, s2)
#define QCHECK_STRNE(s1, s2) \
ABSL_LOG_INTERNAL_QCHECK_STROP(strcmp, !=, false, s1, s2)
#define QCHECK_STRCASEEQ(s1, s2) \
ABSL_LOG_INTERNAL_QCHECK_STROP(strcasecmp, ==, true, s1, s2)
#define QCHECK_STRCASENE(s1, s2) \
ABSL_LOG_INTERNAL_QCHECK_STROP(strcasecmp, !=, false, s1, s2)
#ifndef NDEBUG
#define DCHECK_STREQ(s1, s2) CHECK_STREQ(s1, s2)
#define DCHECK_STRCASEEQ(s1, s2) CHECK_STRCASEEQ(s1, s2)
#define DCHECK_STRNE(s1, s2) CHECK_STRNE(s1, s2)
#define DCHECK_STRCASENE(s1, s2) CHECK_STRCASENE(s1, s2)
#else // ndef NDEBUG
#define DCHECK_STREQ(s1, s2) ABSL_LOG_INTERNAL_DCHECK_NOP(s1, s2)
#define DCHECK_STRCASEEQ(s1, s2) ABSL_LOG_INTERNAL_DCHECK_NOP(s1, s2)
#define DCHECK_STRNE(s1, s2) ABSL_LOG_INTERNAL_DCHECK_NOP(s1, s2)
#define DCHECK_STRCASENE(s1, s2) ABSL_LOG_INTERNAL_DCHECK_NOP(s1, s2)
#endif // def NDEBUG
#endif // ABSL_LOG_CHECK_H_
// 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.
#include "absl/log/die_if_null.h"
#include "absl/base/config.h"
#include "absl/log/log.h"
#include "absl/strings/str_cat.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {
void DieBecauseNull(const char* file, int line, const char* exprtext) {
LOG(FATAL).AtLocation(file, line)
<< absl::StrCat("Check failed: '", exprtext, "' Must be non-null");
}
} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl
// 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/die_if_null.h
// -----------------------------------------------------------------------------
//
// This header declares macro `ABSL_DIE_IF_NULL`.
#ifndef ABSL_LOG_DIE_IF_NULL_H_
#define ABSL_LOG_DIE_IF_NULL_H_
#include <stdint.h>
#include <utility>
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/optimization.h"
// ABSL_DIE_IF_NULL()
//
// `ABSL_DIE_IF_NULL` behaves as `CHECK_NE` against `nullptr` but *also*
// "returns" its argument. It is useful in initializers where statements (like
// `CHECK_NE`) can't be used. Outside initializers, prefer `CHECK` or
// `CHECK_NE`. `ABSL_DIE_IF_NULL` works for both raw pointers and (compatible)
// smart pointers including `std::unique_ptr` and `std::shared_ptr`; more
// generally, it works for any type that can be compared to nullptr_t. For
// types that aren't raw pointers, `ABSL_DIE_IF_NULL` returns a reference to
// its argument, preserving the value category. Example:
//
// Foo() : bar_(ABSL_DIE_IF_NULL(MethodReturningUniquePtr())) {}
//
// Use `CHECK(ptr)` or `CHECK(ptr != nullptr)` if the returned pointer is
// unused.
#define ABSL_DIE_IF_NULL(val) \
::absl::log_internal::DieIfNull(__FILE__, __LINE__, #val, (val))
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {
// Crashes the process after logging `exprtext` annotated at the `file` and
// `line` location. Called when `ABSL_DIE_IF_NULL` fails. Calling this function
// generates less code than its implementation would if inlined, for a slight
// code size reduction each time `ABSL_DIE_IF_NULL` is called.
ABSL_ATTRIBUTE_NORETURN ABSL_ATTRIBUTE_NOINLINE void DieBecauseNull(
const char* file, int line, const char* exprtext);
// Helper for `ABSL_DIE_IF_NULL`.
template <typename T>
ABSL_MUST_USE_RESULT T DieIfNull(const char* file, int line,
const char* exprtext, T&& t) {
if (ABSL_PREDICT_FALSE(t == nullptr)) {
// Call a non-inline helper function for a small code size improvement.
DieBecauseNull(file, line, exprtext);
}
return std::forward<T>(t);
}
} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_LOG_DIE_IF_NULL_H_
//
// 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.
#include "absl/log/die_if_null.h"
#include <stdint.h>
#include <memory>
#include <utility>
#include "gtest/gtest.h"
#include "absl/base/attributes.h"
#include "absl/log/internal/test_helpers.h"
namespace {
auto* test_env ABSL_ATTRIBUTE_UNUSED = ::testing::AddGlobalTestEnvironment(
new absl::log_internal::LogTestEnvironment);
// TODO(b/69907837): Revisit these tests with the goal of making them less
// convoluted.
TEST(AbslDieIfNull, Simple) {
int64_t t;
void* ptr = static_cast<void*>(&t);
void* ref = ABSL_DIE_IF_NULL(ptr);
ASSERT_EQ(ptr, ref);
char* t_as_char;
t_as_char = ABSL_DIE_IF_NULL(reinterpret_cast<char*>(&t));
(void)t_as_char;
unsigned char* t_as_uchar;
t_as_uchar = ABSL_DIE_IF_NULL(reinterpret_cast<unsigned char*>(&t));
(void)t_as_uchar;
int* t_as_int;
t_as_int = ABSL_DIE_IF_NULL(reinterpret_cast<int*>(&t));
(void)t_as_int;
int64_t* t_as_int64_t;
t_as_int64_t = ABSL_DIE_IF_NULL(reinterpret_cast<int64_t*>(&t));
(void)t_as_int64_t;
std::unique_ptr<int64_t> sptr(new int64_t);
EXPECT_EQ(sptr.get(), ABSL_DIE_IF_NULL(sptr).get());
ABSL_DIE_IF_NULL(sptr).reset();
int64_t* int_ptr = new int64_t();
EXPECT_EQ(int_ptr, ABSL_DIE_IF_NULL(std::unique_ptr<int64_t>(int_ptr)).get());
}
#if GTEST_HAS_DEATH_TEST
TEST(DeathCheckAbslDieIfNull, Simple) {
void* ptr;
ASSERT_DEATH({ ptr = ABSL_DIE_IF_NULL(nullptr); }, "");
(void)ptr;
std::unique_ptr<int64_t> sptr;
ASSERT_DEATH(ptr = ABSL_DIE_IF_NULL(sptr).get(), "");
}
#endif
// Ensures that ABSL_DIE_IF_NULL works with C++11's std::unique_ptr and
// std::shared_ptr.
TEST(AbslDieIfNull, DoesNotCompareSmartPointerToNULL) {
std::unique_ptr<int> up(new int);
EXPECT_EQ(&up, &ABSL_DIE_IF_NULL(up));
ABSL_DIE_IF_NULL(up).reset();
std::shared_ptr<int> sp(new int);
EXPECT_EQ(&sp, &ABSL_DIE_IF_NULL(sp));
ABSL_DIE_IF_NULL(sp).reset();
}
// Verifies that ABSL_DIE_IF_NULL returns an rvalue reference if its argument is
// an rvalue reference.
TEST(AbslDieIfNull, PreservesRValues) {
int64_t* ptr = new int64_t();
auto uptr = ABSL_DIE_IF_NULL(std::unique_ptr<int64_t>(ptr));
EXPECT_EQ(ptr, uptr.get());
}
// Verifies that ABSL_DIE_IF_NULL returns an lvalue if its argument is an
// lvalue.
TEST(AbslDieIfNull, PreservesLValues) {
int64_t array[2] = {0};
int64_t* a = array + 0;
int64_t* b = array + 1;
using std::swap;
swap(ABSL_DIE_IF_NULL(a), ABSL_DIE_IF_NULL(b));
EXPECT_EQ(array + 1, a);
EXPECT_EQ(array + 0, b);
}
} // namespace
//
// 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.
#include "absl/log/internal/flags.h"
#include <stddef.h>
#include <algorithm>
#include <cstdlib>
#include <string>
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/log_severity.h"
#include "absl/flags/flag.h"
#include "absl/flags/marshalling.h"
#include "absl/log/globals.h"
#include "absl/log/internal/config.h"
#include "absl/strings/numbers.h"
#include "absl/strings/string_view.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {
namespace {
void SyncLoggingFlags() {
absl::SetFlag(&FLAGS_minloglevel, static_cast<int>(absl::MinLogLevel()));
absl::SetFlag(&FLAGS_log_prefix, absl::ShouldPrependLogPrefix());
}
bool RegisterSyncLoggingFlags() {
log_internal::SetLoggingGlobalsListener(&SyncLoggingFlags);
return true;
}
ABSL_ATTRIBUTE_UNUSED const bool unused = RegisterSyncLoggingFlags();
template <typename T>
T GetFromEnv(const char* varname, T dflt) {
const char* val = ::getenv(varname);
if (val != nullptr) {
std::string err;
ABSL_INTERNAL_CHECK(absl::ParseFlag(val, &dflt, &err), err.c_str());
}
return dflt;
}
constexpr absl::LogSeverityAtLeast StderrThresholdDefault() {
return absl::LogSeverityAtLeast::kError;
}
} // namespace
} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl
ABSL_FLAG(int, stderrthreshold,
static_cast<int>(absl::log_internal::StderrThresholdDefault()),
"Log messages at or above this threshold level are copied to stderr.")
.OnUpdate([] {
absl::log_internal::RawSetStderrThreshold(
static_cast<absl::LogSeverityAtLeast>(
absl::GetFlag(FLAGS_stderrthreshold)));
});
ABSL_FLAG(int, minloglevel, static_cast<int>(absl::LogSeverityAtLeast::kInfo),
"Messages logged at a lower level than this don't actually "
"get logged anywhere")
.OnUpdate([] {
absl::log_internal::RawSetMinLogLevel(
static_cast<absl::LogSeverityAtLeast>(
absl::GetFlag(FLAGS_minloglevel)));
});
ABSL_FLAG(std::string, log_backtrace_at, "",
"Emit a backtrace when logging at file:linenum.")
.OnUpdate([] {
const std::string log_backtrace_at =
absl::GetFlag(FLAGS_log_backtrace_at);
if (log_backtrace_at.empty()) return;
const size_t last_colon = log_backtrace_at.rfind(':');
if (last_colon == log_backtrace_at.npos) return;
const absl::string_view file =
absl::string_view(log_backtrace_at).substr(0, last_colon);
int line;
if (absl::SimpleAtoi(
absl::string_view(log_backtrace_at).substr(last_colon + 1),
&line)) {
absl::SetLogBacktraceLocation(file, line);
}
});
ABSL_FLAG(bool, log_prefix, true,
"Prepend the log prefix to the start of each log line")
.OnUpdate([] {
absl::log_internal::RawEnableLogPrefix(absl::GetFlag(FLAGS_log_prefix));
});
// 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/flags.h
// -----------------------------------------------------------------------------
//
#ifndef ABSL_LOG_FLAGS_H_
#define ABSL_LOG_FLAGS_H_
// The Abseil Logging library supports the following command line flags to
// configure logging behavior at runtime:
//
// --stderrthreshold=<value>
// Log messages at or above this threshold level are copied to stderr.
//
// --minloglevel=<value>
// Messages logged at a lower level than this are discarded and don't actually
// get logged anywhere.
//
// --log_backtrace_at=<file:linenum>
// Emit a backtrace (stack trace) when logging at file:linenum.
//
// To use these commandline flags, the //absl/log:flags library must be
// explicitly linked, and absl::ParseCommandLine() must be called before the
// call to absl::InitializeLog().
//
// To configure the Log library programmatically, use the interfaces defined in
// absl/log/globals.h.
#endif // ABSL_LOG_FLAGS_H_
//
// 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.
#include "absl/log/internal/flags.h"
#include <string>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/base/attributes.h"
#include "absl/base/log_severity.h"
#include "absl/flags/flag.h"
#include "absl/flags/reflection.h"
#include "absl/log/globals.h"
#include "absl/log/internal/test_helpers.h"
#include "absl/log/internal/test_matchers.h"
#include "absl/log/log.h"
#include "absl/log/scoped_mock_log.h"
#include "absl/strings/str_cat.h"
namespace {
using ::absl::log_internal::TextMessage;
using ::testing::HasSubstr;
using ::testing::Not;
auto* test_env ABSL_ATTRIBUTE_UNUSED = ::testing::AddGlobalTestEnvironment(
new absl::log_internal::LogTestEnvironment);
constexpr static absl::LogSeverityAtLeast DefaultStderrThreshold() {
return absl::LogSeverityAtLeast::kError;
}
class LogFlagsTest : public ::testing::Test {
protected:
absl::FlagSaver flag_saver_;
};
TEST_F(LogFlagsTest, StderrKnobsDefault) {
EXPECT_EQ(absl::StderrThreshold(), DefaultStderrThreshold());
}
TEST_F(LogFlagsTest, SetStderrThreshold) {
absl::SetFlag(&FLAGS_stderrthreshold,
static_cast<int>(absl::LogSeverityAtLeast::kInfo));
EXPECT_EQ(absl::StderrThreshold(), absl::LogSeverityAtLeast::kInfo);
absl::SetFlag(&FLAGS_stderrthreshold,
static_cast<int>(absl::LogSeverityAtLeast::kError));
EXPECT_EQ(absl::StderrThreshold(), absl::LogSeverityAtLeast::kError);
}
TEST_F(LogFlagsTest, SetMinLogLevel) {
absl::SetFlag(&FLAGS_minloglevel,
static_cast<int>(absl::LogSeverityAtLeast::kError));
EXPECT_EQ(absl::MinLogLevel(), absl::LogSeverityAtLeast::kError);
absl::log_internal::ScopedMinLogLevel scoped_min_log_level(
absl::LogSeverityAtLeast::kWarning);
EXPECT_EQ(absl::GetFlag(FLAGS_minloglevel),
static_cast<int>(absl::LogSeverityAtLeast::kWarning));
}
TEST_F(LogFlagsTest, PrependLogPrefix) {
absl::SetFlag(&FLAGS_log_prefix, false);
EXPECT_EQ(absl::ShouldPrependLogPrefix(), false);
absl::EnableLogPrefix(true);
EXPECT_EQ(absl::GetFlag(FLAGS_log_prefix), true);
}
TEST_F(LogFlagsTest, EmptyBacktraceAtFlag) {
absl::SetMinLogLevel(absl::LogSeverityAtLeast::kInfo);
absl::SetFlag(&FLAGS_log_backtrace_at, "");
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
EXPECT_CALL(test_sink, Send(TextMessage(Not(HasSubstr("(stacktrace:")))));
test_sink.StartCapturingLogs();
LOG(INFO) << "hello world";
}
TEST_F(LogFlagsTest, BacktraceAtNonsense) {
absl::SetMinLogLevel(absl::LogSeverityAtLeast::kInfo);
absl::SetFlag(&FLAGS_log_backtrace_at, "gibberish");
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
EXPECT_CALL(test_sink, Send(TextMessage(Not(HasSubstr("(stacktrace:")))));
test_sink.StartCapturingLogs();
LOG(INFO) << "hello world";
}
TEST_F(LogFlagsTest, BacktraceAtWrongFile) {
absl::SetMinLogLevel(absl::LogSeverityAtLeast::kInfo);
const int log_line = __LINE__ + 1;
auto do_log = [] { LOG(INFO) << "hello world"; };
absl::SetFlag(&FLAGS_log_backtrace_at,
absl::StrCat("some_other_file.cc:", log_line));
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
EXPECT_CALL(test_sink, Send(TextMessage(Not(HasSubstr("(stacktrace:")))));
test_sink.StartCapturingLogs();
do_log();
}
TEST_F(LogFlagsTest, BacktraceAtWrongLine) {
absl::SetMinLogLevel(absl::LogSeverityAtLeast::kInfo);
const int log_line = __LINE__ + 1;
auto do_log = [] { LOG(INFO) << "hello world"; };
absl::SetFlag(&FLAGS_log_backtrace_at,
absl::StrCat("flags_test.cc:", log_line + 1));
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
EXPECT_CALL(test_sink, Send(TextMessage(Not(HasSubstr("(stacktrace:")))));
test_sink.StartCapturingLogs();
do_log();
}
TEST_F(LogFlagsTest, BacktraceAtWholeFilename) {
absl::SetMinLogLevel(absl::LogSeverityAtLeast::kInfo);
const int log_line = __LINE__ + 1;
auto do_log = [] { LOG(INFO) << "hello world"; };
absl::SetFlag(&FLAGS_log_backtrace_at, absl::StrCat(__FILE__, ":", log_line));
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
EXPECT_CALL(test_sink, Send(TextMessage(Not(HasSubstr("(stacktrace:")))));
test_sink.StartCapturingLogs();
do_log();
}
TEST_F(LogFlagsTest, BacktraceAtNonmatchingSuffix) {
absl::SetMinLogLevel(absl::LogSeverityAtLeast::kInfo);
const int log_line = __LINE__ + 1;
auto do_log = [] { LOG(INFO) << "hello world"; };
absl::SetFlag(&FLAGS_log_backtrace_at,
absl::StrCat("flags_test.cc:", log_line, "gibberish"));
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
EXPECT_CALL(test_sink, Send(TextMessage(Not(HasSubstr("(stacktrace:")))));
test_sink.StartCapturingLogs();
do_log();
}
TEST_F(LogFlagsTest, LogsBacktrace) {
absl::SetMinLogLevel(absl::LogSeverityAtLeast::kInfo);
const int log_line = __LINE__ + 1;
auto do_log = [] { LOG(INFO) << "hello world"; };
absl::SetFlag(&FLAGS_log_backtrace_at,
absl::StrCat("flags_test.cc:", log_line));
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
EXPECT_CALL(test_sink, Send(TextMessage(HasSubstr("(stacktrace:"))));
test_sink.StartCapturingLogs();
do_log();
}
} // namespace
// 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.
#include "absl/log/globals.h"
#include <stddef.h>
#include <stdint.h>
#include <atomic>
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/internal/atomic_hook.h"
#include "absl/base/log_severity.h"
#include "absl/hash/hash.h"
#include "absl/strings/string_view.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace {
// These atomics represent logging library configuration.
// Integer types are used instead of absl::LogSeverity to ensure that a
// lock-free std::atomic is used when possible.
ABSL_CONST_INIT std::atomic<int> min_log_level{
static_cast<int>(absl::LogSeverityAtLeast::kInfo)};
ABSL_CONST_INIT std::atomic<int> stderrthreshold{
static_cast<int>(absl::LogSeverityAtLeast::kError)};
// We evaluate this value as a hash comparison to avoid having to
// hold a mutex or make a copy (to access the value of a string-typed flag) in
// very hot codepath.
ABSL_CONST_INIT std::atomic<size_t> log_backtrace_at_hash{0};
ABSL_CONST_INIT std::atomic<bool> prepend_log_prefix{true};
ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
absl::base_internal::AtomicHook<log_internal::LoggingGlobalsListener>
logging_globals_listener;
size_t HashSiteForLogBacktraceAt(absl::string_view file, int line) {
return absl::HashOf(file, line);
}
void TriggerLoggingGlobalsListener() {
auto* listener = logging_globals_listener.Load();
if (listener != nullptr) listener();
}
} // namespace
namespace log_internal {
void RawSetMinLogLevel(absl::LogSeverityAtLeast severity) {
min_log_level.store(static_cast<int>(severity), std::memory_order_release);
}
void RawSetStderrThreshold(absl::LogSeverityAtLeast severity) {
stderrthreshold.store(static_cast<int>(severity), std::memory_order_release);
}
void RawEnableLogPrefix(bool on_off) {
prepend_log_prefix.store(on_off, std::memory_order_release);
}
void SetLoggingGlobalsListener(LoggingGlobalsListener l) {
logging_globals_listener.Store(l);
}
} // namespace log_internal
absl::LogSeverityAtLeast MinLogLevel() {
return static_cast<absl::LogSeverityAtLeast>(
min_log_level.load(std::memory_order_acquire));
}
void SetMinLogLevel(absl::LogSeverityAtLeast severity) {
log_internal::RawSetMinLogLevel(severity);
TriggerLoggingGlobalsListener();
}
namespace log_internal {
ScopedMinLogLevel::ScopedMinLogLevel(absl::LogSeverityAtLeast severity)
: saved_severity_(absl::MinLogLevel()) {
absl::SetMinLogLevel(severity);
}
ScopedMinLogLevel::~ScopedMinLogLevel() {
absl::SetMinLogLevel(saved_severity_);
}
} // namespace log_internal
absl::LogSeverityAtLeast StderrThreshold() {
return static_cast<absl::LogSeverityAtLeast>(
stderrthreshold.load(std::memory_order_acquire));
}
void SetStderrThreshold(absl::LogSeverityAtLeast severity) {
log_internal::RawSetStderrThreshold(severity);
TriggerLoggingGlobalsListener();
}
ScopedStderrThreshold::ScopedStderrThreshold(absl::LogSeverityAtLeast severity)
: saved_severity_(absl::StderrThreshold()) {
absl::SetStderrThreshold(severity);
}
ScopedStderrThreshold::~ScopedStderrThreshold() {
absl::SetStderrThreshold(saved_severity_);
}
namespace log_internal {
bool ShouldLogBacktraceAt(absl::string_view file, int line) {
const size_t flag_hash =
log_backtrace_at_hash.load(std::memory_order_acquire);
return flag_hash != 0 && flag_hash == HashSiteForLogBacktraceAt(file, line);
}
} // namespace log_internal
void SetLogBacktraceLocation(absl::string_view file, int line) {
log_backtrace_at_hash.store(HashSiteForLogBacktraceAt(file, line),
std::memory_order_release);
}
bool ShouldPrependLogPrefix() {
return prepend_log_prefix.load(std::memory_order_acquire);
}
void EnableLogPrefix(bool on_off) {
log_internal::RawEnableLogPrefix(on_off);
TriggerLoggingGlobalsListener();
}
ABSL_NAMESPACE_END
} // namespace absl
// 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/globals.h
// -----------------------------------------------------------------------------
//
// This header declares global logging library configuration knobs.
#ifndef ABSL_LOG_GLOBALS_H_
#define ABSL_LOG_GLOBALS_H_
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/log_severity.h"
#include "absl/strings/string_view.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
//------------------------------------------------------------------------------
// Minimum Log Level
//------------------------------------------------------------------------------
//
// Messages logged at or above this severity are directed to all registered log
// sinks or skipped otherwise. This parameter can also be modified using
// command line flag --minloglevel.
// See absl/base/log_severity.h for descriptions of severity levels.
// MinLogLevel()
//
// Returns the value of the Minimum Log Level parameter.
// This function is async-signal-safe.
ABSL_MUST_USE_RESULT absl::LogSeverityAtLeast MinLogLevel();
// SetMinLogLevel()
//
// Updates the value of Minimum Log Level parameter.
// This function is async-signal-safe.
void SetMinLogLevel(absl::LogSeverityAtLeast severity);
namespace log_internal {
// ScopedMinLogLevel
//
// RAII type used to temporarily update the Min Log Level parameter.
class ScopedMinLogLevel final {
public:
explicit ScopedMinLogLevel(absl::LogSeverityAtLeast severity);
ScopedMinLogLevel(const ScopedMinLogLevel&) = delete;
ScopedMinLogLevel& operator=(const ScopedMinLogLevel&) = delete;
~ScopedMinLogLevel();
private:
absl::LogSeverityAtLeast saved_severity_;
};
} // namespace log_internal
//------------------------------------------------------------------------------
// Stderr Threshold
//------------------------------------------------------------------------------
//
// Messages logged at or above this level are directed to stderr in
// addition to other registered log sinks. This parameter can also be modified
// using command line flag --stderrthreshold.
// See absl/base/log_severity.h for descriptions of severity levels.
// StderrThreshold()
//
// Returns the value of the Stderr Threshold parameter.
// This function is async-signal-safe.
ABSL_MUST_USE_RESULT absl::LogSeverityAtLeast StderrThreshold();
// SetStderrThreshold()
//
// Updates the Stderr Threshold parameter.
// This function is async-signal-safe.
void SetStderrThreshold(absl::LogSeverityAtLeast severity);
inline void SetStderrThreshold(absl::LogSeverity severity) {
absl::SetStderrThreshold(static_cast<absl::LogSeverityAtLeast>(severity));
}
// ScopedStderrThreshold
//
// RAII type used to temporarily update the Stderr Threshold parameter.
class ScopedStderrThreshold final {
public:
explicit ScopedStderrThreshold(absl::LogSeverityAtLeast severity);
ScopedStderrThreshold(const ScopedStderrThreshold&) = delete;
ScopedStderrThreshold& operator=(const ScopedStderrThreshold&) = delete;
~ScopedStderrThreshold();
private:
absl::LogSeverityAtLeast saved_severity_;
};
//------------------------------------------------------------------------------
// Log Backtrace At
//------------------------------------------------------------------------------
//
// Users can request backtrace to be logged at specific locations, specified
// by file and line number.
// ShouldLogBacktraceAt()
//
// Returns true if we should log a backtrace at the specified location.
namespace log_internal {
ABSL_MUST_USE_RESULT bool ShouldLogBacktraceAt(absl::string_view file,
int line);
} // namespace log_internal
// SetLogBacktraceLocation()
//
// Sets the location the backtrace should be logged at.
void SetLogBacktraceLocation(absl::string_view file, int line);
//------------------------------------------------------------------------------
// Prepend Log Prefix
//------------------------------------------------------------------------------
//
// This option tells the logging library that every logged message
// should include the prefix (severity, date, time, PID, etc.)
// ShouldPrependLogPrefix()
//
// Returns the value of the Prepend Log Prefix option.
// This function is async-signal-safe.
ABSL_MUST_USE_RESULT bool ShouldPrependLogPrefix();
// EnableLogPrefix()
//
// Updates the value of the Prepend Log Prefix option.
// This function is async-signal-safe.
void EnableLogPrefix(bool on_off);
namespace log_internal {
using LoggingGlobalsListener = void (*)();
void SetLoggingGlobalsListener(LoggingGlobalsListener l);
// Internal implementation for the setter routines. These are used
// to break circular dependencies between flags and globals. Each "Raw"
// routine corresponds to the non-"Raw" counterpart and used to set the
// configuration parameter directly without calling back to the listener.
void RawSetMinLogLevel(absl::LogSeverityAtLeast severity);
void RawSetStderrThreshold(absl::LogSeverityAtLeast severity);
void RawEnableLogPrefix(bool on_off);
} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_LOG_GLOBALS_H_
//
// 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.
#include "absl/log/globals.h"
#include <string>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/base/attributes.h"
#include "absl/base/log_severity.h"
#include "absl/log/internal/globals.h"
#include "absl/log/internal/test_helpers.h"
#include "absl/log/log.h"
#include "absl/log/scoped_mock_log.h"
namespace {
auto* test_env ABSL_ATTRIBUTE_UNUSED = ::testing::AddGlobalTestEnvironment(
new absl::log_internal::LogTestEnvironment);
constexpr static absl::LogSeverityAtLeast DefaultMinLogLevel() {
return absl::LogSeverityAtLeast::kInfo;
}
constexpr static absl::LogSeverityAtLeast DefaultStderrThreshold() {
return absl::LogSeverityAtLeast::kError;
}
TEST(TestGlobals, MinLogLevel) {
EXPECT_EQ(absl::MinLogLevel(), DefaultMinLogLevel());
absl::SetMinLogLevel(absl::LogSeverityAtLeast::kError);
EXPECT_EQ(absl::MinLogLevel(), absl::LogSeverityAtLeast::kError);
absl::SetMinLogLevel(DefaultMinLogLevel());
}
TEST(TestGlobals, ScopedMinLogLevel) {
EXPECT_EQ(absl::MinLogLevel(), DefaultMinLogLevel());
{
absl::log_internal::ScopedMinLogLevel scoped_stderr_threshold(
absl::LogSeverityAtLeast::kError);
EXPECT_EQ(absl::MinLogLevel(), absl::LogSeverityAtLeast::kError);
}
EXPECT_EQ(absl::MinLogLevel(), DefaultMinLogLevel());
}
TEST(TestGlobals, StderrThreshold) {
EXPECT_EQ(absl::StderrThreshold(), DefaultStderrThreshold());
absl::SetStderrThreshold(absl::LogSeverityAtLeast::kError);
EXPECT_EQ(absl::StderrThreshold(), absl::LogSeverityAtLeast::kError);
absl::SetStderrThreshold(DefaultStderrThreshold());
}
TEST(TestGlobals, ScopedStderrThreshold) {
EXPECT_EQ(absl::StderrThreshold(), DefaultStderrThreshold());
{
absl::ScopedStderrThreshold scoped_stderr_threshold(
absl::LogSeverityAtLeast::kError);
EXPECT_EQ(absl::StderrThreshold(), absl::LogSeverityAtLeast::kError);
}
EXPECT_EQ(absl::StderrThreshold(), DefaultStderrThreshold());
}
TEST(TestGlobals, LogBacktraceAt) {
EXPECT_FALSE(absl::log_internal::ShouldLogBacktraceAt("some_file.cc", 111));
absl::SetLogBacktraceLocation("some_file.cc", 111);
EXPECT_TRUE(absl::log_internal::ShouldLogBacktraceAt("some_file.cc", 111));
EXPECT_FALSE(
absl::log_internal::ShouldLogBacktraceAt("another_file.cc", 222));
}
TEST(TestGlobals, LogPrefix) {
EXPECT_TRUE(absl::ShouldPrependLogPrefix());
absl::EnableLogPrefix(false);
EXPECT_FALSE(absl::ShouldPrependLogPrefix());
absl::EnableLogPrefix(true);
EXPECT_TRUE(absl::ShouldPrependLogPrefix());
}
} // namespace
// 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.
#include "absl/log/initialize.h"
#include "absl/base/config.h"
#include "absl/log/internal/globals.h"
#include "absl/time/time.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
void InitializeLog() {
// This comes first since it is used by RAW_LOG.
absl::log_internal::SetTimeZone(absl::LocalTimeZone());
// Note that initialization is complete, so logs can now be sent to their
// proper destinations rather than stderr.
log_internal::SetInitialized();
}
ABSL_NAMESPACE_END
} // namespace absl
// 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/initialize.h
// -----------------------------------------------------------------------------
//
// This header declares the Abseil Log initialization routine InitializeLog().
#ifndef ABSL_LOG_INITIALIZE_H_
#define ABSL_LOG_INITIALIZE_H_
#include "absl/base/config.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
// InitializeLog()
//
// Initializes the Abseil logging library.
//
// Before this function is called, all log messages are directed only to stderr.
// After initialization is finished, log messages are directed to all registered
// `LogSink`s.
//
// It is an error to call this function twice.
//
// There is no corresponding function to shut down the logging library.
void InitializeLog();
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_LOG_INITIALIZE_H_
#
# 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.
#
load(
"//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
"ABSL_DEFAULT_LINKOPTS",
"ABSL_TEST_COPTS",
)
package(default_visibility = [
"//absl/log:__pkg__",
])
licenses(["notice"])
cc_library(
name = "check_op",
srcs = ["check_op.cc"],
hdrs = ["check_op.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
"//absl/log:__pkg__",
],
deps = [
":nullguard",
":nullstream",
":strip",
"//absl/base:config",
"//absl/base:core_headers",
"//absl/strings",
],
)
cc_library(
name = "conditions",
srcs = ["conditions.cc"],
hdrs = ["conditions.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":voidify",
"//absl/base",
"//absl/base:config",
"//absl/base:core_headers",
],
)
cc_library(
name = "config",
hdrs = ["config.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
"//absl/log:__pkg__",
],
deps = [
"//absl/base:config",
"//absl/base:core_headers",
],
)
cc_library(
name = "flags",
hdrs = ["flags.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/flags:flag",
],
)
cc_library(
name = "format",
srcs = ["log_format.cc"],
hdrs = ["log_format.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":config",
":globals",
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:log_severity",
"//absl/strings",
"//absl/strings:str_format",
"//absl/time",
"//absl/types:span",
],
)
cc_library(
name = "globals",
srcs = ["globals.cc"],
hdrs = ["globals.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
"//absl/log:__pkg__",
],
deps = [
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:log_severity",
"//absl/base:raw_logging_internal",
"//absl/strings",
"//absl/time",
],
)
cc_library(
name = "log_message",
srcs = ["log_message.cc"],
hdrs = ["log_message.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
"//absl/log:__pkg__",
],
deps = [
":config",
":format",
":globals",
":log_sink_set",
":nullguard",
"//absl/base",
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:errno_saver",
"//absl/base:log_severity",
"//absl/base:raw_logging_internal",
"//absl/base:strerror",
"//absl/container:inlined_vector",
"//absl/debugging:examine_stack",
"//absl/log:globals",
"//absl/log:log_entry",
"//absl/log:log_sink",
"//absl/log:log_sink_registry",
"//absl/memory",
"//absl/strings",
"//absl/strings:str_format",
"//absl/time",
"//absl/types:span",
],
)
cc_library(
name = "log_sink_set",
srcs = ["log_sink_set.cc"],
hdrs = ["log_sink_set.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":config",
":globals",
"//absl/base",
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:log_severity",
"//absl/base:raw_logging_internal",
"//absl/cleanup",
"//absl/log:globals",
"//absl/log:log_entry",
"//absl/log:log_sink",
"//absl/strings",
"//absl/synchronization",
"//absl/types:span",
],
)
cc_library(
name = "nullguard",
hdrs = ["nullguard.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/base:config",
],
)
cc_library(
name = "nullstream",
hdrs = ["nullstream.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:log_severity",
"//absl/strings",
],
)
cc_library(
name = "strip",
hdrs = ["strip.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":log_message",
":nullstream",
"//absl/base:log_severity",
],
)
cc_library(
name = "test_actions",
testonly = True,
srcs = ["test_actions.cc"],
hdrs = ["test_actions.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":config",
"//absl/base:config",
"//absl/base:log_severity",
"//absl/log:log_entry",
"//absl/strings",
"//absl/time",
],
)
cc_library(
name = "test_helpers",
testonly = True,
srcs = ["test_helpers.cc"],
hdrs = ["test_helpers.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":globals",
"//absl/base:config",
"//absl/base:log_severity",
"//absl/log:globals",
"//absl/log:initialize",
"@com_google_googletest//:gtest",
],
)
cc_library(
name = "test_matchers",
testonly = True,
srcs = ["test_matchers.cc"],
hdrs = ["test_matchers.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":config",
":test_helpers",
"//absl/base:config",
"//absl/base:log_severity",
"//absl/log:log_entry",
"//absl/strings",
"//absl/time",
"@com_google_googletest//:gtest",
],
)
cc_library(
name = "voidify",
hdrs = ["voidify.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = ["//absl/base:config"],
)
# Test targets
cc_test(
name = "stderr_log_sink_test",
size = "small",
srcs = ["stderr_log_sink_test.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
tags = [
"no_test_android",
"no_test_darwin_x86_64",
"no_test_ios",
"no_test_wasm",
],
deps = [
":test_helpers",
"//absl/base:core_headers",
"//absl/base:log_severity",
"//absl/log",
"//absl/log:globals",
"@com_google_googletest//:gtest_main",
],
)
// 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.
#include "absl/log/internal/check_op.h"
#include <string.h>
#ifdef _MSC_VER
#define strcasecmp _stricmp
#else
#include <strings.h> // for strcasecmp, but msvc does not have this header
#endif
#include <sstream>
#include <string>
#include "absl/base/config.h"
#include "absl/strings/str_cat.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {
#define ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(x) \
template std::string* MakeCheckOpString(x, x, const char*)
ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(bool);
ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(int64_t);
ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(uint64_t);
ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(float);
ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(double);
ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(char);
ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(unsigned char);
ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(const std::string&);
ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(const absl::string_view&);
ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(const char*);
ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(const signed char*);
ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(const unsigned char*);
ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(const void*);
#undef ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING
CheckOpMessageBuilder::CheckOpMessageBuilder(const char* exprtext) {
stream_ << exprtext << " (";
}
std::ostream& CheckOpMessageBuilder::ForVar2() {
stream_ << " vs. ";
return stream_;
}
std::string* CheckOpMessageBuilder::NewString() {
stream_ << ")";
return new std::string(stream_.str());
}
void MakeCheckOpValueString(std::ostream& os, const char v) {
if (v >= 32 && v <= 126) {
os << "'" << v << "'";
} else {
os << "char value " << int{v};
}
}
void MakeCheckOpValueString(std::ostream& os, const signed char v) {
if (v >= 32 && v <= 126) {
os << "'" << v << "'";
} else {
os << "signed char value " << int{v};
}
}
void MakeCheckOpValueString(std::ostream& os, const unsigned char v) {
if (v >= 32 && v <= 126) {
os << "'" << v << "'";
} else {
os << "unsigned char value " << int{v};
}
}
void MakeCheckOpValueString(std::ostream& os, const void* p) {
if (p == nullptr) {
os << "(null)";
} else {
os << p;
}
}
// Helper functions for string comparisons.
#define DEFINE_CHECK_STROP_IMPL(name, func, expected) \
std::string* Check##func##expected##Impl(const char* s1, const char* s2, \
const char* exprtext) { \
bool equal = s1 == s2 || (s1 && s2 && !func(s1, s2)); \
if (equal == expected) { \
return nullptr; \
} else { \
return new std::string( \
absl::StrCat(exprtext, " (", s1, " vs. ", s2, ")")); \
} \
}
DEFINE_CHECK_STROP_IMPL(CHECK_STREQ, strcmp, true)
DEFINE_CHECK_STROP_IMPL(CHECK_STRNE, strcmp, false)
DEFINE_CHECK_STROP_IMPL(CHECK_STRCASEEQ, strcasecmp, true)
DEFINE_CHECK_STROP_IMPL(CHECK_STRCASENE, strcasecmp, false)
#undef DEFINE_CHECK_STROP_IMPL
} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl
// 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.
#include "absl/log/internal/conditions.h"
#include <atomic>
#include <cstdint>
#include "absl/base/config.h"
#include "absl/base/internal/cycleclock.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {
namespace {
// The following code behaves like AtomicStatsCounter::LossyAdd() for
// speed since it is fine to lose occasional updates.
// Returns old value of *counter.
uint32_t LossyIncrement(std::atomic<uint32_t>* counter) {
const uint32_t value = counter->load(std::memory_order_relaxed);
counter->store(value + 1, std::memory_order_relaxed);
return value;
}
} // namespace
bool LogEveryNState::ShouldLog(int n) {
return n != 0 && (LossyIncrement(&counter_) % n) == 0;
}
bool LogFirstNState::ShouldLog(int n) {
const uint32_t counter_value = counter_.load(std::memory_order_relaxed);
if (static_cast<int64_t>(counter_value) < n) {
counter_.store(counter_value + 1, std::memory_order_relaxed);
return true;
}
return false;
}
bool LogEveryPow2State::ShouldLog() {
const uint32_t new_value = LossyIncrement(&counter_) + 1;
return (new_value & (new_value - 1)) == 0;
}
bool LogEveryNSecState::ShouldLog(double seconds) {
using absl::base_internal::CycleClock;
LossyIncrement(&counter_);
const int64_t now_cycles = CycleClock::Now();
int64_t next_cycles = next_log_time_cycles_.load(std::memory_order_relaxed);
#if defined(__myriad2__)
// myriad2 does not have 8-byte compare and exchange. Use a racy version that
// is "good enough" but will over-log in the face of concurrent logging.
if (now_cycles > next_cycles) {
next_log_time_cycles_.store(now_cycles + seconds * CycleClock::Frequency(),
std::memory_order_relaxed);
return true;
}
return false;
#else
do {
if (now_cycles <= next_cycles) return false;
} while (!next_log_time_cycles_.compare_exchange_weak(
next_cycles, now_cycles + seconds * CycleClock::Frequency(),
std::memory_order_relaxed, std::memory_order_relaxed));
return true;
#endif
}
} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl
// 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/internal/config.h
// -----------------------------------------------------------------------------
//
#ifndef ABSL_LOG_INTERNAL_CONFIG_H_
#define ABSL_LOG_INTERNAL_CONFIG_H_
#include "absl/base/config.h"
#ifdef _WIN32
#include <cstdint>
#else
#include <sys/types.h>
#endif
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {
#ifdef _WIN32
using Tid = uint32_t;
#else
using Tid = pid_t;
#endif
} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_LOG_INTERNAL_CONFIG_H_
// 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_flags.h
// -----------------------------------------------------------------------------
//
// This header declares set of flags which can be used to configure Abseil
// Logging library behaviour at runtime.
#ifndef ABSL_LOG_INTERNAL_FLAGS_H_
#define ABSL_LOG_INTERNAL_FLAGS_H_
#include <string>
#include "absl/flags/declare.h"
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// These flags should not be used in C++ code to access logging library
// configuration knobs. Use interfaces defined in absl/log/globals.h
// instead. It is still ok to use these flags on a command line.
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Log messages at this severity or above are sent to stderr in *addition* to
// logfiles. Defaults to `ERROR`. See log_severity.h for numeric values of
// severity levels.
ABSL_DECLARE_FLAG(int, stderrthreshold);
// Log messages at this severity or above are logged; others are discarded.
// Defaults to `INFO`, i.e. log all severities. See log_severity.h for numeric
// values of severity levels.
ABSL_DECLARE_FLAG(int, minloglevel);
// If specified in the form file:linenum, any messages logged from a matching
// location will also include a backtrace.
ABSL_DECLARE_FLAG(std::string, log_backtrace_at);
// If true, the log prefix (severity, date, time, PID, etc.) is prepended to
// each message logged. Defaults to true.
ABSL_DECLARE_FLAG(bool, log_prefix);
#endif // ABSL_LOG_INTERNAL_FLAGS_H_
// 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.
#include "absl/log/internal/globals.h"
#include <atomic>
#include <cstdio>
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/log_severity.h"
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {
namespace {
// Keeps track of whether Logging initialization is finalized.
// Log messages generated before that will go to stderr.
ABSL_CONST_INIT std::atomic<bool> logging_initialized(false);
// The TimeZone used for logging. This may only be set once.
ABSL_CONST_INIT std::atomic<absl::TimeZone*> timezone_ptr{nullptr};
// If true, the logging library will symbolize stack in fatal messages
ABSL_CONST_INIT std::atomic<bool> symbolize_stack_trace(true);
// Specifies maximum number of stack frames to report in fatal messages.
ABSL_CONST_INIT std::atomic<int> max_frames_in_stack_trace(64);
ABSL_CONST_INIT std::atomic<bool> exit_on_dfatal(true);
ABSL_CONST_INIT std::atomic<bool> suppress_sigabort_trace(false);
} // namespace
bool IsInitialized() {
return logging_initialized.load(std::memory_order_acquire);
}
void SetInitialized() {
logging_initialized.store(true, std::memory_order_release);
}
void WriteToStderr(absl::string_view message, absl::LogSeverity severity) {
// Avoid using std::cerr from this module since we may get called during
// exit code, and cerr may be partially or fully destroyed by then.
std::fwrite(message.data(), message.size(), 1, stderr);
#if defined(_WIN64) || defined(_WIN32) || defined(_WIN16)
// C99 requires stderr to not be fully-buffered by default (7.19.3.7), but
// MS CRT buffers it anyway, so we must `fflush` to ensure the string hits
// the console/file before the program dies (and takes the libc buffers
// with it).
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/stream-i-o
if (severity >= absl::LogSeverity::kWarning) {
std::fflush(stderr);
}
#else
// Avoid unused parameter warning in this branch.
(void)severity;
#endif
}
void SetTimeZone(absl::TimeZone tz) {
absl::TimeZone* expected = nullptr;
absl::TimeZone* new_tz = new absl::TimeZone(tz);
// timezone_ptr can only be set once, otherwise new_tz is leaked.
if (!timezone_ptr.compare_exchange_strong(expected, new_tz,
std::memory_order_release,
std::memory_order_relaxed)) {
ABSL_RAW_LOG(FATAL,
"absl::log_internal::SetTimeZone() has already been called");
}
}
const absl::TimeZone* TimeZone() {
return timezone_ptr.load(std::memory_order_acquire);
}
bool ShouldSymbolizeLogStackTrace() {
return symbolize_stack_trace.load(std::memory_order_acquire);
}
void EnableSymbolizeLogStackTrace(bool on_off) {
symbolize_stack_trace.store(on_off, std::memory_order_release);
}
int MaxFramesInLogStackTrace() {
return max_frames_in_stack_trace.load(std::memory_order_acquire);
}
void SetMaxFramesInLogStackTrace(int max_num_frames) {
max_frames_in_stack_trace.store(max_num_frames, std::memory_order_release);
}
bool ExitOnDFatal() { return exit_on_dfatal.load(std::memory_order_acquire); }
void SetExitOnDFatal(bool on_off) {
exit_on_dfatal.store(on_off, std::memory_order_release);
}
bool SuppressSigabortTrace() {
return suppress_sigabort_trace.load(std::memory_order_acquire);
}
bool SetSuppressSigabortTrace(bool on_off) {
return suppress_sigabort_trace.exchange(on_off);
}
} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl
// 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/internal/globals.h
// -----------------------------------------------------------------------------
//
// This header file contains various global objects and static helper routines
// use in logging implementation.
#ifndef ABSL_LOG_INTERNAL_GLOBALS_H_
#define ABSL_LOG_INTERNAL_GLOBALS_H_
#include "absl/base/config.h"
#include "absl/base/log_severity.h"
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {
// IsInitialized returns true if the logging library is initialized.
// This function is async-signal-safe
bool IsInitialized();
// SetLoggingInitialized is called once after logging initialization is done.
void SetInitialized();
// Unconditionally write a `message` to stderr. If `severity` exceeds kInfo
// we also flush the stderr stream.
void WriteToStderr(absl::string_view message, absl::LogSeverity severity);
// Set the TimeZone used for human-friendly times (for example, the log message
// prefix) printed by the logging library. This may only be called once.
void SetTimeZone(absl::TimeZone tz);
// Returns the TimeZone used for human-friendly times (for example, the log
// message prefix) printed by the logging library Returns nullptr prior to
// initialization.
const absl::TimeZone* TimeZone();
// Returns true if stack traces emitted by the logging library should be
// symbolized. This function is async-signal-safe.
bool ShouldSymbolizeLogStackTrace();
// Enables or disables symbolization of stack traces emitted by the
// logging library. This function is async-signal-safe.
void EnableSymbolizeLogStackTrace(bool on_off);
// Returns the maximum number of frames that appear in stack traces
// emitted by the logging library. This function is async-signal-safe.
int MaxFramesInLogStackTrace();
// Sets the maximum number of frames that appear in stack traces emitted by
// the logging library. This function is async-signal-safe.
void SetMaxFramesInLogStackTrace(int max_num_frames);
// Determines whether we exit the program for a LOG(DFATAL) message in
// debug mode. It does this by skipping the call to Fail/FailQuietly.
// This is intended for testing only.
//
// This can have some effects on LOG(FATAL) as well. Failure messages
// are always allocated (rather than sharing a buffer), the crash
// reason is not recorded, the "gwq" status message is not updated,
// and the stack trace is not recorded. The LOG(FATAL) *will* still
// exit the program. Since this function is used only in testing,
// these differences are acceptable.
//
// Additionally, LOG(LEVEL(FATAL)) is indistinguishable from LOG(DFATAL) and
// will not terminate the program if SetExitOnDFatal(false) has been called.
bool ExitOnDFatal();
// SetExitOnDFatal() sets the ExitOnDFatal() status
void SetExitOnDFatal(bool on_off);
// Determines if the logging library should suppress logging of stacktraces in
// the `SIGABRT` handler, typically because we just logged a stacktrace as part
// of `LOG(FATAL)` and are about to send ourselves a `SIGABRT` to end the
// program.
bool SuppressSigabortTrace();
// Sets the SuppressSigabortTrace() status and returns the previous state.
bool SetSuppressSigabortTrace(bool on_off);
} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_LOG_INTERNAL_GLOBALS_H_
//
// 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.
#include "absl/log/internal/log_format.h"
#include <string.h>
#ifdef _MSC_VER
#include <winsock2.h> // For timeval
#else
#include <sys/time.h>
#endif
#include <cstddef>
#include <cstdint>
#include <limits>
#include <string>
#include <type_traits>
#include "absl/base/config.h"
#include "absl/base/log_severity.h"
#include "absl/base/optimization.h"
#include "absl/log/internal/config.h"
#include "absl/log/internal/globals.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "absl/time/civil_time.h"
#include "absl/time/time.h"
#include "absl/types/span.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {
namespace {
// The fields before the filename are all fixed-width except for the thread ID,
// which is of bounded width.
size_t FormatBoundedFields(absl::LogSeverity severity, absl::Time timestamp,
log_internal::Tid tid, absl::Span<char>& buf) {
constexpr size_t kBoundedFieldsMaxLen =
sizeof("SMMDD HH:MM:SS.NNNNNN ") +
(1 + std::numeric_limits<log_internal::Tid>::digits10 + 1) - sizeof("");
if (ABSL_PREDICT_FALSE(buf.size() < kBoundedFieldsMaxLen)) {
// We don't bother trying to truncate these fields if the buffer is too
// short (or almost too short) because it would require doing a lot more
// length checking (slow) and it should never happen. A 15kB buffer should
// be enough for anyone. Instead we mark `buf` full without writing
// anything.
buf.remove_suffix(buf.size());
return 0;
}
// We can't call absl::LocalTime(), localtime_r(), or anything else here that
// isn't async-signal-safe. We can only use the time zone if it has already
// been loaded.
const absl::TimeZone* tz = absl::log_internal::TimeZone();
if (ABSL_PREDICT_FALSE(tz == nullptr)) {
// If a time zone hasn't been set yet because we are logging before the
// logging library has been initialized, we fallback to a simpler, slower
// method. Just report the raw Unix time in seconds. We cram this into the
// normal time format for the benefit of parsers.
auto tv = absl::ToTimeval(timestamp);
int snprintf_result = absl::SNPrintF(
buf.data(), buf.size(), "%c0000 00:00:%02d.%06d %7d ",
absl::LogSeverityName(severity)[0], static_cast<int>(tv.tv_sec),
static_cast<int>(tv.tv_usec), static_cast<int>(tid));
if (snprintf_result >= 0) {
buf.remove_prefix(snprintf_result);
return static_cast<size_t>(snprintf_result);
}
return 0;
}
char* p = buf.data();
*p++ = absl::LogSeverityName(severity)[0];
const absl::TimeZone::CivilInfo ci = tz->At(timestamp);
absl::numbers_internal::PutTwoDigits(ci.cs.month(), p);
p += 2;
absl::numbers_internal::PutTwoDigits(ci.cs.day(), p);
p += 2;
*p++ = ' ';
absl::numbers_internal::PutTwoDigits(ci.cs.hour(), p);
p += 2;
*p++ = ':';
absl::numbers_internal::PutTwoDigits(ci.cs.minute(), p);
p += 2;
*p++ = ':';
absl::numbers_internal::PutTwoDigits(ci.cs.second(), p);
p += 2;
*p++ = '.';
const int64_t usecs = absl::ToInt64Microseconds(ci.subsecond);
absl::numbers_internal::PutTwoDigits(usecs / 10000, p);
p += 2;
absl::numbers_internal::PutTwoDigits(usecs / 100 % 100, p);
p += 2;
absl::numbers_internal::PutTwoDigits(usecs % 100, p);
p += 2;
*p++ = ' ';
constexpr bool unsigned_tid_t = !std::is_signed<log_internal::Tid>::value;
if ((unsigned_tid_t || tid >= 0) && tid < 10) *p++ = ' ';
if ((unsigned_tid_t || tid > -10) && tid < 100) *p++ = ' ';
if ((unsigned_tid_t || tid > -100) && tid < 1000) *p++ = ' ';
if ((unsigned_tid_t || tid > -1000) && tid < 10000) *p++ = ' ';
if ((unsigned_tid_t || tid > -10000) && tid < 100000) *p++ = ' ';
if ((unsigned_tid_t || tid > -100000) && tid < 1000000) *p++ = ' ';
p = absl::numbers_internal::FastIntToBuffer(tid, p);
*p++ = ' ';
const size_t bytes_formatted = p - buf.data();
buf.remove_prefix(bytes_formatted);
return bytes_formatted;
}
// Copies into `dst` as many bytes of `src` as will fit, then advances `dst`
// past the copied bytes and returns the number of bytes written.
size_t AppendTruncated(absl::string_view src, absl::Span<char>& dst) {
if (src.size() > dst.size()) src = src.substr(0, dst.size());
memcpy(dst.data(), src.data(), src.size());
dst.remove_prefix(src.size());
return src.size();
}
size_t FormatLineNumber(int line, absl::Span<char>& buf) {
constexpr size_t kLineFieldMaxLen =
sizeof(":] ") + (1 + std::numeric_limits<int>::digits10 + 1) - sizeof("");
if (ABSL_PREDICT_FALSE(buf.size() < kLineFieldMaxLen)) {
// As above, we don't bother trying to truncate this if the buffer is too
// short and it should never happen.
buf.remove_suffix(buf.size());
return 0;
}
char* p = buf.data();
*p++ = ':';
p = absl::numbers_internal::FastIntToBuffer(line, p);
*p++ = ']';
*p++ = ' ';
const size_t bytes_formatted = p - buf.data();
buf.remove_prefix(bytes_formatted);
return bytes_formatted;
}
} // namespace
std::string FormatLogMessage(absl::LogSeverity severity,
absl::CivilSecond civil_second,
absl::Duration subsecond, log_internal::Tid tid,
absl::string_view basename, int line,
absl::string_view message) {
return absl::StrFormat(
"%c%02d%02d %02d:%02d:%02d.%06d %7d %s:%d] %s",
absl::LogSeverityName(severity)[0], civil_second.month(),
civil_second.day(), civil_second.hour(), civil_second.minute(),
civil_second.second(), absl::ToInt64Microseconds(subsecond), tid,
basename, line, message);
}
// This method is fairly hot, and the library always passes a huge `buf`, so we
// save some bounds-checking cycles by not trying to do precise truncation.
// Truncating at a field boundary is probably a better UX anyway.
//
// The prefix is written in three parts, each of which does a single
// bounds-check and truncation:
// 1. severity, timestamp, and thread ID
// 2. filename
// 3. line number and bracket
size_t FormatLogPrefix(absl::LogSeverity severity, absl::Time timestamp,
log_internal::Tid tid, absl::string_view basename,
int line, absl::Span<char>& buf) {
auto prefix_size = FormatBoundedFields(severity, timestamp, tid, buf);
prefix_size += AppendTruncated(basename, buf);
prefix_size += FormatLineNumber(line, buf);
return prefix_size;
}
} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl
// 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/internal/log_format.h
// -----------------------------------------------------------------------------
//
// This file declares routines implementing formatting of log message and log
// prefix.
#ifndef ABSL_LOG_INTERNAL_LOG_FORMAT_H_
#define ABSL_LOG_INTERNAL_LOG_FORMAT_H_
#include <stddef.h>
#include <string>
#include "absl/base/config.h"
#include "absl/base/log_severity.h"
#include "absl/log/internal/config.h"
#include "absl/strings/string_view.h"
#include "absl/time/civil_time.h"
#include "absl/time/time.h"
#include "absl/types/span.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {
// Formats log message based on provided data.
std::string FormatLogMessage(absl::LogSeverity severity,
absl::CivilSecond civil_second,
absl::Duration subsecond, log_internal::Tid tid,
absl::string_view basename, int line,
absl::string_view message);
// Formats various entry metadata into a text string meant for use as a
// prefix on a log message string. Writes into `buf`, advances `buf` to point
// at the remainder of the buffer (i.e. past any written bytes), and returns the
// number of bytes written.
//
// In addition to calling `buf->remove_prefix()` (or the equivalent), this
// function may also do `buf->remove_suffix(buf->size())` in cases where no more
// bytes (i.e. no message data) should be written into the buffer. For example,
// if the prefix ought to be:
// I0926 09:00:00.000000 1234567 foo.cc:123]
// `buf` is too small, the function might fill the whole buffer:
// I0926 09:00:00.000000 1234
// (note the apparrently incorrect thread ID), or it might write less:
// I0926 09:00:00.000000
// In this case, it might also empty `buf` prior to returning to prevent
// message data from being written into the space where a reader would expect to
// see a thread ID.
size_t FormatLogPrefix(absl::LogSeverity severity, absl::Time timestamp,
log_internal::Tid tid, absl::string_view basename,
int line, absl::Span<char>& buf);
} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_LOG_INTERNAL_LOG_FORMAT_H_
//
// 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.
#include "absl/log/internal/log_sink_set.h"
#ifndef ABSL_HAVE_THREAD_LOCAL
#include <pthread.h>
#endif
#ifdef __ANDROID__
#include <android/log.h>
#endif
#ifdef _WIN32
#include <windows.h>
#endif
#include <algorithm>
#include <vector>
#include "absl/base/attributes.h"
#include "absl/base/call_once.h"
#include "absl/base/config.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/log_severity.h"
#include "absl/base/thread_annotations.h"
#include "absl/cleanup/cleanup.h"
#include "absl/log/globals.h"
#include "absl/log/internal/config.h"
#include "absl/log/internal/globals.h"
#include "absl/log/log_entry.h"
#include "absl/log/log_sink.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "absl/types/span.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {
namespace {
// Returns a mutable reference to a thread-local variable that should be true if
// a globally-registered `LogSink`'s `Send()` is currently being invoked on this
// thread.
bool& ThreadIsLoggingStatus() {
#ifdef ABSL_HAVE_THREAD_LOCAL
ABSL_CONST_INIT thread_local bool thread_is_logging = false;
return thread_is_logging;
#else
ABSL_CONST_INIT static pthread_key_t thread_is_logging_key;
static const bool unused = [] {
if (pthread_key_create(&thread_is_logging_key, [](void* data) {
delete reinterpret_cast<bool*>(data);
})) {
perror("pthread_key_create failed!");
abort();
}
return true;
}();
bool* thread_is_logging_ptr =
reinterpret_cast<bool*>(pthread_getspecific(thread_is_logging_key));
if (ABSL_PREDICT_FALSE(!thread_is_logging_ptr)) {
thread_is_logging_ptr = new bool{false};
if (pthread_setspecific(thread_is_logging_key, thread_is_logging_ptr)) {
perror("pthread_setspecific failed");
abort();
}
}
return *thread_is_logging_ptr;
#endif
}
class StderrLogSink final : public LogSink {
public:
~StderrLogSink() override = default;
void Send(const absl::LogEntry& entry) override {
if (entry.log_severity() < absl::StderrThreshold() &&
absl::log_internal::IsInitialized()) {
return;
}
ABSL_CONST_INIT static absl::once_flag warn_if_not_initialized;
absl::call_once(warn_if_not_initialized, []() {
if (absl::log_internal::IsInitialized()) return;
const char w[] =
"WARNING: All log messages before absl::InitializeLog() is called"
" are written to STDERR\n";
absl::log_internal::WriteToStderr(w, absl::LogSeverity::kWarning);
});
if (!entry.stacktrace().empty()) {
absl::log_internal::WriteToStderr(entry.stacktrace(),
entry.log_severity());
} else {
// TODO(b/226937039): do this outside else condition once we avoid
// ReprintFatalMessage
absl::log_internal::WriteToStderr(
entry.text_message_with_prefix_and_newline(), entry.log_severity());
}
}
};
#if defined(__ANDROID__)
class AndroidLogSink final : public LogSink {
public:
~AndroidLogSink() override = default;
void Send(const absl::LogEntry& entry) override {
const int level = AndroidLogLevel(entry);
// TODO(b/37587197): make the tag ("native") configurable.
__android_log_write(level, "native",
entry.text_message_with_prefix_and_newline_c_str());
if (entry.log_severity() == absl::LogSeverity::kFatal)
__android_log_write(ANDROID_LOG_FATAL, "native", "terminating.\n");
}
private:
static int AndroidLogLevel(const absl::LogEntry& entry) {
switch (entry.log_severity()) {
case absl::LogSeverity::kFatal:
return ANDROID_LOG_FATAL;
case absl::LogSeverity::kError:
return ANDROID_LOG_ERROR;
case absl::LogSeverity::kWarning:
return ANDROID_LOG_WARN;
default:
if (entry.verbosity() >= 2) return ANDROID_LOG_VERBOSE;
if (entry.verbosity() == 1) return ANDROID_LOG_DEBUG;
return ANDROID_LOG_INFO;
}
}
};
#endif // !defined(__ANDROID__)
#if defined(_WIN32)
class WindowsDebuggerLogSink final : public LogSink {
public:
~WindowsDebuggerLogSink() override = default;
void Send(const absl::LogEntry& entry) override {
if (entry.log_severity() < absl::StderrThreshold() &&
absl::log_internal::IsInitialized()) {
return;
}
::OutputDebugStringA(entry.text_message_with_prefix_and_newline_c_str());
}
};
#endif // !defined(_WIN32)
class GlobalLogSinkSet final {
public:
GlobalLogSinkSet() {
#if defined(__myriad2__) || defined(__Fuchsia__)
// myriad2 and Fuchsia do not log to stderr by default.
#else
static StderrLogSink* stderr_log_sink = new StderrLogSink;
AddLogSink(stderr_log_sink);
#endif
#ifdef __ANDROID__
static AndroidLogSink* android_log_sink = new AndroidLogSink;
AddLogSink(android_log_sink);
#endif
#if defined(_WIN32)
static WindowsDebuggerLogSink* debugger_log_sink =
new WindowsDebuggerLogSink;
AddLogSink(debugger_log_sink);
#endif // !defined(_WIN32)
}
void LogToSinks(const absl::LogEntry& entry,
absl::Span<absl::LogSink*> extra_sinks, bool extra_sinks_only)
ABSL_LOCKS_EXCLUDED(guard_) {
SendToSinks(entry, extra_sinks);
if (!extra_sinks_only) {
if (ThreadIsLoggingToLogSink()) {
absl::log_internal::WriteToStderr(
entry.text_message_with_prefix_and_newline(), entry.log_severity());
} else {
absl::ReaderMutexLock global_sinks_lock(&guard_);
ThreadIsLoggingStatus() = true;
// Ensure the "thread is logging" status is reverted upon leaving the
// scope even in case of exceptions.
auto status_cleanup =
absl::MakeCleanup([] { ThreadIsLoggingStatus() = false; });
SendToSinks(entry, absl::MakeSpan(sinks_));
}
}
}
void AddLogSink(absl::LogSink* sink) ABSL_LOCKS_EXCLUDED(guard_) {
{
absl::WriterMutexLock global_sinks_lock(&guard_);
auto pos = std::find(sinks_.begin(), sinks_.end(), sink);
if (pos == sinks_.end()) {
sinks_.push_back(sink);
return;
}
}
ABSL_INTERNAL_LOG(FATAL, "Duplicate log sinks are not supported");
}
void RemoveLogSink(absl::LogSink* sink) ABSL_LOCKS_EXCLUDED(guard_) {
{
absl::WriterMutexLock global_sinks_lock(&guard_);
auto pos = std::find(sinks_.begin(), sinks_.end(), sink);
if (pos != sinks_.end()) {
sinks_.erase(pos);
return;
}
}
ABSL_INTERNAL_LOG(FATAL, "Mismatched log sink being removed");
}
void FlushLogSinks() ABSL_LOCKS_EXCLUDED(guard_) {
if (ThreadIsLoggingToLogSink()) {
// The thread_local condition demonstrates that we're already holding the
// lock in order to iterate over `sinks_` for dispatch. The thread-safety
// annotations don't know this, so we use `ABSL_NO_THREAD_SAFETY_ANALYSIS`
guard_.AssertReaderHeld();
FlushLogSinksLocked();
} else {
absl::ReaderMutexLock global_sinks_lock(&guard_);
// In case if LogSink::Flush overload decides to log
ThreadIsLoggingStatus() = true;
// Ensure the "thread is logging" status is reverted upon leaving the
// scope even in case of exceptions.
auto status_cleanup =
absl::MakeCleanup([] { ThreadIsLoggingStatus() = false; });
FlushLogSinksLocked();
}
}
private:
void FlushLogSinksLocked() ABSL_SHARED_LOCKS_REQUIRED(guard_) {
for (absl::LogSink* sink : sinks_) {
sink->Flush();
}
}
// Helper routine for LogToSinks.
static void SendToSinks(const absl::LogEntry& entry,
absl::Span<absl::LogSink*> sinks) {
for (absl::LogSink* sink : sinks) {
sink->Send(entry);
}
}
using LogSinksSet = std::vector<absl::LogSink*>;
absl::Mutex guard_;
LogSinksSet sinks_ ABSL_GUARDED_BY(guard_);
};
// Returns reference to the global LogSinks set.
GlobalLogSinkSet& GlobalSinks() {
static GlobalLogSinkSet* global_sinks = new GlobalLogSinkSet;
return *global_sinks;
}
} // namespace
bool ThreadIsLoggingToLogSink() { return ThreadIsLoggingStatus(); }
void LogToSinks(const absl::LogEntry& entry,
absl::Span<absl::LogSink*> extra_sinks, bool extra_sinks_only) {
log_internal::GlobalSinks().LogToSinks(entry, extra_sinks, extra_sinks_only);
}
void AddLogSink(absl::LogSink* sink) {
log_internal::GlobalSinks().AddLogSink(sink);
}
void RemoveLogSink(absl::LogSink* sink) {
log_internal::GlobalSinks().RemoveLogSink(sink);
}
void FlushLogSinks() { log_internal::GlobalSinks().FlushLogSinks(); }
} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl
// 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/internal/log_sink_set.h
// -----------------------------------------------------------------------------
#ifndef ABSL_LOG_INTERNAL_LOG_SINK_SET_H_
#define ABSL_LOG_INTERNAL_LOG_SINK_SET_H_
#include "absl/base/config.h"
#include "absl/log/log_entry.h"
#include "absl/log/log_sink.h"
#include "absl/types/span.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {
// Returns true if a globally-registered `LogSink`'s `Send()` is currently
// being invoked on this thread.
bool ThreadIsLoggingToLogSink();
// This function may log to two sets of sinks:
//
// * If `extra_sinks_only` is true, it will dispatch only to `extra_sinks`.
// `LogMessage::ToSinkAlso` and `LogMessage::ToSinkOnly` are used to attach
// extra sinks to the entry.
// * Otherwise it will also log to the global sinks set. This set is managed
// by `absl::AddLogSink` and `absl::RemoveLogSink`.
void LogToSinks(const absl::LogEntry& entry,
absl::Span<absl::LogSink*> extra_sinks, bool extra_sinks_only);
// Implementation for operations with log sink set.
void AddLogSink(absl::LogSink* sink);
void RemoveLogSink(absl::LogSink* sink);
void FlushLogSinks();
} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_LOG_INTERNAL_LOG_SINK_SET_H_
// 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/internal/nullguard.h
// -----------------------------------------------------------------------------
//
// NullGuard exists such that NullGuard<T>::Guard(v) returns v, unless passed a
// nullptr_t, or a null char* or const char*, in which case it returns "(null)".
// This allows streaming NullGuard<T>::Guard(v) to an output stream without
// hitting undefined behavior for null values.
#ifndef ABSL_LOG_INTERNAL_NULLGUARD_H_
#define ABSL_LOG_INTERNAL_NULLGUARD_H_
#include <cstddef>
#include "absl/base/config.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {
template <typename T>
struct NullGuard final {
static const T& Guard(const T& v) { return v; }
};
template <>
struct NullGuard<char*> final {
static const char* Guard(const char* v) { return v ? v : "(null)"; }
};
template <>
struct NullGuard<const char*> final {
static const char* Guard(const char* v) { return v ? v : "(null)"; }
};
template <>
struct NullGuard<std::nullptr_t> final {
static const char* Guard(const std::nullptr_t&) { return "(null)"; }
};
} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_LOG_INTERNAL_NULLGUARD_H_
// 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/internal/nullstream.h
// -----------------------------------------------------------------------------
//
// Classes `NullStream`, `NullStreamMaybeFatal ` and `NullStreamFatal`
// implement a subset of the `LogMessage` API and are used instead when logging
// of messages has been disabled.
#ifndef ABSL_LOG_INTERNAL_NULLSTREAM_H_
#define ABSL_LOG_INTERNAL_NULLSTREAM_H_
#ifdef _WIN32
#include <cstdlib>
#else
#include <unistd.h>
#endif
#include <ios>
#include <ostream>
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/log_severity.h"
#include "absl/strings/string_view.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {
// A `NullStream` implements the API of `LogMessage` (a few methods and
// `operator<<`) but does nothing. All methods are defined inline so the
// compiler can eliminate the whole instance and discard anything that's
// streamed in.
class NullStream {
public:
NullStream& AtLocation(absl::string_view, int) { return *this; }
template <typename SourceLocationType>
NullStream& AtLocation(SourceLocationType) {
return *this;
}
NullStream& NoPrefix() { return *this; }
NullStream& WithVerbosity(int) { return *this; }
template <typename TimeType>
NullStream& WithTimestamp(TimeType) {
return *this;
}
template <typename Tid>
NullStream& WithThreadID(Tid) {
return *this;
}
template <typename LogEntryType>
NullStream& WithMetadataFrom(const LogEntryType&) {
return *this;
}
NullStream& WithPerror() { return *this; }
template <typename LogSinkType>
NullStream& ToSinkAlso(LogSinkType*) {
return *this;
}
template <typename LogSinkType>
NullStream& ToSinkOnly(LogSinkType*) {
return *this;
}
template <typename LogSinkType>
NullStream& OutputToSink(LogSinkType*, bool) {
return *this;
}
NullStream& InternalStream() { return *this; }
};
template <typename T>
inline NullStream& operator<<(NullStream& str, const T&) {
return str;
}
inline NullStream& operator<<(NullStream& str,
std::ostream& (*)(std::ostream& os)) {
return str;
}
inline NullStream& operator<<(NullStream& str,
std::ios_base& (*)(std::ios_base& os)) {
return str;
}
// `NullStreamMaybeFatal` implements the process termination semantics of
// `LogMessage`, which is used for `DFATAL` severity and expression-defined
// severity e.g. `LOG(LEVEL(HowBadIsIt()))`. Like `LogMessage`, it terminates
// the process when destroyed if the passed-in severity equals `FATAL`.
class NullStreamMaybeFatal final : public NullStream {
public:
explicit NullStreamMaybeFatal(absl::LogSeverity severity)
: fatal_(severity == absl::LogSeverity::kFatal) {}
~NullStreamMaybeFatal() {
if (fatal_) _exit(1);
}
private:
bool fatal_;
};
// `NullStreamFatal` implements the process termination semantics of
// `LogMessageFatal`, which means it always terminates the process. `DFATAL`
// and expression-defined severity use `NullStreamMaybeFatal` above.
class NullStreamFatal final : public NullStream {
public:
NullStreamFatal() {}
// ABSL_ATTRIBUTE_NORETURN doesn't seem to work on destructors with msvc, so
// disable msvc's warning about the d'tor never returning.
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4722)
#endif
ABSL_ATTRIBUTE_NORETURN ~NullStreamFatal() { _exit(1); }
#ifdef _MSC_VER
#pragma warning(pop)
#endif
};
} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_LOG_INTERNAL_GLOBALS_H_
//
// 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.
#include <stdlib.h>
#include <string>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/base/attributes.h"
#include "absl/base/log_severity.h"
#include "absl/log/globals.h"
#include "absl/log/internal/test_helpers.h"
#include "absl/log/log.h"
namespace {
using ::testing::AllOf;
using ::testing::HasSubstr;
auto* test_env ABSL_ATTRIBUTE_UNUSED = ::testing::AddGlobalTestEnvironment(
new absl::log_internal::LogTestEnvironment);
MATCHER_P2(HasSubstrTimes, substr, expected_count, "") {
int count = 0;
std::string::size_type pos = 0;
std::string needle(substr);
while ((pos = arg.find(needle, pos)) != std::string::npos) {
++count;
pos += needle.size();
}
return count == expected_count;
}
TEST(StderrLogSinkDeathTest, InfoMessagesInStderr) {
EXPECT_DEATH_IF_SUPPORTED(
{
absl::SetStderrThreshold(absl::LogSeverityAtLeast::kInfo);
LOG(INFO) << "INFO message";
exit(1);
},
"INFO message");
}
TEST(StderrLogSinkDeathTest, WarningMessagesInStderr) {
EXPECT_DEATH_IF_SUPPORTED(
{
absl::SetStderrThreshold(absl::LogSeverityAtLeast::kInfo);
LOG(WARNING) << "WARNING message";
exit(1);
},
"WARNING message");
}
TEST(StderrLogSinkDeathTest, ErrorMessagesInStderr) {
EXPECT_DEATH_IF_SUPPORTED(
{
absl::SetStderrThreshold(absl::LogSeverityAtLeast::kInfo);
LOG(ERROR) << "ERROR message";
exit(1);
},
"ERROR message");
}
TEST(StderrLogSinkDeathTest, FatalMessagesInStderr) {
char message[] = "FATAL message";
char stacktrace[] = "*** Check failure stack trace: ***";
int expected_count = 1;
EXPECT_DEATH_IF_SUPPORTED(
{
absl::SetStderrThreshold(absl::LogSeverityAtLeast::kInfo);
LOG(FATAL) << message;
},
AllOf(HasSubstrTimes(message, expected_count), HasSubstr(stacktrace)));
}
TEST(StderrLogSinkDeathTest, SecondaryFatalMessagesInStderr) {
auto MessageGen = []() -> std::string {
LOG(FATAL) << "Internal failure";
return "External failure";
};
EXPECT_DEATH_IF_SUPPORTED(
{
absl::SetStderrThreshold(absl::LogSeverityAtLeast::kInfo);
LOG(FATAL) << MessageGen();
},
"Internal failure");
}
} // namespace
// 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/internal/strip.h
// -----------------------------------------------------------------------------
//
#ifndef ABSL_LOG_INTERNAL_STRIP_H_
#define ABSL_LOG_INTERNAL_STRIP_H_
#include "absl/base/log_severity.h"
#include "absl/log/internal/log_message.h"
#include "absl/log/internal/nullstream.h"
// `ABSL_LOGGING_INTERNAL_LOG_*` evaluates to a temporary `LogMessage` object or
// to a related object with a compatible API but different behavior. This set
// of defines comes in three flavors: vanilla, plus two variants that strip some
// logging in subtly different ways for subtly different reasons (see below).
#if defined(STRIP_LOG) && STRIP_LOG
#define ABSL_LOGGING_INTERNAL_LOG_INFO ::absl::log_internal::NullStream()
#define ABSL_LOGGING_INTERNAL_LOG_WARNING ::absl::log_internal::NullStream()
#define ABSL_LOGGING_INTERNAL_LOG_ERROR ::absl::log_internal::NullStream()
#define ABSL_LOGGING_INTERNAL_LOG_FATAL ::absl::log_internal::NullStreamFatal()
#define ABSL_LOGGING_INTERNAL_LOG_QFATAL ::absl::log_internal::NullStreamFatal()
#define ABSL_LOGGING_INTERNAL_LOG_DFATAL \
::absl::log_internal::NullStreamMaybeFatal(::absl::kLogDebugFatal)
#define ABSL_LOGGING_INTERNAL_LOG_LEVEL(severity) \
::absl::log_internal::NullStreamMaybeFatal(log_internal_severity)
#define ABSL_LOG_INTERNAL_CHECK(failure_message) ABSL_LOGGING_INTERNAL_LOG_FATAL
#define ABSL_LOG_INTERNAL_QCHECK(failure_message) \
ABSL_LOGGING_INTERNAL_LOG_QFATAL
#else // !defined(STRIP_LOG) || !STRIP_LOG
#define ABSL_LOGGING_INTERNAL_LOG_INFO \
::absl::log_internal::LogMessage(__FILE__, __LINE__, \
::absl::LogSeverity::kInfo)
#define ABSL_LOGGING_INTERNAL_LOG_WARNING \
::absl::log_internal::LogMessage(__FILE__, __LINE__, \
::absl::LogSeverity::kWarning)
#define ABSL_LOGGING_INTERNAL_LOG_ERROR \
::absl::log_internal::LogMessage(__FILE__, __LINE__, \
::absl::LogSeverity::kError)
#define ABSL_LOGGING_INTERNAL_LOG_FATAL \
::absl::log_internal::LogMessageFatal(__FILE__, __LINE__)
#define ABSL_LOGGING_INTERNAL_LOG_QFATAL \
::absl::log_internal::LogMessageQuietlyFatal(__FILE__, __LINE__)
#define ABSL_LOGGING_INTERNAL_LOG_DFATAL \
::absl::log_internal::LogMessage(__FILE__, __LINE__, ::absl::kLogDebugFatal)
#define ABSL_LOGGING_INTERNAL_LOG_LEVEL(severity) \
::absl::log_internal::LogMessage(__FILE__, __LINE__, log_internal_severity)
// These special cases dispatch to special-case constructors that allow us to
// avoid an extra function call and shrink non-LTO binaries by a percent or so.
#define ABSL_LOG_INTERNAL_CHECK(failure_message) \
::absl::log_internal::LogMessageFatal(__FILE__, __LINE__, failure_message)
#define ABSL_LOG_INTERNAL_QCHECK(failure_message) \
::absl::log_internal::LogMessageQuietlyFatal(__FILE__, __LINE__, \
failure_message)
#endif // !defined(STRIP_LOG) || !STRIP_LOG
#endif // ABSL_LOG_INTERNAL_STRIP_H_
//
// 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.
#include "absl/log/internal/test_actions.h"
#include <cassert>
#include <iostream>
#include <string>
#include "absl/base/config.h"
#include "absl/log/internal/config.h"
#include "absl/strings/escaping.h"
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {
void WriteToStderrWithFilename::operator()(const absl::LogEntry& entry) const {
std::cerr << message << " (file: " << entry.source_filename() << ")"
<< std::endl;
}
void WriteEntryToStderr::operator()(const absl::LogEntry& entry) const {
if (!message.empty()) std::cerr << message << std::endl;
std::cerr << "LogEntry{\n"
<< " source_filename: \""
<< absl::CHexEscape(entry.source_filename()) << "\"\n"
<< " source_basename: \""
<< absl::CHexEscape(entry.source_basename()) << "\"\n"
<< " source_line: " << entry.source_line() << "\n"
<< " prefix: " << (entry.prefix() ? "true\n" : "false\n")
<< " log_severity: " << entry.log_severity() << "\n"
<< " timestamp: " << entry.timestamp() << "\n"
<< " text_message: \"" << absl::CHexEscape(entry.text_message())
<< "\"\n verbosity: " << entry.verbosity() << "\n"
<< "}" << std::endl;
}
void WriteEntryToStderr::operator()(absl::LogSeverity severity,
absl::string_view filename,
absl::string_view log_message) const {
if (!message.empty()) std::cerr << message << std::endl;
std::cerr << "LogEntry{\n"
<< " source_filename: \"" << absl::CHexEscape(filename) << "\"\n"
<< " log_severity: " << severity << "\n"
<< " text_message: \"" << absl::CHexEscape(log_message) << "}"
<< std::endl;
}
} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl
// 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/internal/test_actions.h
// -----------------------------------------------------------------------------
//
// This file declares Googletest's actions used in the Abseil Logging library
// unit tests.
#ifndef ABSL_LOG_INTERNAL_TEST_ACTIONS_H_
#define ABSL_LOG_INTERNAL_TEST_ACTIONS_H_
#include <iostream>
#include <ostream>
#include <string>
#include "absl/base/config.h"
#include "absl/base/log_severity.h"
#include "absl/log/log_entry.h"
#include "absl/strings/string_view.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {
// These actions are used by the child process in a death test.
//
// Expectations set in the child cannot cause test failure in the parent
// directly. Instead, the child can use these actions with
// `EXPECT_CALL`/`WillOnce` and `ON_CALL`/`WillByDefault` (for unexpected calls)
// to write messages to stderr that the parent can match against.
struct WriteToStderr final {
explicit WriteToStderr(absl::string_view m) : message(m) {}
std::string message;
template <typename... Args>
void operator()(const Args&...) const {
std::cerr << message << std::endl;
}
};
struct WriteToStderrWithFilename final {
explicit WriteToStderrWithFilename(absl::string_view m) : message(m) {}
std::string message;
void operator()(const absl::LogEntry& entry) const;
};
struct WriteEntryToStderr final {
explicit WriteEntryToStderr(absl::string_view m) : message(m) {}
std::string message = "";
void operator()(const absl::LogEntry& entry) const;
void operator()(absl::LogSeverity, absl::string_view,
absl::string_view) const;
};
// See the documentation for `DeathTestValidateExpectations` above.
// `DeathTestExpectedLogging` should be used once in a given death test, and the
// applicable severity level is the one that should be passed to
// `DeathTestValidateExpectations`.
inline WriteEntryToStderr DeathTestExpectedLogging() {
return WriteEntryToStderr{"Mock received expected entry:"};
}
// `DeathTestUnexpectedLogging` should be used zero or more times to mark
// messages that should not hit the logs as the process dies.
inline WriteEntryToStderr DeathTestUnexpectedLogging() {
return WriteEntryToStderr{"Mock received unexpected entry:"};
}
} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_LOG_INTERNAL_TEST_ACTIONS_H_
// 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.
//
#include "absl/log/internal/test_helpers.h"
#ifdef __Fuchsia__
#include <zircon/syscalls.h>
#endif
#include "gtest/gtest.h"
#include "absl/base/config.h"
#include "absl/base/log_severity.h"
#include "absl/log/globals.h"
#include "absl/log/initialize.h"
#include "absl/log/internal/globals.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {
// Returns false if the specified severity level is disabled by
// `ABSL_MIN_LOG_LEVEL` or `absl::MinLogLevel()`.
bool LoggingEnabledAt(absl::LogSeverity severity) {
return severity >= kAbslMinLogLevel && severity >= absl::MinLogLevel();
}
// -----------------------------------------------------------------------------
// Googletest Death Test Predicates
// -----------------------------------------------------------------------------
#if GTEST_HAS_DEATH_TEST
bool DiedOfFatal(int exit_status) {
#if defined(_WIN32)
// Depending on NDEBUG and (configuration?) MSVC's abort either results
// in error code 3 (SIGABRT) or error code 0x80000003 (breakpoint
// triggered).
return ::testing::ExitedWithCode(3)(exit_status & ~0x80000000);
#elif defined(__Fuchsia__)
// The Fuchsia death test implementation kill()'s the process when it detects
// an exception, so it should exit with the corresponding code. See
// FuchsiaDeathTest::Wait().
return ::testing::ExitedWithCode(ZX_TASK_RETCODE_SYSCALL_KILL)(exit_status);
#elif defined(__ANDROID__) && defined(__aarch64__)
// These are all run under a qemu config that eats died-due-to-signal exit
// statuses.
return true;
#else
return ::testing::KilledBySignal(SIGABRT)(exit_status);
#endif
}
bool DiedOfQFatal(int exit_status) {
return ::testing::ExitedWithCode(1)(exit_status);
}
#endif
// -----------------------------------------------------------------------------
// Helper for Log inititalization in test
// -----------------------------------------------------------------------------
void LogTestEnvironment::SetUp() {
if (!absl::log_internal::IsInitialized()) {
absl::InitializeLog();
}
}
} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl
// 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/internal/test_helpers.h
// -----------------------------------------------------------------------------
//
// This file declares testing helpers for the logging library.
#ifndef ABSL_LOG_INTERNAL_TEST_HELPERS_H_
#define ABSL_LOG_INTERNAL_TEST_HELPERS_H_
#include "gtest/gtest.h"
#include "absl/base/config.h"
#include "absl/base/log_severity.h"
#include "absl/log/globals.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {
// `ABSL_MIN_LOG_LEVEL` can't be used directly since it is not always defined.
constexpr auto kAbslMinLogLevel =
#ifdef ABSL_MIN_LOG_LEVEL
static_cast<absl::LogSeverityAtLeast>(ABSL_MIN_LOG_LEVEL);
#else
absl::LogSeverityAtLeast::kInfo;
#endif
// Returns false if the specified severity level is disabled by
// `ABSL_MIN_LOG_LEVEL` or `absl::MinLogLevel()`.
bool LoggingEnabledAt(absl::LogSeverity severity);
// -----------------------------------------------------------------------------
// Googletest Death Test Predicates
// -----------------------------------------------------------------------------
#if GTEST_HAS_DEATH_TEST
bool DiedOfFatal(int exit_status);
bool DiedOfQFatal(int exit_status);
#endif
// -----------------------------------------------------------------------------
// Helper for Log inititalization in test
// -----------------------------------------------------------------------------
class LogTestEnvironment : public ::testing::Environment {
public:
~LogTestEnvironment() override = default;
void SetUp() override;
};
} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_LOG_INTERNAL_TEST_HELPERS_H_
//
// 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.
#include "absl/log/internal/test_matchers.h"
#include <sstream>
#include <string>
#include <utility>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/base/config.h"
#include "absl/log/internal/config.h"
#include "absl/log/internal/test_helpers.h"
#include "absl/strings/string_view.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {
::testing::Matcher<const absl::LogEntry&> SourceFilename(
const ::testing::Matcher<absl::string_view>& source_filename) {
return Property("source_filename", &absl::LogEntry::source_filename,
source_filename);
}
::testing::Matcher<const absl::LogEntry&> SourceBasename(
const ::testing::Matcher<absl::string_view>& source_basename) {
return Property("source_basename", &absl::LogEntry::source_basename,
source_basename);
}
::testing::Matcher<const absl::LogEntry&> SourceLine(
const ::testing::Matcher<int>& source_line) {
return Property("source_line", &absl::LogEntry::source_line, source_line);
}
::testing::Matcher<const absl::LogEntry&> Prefix(
const ::testing::Matcher<bool>& prefix) {
return Property("prefix", &absl::LogEntry::prefix, prefix);
}
::testing::Matcher<const absl::LogEntry&> LogSeverity(
const ::testing::Matcher<absl::LogSeverity>& log_severity) {
return Property("log_severity", &absl::LogEntry::log_severity, log_severity);
}
::testing::Matcher<const absl::LogEntry&> Timestamp(
const ::testing::Matcher<absl::Time>& timestamp) {
return Property("timestamp", &absl::LogEntry::timestamp, timestamp);
}
::testing::Matcher<const absl::LogEntry&> TimestampInMatchWindow() {
return Property("timestamp", &absl::LogEntry::timestamp,
::testing::AllOf(::testing::Ge(absl::Now()),
::testing::Truly([](absl::Time arg) {
return arg <= absl::Now();
})));
}
::testing::Matcher<const absl::LogEntry&> ThreadID(
const ::testing::Matcher<absl::LogEntry::tid_t>& tid) {
return Property("tid", &absl::LogEntry::tid, tid);
}
::testing::Matcher<const absl::LogEntry&> TextMessageWithPrefixAndNewline(
const ::testing::Matcher<absl::string_view>&
text_message_with_prefix_and_newline) {
return Property("text_message_with_prefix_and_newline",
&absl::LogEntry::text_message_with_prefix_and_newline,
text_message_with_prefix_and_newline);
}
::testing::Matcher<const absl::LogEntry&> TextMessageWithPrefix(
const ::testing::Matcher<absl::string_view>& text_message_with_prefix) {
return Property("text_message_with_prefix",
&absl::LogEntry::text_message_with_prefix,
text_message_with_prefix);
}
::testing::Matcher<const absl::LogEntry&> TextMessage(
const ::testing::Matcher<absl::string_view>& text_message) {
return Property("text_message", &absl::LogEntry::text_message, text_message);
}
::testing::Matcher<const absl::LogEntry&> TextPrefix(
const ::testing::Matcher<absl::string_view>& text_prefix) {
return ResultOf(
[](const absl::LogEntry& entry) {
absl::string_view msg = entry.text_message_with_prefix();
msg.remove_suffix(entry.text_message().size());
return msg;
},
text_prefix);
}
::testing::Matcher<const absl::LogEntry&> Verbosity(
const ::testing::Matcher<int>& verbosity) {
return Property("verbosity", &absl::LogEntry::verbosity, verbosity);
}
::testing::Matcher<const absl::LogEntry&> Stacktrace(
const ::testing::Matcher<absl::string_view>& stacktrace) {
return Property("stacktrace", &absl::LogEntry::stacktrace, stacktrace);
}
class MatchesOstreamImpl final
: public ::testing::MatcherInterface<absl::string_view> {
public:
explicit MatchesOstreamImpl(std::string expected)
: expected_(std::move(expected)) {}
bool MatchAndExplain(absl::string_view actual,
::testing::MatchResultListener*) const override {
return actual == expected_;
}
void DescribeTo(std::ostream* os) const override {
*os << "matches the contents of the ostringstream, which are \""
<< expected_ << "\"";
}
void DescribeNegationTo(std::ostream* os) const override {
*os << "does not match the contents of the ostringstream, which are \""
<< expected_ << "\"";
}
private:
const std::string expected_;
};
::testing::Matcher<absl::string_view> MatchesOstream(
const std::ostringstream& stream) {
return ::testing::MakeMatcher(new MatchesOstreamImpl(stream.str()));
}
// We need to validate what is and isn't logged as the process dies due to
// `FATAL`, `QFATAL`, `CHECK`, etc., but assertions inside a death test
// subprocess don't directly affect the pass/fail status of the parent process.
// Instead, we use the mock actions `DeathTestExpectedLogging` and
// `DeathTestUnexpectedLogging` to write specific phrases to `stderr` that we
// can validate in the parent process using this matcher.
::testing::Matcher<const std::string&> DeathTestValidateExpectations() {
if (log_internal::LoggingEnabledAt(absl::LogSeverity::kFatal)) {
return ::testing::Matcher<const std::string&>(::testing::AllOf(
::testing::HasSubstr("Mock received expected entry"),
Not(::testing::HasSubstr("Mock received unexpected entry"))));
}
// If `FATAL` logging is disabled, neither message should have been written.
return ::testing::Matcher<const std::string&>(::testing::AllOf(
Not(::testing::HasSubstr("Mock received expected entry")),
Not(::testing::HasSubstr("Mock received unexpected entry"))));
}
} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl
// 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/internal/test_matchers.h
// -----------------------------------------------------------------------------
//
// This file declares Googletest's matchers used in the Abseil Logging library
// unit tests.
#ifndef ABSL_LOG_INTERNAL_TEST_MATCHERS_H_
#define ABSL_LOG_INTERNAL_TEST_MATCHERS_H_
#include <iosfwd>
#include <sstream>
#include <string>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/base/config.h"
#include "absl/base/log_severity.h"
#include "absl/log/internal/config.h"
#include "absl/log/internal/test_helpers.h"
#include "absl/log/log_entry.h"
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {
// These matchers correspond to the components of `absl::LogEntry`.
::testing::Matcher<const absl::LogEntry&> SourceFilename(
const ::testing::Matcher<absl::string_view>& source_filename);
::testing::Matcher<const absl::LogEntry&> SourceBasename(
const ::testing::Matcher<absl::string_view>& source_basename);
// Be careful with this one; multi-line statements using `__LINE__` evaluate
// differently on different platforms. In particular, the MSVC implementation
// of `EXPECT_DEATH` returns the line number of the macro expansion to all lines
// within the code block that's expected to die.
::testing::Matcher<const absl::LogEntry&> SourceLine(
const ::testing::Matcher<int>& source_line);
::testing::Matcher<const absl::LogEntry&> Prefix(
const ::testing::Matcher<bool>& prefix);
::testing::Matcher<const absl::LogEntry&> LogSeverity(
const ::testing::Matcher<absl::LogSeverity>& log_severity);
::testing::Matcher<const absl::LogEntry&> Timestamp(
const ::testing::Matcher<absl::Time>& timestamp);
// Matches if the `LogEntry`'s timestamp falls after the instantiation of this
// matcher and before its execution, as is normal when used with EXPECT_CALL.
::testing::Matcher<const absl::LogEntry&> TimestampInMatchWindow();
::testing::Matcher<const absl::LogEntry&> ThreadID(
const ::testing::Matcher<absl::LogEntry::tid_t>&);
::testing::Matcher<const absl::LogEntry&> TextMessageWithPrefixAndNewline(
const ::testing::Matcher<absl::string_view>&
text_message_with_prefix_and_newline);
::testing::Matcher<const absl::LogEntry&> TextMessageWithPrefix(
const ::testing::Matcher<absl::string_view>& text_message_with_prefix);
::testing::Matcher<const absl::LogEntry&> TextMessage(
const ::testing::Matcher<absl::string_view>& text_message);
::testing::Matcher<const absl::LogEntry&> TextPrefix(
const ::testing::Matcher<absl::string_view>& text_prefix);
::testing::Matcher<const absl::LogEntry&> Verbosity(
const ::testing::Matcher<int>& verbosity);
::testing::Matcher<const absl::LogEntry&> Stacktrace(
const ::testing::Matcher<absl::string_view>& stacktrace);
// Behaves as `Eq(stream.str())`, but produces better failure messages.
::testing::Matcher<absl::string_view> MatchesOstream(
const std::ostringstream& stream);
::testing::Matcher<const std::string&> DeathTestValidateExpectations();
// This feature coming soon =).
#define ENCODED_MESSAGE(message_matcher) ::testing::_
} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_LOG_INTERNAL_TEST_MATCHERS_H_
// 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/internal/voidify.h
// -----------------------------------------------------------------------------
//
// This class is used to explicitly ignore values in the conditional logging
// macros. This avoids compiler warnings like "value computed is not used" and
// "statement has no effect".
#ifndef ABSL_LOG_INTERNAL_VOIDIFY_H_
#define ABSL_LOG_INTERNAL_VOIDIFY_H_
#include "absl/base/config.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {
class Voidify final {
public:
// This has to be an operator with a precedence lower than << but higher than
// ?:
template <typename T>
void operator&&(const T&) const&& {}
};
} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_LOG_INTERNAL_VOIDIFY_H_
This diff is collapsed. Click to expand it.
// 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.
#include "absl/base/attributes.h"
#include "absl/base/log_severity.h"
#include "absl/flags/flag.h"
#include "absl/log/check.h"
#include "absl/log/globals.h"
#include "absl/log/log.h"
#include "absl/log/log_entry.h"
#include "absl/log/log_sink.h"
#include "absl/log/log_sink_registry.h"
#include "benchmark/benchmark.h"
namespace {
class NullLogSink : public absl::LogSink {
public:
NullLogSink() { absl::AddLogSink(this); }
~NullLogSink() override { absl::RemoveLogSink(this); }
void Send(const absl::LogEntry&) override {}
};
constexpr int x = -1;
void BM_SuccessfulBinaryCheck(benchmark::State& state) {
int n = 0;
while (state.KeepRunningBatch(8)) {
CHECK_GE(n, x);
CHECK_GE(n, x);
CHECK_GE(n, x);
CHECK_GE(n, x);
CHECK_GE(n, x);
CHECK_GE(n, x);
CHECK_GE(n, x);
CHECK_GE(n, x);
++n;
}
benchmark::DoNotOptimize(n);
}
BENCHMARK(BM_SuccessfulBinaryCheck);
static void BM_SuccessfulUnaryCheck(benchmark::State& state) {
int n = 0;
while (state.KeepRunningBatch(8)) {
CHECK(n >= x);
CHECK(n >= x);
CHECK(n >= x);
CHECK(n >= x);
CHECK(n >= x);
CHECK(n >= x);
CHECK(n >= x);
CHECK(n >= x);
++n;
}
benchmark::DoNotOptimize(n);
}
BENCHMARK(BM_SuccessfulUnaryCheck);
static void BM_DisabledLogOverhead(benchmark::State& state) {
absl::ScopedStderrThreshold disable_stderr_logging(
absl::LogSeverityAtLeast::kInfinity);
absl::log_internal::ScopedMinLogLevel scoped_min_log_level(
absl::LogSeverityAtLeast::kInfinity);
for (auto _ : state) {
LOG(INFO);
}
}
BENCHMARK(BM_DisabledLogOverhead);
static void BM_EnabledLogOverhead(benchmark::State& state) {
absl::ScopedStderrThreshold stderr_logging(
absl::LogSeverityAtLeast::kInfinity);
absl::log_internal::ScopedMinLogLevel scoped_min_log_level(
absl::LogSeverityAtLeast::kInfo);
ABSL_ATTRIBUTE_UNUSED NullLogSink null_sink;
for (auto _ : state) {
LOG(INFO);
}
}
BENCHMARK(BM_EnabledLogOverhead);
} // namespace
//
// 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.
#include "absl/log/log_entry.h"
#include "absl/base/config.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
constexpr int LogEntry::kNoVerbosityLevel;
constexpr int LogEntry::kNoVerboseLevel;
#endif
ABSL_NAMESPACE_END
} // namespace absl
// 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_entry.h
// -----------------------------------------------------------------------------
//
// This header declares `class absl::LogEntry`, which represents a log record as
// passed to `LogSink::Send`. Data returned by pointer or by reference or by
// `absl::string_view` must be copied if they are needed after the lifetime of
// the `absl::LogEntry`.
#ifndef ABSL_LOG_LOG_ENTRY_H_
#define ABSL_LOG_LOG_ENTRY_H_
#include <cstddef>
#include <string>
#include "absl/base/config.h"
#include "absl/base/log_severity.h"
#include "absl/log/internal/config.h"
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
#include "absl/types/span.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {
// Test only friend.
class LogEntryTestPeer;
class LogMessage;
} // namespace log_internal
// LogEntry
//
// Represents a single entry in a log, i.e., one log message.
//
// LogEntry is copyable and thread-compatible.
class LogEntry final {
public:
using tid_t = log_internal::Tid;
// For non-verbose log entries, `verbosity()` returns `kNoVerbosityLevel`.
static constexpr int kNoVerbosityLevel = -1;
static constexpr int kNoVerboseLevel = -1; // TO BE removed
LogEntry(const LogEntry&) = default;
LogEntry& operator=(const LogEntry&) = default;
// Source file and line where the log message occurred.
// Take special care not to dereference the pointers returned by
// source_filename() and source_basename() after the lifetime of the
// `LogEntry`. This will usually work, because these are usually backed by a
// statically allocated char array obtained from the `__FILE__` macro, but
// it is nevertheless incorrect and will be broken by statements like
// `LOG(INFO).AtLocation(...)` (see above). If you need the data later, you
// must copy it.
absl::string_view source_filename() const { return full_filename_; }
absl::string_view source_basename() const { return base_filename_; }
int source_line() const { return line_; }
// LogEntry::prefix()
//
// True unless cleared by LOG(...).NoPrefix(), which indicates suppression of
// the line prefix containing metadata like file, line, timestamp, etc.
bool prefix() const { return prefix_; }
// LogEntry::log_severity()
//
// Returns this LogEntry's severity.
absl::LogSeverity log_severity() const { return severity_; }
// LogEntry::verbosity()
//
// Returns this LogEntry's verbosity, or kNoVerbosityLevel for a non-verbose
// LogEntry.
int verbosity() const { return verbose_level_; }
// LogEntry::timestamp()
//
// Returns the time at which this LogEntry was written.
absl::Time timestamp() const { return timestamp_; }
// LogEntry::tid()
//
// Returns the id of the thread that wrote this LogEntry.
tid_t tid() const { return tid_; }
// Text-formatted version of the log message. An underlying buffer holds:
//
// * A prefix formed by formatting metadata (timestamp, filename, line number,
// etc.)
// * The streamed data
// * A newline
// * A nul terminator
//
// These methods give access to the most commonly-used substrings of the
// buffer's contents. Other combinations can be obtained with substring
// arithmetic.
absl::string_view text_message_with_prefix_and_newline() const {
return absl::string_view(
text_message_with_prefix_and_newline_and_nul_.data(),
text_message_with_prefix_and_newline_and_nul_.size() - 1);
}
absl::string_view text_message_with_prefix() const {
return absl::string_view(
text_message_with_prefix_and_newline_and_nul_.data(),
text_message_with_prefix_and_newline_and_nul_.size() - 2);
}
absl::string_view text_message_with_newline() const {
return absl::string_view(
text_message_with_prefix_and_newline_and_nul_.data() + prefix_len_,
text_message_with_prefix_and_newline_and_nul_.size() - prefix_len_ - 1);
}
absl::string_view text_message() const {
return absl::string_view(
text_message_with_prefix_and_newline_and_nul_.data() + prefix_len_,
text_message_with_prefix_and_newline_and_nul_.size() - prefix_len_ - 2);
}
const char* text_message_with_prefix_and_newline_c_str() const {
return text_message_with_prefix_and_newline_and_nul_.data();
}
// LogEntry::stacktrace()
//
// Optional stacktrace, e.g., for `FATAL` logs.
absl::string_view stacktrace() const { return stacktrace_; }
private:
LogEntry() = default;
absl::string_view full_filename_;
absl::string_view base_filename_;
int line_;
bool prefix_;
absl::LogSeverity severity_;
int verbose_level_; // >=0 for `VLOG`, etc.; otherwise `kNoVerbosityLevel`.
absl::Time timestamp_;
tid_t tid_;
absl::Span<const char> text_message_with_prefix_and_newline_and_nul_;
size_t prefix_len_;
std::string stacktrace_;
friend class log_internal::LogEntryTestPeer;
friend class log_internal::LogMessage;
};
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_LOG_LOG_ENTRY_H_
//
// 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.
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/base/attributes.h"
#include "absl/base/log_severity.h"
#include "absl/log/log.h"
#include "absl/log/scoped_mock_log.h"
namespace {
using ::testing::_;
using ::testing::Eq;
namespace not_absl {
class Dummy {
public:
Dummy() {}
private:
Dummy(const Dummy&) = delete;
Dummy& operator=(const Dummy&) = delete;
};
// This line tests that local definitions of INFO, WARNING, ERROR, and
// etc don't shadow the global ones used by the logging macros. If
// they do, the LOG() calls in the tests won't compile, catching the
// bug.
const Dummy INFO, WARNING, ERROR, FATAL, NUM_SEVERITIES;
// These makes sure that the uses of same-named types in the
// implementation of the logging macros are fully qualified.
class string {};
class vector {};
class LogMessage {};
class LogMessageFatal {};
class LogMessageQuietlyFatal {};
class LogMessageVoidify {};
class LogSink {};
class NullStream {};
class NullStreamFatal {};
} // namespace not_absl
using namespace not_absl; // NOLINT
// Tests for LOG(LEVEL(()).
TEST(LogHygieneTest, WorksForQualifiedSeverity) {
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
::testing::InSequence seq;
EXPECT_CALL(test_sink, Log(absl::LogSeverity::kInfo, _, "To INFO"));
EXPECT_CALL(test_sink, Log(absl::LogSeverity::kWarning, _, "To WARNING"));
EXPECT_CALL(test_sink, Log(absl::LogSeverity::kError, _, "To ERROR"));
test_sink.StartCapturingLogs();
// Note that LOG(LEVEL()) expects the severity as a run-time
// expression (as opposed to a compile-time constant). Hence we
// test that :: is allowed before INFO, etc.
LOG(LEVEL(absl::LogSeverity::kInfo)) << "To INFO";
LOG(LEVEL(absl::LogSeverity::kWarning)) << "To WARNING";
LOG(LEVEL(absl::LogSeverity::kError)) << "To ERROR";
}
TEST(LogHygieneTest, WorksWithAlternativeINFOSymbol) {
const double INFO ABSL_ATTRIBUTE_UNUSED = 7.77;
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
EXPECT_CALL(test_sink, Log(absl::LogSeverity::kInfo, _, "Hello world"));
test_sink.StartCapturingLogs();
LOG(INFO) << "Hello world";
}
TEST(LogHygieneTest, WorksWithAlternativeWARNINGSymbol) {
const double WARNING ABSL_ATTRIBUTE_UNUSED = 7.77;
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
EXPECT_CALL(test_sink, Log(absl::LogSeverity::kWarning, _, "Hello world"));
test_sink.StartCapturingLogs();
LOG(WARNING) << "Hello world";
}
TEST(LogHygieneTest, WorksWithAlternativeERRORSymbol) {
const double ERROR ABSL_ATTRIBUTE_UNUSED = 7.77;
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
EXPECT_CALL(test_sink, Log(absl::LogSeverity::kError, _, "Hello world"));
test_sink.StartCapturingLogs();
LOG(ERROR) << "Hello world";
}
TEST(LogHygieneTest, WorksWithAlternativeLEVELSymbol) {
const double LEVEL ABSL_ATTRIBUTE_UNUSED = 7.77;
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
EXPECT_CALL(test_sink, Log(absl::LogSeverity::kError, _, "Hello world"));
test_sink.StartCapturingLogs();
LOG(LEVEL(absl::LogSeverity::kError)) << "Hello world";
}
#define INFO Bogus
#ifdef NDEBUG
constexpr bool IsOptimized = false;
#else
constexpr bool IsOptimized = true;
#endif
TEST(LogHygieneTest, WorksWithINFODefined) {
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
EXPECT_CALL(test_sink, Log(absl::LogSeverity::kInfo, _, "Hello world"))
.Times(2 + (IsOptimized ? 2 : 0));
test_sink.StartCapturingLogs();
LOG(INFO) << "Hello world";
LOG_IF(INFO, true) << "Hello world";
DLOG(INFO) << "Hello world";
DLOG_IF(INFO, true) << "Hello world";
}
#undef INFO
TEST(LogHygieneTest, ExpressionEvaluationInLEVELSeverity) {
auto i = static_cast<int>(absl::LogSeverity::kInfo);
LOG(LEVEL(++i)) << "hello world"; // NOLINT
EXPECT_THAT(i, Eq(static_cast<int>(absl::LogSeverity::kInfo) + 1));
}
TEST(LogHygieneTest, ExpressionEvaluationInStreamedMessage) {
int i = 0;
LOG(INFO) << ++i;
EXPECT_THAT(i, 1);
LOG_IF(INFO, false) << ++i;
EXPECT_THAT(i, 1);
}
// Tests that macros are usable in unbraced switch statements.
// -----------------------------------------------------------
class UnbracedSwitchCompileTest {
static void Log() {
switch (0) {
case 0:
LOG(INFO);
break;
default:
break;
}
}
};
} // namespace
//
// 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.
#include <errno.h>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/log/internal/test_actions.h"
#include "absl/log/internal/test_helpers.h"
#include "absl/log/internal/test_matchers.h"
#include "absl/log/log.h"
#include "absl/log/log_sink.h"
#include "absl/log/scoped_mock_log.h"
#include "absl/strings/match.h"
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
namespace {
#if GTEST_HAS_DEATH_TEST
using ::absl::log_internal::DeathTestExpectedLogging;
using ::absl::log_internal::DeathTestUnexpectedLogging;
using ::absl::log_internal::DeathTestValidateExpectations;
using ::absl::log_internal::DiedOfQFatal;
#endif
using ::absl::log_internal::LogSeverity;
using ::absl::log_internal::Prefix;
using ::absl::log_internal::SourceBasename;
using ::absl::log_internal::SourceFilename;
using ::absl::log_internal::SourceLine;
using ::absl::log_internal::Stacktrace;
using ::absl::log_internal::TextMessage;
using ::absl::log_internal::TextMessageWithPrefix;
using ::absl::log_internal::TextMessageWithPrefixAndNewline;
using ::absl::log_internal::TextPrefix;
using ::absl::log_internal::ThreadID;
using ::absl::log_internal::Timestamp;
using ::absl::log_internal::Verbosity;
using ::testing::AllOf;
using ::testing::AnyNumber;
using ::testing::AnyOf;
using ::testing::Eq;
using ::testing::IsEmpty;
using ::testing::IsFalse;
using ::testing::Truly;
TEST(TailCallsModifiesTest, AtLocationFileLine) {
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
EXPECT_CALL(
test_sink,
Send(AllOf(
// The metadata should change:
SourceFilename(Eq("/my/very/very/very_long_source_file.cc")),
SourceBasename(Eq("very_long_source_file.cc")), SourceLine(Eq(777)),
// The logged line should change too, even though the prefix must
// grow to fit the new metadata.
TextMessageWithPrefix(Truly([](absl::string_view msg) {
return absl::EndsWith(msg,
" very_long_source_file.cc:777] hello world");
})))));
test_sink.StartCapturingLogs();
LOG(INFO).AtLocation("/my/very/very/very_long_source_file.cc", 777)
<< "hello world";
}
TEST(TailCallsModifiesTest, NoPrefix) {
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
EXPECT_CALL(test_sink, Send(AllOf(Prefix(IsFalse()), TextPrefix(IsEmpty()),
TextMessageWithPrefix(Eq("hello world")))));
test_sink.StartCapturingLogs();
LOG(INFO).NoPrefix() << "hello world";
}
TEST(TailCallsModifiesTest, NoPrefixNoMessageNoShirtNoShoesNoService) {
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
EXPECT_CALL(test_sink,
Send(AllOf(Prefix(IsFalse()), TextPrefix(IsEmpty()),
TextMessageWithPrefix(IsEmpty()),
TextMessageWithPrefixAndNewline(Eq("\n")))));
test_sink.StartCapturingLogs();
LOG(INFO).NoPrefix();
}
TEST(TailCallsModifiesTest, WithVerbosity) {
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
EXPECT_CALL(test_sink, Send(Verbosity(Eq(2))));
test_sink.StartCapturingLogs();
LOG(INFO).WithVerbosity(2) << "hello world";
}
TEST(TailCallsModifiesTest, WithVerbosityNoVerbosity) {
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
EXPECT_CALL(test_sink,
Send(Verbosity(Eq(absl::LogEntry::kNoVerbosityLevel))));
test_sink.StartCapturingLogs();
LOG(INFO).WithVerbosity(2).WithVerbosity(absl::LogEntry::kNoVerbosityLevel)
<< "hello world";
}
TEST(TailCallsModifiesTest, WithTimestamp) {
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
EXPECT_CALL(test_sink, Send(Timestamp(Eq(absl::UnixEpoch()))));
test_sink.StartCapturingLogs();
LOG(INFO).WithTimestamp(absl::UnixEpoch()) << "hello world";
}
TEST(TailCallsModifiesTest, WithThreadID) {
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
EXPECT_CALL(test_sink, Send(AllOf(ThreadID(Eq(1234)))));
test_sink.StartCapturingLogs();
LOG(INFO).WithThreadID(1234) << "hello world";
}
TEST(TailCallsModifiesTest, WithMetadataFrom) {
class ForwardingLogSink : public absl::LogSink {
public:
void Send(const absl::LogEntry &entry) override {
LOG(LEVEL(entry.log_severity())).WithMetadataFrom(entry)
<< "forwarded: " << entry.text_message();
}
} forwarding_sink;
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
EXPECT_CALL(
test_sink,
Send(AllOf(SourceFilename(Eq("fake/file")), SourceBasename(Eq("file")),
SourceLine(Eq(123)), Prefix(IsFalse()),
LogSeverity(Eq(absl::LogSeverity::kWarning)),
Timestamp(Eq(absl::UnixEpoch())), ThreadID(Eq(456)),
TextMessage(Eq("forwarded: hello world")), Verbosity(Eq(7)),
ENCODED_MESSAGE(
EqualsProto(R"pb(value { literal: "forwarded: " }
value { str: "hello world" })pb")))));
test_sink.StartCapturingLogs();
LOG(WARNING)
.AtLocation("fake/file", 123)
.NoPrefix()
.WithTimestamp(absl::UnixEpoch())
.WithThreadID(456)
.WithVerbosity(7)
.ToSinkOnly(&forwarding_sink)
<< "hello world";
}
TEST(TailCallsModifiesTest, WithPerror) {
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
EXPECT_CALL(
test_sink,
Send(AllOf(TextMessage(AnyOf(Eq("hello world: Bad file number [9]"),
Eq("hello world: Bad file descriptor [9]"),
Eq("hello world: Bad file descriptor [8]"))),
ENCODED_MESSAGE(
AnyOf(EqualsProto(R"pb(value { literal: "hello world" }
value { literal: ": " }
value { str: "Bad file number" }
value { literal: " [" }
value { str: "9" }
value { literal: "]" })pb"),
EqualsProto(R"pb(value { literal: "hello world" }
value { literal: ": " }
value { str: "Bad file descriptor" }
value { literal: " [" }
value { str: "9" }
value { literal: "]" })pb"),
EqualsProto(R"pb(value { literal: "hello world" }
value { literal: ": " }
value { str: "Bad file descriptor" }
value { literal: " [" }
value { str: "8" }
value { literal: "]" })pb"))))));
test_sink.StartCapturingLogs();
errno = EBADF;
LOG(INFO).WithPerror() << "hello world";
}
#if GTEST_HAS_DEATH_TEST
TEST(ModifierMethodDeathTest, ToSinkOnlyQFatal) {
EXPECT_EXIT(
{
absl::ScopedMockLog test_sink(
absl::MockLogDefault::kDisallowUnexpected);
auto do_log = [&test_sink] {
LOG(QFATAL).ToSinkOnly(&test_sink.UseAsLocalSink()) << "hello world";
};
EXPECT_CALL(test_sink, Send)
.Times(AnyNumber())
.WillRepeatedly(DeathTestUnexpectedLogging());
EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("hello world")),
Stacktrace(IsEmpty()))))
.WillOnce(DeathTestExpectedLogging());
test_sink.StartCapturingLogs();
do_log();
},
DiedOfQFatal, DeathTestValidateExpectations());
}
#endif
} // namespace
// 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.
#include "absl/log/log_sink.h"
#include "absl/base/config.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
void LogSink::KeyFunction() const {}
ABSL_NAMESPACE_END
} // namespace absl
// 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_sink.h
// -----------------------------------------------------------------------------
//
// This header declares the interface class `absl::LogSink`.
#ifndef ABSL_LOG_LOG_SINK_H_
#define ABSL_LOG_LOG_SINK_H_
#include "absl/base/config.h"
#include "absl/log/log_entry.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
// absl::LogSink
//
// `absl::LogSink` is an interface which can be extended to intercept and
// process particular messages (with `LOG.ToSinkOnly()` or
// `LOG.ToSinkAlso()`) or all messages (if registered with
// `absl::AddLogSink`). Implementations must be thread-safe, and should take
// care not to take any locks that might be held by the `LOG` caller.
class LogSink {
public:
virtual ~LogSink() = default;
// LogSink::Send()
//
// `Send` is called synchronously during the log statement.
//
// It is safe to use `LOG` within an implementation of `Send`. `ToSinkOnly`
// and `ToSinkAlso` are safe in general but can be used to create an infinite
// loop if you try.
virtual void Send(const absl::LogEntry& entry) = 0;
// LogSink::Flush()
//
// Sinks that buffer messages should override this method to flush the buffer
// and return.
virtual void Flush() {}
private:
// https://lld.llvm.org/missingkeyfunction.html#missing-key-function
virtual void KeyFunction() const final; // NOLINT(readability/inheritance)
};
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_LOG_LOG_SINK_H_
// 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_sink_registry.h
// -----------------------------------------------------------------------------
//
// This header declares APIs to operate on global set of registered log sinks.
#ifndef ABSL_LOG_LOG_SINK_REGISTRY_H_
#define ABSL_LOG_LOG_SINK_REGISTRY_H_
#include "absl/base/config.h"
#include "absl/log/internal/log_sink_set.h"
#include "absl/log/log_sink.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
// AddLogSink(), RemoveLogSink()
//
// Adds or removes a `absl::LogSink` as a consumer of logging data.
//
// These functions are thread-safe.
//
// It is an error to attempt to add a sink that's already registered or to
// attempt to remove one that isn't.
//
// To avoid unbounded recursion, dispatch to registered `absl::LogSink`s is
// disabled per-thread while running the `Send()` method of registered
// `absl::LogSink`s. Affected messages are dispatched to a special internal
// sink instead which writes them to `stderr`.
//
// Do not call these inside `absl::LogSink::Send`.
inline void AddLogSink(absl::LogSink* sink) { log_internal::AddLogSink(sink); }
inline void RemoveLogSink(absl::LogSink* sink) {
log_internal::RemoveLogSink(sink);
}
// FlushLogSinks()
//
// Calls `absl::LogSink::Flush` on all registered sinks.
//
// Do not call this inside `absl::LogSink::Send`.
inline void FlushLogSinks() { log_internal::FlushLogSinks(); }
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_LOG_LOG_SINK_REGISTRY_H_
// 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_streamer.h
// -----------------------------------------------------------------------------
//
// This header declares the class `LogStreamer` and convenience functions to
// construct LogStreamer objects with different associated log severity levels.
#ifndef ABSL_LOG_LOG_STREAMER_H_
#define ABSL_LOG_LOG_STREAMER_H_
#include <ios>
#include <memory>
#include <ostream>
#include <string>
#include <utility>
#include "absl/base/config.h"
#include "absl/base/log_severity.h"
#include "absl/log/log.h"
#include "absl/memory/memory.h"
#include "absl/strings/internal/ostringstream.h"
#include "absl/strings/string_view.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
// LogStreamer
//
// Although you can stream into `LOG(INFO)`, you can't pass it into a function
// that takes a `std::ostream` parameter. `LogStreamer::stream()` provides a
// `std::ostream` that buffers everything that's streamed in. The buffer's
// contents are logged as if by `LOG` when the `LogStreamer` is destroyed.
// If nothing is streamed in, an empty message is logged. If the specified
// severity is `absl::LogSeverity::kFatal`, the program will be terminated when
// the `LogStreamer` is destroyed regardless of whether any data were streamed
// in.
//
// Factory functions corresponding to the `absl::LogSeverity` enumerators
// are provided for convenience; if the desired severity is variable, invoke the
// constructor directly.
//
// LogStreamer is movable, but not copyable.
//
// Examples:
//
// ShaveYakAndWriteToStream(
// yak, absl::LogInfoStreamer(__FILE__, __LINE__).stream());
//
// {
// // This logs a single line containing data streamed by all three function
// // calls.
// absl::LogStreamer streamer(absl::LogSeverity::kInfo, __FILE__, __LINE__);
// ShaveYakAndWriteToStream(yak1, streamer.stream());
// streamer.stream() << " ";
// ShaveYakAndWriteToStream(yak2, streamer.stream());
// streamer.stream() << " ";
// ShaveYakAndWriteToStreamPointer(yak3, &streamer.stream());
// }
class LogStreamer final {
public:
// LogStreamer::LogStreamer()
//
// Creates a LogStreamer with a given `severity` that will log a message
// attributed to the given `file` and `line`.
explicit LogStreamer(absl::LogSeverity severity, absl::string_view file,
int line)
: severity_(severity),
line_(line),
file_(file),
stream_(
absl::make_unique<absl::strings_internal::OStringStream>(&buf_)) {
// To match `LOG`'s defaults:
stream_->setf(std::ios_base::showbase | std::ios_base::boolalpha);
}
// A moved-from `absl::LogStreamer` does not `LOG` when destroyed,
// and a program that streams into one has undefined behavior.
LogStreamer(LogStreamer&& that) noexcept
: severity_(that.severity_),
line_(that.line_),
file_(std::move(that.file_)),
buf_(std::move(that.buf_)),
stream_(that.stream_
? absl::make_unique<absl::strings_internal::OStringStream>(
&buf_)
: nullptr) {
that.stream_.reset();
}
LogStreamer& operator=(LogStreamer&& that) {
LOG_IF(LEVEL(severity_), stream_).AtLocation(file_, line_) << buf_;
severity_ = that.severity_;
file_ = std::move(that.file_);
line_ = that.line_;
buf_ = std::move(that.buf_);
stream_ =
that.stream_
? absl::make_unique<absl::strings_internal::OStringStream>(&buf_)
: nullptr;
that.stream_.reset();
return *this;
}
// LogStreamer::~LogStreamer()
//
// Logs this LogStreamer's buffered content as if by LOG.
~LogStreamer() {
LOG_IF(LEVEL(severity_), stream_).AtLocation(file_, line_) << buf_;
}
// LogStreamer::stream()
//
// Returns the `std::ostream` to use to write into this LogStreamer' internal
// buffer.
std::ostream& stream() { return *stream_; }
private:
absl::LogSeverity severity_;
int line_;
std::string file_;
std::string buf_;
// TODO(durandal): de-pointerize this once we are off of our old mostly-C++11
// libstdc++ (which lacks move constructors for std streams).
// `stream_` is null in a moved-from `LogStreamer`; this is in fact how we
// recognize one to avoid logging when it is destroyed or reassigned.
std::unique_ptr<absl::strings_internal::OStringStream> stream_;
};
// LogInfoStreamer()
//
// Returns a LogStreamer that writes at level LogSeverity::kInfo.
inline LogStreamer LogInfoStreamer(absl::string_view file, int line) {
return absl::LogStreamer(absl::LogSeverity::kInfo, file, line);
}
// LogWarningStreamer()
//
// Returns a LogStreamer that writes at level LogSeverity::kWarning.
inline LogStreamer LogWarningStreamer(absl::string_view file, int line) {
return absl::LogStreamer(absl::LogSeverity::kWarning, file, line);
}
// LogErrorStreamer()
//
// Returns a LogStreamer that writes at level LogSeverity::kError.
inline LogStreamer LogErrorStreamer(absl::string_view file, int line) {
return absl::LogStreamer(absl::LogSeverity::kError, file, line);
}
// LogFatalStreamer()
//
// Returns a LogStreamer that writes at level LogSeverity::kFatal.
//
// The program will be terminated when this `LogStreamer` is destroyed,
// regardless of whether any data were streamed in.
inline LogStreamer LogFatalStreamer(absl::string_view file, int line) {
return absl::LogStreamer(absl::LogSeverity::kFatal, file, line);
}
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_LOG_LOG_STREAMER_H_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment