| // 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 |