Skip to content

[CSHARP-969] - OpenTelemetry tracing #608

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 41 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
a6b2cdc
feat: add opentelemetry session level tracing
simaoribeiro Nov 29, 2023
b9927ea
fix: build errors
simaoribeiro May 21, 2024
35635f2
fix: renamed Trace class to OpenTelemetryRequestTracker
simaoribeiro Jul 15, 2024
c27fdf7
fix: rename cassandra instrumentation to Cassandra source helper
simaoribeiro Jul 15, 2024
1f8a745
documentation
simaoribeiro Jul 15, 2024
ddf0c31
include observers in folder
simaoribeiro Jul 15, 2024
febd548
change to tasks
simaoribeiro Aug 5, 2024
2565a4b
include node implementation on opentelemetry request tracker
simaoribeiro Aug 5, 2024
879c0c4
include more mappings for request tracking info
simaoribeiro Aug 7, 2024
4533a0d
fixes
simaoribeiro Aug 8, 2024
8447ed7
code reviews
simaoribeiro Aug 8, 2024
b236d8f
await tasks
simaoribeiro Aug 9, 2024
204d56b
virtual on OnNodeStart
simaoribeiro Aug 9, 2024
5555e41
fix: code review
simaoribeiro Aug 22, 2024
5ae14fd
fix: pipeline
simaoribeiro Aug 22, 2024
13f3eec
include more integration tests
simaoribeiro Aug 29, 2024
f2cf467
fix linq tests
simaoribeiro Sep 2, 2024
5cbe61b
fix pipeline
simaoribeiro Sep 3, 2024
a43fda0
fix
simaoribeiro Sep 3, 2024
1e7c1a9
Merge branch 'master' into feat/add-opentelemetry
joao-r-reis Sep 10, 2024
b28863e
await request observer tasks
joao-r-reis Sep 11, 2024
19e686e
fix configureawait
joao-r-reis Sep 11, 2024
fbdae23
add compositeconnectionobserver
joao-r-reis Sep 11, 2024
03af90f
fix flaky test
joao-r-reis Sep 11, 2024
bfaa56a
replace Task.FromResult with TaskHelper.Completed
joao-r-reis Sep 11, 2024
5ae1f6c
add missing await
joao-r-reis Sep 11, 2024
48f11c1
fix last commit
joao-r-reis Sep 11, 2024
9425f43
make composite observers fixed length
joao-r-reis Sep 12, 2024
6cbf77e
add test cases to an opentelemetry test
joao-r-reis Sep 12, 2024
5445d6a
Merge pull request #3 from joao-r-reis/opentelemetry-async
simaoribeiro Sep 12, 2024
3de1216
fix otel tests
joao-r-reis Sep 13, 2024
c03e992
Merge pull request #4 from joao-r-reis/fix-otel-tests
simaoribeiro Sep 13, 2024
28c9e5a
fix flaky tests
joao-r-reis Sep 13, 2024
81b081f
Merge pull request #5 from joao-r-reis/fix-otel-tests
simaoribeiro Sep 13, 2024
d9c697b
docs: include documentation
simaoribeiro Sep 13, 2024
f5585cd
fix: include null validation in request.Statement
simaoribeiro Sep 13, 2024
d62398a
fix: update to semantic conventions 1.27.0
simaoribeiro Sep 17, 2024
59804ae
tests: include null validation unit tests for OpenTelemetry
simaoribeiro Sep 17, 2024
f4ea044
fix: unit test and node start async naming
simaoribeiro Sep 17, 2024
0a48fcd
docs: request tracker
simaoribeiro Sep 17, 2024
fd0d7ed
include header in OTEL unit test class
simaoribeiro Sep 17, 2024
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
2 changes: 2 additions & 0 deletions doc/features/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ The DataStax C# Driver for Apache Cassandra and DataStax Enterprise is a feature
- [App.Metrics Provider](metrics/app-metrics)
- [List of metrics](metrics/metrics-list)
- [Native protocol](native-protocol)
- [OpenTelemetry](opentelemetry)
- [Parametrized queries](parametrized-queries)
- [Query timestamps](query-timestamps)
- [Query warnings](query-warnings)
- [Request tracker](request-tracker)
- [Result paging](paging)
- [Routing queries](routing-queries)
- [Speculative executions](speculative-retries)
Expand Down
78 changes: 78 additions & 0 deletions doc/features/opentelemetry/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# OpenTelemetry

