Skip to content
Merged
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
31 changes: 20 additions & 11 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ The package family is public. Existing NuGet artifacts are immutable. Make
intentional breaking convergence in a new major version, migrate known consumers,
and do not add compatibility shims without a proven external requirement.

Three API categories are explicit, and 6.0.0 fixed their concrete form. Preserve it:
The following API/ABI categories define the active 8.0 architecture. Preserve them:

1. A small supported user API for bootstrap and configuration: Hosting
`Boot()`/`AddQylAutoInstrumentation(...)`, `Qyl.Sdk` `AddQyl(...)`/`QylSdkOptions`,
Expand All @@ -29,15 +29,24 @@ Three API categories are explicit, and 6.0.0 fixed their concrete form. Preserve
`[EditorBrowsable(EditorBrowsableState.Never)]`, anchored by the
`QylGeneratedCodeAbi.V8` const that every generated interceptor file references so
a generator/runtime ABI mismatch fails compilation. That namespace, the anchor, and
the `V<major>` bump on a breaking ABI change are load-bearing: the snapshot and
invariant verifiers pin these exact tokens. Do not rename or re-derive them.
the `V<major>` bump on a breaking ABI change are load-bearing: the version-sync and
generated-source snapshot verifiers pin the exact token. Do not rename or re-derive it.
Generated code must not reference `QylAutoInstrumentationOptions` or
`QylInstrumentationDomains` — gate opt-ins at the policy type and emit domain names
as literals.
3. Internal implementation types, semantic helpers, listeners, and runtime state —
3. A narrow generated-code/build-transitive package bootstrap ABI, also under the
`Qyl.OpenTelemetry.AutoInstrumentation.GeneratedCode` namespace and hidden with
`[EditorBrowsable(EditorBrowsableState.Never)]`:
`EntityFrameworkCoreAutoInstrumentationBootstrap` and
`SqlClientAutoInstrumentationBootstrap`. They are public because generated source
compiled into consumer assemblies calls them; they are package plumbing, not user
configuration APIs.
4. Internal implementation types, semantic helpers, listeners, meter registration
inventory, and runtime state —
everything else, including `QylSemanticAttributes`, `QylActivityNames`,
`QylActivitySource`, `QylAutoInstrumentationOptions`, and `QylInstrumentationDomains`.
Reach across assemblies with IVT, never by widening a type to public.
`QylActivitySource`, `QylAutoInstrumentationOptions`, `QylInstrumentationDomains`,
and `QylMetricMeters`. Reach across assemblies with IVT, never by widening a type to
public.

Cross-assembly accessibility does not make generator ABI a user-facing product API.
Any Qyl-specific client-visible request, response, event, or error contract belongs
Expand All @@ -55,10 +64,10 @@ Two generated namespaces exist, four characters apart. Do not conflate them:

- `Qyl.OpenTelemetry.AutoInstrumentation.Generated` — where the generator emits
interceptor methods, and the value `buildTransitive` adds to
`InterceptorsNamespaces`. Compiler-facing wiring; 6.0.0 did not move it.
`InterceptorsNamespaces`. Compiler-facing wiring; it remains load-bearing in 8.0.
- `Qyl.OpenTelemetry.AutoInstrumentation.GeneratedCode` — the runtime ABI helpers
(`QylIntercepted*`, `QylMetricMeters`, the `QylGeneratedCodeAbi.V8` anchor) that
emitted interceptors call into.
(`QylIntercepted*` and the `QylGeneratedCodeAbi.V8` anchor) that emitted
interceptors call into.

Emitted code lives in the first and delegates to the second. Renaming either side —
or "fixing" the near-duplicate names — breaks the build assets or the pinned
Expand Down Expand Up @@ -88,8 +97,8 @@ own the same call site.
generated coverage matrix and conformance artifacts. Change inputs/generators,
regenerate, and commit the outputs together.
- The coverage matrix distinguishes runtime evidence from configuration bindings and
unsupported rows. Never summarize all 60 contract rows as 60 runtime-implemented or
NativeAOT-verified integrations.
unsupported rows. Never summarize the 60-row upstream contract or the separate
qyl-native promises as universally runtime-implemented or NativeAOT-verified.
- Missing runtime values stay missing. Keep span names and metric dimensions bounded;
sensitive values follow the repository's explicit redaction/opt-in controls.

