The existing codebase up until version 1.4.367 uses the following primitives for logging:
Utils.Tracefunctions to log messages in the codebase with message format strings and arguments as format parameters, along with optionalTraceMasksandExceptions.- Logging configuration uses the
ApplicationConfigurationsection forTraceConfigurationto specify theOutputFilePathandTraceMasks. - The built in file logging is really slowing the whole system down, so logging and investigating of events with frequent output (10s of messages per second) is not possible without changing system behavior and performance.
- The current model allows to set a
TraceEventcallback event, which allows an application to capture all messages and filter on its behalf. With some wrapper code it is possible to map theTraceEventmessages to existing loggers like Serilog and others. Again, the TraceEvent callback is not suitable for high performance logging, but so far the best solution using the .NET UA stack. - A sample how to map
TraceEventto Serilog is provided in the .NET Framework Reference Server sample application.
- At least for a transition period backward compatibility for existing applications. Support for
TraceEvents. - Reasonable flow of messages at the
Informationlevel to allow production applications to run with logging always enabled. - High performance logging using
EventSourcefor development, which is available for Etw on Windows and in a different flavor on Linux with adotnet-tracecommand. - Support for a modern pluggable
ILoggerinterface as replacement for theUtils.Tracefunctions to log leveled messages in the codebase with message format strings and arguments as format parameters, similar to the existing approach. - Do not force users to use a specific logging framework. But simplify the use of third party logging frameworks like Serilog, Log4Net, OpenTelemetry etc.
- Support for structured logging including activities (
System.Diagnostics.Activity) and scopes (BeginScope). - Support for correlation IDs with OpenTelemetry, Zipkin etc.
- The proposed solution uses the
ILoggerinterface which is defined inMicrosoft.Extensions.Logging.Abstractionsas core abstraction for logging functions. This dependency leads to include a new Nuget package with abstractions, but only to the core library. - This
ILoggerinterface is the proposed logging interface for .NET with OpenTelemetry. It is also supported with prebuilt libraries by all popular logging frameworks. Including the UA stack logger in existing applications becomes a lot easier. - As a design decision, to avoid change of API signatures in the codebase, the logger in
Opc.Ua.Coreremains a singleton which is used by all depending libraries. Also due to some C# naming convention limitations the singleton forILoggerremains in theOpc.Ua.Utilsclass. - By default, a backward compatibility
TraceEventLoggeris initialized to support the existingTraceEventcallback. Once the logger strings are converted to semantic logging, the trace event callback gets the semantic version only, which may cause a format exception if directly passed toString.Format. Typically logging frameworks handle the semantic logging strings, but if not it is recommended to switch to the newILoggerbased interface. TheTraceEventinterface will be marked as deprecated after a transistion period. - In order to efficiently support the existing logging all the
LoggerExtensionsfunctions are integrated inOpc.Ua.Utilsas static functions instead of the Logging extension functions. This approach also allows to call theEventSourcelogger if enabled. - For high frequency logging calls, e.g. to log monitored items data, the
EventSourcesupports dedicated methods in theUtils.EventLogimplementation class, to keep the overhead of such logging calls as low as possible and to avoid boxing. These methods may route logging calls back to theUtils.LogXXXmethods if no EventListener is enabled. - The
EventSourcesingleton, calledEventLog, has also seperate implementations in theOpc.Ua.ClientandOpc.Ua.Serverlibraries. The rational for seperate event source implementations is to seperate the library implementation from the core library and to allow for hooking up an event listener to specifically log client or server or core events. The implementation in the client and server library is available from theClientUtilsandServerUtilsclass. - The existing
Utils.Tracelogging functions are mapped in a best effort to the newILoggerinterface. Existing application should still work and log information as previously, even after updating to the latestOpc.Ua.Corelibrary with the new logging support. TheUtils.Tracemethods will be marked as deprecated after a transistion period. - The new
ILoggerinterface is available directly as a singletonOpc.Ua.Utils.Loggerinterface. But using this interface is quite cumbersome, theUtils.LogXXXfunctions should rather be used. - In order to support
EventSourcelogging there is another singleton with the high performance logging interface exposed asOpc.Ua.Utils.EventLog. There are also seperateEventLogsingletons for theOpc.Ua.ClientandOpc.Ua.Serverlibraries, to allow for specific logging in these libraries. - An application can override the
ILoggerwith its own implementation by calling the newOpc.Ua.Utils.SetLoggermethod. Then the existing logging withTraceEventsis disabled. However tracing withEventSourceis still possible, even after theILoggeris replaced. For best performance, once logging through aEventListenerstarts, all logging through the externally setILoggerinterface is disconnected. - To update existing applications to use the new logging functions, the following changes have to be made:
Utils.Traceis replaced byUtils.LogXXX, whereXXXcorresponds to the log level. The supported log levels are:Critical,Error,Warning,Information,DebugandTrace.- If a tracemask was used, the tracemask can be passed to
Utils.LogXXXas theEventId. The tracemask is still used to filter events at the Trace level. - Other parameters can be passed in as required, there is support for exceptions, format strings and format parameters.
- Using the built in file logging or TraceEvent callback is not recommended anymore, choose a logging framework which supports the
Microsoft.Extensions.Logging.Abstractions.ILoggerinterface as a source or even theMicrosoft.Extensions.Loggingframwork as application logger. - Many frameworks already supply Nuget packages for the
ILoggerinterface as a logger source. Instantiate anILoggerinstance and call theUtils.SetLoggermethod to hook up the logging framework.
- Full support for structured logging has been added to the core library, however, the format strings have not been decorated yet with semantic information. Structured logging requires to replace the format parameters like
{0}by a name, e.g.{ChannelId}. Currently theTraceEventcallback does not convert the structured logging format strings because it will be deprecated. Once the semantic information is added a TraceEvent based logger may run intoFormatExceptionscallingString.Format. If the Trace Events are consumed in the application by engines like Serilog, which support semantic logging, no issues should occur. - There is no attempt made to support
ActivitiesorScopesfrom within the UA stack core codebase yet. How to achieve the goal to support correlation ids is still under investigation and we are happy to receive feedback. - The best use of the
EventIdparameter is still under investigation. Currently it is only used to support the tracemask used by existing logging calls. The tracemask is passed toTraceEventfor filtering and for backward compatibility. - Not all log functions with frequent log output have been ported yet to support the
EventSourcemodel. Please expect more improvements in this area once we get more feedback. - Samples are provided for Serilog and the Microsoft Extensions logging framework, but there is no sample yet for OpenTelemetry, Nlog and other popular logging frameworks.
The ConsoleReferenceClient and the ConsoleReferenceServer have been modified to show how to use a Serilog logging provider with new ILogger interface.
The file logging provider uses the Information or Verbose level depending on the chosen Tracemasks and the file location used in the configuration file.
The console logger uses the Information level by default and is enabled using the command line option -c. App output can be redirected to log using the -l option.
A command file for windows called dotnettrace.cmd is provided to capture .NET traces using the EventSource of the OPC-UA-* providers.
The trace tool is installed using:
dotnet tool install --global dotnet-trace,
The trace is captured from a running application with the following command:
dotnet-trace collect --name consolereferenceserver --providers OPC-UA-Core,OPC-UA-Client,OPC-UA-Server
Perfview on Windows shows the traces captured in the .nettrace files.