Skip to content

Commit

Permalink
Update to latest (#4027)
Browse files Browse the repository at this point in the history
Co-authored-by: Martin Taillefer <[email protected]>
  • Loading branch information
geeknoid and Martin Taillefer authored Jun 2, 2023
1 parent 8967a24 commit 5881e19
Show file tree
Hide file tree
Showing 18 changed files with 575 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@
"Member": "static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder Microsoft.Extensions.Http.Telemetry.Metering.HttpClientMeteringExtensions.AddHttpClientMetering(this Microsoft.Extensions.DependencyInjection.IHttpClientBuilder builder);",
"Stage": "Stable"
},
{
"Member": "static Microsoft.Extensions.DependencyInjection.IServiceCollection Microsoft.Extensions.Http.Telemetry.Metering.HttpClientMeteringExtensions.AddHttpClientMeteringForAllHttpClients(this Microsoft.Extensions.DependencyInjection.IServiceCollection services);",
"Stage": "Experimental"
},
{
"Member": "static Microsoft.Extensions.DependencyInjection.IServiceCollection Microsoft.Extensions.Http.Telemetry.Metering.HttpClientMeteringExtensions.AddOutgoingRequestMetricEnricher<T>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services);",
"Stage": "Stable"
Expand Down Expand Up @@ -216,6 +220,33 @@
}
]
},
{
"Type": "enum Microsoft.Extensions.Http.Telemetry.Metering.HttpRequestResultType",
"Stage": "Experimental",
"Methods": [
{
"Member": "Microsoft.Extensions.Http.Telemetry.Metering.HttpRequestResultType.HttpRequestResultType();",
"Stage": "Experimental"
}
],
"Fields": [
{
"Member": "const Microsoft.Extensions.Http.Telemetry.Metering.HttpRequestResultType Microsoft.Extensions.Http.Telemetry.Metering.HttpRequestResultType.ExpectedFailure",
"Stage": "Experimental",
"Value": "2"
},
{
"Member": "const Microsoft.Extensions.Http.Telemetry.Metering.HttpRequestResultType Microsoft.Extensions.Http.Telemetry.Metering.HttpRequestResultType.Failure",
"Stage": "Experimental",
"Value": "1"
},
{
"Member": "const Microsoft.Extensions.Http.Telemetry.Metering.HttpRequestResultType Microsoft.Extensions.Http.Telemetry.Metering.HttpRequestResultType.Success",
"Stage": "Experimental",
"Value": "0"
}
]
},
{
"Type": "interface Microsoft.Extensions.Http.Telemetry.Logging.IHttpClientLogEnricher",
"Stage": "Stable",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics;

namespace Microsoft.Extensions.Telemetry.Metering;

Expand All @@ -28,6 +29,7 @@ namespace Microsoft.Extensions.Telemetry.Metering;
/// </code>
/// </example>
[AttributeUsage(AttributeTargets.Method)]
[Conditional("CODE_GENERATION_ATTRIBUTES")]
public sealed class CounterAttribute : Attribute
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics;

namespace Microsoft.Extensions.Telemetry.Metering;

Expand Down Expand Up @@ -34,6 +35,7 @@ namespace Microsoft.Extensions.Telemetry.Metering;
/// </code>
/// </example>
[AttributeUsage(AttributeTargets.Method)]
[Conditional("CODE_GENERATION_ATTRIBUTES")]
public sealed class CounterAttribute<T> : Attribute
where T : struct
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics;

namespace Microsoft.Extensions.Telemetry.Metering;

Expand All @@ -28,6 +29,7 @@ namespace Microsoft.Extensions.Telemetry.Metering;
/// </code>
/// </example>
[AttributeUsage(AttributeTargets.Method)]
[Conditional("CODE_GENERATION_ATTRIBUTES")]
public sealed class GaugeAttribute : Attribute
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics;

namespace Microsoft.Extensions.Telemetry.Metering;

Expand All @@ -28,6 +29,7 @@ namespace Microsoft.Extensions.Telemetry.Metering;
/// </code>
/// </example>
[AttributeUsage(AttributeTargets.Method)]
[Conditional("CODE_GENERATION_ATTRIBUTES")]
public sealed class HistogramAttribute : Attribute
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics;

namespace Microsoft.Extensions.Telemetry.Metering;

Expand Down Expand Up @@ -34,8 +34,8 @@ namespace Microsoft.Extensions.Telemetry.Metering;
/// }
/// </code>
/// </example>
[Experimental]
[AttributeUsage(AttributeTargets.Method)]
[Conditional("CODE_GENERATION_ATTRIBUTES")]
public sealed class HistogramAttribute<T> : Attribute
where T : struct
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,29 +225,29 @@
},
{
"Type": "sealed class Microsoft.Extensions.Telemetry.Metering.HistogramAttribute<T> : System.Attribute where T : struct",
"Stage": "Experimental",
"Stage": "Stable",
"Methods": [
{
"Member": "Microsoft.Extensions.Telemetry.Metering.HistogramAttribute<T>.HistogramAttribute(params string[] dimensions);",
"Stage": "Experimental"
"Stage": "Stable"
},
{
"Member": "Microsoft.Extensions.Telemetry.Metering.HistogramAttribute<T>.HistogramAttribute(System.Type type);",
"Stage": "Experimental"
"Stage": "Stable"
}
],
"Properties": [
{
"Member": "string[]? Microsoft.Extensions.Telemetry.Metering.HistogramAttribute<T>.Dimensions { get; }",
"Stage": "Experimental"
"Stage": "Stable"
},
{
"Member": "string? Microsoft.Extensions.Telemetry.Metering.HistogramAttribute<T>.Name { get; set; }",
"Stage": "Experimental"
"Stage": "Stable"
},
{
"Member": "System.Type? Microsoft.Extensions.Telemetry.Metering.HistogramAttribute<T>.Type { get; }",
"Stage": "Experimental"
"Stage": "Stable"
}
]
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Shared.Data.Validation;

namespace Microsoft.Extensions.Telemetry.Metering;
Expand Down Expand Up @@ -34,7 +35,6 @@ public class EventCountersCollectorOptions
/// Default set to an empty dictionary.
/// </remarks>
[Required]
[Microsoft.Shared.Data.Validation.Length(1)]
#pragma warning disable CA2227 // Collection properties should be read only
#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
public IDictionary<string, ISet<string>> Counters { get; set; }
Expand All @@ -51,6 +51,23 @@ public class EventCountersCollectorOptions
[TimeSpan("00:00:01", "00:10:00")]
public TimeSpan SamplingInterval { get; set; } = _defaultSamplingInterval;

/// <summary>
/// Gets or sets a value indicating whether to include recommended default counters.
/// </summary>
/// <remarks>
/// Includes the recommended default event counters in addition to the counters specified in <see cref="Counters"/>.
/// Default set to false. However, if <see cref="Counters"/> is empty, it is set to true so
/// default recommended counters are included when the listener is created.
/// Please see the list of recommended default counters in <see href="https://eng.ms/docs/experiences-devices/r9-sdk/docs/telemetry/metering/event-counters"/>.
/// EventSource: "System.Runtime", Counters:
/// - "cpu-usage", "working-set", "time-in-gc", "alloc-rate", "exception-count", "gen-2-gc-count", "gen-2-size",
/// - "monitor-lock-contention-count", "active-timer-count", "threadpool-queue-length", "threadpool-thread-count",
/// EventSource: "Microsoft-AspNetCore-Server-Kestrel", Counters:
/// - "connection-queue-length", "request-queue-length".
/// </remarks>
[Experimental]
public bool IncludeRecommendedDefault { get; set; }

#if NET5_0_OR_GREATER
/// <summary>
/// Gets or sets the interval at which to recycle the <see cref="EventCountersListener"/>.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Concurrent;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Diagnostics.Metrics;
Expand All @@ -22,10 +23,13 @@ namespace Microsoft.Extensions.Telemetry.Metering;
/// </summary>
internal sealed class EventCountersListener : EventListener
{
internal readonly ConcurrentDictionary<string, Counter<long>> CounterInstruments = new();
internal readonly ConcurrentDictionary<string, Histogram<long>> HistogramInstruments = new();
internal readonly FrozenDictionary<string, FrozenSet<string>> Counters;

private readonly bool _isInitialized;
private readonly Dictionary<string, string?> _eventSourceSettings;
private readonly Meter _meter;
private readonly FrozenDictionary<string, FrozenSet<string>> _counters;
private readonly ILogger<EventCountersListener> _logger;

/// <summary>
Expand All @@ -40,7 +44,7 @@ public EventCountersListener(
ILogger<EventCountersListener>? logger = null)
{
var value = Throw.IfMemberNull(options, options.Value);
_counters = CreateCountersDictionary(value.Counters);
Counters = CreateCountersDictionary(value);
_meter = meter;
_logger = logger ?? NullLoggerFactory.Instance.CreateLogger<EventCountersListener>();
_eventSourceSettings = new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase)
Expand Down Expand Up @@ -110,7 +114,7 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData)
return;
}

