blob: 358b8f5a7ce070d3b355a832a4b4f36d45bf8620 [file] [log] [blame]
// 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