| // 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 <array> |
| #include <cstddef> |
| #include <mutex> |
| |
| #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<std::byte, PW_SYSTEM_MAX_LOG_ENTRY_SIZE> 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<std::byte, PW_SYSTEM_MAX_LOG_ENTRY_SIZE> 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<ConstByteSpan> 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<ConstByteSpan> 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 |