Expand Down
76 changes: 76 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,82 @@ stack line and are owned by `<Version>` in `Directory.Build.props`. CI packs tha
proves the indexed packages in clean managed and NativeAOT consumers, and only then creates the
matching `v*` tag and GitHub release.

## [8.0.0] - 2026-07-19

Intentional breaking convergence plus version-pinned telemetry paths. The new AI,
MCP, and CoreWCF entries below describe only the exact library versions and hooks
exercised by repository evidence; they are not provider- or protocol-wide claims.
The exact `ModelContextProtocol` 1.4.1 client/server path has strict NativeAOT
evidence; the other new paths have managed evidence only.

### Breaking changes

- **BREAKING:** the generated-code ABI anchor moved from
`QylGeneratedCodeAbi.V6` to `QylGeneratedCodeAbi.V8`. Generated interceptors now
require the V8 runtime anchor, so mixing an 8.x generator with a 6.x runtime (or
the reverse) fails compilation.
- **BREAKING:** deleted the orphan `QylInterceptedWcfCore` generated-code helper and
its unused policy/domain/name tail. No generator called it; CoreWCF server spans
now use the official `CoreWCF.Primitives` `ActivitySource` path.
- **BREAKING:** deleted the generated HttpWebRequest, ASP.NET endpoint-map,
EF Core, Azure client, and `MeterProviderBuilder.AddMeter` interceptor lanes and
their unused generated-code helpers. Runtime listeners, specialist packages,
explicit SDK meter registration, and first-party Azure sources are now the single
owners of those signals. The HttpClient and gRPC client interceptor lanes remain
the call-site owners of outbound HTTP/gRPC spans, header/metadata capture, and
URL redaction; their completion listeners defer per signal ownership.
- **BREAKING:** deleted the DiagnosticListeners package's synthetic `qyl.db.efcore` and
`qyl.db.sqlclient` demo listeners. Real EF Core and Microsoft.Data.SqlClient events
are owned only by their dependency-isolating specialist packages.
- **BREAKING:** deleted the custom HTTP duration producer; the
`System.Net.Http/http.client.request.duration` instrument is authoritative. The
NServiceBus qyl meter is now `Qyl.OpenTelemetry.AutoInstrumentation.NServiceBus`,
and `Qyl.Sdk` no longer force-registers the library-native `Npgsql`,
`NServiceBus.Core`, and `NServiceBus.Core.Pipeline.Incoming` meters — consumers
that want those instruments exported register them via
`QylSdkOptions.AdditionalMeters`. MCP metrics are likewise outside the 8.0.0
contract (mcp spans are registered; the `Experimental.ModelContextProtocol` meter
is consumer-registered).
- **BREAKING:** renamed the public diagnostic extension base
`DiagnosticListenerSubscriber` to `QylDiagnosticListenerSubscriber`. The five
concrete ASP.NET Core, EF Core, gRPC client, HttpClient, and SqlClient listener
types are internal; the abstract qyl-prefixed subscriber remains the supported
extension surface.

### Changed

