Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Project>
<!-- These properties will be shared for all projects -->
<PropertyGroup>
<VersionPrefix>3.800.0</VersionPrefix>
<VersionPrefix>3.1000.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
<VersionSuffix Condition=" '$(VersionSuffix)' != '' AND '$(BuildNumber)' != '' ">$(VersionSuffix)-$(BuildNumber)</VersionSuffix>
</PropertyGroup>
Expand Down
108 changes: 78 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,46 +1,98 @@
# OpenTelemetry
# Open Telemetry Module

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

Short overview of what the new module is.
## Features

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

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

- Does this module has dependency on other ? If yes, list/explain the dependencies.
- VirtoCommerce Platform 3.1002.0+
- 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))

- List the key deployment scenarios - why would people use this module?
## Installation

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

Short description of the new module functional requirements.
## Configuration

## Scenarios
Add to `appsettings.json`:

List of scenarios that the new module implements
```json
{
"OpenTelemetry": {
"Enabled": true,
"Endpoint": "http://localhost:4317",
"ServiceName": "VirtoCommerce.Platform"
}
}
```

1. [Scenario 1](/doc/scenario-name1.md)
1. [Scenario 2](/doc/scenario-name2.md)
1. [Scenario 3](/doc/scenario-name3.md)
1. [Scenario 3.1](/doc/scenario-name31.md)
1. [Scenario 3.2](/doc/scenario-name32.md)
1. [Scenario 4](/doc/scenario-name4.md)
| Key | Required | Default | Description |
|-----|----------|---------|-------------|
| `Enabled` | Yes | `false` | Enables the module. Set to `true` to activate. |
| `Endpoint` | Yes | — | OTLP collector endpoint (gRPC). Required to export data. |
| `ServiceName` | No | `VirtoCommerce.Platform` | Service name reported in telemetry. |

## Web API
Settings can also be provided via environment variables:

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

## Database Model
## What Gets Collected

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

## Related topics
| Source | Description |
|--------|-------------|
| ASP.NET Core | Request rate, duration, active connections |
| HTTP Client | Outbound request duration and status |
| .NET Runtime | GC, thread pool, memory |
| Process | CPU, memory |
| EF Core | Query counts and duration |
| Elasticsearch | Transport-level metrics |
| Kestrel | Connection and request metrics |

[Some Article1](some-article1.md)
### Traces

[Some Article2](some-article2.md)
| Source | Description |
|--------|-------------|
| ASP.NET Core | Incoming HTTP requests |
| HTTP Client | Outbound HTTP calls |
| EF Core | Database queries |
| Hangfire | Background job execution |
| Elasticsearch | Search and index operations |
| Redis | Cache operations |

### Logs

Structured logs are forwarded to the OTLP endpoint via Serilog with trace/span ID fields for correlation with distributed traces.

## Module Structure

```
src/
└── VirtoCommerce.OpenTelemetry.Web/
├── Module.cs # Module entry point
├── ServiceCollectionExtensions.cs # OTel metrics and tracing registration
├── OpenTelemetryLoggerConfigurationService.cs # Serilog → OTLP logging
└── VirtoCommerce.OpenTelemetry.Web.csproj
```

## Troubleshooting

**Module not activating** — verify `OpenTelemetry:Enabled` is `true` in configuration.

**No data exported** — verify `OpenTelemetry:Endpoint` is set and the collector is reachable.

**Traces missing correlations** — ensure the collector supports OTLP gRPC on the configured endpoint.

## License

Expand All @@ -50,9 +102,5 @@ 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

<https://virtocommerce.com/open-source-license>
http://virtocommerce.com/opensourcelicense

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.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 15 additions & 14 deletions src/VirtoCommerce.OpenTelemetry.Web/Module.cs
Original file line number Diff line number Diff line change
@@ -1,32 +1,33 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using VirtoCommerce.Platform.Core.Logger;
using VirtoCommerce.Platform.Core.Modularity;
using VirtoCommerce.Platform.Core.Security;
using VirtoCommerce.Platform.Core.Settings;

namespace VirtoCommerce.OpenTelemetry.Web;

