diff --git a/design/slot_drainer_sequence_design.puml b/design/slot_drainer_sequence_design.puml new file mode 100644 index 0000000..c1a6260 --- /dev/null +++ b/design/slot_drainer_sequence_design.puml @@ -0,0 +1,62 @@ +@startuml slot_drainer_sequence_design +title "SlotDrainer Sequence Design" + +participant "Backend" as Backend +participant "SlotDrainer" as SlotDrainer +participant "NonBlockingWriter" as NonBlockingWriter +participant "CircularBuffer" as CircularBuffer +participant "MessageBuilder" as MessageBuilder +participant "SlotAllocator" as SlotAllocator + +note over SlotDrainer : Slot Drainer Flush Sequence + +activate SlotDrainer +activate Backend +activate NonBlockingWriter +activate CircularBuffer +activate SlotAllocator +activate MessageBuilder + +group "First Slot" +Backend -> SlotDrainer : Flush() + +SlotDrainer -> MessageBuilder : GetNextSpan(log_record) + +SlotDrainer -> CircularBuffer : empty() +CircularBuffer -> SlotDrainer: false + +SlotDrainer -> CircularBuffer : front() +SlotDrainer -> CircularBuffer : pop_front() + +SlotDrainer -> CircularBuffer : empty() +CircularBuffer -> SlotDrainer: false +SlotDrainer -> CircularBuffer : front() + +SlotDrainer -> SlotAllocator : GetUnderlyingBufferFor(slot) +SlotDrainer -> MessageBuilder : SetNextMessage(log_record) + +SlotDrainer -> NonBlockingWriter : FlushIntoFile() +NonBlockingWriter -> SlotDrainer: kDone + + +SlotDrainer -> MessageBuilder : GetNextSpan() +end + +group "Last Slot" + +SlotDrainer -> MessageBuilder : GetNextSpan() + +SlotDrainer -> NonBlockingWriter : FlushIntoFile() +NonBlockingWriter -> SlotDrainer: kDone + +SlotDrainer -> MessageBuilder : GetNextSpan() + +SlotDrainer -> CircularBuffer : empty() +CircularBuffer -> SlotDrainer: true + +Backend <-- SlotDrainer + + +end + +@enduml diff --git a/design/verbose_logging_ara_log_interaction.puml b/design/verbose_logging_ara_log_interaction.puml new file mode 100644 index 0000000..4fcd34b --- /dev/null +++ b/design/verbose_logging_ara_log_interaction.puml @@ -0,0 +1,43 @@ +@startuml verbose_logging_ara_log_interaction +title "Score Logging ARA Log Interaction" + +package "ara::log API" { + class "Free Functions" as AraLogFunctions { + + ara::log::LogError(): ara::log::LogStream + + ara::log::LogWarn(): ara::log::LogStream + + ara::log::LogInfo(): ara::log::LogStream + + ara::log::LogDebug(): ara::log::LogStream + } +} + +package "score::mw Log Implementation" { + class "Free Functions" as ScoreMwLogFunctions { + + score::mw::LogError(): score::mw::LogStream + + score::mw::LogWarn(): score::mw::LogStream + + score::mw::LogInfo(): score::mw::LogStream + + score::mw::LogDebug(): score::mw::LogStream + } +} + +AraLogFunctions --> ScoreMwLogFunctions : facade + +note top of AraLogFunctions + AUTOSAR Adaptive Platform + Logging API - standardized + interface for automotive + applications +end note + +note bottom of ScoreMwLogFunctions + Score Middleware logging + implementation providing + the actual logging functionality +end note + +note on link + ara::log functions act as + a facade that delegates to + score::mw logging implementation +end note + +@enduml diff --git a/design/verbose_logging_static.puml b/design/verbose_logging_static.puml new file mode 100644 index 0000000..6f03d51 --- /dev/null +++ b/design/verbose_logging_static.puml @@ -0,0 +1,375 @@ +@startuml +title "Middleware Log Class Diagram" + +package "User Facing API" +{ + +class score::mw::log::Logger { ++Logger(const std::string_view context) noexcept : void +.. ++GetContext() const noexcept : std::string_view ++IsEnabled(const LogLevel) const noexcept : bool ++IsLogEnabled(const LogLevel) const noexcept : bool ++LogDebug() const noexcept : log::LogStream ++LogError() const noexcept : log::LogStream ++LogFatal() const noexcept : log::LogStream ++LogInfo() const noexcept : log::LogStream ++LogVerbose() const noexcept : log::LogStream ++LogWarn() const noexcept : log::LogStream ++WithLevel(const LogLevel log_level) const noexcept : log::LogStream +__ +-context_ : detail::LoggingIdentifier +} +} + +package "Not Mockable Part" { + +class score::mw::log::LogStream { ++LogStream(const LogStream &) noexcept = deleted : void ++LogStream(LogStream &&) noexcept : void +-LogStream(Recorder &, Recorder &, const LogLevel, const std::string_view) noexcept : void ++~LogStream() noexcept : void +.. ++operator=(const LogStream &) noexcept = deleted : LogStream & ++operator=(LogStream &&) noexcept = deleted : LogStream & +.. ++operator(const T & value) noexcept : std::enable_if_t(), LogStream &> ++operator(T char_ptr) : std::enable_if_t(), LogStream &> ++operator(const LogString::CharType (&)[N] array) noexcept : LogStream & +.. +-CallOnRecorder(ReturnValue (Recorder::*)(ArgsOfFunction...) noexcept arbitrary_function, ArgsPassed &&... args) noexcept : ReturnValue ++Flush() noexcept : void +-Log(const std::uint64_t) noexcept : LogStream & +-Log(const RawBufferType &) noexcept : std::enable_if_t(), LogStream &> +-Log(const LogSlog2Message & value) noexcept : LogStream & +-Log(const LogHex64 & value) noexcept : LogStream & +-Log(const LogHex32 & value) noexcept : LogStream & +-Log(const LogHex16 & value) noexcept : LogStream & +-Log(const LogHex8 & value) noexcept : LogStream & +-Log(const LogBin64 & value) noexcept : LogStream & +-Log(const LogBin32 & value) noexcept : LogStream & +-Log(const LogBin16 & value) noexcept : LogStream & +-Log(const LogBin8 & value) noexcept : LogStream & +-Log(const std::uint32_t) noexcept : LogStream & +-Log(const std::uint16_t) noexcept : LogStream & +-Log(const std::uint8_t) noexcept : LogStream & +-Log(const std::int64_t) noexcept : LogStream & +-Log(const std::int32_t) noexcept : LogStream & +-Log(const std::int16_t) noexcept : LogStream & +-Log(const std::int8_t) noexcept : LogStream & +-Log(const LogString) noexcept : LogStream & +-Log(const double) noexcept : LogStream & +-Log(const float) noexcept : LogStream & +-Log(const bool) noexcept : LogStream & +-LogWithRecorder(const T value) noexcept : LogStream & +__ +-context_id_ : detail::LoggingIdentifier +-fallback_recorder_ : Recorder & +-log_level_ : LogLevel +-recorder_ : Recorder & +-slot_ : score::cpp::optional +} + +enum score::mw::log::LogLevel { +kOff +kFatal +kError +kWarn +kInfo +kDebug +kVerbose +} + +class score::mw::log::detail::LoggingIdentifier { ++LoggingIdentifier(const std::string_view) noexcept : void ++LoggingIdentifier() noexcept = default : void ++LoggingIdentifier(const LoggingIdentifier &) noexcept = default : void ++LoggingIdentifier(LoggingIdentifier &&) noexcept = default : void ++~LoggingIdentifier() noexcept = default : void +.. ++operator=(const LoggingIdentifier & rhs) constexpr noexcept = default : LoggingIdentifier & ++operator=(LoggingIdentifier && rhs) constexpr noexcept = default : LoggingIdentifier & +.. ++GetStringView() const noexcept : std::string_view +__ ++data_ : std::array +{static} +kMaxLength : const std::size_t +} +class score::mw::log::detail::LogStreamFactory { +{static} +GetStream(const LogLevel, const std::string_view context_id = "DFLT") noexcept : LogStream +__ +} + +class score::mw::log::detail::Runtime { ++Runtime(const Runtime &) noexcept = deleted : void ++Runtime(Runtime &&) noexcept = deleted : void +-Runtime(Recorder *const recorder, score::cpp::pmr::memory_resource * memory_resource) noexcept : void ++~Runtime() = default : void +.. ++operator=(const Runtime &) noexcept = deleted : Runtime & ++operator=(Runtime &&) noexcept = deleted : Runtime & +.. +{static} +GetFallbackRecorder() noexcept : Recorder & +{static} +GetLoggerContainer() noexcept : score::mw::log::LoggerContainer & +{static} +GetRecorder() noexcept : Recorder & +{static} -Instance(Recorder *const recorder, score::cpp::pmr::memory_resource * memory_resource = score::cpp::pmr::get_default_resource()) noexcept : Runtime & +{static} +SetRecorder(Recorder *const recorder, score::cpp::pmr::memory_resource * memory_resource = score::cpp::pmr::get_default_resource()) noexcept : void +__ +-default_recorder_ : std::unique_ptr +-logger_container_instance_ : LoggerContainer +-recorder_instance_ : Recorder * +} + +class score::mw::log::SlotHandle { ++SlotHandle() noexcept = default : void ++SlotHandle(const SlotIndex) noexcept : void +.. ++GetSelectedRecorder() const noexcept : RecorderIdentifier ++GetSlot(const RecorderIdentifier) const noexcept : SlotIndex ++GetSlotOfSelectedRecorder() const noexcept : SlotIndex ++IsRecorderActive(const RecorderIdentifier) const noexcept : bool ++SetSelectedRecorder(const RecorderIdentifier) noexcept : void ++SetSlot(const SlotIndex, const RecorderIdentifier recorder = {{}}) noexcept : void +__ +{static} +kMaxRecorders : const std::size_t +-recorder_slot_available_ : std::bitset +-recorder_to_slot_ : std::array +-selected_recorder_ : RecorderIdentifier +} + +} + +package "Mockable Part" { + +class "score::mw::log::detail::WaitFreeStack" as score::mw::log::detail::WaitFreeStack_of_Element { + + WaitFreeStack(std::size_t) + + TryPush(Element&&): amp::optional> + + Find(const FindPredicate&): amp::optional> + -- + - elements_: std::vector> + - elements_written_: std::vector + - write_index_: AtomicIndex + - capacity_full_: AtomicBool +} + +class score::mw::log::detail::EmptyRecorder { ++IsLogEnabled(const LogLevel &, const std::string_view context) const noexcept : bool ++Log(const SlotHandle &, const double) noexcept : void ++Log(const SlotHandle &, const LogSlog2Message) noexcept : void ++Log(const SlotHandle &, const LogRawBuffer) noexcept : void ++Log(const SlotHandle &, const LogBin64) noexcept : void ++Log(const SlotHandle &, const LogBin32) noexcept : void ++Log(const SlotHandle &, const LogBin16) noexcept : void ++Log(const SlotHandle &, const LogBin8) noexcept : void ++Log(const SlotHandle &, const LogHex64) noexcept : void ++Log(const SlotHandle &, const LogHex32) noexcept : void ++Log(const SlotHandle &, const LogHex16) noexcept : void ++Log(const SlotHandle &, const LogHex8) noexcept : void ++Log(const SlotHandle &, const std::string_view) noexcept : void ++Log(const SlotHandle &, const float) noexcept : void ++Log(const SlotHandle &, const std::int64_t) noexcept : void ++Log(const SlotHandle &, const std::uint64_t) noexcept : void ++Log(const SlotHandle &, const std::int32_t) noexcept : void ++Log(const SlotHandle &, const std::uint32_t) noexcept : void ++Log(const SlotHandle &, const std::int16_t) noexcept : void ++Log(const SlotHandle &, const std::uint16_t) noexcept : void ++Log(const SlotHandle &, const std::int8_t) noexcept : void ++Log(const SlotHandle &, const std::uint8_t) noexcept : void ++Log(const SlotHandle &, const bool data) noexcept : void ++StartRecord(const std::string_view context_id, const LogLevel log_level) noexcept : score::cpp::optional ++StopRecord(const SlotHandle & slot) noexcept : void +__ +} + +class score::mw::log::detail::LogEntry { +__ ++app_id : LoggingIdentifier ++ctx_id : LoggingIdentifier ++header_buffer : ByteVector ++log_level : LogLevel ++num_of_args : std::uint8_t ++payload : ByteVector ++timestamp_steady_nsec : std::uint64_t ++timestamp_system_nsec : std::uint64_t +} + +class score::mw::log::detail::TextRecorder { ++TextRecorder(const detail::Configuration & config, std::unique_ptr backend, const bool check_log_level_for_console) noexcept : void ++TextRecorder(TextRecorder &&) noexcept = deleted : void ++TextRecorder(const TextRecorder &) noexcept = deleted : void ++~TextRecorder() = default : void +.. ++operator=(TextRecorder &&) noexcept = deleted : TextRecorder & ++operator=(const TextRecorder &) noexcept = deleted : TextRecorder & +.. ++IsLogEnabled(const LogLevel &, const std::string_view) const noexcept : bool ++Log(const SlotHandle & slot, const double data) noexcept : void ++Log(const SlotHandle & slot, const LogSlog2Message data) noexcept : void ++Log(const SlotHandle & slot, const LogBin64 data) noexcept : void ++Log(const SlotHandle & slot, const LogBin32 data) noexcept : void ++Log(const SlotHandle & slot, const LogBin16 data) noexcept : void ++Log(const SlotHandle & slot, const LogBin8 data) noexcept : void ++Log(const SlotHandle & slot, const LogHex64 data) noexcept : void ++Log(const SlotHandle & slot, const LogHex32 data) noexcept : void ++Log(const SlotHandle & slot, const LogHex16 data) noexcept : void ++Log(const SlotHandle & slot, const LogHex8 data) noexcept : void ++Log(const SlotHandle & slot, const std::string_view data) noexcept : void ++Log(const SlotHandle & slot, const LogRawBuffer data) noexcept : void ++Log(const SlotHandle & slot, const float data) noexcept : void ++Log(const SlotHandle & slot, const std::int64_t data) noexcept : void ++Log(const SlotHandle & slot, const std::uint64_t data) noexcept : void ++Log(const SlotHandle & slot, const std::int32_t data) noexcept : void ++Log(const SlotHandle & slot, const std::uint32_t data) noexcept : void ++Log(const SlotHandle & slot, const std::int16_t data) noexcept : void ++Log(const SlotHandle & slot, const std::uint16_t data) noexcept : void ++Log(const SlotHandle & slot, const std::int8_t data) noexcept : void ++Log(const SlotHandle & slot, const std::uint8_t data) noexcept : void ++Log(const SlotHandle & slot, const bool data) noexcept : void ++StartRecord(const std::string_view context_id, const LogLevel log_level) noexcept : score::cpp::optional ++StopRecord(const SlotHandle & slot) noexcept : void +__ +-backend_ : std::unique_ptr +-check_log_level_for_console_ : bool +-config_ : detail::Configuration +} +class score::mw::log::detail::FileRecorder { ++FileRecorder(const detail::Configuration & config, std::unique_ptr backend) : void +.. ++IsLogEnabled(const LogLevel &, const std::string_view context) const noexcept : bool ++Log(const SlotHandle &, const double) noexcept : void ++Log(const SlotHandle &, const LogSlog2Message) noexcept : void ++Log(const SlotHandle &, const LogRawBuffer) noexcept : void ++Log(const SlotHandle &, const LogBin64) noexcept : void ++Log(const SlotHandle &, const LogBin32) noexcept : void ++Log(const SlotHandle &, const LogBin16) noexcept : void ++Log(const SlotHandle &, const LogBin8) noexcept : void ++Log(const SlotHandle &, const LogHex64) noexcept : void ++Log(const SlotHandle &, const LogHex32) noexcept : void ++Log(const SlotHandle &, const LogHex16) noexcept : void ++Log(const SlotHandle &, const LogHex8) noexcept : void ++Log(const SlotHandle &, const std::string_view) noexcept : void ++Log(const SlotHandle &, const float) noexcept : void ++Log(const SlotHandle &, const std::int64_t) noexcept : void ++Log(const SlotHandle &, const std::uint64_t) noexcept : void ++Log(const SlotHandle &, const std::int32_t) noexcept : void ++Log(const SlotHandle &, const std::uint32_t) noexcept : void ++Log(const SlotHandle &, const std::int16_t) noexcept : void ++Log(const SlotHandle &, const std::uint16_t) noexcept : void ++Log(const SlotHandle &, const std::int8_t) noexcept : void ++Log(const SlotHandle &, const std::uint8_t) noexcept : void ++Log(const SlotHandle &, const bool data) noexcept : void ++StartRecord(const std::string_view context_id, const LogLevel log_level) noexcept : score::cpp::optional ++StopRecord(const SlotHandle & slot) noexcept : void +__ +-backend_ : std::unique_ptr +-config_ : detail::Configuration +} + +class score::mw::log::detail::LogRecord { ++LogRecord(const std::size_t max_payload_size_bytes = 255U) noexcept : void ++LogRecord(const LogRecord &) noexcept : void ++LogRecord(LogRecord &&) noexcept : void ++~LogRecord() noexcept = default : void +.. ++operator=(const LogRecord &) noexcept : LogRecord & ++operator=(LogRecord &&) noexcept : LogRecord & +.. ++getLogEntry() noexcept : LogEntry & ++getLogEntry() const noexcept : const LogEntry & ++getVerbosePayload() noexcept : detail::VerbosePayload & ++getVerbosePayload() const noexcept : const detail::VerbosePayload & +__ +-logEntry_ : LogEntry +-verbosePayload_ : detail::VerbosePayload +} + +abstract score::mw::log::Recorder { ++Recorder() = default : void ++Recorder(const Recorder &) noexcept = deleted : void ++Recorder(Recorder &&) noexcept = deleted : void ++~Recorder() : void +.. ++operator=(const Recorder &) noexcept = deleted : Recorder & ++operator=(Recorder &&) noexcept = deleted : Recorder & +.. +{abstract} +IsLogEnabled(const LogLevel &, const std::string_view context) const noexcept = 0 : bool +{abstract} +Log(const SlotHandle &, const double) noexcept = 0 : void +{abstract} +Log(const SlotHandle &, const LogSlog2Message) noexcept = 0 : void +{abstract} +Log(const SlotHandle &, const LogRawBuffer) noexcept = 0 : void +{abstract} +Log(const SlotHandle &, const LogBin64) noexcept = 0 : void +{abstract} +Log(const SlotHandle &, const LogBin32) noexcept = 0 : void +{abstract} +Log(const SlotHandle &, const LogBin16) noexcept = 0 : void +{abstract} +Log(const SlotHandle &, const LogBin8) noexcept = 0 : void +{abstract} +Log(const SlotHandle &, const LogHex64) noexcept = 0 : void +{abstract} +Log(const SlotHandle &, const LogHex32) noexcept = 0 : void +{abstract} +Log(const SlotHandle &, const LogHex16) noexcept = 0 : void +{abstract} +Log(const SlotHandle &, const LogHex8) noexcept = 0 : void +{abstract} +Log(const SlotHandle &, const std::string_view) noexcept = 0 : void +{abstract} +Log(const SlotHandle &, const float) noexcept = 0 : void +{abstract} +Log(const SlotHandle &, const std::int64_t) noexcept = 0 : void +{abstract} +Log(const SlotHandle &, const std::uint64_t) noexcept = 0 : void +{abstract} +Log(const SlotHandle &, const std::int32_t) noexcept = 0 : void +{abstract} +Log(const SlotHandle &, const std::uint32_t) noexcept = 0 : void +{abstract} +Log(const SlotHandle &, const std::int16_t) noexcept = 0 : void +{abstract} +Log(const SlotHandle &, const std::uint16_t) noexcept = 0 : void +{abstract} +Log(const SlotHandle &, const std::int8_t) noexcept = 0 : void +{abstract} +Log(const SlotHandle &, const std::uint8_t) noexcept = 0 : void +{abstract} +Log(const SlotHandle &, const bool data) noexcept = 0 : void +{abstract} +StartRecord(const std::string_view context_id, const LogLevel log_level) noexcept = 0 : score::cpp::optional +{abstract} +StopRecord(const SlotHandle & slot) noexcept = 0 : void +__ +} + +class score::mw::log::LoggerContainer { ++LoggerContainer() : void +.. +-FindExistingLogger(const std::string_view context) noexcept : score::cpp::optional> ++GetCapacity() const noexcept : size_t ++GetDefaultLogger() noexcept : Logger & ++GetLogger(const std::string_view context) noexcept : Logger & +-InsertNewLogger(const std::string_view context) noexcept : Logger & +__ +-default_logger_ : Logger +-stack_ : detail::WaitFreeStack +} + +} + +score::mw::log::detail::LogStreamFactory ..> score::mw::log::LogLevel +score::mw::log::detail::LogStreamFactory ..> score::mw::log::LogStream +score::mw::log::detail::Runtime o-- score::mw::log::LoggerContainer : -logger_container_instance_ +score::mw::log::detail::Runtime --> score::mw::log::Recorder : -recorder_instance_ +score::mw::log::detail::Runtime o-- score::mw::log::Recorder : -default_recorder_ +score::mw::log::detail::EmptyRecorder ..> score::mw::log::LogLevel +score::mw::log::detail::EmptyRecorder ..> score::mw::log::SlotHandle +score::mw::log::Recorder <|-- score::mw::log::detail::EmptyRecorder +score::mw::log::detail::LogEntry o-- score::mw::log::detail::LoggingIdentifier : +app_id +score::mw::log::detail::LogEntry o-- score::mw::log::detail::LoggingIdentifier : +ctx_id +score::mw::log::detail::LogEntry o-- score::mw::log::LogLevel : +log_level +score::mw::log::detail::LogRecord o-- score::mw::log::detail::LogEntry : -logEntry_ +score::mw::log::detail::TextRecorder ..> score::mw::log::LogLevel +score::mw::log::detail::TextRecorder ..> score::mw::log::SlotHandle +score::mw::log::Recorder <|-- score::mw::log::detail::TextRecorder +score::mw::log::detail::FileRecorder ..> score::mw::log::LogLevel +score::mw::log::detail::FileRecorder ..> score::mw::log::SlotHandle +score::mw::log::Recorder <|-- score::mw::log::detail::FileRecorder +score::mw::log::Recorder ..> score::mw::log::LogLevel +score::mw::log::Recorder ..> score::mw::log::SlotHandle +score::mw::log::LogStream --> score::mw::log::Recorder : -recorder_ +score::mw::log::LogStream --> score::mw::log::Recorder : -fallback_recorder_ +score::mw::log::LogStream o-- score::mw::log::SlotHandle : -slot_ +score::mw::log::LogStream o-- score::mw::log::detail::LoggingIdentifier : -context_id_ +score::mw::log::LogStream o-- score::mw::log::LogLevel : -log_level_ +score::mw::log::LogStream <.. score::mw::log::detail::LogStreamFactory : +<> +score::mw::log::Logger ..> score::mw::log::LogStream +score::mw::log::Logger ..> score::mw::log::LogLevel +score::mw::log::Logger o-- score::mw::log::detail::LoggingIdentifier : -context_ +score::mw::log::LoggerContainer o-- score::mw::log::detail::WaitFreeStack_of_Element : -stack_ +score::mw::log::LoggerContainer o-- score::mw::log::Logger : -default_logger_ + +note "This diagram only illustrates the use-case of verbose logging." as N0 +note "A user is allowed to use the Recorder interface for its abstraction, but it is not recommended due to its more complicated usage." as N1 + +N1 .. score::mw::log::Recorder + +@enduml diff --git a/design/wait_free_stack_trypush.puml b/design/wait_free_stack_trypush.puml new file mode 100644 index 0000000..f9ee610 --- /dev/null +++ b/design/wait_free_stack_trypush.puml @@ -0,0 +1,21 @@ +@startuml wait_free_stack_trypush +title "Wait Free Stack TryPush" + +start +if (Stack capacity is full?) then (Yes) +else (No) + :Atomically + Current write index = write index + Increment write index; + if (Current write index >= number of elements in stack) then (Yes) + :Stack capacity full = true; + else (No) + :Push element to stack; + :Memory Fence (Release); + :Return element value; + stop + endif +endif + :Return null value; +stop +@enduml