- Every emitted interceptor now carries one adjacent machine-readable JSON manifest
containing its interceptor kind, signal, instrumentation ID, additional metric
IDs, and canonically derived contract keys. Contract verification reads emitted
generated output instead of reconstructing ownership from generator source text,
and proves that every remaining catalog kind appears in the checked artifact.
- Azure SDK instrumentation now uses the SDK's first-party `Azure.*`
`ActivitySource` path. Bootstrap enables `Azure.Experimental.EnableActivitySource`;
`Qyl.Sdk` subscribes the wildcard and normalizes the bounded qyl domain/name/error
contract before export.
- The `Qyl.Sdk` → Hosting → core NuGet dependency chain now preserves build and
analyzer assets. A clean consumer references only `Qyl.Sdk`, executes `AddQyl`,
requires an emitted interceptor, and runs the same payload as managed code and
NativeAOT.
- `Qyl.Sdk` registers the following version-pinned, environment-switchable telemetry paths:
- `Microsoft.Extensions.AI` 10.8.0 traces and metrics through the application's
explicit `UseOpenTelemetry()` chat-client wrapper;
- `Microsoft.Agents.AI` 1.13.0 traces and metrics through the application's
explicit `UseOpenTelemetry()` agent wrapper;
- `Microsoft.Agents.AI.Workflows` 1.13.0 traces through the application's explicit
`WithOpenTelemetry()` workflow hook;
- `ModelContextProtocol` 1.4.1 automatic official client/server traces, verified
on the exact path under both managed execution and strict NativeAOT; and
- `CoreWCF.Http` 1.9.1 managed server traces from `CoreWCF.Primitives`.
- The new signal-specific IDs are `MICROSOFTEXTENSIONSAI`, `MICROSOFTAGENTSAI`,
`MICROSOFTAGENTSAIWORKFLOWS`, and `MCP`; CoreWCF uses `WCFCORE`. Each follows the
standard `OTEL_DOTNET_AUTO_{SIGNAL}_{ID}_INSTRUMENTATION_ENABLED` switch shape.
- MCP is traces-only in 8.0. Its metrics are deliberately not registered because the
official instruments attach dynamic tool and resource names as dimensions, which
conflicts with qyl's bounded-cardinality policy.
- Direct OpenAI SDK instrumentation, raw Anthropic SDK instrumentation,
`Azure.AI.Inference`, Amazon Bedrock, and A2A are not claimed by 8.0.

## [6.0.0] - 2026-07-18

Intentional pre-consumer convergence release: the last cheap breaking window
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<Deterministic>true</Deterministic>
<ContinuousIntegrationBuild Condition="'$(CI)' == 'true'">true</ContinuousIntegrationBuild>

