Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions SilKit/source/config/Test_YamlParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,8 @@ TEST_F(Test_YamlParser, yaml_complete_configuration)
EXPECT_EQ(config.logging.sinks.at(0).level, SilKit::Services::Logging::Level::Critical);
EXPECT_EQ(config.logging.sinks.at(0).logName, "MyLog1");

EXPECT_EQ(config.logging.sinks.at(0).format, Sink::Format::Json);

EXPECT_EQ(config.healthCheck.softResponseTimeout.value(), 500ms);
EXPECT_EQ(config.healthCheck.hardResponseTimeout.value(), 5000ms);

Expand All @@ -263,6 +265,39 @@ TEST_F(Test_YamlParser, yaml_complete_configuration)
ASSERT_FALSE(config.middleware.registryAsFallbackProxy);
}

TEST_F(Test_YamlParser, yaml_file_sink_defaults_to_json_format)
{
auto config = Deserialize<ParticipantConfiguration>(R"(
Logging:
Sinks:
- Type: File
LogName: MyLog1
)");
ASSERT_EQ(config.logging.sinks.size(), 1u);
EXPECT_EQ(config.logging.sinks.at(0).type, Sink::Type::File);
EXPECT_EQ(config.logging.sinks.at(0).format, Sink::Format::Json);

auto configExplicit = Deserialize<ParticipantConfiguration>(R"(
Logging:
Sinks:
- Type: File
Format: Simple
LogName: MyLog1
)");
ASSERT_EQ(configExplicit.logging.sinks.size(), 1u);
EXPECT_EQ(configExplicit.logging.sinks.at(0).type, Sink::Type::File);
EXPECT_EQ(configExplicit.logging.sinks.at(0).format, Sink::Format::Simple);

auto configStdout = Deserialize<ParticipantConfiguration>(R"(
Logging:
Sinks:
- Type: Stdout
)");
ASSERT_EQ(configStdout.logging.sinks.size(), 1u);
EXPECT_EQ(configStdout.logging.sinks.at(0).type, Sink::Type::Stdout);
EXPECT_EQ(configStdout.logging.sinks.at(0).format, Sink::Format::Simple);
}

