Files
Marc Schier 8d2402c995 Bump version to 2.0 and land 1.5.378 to 2.0 migration guide (#3819)
Prepares the repository for a 2.0 release: bumps every version reference
from 1.6 to 2.0, and lands the migration guide describing the 1.5.378 →
2.0 upgrade path. The 1.6 line never shipped, so this is a straight
rename with no historical 1.6 migration content to preserve.

The PR is split into two commits:

1. **`Bump version to 2.0 (next release is a major version change)`** —
version metadata, NuGet metadata, the side documentation, and the
migration agent file.
2. **`[Docs] Close 19 audit gaps in 1.5.378 to 2.0 migration guide`** —
adds and reorganizes `Docs/MigrationGuide.md` to close every gap from a
rigorous code-review audit of the 1.5.378 → 2.0 breaking-change surface.

### Version bump (commit 1)

- `version.json`: `1.6-preview` → `2.0-preview`
- `common.props`: `<VersionPrefix>1.6</VersionPrefix>` →
`<VersionPrefix>2.0</VersionPrefix>`
- `nuget/Opc.Ua.nuspec` and `nuget/Opc.Ua.Symbols.nuspec`: `1.6.0` →
`2.0.0`
- `README.md`: "New in 1.6" → "New in 2.0"
- `Docs/ComplexTypes.md`, `Docs/Observability.md`, `Docs/Sessions.md`:
1.6 → 2.0 mentions
- Renames `.github/agents/opcua-v16-migration.agent.md` →
`.github/agents/opcua-v20-migration.agent.md` and updates the agent
metadata (name, description, trigger phrases, version table)
- `UA.slnx`: solution-items reference updated to the new agent filename
-
`Tools/Opc.Ua.SourceGeneration.Core/Generators/ObjectTypeProxyGenerator.cs`:
two v16 → v20 comment fixes

### Migration guide (commit 2)

Closes 19 gaps from an audit comparing `master378` (1.5.378) with
`master` (2.0). Adds a new top-level **Package, Target Framework and
Dependency Changes** section covering the new `Opc.Ua.Core.Types` and
`Opc.Ua.Security.Certificates` packages, the `LibTypesTargetFrameworks`
netstandard2.0 drop, the NuGet dependency additions/removals, and the
residual Newtonsoft.Json dependency in `Opc.Ua.PubSub`.

In-place additions:

- new H4 for `INodeManager3` under Node States
- `Session.Call` `Variant.From` worked example
- new H3 `Subscriptions and Transports` with H4 verdicts for Durable
subscriptions (source-breaking), PubSub (no source break) and Reverse
connect (no source break)
- new H3 `Telemetry and Logging` covering `ITelemetryContext`
constructor-injection patterns
- `in DataValue` async copy-to-local pattern
- UNSAFE / SAFE pair for `WithPoolNotifications` pooling
- using-alias example for classic vs V2 `SubscriptionOptions`
- "Silent regression" callout for `OnAfterCreate`
- numbered lifecycle ordering for
`ApplicationConfiguration.CertificateManager`

Corrections:

- clarifies that the `SessionReconnectHandler` `[Obsolete]` is still
present in 2.0 (not withdrawn);
- clarifies that the source-generated `ServerCapability` constants vs
the `ServerCapabilityInfo` registry type are distinct;
- disambiguates `ReconnectPolicyOptions` (DTO) from `ReconnectPolicy`
(runtime).

Adds an "Automate the migration" pointer to the forthcoming
`Opc.Ua.CodeFixers` analyzer package, which mechanizes 17 of the
patterns covered in this guide. The analyzer is published in a follow-up
PR.
2026-05-29 08:18:41 +02:00

719 lines
35 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Observability model of the OPC UA .NET Standard Stack
## Context: Historic approach of logging inside the UA .NET and UA .NET Standard stack
### 1.4.367 and earlier
The codebase up until version 1.4.367 used static tracing to support logging. The `Utils.Trace` function was used to log
messages in the codebase with message format strings and arguments as format parameters, along with optional
`TraceMasks` and `Exceptions`. The logging system was configured via the `ApplicationConfiguration` section for
`TraceConfiguration` to specify the `OutputFilePath` and `TraceMasks`.
### Changes introduced in 1.4.368
In 1.4.368 we introduced a global `ILogger` interface which is defined in `Microsoft.Extensions.Logging.Abstractions`
as core abstraction for logging functions. To avoid change of API signatures in the codebase the logger in `Opc.Ua.Core`
remained a singleton used by all depending libraries.
By default, a backward compatibility `TraceEventLogger` was initialized to support the existing `TraceEvent` callback.
An application can override the `ILogger` with its own implementation by calling the new `Opc.Ua.Utils.SetLogger`
method. 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 to `String.Format`. Typically logging frameworks handle the
semantic logging strings, but if not it is recommended to switch to the new `ILogger` based interface. The `TraceEvent`
interface will be marked as deprecated after a transistion period.
In order to efficiently support the existing logging all the `LoggerExtensions` functions are integrated in
`Opc.Ua.Utils` as static functions instead of the Logging extension functions. `Utils.Trace` is replaced by
`Utils.LogXXX`, where `XXX` corresponds to the log level. The supported log levels are: `Critical`, `Error`, `Warning`,
`Information`, `Debug` and `Trace`. This approach also allows to call the `EventSource` logger if enabled.
This logging approach does not support structured logging and does not fit well with the overall `ILoggerProvider`
model. `Activities` or `Scopes` are also not supported. The `EventId` parameter is used to plumb through trace masks
which means it cannot be used to replace EventSource. The approach also does not allow support for source generated
logging, but worse, it requires a single logging context in the same process, prohibiting you from running server
and clients with different logging mechanism.
## Telemetry context design introduced in 1.5.378
The new and more flexible observability design introduced in 1.5.378 deprecates and in part removes the previous
model with the intend of supporting dependency injection, structured logging and OpenTelemetry based [observability
(metrics, traces and logs)](https://learn.microsoft.com/dotnet/core/diagnostics/). `ITelemetryContext`
standardizes how logging, tracing and metrics are accessed, removes prior limitations of a singleton logger,
and aligns the stack with current .NET and OpenTelemetry practices. The logger design follows common
[guidance for library authors](https://learn.microsoft.com/dotnet/core/extensions/logging-library-authors).
The `ITelemetryContext` interface provides access to the `ILoggerFactory`, `Activity` sources and acts as a `Meter`
factory (the latter two are used to create OpenTelemetry compliant traces and metrics).
### `ITelemetryContext` overview
```csharp
public interface ITelemetryContext
{
// Creates a new Meter for recording metrics (caller disposes).
Meter CreateMeter();
// Factory used to create typed ILogger instances.
ILoggerFactory LoggerFactory { get; }
// Shared ActivitySource representing the current assembly/component.
ActivitySource ActivitySource { get; }
}
```
This single abstraction covers logs, traces and metrics. External dependencies (`ILoggerFactory`, `ActivitySource`,
`Meter`) are localized. This promotes dependency injection by enabling passing one context instead of many
singletons.
Lifetime semantics are explicit: callers dispose meters they create while the context owns the long‑lived
activity source. Multiple telemetry context can be hosted in the same process, e.g. running a server and a client
or multiple servers with different logging configurations in a container.
The `ActivitySource` is a context scoped instance representing the current assembly or component and long lived.
A `Meter` is created when a component needs instruments. It is owned by the caller and must be disposed when no
longer needed.
The `LoggerFactory` is long lived and allows creation of typed `ILogger` instances which are maintained by the
caller. [Documentation can be found here](https://learn.microsoft.com/dotnet/core/extensions/logging).
In addition there are several extension methods to simplify usage of telemetry context:
```csharp
public static class TelemetryExtensions
{
// Creates a logger for the specified category.
ILogger CreateLogger(this ITelemetryContext context, string categoryName);
ILogger<T> CreateLogger<T>(this ITelemetryContext context);
// Starts a new Activity with the shared ActivitySource.
Activity StartActivity(this ITelemetryContext context, string activityName, ActivityKind kind = ActivityKind.Internal);
}
```
Always use these extension methods! They ensure that null telemetry contexts produce a backwards compatible trace
logger in release builds, and a debug check enabled logger in debug builds. This allows gradual adoption and
verification of the new telemetry model.
### High speed logging and instruments
For high speed logging we are using source generated logging and instruments throughout the code and code will be
gradually enabled to use source generated logging and instruments, enabling us to turn roslyn analzers on to warn
if new logging is added without source generation.
### Obtaining a telemetry context
Telemetry context should be passed (only) via constructors. This enables dependency injection and testability
and the creation of `readonly` logger and meter fields. It also aligns with the lifecycle of the owning class, e.g.
`Dispose` calls disposing the obtained meter.
In addition to being passed as part of a class/service's constructor, existing code can obtain a `ITelemetryContext`
from `IServiceMessageContext.Telemetry`, `ISystemContext.Telemetry` or `IServerInternal.Telemetry`. This allows
gradual adoption but also provides telemetry context to frequently used capabilities, such as encoders, session
users, or filtering. On the server side, `ISystemContext` is passed to many methods, allowing access to telemetry.
On the client side, IServiceMessageContext is available from `ISession` as a property.
In server context or when code is shared between client and server use the following priority should there be
ambiguity of where to obtain the telemetry context from:
0. From a `ITelemetryContext` member variable (e.g. `m_telemetry`) of the current class. If the constructor is passed
any of the types in this list pick the first and assign a private readonly m_telemetry variable then use it
everywhere in the current class. You might want to create a logger at the same time if it is needed.
1. `ISystemContext.Telemetry`
2. `IServerInternal.Telemetry`
3. `IServiceMessageContext.Telemetry`
In pure client context use the following priority should there be ambiguity of where to obtain the telemetry context from:
0. From a `ITelemetryContext` member variable (e.g. `m_telemetry`) of the current class initialized in the constructor
from any context in this list. Same as above.
1. `ISession` via `session.MessageContext.Telemetry`
2. `ISystemContext.Telemetry`
3. `IServiceMessageContext.Telemetry`
When deriving from `NodeState` and the derived class requires an `ITelemetryContext`, the subclass can override the
`void Initialize(ITelemetryContext)` method and store the context in a private field. Ensure to call the base class
so that it also receives the telemetry context. The Initialize method is called after creation of the NodeState
instance and before any other method is called.
To create a telemetry context you can use the `public ITelemetryContext DefaultTelemetry.Create()` static
method. Do not create new telemetry contexts in cases where you have no access to one but try to wire it from
an area in code where you have to the place you need it. Best to initialize the telemetry context at the root
of your application, e.g. at time you create a `new ApplicationInstance(...)`. See [migrating](#migrating)
for more information.
### Using the telemetry context
Code should always use the `ITelemetryContext` extension methods to create loggers, meters and activities.
This ensures proper fallback to tracing if `ITelemetryContext` is null or returns null for any of its properties.
A caller can be assured that the returned logger, meter or activity is never null.
Example usage:
```csharp
// Obtain telemetry context
ITelemetryContext telemetry = xxxxx.Telemetry;
// Logging
var logger = telemetry.CreateLogger("Sample");
// or
var logger = telemetry.CreateLogger<MyClass>();
logger.LogInformation("Connecting to {Endpoint}", endpointUrl);
// Tracing
using var activity = telemetry.StartActivity("ConnectSession");
// Perform OPC UA operation ...
// Metrics
using var meter = telemetry.CreateMeter();
var connectCounter = meter.CreateCounter<long>("my.app.connects");
connectCounter.Add(1);
```
The `ConsoleReferenceClient` and the `ConsoleReferenceServer` have been modified to show how to use ILogger and
ITelemetryContext.
When a logger or meter is created it should always be stored it in a readonly field inside the class inside the
constructor.
Logger instances are cached inside the `ILoggerProvider` Logger provider, therefore obtaining one is relatively
cheap. However, the cost of the size of the reference should be considered when creating loggers for large number
of objects such as NodeState or NodeId instances.
In most cases consider the following refactoring patterns:
- Only pass an ILogger instance via constructor to objects that need it, e.g. NodeState derived classes can
choose to create a ILogger but do not have to.
- It is better to create a logger in the class using it and handling "Loggable" events by throwing exceptions
from the "model" object. Example: parsing a NodeId could throw when it fails with the caller deciding to convert
the exception to a null node id and logging or throwing the exception on. A TryParse is typically the better
api model, with options to handle failures (e.g. today we log a warning, but tomorrow we could add a parsing
option that determines whether in the warning case we should throw or gracefully handle the parsing.
- Separate "service" classes that manage large number of objects can be created and passed the telemetry context
via constructor. The service class can then create loggers and meters as needed. Example: a NodeStateManager
that manages a large number of NodeState instances and handles logging for them. We intend to follow this
pattern for certificate handling, storage, and general configuration management (vs. today's data contract
model)
In some cases the ILogger or Meter can be created in a class and passed to other classes that are created in the
context of the out class. One example is the message objects in the PubSub stack.
If that is not possible it is best to initialize the field with a `Telemetry.NullLogger` which will avoid null
reference exceptions. Note that the `Telemetry.NullLogger` is different from `NullLogger.Instance` which it returns
only in release builds. In debug builds `Telemetry.NullLogger.Instance` is a debug check logger which will
throw if any logging method is called. This allows to verify that a logger is not used before a ITelemetryContext
is available. Such code shall be gradually refactored.
### Other temporary compromises
The current codebase is still relying on some static methods and static classes, the
telemetry context is added as argument to these static methods or to methods that belong to classes that are
instantiated via default constructors and are effectively static too (e.g. anything that is DataContract
serializable). The goal is to eventually remove static utilities and pass the context through constructors only.
The static `CertificateFactory.Create / CreateCertificate / CreateCertificateWith{,PEM}PrivateKey` methods are
now `[Obsolete]` and forward to `Certificate.FromRawData(...)` / `DefaultCertificateFactory.Instance.*` /
`DefaultCertificateIssuer.Instance.*`. Internal callers have been migrated; new code should use the new
factory/issuer interfaces (or their singletons) directly. See [CertificateManager.md](CertificateManager.md).
Meanwhile, any passing of `ITelemetryContext` to "public" static methods was done by adding it as the last optional
argument with a default null value except for async methods, where it comes before the CancellationToken argument.
While it does not promote adoption which a Obsolete tagged method would it makes for smaller/simpler code changes.
`IServiceMessageContext` access is at times needed in places where no context is available. For these situations
an ambient `ServiceMessageContext` is available as an async local, e.g. when using the decoder during
deserialization of extension objects. This is a compromise until the codebase is refactored to pass the telemetry
context through constructors into "service" classes that manage things like parsing, loading, deserialization, etc.
The ambient model is marked as `Experimental` at this point and should not be used in new code.
These issues will be addressed over time by refactoring the code base to be dependency injection friendly.
### Opt out
The simplest is to use a dummy implementation of `ITelemetryContext` such as
```csharp
sealed class NullTelemetry : TelemetryContextBase
{
public NullTelemetry()
: base(NullLoggerFactory.Instance) // <--- This comes from Microsoft.Extensions.Logging.Abstractions
{
}
}
```
It is also possible to pass `null` for a `ITelemetryContext` parameter, but this is not recommended as it
will cause the code to fallback to the old tracing model and may cause format exceptions if the trace logger
is not configured to handle semantic logging.
### Migrating
#### Important context - read first
- Breaking Changes to be aware of upfront. While affecting public signatures, much of the updated API can be
considered internal and the effect on current code is expected to be low. Generally affected are:
1. **Core infrastructure classes** (`ServiceMessageContext`, `EncodeableFactory`) no longer have parameter-less constructors.
2. **Transport binding factories** require telemetry context in `Create()` methods
3. **Certificate operations** require telemetry context parameters
4. **Client session and subscription classes** require telemetry in constructors
Details [below](#non-exhaustive-summary-of-breaking-changes-and-deprecations-as-part-of-the-implementation).
- Existing static `Utils.Trace` and `Utils.Log` methods are marked deprecated but continue to work using the old
tracing model. They are however not tested anymore and usage is advised against.
- The static ILogger model via `Utils.SetLogger` API has been **completely** removed. Callers should create a new
`ApplicationInstance` with a default telemetry context, or custom telemetry context for their application.
- See [Obtaining a telemetry context](#obtaining-a-telemetry-context) for how to get a telemetry context in existing
code and guidelines above.
- See [Using the telemetry context](#using-the-telemetry-context) for how to use the telemetry context.
- See the official documentation for ILoggerFactory and ILogger for more details on logging.
- Use Github Copilot to make the changes in your codebase by pointing to this document.
#### Utilities
To aid migration, the following functionality is provided:
- A default telemetry context (`DefaultTelemetry`) which when created using the default constructor provides trace based
logging via the `Utils.LoggingProvider` provider.
- A NullLogger (not the one in `Microsoft.Extensions.Logging.Abstraction` nuget package). This `Utils.Null.Logger` and
`Utils.Null<T>.Logger` can not be instantiated but obtained via its `static Logger` property.
This logger can be used to initialize a `m_logger` to prevent null reference exceptions. In release builds it is a
dummy, in debug builds it debug checks and crashes the application with stack trace.
- A Logger that can be used to replace the `Utils.LogXXX` calls called `Utils.Fallback.Logger` and can be used in places
where no telemetry context can be plumbed through (for example static global properties) or in cases where a ILogger
is required in the method signature but a null was passed by the caller. The logger can be used just
like the old static `ILogger`, e.g. `Utils.Fallback.Logger.LogInformation(...)`. However, it must be temporary and a
proper refactoring of the area is advised as such the Fallback class has been marked as Experimental and can be removed
at any point in time in future releases.
When running the tests in debug, wherever a null telemetry is used triggers a debug check (`Debug.Fail`) to crash the
system in this case. When linking applications to the debug stack they can take advantage of this capability.
#### From Static Logger Management
```csharp
// OLD - No longer works
Utils.SetLogger(myLogger);
Utils.SetLogLevel(LogLevel.Information);
// NEW - Use ITelemetryContext
var telemetryContext = DefaultTelemetry.Create(builder => builder.AddConsole());
var applicationInstance = new ApplicationInstance(telemetryContext);
```
#### From Static Logging Methods
```csharp
// OLD - Obsolete
Utils.LogInformation("Connection established to {0}", endpoint);
Utils.LogError(exception, "Failed to connect to {0}", endpoint);
// NEW - Context-based logging
var logger = telemetryContext.CreateLogger<MyClass>();
logger.LogInformation("Connection established to {Endpoint}", endpoint);
logger.LogError(exception, "Failed to connect to {Endpoint}", endpoint);
```
#### From Trace Methods
```csharp
// OLD - Obsolete
Utils.Trace("Processing request {0}", id);
Utils.Trace(TraceMasks.Information, "Request processed successfully");
// NEW - Structured logging with context
var logger = telemetryContext.CreateLogger<MyClass>();
logger.LogInformation("Processing request {RequestId}", id);
logger.LogInformation("Request processed successfully");
```
## Non-exhaustive summary of breaking changes and deprecations as part of the implementation
### 1. Core Infrastructure Classes - Constructor Changes
#### `Opc.Ua.ServiceMessageContext`
**File:** `Stack/Opc.Ua.Core/Types/Utils/ServiceMessageContext.cs`
- **REMOVED:** `public ServiceMessageContext()` - Parameter-less constructor used by stack only.
- **ADDED:** `public ServiceMessageContext(ITelemetryContext telemetry)` - Now requires telemetry context
- **ADDED:** `public ServiceMessageContext(IServiceMessageContext context, ITelemetryContext telemetry)` - Copy constructor with telemetry
#### `Opc.Ua.EncodeableFactory`
**File:** `Stack/Opc.Ua.Core/Types/Encoders/EncodeableFactory.cs`
- **REMOVED:** `public EncodeableFactory()` - Parameter-less constructor used by stack only.
- **ADDED:** `public EncodeableFactory(ITelemetryContext telemetry)` - Now requires telemetry context
- **ADDED:** `public EncodeableFactory(IEncodeableFactory factory, ITelemetryContext telemetry)` - Copy constructor with telemetry
#### `Opc.Ua.ApplicationConfiguration`
**File:** `Stack/Opc.Ua.Core/Schema/ApplicationConfiguration.cs`
- **ADDED:** `public ApplicationConfiguration(ITelemetryContext telemetry)` - New constructor with telemetry context
**File:** `Stack\Opc.Ua.Core\Stack\Types\ContentFilter.cs`
- **REMOVED:** `public ContentFilter.Evaluate(...)` - Moved to new `FilterEvaluator` class which requires telemetry context
- **ADDED:** `FilterEvaluator` class that encapsulates a filter evaluation operation with result returned as `Result` property.
Various other methods in Content filter were modified to pass telemetry context or logger, but those are used mostly internally
to the stack.
### 2. Interface Changes
#### `IServiceMessageContext`
**File:** `Stack/Opc.Ua.Core/Types/Utils/IServiceMessageContext.cs`
- **ADDED:** `ITelemetryContext Telemetry { get; }` - New property that implementations must provide
#### `ITransportBindingFactory<T>`
**File:** `Stack/Opc.Ua.Core/Stack/Bindings/ITransportBindings.cs`
- **MODIFIED:** `T Create(ITelemetryContext telemetry)` - Method signature changed to require telemetry parameter. Used by stack code only.
### 3. System Context Classes
#### `Opc.Ua.SystemContext`
**File:** `Stack/Opc.Ua.Core/Stack/State/ISystemContext.cs`
- **REMOVED:** creation via default constructor. Used by stack code only.
- **ADDED:** `public SystemContext(ITelemetryContext telemetry)` - New constructor
- **ADDED:** `public SystemContext(IOperationContext context, ITelemetryContext telemetry)` - New constructor with telemetry
### 4. Certificate and Security Classes
#### `Opc.Ua.CertificateValidator`
**File:** `Stack/Opc.Ua.Core/Security/Certificates/CertificateValidator.cs`
- **ADDED:** `public CertificateValidator(ITelemetryContext telemetry)` - Constructor now requires telemetry context. Used by stack code only.
#### `Opc.Ua.CertificateStoreIdentifier`
**File:** `Stack/Opc.Ua.Core/Security/Certificates/CertificateStoreIdentifier.cs`
- **MODIFIED:** `public static ICertificateStore CreateStore(string storeTypeName, ITelemetryContext telemetry)` - Added telemetry parameter. Used by stack code only. However, custom stores need to change their implementation.
- **MODIFIED:** `public virtual ICertificateStore OpenStore(ITelemetryContext telemetry)` - Added telemetry parameter. Used by stack code only. However, custom stores need to change their implementation.
#### `Opc.Ua.CertificateIdentifier`
**File:** `Stack/Opc.Ua.Core/Security/Certificates/CertificateIdentifier.cs`
- **MODIFIED:** `public ICertificateStore OpenStore(ITelemetryContext telemetry)` - Added telemetry parameter. Used by stack code only. However, custom stores need to change their implementation.
##### `CertificateIdentiferCollection`
- **REMOVED**: `ICertificateStore` interface removed, pass to `CertificateIdentifierCollectionStore` to make it a **readonly** store as before.
#### Certificate Store Classes
##### `CertificateIdentifierCollectionStore`
**NEW**, replaces `ICertificateStore` interface on CertificateIdentifierCollection, which should not implement the store interface. Used internally only, so no impact.
##### `DirectoryCertificateStore`
**File:** `Stack/Opc.Ua.Core/Security/Certificates/DirectoryCertificateStore.cs`
- **REMOVED:** creation via default constructor. Used by stack code only.
- **ADDED:** `public DirectoryCertificateStore(ITelemetryContext telemetry)`
- **ADDED:** `public DirectoryCertificateStore(bool noSubDirs, ITelemetryContext telemetry)`
##### `X509CertificateStore`
**File:** `Stack/Opc.Ua.Core/Security/Certificates/X509CertificateStore/X509CertificateStore.cs`
- **REMOVED:** creation via default constructor. Used by stack code only.
- **ADDED:** `public X509CertificateStore(ITelemetryContext telemetry)`
### 5. Transport Layer Breaking Changes
#### Transport Channel Factories
##### `TcpTransportChannel`
**File:** `Stack/Opc.Ua.Core/Stack/Tcp/TcpMessageSocket.cs`
- **REMOVED:** creation via default constructor. Used by stack code only.
- **ADDED:** `public TcpTransportChannel(ITelemetryContext telemetry)`
- **MODIFIED:** `public ITransportChannel Create(ITelemetryContext telemetry)` - Added telemetry parameter
#### Transport Listeners
##### `TcpTransportListener`
**File:** `Stack/Opc.Ua.Core/Stack/Tcp/TcpTransportListener.cs`
- **REMOVED:** creation via default constructor. Used by stack code only.
- **ADDED:** `public TcpTransportListener(ITelemetryContext telemetry)`
##### `HttpsTransportListener`
**File:** `Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsTransportListener.cs`
- **MODIFIED:** `public HttpsTransportListener(string uriScheme, ITelemetryContext telemetry)` - Added telemetry parameter. Used by stack code only.
#### Transport Bindings
##### `TransportBindings`
**File:** `Stack/Opc.Ua.Core/Stack/Bindings/TransportBindings.cs`
- **MODIFIED:** `public ITransportChannel GetChannel(string uriScheme, ITelemetryContext telemetry)` - Added telemetry parameter. Used by stack code only.
- **MODIFIED:** `public ITransportListener GetListener(string uriScheme, ITelemetryContext telemetry)` - Added telemetry parameter. Used by stack code only.
### 6. Client Library Breaking Changes
#### `Opc.Ua.Client.SessionClient`
**File:** `Stack/Opc.Ua.Core/Stack/Client/SessionClient.cs`
- **ADDED:** `public SessionClient(ITransportChannel channel, ITelemetryContext telemetry)` - Constructor requires telemetry. Used by derived types which are stack code only.
#### `Opc.Ua.Client.Subscription`
**File:** `Libraries/Opc.Ua.Client/Subscription/Subscription.cs`
- **ADDED:** `public Subscription(ITelemetryContext telemetry)` - Constructor with telemetry. Otherwise telemetry will be attached to subscription when calling `AddSubscription`.
#### `Opc.Ua.Client.Browser`
**File:** `Libraries/Opc.Ua.Client/Browser.cs`
- **ADDED:** `public Browser(ISession session, ITelemetryContext telemetry)` - Constructor with telemetry. Otherwise set via new Telemetry property.
#### `Opc.Ua.Client.ReverseConnectManager`
**File:** `Libraries/Opc.Ua.Client/ReverseConnectManager.cs`
- **ADDED:** `public ReverseConnectManager(ITelemetryContext telemetry)` - Constructor requires telemetry, default constructor marked as deprecated.
#### Session Factories
##### `DefaultSessionFactory`
**File:** `Libraries/Opc.Ua.Client/Session/DefaultSessionFactory.cs`
- Creates raw `Session` instances (unchanged from earlier versions).
- **ADDED:** `public DefaultSessionFactory(ITelemetryContext telemetry)` - Constructor requires telemetry, default constructor marked as deprecated.
##### `ManagedSessionFactory`
**File:** `Libraries/Opc.Ua.Client/Session/ManagedSessionFactory.cs`
- **ADDED** in 2.0 as a new factory.
- Creates `ManagedSession` instances that automatically handle reconnection and failover.
- Uses `DefaultSessionFactory` internally to create the raw `Session` that is wrapped by `ManagedSession`.
- Constructor: `public ManagedSessionFactory(ITelemetryContext telemetry)`.
##### `TraceableSessionFactory`
**File:** `Libraries/Opc.Ua.Client/Session/Factory/TraceableSessionFactory.cs`
- **ADDED:** `public TraceableSessionFactory(ITelemetryContext telemetry)`- Constructor requires telemetry, default constructor marked as deprecated.
#### `TraceableSession`
**File:** `Libraries/Opc.Ua.Client/Session/TraceableSession.cs`
- **ADDED:** `public TraceableSession(ISession session, ITelemetryContext telemetry)` - Constructor requires telemetry, non telemetry constructors marked as deprecated.
#### `ComplexTypeSystem`
**File:** `Libraries/Opc.Ua.Client.ComplexTypes/ComplexTypeSystem.cs`
- **ADDED:** `public ComplexTypeSystem(..., ITelemetryContext telemetry)` - Constructors require telemetry, non telemetry constructors marked as deprecated.
#### `SessionReconnectHandler`
**File:** `Libraries/Opc.Ua.Client/Session/SessionReconnectHandler.cs`
- **ADDED:** `public SessionReconnectHandler(ITelemetryContext telemetry, bool reconnectAbort = false, int maxReconnectPeriod = -1)` - Constructor requires telemetry, non telemetry constructors marked as deprecated.
### 7. Configuration Library Breaking Changes
#### `Opc.Ua.Configuration.ApplicationInstance`
**File:** `Libraries/Opc.Ua.Configuration/ApplicationInstance.cs`
- **ADDED:** `public ApplicationInstance(ITelemetryContext telemetry)` - Constructor requires telemetry, non telemetry constructors marked as deprecated.
- **ADDED:** `public ApplicationInstance(ITelemetryContext telemetry, ApplicationConfiguration applicationConfiguration)` - Constructor requires telemetry, non telemetry constructors marked as deprecated.
#### `ConfiguredEndpointCollection`
**File:** `Stack/Opc.Ua.Core/Stack/Configuration/ConfiguredEndpoints.cs`
- **MODIFIED:** `public static ConfiguredEndpointCollection Load(string filePath, ITelemetryContext telemetry)` - Added telemetry parameter
- **MODIFIED:** `public static ConfiguredEndpointCollection Load(Stream istrm, ITelemetryContext telemetry)` - Added telemetry parameter
#### `ConfiguredEndpoint`
**File:** `Stack/Opc.Ua.Core/Stack/Configuration/ConfiguredEndpoints.cs`
- **MODIFIED:** `public Task UpdateFromServerAsync(ITelemetryContext telemetry, CancellationToken ct = default)` - Added telemetry parameter
### 8. Server Library Breaking Changes
#### Server Subscription Components
##### `DataChangeMonitoredItemQueue`
**File:** `Libraries/Opc.Ua.Server/Subscription/MonitoredItem/Queue/DataChangeMonitoredItemQueue.cs`
- **ADDED:** `public DataChangeMonitoredItemQueue(bool createDurable, uint monitoredItemId, ITelemetryContext telemetry)`
##### `EventMonitoredItemQueue`
**File:** `Libraries/Opc.Ua.Server/Subscription/MonitoredItem/Queue/EventMonitoredItemQueue.cs`
- **ADDED:** `public EventMonitoredItemQueue(bool createDurable, uint monitoredItemId, ITelemetryContext telemetry)`
##### `MonitoredItemQueueFactory`
**File:** `Libraries/Opc.Ua.Server/Subscription/MonitoredItem/Queue/MonitoredItemQueueFactory.cs`
- **ADDED:** `public MonitoredItemQueueFactory(ITelemetryContext telemetry)`
### 9. PubSub Library Breaking Changes
#### `UaPubSubApplication`
**File:** `Libraries/Opc.Ua.PubSub/UaPubSubApplication.cs`
- **MODIFIED:** `public static UaPubSubApplication Create(IUaPubSubDataStore dataStore, ITelemetryContext telemetry)` - Added telemetry parameter, must update
#### `UaPubSubConfigurator`
**File:** `Libraries/Opc.Ua.PubSub/Configuration/UaPubSubConfigurator.cs`
- **ADDED:** `public UaPubSubConfigurator(ITelemetryContext telemetry)` - Constructor requires telemetry, must update
#### Transport Components
##### `UdpClientBroadcast`
**File:** `Libraries/Opc.Ua.PubSub/Transport/UdpClientBroadcast.cs`
- **ADDED:** `public UdpClientBroadcast(IPAddress address, int port, UsedInContext pubSubContext, ITelemetryContext telemetry)`, only used internally.
##### `UdpClientUnicast`
**File:** `Libraries/Opc.Ua.PubSub/Transport/UdpClientUnicast.cs`
- **ADDED:** `public UdpClientUnicast(IPAddress localAddress, int port, ITelemetryContext telemetry)`, only used internally.
### 10. Method Signature Changes
#### `UserIdentityToken`
**File:** `Stack/Opc.Ua.Core/Stack/Types/UserIdentityToken.cs`
- **MODIFIED:** `public X509Certificate2 GetOrCreateCertificate(ITelemetryContext telemetry)` - must be called to create cert (previously done implicitly in Certificate getter but not anymore)
#### `ServerSecurityPolicy`
**File:** `Stack/Opc.Ua.Core/Schema/ApplicationConfiguration.cs`
- **ADDED:** `public static byte CalculateSecurityLevel(MessageSecurityMode mode, string policyUri, ILogger logger)` - Added version with ILogger parameter and deprecated non logger API
### 11. Removed and Obsolete APIs from Utils Static Class
#### Static Logger Management
- **`public static void SetLogger(ILogger logger)`** - Static logger assignment completely removed
- **`public static void SetLogLevel(LogLevel logLevel)`** - Static log level control completely removed
These methods now do nothing when called and should be replaced with the `ITelemetryContext` dependency injection pattern.
The following methods in the `Utils` class on the other hand are marked with`[Obsolete]` and will be removed
in future versions:
#### Trace Configuration Methods
- `public static void SetTraceOutput(TraceOutput output)`
- `public static int TraceMask { get; }`
- `public static void SetTraceMask(int masks)`
- `public static Tracing Tracing { get; }`
- `public static void SetTraceLog(string filePath, bool deleteExisting)`
- `public static bool UseTraceEvent { get; set; }`
#### Basic Trace Methods
- `public static void Trace(string message)`
- `public static void Trace(string format, params object[] args)`
- `public static void TraceDebug(string format, params object[] args)` (DEBUG only)
- `public static void Trace(Exception e, string message)`
- `public static void Trace(Exception e, string format, params object[] args)`
- `public static void Trace(Exception e, string format, bool handled, params object[] args)`
#### TraceMask-based Trace Methods
- `public static void Trace(int traceMask, string format, params object[] args)`
- `public static void Trace(int traceMask, string format, bool handled, params object[] args)`
- `public static void Trace<TState>(TState state, Exception exception, int traceMask, Func<TState, Exception, string> formatter)`
- `public static void Trace(Exception e, int traceMask, string format, bool handled, params object[] args)`
#### Debug Log Methods
- `public static void LogDebug(EventId eventId, Exception exception, string message, params object[] args)` (DEBUG only)
- `public static void LogDebug(EventId eventId, string message, params object[] args)` (DEBUG only)
- `public static void LogDebug(Exception exception, string message, params object[] args)` (DEBUG only)
- `public static void LogDebug(string message, params object[] args)` (DEBUG only)
#### Trace Log Methods
- `public static void LogTrace(EventId eventId, Exception exception, string message, params object[] args)`
- `public static void LogTrace(EventId eventId, string message, params object[] args)`
- `public static void LogTrace(Exception exception, string message, params object[] args)`
- `public static void LogTrace(string message, params object[] args)`
#### Information Log Methods
- `public static void LogInformation(EventId eventId, Exception exception, string message, params object[] args)`
- `public static void LogInformation(EventId eventId, string message, params object[] args)`
- `public static void LogInformation(Exception exception, string message, params object[] args)`
- `public static void LogInformation(string message, params object[] args)`
#### Warning Log Methods
- `public static void LogWarning(EventId eventId, Exception exception, string message, params object[] args)`
- `public static void LogWarning(EventId eventId, string message, params object[] args)`
- `public static void LogWarning(Exception exception, string message, params object[] args)`
- `public static void LogWarning(string message, params object[] args)`
#### Error Log Methods
- `public static void LogError(EventId eventId, Exception exception, string message, params object[] args)`
- `public static void LogError(EventId eventId, string message, params object[] args)`
- `public static void LogError(Exception exception, string message, params object[] args)`
- `public static void LogError(string message, params object[] args)`
- `public static void LogError(Exception e, string format, bool handled, params object[] args)`
#### Critical Log Methods
- `public static void LogCritical(EventId eventId, Exception exception, string message, params object[] args)`
- `public static void LogCritical(EventId eventId, string message, params object[] args)`
- `public static void LogCritical(Exception exception, string message, params object[] args)`
- `public static void LogCritical(string message, params object[] args)`
#### Generic Log Methods
- `public static void Log(LogLevel logLevel, string message, params object[] args)`
- `public static void Log(LogLevel logLevel, EventId eventId, string message, params object[] args)`
- `public static void Log(LogLevel logLevel, Exception exception, string message, params object[] args)`
- `public static void Log(LogLevel logLevel, EventId eventId, Exception exception, string message, params object[] args)`
- `public static void Log(int traceMask, string format, params object[] args)`
- `public static void Log(int traceMask, string format, bool handled, params object[] args)`