Skip to content

Commit a813c4a

Browse files
committed
Add OpenTelemetry integration with metrics, tracing, and logging support
1 parent dc94beb commit a813c4a

File tree

7 files changed

+208
-109
lines changed

7 files changed

+208
-109
lines changed

README.md

Lines changed: 79 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,103 @@
1-
# OpenTelemetry
1+
# VirtoCommerce OpenTelemetry Module
22

3-
## Overview
3+
This module provides OpenTelemetry observability for VirtoCommerce Platform — metrics, distributed tracing, and structured logging via OTLP exporter.
44

5-
Short overview of what the new module is.
5+
## Features
66

7-
- What is the new or updated experience?
7+
- **Metrics**: ASP.NET Core, HTTP Client, Runtime, Process, EF Core, Elasticsearch, Redis instrumentation
8+
- **Distributed Tracing**: ASP.NET Core, HTTP Client, Hangfire, EF Core, Elasticsearch, Redis instrumentation
9+
- **Logging**: Serilog → OpenTelemetry via OTLP sink, with trace/span ID correlation
10+
- **Conditional Activation**: Only enabled when explicitly configured
811

9-
- Does this module replace an existing module/experience? If yes, what is the transition plan?
12+
## Prerequisites
1013

11-
- Does this module has dependency on other ? If yes, list/explain the dependencies.
14+
- VirtoCommerce Platform 3.1002.0+
15+
- OTLP-compatible collector (e.g. [Grafana Alloy](https://grafana.com/docs/alloy/), [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/), [Aspire Dashboard](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/dashboard/overview))
1216

13-
- List the key deployment scenarios - why would people use this module?
17+
## Installation
1418

15-
## Functional Requirements
19+
Copy the module to your platform `modules` directory. It will be automatically discovered and loaded by VirtoCommerce Platform.
1620

17-
Short description of the new module functional requirements.
21+
## Configuration
1822

19-
## Scenarios
23+
Add to `appsettings.json`:
2024

21-
List of scenarios that the new module implements
25+
```json
26+
{
27+
"OpenTelemetry": {
28+
"Enabled": true,
29+
"Endpoint": "http://localhost:4317",
30+
"ServiceName": "VirtoCommerce.Platform"
31+
}
32+
}
33+
```
2234

23-
1. [Scenario 1](/doc/scenario-name1.md)
24-
1. [Scenario 2](/doc/scenario-name2.md)
25-
1. [Scenario 3](/doc/scenario-name3.md)
26-
1. [Scenario 3.1](/doc/scenario-name31.md)
27-
1. [Scenario 3.2](/doc/scenario-name32.md)
28-
1. [Scenario 4](/doc/scenario-name4.md)
35+
| Key | Required | Default | Description |
36+
|-----|----------|---------|-------------|
37+
| `Enabled` | Yes | `false` | Enables the module. Set to `true` to activate. |
38+
| `Endpoint` | Yes || OTLP collector endpoint (gRPC). Required to export data. |
39+
| `ServiceName` | No | `VirtoCommerce.Platform` | Service name reported in telemetry. |
2940

30-
## Web API
41+
Settings can also be provided via environment variables:
3142

32-
Web API documentation for each module is built out automatically and can be accessed by following the link bellow:
33-
<https://link-to-swager-api>
43+
```
44+
OpenTelemetry__Enabled=true
45+
OpenTelemetry__Endpoint=http://collector:4317
46+
OpenTelemetry__ServiceName=my-store
47+
```
3448

35-
## Database Model
49+
## What Gets Collected
3650

37-
![DB model](./docs/media/diagram-db-model.png)
51+
### Metrics
3852

39-
## Related topics
53+
| Source | Description |
54+
|--------|-------------|
55+
| ASP.NET Core | Request rate, duration, active connections |
56+
| HTTP Client | Outbound request duration and status |
57+
| .NET Runtime | GC, thread pool, memory |
58+
| Process | CPU, memory |
59+
| EF Core | Query counts and duration |
60+
| Elasticsearch | Transport-level metrics |
61+
| Kestrel | Connection and request metrics |
4062

41-
[Some Article1](some-article1.md)
63+
### Traces
4264

43-
[Some Article2](some-article2.md)
65+
| Source | Description |
66+
|--------|-------------|
67+
| ASP.NET Core | Incoming HTTP requests |
68+
| HTTP Client | Outbound HTTP calls |
69+
| EF Core | Database queries |
70+
| Hangfire | Background job execution |
71+
| Elasticsearch | Search and index operations |
72+
| Redis | Cache operations |
73+
74+
### Logs
75+
76+
Structured logs are forwarded to the OTLP endpoint via Serilog with trace/span ID fields for correlation with distributed traces.
77+
78+
## Module Structure
79+
80+
```
81+
src/
82+
└── VirtoCommerce.OpenTelemetry.Web/
83+
├── Module.cs # Module entry point
84+
├── ServiceCollectionExtensions.cs # OTel metrics and tracing registration
85+
├── OpenTelemetryLoggerConfigurationService.cs # Serilog → OTLP logging
86+
└── VirtoCommerce.OpenTelemetry.Web.csproj
87+
```
88+
89+
## Troubleshooting
90+
91+
**Module not activating** — verify `OpenTelemetry:Enabled` is `true` in configuration.
92+
93+
**No data exported** — verify `OpenTelemetry:Endpoint` is set and the collector is reachable.
94+
95+
**Traces missing correlations** — ensure the collector supports OTLP gRPC on the configured endpoint.
4496

4597
## License
4698

47-
Copyright (c) Virto Solutions LTD. All rights reserved.
99+
Copyright (c) Virto Solutions LTD. All rights reserved.
48100

49-
Licensed under the Virto Commerce Open Software License (the "License"); you
50-
may not use this file except in compliance with the License. You may
51-
obtain a copy of the License at
101+
Licensed under the Virto Commerce Open Software License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
52102

53103
<https://virtocommerce.com/open-source-license>
54-
55-
Unless required by applicable law or agreed to in writing, software
56-
distributed under the License is distributed on an "AS IS" BASIS,
57-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
58-
implied.

src/VirtoCommerce.OpenTelemetry.Web/Module.cs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,33 @@
11
using Microsoft.AspNetCore.Builder;
2+
using Microsoft.Extensions.Configuration;
23
using Microsoft.Extensions.DependencyInjection;
4+
using VirtoCommerce.Platform.Core.Logger;
35
using VirtoCommerce.Platform.Core.Modularity;
4-
using VirtoCommerce.Platform.Core.Security;
5-
using VirtoCommerce.Platform.Core.Settings;
66

77
namespace VirtoCommerce.OpenTelemetry.Web;
88

9-
public class Module : IModule
9+
public class Module : IModule, IHasConfiguration
1010
{
1111
public ManifestModuleInfo ModuleInfo { get; set; }
12+
public IConfiguration Configuration { get; set; }
1213

1314
public void Initialize(IServiceCollection serviceCollection)
1415
{
15-
// Register services
16-
//serviceCollection.AddTransient<IMyService, MyService>();
16+
if (!Configuration.GetValue("OpenTelemetry:Enabled", false))
17+
{
18+
return;
19+
}
20+
21+
// Integrate Serilog → OpenTelemetry logging via platform's Serilog pipeline
22+
serviceCollection.AddTransient<ILoggerConfigurationService, OpenTelemetryLoggerConfigurationService>();
23+
24+
// Register OpenTelemetry metrics, tracing, and OTLP exporter
25+
serviceCollection.AddOpenTelemetryModule(Configuration);
1726
}
1827

1928
public void PostInitialize(IApplicationBuilder appBuilder)
2029
{
21-
var serviceProvider = appBuilder.ApplicationServices;
22-
23-
// Register settings
24-
var settingsRegistrar = serviceProvider.GetRequiredService<ISettingsRegistrar>();
25-
settingsRegistrar.RegisterSettings(ModuleConstants.Settings.AllSettings, ModuleInfo.Id);
26-
27-
// Register permissions
28-
var permissionsRegistrar = serviceProvider.GetRequiredService<IPermissionsRegistrar>();
29-
permissionsRegistrar.RegisterPermissions(ModuleInfo.Id, "OpenTelemetry", ModuleConstants.Security.Permissions.AllPermissions);
30+
// Nothing to do here
3031
}
3132

3233
public void Uninstall()

src/VirtoCommerce.OpenTelemetry.Web/ModuleConstants.cs

Lines changed: 0 additions & 58 deletions
This file was deleted.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using System.Collections.Generic;
2+
using Microsoft.Extensions.Configuration;
3+
using Serilog;
4+
using Serilog.Sinks.OpenTelemetry;
5+
using VirtoCommerce.Platform.Core.Logger;
6+
7+
namespace VirtoCommerce.OpenTelemetry.Web;
8+
9+
/// <summary>
10+
/// Configures Serilog to send logs to OpenTelemetry via OTLP.
11+
/// Integrates with the platform's Serilog configuration pipeline.
12+
/// </summary>
13+
public class OpenTelemetryLoggerConfigurationService : ILoggerConfigurationService
14+
{
15+
private readonly IConfiguration _configuration;
16+
17+
public OpenTelemetryLoggerConfigurationService(IConfiguration configuration)
18+
{
19+
_configuration = configuration;
20+
}
21+
22+
public void Configure(LoggerConfiguration loggerConfiguration)
23+
{
24+
var otlpEndpoint = _configuration["OpenTelemetry:Endpoint"];
25+
if (string.IsNullOrWhiteSpace(otlpEndpoint))
26+
{
27+
return;
28+
}
29+
30+
loggerConfiguration.WriteTo.OpenTelemetry(options =>
31+
{
32+
options.Endpoint = otlpEndpoint;
33+
options.Protocol = OtlpProtocol.Grpc;
34+
35+
// Include trace context for correlation with distributed traces
36+
options.IncludedData = IncludedData.TraceIdField | IncludedData.SpanIdField |
37+
IncludedData.MessageTemplateTextAttribute |
38+
IncludedData.MessageTemplateMD5HashAttribute;
39+
40+
var serviceName = _configuration["OpenTelemetry:ServiceName"] ?? "VirtoCommerce.Platform";
41+
options.ResourceAttributes = new Dictionary<string, object>
42+
{
43+
["service.name"] = serviceName,
44+
};
45+
});
46+
}
47+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using Microsoft.Extensions.Configuration;
2+
using Microsoft.Extensions.DependencyInjection;
3+
using OpenTelemetry;
4+
using OpenTelemetry.Metrics;
5+
using OpenTelemetry.Trace;
6+
7+
namespace VirtoCommerce.OpenTelemetry.Web;
8+
9+
public static class ServiceCollectionExtensions
10+
{
11+
public static IServiceCollection AddOpenTelemetryModule(this IServiceCollection services, IConfiguration configuration)
12+
{
13+
// Note: OpenTelemetry logging is integrated via Serilog sink (see OpenTelemetryLoggerConfigurationService)
14+
// This avoids duplicate logging providers and follows VirtoCommerce Platform patterns
15+
16+
var otelBuilder = services.AddOpenTelemetry()
17+
.WithMetrics(metrics =>
18+
{
19+
metrics.AddAspNetCoreInstrumentation()
20+
.AddHttpClientInstrumentation()
21+
.AddRuntimeInstrumentation()
22+
.AddProcessInstrumentation()
23+
.AddEventCountersInstrumentation(options =>
24+
{
25+
options.AddEventSources("Microsoft.AspNetCore.Hosting", "Microsoft-AspNetCore-Server-Kestrel");
26+
})
27+
.AddMeter("Microsoft.EntityFrameworkCore", "Elastic.Transport");
28+
})
29+
.WithTracing(tracing =>
30+
{
31+
tracing.AddAspNetCoreInstrumentation()
32+
.AddHttpClientInstrumentation()
33+
.AddHangfireInstrumentation()
34+
.AddEntityFrameworkCoreInstrumentation()
35+
.AddElasticsearchClientInstrumentation(options =>
36+
{
37+
options.SuppressDownstreamInstrumentation = true;
38+
options.ParseAndFormatRequest = true;
39+
})
40+
.AddSource("Elastic.Transport")
41+
.AddRedisInstrumentation();
42+
});
43+
44+
// Add OTLP exporter if endpoint is configured
45+
if (!string.IsNullOrWhiteSpace(configuration["OpenTelemetry:Endpoint"]))
46+
{
47+
otelBuilder.UseOtlpExporter();
48+
}
49+
50+
return services;
51+
}
52+
}

src/VirtoCommerce.OpenTelemetry.Web/VirtoCommerce.OpenTelemetry.Web.csproj

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,25 @@
44
<OutputType>Library</OutputType>
55
<IsPackable>false</IsPackable>
66
<GenerateDocumentationFile>true</GenerateDocumentationFile>
7-
<NoWarn>1591</NoWarn>
7+
<NoWarn>1591;NU1608</NoWarn>
88
</PropertyGroup>
99
<PropertyGroup>
1010
<!-- Project is not a test project -->
1111
<SonarQubeTestProject>false</SonarQubeTestProject>
1212
</PropertyGroup>
1313
<ItemGroup>
14+
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.0" />
15+
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.15.0" />
16+
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.15.0" />
17+
<PackageReference Include="OpenTelemetry.Instrumentation.ElasticsearchClient" Version="1.14.0-beta.1" />
18+
<PackageReference Include="OpenTelemetry.Instrumentation.EntityFrameworkCore" Version="1.15.0-beta.1" />
19+
<PackageReference Include="OpenTelemetry.Instrumentation.EventCounters" Version="1.15.0-alpha.1" />
20+
<PackageReference Include="OpenTelemetry.Instrumentation.Hangfire" Version="1.14.0-beta.1" />
21+
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.15.0" />
22+
<PackageReference Include="OpenTelemetry.Instrumentation.Process" Version="1.15.0-beta.1" />
23+
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.15.0" />
24+
<PackageReference Include="OpenTelemetry.Instrumentation.StackExchangeRedis" Version="1.15.0-beta.1" />
25+
<PackageReference Include="Serilog.Sinks.OpenTelemetry" Version="4.2.0" />
1426
<PackageReference Include="VirtoCommerce.Platform.Core" Version="3.1002.0" />
1527
</ItemGroup>
1628
</Project>

src/VirtoCommerce.OpenTelemetry.Web/module.manifest

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
<version>3.800.0</version>
55
<version-tag></version-tag>
66

7-
<platformVersion>3.876.0</platformVersion>
7+
<platformVersion>3.1002.0</platformVersion>
88
<dependencies>
99
<!--<dependency id="VirtoCommerce.Core" version="3.800.0" />-->
1010
</dependencies>
1111

1212
<title>VirtoCommerce OpenTelemetry</title>
13-
<description>VirtoCommerce OpenTelemetry</description>
13+
<description>Provides OpenTelemetry metrics, tracing, and logging via OTLP exporter</description>
1414

1515
<authors>
1616
<author>Anton Zorya</author>

0 commit comments

Comments
 (0)