TEST_F(Test_YamlParser, yaml_elements_in_random_order)
{
auto config = Deserialize<ParticipantConfiguration>(R"(
Expand Down Expand Up @@ -334,10 +369,12 @@ TEST_F(Test_YamlParser, yaml_native_type_conversions)
Sink sink;
logger.logFromRemotes = true;
sink.type = Sink::Type::File;
sink.format = Sink::Format::Json;
sink.level = SilKit::Services::Logging::Level::Trace;
sink.logName = "filename";
logger.sinks.push_back(sink);
sink.type = Sink::Type::Stdout;
sink.format = Sink::Format::Simple;
sink.logName = "";
logger.sinks.push_back(sink);
auto txt = Serialize(logger);
Expand Down
6 changes: 6 additions & 0 deletions SilKit/source/config/YamlReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,12 @@ void YamlReader::Read(SilKit::Config::Sink& obj)
{
OptionalRead(obj.type, "Type");
OptionalRead(obj.level, "Level");

// A File sink defaults to the Json format. An explicitly configured Format takes precedence.
if (obj.type == SilKit::Config::Sink::Type::File)
{
obj.format = SilKit::Config::Sink::Format::Json;
}
OptionalRead(obj.format, "Format");

auto&& child = GetChildSafe("Experimental");
Expand Down
5 changes: 4 additions & 1 deletion docs/changelog/versions/latest.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# [5.0.7] - UNRELEASED

> This changelog entry is still empty.
## Changed

- `config`: default format of file logging is set to JSON. Set "Format: Simple" in the sink to get previous behaviour.
- `docs`: added description of the logging "Format".
77 changes: 70 additions & 7 deletions docs/configuration/logging-configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,20 @@ Logging Configuration
Overview
========================================

Within the SIL Kit, the Logger provides features for local and distributed logging on different log
levels.
Within the SIL Kit, the Logger provides features for local and distributed logging on different log levels.

- Logging output is configured through **sinks**, where each sink defines where messages are written (for example *Stdout*, *File*, or *Remote*) and which minimum log level is emitted.

- Log messages can be classified by **topics** (for example middleware internals, service controllers, or user-level logging). Topic-based filtering can be configured per sink to include or exclude specific topics.

- For sinks of type *Stdout* and *File*, the output **format** can be selected as *Simple* (human-readable text) or *Json* (structured one-object-per-line output).

Configuration
========================================
The Logging configuration allows to configure the logging behavior of the simulation participant.
Within the SIL Kit, the Logger uses so-called sinks to store log messages.
Multiple sinks can be configured at the same time. For example, to send log
messages with log level ``Debug`` or higher to a remote logger and write ``Trace`` level
logs to a file, the following configuration could be used:
Multiple sinks can be configured at the same time.
For example, to send log messages with log level ``Debug`` or higher to a remote logger and write ``Trace`` level logs to a file, the following configuration could be used:

.. code-block:: yaml

Expand Down Expand Up @@ -70,20 +74,78 @@ logs to a file, the following configuration could be used:
*Remote* send the log messages over the underlying middleware. Note that
this can result in a significant amount of traffic, which can impact the
simulation performance, in particular when using a low log level.
* - Format
- The output format used for log messages written by the sink. Valid
options are *Simple* and *Json* (see
:ref:`Log message format<sec:cfg-participant-logformat>`). Applies to
sinks of type *Stdout* and *File*. If not set, sinks of type *File*
default to *Json*, while all other sinks default to *Simple*.
* - Level
- The minimum log level of a message to be logged by the sink. All messages
with a lower log level are ignored. Valid options are *Critical*,
*Error*, *Warn*, *Info*, *Debug*, *Trace*, and *Off*.
* - LogName
- The filename used by sinks of type *File*. The
resulting filename is ``<LogName>_<Sanitized-Participant-Name>_<ISO-TimeStamp>.txt``.
- The filename used by sinks of type *File*. The resulting filename is
``<LogName>_<Sanitized-Participant-Name>_<ISO-TimeStamp>.txt`` for the
*Simple* format and
``<LogName>_<Sanitized-Participant-Name>_<ISO-TimeStamp>.jsonl`` for the
*Json* format.
* - Experimental: EnabledTopics
- Optional allow-list of logging topics for this sink. If this list is non-empty,
only messages with topics from this list are written to the sink.
* - Experimental: DisabledTopics
- Optional block-list of logging topics for this sink. Disabled topics are always
filtered out, even if they are also listed in *EnabledTopics*.

.. _sec:cfg-participant-logformat:

Log message format
========================================

The *Format* property of a sink controls how log messages are rendered.
It applies to sinks of type *Stdout* and *File*.
Sinks of type *Remote* always transmit the messages in the *Simple* format.

.. note::

If the *Format* property is not set explicitly, sinks of type *File* default to *Json*, while sinks of type *Stdout* default to *Simple*.

Simple
Human-readable, single-line text output.
This is the default for *Stdout* sinks.
For *File* sinks, the messages are written to a ``.txt`` file.

.. code-block:: text

[2026-07-09 11:59:50.287] [CanWriter] [trace] [TimeSync] Finished Simulation Step., ExecutionTime: 0.4058, VirtualTimeNS: 60000000


Json
One JSON object per line, which is convenient for automated processing of the log.

.. code-block:: text

{"ts":"1783591190287458","log":"CanWriter","lvl":"trace", "topic": "TimeSync", "msg": "Finished Simulation Step.", "kv": {"ExecutionTime":"0.4058","VirtualTimeNS":"60000000"} }

Each entry contains the UNIX epoch timestamp in microseconds (``ts``), the participant name (``log``), the log level (``lvl``), and the message (``msg``).
Depending on the message, the ``topic`` (see :ref:`logging topics<sec:cfg-participant-logtopics>`) and the optional field ``kv`` (structured key-value data) are added.
For *File* sinks, the messages are written to a ``.jsonl`` file.

The following example configures a *File* sink using the *Simple* format and a *Stdout* sink using the *Json* format:

.. code-block:: yaml

Logging:
Sinks:
- Type: File
Format: Simple
Level: Trace
LogName: ParticipantLog
- Type: Stdout
Format: Json
Level: Info


Experimental: Topic-based sink filtering
========================================

Expand Down Expand Up @@ -125,6 +187,7 @@ With the next example, topics that produce verbose log messages at startup are d
- Asio
- ServiceDiscovery

.. _sec:cfg-participant-logtopics:

The following topic names are currently assigned by SIL Kit components:

Expand Down
Loading