OpenTelemetry
Modern computing has seen more distributed systems scaled and more services added, such as with microservices and serverless applications. With this growth, service ownership across the system is allocated to different individuals, or even organizations. It is increasingly difficult to observe how these services depend on each and affect other services without a unified observability framework. This becomes clear after a deployment or during an outage when issue identification requires speed and accuracy.
OpenTelemetry is such a unified observability framework. It is a popular open-source observability framework for instrumenting, generating, collecting, and exporting telemetry data. It provides a common specification and protocol so that multiple services can furnish a unified version of traces, metrics, and logs. OpenTelemetry relies on components that participate in the observability model to be instrumented, which means the code emits traces, metrics, and logs.
Numerous managed ODP.NET and ODP.NET Core APIs have been instrumented to support OpenTelemetry observability and standards. Developers and operators can then customize the ODP.NET metrics collected.
ODP.NET OpenTelemetry Traces
Traces record the request paths taken either by an application or end user as they propagate through a multi-service architecture. Traces in OpenTelemetry are defined implicitly by their spans. A trace can be thought of as a directed acyclic graph of spans where the edges between spans are defined as parent/child relationships.
A span, or activity, represents an operation within a transaction. Each span encapsulates the following state:
-
Display name
-
ODP.NET NuGet version
-
Start timestamp and duration
-
Attributes – list of key-value pairs
-
Events – a tuple (timestamp, name, attributes) and can number from zero or more
-
The parent span identifier
-
Links to causally related spans through SpanContext, which can number from zero or more
ODP.NET spans become child spans if the application creates a (parent) span before calling ODP.NET instrumented APIs.
ODP.NET OpenTelemetry publishes the following activity tags, or attributes.
Table 3-43 ODP.NET OpenTelemetry activity tags
Attribute Name | Description |
---|---|
|
Activity display name or the name of the operation being instrumented. |
|
Database being accessed by the command. The attribute value is the same as the |
|
Gives each connection a unique identifier for diagnostic purposes. This identifier can be prefixed with a custom application generated string by setting the |
|
Row count affected by the SQL DML ( |
|
Oracle database SQL statement identifier value, equivalent to |
|
Redacted ODP.NET user-supplied command text which can differ from the database statement being executed, such as the case with stored procedures and XML commands |
|
Redacted database statement being executed |
|
Database name. |
|
Database user |
|
Exception message |
|
Exception stack trace |
|
Exception type |
|
Status code of the trace |
|
Status description of the trace |
|
Name of the database host |
|
Server port number |
ODP.NET OpenTelemetry Trace Sample Exporter Visualization:
Activity.TraceId: 29399ee7598dea88defd7c5421bc41d4
Activity.SpanId: e1878b5fc4435f23
Activity.TraceFlags: Recorded
Activity.ParentSpanId: 8487a50b9ace7808
Activity.ActivitySourceName: Oracle.ManagedDataAccess.Core
Activity.ActivitySourceVersion: 23.6.0
Activity.DisplayName: Connect MYHOSTNAME:1521:dbview
Activity.Kind: Client
Activity.StartTime: 2024-09-19T07:26:16.4615973Z
Activity.Duration: 00:00:00.4114888
Activity.Tags:
db.system: oracle
db.user: scott
db.name: dbview
server.address: MYHOSTNAME
server.port: 1521
StatusCode: Ok
Resource associated with Activity:
service.name: DemoApp
service.version: 1.0.0
service.instance.id: 312ec47d-c0a1-4df3-b59f-f38aa225c39d
telemetry.sdk.name: opentelemetry
telemetry.sdk.language: dotnet
telemetry.sdk.version: 1.9.0
Activity.TraceId: 29399ee7598dea88defd7c5421bc41d4
Activity.SpanId: 8487a50b9ace7808
Activity.TraceFlags: Recorded
Activity.ParentSpanId: 95b69d7844ae0dd3
Activity.ActivitySourceName: Oracle.ManagedDataAccess.Core
Activity.ActivitySourceVersion: 23.6.0
Activity.DisplayName: Open MYHOSTNAME:1521:dbview
Activity.Kind: Client
Activity.StartTime: 2024-09-19T07:26:16.3584252Z
Activity.Duration: 00:00:00.5781012
Activity.Tags:
db.system: oracle
db.user: scott
db.name: dbview
server.address: MYHOSTNAME
server.port: 1521
StatusCode: Ok
Resource associated with Activity:
service.name: DemoApp
service.version: 1.0.0
service.instance.id: 312ec47d-c0a1-4df3-b59f-f38aa225c39d
telemetry.sdk.name: opentelemetry
telemetry.sdk.language: dotnet
telemetry.sdk.version: 1.9.0
Activity.TraceId: 29399ee7598dea88defd7c5421bc41d4
Activity.SpanId: 89b3cd0b7b2d2f35
Activity.TraceFlags: Recorded
Activity.ParentSpanId: e0cf4916dc1e4328
Activity.ActivitySourceName: Oracle.ManagedDataAccess.Core
Activity.ActivitySourceVersion: 23.6.0
Activity.DisplayName: SendExecuteRequest MYHOSTNAME:1521:dbview
Activity.Kind: Client
Activity.StartTime: 2024-09-19T07:26:17.0031962Z
Activity.Duration: 00:00:00.0492725
Activity.Tags:
db.system: oracle
server.address: MYHOSTNAME
server.port: 1521
db.name: dbview
db.user: scott
db.statement: update Blogs set Blog_Name=? where Blog_Id=?
db.odp.sql_id: 71jyh89d1cz9r
StatusCode: Ok
Resource associated with Activity:
service.name: DemoApp
service.version: 1.0.0
service.instance.id: 312ec47d-c0a1-4df3-b59f-f38aa225c39d
telemetry.sdk.name: opentelemetry
telemetry.sdk.language: dotnet
telemetry.sdk.version: 1.9.0
Activity.TraceId: 29399ee7598dea88defd7c5421bc41d4
Activity.SpanId: e0cf4916dc1e4328
Activity.TraceFlags: Recorded
Activity.ParentSpanId: 95b69d7844ae0dd3
Activity.ActivitySourceName: Oracle.ManagedDataAccess.Core
Activity.ActivitySourceVersion: 23.6.0
Activity.DisplayName: ExecuteNonQuery MYHOSTNAME:1521:dbview
Activity.Kind: Client
Activity.StartTime: 2024-09-19T07:26:16.9671882Z
Activity.Duration: 00:00:00.1279960
Activity.Tags:
db.system: oracle
server.address: MYHOSTNAME
server.port: 1521
db.name: dbview
db.user: scott
db.statement: update Blogs set Blog_Name=? where Blog_Id=?
db.odp.rows_affected: 1
db.odp.sql_id: 71jyh89d1cz9r
StatusCode: Ok
Resource associated with Activity:
service.name: DemoApp
service.version: 1.0.0
service.instance.id: 312ec47d-c0a1-4df3-b59f-f38aa225c39d
telemetry.sdk.name: opentelemetry
telemetry.sdk.language: dotnet
telemetry.sdk.version: 1.9.0
Activity.TraceId: 29399ee7598dea88defd7c5421bc41d4
Activity.SpanId: 8d2ebac56ee5c04f
Activity.TraceFlags: Recorded
Activity.ParentSpanId: 95b69d7844ae0dd3
Activity.ActivitySourceName: Oracle.ManagedDataAccess.Core
Activity.ActivitySourceVersion: 23.6.0
Activity.DisplayName: Close MYHOSTNAME:1521:dbview
Activity.Kind: Client
Activity.StartTime: 2024-09-19T07:26:17.1450407Z
Activity.Duration: 00:00:00.0144354
Activity.Tags:
db.system: oracle
server.address: MYHOSTNAME
server.port: 1521
db.name: dbview
db.user: scott
StatusCode: Ok
Resource associated with Activity:
service.name: DemoApp
service.version: 1.0.0
service.instance.id: 312ec47d-c0a1-4df3-b59f-f38aa225c39d
telemetry.sdk.name: opentelemetry
telemetry.sdk.language: dotnet
telemetry.sdk.version: 1.9.0
Activity.TraceId: 29399ee7598dea88defd7c5421bc41d4
Activity.SpanId: 95b69d7844ae0dd3
Activity.TraceFlags: Recorded
Activity.ActivitySourceName: Test
Activity.DisplayName: SampleTestActivity
Activity.Kind: Internal
Activity.StartTime: 2024-09-19T07:26:16.2164456Z
Activity.Duration: 00:00:00.9785065
Resource associated with Activity:
service.name: DemoApp
service.version: 1.0.0
service.instance.id: 312ec47d-c0a1-4df3-b59f-f38aa225c39d
telemetry.sdk.name: opentelemetry
telemetry.sdk.language: dotnet
telemetry.sdk.version: 1.9.0
ODP.NET OpenTelemetry supports both dynamic and manual instrumentation. The next section describes how to set up each instrumentation method.
Dynamic and Manual Instrumentation
ODP.NET OpenTelemetry requires an exporter, such Jaeger or Zipkin, to visualize and analyze traces. These exporters are available as NuGet packages and will also include the OpenTelemetry SDK as a NuGet dependency.
ODP.NET OpenTelemetry manual instrumentation has the following requirements:
-
Oracle.ManagedDataAccess.OpenTelemetry
package available from NuGet Gallery. -
Exporter NuGet package, such as Console or Zipkin, which is used for instrumentation visualization.
-
OpenTelemetry SDK, which will be installed automatically with an exporter NuGet package.
Once the ODP.Net OpenTelemetry
nuget package is installed, ODP.NET OpenTelemetry is enabled by invoking the TracerProviderBuilder
AddOracleDataProviderInstrumentation
extension method upon application startup. It accepts various options for configuring OpenTelemetry instrumentation.
Code sample: Enabling ODP.NET OpenTelemetry instrumentation with default options
using OpenTelemetry.Trace; Sdk.CreateTracerProviderBuilder() .AddOracleDataProviderInstrumentation() // ODP.NET extension method .AddConsoleExporter() .Build();
Code sample: Enabling ODP.NET OpenTelemetry instrumentation with all options enabled
using OpenTelemetry.Trace; Sdk.CreateTracerProviderBuilder() .AddOracleDataProviderInstrumentation(o => { o.EnableConnectionLevelAttributes = true; o.RecordException = true; o.InstrumentOracleDataReaderRead = true; o.SetDbStatementForText = true; }) .AddConsoleExporter() .Build();
After enabling ODP.NET OpenTelemetry, whenever a provider instrumented API is called, OpenTelemetry traces will be generated and sent to the configured exporter.
By default, instrumentation for potentially sensitive data is disabled, such as for SQL statements.
A second manual instrumentation method allows enabling ODP.NET OpenTelemetry without adding the ODP.NET OpenTelemetry NuGet package and without calling the AddOracleDataProviderInstrumentation()
extension method. It requires adding the TracerProviderBuilder
call AddSource(“Oracle.ManagedDataAccess.Core”)
for ODP.NET Core or AddSource(“Oracle.ManagedDataAccess”)
for managed ODP.NET.
ODP.NET OpenTelemetry instrumentation will then be enabled using default options. The defaults must be used as there is no way to modify option values. Changing these values require using ODP.NET OpenTelemetry NuGet package directly.
OpenTelemetry.Api
NuGet package is installed automatically if the application adds any OpenTelemetry exporter NuGet packages, such as OpenTelemetry.Exporter.Console
or OpenTelemetry.Exporter.Zipkin
. OpenTelemetry.Api
is necessary to call the AddSource()
method.
Code sample: Enabling ODP.NET OpenTelemetry manual instrumentation via AddSource
Sdk.CreateTracerProviderBuilder()
.AddSource("Oracle.ManagedDataAccess.Core")
.AddConsoleExporter()
.Build();
Through this instrumentation method, it is possible to enable and disable ODP.NET OpenTelemetry tracing programmatically at runtime dynamically. To enable, set OracleConfiguration
OpenTelemetryTracing
to true
(default). To disable, set it to false
.
OpenTelemetryTracing
is available as a managed ODP.NET .NET configuration file setting as well. As a .NET config setting, it is read upon app startup only. Changes to this setting's value after startup are ignored.
Automatic Instrumentation
OpenTelemetry automatic instrumentation enables ODP.NET tracing without requiring code changes. Existing .NET apps can turn on tracing without having to recompile.
To use it, add the OpenTelemetry.AutoInstrumentation 1.7.0
NuGet package or higher to your project. Older package versions require setting environment variables to enable ODP.NET tracing. For example, the following environment variable settings turn on ODP.NET Core tracing using the console exporter.
OTEL_DOTNET_AUTO_TRACES_ADDITIONAL_SOURCES=Oracle.ManagedDataAccess.Core
OTEL_DOTNET_AUTO_TRACES_CONSOLE_EXPORTER_ENABLED=true
ODP.NET automatic instrumentation is on by default when using a newer OpenTelemetry.AutoInstrumentation
NuGet package.
Instrumented ODP.NET APIs
The list of managed ODP.NET and ODP.NET Core APIs that are instrumented to support OpenTelemetry is as follows. Every ODP.NET database round trip originating from one of these APIs is instrumented as well.
-
OracleCommand
-
ExecuteNonQuery()
-
ExecuteNonQueryAsync(CancellationToken cancellationToken)
-
ExecuteNonQueryAsync()
-
All
ExecuteReader
overloads -
All
ExecuteReaderAsync
overloads -
ExecuteScalar()
-
ExecuteScalarAsync(CancellationToken cancellationToken)
-
ExecuteStream()
-
ExecuteToStream(Stream)
-
ExecuteXmlReader()
-
All
ExecuteXmlReaderAsync
overloads
-
-
OracleConnection
-
Close()
-
Open()
-
OpenAsync()
-
-
OracleDataAdapter
-
All
Fill
overloads
-
-
OracleDataReader
-
Read()
-
ReadAsync()
-
See Also:
Oracle Data Provider for .NET OpenTelemetry and Metrics Classes
OpenTelemetry documentation