public class Module : IModule
public class Module : IModule, IHasConfiguration
{
public ManifestModuleInfo ModuleInfo { get; set; }
public IConfiguration Configuration { get; set; }

public void Initialize(IServiceCollection serviceCollection)
{
// Register services
//serviceCollection.AddTransient<IMyService, MyService>();
if (!Configuration.GetValue("OpenTelemetry:Enabled", false))
{
return;
}

// Integrate Serilog → OpenTelemetry logging via platform's Serilog pipeline
serviceCollection.AddTransient<ILoggerConfigurationService, OpenTelemetryLoggerConfigurationService>();

// Register OpenTelemetry metrics, tracing, and OTLP exporter
serviceCollection.AddOpenTelemetryModule(Configuration);
}

public void PostInitialize(IApplicationBuilder appBuilder)
{
var serviceProvider = appBuilder.ApplicationServices;

// Register settings
var settingsRegistrar = serviceProvider.GetRequiredService<ISettingsRegistrar>();
settingsRegistrar.RegisterSettings(ModuleConstants.Settings.AllSettings, ModuleInfo.Id);

// Register permissions
var permissionsRegistrar = serviceProvider.GetRequiredService<IPermissionsRegistrar>();
permissionsRegistrar.RegisterPermissions(ModuleInfo.Id, "OpenTelemetry", ModuleConstants.Security.Permissions.AllPermissions);
// Nothing to do here
}

public void Uninstall()
Expand Down
58 changes: 0 additions & 58 deletions src/VirtoCommerce.OpenTelemetry.Web/ModuleConstants.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System.Collections.Generic;
using Microsoft.Extensions.Configuration;
using Serilog;
using Serilog.Sinks.OpenTelemetry;
using VirtoCommerce.Platform.Core.Logger;

namespace VirtoCommerce.OpenTelemetry.Web;

/// <summary>
/// Configures Serilog to send logs to OpenTelemetry via OTLP.
/// Integrates with the platform's Serilog configuration pipeline.
/// </summary>
public class OpenTelemetryLoggerConfigurationService : ILoggerConfigurationService
{
private readonly IConfiguration _configuration;

public OpenTelemetryLoggerConfigurationService(IConfiguration configuration)
{
_configuration = configuration;
}

public void Configure(LoggerConfiguration loggerConfiguration)
{
var otlpEndpoint = _configuration["OpenTelemetry:Endpoint"];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var endpoint = ...

if (string.IsNullOrWhiteSpace(otlpEndpoint))
{
return;
}

loggerConfiguration.WriteTo.OpenTelemetry(options =>
{
options.Endpoint = otlpEndpoint;
options.Protocol = OtlpProtocol.Grpc;

// Include trace context for correlation with distributed traces
options.IncludedData = IncludedData.TraceIdField | IncludedData.SpanIdField |
IncludedData.MessageTemplateTextAttribute |
IncludedData.MessageTemplateMD5HashAttribute;

var serviceName = _configuration["OpenTelemetry:ServiceName"] ?? "VirtoCommerce.Platform";
options.ResourceAttributes = new Dictionary<string, object>
{
["service.name"] = serviceName,
};
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;

namespace VirtoCommerce.OpenTelemetry.Web;

public static class ServiceCollectionExtensions
{
public static IServiceCollection AddOpenTelemetryModule(this IServiceCollection services, IConfiguration configuration)
{
// Note: OpenTelemetry logging is integrated via Serilog sink (see OpenTelemetryLoggerConfigurationService)
// This avoids duplicate logging providers and follows VirtoCommerce Platform patterns

var otelBuilder = services.AddOpenTelemetry()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var builder = ...

.WithMetrics(metrics =>
{
metrics.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddRuntimeInstrumentation()
.AddProcessInstrumentation()
.AddEventCountersInstrumentation(options =>
{
options.AddEventSources("Microsoft.AspNetCore.Hosting", "Microsoft-AspNetCore-Server-Kestrel");
})
.AddMeter("Microsoft.EntityFrameworkCore", "Elastic.Transport");
})
.WithTracing(tracing =>
{
tracing.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddHangfireInstrumentation()
.AddEntityFrameworkCoreInstrumentation()
.AddElasticsearchClientInstrumentation(options =>
{
options.SuppressDownstreamInstrumentation = true;
options.ParseAndFormatRequest = true;
})
.AddSource("Elastic.Transport")
.AddRedisInstrumentation();
});

// Add OTLP exporter if endpoint is configured
if (!string.IsNullOrWhiteSpace(configuration["OpenTelemetry:Endpoint"]))
{
otelBuilder.UseOtlpExporter();
}

return services;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,25 @@
<OutputType>Library</OutputType>
<IsPackable>false</IsPackable>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>1591</NoWarn>
<NoWarn>1591;NU1608</NoWarn>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this?

</PropertyGroup>
<PropertyGroup>
<!-- Project is not a test project -->
<SonarQubeTestProject>false</SonarQubeTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.0" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.15.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.15.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.ElasticsearchClient" Version="1.14.0-beta.1" />
<PackageReference Include="OpenTelemetry.Instrumentation.EntityFrameworkCore" Version="1.15.0-beta.1" />
<PackageReference Include="OpenTelemetry.Instrumentation.EventCounters" Version="1.15.0-alpha.1" />
<PackageReference Include="OpenTelemetry.Instrumentation.Hangfire" Version="1.14.0-beta.1" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.15.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Process" Version="1.15.0-beta.1" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.15.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.StackExchangeRedis" Version="1.15.0-beta.1" />
<PackageReference Include="Serilog.Sinks.OpenTelemetry" Version="4.2.0" />
<PackageReference Include="VirtoCommerce.Platform.Core" Version="3.1002.0" />
</ItemGroup>
</Project>
Loading
Loading