Qyl.Telemetry.AutoInstrumentation
14.0.1
See the version list below for details.
dotnet add package Qyl.Telemetry.AutoInstrumentation --version 14.0.1
NuGet\Install-Package Qyl.Telemetry.AutoInstrumentation -Version 14.0.1
<PackageReference Include="Qyl.Telemetry.AutoInstrumentation" Version="14.0.1" />
<PackageVersion Include="Qyl.Telemetry.AutoInstrumentation" Version="14.0.1" />
<PackageReference Include="Qyl.Telemetry.AutoInstrumentation" />
paket add Qyl.Telemetry.AutoInstrumentation --version 14.0.1
#r "nuget: Qyl.Telemetry.AutoInstrumentation, 14.0.1"
#:package Qyl.Telemetry.AutoInstrumentation@14.0.1
#addin nuget:?package=Qyl.Telemetry.AutoInstrumentation&version=14.0.1
#tool nuget:?package=Qyl.Telemetry.AutoInstrumentation&version=14.0.1
Qyl.Telemetry.AutoInstrumentation
Managed automatic instrumentation for .NET 10 applications, including NativeAOT consumers. The package uses compiler-generated Roslyn interceptors, build assets, BCL telemetry primitives, public diagnostic hooks, and module-initializer bootstrap. It does not use a CLR profiler, startup hooks, ReJIT, runtime IL rewriting, or dynamic plugin loading.
Roslyn interceptors are supported by this repository's .NET SDK 10.0.400. See the official
interceptors.md
contract.
Packages
| Package | Responsibility |
|---|---|
Qyl.Telemetry.Hosting |
One-line onboarding: OpenTelemetry SDK wiring, OTLP export, collector discovery, session propagation |
Qyl.Telemetry.AutoInstrumentation |
Core runtime, compiler-facing ABI, build assets, and source generator |
.Hosting |
Generic DI and process bootstrap |
.DiagnosticListeners |
Framework/library diagnostic event consumption |
.EntityFrameworkCore |
EF Core integration |
.SqlClient |
Microsoft.Data.SqlClient integration |
Add the package that owns the integration you need. The supported zero-configuration
consumer path is a PackageReference; build and analyzer assets flow through NuGet.
The family ships as one line; Directory.Build.props owns its version and
Directory.Packages.props the semantic-conventions pin. Its major is the compile-time ABI: a 14.x package pairs with QylGeneratedCodeAbi.V14
and nothing else, which is why the number is ahead of the rest of qyl and does not move
with the product version.
Coming from 8.x? These are new package IDs, not new versions of the old ones.
Qyl.OpenTelemetry.AutoInstrumentation* and Qyl.Sdk stop at 8.5.0 and are not
updated further; change the ID and take the current version. Qyl.Telemetry.Hosting is the
successor to Qyl.Sdk, and builder.AddQyl() is
unchanged. The generated-code ABI anchor is QylGeneratedCodeAbi.V14 in the
Qyl.Telemetry.AutoInstrumentation.GeneratedCode namespace — the anchor tracks the
package major, so it moved from V12 with the 14.x line, and no 13.x was ever
published — so a stale generated
interceptor cannot bind to the new runtime — it fails to compile rather than
misbehaving. The emitted scope names move to the package family in 10.0.0: the
ActivitySource is Qyl.Telemetry.AutoInstrumentation and the qyl meter is
Qyl.Telemetry.AutoInstrumentation.Database. Update AddSource(...),
AddMeter(...) and OTEL_DOTNET_AUTO_TRACES_ADDITIONAL_SOURCES. This package
emits the Qyl.Telemetry.AutoInstrumentation* scope names and nothing else, and
makes no compatibility promise for the old spellings. The strings are owned by
the semantic-convention registry, not by this repository — the code reads them
from QylTelemetryNames.Scopes.
dotnet add package Qyl.Telemetry.Hosting
How it works
- The source generator discovers supported source-visible calls and emits ordinary
C# methods annotated with
[InterceptsLocation]. buildandbuildTransitiveassets include the compiler-facing generator and enable the generated namespace in consumers.- Runtime helpers and diagnostic listeners emit bounded
ActivityandMetertelemetry using the referenced semantic-convention vocabulary. - Package-specific bootstrap activates the applicable listeners once per process.
Where a framework exposes a first-class DI or runtime hook, the package uses that hook. Interception is reserved for source-visible calls that require compile-time ownership.
Exporting to a collector
The shortest path is Qyl.Telemetry.Hosting, which owns all of the wiring below as one call:
using Qyl;
builder.AddQyl();
That activates the qyl listeners; registers the single qyl source for qyl-owned
ASP.NET Core, HttpClient, gRPC, and database spans plus the enabled first-party
library sources; and registers the native and qyl-owned meter inventory (ASP.NET
Core, HttpClient, DNS, database, messaging, and runtime). It copies session.id
from the nearest tagged in-process
ancestor to descendant spans (remote parents and unrelated trace branches are not
propagated); and exports traces, metrics, and logs over OTLP — to
OTEL_EXPORTER_OTLP_ENDPOINT when set, otherwise to QYL_ENDPOINT when that is
set, otherwise to a qyl collector discovered on localhost (4318/4317).
QYL_ENDPOINT names a collector for the qyl exporters alone, where the standard
variable would redirect every OTLP exporter in the process. It also registers the
exact library telemetry paths
listed below; wrapper-based libraries still require their explicit one-line opt-in.
The rest of this section is the manual wiring for apps that want to own it.
The lower-level instrumentation packages emit Activity and Meter telemetry; they
ship no exporter. An application that does not use Qyl.Telemetry.Hosting wires the OpenTelemetry
SDK and chooses where the telemetry goes. A working setup against the qyl collector
adds
OpenTelemetry.Extensions.Hosting and OpenTelemetry.Exporter.OpenTelemetryProtocol
alongside Qyl.Telemetry.AutoInstrumentation.Hosting, then registers the sources:
builder.Services.AddOpenTelemetry()
.ConfigureResource(r => r.AddService("my-service"))
.WithTracing(t => t
.AddSource("Qyl.Telemetry.AutoInstrumentation") // the qyl scope name — see note below
.AddOtlpExporter());
builder.Logging.AddOpenTelemetry(o => o.AddOtlpExporter());
Configure the exporter through the standard environment variables:
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318,
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf, and OTEL_SERVICE_NAME.
Do not also subscribe to Microsoft.AspNetCore or System.Net.Http traces when the
qyl listeners own those operations; doing so exports the same request twice. Azure
SDK tracing is the first-party exception: Qyl.Telemetry.Hosting enables
Azure.Experimental.EnableActivitySource, subscribes Azure.*, and normalizes the
exported Azure spans. A manually wired application must make those two choices
explicitly if it wants Azure SDK spans.
MassTransit
MassTransit emits its own spans from an ActivitySource named MassTransit
(MassTransit.Logging.DiagnosticHeaders.DefaultListenerName), so qyl subscribes
to that source and stamps qyl.instrumentation.domain onto its spans instead of
intercepting the call sites. The floor is MassTransit 8.0.0, the version that
introduced the source; verified against 8.5.10 (Apache-2.0). Below the floor
the source does not exist and no span is produced.
What the native span carries differs from the interceptor it replaces: the
producer span is named {destination} send, reports the transport in
messaging.system (rabbitmq, not masstransit), and reports the operation
through the deprecated messaging.operation key, always as send — MassTransit
routes Publish and Send through the same send transport, so the two are no
longer distinguishable in the span. MassTransit 9 is commercially licensed and is
neither referenced nor redistributed by this package, and the repository's own
demo pin is the range [8.5.10,9.0.0).
NServiceBus
NServiceBus emits its own spans from an ActivitySource named NServiceBus.Core
(NServiceBus.Core/OpenTelemetry/Tracing/ActivitySources.cs), on by default from
v10, so qyl subscribes to that source and stamps qyl.instrumentation.domain
onto its spans instead of intercepting IMessageSession and
IMessageHandlerContext. The floor is NServiceBus 8.0, the version that
introduced OpenTelemetry support; verified against 10.2.9.
What the native spans carry differs from the interceptor they replace. The
outgoing spans are named send message and publish event, the incoming
pipeline adds a process message span and a span named after each handler type,
and the whole vocabulary is the vendor nservicebus.* namespace plus
otel.status_code / otel.status_description: NServiceBus publishes no
messaging semantic conventions, so messaging.system,
messaging.operation.type, messaging.operation.name and error.type are gone
rather than reconstructed by qyl.
The qyl-synthesized nservicebus.messaging.operation.duration histogram, and
the Qyl.Telemetry.AutoInstrumentation.NServiceBus meter that carried it, are
gone with the interceptor that produced them. NServiceBus publishes its own
instruments — nservicebus.messaging.successes, .fetches, .failures,
.handler_time, .critical_time, .processing_time — on the meters
NServiceBus.Core and NServiceBus.Core.Pipeline.Incoming. Qyl.Telemetry.Hosting
does not force-register a library's own meters; a consumer that wants those
instruments exported registers them through
OTEL_DOTNET_AUTO_METRICS_ADDITIONAL_SOURCES (or QylSdkOptions.AdditionalMeters),
exactly as for the native Npgsql meter.
AI, MCP, and CoreWCF paths in 12.0
These are version-pinned library-hook claims, not provider- or protocol-wide claims.
The exact ModelContextProtocol 2.2.0 client/server path has strict NativeAOT
evidence; the other paths in this table have managed evidence only:
| Library path | Application opt-in | Signals registered by Qyl.Telemetry.Hosting |
Integration ID |
|---|---|---|---|
Microsoft.Extensions.AI 10.9.0 |
chatClient.AsBuilder().UseOpenTelemetry().Build() |
traces and metrics from Experimental.Microsoft.Extensions.AI |
MICROSOFTEXTENSIONSAI |
Microsoft.Agents.AI 1.20.0 |
agent.AsBuilder().UseOpenTelemetry().Build() |
traces and metrics from Experimental.Microsoft.Agents.AI |
MICROSOFTAGENTSAI |
Microsoft.Agents.AI.Workflows 1.20.0 |
WorkflowBuilder.WithOpenTelemetry() |
traces from Microsoft.Agents.AI.Workflows |
MICROSOFTAGENTSAIWORKFLOWS |
ModelContextProtocol 2.2.0 |
none; the official client/server SDK emits automatically | managed and strict NativeAOT traces from Experimental.ModelContextProtocol |
MCP |
CoreWCF.Http 1.9.1 |
none; CoreWCF emits server activities | managed traces from CoreWCF.Primitives |
WCFCORE |
MCP metrics are intentionally not registered: the official instruments attach
dynamic tool and resource names as dimensions, which conflicts with qyl's bounded-cardinality
policy. The 12.0 contract does not claim direct OpenAI SDK instrumentation, raw Anthropic SDK
instrumentation, Azure.AI.Inference, Amazon Bedrock, or A2A.
Every path is enabled by default when its signal is enabled. Set the applicable
signal-specific variable to false to disable it:
MICROSOFTEXTENSIONSAI:OTEL_DOTNET_AUTO_TRACES_MICROSOFTEXTENSIONSAI_INSTRUMENTATION_ENABLEDandOTEL_DOTNET_AUTO_METRICS_MICROSOFTEXTENSIONSAI_INSTRUMENTATION_ENABLED.MICROSOFTAGENTSAI:OTEL_DOTNET_AUTO_TRACES_MICROSOFTAGENTSAI_INSTRUMENTATION_ENABLEDandOTEL_DOTNET_AUTO_METRICS_MICROSOFTAGENTSAI_INSTRUMENTATION_ENABLED.MICROSOFTAGENTSAIWORKFLOWS:OTEL_DOTNET_AUTO_TRACES_MICROSOFTAGENTSAIWORKFLOWS_INSTRUMENTATION_ENABLED.MCP:OTEL_DOTNET_AUTO_TRACES_MCP_INSTRUMENTATION_ENABLED.WCFCORE:OTEL_DOTNET_AUTO_TRACES_WCFCORE_INSTRUMENTATION_ENABLED.
The global OTEL_DOTNET_AUTO_INSTRUMENTATION_ENABLED and per-signal
OTEL_DOTNET_AUTO_{TRACES|METRICS|LOGS}_INSTRUMENTATION_ENABLED switches still take
precedence.
Coverage and evidence
The generated coverage matrix is the detailed contract
view. It keeps NativeAOT runtime evidence, managed runtime evidence, configuration
bindings, and unsupported rows separate. A configuration binding is not runtime
instrumentation, and the matrix is generated from the declared contracts rather than
being independent empirical proof. Runtime claims are backed by executable demos or
consumers named in the underlying ownership contracts.
The NativeAOT boundary applies to this compile-time/managed substrate. It does not claim parity with the CLR-profiler OpenTelemetry .NET automatic instrumentor, and it does not imply that every third-party library itself publishes warning-free under NativeAOT.
Limitations
- Only source-visible call sites can be intercepted. Calls hidden in compiled dependencies, reflection, or dynamic dispatch need a public runtime hook or remain unsupported.
- Some integrations are managed-only because the instrumented library requires runtime code generation.
- Query text and other sensitive or high-cardinality values remain opt-in or redacted according to the package options and upstream OpenTelemetry controls.
- Generic HTTP header capture never records the reserved
Mcp-Param-*namespace. Those headers mirror MCP tool arguments; any argument-content capture belongs to an MCP-specific, explicitly enabled policy rather than the HTTP instrumentation layer. - Generator snapshots prove emitted source shape; protocol interoperability requires a real OTLP receiver and structural decoding of official protobuf messages.
Verify
Run the complete local gate:
python3 tools/verify-aot-autoinstrumentation-goal.py
That gate builds the package and demo solutions, validates generated artifacts and public API baselines, and executes managed/NativeAOT consumer evidence.
Live check
tools/verify-live-check.py runs weaver registry live-check as an OTLP listener and points
the native-source demo lanes at it, so every span this package's processor stamps is judged
against the pinned semantic-convention registry rather than against an assertion written here.
--fail-on violation is the threshold and there is no allowlist in the gate. A finding is
closed by changing what the instrumentation writes or by declaring the key in the registry —
never by waving it through.
One gap is recorded rather than hidden: RabbitMQ.Client.Subscriber has no consuming demo.
Qyl.Telemetry.Hosting subscribes to both RabbitMQ source names, but the RabbitMQ lane only
publishes, so the subscriber source emits nothing and the deliver and fetch spans the
14.x line added are unjudged by this gate.
License
Apache-2.0
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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
- Qyl.Telemetry.SemanticConventions (>= 9.1.0)
- Qyl.Telemetry.SemanticConventions.Incubating (>= 9.1.0)
NuGet packages (4)
Showing the top 4 NuGet packages that depend on Qyl.Telemetry.AutoInstrumentation:
| Package | Downloads |
|---|---|
|
Qyl.Telemetry.AutoInstrumentation.DiagnosticListeners
AOT-native DiagnosticListener subscribers — qyl's replacement for the substrate's IL-rewriting CallTarget integrations. |
|
|
Qyl.Telemetry.AutoInstrumentation.Hosting
Zero-code AOT boot: [ModuleInitializer] auto-activates the qyl listeners when the assembly is loaded. Also exposes AddQylAutoInstrumentation() for explicit wiring. |
|
|
Qyl.Telemetry.AutoInstrumentation.SqlClient
Zero-code AOT-native Microsoft.Data.SqlClient DiagnosticSource instrumentation for qyl. |
|
|
Qyl.Telemetry.AutoInstrumentation.EntityFrameworkCore
Zero-code AOT-native EFCore DiagnosticSource instrumentation for qyl. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 21.1.0 | 212 | 9/11/2026 |
| 21.0.2 | 65 | 9/11/2026 |
| 21.0.1 | 238 | 9/9/2026 |
| 20.0.0 | 106 | 9/8/2026 |
| 17.0.0 | 104 | 9/8/2026 |
| 16.0.0 | 110 | 9/7/2026 |
| 15.0.0 | 105 | 9/7/2026 |
| 14.1.0 | 418 | 9/7/2026 |
| 14.0.1 | 262 | 9/7/2026 |
| 12.0.0 | 141 | 9/4/2026 |
| 11.0.0 | 252 | 9/3/2026 |
| 10.1.0 | 231 | 9/2/2026 |
| 10.0.0 | 203 | 9/2/2026 |
| 9.1.0 | 1,168 | 8/20/2026 |
| 9.0.1 | 1,074 | 7/27/2026 |
| 9.0.0 | 179 | 7/27/2026 |