Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Telemetry Schema Url in tracing and metrics #113034

Merged
merged 4 commits into from
Mar 4, 2025
Merged
Show file tree
Hide file tree
Changes from 2 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
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,10 @@ public sealed class ActivitySource : IDisposable
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public ActivitySource(string name, string? version = "") { throw null; }
public ActivitySource(string name, string? version = "", System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, object?>>? tags = default) { throw null; }
public ActivitySource(ActivitySourceOptions options) { throw null; }
public string Name { get { throw null; } }
public string? Version { get { throw null; } }
public string? TelemetrySchemaUrl { get; }
public System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, object?>>? Tags { get { throw null; } }
public bool HasListeners() { throw null; }
public System.Diagnostics.Activity? CreateActivity(string name, System.Diagnostics.ActivityKind kind) { throw null; }
Expand All @@ -169,6 +171,14 @@ public sealed class ActivitySource : IDisposable
public static void AddActivityListener(System.Diagnostics.ActivityListener listener) { throw null; }
public void Dispose() { throw null; }
}
public class ActivitySourceOptions
{
public ActivitySourceOptions(string name) { throw null; }
public string Name { get { throw null; } set { throw null; } }
public string? Version { get { throw null; } set { throw null; } }
public System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, object?>>? Tags { get { throw null; } set { throw null; } }
public string? TelemetrySchemaUrl { get { throw null; } set { throw null; } }
}
[System.FlagsAttribute]
public enum ActivityTraceFlags
{
Expand Down Expand Up @@ -565,6 +575,7 @@ public ObservableGauge<T> CreateObservableGauge<T>(
public string? Version { get { throw null; } }
public System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, object?>>? Tags { get { throw null; } }
public object? Scope { get { throw null; } }
public string? TelemetrySchemaUrl { get { throw null; } }
}
public static class MeterFactoryExtensions
{
Expand All @@ -588,6 +599,7 @@ public class MeterOptions
public string? Version { get { throw null;} set { throw null;} }
public System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string,object?>>? Tags { get { throw null;} set { throw null;} }
public object? Scope { get { throw null;} set { throw null;} }
public string? TelemetrySchemaUrl { get { throw null;} set { throw null;} }
public MeterOptions(string name) { throw null;}
}
public sealed class ObservableCounter<T> : ObservableInstrument<T> where T : struct
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ System.Diagnostics.DiagnosticSource</PackageDescription>
<Compile Include="System\Diagnostics\ActivityLink.cs" />
<Compile Include="System\Diagnostics\ActivityListener.cs" />
<Compile Include="System\Diagnostics\ActivitySource.cs" />
<Compile Include="System\Diagnostics\ActivitySourceOptions.cs" />
<Compile Include="System\Diagnostics\DiagnosticSource.cs" />
<Compile Include="System\Diagnostics\DiagnosticSourceActivity.cs" />
<Compile Include="System\Diagnostics\DiagnosticListener.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,35 @@ public sealed class ActivitySource : IDisposable
/// Construct an ActivitySource object with the input name
/// </summary>
/// <param name="name">The name of the ActivitySource object</param>
public ActivitySource(string name) : this(name, version: "", tags: null) {}
public ActivitySource(string name) : this(name, version: "", tags: null, telemetrySchemaUrl: null) {}

/// <summary>
/// Construct an ActivitySource object with the input name
/// </summary>
/// <param name="name">The name of the ActivitySource object</param>
/// <param name="version">The version of the component publishing the tracing info.</param>
[EditorBrowsable(EditorBrowsableState.Never)]
public ActivitySource(string name, string? version = "") : this(name, version, tags: null) {}
public ActivitySource(string name, string? version = "") : this(name, version, tags: null, telemetrySchemaUrl: null) {}

/// <summary>
/// Construct an ActivitySource object with the input name
/// </summary>
/// <param name="name">The name of the ActivitySource object</param>
/// <param name="version">The version of the component publishing the tracing info.</param>
/// <param name="tags">The optional ActivitySource tags.</param>
public ActivitySource(string name, string? version = "", IEnumerable<KeyValuePair<string, object?>>? tags = default)
public ActivitySource(string name, string? version = "", IEnumerable<KeyValuePair<string, object?>>? tags = default) : this(name, version, tags, telemetrySchemaUrl: null) {}

/// <summary>
/// Initialize a new instance of the ActivitySource object using the <see cref="ActivitySourceOptions" />.
/// </summary>
/// <param name="options">The <see cref="ActivitySourceOptions" /> object to use for initializing the ActivitySource object.</param>
public ActivitySource(ActivitySourceOptions options) : this(options?.Name ?? throw new ArgumentNullException(nameof(options)), options.Version, options.Tags, options.TelemetrySchemaUrl) {}

private ActivitySource(string name, string? version, IEnumerable<KeyValuePair<string, object?>>? tags, string? telemetrySchemaUrl)
{
Name = name ?? throw new ArgumentNullException(nameof(name));
Version = version;
TelemetrySchemaUrl = telemetrySchemaUrl;

// Sorting the tags to make sure the tags are always in the same order.
// Sorting can help in comparing the tags used for any scenario.
Expand Down Expand Up @@ -84,6 +93,11 @@ public ActivitySource(string name, string? version = "", IEnumerable<KeyValuePai
/// </summary>
public IEnumerable<KeyValuePair<string, object?>>? Tags { get; }

/// <summary>
/// Returns the telemetry schema URL associated with the ActivitySource.
/// </summary>
public string? TelemetrySchemaUrl { get; }

/// <summary>
/// Check if there is any listeners for this ActivitySource.
/// This property can be helpful to tell if there is no listener, then no need to create Activity object
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;

namespace System.Diagnostics
{
/// <summary>
/// Options for creating a <see cref="ActivitySource"/>.
/// </summary>
public class ActivitySourceOptions
{
private string _name;

/// <summary>
/// Constructs a new instance of <see cref="ActivitySourceOptions"/>.
/// </summary>
/// <param name="name">The name of the <see cref="ActivitySourceOptions"/> object</param>
public ActivitySourceOptions(string name)
{
_name = name ?? throw new ArgumentNullException(nameof(name));
}

/// <summary>
/// Get or set the <see cref="ActivitySourceOptions"/> object name. Cannot be null.
/// </summary>
public string Name
{
get => _name;
set
{
if (value is null)
{
throw new ArgumentNullException(nameof(value));
}

_name = value;
}
}

/// <summary>
/// The optional <see cref="ActivitySourceOptions"/> version. Defaulted to empty string.
/// </summary>
public string? Version { get; set; } = string.Empty;

/// <summary>
/// The optional list of key-value pair tags associated with the <see cref="ActivitySourceOptions"/>.
/// </summary>
public IEnumerable<KeyValuePair<string, object?>>? Tags { get; set; }

/// <summary>
/// The optional schema URL specifies a location of a <see href="https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/schemas/file_format_v1.1.0.md">Schema File</see> that
/// can be retrieved using HTTP or HTTPS protocol.
/// </summary>
public string? TelemetrySchemaUrl { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public Meter(MeterOptions options)

Debug.Assert(options.Name is not null);

Initialize(options.Name, options.Version, options.Tags, options.Scope);
Initialize(options.Name, options.Version, options.Tags, options.Scope, options.TelemetrySchemaUrl);

Debug.Assert(Name is not null);
}
Expand Down Expand Up @@ -71,11 +71,11 @@ public Meter(string name, string? version) : this(name, version, null, null) { }
/// </remarks>
public Meter(string name, string? version, IEnumerable<KeyValuePair<string, object?>>? tags, object? scope = null)
{
Initialize(name, version, tags, scope);
Initialize(name, version, tags, scope, telemetrySchemaUrl: null);
Debug.Assert(Name is not null);
}

private void Initialize(string name, string? version, IEnumerable<KeyValuePair<string, object?>>? tags, object? scope = null)
private void Initialize(string name, string? version, IEnumerable<KeyValuePair<string, object?>>? tags, object? scope = null, string? telemetrySchemaUrl = null)
{
Name = name ?? throw new ArgumentNullException(nameof(name));
Version = version;
Expand All @@ -86,6 +86,7 @@ private void Initialize(string name, string? version, IEnumerable<KeyValuePair<s
Tags = tagList.AsReadOnly();
}
Scope = scope;
TelemetrySchemaUrl = telemetrySchemaUrl;

if (!IsSupported)
{
Expand Down Expand Up @@ -121,6 +122,12 @@ private void Initialize(string name, string? version, IEnumerable<KeyValuePair<s
/// </summary>
public object? Scope { get; private set; }

/// <summary>
/// The optional schema URL specifies a location of a <see href="https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/schemas/file_format_v1.1.0.md">Schema File</see> that
/// can be retrieved using HTTP or HTTPS protocol.
/// </summary>
public string? TelemetrySchemaUrl { get; private set; }

/// <summary>
/// Create a metrics Counter object.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ public string Name
/// </summary>
public object? Scope { get; set; }

/// <summary>
/// The optional schema URL specifies a location of a <see href="https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/schemas/file_format_v1.1.0.md">Schema File</see> that
/// can be retrieved using HTTP or HTTPS protocol.
/// </summary>
public string? TelemetrySchemaUrl { get; set; }

/// <summary>
/// Constructs a new instance of <see cref="MeterOptions"/>.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ public void HistogramValuePublished(string sessionId, string meterName, string?
// Sent when we begin to monitor the value of a instrument, either because new session filter arguments changed subscriptions
// or because an instrument matching the pre-existing filter has just been created. This event precedes all *MetricPublished events
// for the same named instrument.
[Event(7, Keywords = Keywords.TimeSeriesValues, Version = 2)]
[Event(7, Keywords = Keywords.TimeSeriesValues, Version = 3)]
#if !NET8_0_OR_GREATER
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")]
Expand All @@ -169,15 +169,16 @@ public void BeginInstrumentReporting(
string instrumentTags,
string meterTags,
string meterScopeHash,
int instrumentId)
int instrumentId,
string? meterTelemetrySchemaUrl)
{
WriteEvent(7, sessionId, meterName, meterVersion ?? "", instrumentName, instrumentType, unit ?? "", description ?? "",
instrumentTags, meterTags, meterScopeHash, instrumentId);
instrumentTags, meterTags, meterScopeHash, instrumentId, meterTelemetrySchemaUrl);
}

// Sent when we stop monitoring the value of a instrument, either because new session filter arguments changed subscriptions
// or because the Meter has been disposed.
[Event(8, Keywords = Keywords.TimeSeriesValues, Version = 2)]
[Event(8, Keywords = Keywords.TimeSeriesValues, Version = 3)]
#if !NET8_0_OR_GREATER
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")]
Expand All @@ -193,10 +194,11 @@ public void EndInstrumentReporting(
string instrumentTags,
string meterTags,
string meterScopeHash,
int instrumentId)
int instrumentId,
string? meterTelemetrySchemaUrl)
{
WriteEvent(8, sessionId, meterName, meterVersion ?? "", instrumentName, instrumentType, unit ?? "", description ?? "",
instrumentTags, meterTags, meterScopeHash, instrumentId);
instrumentTags, meterTags, meterScopeHash, instrumentId, meterTelemetrySchemaUrl);
}

[Event(9, Keywords = Keywords.TimeSeriesValues | Keywords.Messages | Keywords.InstrumentPublishing)]
Expand All @@ -211,7 +213,7 @@ public void InitialInstrumentEnumerationComplete(string sessionId)
WriteEvent(10, sessionId);
}

[Event(11, Keywords = Keywords.InstrumentPublishing, Version = 2)]
[Event(11, Keywords = Keywords.InstrumentPublishing, Version = 3)]
#if !NET8_0_OR_GREATER
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")]
Expand All @@ -227,10 +229,11 @@ public void InstrumentPublished(
string instrumentTags,
string meterTags,
string meterScopeHash,
int instrumentId)
int instrumentId,
string? meterTelemetrySchemaUrl)
{
WriteEvent(11, sessionId, meterName, meterVersion ?? "", instrumentName, instrumentType, unit ?? "", description ?? "",
instrumentTags, meterTags, meterScopeHash, instrumentId);
instrumentTags, meterTags, meterScopeHash, instrumentId, meterTelemetrySchemaUrl);
}

[Event(12, Keywords = Keywords.TimeSeriesValues)]
Expand Down Expand Up @@ -463,11 +466,11 @@ public void OnEventCommand(EventCommandEventArgs command)
beginCollection: (startIntervalTime, endIntervalTime) => Parent.CollectionStart(sessionId, startIntervalTime, endIntervalTime),
endCollection: (startIntervalTime, endIntervalTime) => Parent.CollectionStop(sessionId, startIntervalTime, endIntervalTime),
beginInstrumentMeasurements: (i, state) => Parent.BeginInstrumentReporting(sessionId, i.Meter.Name, i.Meter.Version, i.Name, i.GetType().Name, i.Unit, i.Description,
Helpers.FormatTags(i.Tags), Helpers.FormatTags(i.Meter.Tags), Helpers.FormatObjectHash(i.Meter.Scope), state.ID),
Helpers.FormatTags(i.Tags), Helpers.FormatTags(i.Meter.Tags), Helpers.FormatObjectHash(i.Meter.Scope), state.ID, i.Meter.TelemetrySchemaUrl),
endInstrumentMeasurements: (i, state) => Parent.EndInstrumentReporting(sessionId, i.Meter.Name, i.Meter.Version, i.Name, i.GetType().Name, i.Unit, i.Description,
Helpers.FormatTags(i.Tags), Helpers.FormatTags(i.Meter.Tags), Helpers.FormatObjectHash(i.Meter.Scope), state.ID),
Helpers.FormatTags(i.Tags), Helpers.FormatTags(i.Meter.Tags), Helpers.FormatObjectHash(i.Meter.Scope), state.ID, i.Meter.TelemetrySchemaUrl),
instrumentPublished: (i, state) => Parent.InstrumentPublished(sessionId, i.Meter.Name, i.Meter.Version, i.Name, i.GetType().Name, i.Unit, i.Description,
Helpers.FormatTags(i.Tags), Helpers.FormatTags(i.Meter.Tags), Helpers.FormatObjectHash(i.Meter.Scope), state is null ? 0 : state.ID),
Helpers.FormatTags(i.Tags), Helpers.FormatTags(i.Meter.Tags), Helpers.FormatObjectHash(i.Meter.Scope), state is null ? 0 : state.ID, i.Meter.TelemetrySchemaUrl),
initialInstrumentEnumerationComplete: () => Parent.InitialInstrumentEnumerationComplete(sessionId),
collectionError: e => Parent.Error(sessionId, e.ToString()),
timeSeriesLimitReached: () => Parent.TimeSeriesLimitReached(sessionId),
Expand Down
Loading
Loading