if (_counters.TryGetValue(eventData.EventSource.Name, out var counters))
if (Counters.TryGetValue(eventData.EventSource.Name, out var counters))
{
for (var i = 0; i < eventData.Payload.Count; ++i)
{
Expand Down Expand Up @@ -139,7 +143,7 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData)
continue;
}

if (!counters.Contains(name))
if (!counters.Contains("*") && !counters.Contains(name))
{
_logger.CounterNotEnabled(name, eventData.EventSource.Name, eventData.EventName);
continue;
Expand All @@ -162,11 +166,11 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData)
}
}

private static FrozenDictionary<string, FrozenSet<string>> CreateCountersDictionary(IDictionary<string, ISet<string>> counters)
private static FrozenDictionary<string, FrozenSet<string>> CreateCountersDictionary(EventCountersCollectorOptions options)
{
var d = new Dictionary<string, HashSet<string>>(StringComparer.OrdinalIgnoreCase);

foreach (var kvp in counters)
foreach (var kvp in options.Counters)
{
if (kvp.Value == null || kvp.Value.Count == 0)
{
Expand All @@ -176,8 +180,25 @@ private static FrozenDictionary<string, FrozenSet<string>> CreateCountersDiction
d.Add(kvp.Key, new HashSet<string>(kvp.Value, StringComparer.OrdinalIgnoreCase));
}

return d.Select(x => new KeyValuePair<string, FrozenSet<string>>(x.Key,
x.Value.ToFrozenSet(StringComparer.Ordinal, optimizeForReading: true))).ToFrozenDictionary(StringComparer.OrdinalIgnoreCase, optimizeForReading: true);
if (options.IncludeRecommendedDefault)
{
foreach (var kvp in Internal.Constants.DefaultCounters)
{
if (d.TryGetValue(kvp.Key, out var valueSet) && valueSet != null)
{
foreach (var kv in kvp.Value)
{
_ = valueSet.Add(kv);
}
}
else
{
d.Add(kvp.Key, new HashSet<string>(kvp.Value, StringComparer.OrdinalIgnoreCase));
}
}
}

return d.Select(x => new KeyValuePair<string, FrozenSet<string>>(x.Key, x.Value.ToFrozenSet(StringComparer.Ordinal))).ToFrozenDictionary(StringComparer.OrdinalIgnoreCase);
}

private bool TryConvertToLong(object? value, out long convertedValue)
Expand All @@ -204,7 +225,7 @@ private bool TryConvertToLong(object? value, out long convertedValue)

private void EnableIfNeeded(EventSource eventSource)
{
if (!_counters.ContainsKey(eventSource.Name))
if (!Counters.ContainsKey(eventSource.Name))
{
return;
}
Expand All @@ -222,8 +243,8 @@ private void RecordSumEvent(IDictionary<string, object> eventPayload, string cou

if (TryConvertToLong(payloadValue, out long metricValue))
{
var metric = _meter.CreateCounter<long>(counterName);
metric.Add(metricValue);
var counter = CounterInstruments.GetOrAdd(counterName, name => _meter.CreateCounter<long>(name));
counter.Add(metricValue);
}
}

Expand All @@ -236,8 +257,8 @@ private void RecordMeanEvent(IDictionary<string, object> eventPayload, string co

if (TryConvertToLong(payloadValue, out long metricValue))
{
var metric = _meter.CreateHistogram<long>(counterName);
metric.Record(metricValue);
var histogram = HistogramInstruments.GetOrAdd(counterName, name => _meter.CreateHistogram<long>(name));
histogram.Record(metricValue);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// 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 Microsoft.Extensions.Telemetry.Metering.Internal;

internal sealed class Constants
{
#pragma warning disable R9A044 // Assign array of literal values to a static field for improved performance
public static readonly Dictionary<string, HashSet<string>> DefaultCounters = new()
{
["System.Runtime"] = new HashSet<string>
{
"cpu-usage",
"working-set",
"time-in-gc",
"alloc-rate",
"exception-count",
"gen-2-gc-count",
"gen-2-size",
"monitor-lock-contention-count",
"active-timer-count",
"threadpool-queue-length",
"threadpool-thread-count"
},
["Microsoft-AspNetCore-Server-Kestrel"] = new HashSet<string>
{
"connection-queue-length",
"request-queue-length",
},
};
#pragma warning restore R9A044 // Assign array of literal values to a static field for improved performance
}
Loading

0 comments on commit 5881e19

Please sign in to comment.