// 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 #include #include #include #include #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(substr.data() - str.data())); const char old_fill = os->fill(); const auto old_flags = os->flags(); *os << std::right << std::setw(static_cast(absl::CHexEscape(head).size())) << ""; switch (substr.size()) { case 0: *os << "\\"; break; case 1: *os << "^"; break; default: *os << "[" << std::setw(static_cast(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 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