blob: 871a531d2775383c4956f23bf668e3b7d4c8ec95 [file] [log] [blame]
// Copyright 2020 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.
#ifndef LIB_SYSLOG_CPP_HOST_ENCODER_H_
#define LIB_SYSLOG_CPP_HOST_ENCODER_H_
#include <assert.h>
#include <lib/syslog/cpp/log_level.h>
#include <lib/syslog/cpp/macros.h>
#include <cstring>
// This file contains shared implementations for writing string logs between the legacy backend and
// the host backend
namespace fuchsia_logging::internal {
struct MsgHeader {
fuchsia_logging::RawLogSeverity severity;
char* offset;
LogBuffer* buffer;
bool first_tag;
char* user_tag;
bool has_msg;
bool first_kv;
bool terminated;
size_t RemainingSpace() {
auto end = (reinterpret_cast<const char*>(this) + sizeof(LogBuffer));
auto avail = static_cast<size_t>(end - offset -
2); // Allocate an extra byte for a NULL terminator at the end
return avail;
}
void NullTerminate() {
if (!terminated) {
terminated = true;
*(offset++) = 0;
}
}
const char* c_str() {
NullTerminate();
return reinterpret_cast<const char*>(buffer->data());
}
void WriteChar(const char value) {
if (!RemainingSpace()) {
buffer->Flush();
offset = reinterpret_cast<char*>(buffer->data());
WriteString("CONTINUATION: ");
}
assert((offset + 1) < (reinterpret_cast<const char*>(this) + sizeof(LogBuffer)));
*offset = value;
offset++;
}
void WriteString(std::string_view value) {
size_t total_chars = value.size();
size_t written_chars = 0;
while (written_chars < total_chars) {
size_t written = WriteStringInternal(
std::string_view(value.data() + written_chars, value.size() - written_chars));
written_chars += written;
if (written_chars < total_chars) {
FlushAndReset();
WriteStringInternal("CONTINUATION: ");
}
}
}
void FlushAndReset() {
buffer->Flush();
offset = reinterpret_cast<char*>(buffer->data());
}
// Writes a string to the buffer and returns the
// number of bytes written. Returns 0 only if
// the length of the string is 0, or if we're
// exactly at the end of the buffer and need a reset.
size_t WriteStringInternal(std::string_view value) {
size_t len = value.size();
auto remaining = RemainingSpace();
if (len > remaining) {
len = remaining;
}
assert((offset + len) < (reinterpret_cast<const char*>(this) + sizeof(LogBuffer)));
memcpy(offset, value.data(), len);
offset += len;
return len;
}
void Init(LogBuffer* log_buffer, fuchsia_logging::RawLogSeverity log_severity) {
this->severity = log_severity;
user_tag = nullptr;
offset = reinterpret_cast<char*>(log_buffer->data());
first_tag = true;
has_msg = false;
first_kv = true;
terminated = false;
}
static MsgHeader* CreatePtr(LogBuffer* log_buffer) {
return reinterpret_cast<MsgHeader*>(log_buffer->record_state());
}
};
#ifndef __Fuchsia__
const std::string GetNameForLogSeverity(fuchsia_logging::RawLogSeverity severity);
#endif
static_assert(sizeof(MsgHeader) <= LogBuffer::record_state_size(),
"message header must be no larger than record_state");
} // namespace fuchsia_logging::internal
#endif // LIB_SYSLOG_CPP_HOST_ENCODER_H_