<Version>6.0.0</Version>
<Version>8.0.0</Version>
<Authors>qyl</Authors>
<RepositoryUrl>https://github.com/ANcpLua/Qyl.OpenTelemetry.AutoInstrumentation</RepositoryUrl>
<RepositoryType>git</RepositoryType>
Expand Down
5 changes: 5 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<PackageVersion Include="Azure.Storage.Blobs" Version="12.29.0" />
<PackageVersion Include="BenchmarkDotNet" Version="0.15.8" />
<PackageVersion Include="Confluent.Kafka" Version="2.14.2" />
<PackageVersion Include="CoreWCF.Http" Version="1.9.1" />
<PackageVersion Include="Elastic.Clients.Elasticsearch" Version="9.4.2" />
<PackageVersion Include="Elastic.Transport" Version="1.0.0" />
<PackageVersion Include="ErrorProne.NET.CoreAnalyzers" Version="0.8.2-beta.1" />
Expand All @@ -20,6 +21,8 @@
<PackageVersion Include="log4net" Version="3.3.1" />
<!-- MassTransit 9+ requires a runtime license; the verifier stays on the no-secret 8.x line. -->
<PackageVersion Include="MassTransit.RabbitMQ" Version="8.5.10" />
<PackageVersion Include="Microsoft.Agents.AI" Version="1.13.0" />
<PackageVersion Include="Microsoft.Agents.AI.Workflows" Version="1.13.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="5.3.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="5.3.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="3.3.4" />
Expand All @@ -28,11 +31,13 @@
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.9" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.9" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.9" />
<PackageVersion Include="Microsoft.Extensions.AI" Version="10.8.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.9" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.9" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="10.0.9" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.9" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.9" />
<PackageVersion Include="ModelContextProtocol" Version="1.4.1" />
<PackageVersion Include="MongoDB.Driver" Version="3.9.0" />
<PackageVersion Include="MySql.Data" Version="9.7.0" />
<PackageVersion Include="MySqlConnector" Version="2.6.0" />
Expand Down
10 changes: 10 additions & 0 deletions Qyl.OpenTelemetry.AutoInstrumentation.Demos.slnx
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
<Solution>
<Project Path="src/Qyl.OpenTelemetry.AutoInstrumentation/Qyl.OpenTelemetry.AutoInstrumentation.csproj" />
<Project Path="src/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators/Qyl.OpenTelemetry.AutoInstrumentation.SourceGenerators.csproj" />
<Project Path="src/Qyl.OpenTelemetry.AutoInstrumentation.DiagnosticListeners/Qyl.OpenTelemetry.AutoInstrumentation.DiagnosticListeners.csproj" />
<Project Path="src/Qyl.OpenTelemetry.AutoInstrumentation.EntityFrameworkCore/Qyl.OpenTelemetry.AutoInstrumentation.EntityFrameworkCore.csproj" />
<Project Path="src/Qyl.OpenTelemetry.AutoInstrumentation.Hosting/Qyl.OpenTelemetry.AutoInstrumentation.Hosting.csproj" />
<Project Path="src/Qyl.OpenTelemetry.AutoInstrumentation.SqlClient/Qyl.OpenTelemetry.AutoInstrumentation.SqlClient.csproj" />
<Project Path="src/Qyl.Sdk/Qyl.Sdk.csproj" />
<Project Path="demos/Qyl.RealAdoNetDemo/Qyl.RealAdoNetDemo.csproj" />
<Project Path="demos/Qyl.RealAspNetCoreDemo/Qyl.RealAspNetCoreDemo.csproj" />
<Project Path="demos/Qyl.RealAspNetCoreMetricsDemo/Qyl.RealAspNetCoreMetricsDemo.csproj" />
<Project Path="demos/Qyl.RealCoreWcfDemo/Qyl.RealCoreWcfDemo.csproj" />
<Project Path="demos/Qyl.RealAzureDemo/Qyl.RealAzureDemo.csproj" />
<Project Path="demos/Qyl.RealEfCoreDemo/Qyl.RealEfCoreDemo.csproj" />
<Project Path="demos/Qyl.RealElasticsearchDemo/Qyl.RealElasticsearchDemo.csproj" />
<Project Path="demos/Qyl.RealElasticTransportDemo/Qyl.RealElasticTransportDemo.csproj" />
<Project Path="demos/Qyl.RealGenAiDemo/Qyl.RealGenAiDemo.csproj" />
<Project Path="demos/Qyl.RealGraphQlDemo/Qyl.RealGraphQlDemo.csproj" />
<Project Path="demos/Qyl.RealGrpcClientDemo/Qyl.RealGrpcClientDemo.csproj" />
<Project Path="demos/Qyl.RealHttpClientDemo/Qyl.RealHttpClientDemo.csproj" />
<Project Path="demos/Qyl.RealILoggerDemo/Qyl.RealILoggerDemo.csproj" />
<Project Path="demos/Qyl.RealKafkaDemo/Qyl.RealKafkaDemo.csproj" />
<Project Path="demos/Qyl.RealLog4NetDemo/Qyl.RealLog4NetDemo.csproj" />
<Project Path="demos/Qyl.RealMassTransitDemo/Qyl.RealMassTransitDemo.csproj" />
<Project Path="demos/Qyl.RealMcpDemo/Qyl.RealMcpDemo.csproj" />
<Project Path="demos/Qyl.RealMongoDbDemo/Qyl.RealMongoDbDemo.csproj" />
<Project Path="demos/Qyl.RealMySqlConnectorDemo/Qyl.RealMySqlConnectorDemo.csproj" />
<Project Path="demos/Qyl.RealMySqlDataDemo/Qyl.RealMySqlDataDemo.csproj" />
Expand Down
Loading
Loading