From 57986a6842c220a1f59bd9fe28666bfd162c6ea7 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Thu, 1 Sep 2022 13:24:26 -0700 Subject: [PATCH 01/30] wip --- .../EventCounterListener.cs | 172 ++++----------- .../EventCounterMetricsOptions.cs | 19 ++ ...EventCountersInstrumentationEventSource.cs | 46 ---- .../MeterProviderBuilderExtensions.cs | 2 +- .../EventCounterListenerTests.cs | 197 ++++++++---------- .../MeterProviderBuilderExtensionsTests.cs | 33 --- .../TestEventCounter.cs | 44 ---- .../TestIncrementingEventCounter.cs | 39 ---- .../TestIncrementingPollingCounter.cs | 36 ---- .../TestPollingEventCounter.cs | 36 ---- 10 files changed, 148 insertions(+), 476 deletions(-) delete mode 100644 src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationEventSource.cs delete mode 100644 test/OpenTelemetry.Instrumentation.EventCounters.Tests/MeterProviderBuilderExtensionsTests.cs delete mode 100644 test/OpenTelemetry.Instrumentation.EventCounters.Tests/TestEventCounter.cs delete mode 100644 test/OpenTelemetry.Instrumentation.EventCounters.Tests/TestIncrementingEventCounter.cs delete mode 100644 test/OpenTelemetry.Instrumentation.EventCounters.Tests/TestIncrementingPollingCounter.cs delete mode 100644 test/OpenTelemetry.Instrumentation.EventCounters.Tests/TestPollingEventCounter.cs diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCounterListener.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCounterListener.cs index b8ee562d94..bd380d15f4 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCounterListener.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCounterListener.cs @@ -23,167 +23,71 @@ namespace OpenTelemetry.Instrumentation.EventCounters; +/// +/// .NET EventCounters Instrumentation. +/// internal class EventCounterListener : EventListener { internal static readonly AssemblyName AssemblyName = typeof(EventCounterListener).Assembly.GetName(); - internal static readonly string InstrumentationName = AssemblyName.Name; - internal static readonly string InstrumentationVersion = AssemblyName.Version.ToString(); + internal static readonly Meter MeterInstance = new(AssemblyName.Name, AssemblyName.Version.ToString()); - private readonly bool isInitialized = false; - private readonly Meter meter; + // TODO: make these static? private readonly EventCounterMetricsOptions options; - private readonly ConcurrentDictionary metricInstruments = new(); - private readonly ConcurrentDictionary lastValue = new(); - private readonly ConcurrentBag eventSources = new(); - + private readonly ConcurrentBag preInitEventSources = new(); + private readonly ConcurrentDictionary, Instrument> instruments = new(); + private readonly ConcurrentDictionary, double> values = new(); + + /// + /// Initializes a new instance of the class. + /// + /// The options to define the metrics. public EventCounterListener(EventCounterMetricsOptions options) { - this.meter = new Meter(InstrumentationName, InstrumentationVersion); - this.options = options ?? throw new ArgumentNullException(nameof(options)); - - this.isInitialized = true; - this.EnablePendingEventSources(); // Some OnEventSourceCreated may have fired before constructor, enable them - } - - private enum InstrumentType - { - ObservableGauge, - ObservableCounter, - } - - private Dictionary EnableEventArgs => new() { ["EventCounterIntervalSec"] = this.options.RefreshIntervalSecs.ToString(), }; + this.options = options; - protected override void OnEventSourceCreated(EventSource source) - { - // TODO: Add Configuration options to selectively subscribe to EventCounters - try + while (this.preInitEventSources.TryTake(out EventSource source)) { - if (!this.isInitialized) - { - this.eventSources.Add(source); - } - else + if (this.options.Sources.Contains(source.Name)) { - this.EnableEvents(source, EventLevel.Verbose, EventKeywords.All, this.EnableEventArgs); + this.EnableEvents(source, EventLevel.LogAlways, EventKeywords.None, this.options.EnableEventsArguments); } } - catch (Exception ex) - { - EventCountersInstrumentationEventSource.Log.ErrorEventCounter(source.Name, ex.Message); - } - } - - protected override void OnEventWritten(EventWrittenEventArgs eventData) - { - if (!eventData.EventName.Equals("EventCounters") || !this.isInitialized) - { - return; - } - try - { - if (eventData.Payload.Count > 0 && eventData.Payload[0] is IDictionary eventPayload) - { - this.ExtractAndPostMetric(eventData.EventSource.Name, eventPayload); - } - else - { - EventCountersInstrumentationEventSource.Log.IgnoreEventWrittenAsEventPayloadNotParseable(eventData.EventSource.Name); - } - } - catch (Exception ex) - { - EventCountersInstrumentationEventSource.Log.ErrorEventCounter(eventData.EventName, ex.ToString()); - } - } - - private void ExtractAndPostMetric(string eventSourceName, IDictionary eventPayload) - { - try - { - bool calculateRate = false; - double actualValue = 0; - - string counterName = string.Empty; - string counterDisplayName = string.Empty; - InstrumentType instrumentType = InstrumentType.ObservableGauge; - - foreach (KeyValuePair payload in eventPayload) - { - var key = payload.Key; - if (key.Equals("Name", StringComparison.OrdinalIgnoreCase)) - { - counterName = payload.Value.ToString(); - } - else - if (key.Equals("DisplayName", StringComparison.OrdinalIgnoreCase)) - { - counterDisplayName = payload.Value.ToString(); - } - else if (key.Equals("Mean", StringComparison.OrdinalIgnoreCase)) - { - instrumentType = InstrumentType.ObservableGauge; - actualValue = Convert.ToDouble(payload.Value); - } - else if (key.Equals("Increment", StringComparison.OrdinalIgnoreCase)) - { - // Increment indicates we have to calculate rate. - instrumentType = InstrumentType.ObservableCounter; - calculateRate = true; - actualValue = Convert.ToDouble(payload.Value); - } - } - - this.RecordMetric(eventSourceName, counterName, counterDisplayName, instrumentType, actualValue, calculateRate); - } - catch (Exception ex) - { - EventCountersInstrumentationEventSource.Log.EventCountersInstrumentationWarning("ExtractMetric", ex.Message); - } + this.preInitEventSources = null; } - private void RecordMetric(string eventSourceName, string counterName, string displayName, InstrumentType instrumentType, double value, bool calculateRate) + /// + protected override void OnEventSourceCreated(EventSource source) { - var metricKey = new MetricKey(eventSourceName, counterName); - var description = string.IsNullOrEmpty(displayName) ? counterName : displayName; - this.lastValue[metricKey] = calculateRate ? value / this.options.RefreshIntervalSecs : value; - switch (instrumentType) + if (this.preInitEventSources != null) { - case InstrumentType.ObservableCounter: - this.metricInstruments.TryAdd(metricKey, this.meter.CreateObservableCounter(counterName, () => this.ObserveDouble(metricKey), description: description)); - break; - - case InstrumentType.ObservableGauge: - this.metricInstruments.TryAdd(metricKey, this.meter.CreateObservableGauge(counterName, () => this.ObserveDouble(metricKey), description: description)); - break; + this.preInitEventSources.Add(source); } - } - - private double ObserveDouble(MetricKey key) => this.lastValue[key]; - - private void EnablePendingEventSources() - { - foreach (var source in this.eventSources) + else if (this.options.Sources.Contains(source.Name)) { - this.EnableEvents(source, EventLevel.Verbose, EventKeywords.All, this.EnableEventArgs); + this.EnableEvents(source, EventLevel.LogAlways, EventKeywords.None, this.options.EnableEventsArguments); } } - private class MetricKey + /// + protected override void OnEventWritten(EventWrittenEventArgs eventData) { - public MetricKey(string eventSourceName, string counterName) + if (this.preInitEventSources != null || !this.options.Names.Contains(eventData.EventName)) { - this.EventSourceName = eventSourceName; - this.CounterName = counterName; + return; } - public string EventSourceName { get; private set; } - - public string CounterName { get; private set; } + var payload = eventData.Payload[0] as IDictionary; + var name = payload["Name"].ToString(); + var isGauge = payload.ContainsKey("Mean"); + Tuple metricKey = new(eventData.EventSource.Name, name); - public override int GetHashCode() => (this.EventSourceName, this.CounterName).GetHashCode(); + this.values[metricKey] = isGauge + ? Convert.ToDouble(payload["Mean"]) + : Convert.ToDouble(payload["Increment"]) / this.options.RefreshIntervalSecs; - public override bool Equals(object obj) => - obj is MetricKey nextKey && this.EventSourceName == nextKey.EventSourceName && this.CounterName == nextKey.CounterName; + _ = this.instruments.TryAdd( + metricKey, + isGauge ? MeterInstance.CreateObservableGauge(name, () => this.values[metricKey]) : MeterInstance.CreateObservableCounter(name, () => this.values[metricKey])); } } diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCounterMetricsOptions.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCounterMetricsOptions.cs index 0152da017e..210884ec13 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCounterMetricsOptions.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCounterMetricsOptions.cs @@ -14,8 +14,12 @@ // limitations under the License. // +using System.Collections.Generic; + namespace OpenTelemetry.Instrumentation.EventCounters; +// TODO: rename EventCounterListenerOptions ?? + /// /// EventCounterMetrics Options. /// @@ -25,4 +29,19 @@ public class EventCounterMetricsOptions /// Gets or sets the subscription interval in seconds. /// public int RefreshIntervalSecs { get; set; } = 60; + + /// + /// Gets or sets the names of EventSources to listen to. + /// + public HashSet Sources { get; set; } = new(); + + /// + /// Gets or sets the name of EventCounters to listen to. + /// + public HashSet Names { get; set; } = new() { "EventCounters" }; + + /// + /// Gets the arguments object used for the EventListener.EnableEvents function. + /// + public Dictionary EnableEventsArguments => new() { { "EventCounterIntervalSec", this.RefreshIntervalSecs.ToString() } }; } diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationEventSource.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationEventSource.cs deleted file mode 100644 index f3d0d431ce..0000000000 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationEventSource.cs +++ /dev/null @@ -1,46 +0,0 @@ -// -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -using System.Diagnostics.Tracing; - -namespace OpenTelemetry.Instrumentation.EventCounters; - -/// -/// EventSource events emitted from the project. -/// -[EventSource(Name = "OpenTelemetry-Instrumentation-EventCounters")] -internal class EventCountersInstrumentationEventSource : EventSource -{ - public static readonly EventCountersInstrumentationEventSource Log = new(); - - [Event(1, Message = "Error occurred while processing eventCounter, EventCounter: {0}, Exception: {2}", Level = EventLevel.Error)] - public void ErrorEventCounter(string counterName, string exception) - { - this.WriteEvent(1, counterName, exception); - } - - [Event(2, Level = EventLevel.Warning, Message = @"Ignoring event written from EventSource: {0} as payload is not IDictionary to extract metrics.")] - public void IgnoreEventWrittenAsEventPayloadNotParseable(string eventSourceName) - { - this.WriteEvent(4, eventSourceName); - } - - [Event(3, Level = EventLevel.Warning, Message = @"EventCountersInstrumentation - {0} failed with exception: {1}.")] - public void EventCountersInstrumentationWarning(string stage, string exceptionMessage) - { - this.WriteEvent(8, stage, exceptionMessage); - } -} diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs index bb13a85281..e211512790 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs @@ -41,7 +41,7 @@ public static MeterProviderBuilder AddEventCounterMetrics( configure?.Invoke(options); var instrumentation = new EventCounterListener(options); - builder.AddMeter(EventCounterListener.InstrumentationName); + builder.AddMeter(EventCounterListener.MeterInstance.Name); return builder.AddInstrumentation(() => instrumentation); } } diff --git a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs index eab325222c..907fec0b50 100644 --- a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs +++ b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs @@ -15,6 +15,7 @@ // using System.Collections.Generic; +using System.Diagnostics.Tracing; using System.Threading.Tasks; using OpenTelemetry.Metrics; using Xunit; @@ -23,15 +24,15 @@ namespace OpenTelemetry.Instrumentation.EventCounters.Tests; public class EventCounterListenerTests { - private const int MaxTimeToAllowForFlush = 10000; - private MeterProvider meterProvider; + private const int Delay = 1200; [Fact] - public async Task SystemMetricsAreCaptured() + public async Task NoMetricsByDefault() { - var metricItems = new List(); + // Arrange + List metricItems = new(); - this.meterProvider = Sdk.CreateMeterProviderBuilder() + var meterProvider = Sdk.CreateMeterProviderBuilder() .AddEventCounterMetrics(options => { options.RefreshIntervalSecs = 1; @@ -39,161 +40,143 @@ public async Task SystemMetricsAreCaptured() .AddInMemoryExporter(metricItems) .Build(); - await Task.Delay(2000); - this.meterProvider.ForceFlush(MaxTimeToAllowForFlush); + metricItems.Clear(); - this.meterProvider.Dispose(); + // Act + await Task.Delay(Delay); + meterProvider.ForceFlush(); - Assert.True(metricItems.Count > 1); + // Assert + Assert.Empty(metricItems); } - [Fact(Skip = "Unstable")] - public async Task TestEventCounterMetricsAreCaptured() + [Fact] + public async Task EventCounter() { - const int refreshIntervalSeconds = 1; - var metricItems = new List(); - this.meterProvider = Sdk.CreateMeterProviderBuilder() + // Arrange + List metricItems = new(); + EventSource source = new("source-a"); + EventCounter counter = new("counter", source); + + var meterProvider = Sdk.CreateMeterProviderBuilder() .AddEventCounterMetrics(options => { options.RefreshIntervalSecs = 1; + options.Sources.Add(source.Name); }) .AddInMemoryExporter(metricItems) .Build(); - var expected = new[] { 100.3F, 200.1F }; - TestEventCounter.Log.SampleCounter1(expected[0]); - TestEventCounter.Log.SampleCounter2(expected[1]); - - // Wait a little bit over the refresh interval seconds - await Task.Delay((refreshIntervalSeconds * 1000) + 300); - - this.meterProvider.ForceFlush(MaxTimeToAllowForFlush); - this.meterProvider.Dispose(); + // Act + counter.WriteMetric(1997.0202); + await Task.Delay(Delay); + meterProvider.ForceFlush(); - var counter1 = metricItems.Find(m => m.Name == "mycountername1"); - var counter2 = metricItems.Find(m => m.Name == "mycountername2"); - Assert.NotNull(counter1); - Assert.NotNull(counter2); - Assert.Equal(MetricType.DoubleGauge, counter1.MetricType); // EventCounter CounterType is `Mean` - - Assert.Equal(expected[0], GetActualValue(counter1)); - Assert.Equal(expected[1], GetActualValue(counter2)); + // Assert + var metric = metricItems.Find(x => x.Name == "counter"); + Assert.NotNull(metric); + Assert.Equal(MetricType.DoubleGauge, metric.MetricType); + Assert.Equal(1997.0202, GetActualValue(metric)); } - [Fact(Skip = "Unstable")] - public async Task TestIncrementingEventCounterMetricsAreCaptured() + [Fact] + public async Task IncrementingEventCounter() { - const int refreshIntervalSeconds = 1; - var metricItems = new List(); - this.meterProvider = Sdk.CreateMeterProviderBuilder() + // Arrange + List metricItems = new(); + EventSource source = new("source-b"); + IncrementingEventCounter incCounter = new("inc-counter", source); + + var meterProvider = Sdk.CreateMeterProviderBuilder() .AddEventCounterMetrics(options => { options.RefreshIntervalSecs = 1; + options.Sources.Add(source.Name); }) .AddInMemoryExporter(metricItems) .Build(); - TestIncrementingEventCounter.Log.SampleCounter1(1); - TestIncrementingEventCounter.Log.SampleCounter1(1); - TestIncrementingEventCounter.Log.SampleCounter1(1); - - // Wait a little bit over the refresh interval seconds - await Task.Delay((refreshIntervalSeconds * 1000) + 300); - - this.meterProvider.ForceFlush(MaxTimeToAllowForFlush); - - this.meterProvider.Dispose(); - - var counter = metricItems.Find(m => m.Name == TestIncrementingEventCounter.CounterName); - Assert.NotNull(counter); - Assert.Equal(MetricType.DoubleSum, counter.MetricType); // EventCounter CounterType is `Sum` - Assert.Equal(3, GetActualValue(counter)); + // Act + incCounter.Increment(1); + incCounter.Increment(1); + incCounter.Increment(1); + await Task.Delay(Delay); + meterProvider.ForceFlush(); + + // Assert + var metric = metricItems.Find(x => x.Name == "inc-counter"); + Assert.NotNull(metric); + Assert.Equal(MetricType.DoubleSum, metric.MetricType); + Assert.Equal(3, GetActualValue(metric)); } - [Fact(Skip = "Unstable")] - public async Task TestPollingCounterMetricsAreCaptured() + [Fact] + public async Task PollingCounter() { - var metricItems = new List(); - const int refreshIntervalSeconds = 1; + // Arrange + int i = 0; + List metricItems = new(); + EventSource source = new("source-c"); + PollingCounter pollCounter = new("poll-counter", source, () => ++i * 10); - this.meterProvider = Sdk.CreateMeterProviderBuilder() + var meterProvider = Sdk.CreateMeterProviderBuilder() .AddEventCounterMetrics(options => { - options.RefreshIntervalSecs = refreshIntervalSeconds; + options.RefreshIntervalSecs = 1; + options.Sources.Add(source.Name); }) .AddInMemoryExporter(metricItems) .Build(); - int i = 0; - TestPollingEventCounter.CreateSingleton(() => ++i * 10); - - var duration = (refreshIntervalSeconds * 2 * 1000) + 300; // Wait for two refresh intervals to call the valueProvider twice - await Task.Delay(duration); + // Act + await Task.Delay(Delay * 2); + meterProvider.ForceFlush(); - this.meterProvider.ForceFlush(MaxTimeToAllowForFlush); - - this.meterProvider.Dispose(); - - var pollingCounter = metricItems.Find(m => m.Name == TestPollingEventCounter.CounterName); - Assert.NotNull(pollingCounter); - Assert.Equal(MetricType.DoubleGauge, pollingCounter.MetricType); // Polling Counter is EventCounter CounterType of `Mean` - - var expected = i * 10; // The last recorded `Mean` value - Assert.Equal(expected, GetActualValue(pollingCounter)); + // Assert + var metric = metricItems.Find(x => x.Name == "poll-counter"); + Assert.NotNull(metric); + Assert.Equal(MetricType.DoubleGauge, metric.MetricType); + Assert.Equal(20, GetActualValue(metric)); } - [Fact(Skip = "Unstable")] - public async Task TestIncrementingPollingCounterMetrics() + [Fact] + public async Task IncrementingPollingCounter() { - var metricItems = new List(); - const int refreshIntervalSeconds = 1; + // Arrange + int i = 1; + List metricItems = new(); + EventSource source = new("source-d"); + IncrementingPollingCounter incPollCounter = new("inc-poll-counter", source, () => i++); - this.meterProvider = Sdk.CreateMeterProviderBuilder() + var meterProvider = Sdk.CreateMeterProviderBuilder() .AddEventCounterMetrics(options => { - options.RefreshIntervalSecs = refreshIntervalSeconds; + options.RefreshIntervalSecs = 1; + options.Sources.Add(source.Name); }) .AddInMemoryExporter(metricItems) .Build(); - int i = 1; - - TestIncrementingPollingCounter.CreateSingleton(() => i++); + // Act + await Task.Delay(Delay * 2); + meterProvider.ForceFlush(); - var duration = (refreshIntervalSeconds * 2 * 1000) + 300; // Wait for two refresh intervals to call the valueProvider twice - await Task.Delay(duration); - - this.meterProvider.ForceFlush(MaxTimeToAllowForFlush); - - this.meterProvider.Dispose(); - - var pollingCounter = metricItems.Find(m => m.Name == TestIncrementingPollingCounter.CounterName); - Assert.NotNull(pollingCounter); - Assert.Equal(MetricType.DoubleSum, pollingCounter.MetricType); // Polling Counter is EventCounter CounterType of `Sum` - - Assert.Equal(1, GetActualValue(pollingCounter)); + // Assert + var metric = metricItems.Find(x => x.Name == "inc-poll-counter"); + Assert.NotNull(metric); + Assert.Equal(MetricType.DoubleSum, metric.MetricType); + Assert.Equal(1, GetActualValue(metric)); } - /// - /// Event Counters are always Sum or Mean and are always record with `float`. - /// - /// Metric to Aggregate. - /// The Aggregated value. private static double GetActualValue(Metric metric) { double sum = 0; foreach (ref readonly var metricPoint in metric.GetMetricPoints()) { - if (metric.MetricType.IsSum()) - { - sum += metricPoint.GetSumDouble(); - } - else - { - sum += metricPoint.GetGaugeLastValueDouble(); - } + sum += metric.MetricType.IsSum() + ? metricPoint.GetSumDouble() + : metricPoint.GetGaugeLastValueDouble(); } - return sum; } } diff --git a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/MeterProviderBuilderExtensionsTests.cs b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/MeterProviderBuilderExtensionsTests.cs deleted file mode 100644 index 22020300ed..0000000000 --- a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/MeterProviderBuilderExtensionsTests.cs +++ /dev/null @@ -1,33 +0,0 @@ -// -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -using System; -using OpenTelemetry.Metrics; -using Xunit; - -namespace OpenTelemetry.Instrumentation.EventCounters.Tests; - -public class MeterProviderBuilderExtensionsTests -{ - [Fact] - public void Throws_Exception_When_Builder_Is_Null() - { - MeterProviderBuilder builder = null; - - Func action = () => builder.AddEventCounterMetrics(); - Assert.Throws(action); - } -} diff --git a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/TestEventCounter.cs b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/TestEventCounter.cs deleted file mode 100644 index eeaac2b030..0000000000 --- a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/TestEventCounter.cs +++ /dev/null @@ -1,44 +0,0 @@ -// -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -using System.Diagnostics.Tracing; - -namespace OpenTelemetry.Instrumentation.EventCounters.Tests; - -[EventSource(Name = "OpenTelemetry.Instrumentation.EventCounters.Tests.TestEventCounter")] -public sealed class TestEventCounter : EventSource -{ - // define the singleton instance of the event source - public static TestEventCounter Log = new TestEventCounter(); - private EventCounter testCounter1; - private EventCounter testCounter2; - - private TestEventCounter() - { - this.testCounter1 = new EventCounter("mycountername1", this); - this.testCounter2 = new EventCounter("mycountername2", this); - } - - public void SampleCounter1(float counterValue) - { - this.testCounter1.WriteMetric(counterValue); - } - - public void SampleCounter2(float counterValue) - { - this.testCounter2.WriteMetric(counterValue); - } -} diff --git a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/TestIncrementingEventCounter.cs b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/TestIncrementingEventCounter.cs deleted file mode 100644 index 5cd33ba0bd..0000000000 --- a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/TestIncrementingEventCounter.cs +++ /dev/null @@ -1,39 +0,0 @@ -// -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -using System.Diagnostics.Tracing; - -namespace OpenTelemetry.Instrumentation.EventCounters.Tests; - -[EventSource(Name = "OpenTelemetry.Instrumentation.EventCounters.Tests.TestIncrementingEventCounter")] -public sealed class TestIncrementingEventCounter : EventSource -{ - public const string CounterName = "IncrementingEventCounter"; - - // define the singleton instance of the event source - public static TestIncrementingEventCounter Log = new(); - private IncrementingEventCounter incrementingEventCounter; - - private TestIncrementingEventCounter() - { - this.incrementingEventCounter = new IncrementingEventCounter(CounterName, this); - } - - public void SampleCounter1(float counterValue) - { - this.incrementingEventCounter.Increment(counterValue); - } -} diff --git a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/TestIncrementingPollingCounter.cs b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/TestIncrementingPollingCounter.cs deleted file mode 100644 index a60077519e..0000000000 --- a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/TestIncrementingPollingCounter.cs +++ /dev/null @@ -1,36 +0,0 @@ -// -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -using System; -using System.Diagnostics.Tracing; - -namespace OpenTelemetry.Instrumentation.EventCounters.Tests; - -[EventSource(Name = "OpenTelemetry.Instrumentation.EventCounters.Tests.TestPollingIncrementingEventCounter")] -public sealed class TestIncrementingPollingCounter : EventSource -{ - public const string CounterName = "TestIncrementingPollingCounter"; - - private IncrementingPollingCounter incrementingPollingCounter; - - private TestIncrementingPollingCounter(Func provider) - { - this.incrementingPollingCounter = new IncrementingPollingCounter(CounterName, this, provider); - } - - // define the singleton instance of the event source - public static TestIncrementingPollingCounter CreateSingleton(Func provider) => new(provider); -} diff --git a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/TestPollingEventCounter.cs b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/TestPollingEventCounter.cs deleted file mode 100644 index 12c9102e47..0000000000 --- a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/TestPollingEventCounter.cs +++ /dev/null @@ -1,36 +0,0 @@ -// -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -using System; -using System.Diagnostics.Tracing; - -namespace OpenTelemetry.Instrumentation.EventCounters.Tests; - -[EventSource(Name = "OpenTelemetry.Instrumentation.EventCounters.Tests.TestPollingEventCounter")] -public sealed class TestPollingEventCounter : EventSource -{ - public const string CounterName = "TestPollingCounter"; - - private PollingCounter pollingCounter; - - private TestPollingEventCounter(Func provider) - { - this.pollingCounter = new PollingCounter(CounterName, this, provider); - } - - // define the singleton instance of the event source - public static TestPollingEventCounter CreateSingleton(Func provider) => new(provider); -} From 51d9cce46c4045c95b9a96ed3b7bee7aca675ae3 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Thu, 1 Sep 2022 13:32:38 -0700 Subject: [PATCH 02/30] nit --- .../EventCounterListenerTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs index 907fec0b50..4868231ad4 100644 --- a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs +++ b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs @@ -171,12 +171,14 @@ public async Task IncrementingPollingCounter() private static double GetActualValue(Metric metric) { double sum = 0; + foreach (ref readonly var metricPoint in metric.GetMetricPoints()) { sum += metric.MetricType.IsSum() ? metricPoint.GetSumDouble() : metricPoint.GetGaugeLastValueDouble(); } + return sum; } } From 59e4faac51afc4dbfddd922444f3b204ea025d4d Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Thu, 1 Sep 2022 16:05:29 -0700 Subject: [PATCH 03/30] Rename options class --- .../EventCounterListener.cs | 4 ++-- ...ricsOptions.cs => EventCounterListenerOptions.cs} | 8 +++----- .../MeterProviderBuilderExtensions.cs | 8 ++++---- .../EventCounterListenerTests.cs | 12 +++++------- 4 files changed, 14 insertions(+), 18 deletions(-) rename src/OpenTelemetry.Instrumentation.EventCounters/{EventCounterMetricsOptions.cs => EventCounterListenerOptions.cs} (87%) diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCounterListener.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCounterListener.cs index bd380d15f4..01fe511b87 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCounterListener.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCounterListener.cs @@ -32,7 +32,7 @@ internal class EventCounterListener : EventListener internal static readonly Meter MeterInstance = new(AssemblyName.Name, AssemblyName.Version.ToString()); // TODO: make these static? - private readonly EventCounterMetricsOptions options; + private readonly EventCounterListenerOptions options; private readonly ConcurrentBag preInitEventSources = new(); private readonly ConcurrentDictionary, Instrument> instruments = new(); private readonly ConcurrentDictionary, double> values = new(); @@ -41,7 +41,7 @@ internal class EventCounterListener : EventListener /// Initializes a new instance of the class. /// /// The options to define the metrics. - public EventCounterListener(EventCounterMetricsOptions options) + public EventCounterListener(EventCounterListenerOptions options) { this.options = options; diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCounterMetricsOptions.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCounterListenerOptions.cs similarity index 87% rename from src/OpenTelemetry.Instrumentation.EventCounters/EventCounterMetricsOptions.cs rename to src/OpenTelemetry.Instrumentation.EventCounters/EventCounterListenerOptions.cs index 210884ec13..a25a80cb1b 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCounterMetricsOptions.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCounterListenerOptions.cs @@ -1,4 +1,4 @@ -// +// // Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,12 +18,10 @@ namespace OpenTelemetry.Instrumentation.EventCounters; -// TODO: rename EventCounterListenerOptions ?? - /// -/// EventCounterMetrics Options. +/// EventCounterListener Options. /// -public class EventCounterMetricsOptions +public class EventCounterListenerOptions { /// /// Gets or sets the subscription interval in seconds. diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs index e211512790..c9d7da7d87 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs @@ -31,17 +31,17 @@ public static class MeterProviderBuilderExtensions /// being configured. /// Runtime metrics options. /// The instance of to chain the calls. - public static MeterProviderBuilder AddEventCounterMetrics( + public static MeterProviderBuilder AddEventCounterListener( this MeterProviderBuilder builder, - Action configure = null) + Action configure = null) { Guard.ThrowIfNull(builder); - var options = new EventCounterMetricsOptions(); + var options = new EventCounterListenerOptions(); configure?.Invoke(options); var instrumentation = new EventCounterListener(options); - builder.AddMeter(EventCounterListener.MeterInstance.Name); + builder.AddMeter(options.MeterName); return builder.AddInstrumentation(() => instrumentation); } } diff --git a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs index 4868231ad4..fb959486fc 100644 --- a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs +++ b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs @@ -33,15 +33,13 @@ public async Task NoMetricsByDefault() List metricItems = new(); var meterProvider = Sdk.CreateMeterProviderBuilder() - .AddEventCounterMetrics(options => + .AddEventCounterListener(options => { options.RefreshIntervalSecs = 1; }) .AddInMemoryExporter(metricItems) .Build(); - metricItems.Clear(); - // Act await Task.Delay(Delay); meterProvider.ForceFlush(); @@ -59,7 +57,7 @@ public async Task EventCounter() EventCounter counter = new("counter", source); var meterProvider = Sdk.CreateMeterProviderBuilder() - .AddEventCounterMetrics(options => + .AddEventCounterListener(options => { options.RefreshIntervalSecs = 1; options.Sources.Add(source.Name); @@ -88,7 +86,7 @@ public async Task IncrementingEventCounter() IncrementingEventCounter incCounter = new("inc-counter", source); var meterProvider = Sdk.CreateMeterProviderBuilder() - .AddEventCounterMetrics(options => + .AddEventCounterListener(options => { options.RefreshIntervalSecs = 1; options.Sources.Add(source.Name); @@ -120,7 +118,7 @@ public async Task PollingCounter() PollingCounter pollCounter = new("poll-counter", source, () => ++i * 10); var meterProvider = Sdk.CreateMeterProviderBuilder() - .AddEventCounterMetrics(options => + .AddEventCounterListener(options => { options.RefreshIntervalSecs = 1; options.Sources.Add(source.Name); @@ -149,7 +147,7 @@ public async Task IncrementingPollingCounter() IncrementingPollingCounter incPollCounter = new("inc-poll-counter", source, () => i++); var meterProvider = Sdk.CreateMeterProviderBuilder() - .AddEventCounterMetrics(options => + .AddEventCounterListener(options => { options.RefreshIntervalSecs = 1; options.Sources.Add(source.Name); From 2e2af13767d0095ecaf114349000b585330793e9 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Thu, 1 Sep 2022 16:05:37 -0700 Subject: [PATCH 04/30] skip failing test --- .../EventCounterListenerTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs index fb959486fc..74eb4f3af5 100644 --- a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs +++ b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs @@ -26,7 +26,7 @@ public class EventCounterListenerTests { private const int Delay = 1200; - [Fact] + [Fact(Skip ="Other tests metrics are being exported here")] public async Task NoMetricsByDefault() { // Arrange From 8fbb35389eab9aa7ebf1e3832954cc678099b47f Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Thu, 1 Sep 2022 16:22:19 -0700 Subject: [PATCH 05/30] fix build error --- .../MeterProviderBuilderExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs index c9d7da7d87..8d87535247 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs @@ -41,7 +41,7 @@ public static MeterProviderBuilder AddEventCounterListener( configure?.Invoke(options); var instrumentation = new EventCounterListener(options); - builder.AddMeter(options.MeterName); + builder.AddMeter(EventCounterListener.MeterInstance.Name); return builder.AddInstrumentation(() => instrumentation); } } From e13c37f6965cf8919227eece50f8f41cc0813576 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Thu, 1 Sep 2022 16:26:51 -0700 Subject: [PATCH 06/30] whitespacing --- .../EventCounterListenerTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs index 74eb4f3af5..70313696be 100644 --- a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs +++ b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs @@ -26,7 +26,7 @@ public class EventCounterListenerTests { private const int Delay = 1200; - [Fact(Skip ="Other tests metrics are being exported here")] + [Fact(Skip = "Other tests metrics are being exported here")] public async Task NoMetricsByDefault() { // Arrange From 3eb1061489883a219860d5433f18071b6bc0631c Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 6 Sep 2022 10:57:59 -0700 Subject: [PATCH 07/30] Update EventCounterListenerTests.cs --- .../EventCounterListenerTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs index 70313696be..d2c7cad251 100644 --- a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs +++ b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs @@ -24,7 +24,7 @@ namespace OpenTelemetry.Instrumentation.EventCounters.Tests; public class EventCounterListenerTests { - private const int Delay = 1200; + private const int Delay = 1400; [Fact(Skip = "Other tests metrics are being exported here")] public async Task NoMetricsByDefault() From 97ed7270b755aaf2d734cc24f7ce3b525c604fe7 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 6 Sep 2022 12:14:12 -0700 Subject: [PATCH 08/30] Add changelog, owner --- .github/component_owners.yml | 2 ++ .../CHANGELOG.md | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/.github/component_owners.yml b/.github/component_owners.yml index 57fe851901..8bec8de3df 100644 --- a/.github/component_owners.yml +++ b/.github/component_owners.yml @@ -37,6 +37,7 @@ components: - ejsmith src/OpenTelemetry.Instrumentation.EventCounters/: - hananiel + - mic-max src/OpenTelemetry.Instrumentation.GrpcCore/: - pcwiese src/OpenTelemetry.Instrumentation.Hangfire/: @@ -99,6 +100,7 @@ components: - ejsmith test/OpenTelemetry.Instrumentation.EventCounters.Tests/: - hananiel + - mic-max test/OpenTelemetry.Instrumentation.GrpcCore.Tests/: - pcwiese test/OpenTelemetry.Instrumentation.Hangfire.Tests/: diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/CHANGELOG.md b/src/OpenTelemetry.Instrumentation.EventCounters/CHANGELOG.md index 85f97c807a..165812f4e6 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/CHANGELOG.md +++ b/src/OpenTelemetry.Instrumentation.EventCounters/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +* Simplified implementation. EventSources must be explicitly configured to be + listened to now. + ([#620](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/620)) + ## 0.1.0-alpha.1 Released 2022-Jul-12 From 732bc59ca5f38587f91eee060cf66ddcedb4c873 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 6 Sep 2022 12:29:45 -0700 Subject: [PATCH 09/30] clean --- .../EventCounterListener.cs | 7 ++----- .../EventCounterListenerTests.cs | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCounterListener.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCounterListener.cs index 01fe511b87..d1029b71a7 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCounterListener.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCounterListener.cs @@ -31,7 +31,6 @@ internal class EventCounterListener : EventListener internal static readonly AssemblyName AssemblyName = typeof(EventCounterListener).Assembly.GetName(); internal static readonly Meter MeterInstance = new(AssemblyName.Name, AssemblyName.Version.ToString()); - // TODO: make these static? private readonly EventCounterListenerOptions options; private readonly ConcurrentBag preInitEventSources = new(); private readonly ConcurrentDictionary, Instrument> instruments = new(); @@ -52,14 +51,12 @@ public EventCounterListener(EventCounterListenerOptions options) this.EnableEvents(source, EventLevel.LogAlways, EventKeywords.None, this.options.EnableEventsArguments); } } - - this.preInitEventSources = null; } /// protected override void OnEventSourceCreated(EventSource source) { - if (this.preInitEventSources != null) + if (this.options == null) { this.preInitEventSources.Add(source); } @@ -72,7 +69,7 @@ protected override void OnEventSourceCreated(EventSource source) /// protected override void OnEventWritten(EventWrittenEventArgs eventData) { - if (this.preInitEventSources != null || !this.options.Names.Contains(eventData.EventName)) + if (this.options == null || !this.options.Names.Contains(eventData.EventName)) { return; } diff --git a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs index d2c7cad251..70313696be 100644 --- a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs +++ b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs @@ -24,7 +24,7 @@ namespace OpenTelemetry.Instrumentation.EventCounters.Tests; public class EventCounterListenerTests { - private const int Delay = 1400; + private const int Delay = 1200; [Fact(Skip = "Other tests metrics are being exported here")] public async Task NoMetricsByDefault() From a1566d1c5b7f2a8174196a14e4492fc9f601593d Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 6 Sep 2022 12:49:01 -0700 Subject: [PATCH 10/30] readme fixup --- .../README.md | 86 ++++++++++--------- 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/README.md b/src/OpenTelemetry.Instrumentation.EventCounters/README.md index 7ddad17e82..1fdd9cd299 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/README.md +++ b/src/OpenTelemetry.Instrumentation.EventCounters/README.md @@ -1,7 +1,11 @@ -# Event counter instrumentation for OpenTelemetry +# Event Counters Instrumentation for OpenTelemetry .NET -This is an [Instrumentation Library](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/glossary.md#instrumentation-library), -which republishes EventCounters using Metrics Api. +[![NuGet](https://img.shields.io/nuget/v/OpenTelemetry.Instrumentation.EventCounters.svg)](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.EventCounters) +[![NuGet](https://img.shields.io/nuget/dt/OpenTelemetry.Instrumentation.EventCounters.svg)](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.EventCounters) + +This is an +[Instrumentation Library](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/glossary.md#instrumentation-library) +, which **republishes EventCounters using Metrics Api.** ## Steps to enable OpenTelemetry.Instrumentation.EventCounters @@ -9,62 +13,62 @@ which republishes EventCounters using Metrics Api. Add a reference to the [`OpenTelemetry.Instrumentation.EventCounters`](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.EventCounters) -package. Also, add any other instrumentation & exporters you will need. +package. ```shell dotnet add package OpenTelemetry.Instrumentation.EventCounters ``` -### Step 2: Enable EventCounters Instrumentation at application startup - -EventCounters instrumentation must be enabled at application startup. +### Step 2: Enable EventCounters Instrumentation -The following example demonstrates adding EventCounter events to a -console application. This example also sets up the OpenTelemetry Console -exporter, which requires adding the package -[`OpenTelemetry.Exporter.Console`](https://www.nuget.org/packages/OpenTelemetry.Exporter.Console) -to the application. +EventCounters instrumentation should be enabled at application startup using the +`AddEventCounterListener` extension on the `MeterProviderBuilder`: ```csharp -using OpenTelemetry; -using OpenTelemetry.Metrics; - -namespace DotnetMetrics; - -public class Program -{ - public static void Main(string[] args) - { - using var meterprovider = Sdk.CreateMeterProviderBuilder() - .AddEventCounterMetrics(options => - { - options.RefreshIntervalSecs = 5; - }) - .AddConsoleExporter() - .Build(); - } +using var meterProvider = Sdk.CreateMeterProviderBuilder() + .AddEventCounterListener(options => { + options.RefreshIntervalSecs = 1; + options.Sources.Add("MyEventSourceName"); + }) + .AddPrometheusExporter() + .Build(); } ``` -Console Output: - -```console +Additionally, this examples sets up the OpenTelemetry Prometheus exporter, which +requires adding the package +[`OpenTelemetry.Exporter.Prometheus`](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md) +to the application. -Export cpu-usage, CPU Usage, Meter: OpenTelemetry.Instrumentation.EventCounters/0.0.0.0 -(2022-07-12T16:40:37.2639447Z, 2022-07-12T16:40:42.2533747Z] DoubleGauge -Value: 0 +### Step 3: Create EventCounters -Export working-set, Working Set, Meter: OpenTelemetry.Instrumentation.EventCounters/0.0.0.0 -(2022-07-12T16:40:37.2666398Z, 2022-07-12T16:40:42.2534452Z] DoubleGauge -Value: 38 +Learn about +[EventCounters in .NET](https://docs.microsoft.com/en-us/dotnet/core/diagnostics/event-counters) +. -Export gc-heap-size, GC Heap Size, Meter: OpenTelemetry.Instrumentation.EventCounters/0.0.0.0 -(2022-07-12T16:40:37.2667389Z, 2022-07-12T16:40:42.2534456Z] DoubleGauge -Value: 7 +```csharp +EventSource eventSource = new("MyEventSource"); +EventCounter eventCounter = new("MyEventCounterName", eventSource); +eventCounter.WriteMetric(0); +eventCounter.WriteMetric(1000); +PollingCounter pollingCounter = new("MyPollingCounterName", eventSource, () => new Random().NextDouble()); ``` +There are some +[Well-known EventCounters in .NET](https://docs.microsoft.com/en-us/dotnet/core/diagnostics/available-counters) +that are filtered out by this library. +For these counters, use either the `OpenTelemetry.Instrumentation.Process` or +`OpenTelemetry.Instrumentation.Runtime` instrumentation libraries. + +## Notes + +The metrics will only be available after `EventCounterIntervalSec` seconds. +Before that nothing will be exported, if anything is present at the Prometheus +metrics endpoint it is from a prior execution. This is more evident when using +longer polling intervals. + ## References * [OpenTelemetry Project](https://opentelemetry.io/) From 60938d3f2eaf71bbf3c799b99150770c92d2baef Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 6 Sep 2022 15:45:08 -0700 Subject: [PATCH 11/30] use same naming scheme as other instrumentations --- ...ons.cs => EventCountersInstrumentationOptions.cs} | 4 ++-- ...entCounterListener.cs => EventCountersMetrics.cs} | 12 ++++++------ .../MeterProviderBuilderExtensions.cs | 2 +- .../README.md | 4 ++-- .../EventCounterListenerTests.cs | 10 +++++----- 5 files changed, 16 insertions(+), 16 deletions(-) rename src/OpenTelemetry.Instrumentation.EventCounters/{EventCounterListenerOptions.cs => EventCountersInstrumentationOptions.cs} (91%) rename src/OpenTelemetry.Instrumentation.EventCounters/{EventCounterListener.cs => EventCountersMetrics.cs} (90%) diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCounterListenerOptions.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs similarity index 91% rename from src/OpenTelemetry.Instrumentation.EventCounters/EventCounterListenerOptions.cs rename to src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs index a25a80cb1b..18fd5d73ba 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCounterListenerOptions.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs @@ -1,4 +1,4 @@ -// +// // Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ namespace OpenTelemetry.Instrumentation.EventCounters; /// /// EventCounterListener Options. /// -public class EventCounterListenerOptions +public class EventCountersInstrumentationOptions { /// /// Gets or sets the subscription interval in seconds. diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCounterListener.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs similarity index 90% rename from src/OpenTelemetry.Instrumentation.EventCounters/EventCounterListener.cs rename to src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs index d1029b71a7..3e98e50ea0 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCounterListener.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs @@ -1,4 +1,4 @@ -// +// // Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,21 +26,21 @@ namespace OpenTelemetry.Instrumentation.EventCounters; /// /// .NET EventCounters Instrumentation. /// -internal class EventCounterListener : EventListener +internal class EventCountersMetrics : EventListener { - internal static readonly AssemblyName AssemblyName = typeof(EventCounterListener).Assembly.GetName(); + internal static readonly AssemblyName AssemblyName = typeof(EventCountersMetrics).Assembly.GetName(); internal static readonly Meter MeterInstance = new(AssemblyName.Name, AssemblyName.Version.ToString()); - private readonly EventCounterListenerOptions options; + private readonly EventCountersInstrumentationOptions options; private readonly ConcurrentBag preInitEventSources = new(); private readonly ConcurrentDictionary, Instrument> instruments = new(); private readonly ConcurrentDictionary, double> values = new(); /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The options to define the metrics. - public EventCounterListener(EventCounterListenerOptions options) + public EventCountersMetrics(EventCountersInstrumentationOptions options) { this.options = options; diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs index 8d87535247..f7dc055a0b 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs @@ -31,7 +31,7 @@ public static class MeterProviderBuilderExtensions /// being configured. /// Runtime metrics options. /// The instance of to chain the calls. - public static MeterProviderBuilder AddEventCounterListener( + public static MeterProviderBuilder AddEventCountersInstrumentation( this MeterProviderBuilder builder, Action configure = null) { diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/README.md b/src/OpenTelemetry.Instrumentation.EventCounters/README.md index 1fdd9cd299..e97c5a7713 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/README.md +++ b/src/OpenTelemetry.Instrumentation.EventCounters/README.md @@ -22,11 +22,11 @@ dotnet add package OpenTelemetry.Instrumentation.EventCounters ### Step 2: Enable EventCounters Instrumentation EventCounters instrumentation should be enabled at application startup using the -`AddEventCounterListener` extension on the `MeterProviderBuilder`: +`AddEventCountersInstrumentation` extension on the `MeterProviderBuilder`: ```csharp using var meterProvider = Sdk.CreateMeterProviderBuilder() - .AddEventCounterListener(options => { + .AddEventCountersInstrumentation(options => { options.RefreshIntervalSecs = 1; options.Sources.Add("MyEventSourceName"); }) diff --git a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs index 70313696be..72c575f19e 100644 --- a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs +++ b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs @@ -33,7 +33,7 @@ public async Task NoMetricsByDefault() List metricItems = new(); var meterProvider = Sdk.CreateMeterProviderBuilder() - .AddEventCounterListener(options => + .AddEventCountersInstrumentation(options => { options.RefreshIntervalSecs = 1; }) @@ -57,7 +57,7 @@ public async Task EventCounter() EventCounter counter = new("counter", source); var meterProvider = Sdk.CreateMeterProviderBuilder() - .AddEventCounterListener(options => + .AddEventCountersInstrumentation(options => { options.RefreshIntervalSecs = 1; options.Sources.Add(source.Name); @@ -86,7 +86,7 @@ public async Task IncrementingEventCounter() IncrementingEventCounter incCounter = new("inc-counter", source); var meterProvider = Sdk.CreateMeterProviderBuilder() - .AddEventCounterListener(options => + .AddEventCountersInstrumentation(options => { options.RefreshIntervalSecs = 1; options.Sources.Add(source.Name); @@ -118,7 +118,7 @@ public async Task PollingCounter() PollingCounter pollCounter = new("poll-counter", source, () => ++i * 10); var meterProvider = Sdk.CreateMeterProviderBuilder() - .AddEventCounterListener(options => + .AddEventCountersInstrumentation(options => { options.RefreshIntervalSecs = 1; options.Sources.Add(source.Name); @@ -147,7 +147,7 @@ public async Task IncrementingPollingCounter() IncrementingPollingCounter incPollCounter = new("inc-poll-counter", source, () => i++); var meterProvider = Sdk.CreateMeterProviderBuilder() - .AddEventCounterListener(options => + .AddEventCountersInstrumentation(options => { options.RefreshIntervalSecs = 1; options.Sources.Add(source.Name); From 37414cace341d1ab2406c658328459d53671d6d3 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 7 Sep 2022 10:02:35 -0700 Subject: [PATCH 12/30] Update MeterProviderBuilderExtensions.cs --- .../MeterProviderBuilderExtensions.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs index f7dc055a0b..daf35c18ef 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs @@ -33,15 +33,15 @@ public static class MeterProviderBuilderExtensions /// The instance of to chain the calls. public static MeterProviderBuilder AddEventCountersInstrumentation( this MeterProviderBuilder builder, - Action configure = null) + Action configure = null) { Guard.ThrowIfNull(builder); - var options = new EventCounterListenerOptions(); + var options = new EventCountersInstrumentationOptions(); configure?.Invoke(options); - var instrumentation = new EventCounterListener(options); - builder.AddMeter(EventCounterListener.MeterInstance.Name); + var instrumentation = new EventCountersMetrics(options); + builder.AddMeter(EventCountersMetrics.MeterInstance.Name); return builder.AddInstrumentation(() => instrumentation); } } From 1a0c496bd8dcc95b3ed9771752bb1ba6da522ad3 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 13 Sep 2022 09:21:10 -0700 Subject: [PATCH 13/30] Set default polling time to 1 second --- .../EventCountersInstrumentationOptions.cs | 2 +- .../EventCounterListenerTests.cs | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs index 18fd5d73ba..0a9e0fd2b0 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs @@ -26,7 +26,7 @@ public class EventCountersInstrumentationOptions /// /// Gets or sets the subscription interval in seconds. /// - public int RefreshIntervalSecs { get; set; } = 60; + public int RefreshIntervalSecs { get; set; } = 1; /// /// Gets or sets the names of EventSources to listen to. diff --git a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs index 72c575f19e..3f1216b57f 100644 --- a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs +++ b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs @@ -33,10 +33,7 @@ public async Task NoMetricsByDefault() List metricItems = new(); var meterProvider = Sdk.CreateMeterProviderBuilder() - .AddEventCountersInstrumentation(options => - { - options.RefreshIntervalSecs = 1; - }) + .AddEventCountersInstrumentation() .AddInMemoryExporter(metricItems) .Build(); @@ -59,7 +56,6 @@ public async Task EventCounter() var meterProvider = Sdk.CreateMeterProviderBuilder() .AddEventCountersInstrumentation(options => { - options.RefreshIntervalSecs = 1; options.Sources.Add(source.Name); }) .AddInMemoryExporter(metricItems) @@ -88,7 +84,6 @@ public async Task IncrementingEventCounter() var meterProvider = Sdk.CreateMeterProviderBuilder() .AddEventCountersInstrumentation(options => { - options.RefreshIntervalSecs = 1; options.Sources.Add(source.Name); }) .AddInMemoryExporter(metricItems) @@ -120,7 +115,6 @@ public async Task PollingCounter() var meterProvider = Sdk.CreateMeterProviderBuilder() .AddEventCountersInstrumentation(options => { - options.RefreshIntervalSecs = 1; options.Sources.Add(source.Name); }) .AddInMemoryExporter(metricItems) @@ -149,7 +143,6 @@ public async Task IncrementingPollingCounter() var meterProvider = Sdk.CreateMeterProviderBuilder() .AddEventCountersInstrumentation(options => { - options.RefreshIntervalSecs = 1; options.Sources.Add(source.Name); }) .AddInMemoryExporter(metricItems) From 906b84c9114780dd8bc1af45e0c20a19acbf43e7 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 13 Sep 2022 09:24:53 -0700 Subject: [PATCH 14/30] Update README.md --- src/OpenTelemetry.Instrumentation.EventCounters/README.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/README.md b/src/OpenTelemetry.Instrumentation.EventCounters/README.md index e97c5a7713..059f79cc32 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/README.md +++ b/src/OpenTelemetry.Instrumentation.EventCounters/README.md @@ -56,12 +56,6 @@ eventCounter.WriteMetric(1000); PollingCounter pollingCounter = new("MyPollingCounterName", eventSource, () => new Random().NextDouble()); ``` -There are some -[Well-known EventCounters in .NET](https://docs.microsoft.com/en-us/dotnet/core/diagnostics/available-counters) -that are filtered out by this library. -For these counters, use either the `OpenTelemetry.Instrumentation.Process` or -`OpenTelemetry.Instrumentation.Runtime` instrumentation libraries. - ## Notes The metrics will only be available after `EventCounterIntervalSec` seconds. From d5c7fdfd43dcb40417a68c73342ae24a3e8b4ee2 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 13 Sep 2022 11:37:55 -0700 Subject: [PATCH 15/30] AddCounters and ShouldListenTo methods --- .../EventCountersInstrumentationOptions.cs | 23 ++++++++++++++----- .../EventCountersMetrics.cs | 14 ++++++++--- .../EventCounterListenerTests.cs | 8 +++---- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs index 0a9e0fd2b0..d2b176b3cc 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs @@ -23,23 +23,34 @@ namespace OpenTelemetry.Instrumentation.EventCounters; /// public class EventCountersInstrumentationOptions { + private readonly HashSet eventSourceNames = new(); + /// /// Gets or sets the subscription interval in seconds. /// public int RefreshIntervalSecs { get; set; } = 1; /// - /// Gets or sets the names of EventSources to listen to. + /// Gets the arguments object used for the EventListener.EnableEvents function. /// - public HashSet Sources { get; set; } = new(); + public Dictionary EnableEventsArguments => new() { { "EventCounterIntervalSec", this.RefreshIntervalSecs.ToString() } }; /// - /// Gets or sets the name of EventCounters to listen to. + /// Listens to EventCounters from the given EventSource name. /// - public HashSet Names { get; set; } = new() { "EventCounters" }; + /// The EventSource name. + public void AddCounters(string eventSourceName) + { + this.eventSourceNames.Add(eventSourceName); + } /// - /// Gets the arguments object used for the EventListener.EnableEvents function. + /// Returns whether or not an EventSource should be enabled on the EventListener. /// - public Dictionary EnableEventsArguments => new() { { "EventCounterIntervalSec", this.RefreshIntervalSecs.ToString() } }; + /// The EventSource name. + /// true when an EventSource with the name should be enabled. + public bool ShouldListenToSource(string eventSourceName) + { + return this.eventSourceNames.Contains(eventSourceName); + } } diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs index 3e98e50ea0..2f7c9692bc 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs @@ -46,7 +46,7 @@ public EventCountersMetrics(EventCountersInstrumentationOptions options) while (this.preInitEventSources.TryTake(out EventSource source)) { - if (this.options.Sources.Contains(source.Name)) + if (this.options.ShouldListenToSource(source.Name)) { this.EnableEvents(source, EventLevel.LogAlways, EventKeywords.None, this.options.EnableEventsArguments); } @@ -60,7 +60,7 @@ protected override void OnEventSourceCreated(EventSource source) { this.preInitEventSources.Add(source); } - else if (this.options.Sources.Contains(source.Name)) + else if (this.options.ShouldListenToSource(source.Name)) { this.EnableEvents(source, EventLevel.LogAlways, EventKeywords.None, this.options.EnableEventsArguments); } @@ -69,7 +69,7 @@ protected override void OnEventSourceCreated(EventSource source) /// protected override void OnEventWritten(EventWrittenEventArgs eventData) { - if (this.options == null || !this.options.Names.Contains(eventData.EventName)) + if (this.options == null) { return; } @@ -79,6 +79,14 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData) var isGauge = payload.ContainsKey("Mean"); Tuple metricKey = new(eventData.EventSource.Name, name); + /*if (isGauge) + { + this.values[metricKey] = Convert.ToDouble(payload["Mean"]); + } + else + { + this.values[metricKey] += Convert.ToDouble(payload["Increment"]) / this.options.RefreshIntervalSecs; + }*/ this.values[metricKey] = isGauge ? Convert.ToDouble(payload["Mean"]) : Convert.ToDouble(payload["Increment"]) / this.options.RefreshIntervalSecs; diff --git a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs index 3f1216b57f..ca70bb47d7 100644 --- a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs +++ b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs @@ -56,7 +56,7 @@ public async Task EventCounter() var meterProvider = Sdk.CreateMeterProviderBuilder() .AddEventCountersInstrumentation(options => { - options.Sources.Add(source.Name); + options.AddCounters(source.Name); }) .AddInMemoryExporter(metricItems) .Build(); @@ -84,7 +84,7 @@ public async Task IncrementingEventCounter() var meterProvider = Sdk.CreateMeterProviderBuilder() .AddEventCountersInstrumentation(options => { - options.Sources.Add(source.Name); + options.AddCounters(source.Name); }) .AddInMemoryExporter(metricItems) .Build(); @@ -115,7 +115,7 @@ public async Task PollingCounter() var meterProvider = Sdk.CreateMeterProviderBuilder() .AddEventCountersInstrumentation(options => { - options.Sources.Add(source.Name); + options.AddCounters(source.Name); }) .AddInMemoryExporter(metricItems) .Build(); @@ -143,7 +143,7 @@ public async Task IncrementingPollingCounter() var meterProvider = Sdk.CreateMeterProviderBuilder() .AddEventCountersInstrumentation(options => { - options.Sources.Add(source.Name); + options.AddCounters(source.Name); }) .AddInMemoryExporter(metricItems) .Build(); From 8d0a30ed425fa020ba616ce8fd16969d4ac3cfd1 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 14 Sep 2022 10:23:51 -0700 Subject: [PATCH 16/30] Rename EventCountersMetricsTests file --- ...ntCounterListenerTests.cs => EventCountersMetricsTests.cs} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename test/OpenTelemetry.Instrumentation.EventCounters.Tests/{EventCounterListenerTests.cs => EventCountersMetricsTests.cs} (98%) diff --git a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs similarity index 98% rename from test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs rename to test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs index ca70bb47d7..d24ffa3d05 100644 --- a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCounterListenerTests.cs +++ b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs @@ -22,7 +22,7 @@ namespace OpenTelemetry.Instrumentation.EventCounters.Tests; -public class EventCounterListenerTests +public class EventCountersMetricsTests { private const int Delay = 1200; @@ -156,7 +156,7 @@ public async Task IncrementingPollingCounter() var metric = metricItems.Find(x => x.Name == "inc-poll-counter"); Assert.NotNull(metric); Assert.Equal(MetricType.DoubleSum, metric.MetricType); - Assert.Equal(1, GetActualValue(metric)); + Assert.Equal(2, GetActualValue(metric)); } private static double GetActualValue(Metric metric) From c8af401093ee5f739a76b962f9af2727ade8405b Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 14 Sep 2022 10:24:15 -0700 Subject: [PATCH 17/30] Update EventCountersMetricsTests.cs --- .../EventCountersMetricsTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs index d24ffa3d05..b3e8ea9d59 100644 --- a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs +++ b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs @@ -1,4 +1,4 @@ -// +// // Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); From 99097fc18420175a585f14bb3970922c733b7c0b Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 14 Sep 2022 15:46:39 -0700 Subject: [PATCH 18/30] Update EventCountersMetrics.cs --- .../EventCountersMetrics.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs index 2f7c9692bc..794c89fede 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs @@ -79,17 +79,15 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData) var isGauge = payload.ContainsKey("Mean"); Tuple metricKey = new(eventData.EventSource.Name, name); - /*if (isGauge) + if (isGauge) { this.values[metricKey] = Convert.ToDouble(payload["Mean"]); } else { - this.values[metricKey] += Convert.ToDouble(payload["Increment"]) / this.options.RefreshIntervalSecs; - }*/ - this.values[metricKey] = isGauge - ? Convert.ToDouble(payload["Mean"]) - : Convert.ToDouble(payload["Increment"]) / this.options.RefreshIntervalSecs; + _ = this.values.TryAdd(metricKey, 0); + this.values[metricKey] += Convert.ToDouble(payload["Increment"]); + } _ = this.instruments.TryAdd( metricKey, From 78d981ddddc7ea96cec5bd607c2c05f3e3f673bc Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 14 Sep 2022 16:09:38 -0700 Subject: [PATCH 19/30] Throw error when registering multiple times --- .../EventCountersMetrics.cs | 29 ++++--------------- .../MeterProviderBuilderExtensions.cs | 8 ++++- .../EventCountersMetricsTests.cs | 10 +++++++ 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs index 794c89fede..b60757547d 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs @@ -31,49 +31,30 @@ internal class EventCountersMetrics : EventListener internal static readonly AssemblyName AssemblyName = typeof(EventCountersMetrics).Assembly.GetName(); internal static readonly Meter MeterInstance = new(AssemblyName.Name, AssemblyName.Version.ToString()); - private readonly EventCountersInstrumentationOptions options; - private readonly ConcurrentBag preInitEventSources = new(); private readonly ConcurrentDictionary, Instrument> instruments = new(); private readonly ConcurrentDictionary, double> values = new(); /// /// Initializes a new instance of the class. /// - /// The options to define the metrics. - public EventCountersMetrics(EventCountersInstrumentationOptions options) + public EventCountersMetrics() { - this.options = options; - - while (this.preInitEventSources.TryTake(out EventSource source)) - { - if (this.options.ShouldListenToSource(source.Name)) - { - this.EnableEvents(source, EventLevel.LogAlways, EventKeywords.None, this.options.EnableEventsArguments); - } - } } + public static EventCountersInstrumentationOptions Options { get; set; } + /// protected override void OnEventSourceCreated(EventSource source) { - if (this.options == null) + if (Options.ShouldListenToSource(source.Name)) { - this.preInitEventSources.Add(source); - } - else if (this.options.ShouldListenToSource(source.Name)) - { - this.EnableEvents(source, EventLevel.LogAlways, EventKeywords.None, this.options.EnableEventsArguments); + this.EnableEvents(source, EventLevel.LogAlways, EventKeywords.None, Options.EnableEventsArguments); } } /// protected override void OnEventWritten(EventWrittenEventArgs eventData) { - if (this.options == null) - { - return; - } - var payload = eventData.Payload[0] as IDictionary; var name = payload["Name"].ToString(); var isGauge = payload.ContainsKey("Mean"); diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs index daf35c18ef..88ee83690d 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs @@ -36,11 +36,17 @@ public static MeterProviderBuilder AddEventCountersInstrumentation( Action configure = null) { Guard.ThrowIfNull(builder); + if (EventCountersMetrics.Options != null) + { + throw new NotSupportedException($"EventCounters instrumentation has already been registed and doesn't support multiple registrations."); + } var options = new EventCountersInstrumentationOptions(); configure?.Invoke(options); - var instrumentation = new EventCountersMetrics(options); + EventCountersMetrics.Options = options; + + var instrumentation = new EventCountersMetrics(); builder.AddMeter(EventCountersMetrics.MeterInstance.Name); return builder.AddInstrumentation(() => instrumentation); } diff --git a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs index b3e8ea9d59..bee4542f49 100644 --- a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs +++ b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs @@ -14,6 +14,7 @@ // limitations under the License. // +using System; using System.Collections.Generic; using System.Diagnostics.Tracing; using System.Threading.Tasks; @@ -159,6 +160,15 @@ public async Task IncrementingPollingCounter() Assert.Equal(2, GetActualValue(metric)); } + [Fact] + public void MultipleInstrumentation() + { + Assert.Throws(() => Sdk.CreateMeterProviderBuilder() + .AddEventCountersInstrumentation() + .AddEventCountersInstrumentation() + .Build()); + } + private static double GetActualValue(Metric metric) { double sum = 0; From f73858bc027c974191ad324d28a1b184385436e2 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 14 Sep 2022 16:24:49 -0700 Subject: [PATCH 20/30] Revert "Throw error when registering multiple times" This reverts commit 78d981ddddc7ea96cec5bd607c2c05f3e3f673bc. --- .../EventCountersMetrics.cs | 29 +++++++++++++++---- .../MeterProviderBuilderExtensions.cs | 8 +---- .../EventCountersMetricsTests.cs | 10 ------- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs index b60757547d..794c89fede 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs @@ -31,30 +31,49 @@ internal class EventCountersMetrics : EventListener internal static readonly AssemblyName AssemblyName = typeof(EventCountersMetrics).Assembly.GetName(); internal static readonly Meter MeterInstance = new(AssemblyName.Name, AssemblyName.Version.ToString()); + private readonly EventCountersInstrumentationOptions options; + private readonly ConcurrentBag preInitEventSources = new(); private readonly ConcurrentDictionary, Instrument> instruments = new(); private readonly ConcurrentDictionary, double> values = new(); /// /// Initializes a new instance of the class. /// - public EventCountersMetrics() + /// The options to define the metrics. + public EventCountersMetrics(EventCountersInstrumentationOptions options) { - } + this.options = options; - public static EventCountersInstrumentationOptions Options { get; set; } + while (this.preInitEventSources.TryTake(out EventSource source)) + { + if (this.options.ShouldListenToSource(source.Name)) + { + this.EnableEvents(source, EventLevel.LogAlways, EventKeywords.None, this.options.EnableEventsArguments); + } + } + } /// protected override void OnEventSourceCreated(EventSource source) { - if (Options.ShouldListenToSource(source.Name)) + if (this.options == null) { - this.EnableEvents(source, EventLevel.LogAlways, EventKeywords.None, Options.EnableEventsArguments); + this.preInitEventSources.Add(source); + } + else if (this.options.ShouldListenToSource(source.Name)) + { + this.EnableEvents(source, EventLevel.LogAlways, EventKeywords.None, this.options.EnableEventsArguments); } } /// protected override void OnEventWritten(EventWrittenEventArgs eventData) { + if (this.options == null) + { + return; + } + var payload = eventData.Payload[0] as IDictionary; var name = payload["Name"].ToString(); var isGauge = payload.ContainsKey("Mean"); diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs index 88ee83690d..daf35c18ef 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/MeterProviderBuilderExtensions.cs @@ -36,17 +36,11 @@ public static MeterProviderBuilder AddEventCountersInstrumentation( Action configure = null) { Guard.ThrowIfNull(builder); - if (EventCountersMetrics.Options != null) - { - throw new NotSupportedException($"EventCounters instrumentation has already been registed and doesn't support multiple registrations."); - } var options = new EventCountersInstrumentationOptions(); configure?.Invoke(options); - EventCountersMetrics.Options = options; - - var instrumentation = new EventCountersMetrics(); + var instrumentation = new EventCountersMetrics(options); builder.AddMeter(EventCountersMetrics.MeterInstance.Name); return builder.AddInstrumentation(() => instrumentation); } diff --git a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs index bee4542f49..b3e8ea9d59 100644 --- a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs +++ b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs @@ -14,7 +14,6 @@ // limitations under the License. // -using System; using System.Collections.Generic; using System.Diagnostics.Tracing; using System.Threading.Tasks; @@ -160,15 +159,6 @@ public async Task IncrementingPollingCounter() Assert.Equal(2, GetActualValue(metric)); } - [Fact] - public void MultipleInstrumentation() - { - Assert.Throws(() => Sdk.CreateMeterProviderBuilder() - .AddEventCountersInstrumentation() - .AddEventCountersInstrumentation() - .Build()); - } - private static double GetActualValue(Metric metric) { double sum = 0; From b44f952517598e25e30db89f35b54d531e5d2c79 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Thu, 22 Sep 2022 13:38:04 -0700 Subject: [PATCH 21/30] privify EnableEventsArguments --- .../EventCountersInstrumentationOptions.cs | 5 ----- .../EventCountersMetrics.cs | 7 +++++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs index d2b176b3cc..6719ed7e31 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs @@ -30,11 +30,6 @@ public class EventCountersInstrumentationOptions /// public int RefreshIntervalSecs { get; set; } = 1; - /// - /// Gets the arguments object used for the EventListener.EnableEvents function. - /// - public Dictionary EnableEventsArguments => new() { { "EventCounterIntervalSec", this.RefreshIntervalSecs.ToString() } }; - /// /// Listens to EventCounters from the given EventSource name. /// diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs index 794c89fede..d97671d790 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs @@ -48,7 +48,7 @@ public EventCountersMetrics(EventCountersInstrumentationOptions options) { if (this.options.ShouldListenToSource(source.Name)) { - this.EnableEvents(source, EventLevel.LogAlways, EventKeywords.None, this.options.EnableEventsArguments); + this.EnableEvents(source, EventLevel.LogAlways, EventKeywords.None, GetEnableEventsArguments(this.options)); } } } @@ -62,7 +62,7 @@ protected override void OnEventSourceCreated(EventSource source) } else if (this.options.ShouldListenToSource(source.Name)) { - this.EnableEvents(source, EventLevel.LogAlways, EventKeywords.None, this.options.EnableEventsArguments); + this.EnableEvents(source, EventLevel.LogAlways, EventKeywords.None, GetEnableEventsArguments(this.options)); } } @@ -93,4 +93,7 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData) metricKey, isGauge ? MeterInstance.CreateObservableGauge(name, () => this.values[metricKey]) : MeterInstance.CreateObservableCounter(name, () => this.values[metricKey])); } + + private static Dictionary GetEnableEventsArguments(EventCountersInstrumentationOptions options) => + new() { { "EventCounterIntervalSec", options.RefreshIntervalSecs.ToString() } }; } From 12cbb30edbadfe5d8545f99c4d346adcc58c3a6c Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Thu, 22 Sep 2022 15:33:43 -0700 Subject: [PATCH 22/30] pr comments --- .../EventCountersInstrumentationOptions.cs | 4 ++-- .../EventCountersMetricsTests.cs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs index 6719ed7e31..9193d0c8ea 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs @@ -34,7 +34,7 @@ public class EventCountersInstrumentationOptions /// Listens to EventCounters from the given EventSource name. /// /// The EventSource name. - public void AddCounters(string eventSourceName) + public void AddEventSource(string eventSourceName) { this.eventSourceNames.Add(eventSourceName); } @@ -44,7 +44,7 @@ public void AddCounters(string eventSourceName) /// /// The EventSource name. /// true when an EventSource with the name should be enabled. - public bool ShouldListenToSource(string eventSourceName) + internal bool ShouldListenToSource(string eventSourceName) { return this.eventSourceNames.Contains(eventSourceName); } diff --git a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs index b3e8ea9d59..bbe7364af1 100644 --- a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs +++ b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs @@ -56,7 +56,7 @@ public async Task EventCounter() var meterProvider = Sdk.CreateMeterProviderBuilder() .AddEventCountersInstrumentation(options => { - options.AddCounters(source.Name); + options.AddEventSource(source.Name); }) .AddInMemoryExporter(metricItems) .Build(); @@ -84,7 +84,7 @@ public async Task IncrementingEventCounter() var meterProvider = Sdk.CreateMeterProviderBuilder() .AddEventCountersInstrumentation(options => { - options.AddCounters(source.Name); + options.AddEventSource(source.Name); }) .AddInMemoryExporter(metricItems) .Build(); @@ -115,7 +115,7 @@ public async Task PollingCounter() var meterProvider = Sdk.CreateMeterProviderBuilder() .AddEventCountersInstrumentation(options => { - options.AddCounters(source.Name); + options.AddEventSource(source.Name); }) .AddInMemoryExporter(metricItems) .Build(); @@ -143,7 +143,7 @@ public async Task IncrementingPollingCounter() var meterProvider = Sdk.CreateMeterProviderBuilder() .AddEventCountersInstrumentation(options => { - options.AddCounters(source.Name); + options.AddEventSource(source.Name); }) .AddInMemoryExporter(metricItems) .Build(); From 93986172bb4795bb7c19a48f539516c062750585 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 28 Sep 2022 09:22:11 -0700 Subject: [PATCH 23/30] tada --- .../EventCountersInstrumentationOptions.cs | 6 +++ .../EventCountersMetrics.cs | 3 +- .../EventCountersMetricsTests.cs | 38 +++++++++++++++++-- 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs index 9193d0c8ea..e1bab87a63 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs @@ -14,6 +14,7 @@ // limitations under the License. // +using System; using System.Collections.Generic; namespace OpenTelemetry.Instrumentation.EventCounters; @@ -36,6 +37,11 @@ public class EventCountersInstrumentationOptions /// The EventSource name. public void AddEventSource(string eventSourceName) { + if (eventSourceName == "System.Runtime") + { + throw new NotSupportedException("Use the `OpenTelemetry.Instrumentation.Runtime` instrumentation."); + } + this.eventSourceNames.Add(eventSourceName); } diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs index d97671d790..ec8cad9261 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs @@ -89,9 +89,10 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData) this.values[metricKey] += Convert.ToDouble(payload["Increment"]); } + var instrumentName = $"{eventData.EventSource.Name}.{name}"; _ = this.instruments.TryAdd( metricKey, - isGauge ? MeterInstance.CreateObservableGauge(name, () => this.values[metricKey]) : MeterInstance.CreateObservableCounter(name, () => this.values[metricKey])); + isGauge ? MeterInstance.CreateObservableGauge(instrumentName, () => this.values[metricKey]) : MeterInstance.CreateObservableCounter(instrumentName, () => this.values[metricKey])); } private static Dictionary GetEnableEventsArguments(EventCountersInstrumentationOptions options) => diff --git a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs index bbe7364af1..a46a126634 100644 --- a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs +++ b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs @@ -67,7 +67,7 @@ public async Task EventCounter() meterProvider.ForceFlush(); // Assert - var metric = metricItems.Find(x => x.Name == "counter"); + var metric = metricItems.Find(x => x.Name == "source-a.counter"); Assert.NotNull(metric); Assert.Equal(MetricType.DoubleGauge, metric.MetricType); Assert.Equal(1997.0202, GetActualValue(metric)); @@ -97,7 +97,7 @@ public async Task IncrementingEventCounter() meterProvider.ForceFlush(); // Assert - var metric = metricItems.Find(x => x.Name == "inc-counter"); + var metric = metricItems.Find(x => x.Name == "source-b.inc-counter"); Assert.NotNull(metric); Assert.Equal(MetricType.DoubleSum, metric.MetricType); Assert.Equal(3, GetActualValue(metric)); @@ -125,7 +125,7 @@ public async Task PollingCounter() meterProvider.ForceFlush(); // Assert - var metric = metricItems.Find(x => x.Name == "poll-counter"); + var metric = metricItems.Find(x => x.Name == "source-c.poll-counter"); Assert.NotNull(metric); Assert.Equal(MetricType.DoubleGauge, metric.MetricType); Assert.Equal(20, GetActualValue(metric)); @@ -153,12 +153,42 @@ public async Task IncrementingPollingCounter() meterProvider.ForceFlush(); // Assert - var metric = metricItems.Find(x => x.Name == "inc-poll-counter"); + var metric = metricItems.Find(x => x.Name == "source-d.inc-poll-counter"); Assert.NotNull(metric); Assert.Equal(MetricType.DoubleSum, metric.MetricType); Assert.Equal(2, GetActualValue(metric)); } + [Fact] + public async Task EventCounterSameName() + { + // Arrange + List metricItems = new(); + EventSource source = new("source-a"); + EventCounter counter = new("counter", source); + EventCounter counter2 = new("counter", source); + + var meterProvider = Sdk.CreateMeterProviderBuilder() + .AddEventCountersInstrumentation(options => + { + options.AddEventSource(source.Name); + }) + .AddInMemoryExporter(metricItems) + .Build(); + + // Act + counter.WriteMetric(1997.0202); + // counter2.WriteMetric(1980.1208); + await Task.Delay(Delay); + meterProvider.ForceFlush(); + + // Assert + var metric = metricItems.Find(x => x.Name == "counter"); + Assert.NotNull(metric); + Assert.Equal(MetricType.DoubleGauge, metric.MetricType); + Assert.Equal(1997.0202, GetActualValue(metric)); + } + private static double GetActualValue(Metric metric) { double sum = 0; From e5586098d7c177fbe8a556e80ab85007ec89db4d Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 28 Sep 2022 15:01:40 -0700 Subject: [PATCH 24/30] Update EventCountersInstrumentationOptions.cs --- .../EventCountersInstrumentationOptions.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs index e1bab87a63..c82f01df81 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs @@ -27,7 +27,8 @@ public class EventCountersInstrumentationOptions private readonly HashSet eventSourceNames = new(); /// - /// Gets or sets the subscription interval in seconds. + /// Gets or sets the subscription interval in seconds for reading values + /// from the configured EventCounters. /// public int RefreshIntervalSecs { get; set; } = 1; From 72e52d17dc683d45efea6f69cf0334e82e7c4f06 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Thu, 29 Sep 2022 13:04:15 -0700 Subject: [PATCH 25/30] exception tests --- .../EventCountersInstrumentationOptions.cs | 2 +- .../EventCountersMetricsTests.cs | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs index c82f01df81..2b0aa4516b 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs @@ -40,7 +40,7 @@ public void AddEventSource(string eventSourceName) { if (eventSourceName == "System.Runtime") { - throw new NotSupportedException("Use the `OpenTelemetry.Instrumentation.Runtime` instrumentation."); + throw new NotSupportedException("Use the `OpenTelemetry.Instrumentation.Runtime` or `OpenTelemetry.Instrumentation.Process` instrumentations."); } this.eventSourceNames.Add(eventSourceName); diff --git a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs index a46a126634..b200560219 100644 --- a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs +++ b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs @@ -14,6 +14,7 @@ // limitations under the License. // +using System; using System.Collections.Generic; using System.Diagnostics.Tracing; using System.Threading.Tasks; @@ -189,6 +190,28 @@ public async Task EventCounterSameName() Assert.Equal(1997.0202, GetActualValue(metric)); } + [Fact] + public void ThrowExceptionWhenBuilderIsNull() + { + MeterProviderBuilder builder = null; + Assert.Throws(() => builder.AddEventCountersInstrumentation()); + } + + [Fact] + public void ThrowExceptionForUnsupportedEventSources() + { + var ex = Assert.Throws(() => + { + Sdk.CreateMeterProviderBuilder() + .AddEventCountersInstrumentation(options => + { + options.AddEventSource("System.Runtime"); + }); + }); + + Assert.Equal("Use the `OpenTelemetry.Instrumentation.Runtime` or `OpenTelemetry.Instrumentation.Process` instrumentations.", ex.Message); + } + private static double GetActualValue(Metric metric) { double sum = 0; From 54d8b2ce2bef88978c05919af6fdcc16daaac40e Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 5 Oct 2022 15:10:10 -0700 Subject: [PATCH 26/30] fixing recommendations --- ...EventCountersInstrumentationEventSource.cs | 70 ++++++++++++++ .../EventCountersInstrumentationOptions.cs | 9 +- .../EventCountersMetrics.cs | 93 +++++++++++++++---- .../EventCountersMetricsTests.cs | 54 ++++++----- 4 files changed, 179 insertions(+), 47 deletions(-) create mode 100644 src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationEventSource.cs diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationEventSource.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationEventSource.cs new file mode 100644 index 0000000000..787a38bbe8 --- /dev/null +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationEventSource.cs @@ -0,0 +1,70 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System.Diagnostics.Tracing; + +namespace OpenTelemetry.Instrumentation.EventCounters; + +/// +/// EventSource events emitted from the project. +/// +[EventSource(Name = "OpenTelemetry-Instrumentation-EventCounters")] +internal sealed class EventCountersInstrumentationEventSource : EventSource +{ + public static readonly EventCountersInstrumentationEventSource Log = new(); + + [Event(1, Level = EventLevel.Warning, Message = "Duplicate instrument name detected: {0}.")] + internal void DuplicateInstrumentNameWarning(string instrumentName) + { + this.WriteEvent(1, instrumentName); + } + + [Event(2, Level = EventLevel.Warning, Message = "Invalid instrument name: {0}.")] + internal void InvalidInstrumentNameWarning(string instrumentName) + { + this.WriteEvent(2, instrumentName); + } + + [Event(3, Level = EventLevel.Warning, Message = "Error while writing event from source: {0} - {1}.")] + internal void ErrorWhileWritingEvent(string eventSourceName, string exceptionMessage) + { + this.WriteEvent(3, eventSourceName, exceptionMessage); + } + + [Event(4, Level = EventLevel.Warning, Message = "Event data payload not parseable from source: {0}.")] + internal void IgnoreEventWrittenEventArgsPayloadNotParseable(string eventSourceName) + { + this.WriteEvent(4, eventSourceName); + } + + [Event(5, Level = EventLevel.Warning, Message = "Event data has no name from source: {0}.")] + internal void IgnoreEventWrittenEventArgsWithoutName(string eventSourceName) + { + this.WriteEvent(5, eventSourceName); + } + + [Event(6, Level = EventLevel.Warning, Message = "Event data payload problem with values of Mean, Increment from source: {0}.")] + internal void IgnoreMeanIncrementConflict(string eventSourceName) + { + this.WriteEvent(6, eventSourceName); + } + + [Event(7, Level = EventLevel.Warning, Message = "Event data has name other than 'EventCounters' from source: {0}.")] + internal void IgnoreNonEventCountersName(string eventSourceName) + { + this.WriteEvent(7, eventSourceName); + } +} diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs index 2b0aa4516b..87e1a93e75 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationOptions.cs @@ -16,6 +16,7 @@ using System; using System.Collections.Generic; +using System.Linq; namespace OpenTelemetry.Instrumentation.EventCounters; @@ -35,15 +36,15 @@ public class EventCountersInstrumentationOptions /// /// Listens to EventCounters from the given EventSource name. /// - /// The EventSource name. - public void AddEventSource(string eventSourceName) + /// The EventSource names to listen to. + public void AddEventSources(params string[] names) { - if (eventSourceName == "System.Runtime") + if (names.Contains("System.Runtime")) { throw new NotSupportedException("Use the `OpenTelemetry.Instrumentation.Runtime` or `OpenTelemetry.Instrumentation.Process` instrumentations."); } - this.eventSourceNames.Add(eventSourceName); + this.eventSourceNames.UnionWith(names); } /// diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs index ec8cad9261..ddfac3f64d 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs @@ -20,6 +20,7 @@ using System.Diagnostics.Metrics; using System.Diagnostics.Tracing; using System.Reflection; +using System.Text.RegularExpressions; namespace OpenTelemetry.Instrumentation.EventCounters; @@ -28,13 +29,16 @@ namespace OpenTelemetry.Instrumentation.EventCounters; /// internal class EventCountersMetrics : EventListener { - internal static readonly AssemblyName AssemblyName = typeof(EventCountersMetrics).Assembly.GetName(); + private static readonly AssemblyName AssemblyName = typeof(EventCountersMetrics).Assembly.GetName(); internal static readonly Meter MeterInstance = new(AssemblyName.Name, AssemblyName.Version.ToString()); + private static readonly Regex InstrumentNameRegex = new( + @"^[a-zA-Z][-.\w]{0,62}", RegexOptions.IgnoreCase | RegexOptions.Compiled); private readonly EventCountersInstrumentationOptions options; - private readonly ConcurrentBag preInitEventSources = new(); - private readonly ConcurrentDictionary, Instrument> instruments = new(); - private readonly ConcurrentDictionary, double> values = new(); + private readonly ConcurrentQueue preInitEventSources = new(); + private readonly ConcurrentDictionary<(string, string), Instrument> instruments = new(); + private readonly ConcurrentDictionary<(string, string), double> values = new(); + private readonly HashSet instrumentNames = new(); /// /// Initializes a new instance of the class. @@ -44,7 +48,7 @@ public EventCountersMetrics(EventCountersInstrumentationOptions options) { this.options = options; - while (this.preInitEventSources.TryTake(out EventSource source)) + while (this.preInitEventSources.TryDequeue(out EventSource source)) { if (this.options.ShouldListenToSource(source.Name)) { @@ -58,7 +62,7 @@ protected override void OnEventSourceCreated(EventSource source) { if (this.options == null) { - this.preInitEventSources.Add(source); + this.preInitEventSources.Enqueue(source); } else if (this.options.ShouldListenToSource(source.Name)) { @@ -74,27 +78,80 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData) return; } + var eventSourceName = eventData.EventSource.Name; + + if (eventData.EventName != "EventCounters") + { + EventCountersInstrumentationEventSource.Log.IgnoreNonEventCountersName(eventSourceName); + return; + } + + if (eventData.Payload.Count == 0 || eventData.Payload[0] is not IDictionary) + { + EventCountersInstrumentationEventSource.Log.IgnoreEventWrittenEventArgsPayloadNotParseable(eventSourceName); + return; + } + var payload = eventData.Payload[0] as IDictionary; - var name = payload["Name"].ToString(); - var isGauge = payload.ContainsKey("Mean"); - Tuple metricKey = new(eventData.EventSource.Name, name); + var hasName = payload.TryGetValue("Name", out var nameObj); - if (isGauge) + if (!hasName) { - this.values[metricKey] = Convert.ToDouble(payload["Mean"]); + EventCountersInstrumentationEventSource.Log.IgnoreEventWrittenEventArgsWithoutName(eventSourceName); + return; } - else + + var name = nameObj.ToString(); + + var hasMean = payload.TryGetValue("Mean", out var mean); + var hasIncrement = payload.TryGetValue("Increment", out var increment); + + if (!(hasIncrement ^ hasMean)) { - _ = this.values.TryAdd(metricKey, 0); - this.values[metricKey] += Convert.ToDouble(payload["Increment"]); + EventCountersInstrumentationEventSource.Log.IgnoreMeanIncrementConflict(eventSourceName); + return; } - var instrumentName = $"{eventData.EventSource.Name}.{name}"; - _ = this.instruments.TryAdd( - metricKey, - isGauge ? MeterInstance.CreateObservableGauge(instrumentName, () => this.values[metricKey]) : MeterInstance.CreateObservableCounter(instrumentName, () => this.values[metricKey])); + var value = Convert.ToDouble(hasMean ? mean : increment); + this.EventWritten(hasMean, eventSourceName, name, value); } private static Dictionary GetEnableEventsArguments(EventCountersInstrumentationOptions options) => new() { { "EventCounterIntervalSec", options.RefreshIntervalSecs.ToString() } }; + + private static bool IsValidInstrumentName(string name) => + !string.IsNullOrWhiteSpace(name) && InstrumentNameRegex.IsMatch(name); + + private void EventWritten(bool isGauge, string eventSourceName, string name, double value) + { + try + { + ValueTuple metricKey = new(eventSourceName, name); + _ = this.values.AddOrUpdate(metricKey, value, isGauge ? (_, _) => value : (_, existing) => existing + value); + + if (!this.instruments.ContainsKey(metricKey)) + { + var instrumentName = $"EventCounters.{eventSourceName}.{name}"; + + if (!IsValidInstrumentName(instrumentName)) + { + EventCountersInstrumentationEventSource.Log.InvalidInstrumentNameWarning(instrumentName); + } + + Instrument instrument = isGauge + ? MeterInstance.CreateObservableGauge(instrumentName, () => this.values[metricKey]) + : MeterInstance.CreateObservableCounter(instrumentName, () => this.values[metricKey]); + _ = this.instruments.TryAdd(metricKey, instrument); + + if (!this.instrumentNames.Add(instrumentName)) + { + EventCountersInstrumentationEventSource.Log.DuplicateInstrumentNameWarning(instrumentName); + } + } + } + catch (Exception ex) + { + EventCountersInstrumentationEventSource.Log.ErrorWhileWritingEvent(eventSourceName, ex.Message); + } + } } diff --git a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs index b200560219..748e849ed5 100644 --- a/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs +++ b/test/OpenTelemetry.Instrumentation.EventCounters.Tests/EventCountersMetricsTests.cs @@ -51,13 +51,13 @@ public async Task EventCounter() { // Arrange List metricItems = new(); - EventSource source = new("source-a"); - EventCounter counter = new("counter", source); + EventSource source = new("a"); + EventCounter counter = new("c", source); var meterProvider = Sdk.CreateMeterProviderBuilder() .AddEventCountersInstrumentation(options => { - options.AddEventSource(source.Name); + options.AddEventSources(source.Name); }) .AddInMemoryExporter(metricItems) .Build(); @@ -68,7 +68,7 @@ public async Task EventCounter() meterProvider.ForceFlush(); // Assert - var metric = metricItems.Find(x => x.Name == "source-a.counter"); + var metric = metricItems.Find(x => x.Name == "EventCounters.a.c"); Assert.NotNull(metric); Assert.Equal(MetricType.DoubleGauge, metric.MetricType); Assert.Equal(1997.0202, GetActualValue(metric)); @@ -79,13 +79,13 @@ public async Task IncrementingEventCounter() { // Arrange List metricItems = new(); - EventSource source = new("source-b"); - IncrementingEventCounter incCounter = new("inc-counter", source); + EventSource source = new("b"); + IncrementingEventCounter incCounter = new("inc-c", source); var meterProvider = Sdk.CreateMeterProviderBuilder() .AddEventCountersInstrumentation(options => { - options.AddEventSource(source.Name); + options.AddEventSources(source.Name); }) .AddInMemoryExporter(metricItems) .Build(); @@ -98,7 +98,7 @@ public async Task IncrementingEventCounter() meterProvider.ForceFlush(); // Assert - var metric = metricItems.Find(x => x.Name == "source-b.inc-counter"); + var metric = metricItems.Find(x => x.Name == "EventCounters.b.inc-c"); Assert.NotNull(metric); Assert.Equal(MetricType.DoubleSum, metric.MetricType); Assert.Equal(3, GetActualValue(metric)); @@ -110,13 +110,13 @@ public async Task PollingCounter() // Arrange int i = 0; List metricItems = new(); - EventSource source = new("source-c"); - PollingCounter pollCounter = new("poll-counter", source, () => ++i * 10); + EventSource source = new("c"); + PollingCounter pollCounter = new("poll-c", source, () => ++i * 10); var meterProvider = Sdk.CreateMeterProviderBuilder() .AddEventCountersInstrumentation(options => { - options.AddEventSource(source.Name); + options.AddEventSources(source.Name); }) .AddInMemoryExporter(metricItems) .Build(); @@ -126,7 +126,7 @@ public async Task PollingCounter() meterProvider.ForceFlush(); // Assert - var metric = metricItems.Find(x => x.Name == "source-c.poll-counter"); + var metric = metricItems.Find(x => x.Name == "EventCounters.c.poll-c"); Assert.NotNull(metric); Assert.Equal(MetricType.DoubleGauge, metric.MetricType); Assert.Equal(20, GetActualValue(metric)); @@ -138,13 +138,13 @@ public async Task IncrementingPollingCounter() // Arrange int i = 1; List metricItems = new(); - EventSource source = new("source-d"); - IncrementingPollingCounter incPollCounter = new("inc-poll-counter", source, () => i++); + EventSource source = new("d"); + IncrementingPollingCounter incPollCounter = new("inc-poll-c", source, () => i++); var meterProvider = Sdk.CreateMeterProviderBuilder() .AddEventCountersInstrumentation(options => { - options.AddEventSource(source.Name); + options.AddEventSources(source.Name); }) .AddInMemoryExporter(metricItems) .Build(); @@ -154,40 +154,42 @@ public async Task IncrementingPollingCounter() meterProvider.ForceFlush(); // Assert - var metric = metricItems.Find(x => x.Name == "source-d.inc-poll-counter"); + var metric = metricItems.Find(x => x.Name == "EventCounters.d.inc-poll-c"); Assert.NotNull(metric); Assert.Equal(MetricType.DoubleSum, metric.MetricType); Assert.Equal(2, GetActualValue(metric)); } [Fact] - public async Task EventCounterSameName() + public async Task EventCounterSameNameUsesNewestCreated() { // Arrange List metricItems = new(); - EventSource source = new("source-a"); - EventCounter counter = new("counter", source); - EventCounter counter2 = new("counter", source); + EventSource source = new("a"); + EventCounter counter = new("c", source); + EventCounter counter2 = new("c", source); var meterProvider = Sdk.CreateMeterProviderBuilder() .AddEventCountersInstrumentation(options => { - options.AddEventSource(source.Name); + options.AddEventSources(source.Name); }) .AddInMemoryExporter(metricItems) .Build(); // Act + counter2.WriteMetric(1980.1208); counter.WriteMetric(1997.0202); - // counter2.WriteMetric(1980.1208); await Task.Delay(Delay); meterProvider.ForceFlush(); // Assert - var metric = metricItems.Find(x => x.Name == "counter"); + var metric = metricItems.Find(x => x.Name == "EventCounters.a.c"); Assert.NotNull(metric); Assert.Equal(MetricType.DoubleGauge, metric.MetricType); - Assert.Equal(1997.0202, GetActualValue(metric)); + + // Since `counter2` was created after `counter` it is exported + Assert.Equal(1980.1208, GetActualValue(metric)); } [Fact] @@ -205,13 +207,15 @@ public void ThrowExceptionForUnsupportedEventSources() Sdk.CreateMeterProviderBuilder() .AddEventCountersInstrumentation(options => { - options.AddEventSource("System.Runtime"); + options.AddEventSources("System.Runtime"); }); }); Assert.Equal("Use the `OpenTelemetry.Instrumentation.Runtime` or `OpenTelemetry.Instrumentation.Process` instrumentations.", ex.Message); } + // polling and eventcounter with same instrument name? + private static double GetActualValue(Metric metric) { double sum = 0; From 6daa63d94236949e570ace155a049a83b94277a1 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Thu, 6 Oct 2022 14:01:52 -0700 Subject: [PATCH 27/30] cleanup --- ...EventCountersInstrumentationEventSource.cs | 2 +- .../EventCountersMetrics.cs | 33 ++++++++++--------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationEventSource.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationEventSource.cs index 787a38bbe8..207507be82 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationEventSource.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationEventSource.cs @@ -32,7 +32,7 @@ internal void DuplicateInstrumentNameWarning(string instrumentName) this.WriteEvent(1, instrumentName); } - [Event(2, Level = EventLevel.Warning, Message = "Invalid instrument name: {0}.")] + [Event(2, Level = EventLevel.Warning, Message = "Instrument not created. Invalid instrument name: {0}.")] internal void InvalidInstrumentNameWarning(string instrumentName) { this.WriteEvent(2, instrumentName); diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs index ddfac3f64d..506cecfbc5 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs @@ -19,6 +19,7 @@ using System.Collections.Generic; using System.Diagnostics.Metrics; using System.Diagnostics.Tracing; +using System.Linq; using System.Reflection; using System.Text.RegularExpressions; @@ -29,8 +30,8 @@ namespace OpenTelemetry.Instrumentation.EventCounters; /// internal class EventCountersMetrics : EventListener { - private static readonly AssemblyName AssemblyName = typeof(EventCountersMetrics).Assembly.GetName(); internal static readonly Meter MeterInstance = new(AssemblyName.Name, AssemblyName.Version.ToString()); + private static readonly AssemblyName AssemblyName = typeof(EventCountersMetrics).Assembly.GetName(); private static readonly Regex InstrumentNameRegex = new( @"^[a-zA-Z][-.\w]{0,62}", RegexOptions.IgnoreCase | RegexOptions.Compiled); @@ -38,7 +39,7 @@ internal class EventCountersMetrics : EventListener private readonly ConcurrentQueue preInitEventSources = new(); private readonly ConcurrentDictionary<(string, string), Instrument> instruments = new(); private readonly ConcurrentDictionary<(string, string), double> values = new(); - private readonly HashSet instrumentNames = new(); + private readonly ConcurrentDictionary instrumentNames = new(); /// /// Initializes a new instance of the class. @@ -48,11 +49,11 @@ public EventCountersMetrics(EventCountersInstrumentationOptions options) { this.options = options; - while (this.preInitEventSources.TryDequeue(out EventSource source)) + while (this.preInitEventSources.TryDequeue(out EventSource eventSource)) { - if (this.options.ShouldListenToSource(source.Name)) + if (this.options.ShouldListenToSource(eventSource.Name)) { - this.EnableEvents(source, EventLevel.LogAlways, EventKeywords.None, GetEnableEventsArguments(this.options)); + this.EnableEvents(eventSource, EventLevel.LogAlways, EventKeywords.None, GetEnableEventsArguments(this.options)); } } } @@ -86,7 +87,7 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData) return; } - if (eventData.Payload.Count == 0 || eventData.Payload[0] is not IDictionary) + if (eventData.Payload == null || eventData.Payload.Count == 0 || eventData.Payload[0] is not IDictionary) { EventCountersInstrumentationEventSource.Log.IgnoreEventWrittenEventArgsPayloadNotParseable(eventSourceName); return; @@ -113,7 +114,7 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData) } var value = Convert.ToDouble(hasMean ? mean : increment); - this.EventWritten(hasMean, eventSourceName, name, value); + this.UpdateInstrumentWithEvent(hasMean, eventSourceName, name, value); } private static Dictionary GetEnableEventsArguments(EventCountersInstrumentationOptions options) => @@ -122,28 +123,30 @@ private static Dictionary GetEnableEventsArguments(EventCounters private static bool IsValidInstrumentName(string name) => !string.IsNullOrWhiteSpace(name) && InstrumentNameRegex.IsMatch(name); - private void EventWritten(bool isGauge, string eventSourceName, string name, double value) + private void UpdateInstrumentWithEvent(bool isGauge, string eventSourceName, string name, double value) { try { ValueTuple metricKey = new(eventSourceName, name); _ = this.values.AddOrUpdate(metricKey, value, isGauge ? (_, _) => value : (_, existing) => existing + value); - if (!this.instruments.ContainsKey(metricKey)) + var instrumentName = $"EventCounters.{eventSourceName}.{name}"; + + if (!IsValidInstrumentName(instrumentName)) { - var instrumentName = $"EventCounters.{eventSourceName}.{name}"; + EventCountersInstrumentationEventSource.Log.InvalidInstrumentNameWarning(instrumentName); + return; + } - if (!IsValidInstrumentName(instrumentName)) - { - EventCountersInstrumentationEventSource.Log.InvalidInstrumentNameWarning(instrumentName); - } + if (!this.instruments.ContainsKey(metricKey)) + { Instrument instrument = isGauge ? MeterInstance.CreateObservableGauge(instrumentName, () => this.values[metricKey]) : MeterInstance.CreateObservableCounter(instrumentName, () => this.values[metricKey]); _ = this.instruments.TryAdd(metricKey, instrument); - if (!this.instrumentNames.Add(instrumentName)) + if (!this.instrumentNames.TryAdd(instrumentName, 0)) { EventCountersInstrumentationEventSource.Log.DuplicateInstrumentNameWarning(instrumentName); } From 553ae8706ae4498c4f93b5040081db15a107bc52 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Thu, 6 Oct 2022 16:12:55 -0700 Subject: [PATCH 28/30] fix --- .../EventCountersMetrics.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs index 506cecfbc5..8a15bb553f 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs @@ -19,7 +19,6 @@ using System.Collections.Generic; using System.Diagnostics.Metrics; using System.Diagnostics.Tracing; -using System.Linq; using System.Reflection; using System.Text.RegularExpressions; @@ -140,7 +139,6 @@ private void UpdateInstrumentWithEvent(bool isGauge, string eventSourceName, str if (!this.instruments.ContainsKey(metricKey)) { - Instrument instrument = isGauge ? MeterInstance.CreateObservableGauge(instrumentName, () => this.values[metricKey]) : MeterInstance.CreateObservableCounter(instrumentName, () => this.values[metricKey]); From 556b65e729c1152b75823b796c8ce277eb262709 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Mon, 10 Oct 2022 11:30:50 -0700 Subject: [PATCH 29/30] CI rerun From 71560ed15ec240ccbb9e3b3fb658f7199300cdd3 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 12 Oct 2022 17:37:06 -0700 Subject: [PATCH 30/30] remove duplicate checks sdk already does --- ...EventCountersInstrumentationEventSource.cs | 32 ++++++------------- .../EventCountersMetrics.cs | 27 ++-------------- 2 files changed, 13 insertions(+), 46 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationEventSource.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationEventSource.cs index 207507be82..071f963352 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationEventSource.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersInstrumentationEventSource.cs @@ -26,45 +26,33 @@ internal sealed class EventCountersInstrumentationEventSource : EventSource { public static readonly EventCountersInstrumentationEventSource Log = new(); - [Event(1, Level = EventLevel.Warning, Message = "Duplicate instrument name detected: {0}.")] - internal void DuplicateInstrumentNameWarning(string instrumentName) - { - this.WriteEvent(1, instrumentName); - } - - [Event(2, Level = EventLevel.Warning, Message = "Instrument not created. Invalid instrument name: {0}.")] - internal void InvalidInstrumentNameWarning(string instrumentName) - { - this.WriteEvent(2, instrumentName); - } - - [Event(3, Level = EventLevel.Warning, Message = "Error while writing event from source: {0} - {1}.")] + [Event(1, Level = EventLevel.Warning, Message = "Error while writing event from source: {0} - {1}.")] internal void ErrorWhileWritingEvent(string eventSourceName, string exceptionMessage) { - this.WriteEvent(3, eventSourceName, exceptionMessage); + this.WriteEvent(1, eventSourceName, exceptionMessage); } - [Event(4, Level = EventLevel.Warning, Message = "Event data payload not parseable from source: {0}.")] + [Event(2, Level = EventLevel.Warning, Message = "Event data payload not parseable from source: {0}.")] internal void IgnoreEventWrittenEventArgsPayloadNotParseable(string eventSourceName) { - this.WriteEvent(4, eventSourceName); + this.WriteEvent(2, eventSourceName); } - [Event(5, Level = EventLevel.Warning, Message = "Event data has no name from source: {0}.")] + [Event(3, Level = EventLevel.Warning, Message = "Event data has no name from source: {0}.")] internal void IgnoreEventWrittenEventArgsWithoutName(string eventSourceName) { - this.WriteEvent(5, eventSourceName); + this.WriteEvent(3, eventSourceName); } - [Event(6, Level = EventLevel.Warning, Message = "Event data payload problem with values of Mean, Increment from source: {0}.")] + [Event(4, Level = EventLevel.Warning, Message = "Event data payload problem with values of Mean, Increment from source: {0}.")] internal void IgnoreMeanIncrementConflict(string eventSourceName) { - this.WriteEvent(6, eventSourceName); + this.WriteEvent(4, eventSourceName); } - [Event(7, Level = EventLevel.Warning, Message = "Event data has name other than 'EventCounters' from source: {0}.")] + [Event(5, Level = EventLevel.Warning, Message = "Event data has name other than 'EventCounters' from source: {0}.")] internal void IgnoreNonEventCountersName(string eventSourceName) { - this.WriteEvent(7, eventSourceName); + this.WriteEvent(5, eventSourceName); } } diff --git a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs index 8a15bb553f..e01ce8b968 100644 --- a/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs +++ b/src/OpenTelemetry.Instrumentation.EventCounters/EventCountersMetrics.cs @@ -19,26 +19,20 @@ using System.Collections.Generic; using System.Diagnostics.Metrics; using System.Diagnostics.Tracing; -using System.Reflection; -using System.Text.RegularExpressions; namespace OpenTelemetry.Instrumentation.EventCounters; /// /// .NET EventCounters Instrumentation. /// -internal class EventCountersMetrics : EventListener +internal sealed class EventCountersMetrics : EventListener { - internal static readonly Meter MeterInstance = new(AssemblyName.Name, AssemblyName.Version.ToString()); - private static readonly AssemblyName AssemblyName = typeof(EventCountersMetrics).Assembly.GetName(); - private static readonly Regex InstrumentNameRegex = new( - @"^[a-zA-Z][-.\w]{0,62}", RegexOptions.IgnoreCase | RegexOptions.Compiled); + internal static readonly Meter MeterInstance = new(typeof(EventCountersMetrics).Assembly.GetName().Name, typeof(EventCountersMetrics).Assembly.GetName().Version.ToString()); private readonly EventCountersInstrumentationOptions options; private readonly ConcurrentQueue preInitEventSources = new(); private readonly ConcurrentDictionary<(string, string), Instrument> instruments = new(); private readonly ConcurrentDictionary<(string, string), double> values = new(); - private readonly ConcurrentDictionary instrumentNames = new(); /// /// Initializes a new instance of the class. @@ -86,13 +80,12 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData) return; } - if (eventData.Payload == null || eventData.Payload.Count == 0 || eventData.Payload[0] is not IDictionary) + if (eventData.Payload == null || eventData.Payload.Count == 0 || eventData.Payload[0] is not IDictionary payload) { EventCountersInstrumentationEventSource.Log.IgnoreEventWrittenEventArgsPayloadNotParseable(eventSourceName); return; } - var payload = eventData.Payload[0] as IDictionary; var hasName = payload.TryGetValue("Name", out var nameObj); if (!hasName) @@ -119,9 +112,6 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData) private static Dictionary GetEnableEventsArguments(EventCountersInstrumentationOptions options) => new() { { "EventCounterIntervalSec", options.RefreshIntervalSecs.ToString() } }; - private static bool IsValidInstrumentName(string name) => - !string.IsNullOrWhiteSpace(name) && InstrumentNameRegex.IsMatch(name); - private void UpdateInstrumentWithEvent(bool isGauge, string eventSourceName, string name, double value) { try @@ -131,23 +121,12 @@ private void UpdateInstrumentWithEvent(bool isGauge, string eventSourceName, str var instrumentName = $"EventCounters.{eventSourceName}.{name}"; - if (!IsValidInstrumentName(instrumentName)) - { - EventCountersInstrumentationEventSource.Log.InvalidInstrumentNameWarning(instrumentName); - return; - } - if (!this.instruments.ContainsKey(metricKey)) { Instrument instrument = isGauge ? MeterInstance.CreateObservableGauge(instrumentName, () => this.values[metricKey]) : MeterInstance.CreateObservableCounter(instrumentName, () => this.values[metricKey]); _ = this.instruments.TryAdd(metricKey, instrument); - - if (!this.instrumentNames.TryAdd(instrumentName, 0)) - { - EventCountersInstrumentationEventSource.Log.DuplicateInstrumentNameWarning(instrumentName); - } } } catch (Exception ex)