OrionGuard.OpenTelemetry
7.0.0
dotnet add package OrionGuard.OpenTelemetry --version 7.0.0
NuGet\Install-Package OrionGuard.OpenTelemetry -Version 7.0.0
<PackageReference Include="OrionGuard.OpenTelemetry" Version="7.0.0" />
<PackageVersion Include="OrionGuard.OpenTelemetry" Version="7.0.0" />
<PackageReference Include="OrionGuard.OpenTelemetry" />
paket add OrionGuard.OpenTelemetry --version 7.0.0
#r "nuget: OrionGuard.OpenTelemetry, 7.0.0"
#:package OrionGuard.OpenTelemetry@7.0.0
#addin nuget:?package=OrionGuard.OpenTelemetry&version=7.0.0
#tool nuget:?package=OrionGuard.OpenTelemetry&version=7.0.0
OrionGuard.OpenTelemetry
Answers "how often does validation fail, and what does it cost" by wrapping your registered validators and the domain-event dispatcher in System.Diagnostics instrumentation any OpenTelemetry SDK can collect.
dotnet add package OrionGuard.OpenTelemetry
using Microsoft.Extensions.DependencyInjection;
using Moongazing.OrionGuard.DependencyInjection;
using Moongazing.OrionGuard.OpenTelemetry;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
public sealed record CreateUserRequest(string Email);
public sealed class CreateUserValidator : AbstractValidator<CreateUserRequest>
{
public CreateUserValidator() =>
RuleFor(x => x.Email, nameof(CreateUserRequest.Email), p => p.NotEmpty().Email());
}
public static class TelemetrySetup
{
public static void Add(IServiceCollection services)
{
services.AddValidator<CreateUserRequest, CreateUserValidator>();
services.AddOrionGuardOpenTelemetry(); // after every validator is registered
services.AddOpenTelemetry()
.WithMetrics(m => m.AddMeter(OrionGuardInstrumentation.MeterName))
.WithTracing(t => t.AddSource(OrionGuardInstrumentation.ActivitySourceName));
}
}
Every validation now emits a count, a failure count and a duration on the meter Moongazing.OrionGuard, plus an Internal span under whatever activity is current — an ASP.NET Core request span, for instance. The package itself depends only on OpenTelemetry.Api; add the SDK and an exporter (OpenTelemetry.Extensions.Hosting, OpenTelemetry.Exporter.OpenTelemetryProtocol) to get the data out.
There is no AddOrionGuardInstrumentation() builder extension — subscribe to the meter and the activity source by name, as above.
Validator instrumentation
AddOrionGuardOpenTelemetry() replaces every closed, non-keyed IValidator<T> registration already in the collection with an InstrumentedValidator<T> that wraps the original and keeps its lifetime. InstrumentedValidator<T> implements every IValidator<T> overload and passes the ValidationContext through, so context-aware rules keep working.
Meter and ActivitySource name: Moongazing.OrionGuard (OrionGuardInstrumentation.MeterName, OrionGuardInstrumentation.ActivitySourceName); the instrumentation version is the package version.
| Instrument | Type | Unit | Tags |
|---|---|---|---|
orionguard.validations.total |
Counter<long> |
none | none |
orionguard.validations.failures |
Counter<long> |
none | none |
orionguard.validations.duration_ms |
Histogram<double> |
ms | none |
Spans are named OrionGuard.Validate or OrionGuard.ValidateAsync after the method actually called, and carry orionguard.validator_type (the model type's name), orionguard.validation_result (success or failed) and, on failure, orionguard.error_count.
Domain-event instrumentation
using Microsoft.Extensions.DependencyInjection;
using Moongazing.OrionGuard.DependencyInjection;
using Moongazing.OrionGuard.OpenTelemetry.DomainEvents;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
public static class DomainEventTelemetrySetup
{
public static void Add(IServiceCollection services)
{
services.AddOrionGuardDomainEvents();
services.WithOpenTelemetryDomainEvents();
services.AddOpenTelemetry()
.WithMetrics(m => m.AddMeter(OrionGuardDomainEventTelemetry.MeterName))
.WithTracing(t => t.AddSource(OrionGuardDomainEventTelemetry.ActivitySourceName));
}
}
WithOpenTelemetryDomainEvents() wraps the last registered IDomainEventDispatcher in an InstrumentedDomainEventDispatcher of the same lifetime. It throws InvalidOperationException when no dispatcher is registered, and a second call does nothing.
Meter and ActivitySource name: Moongazing.OrionGuard.DomainEvents.
| Instrument | Type | Unit | Tags |
|---|---|---|---|
orionguard.domain_events.dispatched |
Counter<long> |
events | event_type |
orionguard.domain_events.failed |
Counter<long> |
events | event_type |
orionguard.domain_events.duration |
Histogram<double> |
ms | event_type |
event_type is the event's short CLR type name. Each event — including each event of a batch — gets its own Internal span named DomainEvent.Dispatch <EventTypeName>, tagged with orionguard.event.id, orionguard.event.type (full name) and orionguard.event.occurred_on (ISO 8601 round-trip). A failure sets the span status to Error with the exception message, adds an exception event carrying exception.type and exception.message, and rethrows.
Ordering
Call AddOrionGuardOpenTelemetry() after every validator is registered — it decorates what is in the collection at that moment, and a validator registered later is not instrumented.
With the MediatR event bridge the order is AddOrionGuardDomainEvents(), then AddOrionGuardMediatRDomainEvents(), then WithOpenTelemetryDomainEvents(). The bridge refuses to run after the decorator, because replacing the registration would silently remove it.
What this does not do
- It only sees validation that goes through a DI-resolved
IValidator<T>.Guard.Against...,Ensure.That(...),Validate.For(...)andAttributeValidatorare invisible to it — they never touch the container. - Open-generic and keyed registrations are left alone.
AddTransient(typeof(IValidator<>), typeof(MyValidator<>))and keyed validators are not instrumented (and, deliberately, not broken either). - No metric carries the model type. The three validator instruments have no tags at all; the type is on the span, not on the counters, so you cannot split failure rate by model in a metrics backend. The counts stay cheap because of it.
- It exports nothing on its own. Without an SDK and an exporter subscribed to the two names, the instruments and spans are inert.
- It adds a layer per validator. One extra object and one span per validation — small, but not free on a hot path that validates millions of times.
Targets
net8.0, net9.0, net10.0; OpenTelemetry.Api 1.x.
With the rest of OrionGuard
OrionGuard · OrionGuard.MediatR (the MediatR event bridge) · OrionGuard.AspNetCore · OrionGuard.EntityFrameworkCore (the outbox has its own meter)
Documentation
License
MIT. See LICENSE.txt.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- OpenTelemetry.Api (>= 1.19.0)
- OrionGuard (>= 7.0.0)
-
net8.0
- OpenTelemetry.Api (>= 1.19.0)
- OrionGuard (>= 7.0.0)
-
net9.0
- OpenTelemetry.Api (>= 1.19.0)
- OrionGuard (>= 7.0.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on OrionGuard.OpenTelemetry:
| Package | Downloads |
|---|---|
|
OrionGuard.Aspire
Aspire integration for OrionGuard. One call, builder.AddOrionGuardDefaults(), subscribes the app's OpenTelemetry pipeline to every OrionGuard meter and activity source (validation, domain events, EF Core outbox) so they appear in the Aspire dashboard, and registers the OrionGuard health checks for the packages the app uses. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 7.0.0 | 94 | 9/20/2026 |
| 6.7.1 | 123 | 7/20/2026 |
| 6.7.0 | 106 | 7/20/2026 |
| 6.6.2 | 138 | 6/20/2026 |
| 6.6.1 | 118 | 6/20/2026 |
| 6.6.0 | 123 | 6/19/2026 |
| 6.5.30 | 130 | 6/17/2026 |
| 6.5.29 | 113 | 6/15/2026 |
| 6.5.28 | 113 | 6/15/2026 |
| 6.5.27 | 113 | 6/15/2026 |
| 6.5.26 | 118 | 6/13/2026 |
| 6.5.25 | 108 | 6/13/2026 |
| 6.5.24 | 112 | 6/12/2026 |
| 6.5.23 | 119 | 6/12/2026 |
| 6.5.22 | 123 | 6/11/2026 |
| 6.5.21 | 120 | 6/11/2026 |
| 6.5.20 | 108 | 6/11/2026 |
| 6.5.19 | 115 | 6/11/2026 |
| 6.5.18 | 123 | 6/11/2026 |
| 6.5.16 | 113 | 6/11/2026 |