blob: 6650e4e55b1b455990f3acd5eff8a258554364b7 [file]
// Copyright 2026 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/lib/diagnostics/log/message/rust/cpp-log-decoder/log_decoder_api.h"
#include <lib/zx/time.h>
#include <sstream>
#include <string>
#include <string_view>
#include <vector>
namespace log_decoder {
namespace {
void AppendEscaped(std::string* out, std::string_view input) {
for (char ch : input) {
if (ch == '"' || ch == '\\') {
out->push_back('\\');
}
out->push_back(ch);
}
}
std::string_view StringViewFromRustString(CppString rust_string) {
if (rust_string.ptr && rust_string.len > 0) {
return std::string_view(reinterpret_cast<const char*>(rust_string.ptr), rust_string.len);
}
return {};
}
std::string FormatMessageWithKvps(const LogMessage& message) {
std::string_view file_view = StringViewFromRustString(message.file);
std::string_view msg_view = StringViewFromRustString(message.message);
size_t estimated_size = msg_view.size();
if (!file_view.empty()) {
estimated_size += file_view.size() + 26;
}
for (size_t i = 0; i < message.kvps.len; i++) {
const auto& kvp = message.kvps.ptr[i];
estimated_size += 2 + kvp.key.len;
switch (kvp.value.tag) {
case CppValue::Tag::CPP_VALUE_SIGNED_INT:
case CppValue::Tag::CPP_VALUE_UNSIGNED_INT:
estimated_size += 24;
break;
case CppValue::Tag::CPP_VALUE_FLOATING:
estimated_size += 32;
break;
case CppValue::Tag::CPP_VALUE_BOOLEAN:
estimated_size += 5;
break;
case CppValue::Tag::CPP_VALUE_TEXT:
estimated_size += 2 + 2 * kvp.value.TEXT._0.len;
break;
}
}
std::string result;
result.reserve(estimated_size);
if (!file_view.empty()) {
result.push_back('[');
result.append(file_view);
result.push_back('(');
result.append(std::to_string(message.line));
result.append(")]");
if (!msg_view.empty()) {
result.push_back(' ');
}
}
result.append(msg_view);
for (size_t i = 0; i < message.kvps.len; i++) {
if (!result.empty()) {
result.push_back(' ');
}
const auto& kvp = message.kvps.ptr[i];
result.append(StringViewFromRustString(kvp.key));
result.push_back('=');
switch (kvp.value.tag) {
case CppValue::Tag::CPP_VALUE_SIGNED_INT:
result.append(std::to_string(kvp.value.SIGNED_INT._0));
break;
case CppValue::Tag::CPP_VALUE_UNSIGNED_INT:
result.append(std::to_string(kvp.value.UNSIGNED_INT._0));
break;
case CppValue::Tag::CPP_VALUE_FLOATING:
result.append(std::to_string(kvp.value.FLOATING._0));
break;
case CppValue::Tag::CPP_VALUE_BOOLEAN:
result.append(kvp.value.BOOLEAN._0 ? "true" : "false");
break;
case CppValue::Tag::CPP_VALUE_TEXT:
result.push_back('"');
AppendEscaped(&result, StringViewFromRustString(kvp.value.TEXT._0));
result.push_back('"');
break;
}
}
return result;
}
} // namespace
fpromise::result<fuchsia::logger::LogMessage, std::string> ToFidlLogMessage(
const LogMessage& message) {
std::vector<std::string> tags;
tags.reserve(message.tags.len + 1);
std::string_view moniker_tag = StringViewFromRustString(message.moniker_tag);
bool has_moniker_tag = false;
for (size_t i = 0; i < message.tags.len; i++) {
std::string_view tag_view = StringViewFromRustString(message.tags.ptr[i]);
if (tag_view == moniker_tag) {
has_moniker_tag = true;
}
tags.emplace_back(tag_view);
}
if (!moniker_tag.empty() && !has_moniker_tag) {
tags.insert(tags.begin(), std::string(moniker_tag));
}
fuchsia::logger::LogMessage ret = {
.pid = message.pid,
.tid = message.tid,
.time = zx::time_boot(message.timestamp),
.severity = message.severity,
.dropped_logs = static_cast<uint32_t>(message.dropped),
.tags = std::move(tags),
.msg = FormatMessageWithKvps(message),
};
return fpromise::ok(std::move(ret));
}
} // namespace log_decoder