AutoInstrument 1.1.1
dotnet add package AutoInstrument --version 1.1.1
NuGet\Install-Package AutoInstrument -Version 1.1.1
<PackageReference Include="AutoInstrument" Version="1.1.1"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="AutoInstrument" Version="1.1.1" />
<PackageReference Include="AutoInstrument"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add AutoInstrument --version 1.1.1
#r "nuget: AutoInstrument, 1.1.1"
#:package AutoInstrument@1.1.1
#addin nuget:?package=AutoInstrument&version=1.1.1
#tool nuget:?package=AutoInstrument&version=1.1.1
AutoInstrument
[Instrument] for .NET - add an attribute, get OpenTelemetry spans with tagged parameters at every call-site. Inspired by Rust's #[instrument].
[Instrument]
public async Task<string> ShaveYak(int yakId, string style)
{
await Task.Delay(50);
return $"Yak #{yakId} shaved with {style}";
}
Under the hood, the source generator emits C# interceptors that wrap each call-site with an Activity, tag parameters, and record exceptions. Your method is never modified.
Setup
Add the package and enable interceptors:
<PropertyGroup>
<InterceptorsNamespaces>$(InterceptorsNamespaces);AutoInstrument.Generated</InterceptorsNamespaces>
</PropertyGroup>
using AutoInstrument;
[Instrument]
public async Task<Order> ProcessOrder(int orderId, string customer) { ... }
[Instrument(Skip = new[] { "creditCard" })]
public async Task ChargeCustomer(int orderId, string creditCard) { ... }
[Instrument(Name = "orders.compute_total", RecordReturnValue = true)]
public decimal ComputeTotal(List<LineItem> items) => items.Sum(i => i.Price * i.Quantity);
Options
| Property | Default | Description |
|---|---|---|
Name |
Class.Method |
Span name |
Skip |
— | Parameters/properties to exclude from tags |
Fields |
— | Whitelist -D only these become tags |
ActivitySourceName |
Assembly name | Custom ActivitySource name |
RecordReturnValue |
false |
Tag the return value |
RecordException |
true |
Record exceptions on the span |
Kind |
0 (Internal) |
ActivityKind (0=Internal, 1=Server, 2=Client, 3=Producer, 4=Consumer) |
RecordSuccess |
false |
Set status Ok on success |
IgnoreCancellation |
true |
Don't record OperationCanceledException as errors |
Condition |
— | Boolean member name - skip instrumentation when false |
LinkTo |
— | Parameter name (must be ActivityContext) to attach as ActivityLink |
Depth |
Global default (1) | Max depth for expanding complex type properties |
Skip and Fields support dot-notation at any depth: Skip = new[] { "order.Address.City" }.
Parameter attributes
[NoInstrument] on a parameter skips it from tagging. Pass property names to skip specific properties of a complex type:
public void Login(string user, [NoInstrument] string password) { ... }
public void Process([NoInstrument("CreditCard", "SSN")] Order order) { ... }
Member tags
[Tag] on a field or property includes it as a span tag on all [Instrument] methods in the class:
public class OrderService
{
[Tag] public string Region { get; set; }
[Tag(Name = "env")] public string Environment { get; set; }
[Instrument]
public void Process(int orderId) { ... }
// Tags: process.orderid, region, env
}
Complex types are expanded recursively, just like method parameters. Use Skip, Fields, or Depth to control expansion:
public class OrderService
{
[Tag(Skip = new[] { "Secret" })] public Config Settings { get; set; }
[Tag(Fields = new[] { "Region" })] public Config Backup { get; set; }
[Tag(Depth = 1)] public Config Shallow { get; set; }
// Settings → settings.region, settings.timeout (Secret excluded)
// Backup → backup.region (only Region included)
// Shallow → one level only
}
Complex types
Classes and structs are expanded one level deep by default. Dot-notation in Skip or Fields automatically resolves deeper — no need to increase Depth manually:
[Instrument]
public void Process(Order order) { ... }
// Tags: process.order.id, process.order.address (1 level deep)
[Instrument(Fields = new[] { "order.Address.City" })]
public void Targeted(Order order) { ... }
// Tags: process.order.address.city (auto-resolved to reach City)
[Instrument(Depth = 3)]
public void Deep(Order order) { ... }
// Tags: process.order.id, process.order.address.city, process.order.address.zip (fully expanded)
Circular references are detected and stopped automatically. Collections (arrays, List<T>, etc.) are not expanded — they are tagged as-is.
Configuration
The ActivitySource name defaults to the assembly name. Override at three levels (highest priority wins):
- Per-method:
[Instrument(ActivitySourceName = "X")] - MSBuild:
<AutoInstrumentSourceName>X</AutoInstrumentSourceName> - Assembly attribute:
[assembly: AutoInstrumentSource("X")]
Tag naming defaults to methodname.param. Set it to Flat for just param:
[assembly: AutoInstrumentConfig(TagNaming = TagNamingConvention.Flat)]
Or via MSBuild: <AutoInstrumentTagNaming>Flat</AutoInstrumentTagNaming>
The default expansion depth is 1. Dot-notation in Skip/Fields auto-resolves deeper. Override globally:
[assembly: AutoInstrumentConfig(Depth = 2)]
Or via MSBuild: <AutoInstrumentDepth>2</AutoInstrumentDepth>
Diagnostics
| ID | Description |
|---|---|
| AUTOINST001 | Skip references unknown parameter |
| AUTOINST002 | Fields references unknown parameter |
| AUTOINST003 | Dot-notation references unknown property |
| AUTOINST004 | Condition is not a boolean member |
| AUTOINST005 | LinkTo is not an ActivityContext parameter |
| AUTOINST006 | [NoInstrument] references unknown property |
| AUTOINST007 | [Tag] Skip references unknown property |
| AUTOINST008 | [Tag] Fields references unknown property |
Limitations
- Interceptors only work within the same compilation — cross-project calls aren't intercepted.
- Recursive calls create nested spans.
- Complex types expand up to the configured depth (default 1). Dot-notation auto-resolves deeper. Collections are not expanded.
Requirements
.NET 10
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. 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 was computed. 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 was computed. 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
This package has no dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
### Documentation
- update comments in InstrumentAttribute for clarity
- update README for improved clarity and structure
### Features
- add initial project files and configuration for AutoInstrument
- add diagnostic analyzer for InstrumentAttribute validation
- add support for dot-notation property validation
- add README section for attribute options and validation rules
- add tagging and instrumentation attributes for enhanced tracing
- add new sample projects and services for AspireSample API
- add new project GUID for enhanced instrumentation
- add support for complex types in Tag attribute
- add Depth property for complex type expansion control
- implement tag filtering and formatting logic
- add PackageTags and PackageReleaseNotes for better metadata
- update release notes generation and add GitHub release step
### Miscellaneous
- update packaging and push commands for AutoInstrument
- include README.md in package for better documentation access
- update package references for improved compatibility
- update Microsoft.Extensions.Http.Resilience package to version 10.3.0
### Refactor
- remove commented-out code for clarity
- simplify XML documentation for clarity