The driver provides support for session and node level [traces](https://opentelemetry.io/docs/concepts/signals/traces/) using [OpenTelemetry instrumentation](https://opentelemetry.io/docs/instrumentation/net/).

## Including OpenTelemetry instrumentation in your code

Add the package `Cassandra.OpenTelemetry` to the project and add the extension method `AddOpenTelemetryInstrumentation()` when building your cluster:

```csharp
var cluster = Cluster.Builder()
.AddContactPoint(Program.ContactPoint)
.WithSessionName(Program.SessionName)
.AddOpenTelemetryInstrumentation()
.Build();
```

Once you have your .NET application instrumentation configured, Cassandra activities can be captured by adding the source `CassandraActivitySourceHelper.ActivitySourceName` in the tracer provider builder:

```csharp
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddSource(CassandraActivitySourceHelper.ActivitySourceName)
...
```

### Attributes

The table below displays the list of included attributes in this feature:

| Attribute | Description | Output Values|
|---|---|---|
| db.name | The keyspace name. | *keyspace in use* |
| db.operation | The type name of the operation being executed. | *Session Request* for session level calls and *Node Request* for node level calls |
| db.statement | The database statement being executed. Included as [optional configuration](#include-statement-as-an-attribute). | *database statement in use* |
| db.system | An identifier for the database management system (DBMS) product being used. | cassandra |
| server.address | The host node. | e.g.: 127.0.0.1 |
| server.port | Port number. | e.g.: 9042 |

The console log below displays an example of a full Cassandra activity:

```console
Activity.TraceId: 710e1a99afec9bcd056c9fe825bcbb3c
Activity.SpanId: bd42cfc78b552cd1
Activity.TraceFlags: Recorded
Activity.ActivitySourceName: Cassandra.OpenTelemetry
Activity.ActivitySourceVersion: 1.0.0.0
Activity.DisplayName: Session Request
Activity.Kind: Client
Activity.StartTime: 2024-09-13T14:08:36.9762191Z
Activity.Duration: 00:00:00.0416284
Activity.Tags:
db.system: cassandra
db.operation: Session Request
db.name: system
db.statement: SELECT * FROM system.local
Resource associated with Activity:
service.name: CassandraDemo
service.version: 1.0.0
service.instance.id: 5a5d88b9-cc86-4f8a-a206-9b4f507630b9
telemetry.sdk.name: opentelemetry
telemetry.sdk.language: dotnet
telemetry.sdk.version: 1.8.0
```

## Advanced Configuration

The instrumentation can be configured to extend the default behavior by using `CassandraInstrumentationOptions`.

### Include Statement as an attribute

As mentioned above, the attribute `db.statement` is not included by default in the activity. To change it, set the `CassandraInstrumentationOptions` property `IncludeDatabaseStatement` as *true* when building the cluster:

```csharp
var cluster = Cluster.Builder()
.AddContactPoint(Program.ContactPoint)
.WithSessionName(Program.SessionName)
.AddOpenTelemetryInstrumentation(options => options.IncludeDatabaseStatement = true)
.Build();
```
15 changes: 15 additions & 0 deletions doc/features/request-tracker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Request Tracker

The driver provides the `IRequestTracker` interface that tracks the requests at Session and Node levels. It contains *start*, *finish*, and *error* events that can be subscribed by implementing the interface, and should be used by passing the implementation as an argument of the method `WithRequestTracker` that is available in the `Builder`.\
An example of an `IRequestTracker` implementation is the extension package `Cassandra.OpenTelemetry` that can be checked in the [documentation](/doc/features/opentelemetry/README.md).

## Available events

The full API doc is available [here](https://docs.datastax.com/en/drivers/csharp/latest/api/Cassandra.IRequestTracker.html) but the list below summarizes the events are available in the tracker:

- **OnStartAsync** - that is triggered when a session level request starts.
- **OnSuccessAsync** - that is triggered when the session level request finishes successfully.
- **OnErrorAsync** - that is triggered when the session level request finishes unsuccessfully.
- **OnNodeStartAsync** - that is triggered when the node request starts
- **OnNodeSuccessAsync** - that is triggered when the node level request finishes successfully.
- **OnNodeErrorAsync** - that is triggered when the node request finishes unsuccessfully.
18 changes: 18 additions & 0 deletions examples/OpenTelemetry/ConsoleExporter/ConsoleExporter.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.8.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\Extensions\Cassandra.OpenTelemetry\Cassandra.OpenTelemetry.csproj" />
</ItemGroup>

</Project>
82 changes: 82 additions & 0 deletions examples/OpenTelemetry/ConsoleExporter/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//
// Copyright (C) DataStax Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

using Cassandra;
using Cassandra.OpenTelemetry;
using OpenTelemetry;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;

namespace ConsoleExporter
{
internal class Program
{
private const string ContactPoint = "localhost";
private const string SessionName = "otel-example";

private static void Main(string[] args)
{
Program.MainAsync(args).GetAwaiter().GetResult();
}

private static async Task MainAsync(string[] args)
{
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(
serviceName: "CassandraDemo",
serviceVersion: "1.0.0"))
.AddSource(CassandraActivitySourceHelper.ActivitySourceName)
.AddConsoleExporter()
.Build();

var cluster = Cluster.Builder()
.AddContactPoint(Program.ContactPoint)
.WithSessionName(Program.SessionName)
.AddOpenTelemetryInstrumentation(options => options.IncludeDatabaseStatement = true)
.Build();

var session = await cluster.ConnectAsync().ConfigureAwait(false);

//// Execute a query every 5 seconds

var cts = new CancellationTokenSource();
var task = Task.Run(async () =>
{
while (!cts.IsCancellationRequested)
{
try
{
var x = await session.ExecuteAsync(new SimpleStatement("SELECT * FROM system.local"));
}
catch (Exception ex)
{
Console.WriteLine($"ERROR: {ex}");
}

Thread.Sleep(5000);
}
});

Console.WriteLine("Press enter to shutdown the session and exit.");
Console.ReadLine();

cts.Cancel();

await task.ConfigureAwait(false);
await cluster.ShutdownAsync().ConfigureAwait(false);
}
}
}
17 changes: 17 additions & 0 deletions examples/examples.sln
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ColumnEncryption", "ColumnE
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ColumnEncryptionExample", "ColumnEncryption\ColumnEncryptionExample\ColumnEncryptionExample.csproj", "{AE159E33-D289-472C-8174-4FA9C55C29DF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cassandra.OpenTelemetry", "..\src\Extensions\Cassandra.OpenTelemetry\Cassandra.OpenTelemetry.csproj", "{10076771-C9F5-4FF4-82E7-33EC4AF555FD}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OpenTelemetry", "OpenTelemetry", "{DD2D2F9B-513D-4518-8289-E12CB2BC5B12}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleExporter", "OpenTelemetry\ConsoleExporter\ConsoleExporter.csproj", "{616E808D-9BF5-4AB5-866B-6D4F35D1102E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -79,6 +85,14 @@ Global
{AE159E33-D289-472C-8174-4FA9C55C29DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AE159E33-D289-472C-8174-4FA9C55C29DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AE159E33-D289-472C-8174-4FA9C55C29DF}.Release|Any CPU.Build.0 = Release|Any CPU
{10076771-C9F5-4FF4-82E7-33EC4AF555FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{10076771-C9F5-4FF4-82E7-33EC4AF555FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{10076771-C9F5-4FF4-82E7-33EC4AF555FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{10076771-C9F5-4FF4-82E7-33EC4AF555FD}.Release|Any CPU.Build.0 = Release|Any CPU
{616E808D-9BF5-4AB5-866B-6D4F35D1102E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{616E808D-9BF5-4AB5-866B-6D4F35D1102E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{616E808D-9BF5-4AB5-866B-6D4F35D1102E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{616E808D-9BF5-4AB5-866B-6D4F35D1102E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -99,6 +113,9 @@ Global
{1A866971-206C-4A6F-B6B1-8B0408B67618} = {A68222F1-E44C-4B20-8CEC-A10A89FC4982}
{1320BA10-E76B-4247-B1F1-71221349A94E} = {A589A223-6F57-40C7-BE7D-00E87354A69E}
{AE159E33-D289-472C-8174-4FA9C55C29DF} = {1320BA10-E76B-4247-B1F1-71221349A94E}
{10076771-C9F5-4FF4-82E7-33EC4AF555FD} = {EE6E727D-835E-42D1-8E62-081E0B6FAAC2}
{DD2D2F9B-513D-4518-8289-E12CB2BC5B12} = {A589A223-6F57-40C7-BE7D-00E87354A69E}
{616E808D-9BF5-4AB5-866B-6D4F35D1102E} = {DD2D2F9B-513D-4518-8289-E12CB2BC5B12}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A731352A-6C46-4D13-A44F-07731EE671DA}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@

<ItemGroup>
<PackageReference Include="App.Metrics" Version="3.2.0" />
<PackageReference Include="OpenTelemetry.Exporter.InMemory" Version="1.5.1" />
<PackageReference Include="SSH.NET" Version="2020.0.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
Expand Down Expand Up @@ -119,6 +120,9 @@
<PackageReference Include="JetBrains.DotMemoryUnit" Version="3.2.20220510" />
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Extensions\Cassandra.OpenTelemetry\Cassandra.OpenTelemetry.csproj" />
</ItemGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/Cassandra.IntegrationTests/Core/ConnectionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
using Cassandra.IntegrationTests.SimulacronAPI.Models.Logs;
using Cassandra.IntegrationTests.TestBase;
using Cassandra.IntegrationTests.TestClusterManagement.Simulacron;
using Cassandra.Observers;
using Cassandra.Observers.Null;
using Cassandra.Tasks;
using Cassandra.Tests;
using Cassandra.Requests;
Expand Down
Loading