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