mirror of
https://github.com/abseil/abseil-cpp.git
synced 2026-06-04 12:07:05 +08:00
Also, add a GoogleTest debug `PrintTo` routine for `LogEntry`, so that unexpected calls to `ScopedMockLog::Send` print metadata legibly. PiperOrigin-RevId: 790735226 Change-Id: If21821812a9b7ecfaefef9ea5085f161f9331cf4
264 lines
8.8 KiB
C++
264 lines
8.8 KiB
C++
// Copyright 2025 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 <cstddef>
|
|
#include <cstdint>
|
|
#include <iomanip>
|
|
#include <ios>
|
|
#include <ostream>
|
|
|
|
#include "absl/base/config.h"
|
|
#include "absl/log/internal/proto.h"
|
|
#include "absl/strings/escaping.h"
|
|
#include "absl/strings/string_view.h"
|
|
#include "absl/time/time.h"
|
|
#include "absl/types/span.h"
|
|
|
|
namespace absl {
|
|
ABSL_NAMESPACE_BEGIN
|
|
namespace {
|
|
// message `logging.proto.Event`
|
|
enum EventTag : uint8_t {
|
|
kFileName = 2,
|
|
kFileLine = 3,
|
|
kTimeNsecs = 4,
|
|
kSeverity = 5,
|
|
kThreadId = 6,
|
|
kValue = 7,
|
|
kSequenceNumber = 9,
|
|
kThreadName = 10,
|
|
};
|
|
|
|
// message `logging.proto.Value`
|
|
enum ValueTag : uint8_t {
|
|
kString = 1,
|
|
kStringLiteral = 6,
|
|
};
|
|
|
|
// enum `logging.proto.Severity`
|
|
enum Severity : int {
|
|
FINEST = 300,
|
|
FINER = 400,
|
|
FINE = 500,
|
|
VERBOSE_0 = 600,
|
|
CONFIG = 700,
|
|
INFO = 800,
|
|
NOTICE = 850,
|
|
WARNING = 900,
|
|
ERROR = 950,
|
|
SEVERE = 1000,
|
|
FATAL = 1100,
|
|
};
|
|
|
|
void PrintEscapedRangeTo(const absl::string_view str,
|
|
const absl::string_view substr, std::ostream* os) {
|
|
const absl::string_view head =
|
|
str.substr(0, static_cast<size_t>(substr.data() - str.data()));
|
|
const char old_fill = os->fill();
|
|
const auto old_flags = os->flags();
|
|
*os << std::right
|
|
<< std::setw(static_cast<int>(absl::CHexEscape(head).size())) << "";
|
|
switch (substr.size()) {
|
|
case 0:
|
|
*os << "\\";
|
|
break;
|
|
case 1:
|
|
*os << "^";
|
|
break;
|
|
default:
|
|
*os << "[" << std::setw(static_cast<int>(absl::CHexEscape(substr).size()))
|
|
<< std::setfill('-') << ")";
|
|
break;
|
|
}
|
|
os->fill(old_fill);
|
|
os->flags(old_flags);
|
|
}
|
|
} // namespace
|
|
void PrintTo(const LogEntry& entry, std::ostream* os) {
|
|
auto text_message_with_prefix_and_newline_and_nul = absl::string_view(
|
|
entry.text_message_with_prefix_and_newline_and_nul_.data(),
|
|
entry.text_message_with_prefix_and_newline_and_nul_.size());
|
|
*os << "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: " << std::boolalpha << entry.prefix() << "\n"
|
|
<< " log_severity: " << entry.log_severity() << "\n"
|
|
<< " verbosity: " << entry.verbosity();
|
|
if (entry.verbosity() == absl::LogEntry::kNoVerbosityLevel) {
|
|
*os << " (kNoVerbosityLevel)";
|
|
}
|
|
*os << "\n"
|
|
<< " timestamp: " << entry.timestamp() << "\n"
|
|
<< " tid: " << entry.tid() << "\n"
|
|
<< " text_message_with_prefix_and_newline_and_nul_: \""
|
|
<< absl::CHexEscape(text_message_with_prefix_and_newline_and_nul)
|
|
<< "\"\n"
|
|
<< " text_message_with_prefix_and_newline: ";
|
|
PrintEscapedRangeTo(text_message_with_prefix_and_newline_and_nul,
|
|
entry.text_message_with_prefix_and_newline(), os);
|
|
*os << "\n"
|
|
<< " text_message_with_prefix: ";
|
|
PrintEscapedRangeTo(text_message_with_prefix_and_newline_and_nul,
|
|
entry.text_message_with_prefix(), os);
|
|
*os << "\n"
|
|
<< " text_message_with_newline: ";
|
|
PrintEscapedRangeTo(text_message_with_prefix_and_newline_and_nul,
|
|
entry.text_message_with_newline(), os);
|
|
*os << "\n"
|
|
<< " text_message: ";
|
|
PrintEscapedRangeTo(text_message_with_prefix_and_newline_and_nul,
|
|
entry.text_message(), os);
|
|
*os << "\n"
|
|
<< " text_message_with_prefix_and_newline_c_str: ";
|
|
PrintEscapedRangeTo(
|
|
text_message_with_prefix_and_newline_and_nul,
|
|
// NOLINTNEXTLINE(bugprone-string-constructor)
|
|
absl::string_view(entry.text_message_with_prefix_and_newline_c_str(), 0),
|
|
os);
|
|
*os << "\n"
|
|
<< " encoded_message (raw): \""
|
|
<< absl::CHexEscape(entry.encoded_message()) << "\"\n"
|
|
<< " encoded_message {\n";
|
|
absl::Span<const char> event = entry.encoded_message();
|
|
log_internal::ProtoField field;
|
|
while (field.DecodeFrom(&event)) {
|
|
switch (field.tag()) {
|
|
case EventTag::kFileName:
|
|
*os << " file_name: \"" << absl::CHexEscape(field.string_value())
|
|
<< "\"\n";
|
|
break;
|
|
case EventTag::kFileLine:
|
|
*os << " file_line: " << field.int32_value() << "\n";
|
|
break;
|
|
case EventTag::kTimeNsecs:
|
|
*os << " time_nsecs: " << field.int64_value() << " ("
|
|
<< absl::FromUnixNanos(field.int64_value()) << ")\n";
|
|
break;
|
|
case EventTag::kSeverity:
|
|
*os << " severity: " << field.int32_value();
|
|
switch (field.int32_value()) {
|
|
case Severity::FINEST:
|
|
*os << " (FINEST)";
|
|
break;
|
|
case Severity::FINER:
|
|
*os << " (FINER)";
|
|
break;
|
|
case Severity::FINE:
|
|
*os << " (FINE)";
|
|
break;
|
|
case Severity::VERBOSE_0:
|
|
*os << " (VERBOSE_0)";
|
|
break;
|
|
case Severity::CONFIG:
|
|
*os << " (CONFIG)";
|
|
break;
|
|
case Severity::INFO:
|
|
*os << " (INFO)";
|
|
break;
|
|
case Severity::NOTICE:
|
|
*os << " (NOTICE)";
|
|
break;
|
|
case Severity::WARNING:
|
|
*os << " (WARNING)";
|
|
break;
|
|
case Severity::ERROR:
|
|
*os << " (ERROR)";
|
|
break;
|
|
case Severity::SEVERE:
|
|
*os << " (SEVERE)";
|
|
break;
|
|
case Severity::FATAL:
|
|
*os << " (FATAL)";
|
|
break;
|
|
}
|
|
*os << "\n";
|
|
break;
|
|
case EventTag::kThreadId:
|
|
*os << " thread_id: " << field.int64_value() << "\n";
|
|
break;
|
|
case EventTag::kValue: {
|
|
*os << " value {\n";
|
|
auto value = field.bytes_value();
|
|
while (field.DecodeFrom(&value)) {
|
|
switch (field.tag()) {
|
|
case ValueTag::kString:
|
|
*os << " str: \"" << absl::CHexEscape(field.string_value())
|
|
<< "\"\n";
|
|
break;
|
|
case ValueTag::kStringLiteral:
|
|
*os << " literal: \""
|
|
<< absl::CHexEscape(field.string_value()) << "\"\n";
|
|
break;
|
|
default:
|
|
*os << " unknown field " << field.tag();
|
|
switch (field.type()) {
|
|
case log_internal::WireType::kVarint:
|
|
*os << " (VARINT): " << std::hex << std::showbase
|
|
<< field.uint64_value() << std::dec << "\n";
|
|
break;
|
|
case log_internal::WireType::k64Bit:
|
|
*os << " (I64): " << std::hex << std::showbase
|
|
<< field.uint64_value() << std::dec << "\n";
|
|
break;
|
|
case log_internal::WireType::kLengthDelimited:
|
|
*os << " (LEN): \"" << absl::CHexEscape(field.string_value())
|
|
<< "\"\n";
|
|
break;
|
|
case log_internal::WireType::k32Bit:
|
|
*os << " (I32): " << std::hex << std::showbase
|
|
<< field.uint32_value() << std::dec << "\n";
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
*os << " }\n";
|
|
break;
|
|
}
|
|
default:
|
|
*os << " unknown field " << field.tag();
|
|
switch (field.type()) {
|
|
case log_internal::WireType::kVarint:
|
|
*os << " (VARINT): " << std::hex << std::showbase
|
|
<< field.uint64_value() << std::dec << "\n";
|
|
break;
|
|
case log_internal::WireType::k64Bit:
|
|
*os << " (I64): " << std::hex << std::showbase
|
|
<< field.uint64_value() << std::dec << "\n";
|
|
break;
|
|
case log_internal::WireType::kLengthDelimited:
|
|
*os << " (LEN): \"" << absl::CHexEscape(field.string_value())
|
|
<< "\"\n";
|
|
break;
|
|
case log_internal::WireType::k32Bit:
|
|
*os << " (I32): " << std::hex << std::showbase
|
|
<< field.uint32_value() << std::dec << "\n";
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
*os << " }\n"
|
|
<< " stacktrace: \"" << absl::CHexEscape(entry.stacktrace()) << "\"\n"
|
|
<< "}";
|
|
}
|
|
|
|
ABSL_NAMESPACE_END
|
|
} // namespace absl
|