// Copyright 2022 The Pigweed 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 #include #include #include "pw_bytes/span.h" #include "pw_chrono/system_clock.h" #include "pw_log/proto_utils.h" #include "pw_log_string/handler.h" #include "pw_log_tokenized/metadata.h" #include "pw_multisink/multisink.h" #include "pw_result/result.h" #include "pw_string/string_builder.h" #include "pw_sync/interrupt_spin_lock.h" #include "pw_sync/lock_annotations.h" #include "pw_system/config.h" #include "pw_system_private/log.h" #include "pw_tokenizer/tokenize_to_global_handler_with_payload.h" namespace pw::system { namespace { // Buffer used to encode each log entry before saving into log buffer. sync::InterruptSpinLock log_encode_lock; std::array log_encode_buffer PW_GUARDED_BY(log_encode_lock); // String-only logs may need to be formatted first. This buffer is required // so the format string may be passed to the proto log encode. std::array log_format_buffer PW_GUARDED_BY(log_encode_lock); const int64_t boot_time_count = pw::chrono::SystemClock::now().time_since_epoch().count(); } // namespace // Provides time since boot in units defined by the target's pw_chrono backend. int64_t GetTimestamp() { return pw::chrono::SystemClock::now().time_since_epoch().count() - boot_time_count; } // Implementation for tokenized log handling. This will be optimized out for // devices that only use string logging. extern "C" void pw_tokenizer_HandleEncodedMessageWithPayload( pw_tokenizer_Payload payload, const uint8_t message[], size_t size_bytes) { log_tokenized::Metadata metadata = payload; const int64_t timestamp = GetTimestamp(); std::lock_guard lock(log_encode_lock); Result encoded_log_result = log::EncodeTokenizedLog( metadata, message, size_bytes, timestamp, log_encode_buffer); if (!encoded_log_result.ok()) { GetMultiSink().HandleDropped(); return; } GetMultiSink().HandleEntry(encoded_log_result.value()); } // Implementation for string log handling. This will be optimized out for // devices that only use tokenized logging. extern "C" void pw_log_string_HandleMessageVaList(int level, unsigned int flags, const char* module_name, const char* file_name, int line_number, const char* message, va_list args) { const int64_t timestamp = GetTimestamp(); std::lock_guard lock(log_encode_lock); StringBuilder message_builder(log_format_buffer); message_builder.FormatVaList(message, args); Result encoded_log_result = log::EncodeLog(level, flags, module_name, /*thread_name=*/{}, file_name, line_number, timestamp, message_builder.view(), log_encode_buffer); if (!encoded_log_result.ok()) { GetMultiSink().HandleDropped(); return; } GetMultiSink().HandleEntry(encoded_log_result.value()); } } // namespace pw::system