Introduce a new logging pipeline in NLog that uses an immutable LogEvent struct instead of the existing mutable LogEventInfo class.
The goal is to provide a safer, immutable logging pipeline that prevents mutation of log events, while enabling an allocation-efficient execution path where you only pay for the execution-context capture you need. Backwards compatibility for the old LogEventInfo pipeline will still be maintained.
Immutable log events
LogEventInfo is currently mutable, which means targets, layouts, and wrappers can accidentally modify the same log event while it travels through the logging pipeline.
This can lead to subtle bugs where one target changes data that is later observed by another target.
An immutable LogEvent would eliminate these side effects, making the logging pipeline easier to reason about and safer for target authors.
Non-allocation logging
A LogEvent implemented as a struct could be passed through the logging pipeline without heap allocation for the common case.
The struct would contain storage for a small number of built-in properties and event properties (Ex. 5), allowing many log events to remain allocation-free. Only when that capacity is exceeded would it fall back to allocating a Array / Dictionary (or similar).
Mutate by clone
NLog Target Wrappers often want to imbue with additional behavior, or make other adjustments of the LogEvent. There will be extension methods that can clone into a local/temporary "builder" which can be mutated, and finally build a new updated LogEvent.
Compatibility
The new LogEvent-struct will get a new, optimized pipeline. But leaving the old legacy pipeline with LogEventInfo.
Legacy targets continue receiving LogEventInfo. But new targets will receive the immutable LogEvent.
Thinking that LogEvent will have the legacy LogEventInfo as part of the Layout-Precalculate-Cache, when detecting legacy Target / Layout in the logging-output. Thus the LogEvent-struct can provide legacy LogEventInfo-object, when required by the ouput-target-chain.
Because the LogEvent struct will likely be relatively large, the best performance will be achieved on platforms that support passing structs by in (ref readonly) to reduce copy-by-value-overhead.
Introduce a new logging pipeline in NLog that uses an immutable LogEvent struct instead of the existing mutable LogEventInfo class.
The goal is to provide a safer, immutable logging pipeline that prevents mutation of log events, while enabling an allocation-efficient execution path where you only pay for the execution-context capture you need. Backwards compatibility for the old LogEventInfo pipeline will still be maintained.
Immutable log events
LogEventInfo is currently mutable, which means targets, layouts, and wrappers can accidentally modify the same log event while it travels through the logging pipeline.
This can lead to subtle bugs where one target changes data that is later observed by another target.
An immutable LogEvent would eliminate these side effects, making the logging pipeline easier to reason about and safer for target authors.
Non-allocation logging
A LogEvent implemented as a struct could be passed through the logging pipeline without heap allocation for the common case.
The struct would contain storage for a small number of built-in properties and event properties (Ex. 5), allowing many log events to remain allocation-free. Only when that capacity is exceeded would it fall back to allocating a Array / Dictionary (or similar).
Mutate by clone
NLog Target Wrappers often want to imbue with additional behavior, or make other adjustments of the LogEvent. There will be extension methods that can clone into a local/temporary "builder" which can be mutated, and finally build a new updated LogEvent.
Compatibility
The new LogEvent-struct will get a new, optimized pipeline. But leaving the old legacy pipeline with LogEventInfo.
Legacy targets continue receiving LogEventInfo. But new targets will receive the immutable LogEvent.
Thinking that LogEvent will have the legacy LogEventInfo as part of the Layout-Precalculate-Cache, when detecting legacy Target / Layout in the logging-output. Thus the LogEvent-struct can provide legacy LogEventInfo-object, when required by the ouput-target-chain.
Because the LogEvent struct will likely be relatively large, the best performance will be achieved on platforms that support passing structs by in (ref readonly) to reduce copy-by-value-overhead.