-
Notifications
You must be signed in to change notification settings - Fork 3
Multi Targeting
Multi-targeting allows you to generate multiple types of telemetry (Activities, Logs, and Metrics) from a single interface or even a single method.
Important
v4 Update: v4 fully supports multiple generation targets on a single method! This is a powerful feature for creating comprehensive observability from minimal code.
Apply multiple generation attributes to an interface to enable all telemetry types:
using Purview.Telemetry;
[ActivitySource("OrderService")]
[Logger]
[Meter("OrderService")]
interface IOrderTelemetry
{
// Methods can use one or more telemetry types
}v4 supports combining multiple telemetry attributes on a single method. When called, the method emits all specified telemetry types simultaneously:
[ActivitySource("OrderService")]
[Logger]
[Meter]
interface IOrderTelemetry
{
// MULTI-TARGET: Creates Activity + Logs Info + Increments Counter - all from one call!
[Activity]
[Info]
[AutoCounter]
Activity? ProcessingOrder([Baggage]int orderId, [Tag]string customerName);
// MULTI-TARGET: Adds ActivityEvent + Logs as Debug
[Event]
[Debug]
void OrderValidated(Activity? activity, decimal amount);
// SINGLE-TARGET: Only logs
[Warning]
void OrderRejected(int orderId, string reason);
// SINGLE-TARGET: Only metric
[Histogram]
void OrderProcessingDuration([InstrumentMeasurement]int milliseconds);
}Usage:
// Single method call emits 3 telemetry types!
using var activity = telemetry.ProcessingOrder(123, "Acme Corp");
// ✓ Activity created and started
// ✓ Info log entry written
// ✓ Counter incremented by 1| Combination | Supported | Example |
|---|---|---|
| Activity + Log | ✅ Yes |
[Activity] + [Info]
|
| Activity + Metric | ✅ Yes |
[Activity] + [AutoCounter]
|
| Log + Metric | ✅ Yes |
[Info] + [Histogram]
|
| Activity + Log + Metric | ✅ Yes |
[Activity] + [Info] + [AutoCounter]
|
| Event + Log | ✅ Yes |
[Event] + [Debug]
|
| Context + Log | ✅ Yes |
[Context] + [Trace]
|
Important Rules:
- Only one attribute per telemetry family is allowed per method
- Activities: Use ONE of
[Activity],[Event], or[Context] - Logging: Use ONE of
[Log],[Trace],[Debug],[Info],[Warning],[Error],[Critical] - Metrics: Use ONE of
[Counter],[AutoCounter],[Histogram],[UpDownCounter], or Observable variants
Invalid Examples:
// ERROR TSG1002: Multiple activity attributes
[Activity]
[Event]
void InvalidMethod(Activity? activity);
// ERROR TSG1002: Multiple logging attributes
[Info]
[Warning]
void InvalidMethod(string message);
// ERROR TSG1002: Multiple metric attributes
[Counter]
[Histogram]
void InvalidMethod([InstrumentMeasurement]int value);When using multi-target methods, you may want certain parameters to only apply to specific telemetry types. Use [ExcludeTargets] to control this:
using Purview.Telemetry;
[ActivitySource("PaymentService")]
[Logger]
[Meter]
interface IPaymentTelemetry
{
[Activity]
[Info]
[Counter]
Activity? ProcessingPayment(
[Baggage]Guid paymentId,
// Exclude verbose message from metrics (would be wasted as tag)
[ExcludeTargets(Targets.Metrics)]
string processingMessage,
// Measurement only applies to metrics
[InstrumentMeasurement]
decimal amount,
// Exclude internal details from Activity baggage
[ExcludeTargets(Targets.Activities)]
[Tag] // Still included in logs and metrics
string internalReference
);
}[Flags]
public enum Targets
{
Activities = 1,
Logging = 2,
Metrics = 4
}Usage:
// Exclude from multiple targets
[ExcludeTargets(Targets.Activities | Targets.Metrics)]
string loggingOnlyParameter
// Exclude from single target
[ExcludeTargets(Targets.Logging)]
int metricsAndActivityParameterWhen an interface has multiple class-level attributes ([ActivitySource], [Logger], [Meter]), inference is disabled. You must explicitly specify generation targets on each method.
[ActivitySource("MyApp")]
[Logger]
[Meter]
interface IMyTelemetry
{
// ERROR TSG1001: No explicit attribute
void ProcessItem(int id);
// ✅ CORRECT: Explicit attribute
[Info]
void ProcessItem(int id);
// ✅ CORRECT: Excluded from generation
[Exclude]
void ProcessItem(int id);
}If your interface has only ONE generation attribute, inference works normally:
// Single-target: Inference enabled
[Logger]
interface ILogOnlyTelemetry
{
// ✅ Inferred as [Info] because of Exception
void ProcessItem(int id, Exception ex);
// ✅ Inferred as scoped log (returns IDisposable)
IDisposable? ProcessingBatch(int batchId);
}When combining [Activity] with logs/metrics, return Activity?:
[Activity]
[Info]
[AutoCounter]
Activity? ProcessingOrder(int orderId); // ✅ Returns ActivityWhen combining logs and metrics without activities, return void or IDisposable?:
[Info]
[Histogram]
void RecordOperation([InstrumentMeasurement]int duration, string operation); // ✅ void
[Info]
[AutoCounter]
IDisposable? ProcessingBatch(int batchId); // ✅ Scoped log + counterEvents and Context methods with logs should return void:
[Event]
[Debug]
void OrderCompleted(Activity? activity, decimal total); // ✅ voidTrack everything about an operation:
[Activity] // Distributed tracing
[Info] // Structured logging
[AutoCounter] // Count occurrences
Activity? ProcessingRequest(
[Baggage]string requestId,
[Tag]string endpoint,
[Tag]string method
);Add activity events and log them:
[Event]
[Debug]
void StepCompleted(
Activity? activity,
[Tag]string stepName,
[Tag]int duration
);Log operations and track distributions:
[Info]
[Histogram]
void RequestCompleted(
[InstrumentMeasurement]int durationMs,
[Tag]string endpoint,
[Tag]int statusCode
);Use different parameters for different telemetry:
[Activity]
[Info]
[Counter]
Activity? ApiCall(
[Baggage]string traceId, // Activity baggage only
[ExcludeTargets(Targets.Metrics)]
string verboseMessage, // Activity + Log only
[InstrumentMeasurement]
[ExcludeTargets(Targets.Activities | Targets.Logging)]
int callCount, // Metrics only
[Tag]string endpoint // All three!
);- Less Code - One method definition generates multiple telemetry types
- Consistency - Same parameters used across telemetry types (when appropriate)
- Atomicity - All telemetry emitted together, no risk of forgetting one
- Maintainability - Change once, affects all telemetry types
- Performance - Single method call overhead instead of multiple
| Diagnostic | When | Resolution |
|---|---|---|
TSG1001 |
Method has no explicit attribute in multi-target interface | Add [Activity], [Info], [Counter], etc., or [Exclude]
|
TSG1002 |
Multiple attributes from same family | Use only one Activity, Logging, or Metrics attribute per method |
TSG1006 |
[ExcludeTargets] references missing target |
Remove [ExcludeTargets] or add the target attribute to the method |
TSG1007 |
[ExcludeTargets] results in invalid config |
Adjust exclusions to ensure valid parameters remain for each target |
- Activities - Activity generation details
- Logging - Logging generation details
- Metrics - Metrics generation details
- Getting Started - Multi-target examples
- Diagnostics - Error codes and resolutions
Important
Consider helping children around the world affected by conflict. You can donate any amount to War Child here - any amount can help save a life.
Purview Telemetry Source Generator v4.0.0-prerelease.1 | Home | Getting Started | FAQ | Breaking Changes | GitHub