Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Event counter listener #10

Merged
merged 5 commits into from
Feb 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
// limitations under the License.
// </copyright>

using OpenTelemetry.Metrics;

namespace OpenTelemetry.Contrib.Instrumentation.EventCounters
{
/// <summary>
Expand All @@ -34,9 +32,9 @@ public class EventCounter
public string Description { get; set; }

/// <summary>
/// Gets or sets the metric type.
/// Gets or sets the instrumentation type.
/// </summary>
public MetricType? Type { get; set; } = MetricType.LongSum;
public InstrumentationType? Type { get; set; } = InstrumentationType.Counter;

/// <summary>
/// Gets or sets the name used for the published metric.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
using System.Diagnostics.Tracing;
using System.Globalization;
using System.Linq;
using OpenTelemetry.Metrics;

namespace OpenTelemetry.Contrib.Instrumentation.EventCounters.Implementation
{
Expand Down Expand Up @@ -150,10 +149,10 @@ private void ExtractAndPostMetric(string eventSourceName, IDictionary<string, ob
bool calculateRate = false;
double actualValue = 0.0;
double actualInterval = 0.0;
int actualCount = 0;

string counterName = string.Empty;
string counterDisplayName = string.Empty;
string counterDisplayUnit = string.Empty;

foreach (KeyValuePair<string, object> payload in eventPayload)
{
var key = payload.Key;
Expand All @@ -171,18 +170,33 @@ private void ExtractAndPostMetric(string eventSourceName, IDictionary<string, ob
{
counterDisplayName = payload.Value.ToString();
}
else if (key.Equals("DisplayUnits", StringComparison.OrdinalIgnoreCase))
{
counterDisplayUnit = payload.Value.ToString();
}
else if (key.Equals("Mean", StringComparison.OrdinalIgnoreCase))
{
actualValue = Convert.ToDouble(payload.Value, CultureInfo.InvariantCulture);
if (long.TryParse(payload.Value.ToString(), out var longValue))
{
actualValue = longValue;
metricTelemetry.Type = InstrumentationType.Counter;
}
else
{
actualValue = Convert.ToDouble(payload.Value, CultureInfo.InvariantCulture);
metricTelemetry.Type = InstrumentationType.DoubleCounter;
}
}
else if (key.Equals("Increment", StringComparison.OrdinalIgnoreCase))
{
if (long.TryParse(payload.Value.ToString(), out var longValue))
{
actualValue = longValue;
metricTelemetry.Type = InstrumentationType.Gauge;
}
else
{
actualValue = Convert.ToDouble(payload.Value, CultureInfo.InvariantCulture);
metricTelemetry.Type = InstrumentationType.DoubleGauge;
}

// Increment indicates we have to calculate rate.
actualValue = Convert.ToDouble(payload.Value, CultureInfo.InvariantCulture);
calculateRate = true;
}
else if (key.Equals("IntervalSec", StringComparison.OrdinalIgnoreCase))
Expand All @@ -195,87 +209,29 @@ private void ExtractAndPostMetric(string eventSourceName, IDictionary<string, ob
EventCountersInstrumentationEventSource.Log.EventCounterRefreshIntervalLessThanConfigured(actualInterval, this.options.RefreshIntervalSecs);
}
}
else if (key.Equals("Count", StringComparison.OrdinalIgnoreCase))
hananiel marked this conversation as resolved.
Show resolved Hide resolved
{
actualCount = Convert.ToInt32(payload.Value, CultureInfo.InvariantCulture);
}
else if (key.Equals("CounterType", StringComparison.OrdinalIgnoreCase))
{
var isRate = eventPayload.ContainsKey("Increment");

if (payload.Value.Equals("Sum"))
{
if (isRate)
{
metricTelemetry.Type = MetricType.LongGauge;
}
else
{
metricTelemetry.Type = MetricType.LongSum;
}

if (string.IsNullOrEmpty(counterDisplayUnit))
{
counterDisplayUnit = "count";
}
}
else if (payload.Value.Equals("Mean"))
{
if (isRate)
{
metricTelemetry.Type = MetricType.DoubleGauge;
}
else
{
metricTelemetry.Type = MetricType.DoubleSum;
}
}
}
else if (key.Equals("Metadata", StringComparison.OrdinalIgnoreCase))
{
var metadata = payload.Value.ToString();
if (!string.IsNullOrEmpty(metadata))
{
var keyValuePairStrings = metadata.Split(',');
foreach (var keyValuePairString in keyValuePairStrings)
{
var keyValuePair = keyValuePairString.Split(':');
if (!metricTelemetry.Properties.ContainsKey(keyValuePair[0]))
{
metricTelemetry.Properties.Add(keyValuePair[0], keyValuePair[1]);
}
}
}
}
}

if (calculateRate)
{
if (actualInterval > 0)
{
metricTelemetry.Sum = actualValue / actualInterval;
metricTelemetry.Value = actualValue / actualInterval;
}
else
{
metricTelemetry.Sum = actualValue / this.options.RefreshIntervalSecs;
metricTelemetry.Value = actualValue / this.options.RefreshIntervalSecs;
EventCountersInstrumentationEventSource.Log.EventCounterIntervalZero(metricTelemetry.Name);
}
}
else
{
metricTelemetry.Sum = actualValue;
metricTelemetry.Value = actualValue;
}

metricTelemetry.Name = counterName;
metricTelemetry.DisplayName = string.IsNullOrEmpty(counterDisplayName) ? counterName : counterDisplayName;
metricTelemetry.EventSource = eventSourceName;

if (!string.IsNullOrEmpty(counterDisplayUnit))
{
metricTelemetry.Properties.Add("DisplayUnits", counterDisplayUnit);
}

metricTelemetry.Count = actualCount;
this.telemetryPublisher.Publish(metricTelemetry);
}
catch (Exception ex)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
using System.Diagnostics.Metrics;
using System.Linq;
using System.Reflection;
using OpenTelemetry.Metrics;

namespace OpenTelemetry.Contrib.Instrumentation.EventCounters.Implementation
{
Expand Down Expand Up @@ -57,19 +56,16 @@ private void StoreValue(MetricKey metricKey, MetricInstrument instrument, Metric
{
switch (instrument.Type)
{
case MetricType.LongSum:
case MetricType.LongGauge:
this.longValueStore[metricKey] = (long)metricTelemetry.Sum;
case InstrumentationType.Counter:
case InstrumentationType.Gauge:
this.longValueStore[metricKey] = (long)metricTelemetry.Value;
break;
case MetricType.DoubleGauge:
case MetricType.DoubleSum:
this.doubleValueStore[metricKey] = metricTelemetry.Sum;
break;
case MetricType.Histogram:
hananiel marked this conversation as resolved.
Show resolved Hide resolved
((Histogram<double>)instrument.Instrument).Record(metricTelemetry.Sum);
case InstrumentationType.DoubleGauge:
case InstrumentationType.DoubleCounter:
this.doubleValueStore[metricKey] = metricTelemetry.Value;
break;
default:
throw new InvalidOperationException($"Metric type '{instrument.Type}' is not supported.");
throw new InvalidOperationException($"Instrumentation type '{instrument.Type}' is not supported.");
}
}

Expand All @@ -79,31 +75,18 @@ private MetricInstrument CreateInstrument(MetricTelemetry metricTelemetry, Metri
var eventCounter = eventSource.EventCounters.FirstOrDefault(counter => counter.Name.Equals(metricTelemetry.Name, StringComparison.OrdinalIgnoreCase));

var description = !string.IsNullOrEmpty(eventCounter?.Description) ? eventCounter.Description : metricTelemetry.DisplayName;
var metricType = eventCounter?.Type ?? metricTelemetry.Type;
var instrumentationType = eventCounter?.Type ?? metricTelemetry.Type;
var metricName = !string.IsNullOrEmpty(eventCounter?.MetricName) ? eventCounter.MetricName : metricTelemetry.Name;
var metricInstrument = new MetricInstrument { Type = metricType };
var metricInstrument = new MetricInstrument { Type = instrumentationType };

switch (metricType)
metricInstrument.Instrument = instrumentationType switch
{
case MetricType.DoubleGauge:
metricInstrument.Instrument = this.meter.CreateObservableGauge(metricName, () => this.ObserveDouble(metricKey), description: description);
break;
case MetricType.DoubleSum:
metricInstrument.Instrument = this.meter.CreateObservableCounter(metricName, () => this.ObserveDouble(metricKey), description: description);
break;
case MetricType.LongGauge:
metricInstrument.Instrument = this.meter.CreateObservableGauge<long>(metricName, () => this.ObserveLong(metricKey), description: description);
break;
case MetricType.LongSum:
metricInstrument.Instrument = this.meter.CreateObservableCounter<long>(metricName, () => this.ObserveLong(metricKey), description: description);
break;
case MetricType.Histogram:
metricInstrument.Instrument = this.meter.CreateHistogram<double>(metricName, description: description);
break;
default:
throw new InvalidOperationException($"Metric type '{metricType}' is not supported.");
}

InstrumentationType.DoubleGauge => this.meter.CreateObservableGauge(metricName, () => this.ObserveDouble(metricKey), description: description),
InstrumentationType.DoubleCounter => this.meter.CreateObservableCounter(metricName, () => this.ObserveDouble(metricKey), description: description),
InstrumentationType.Gauge => this.meter.CreateObservableGauge<long>(metricName, () => this.ObserveLong(metricKey), description: description),
InstrumentationType.Counter => this.meter.CreateObservableCounter<long>(metricName, () => this.ObserveLong(metricKey), description: description),
_ => throw new InvalidOperationException($"Instrumentation type '{instrumentationType}' is not supported."),
};
return metricInstrument;
}

Expand Down Expand Up @@ -150,7 +133,7 @@ private sealed class MetricInstrument
{
public Instrument Instrument { get; set; }

public MetricType Type { get; set; }
public InstrumentationType Type { get; set; }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@
// limitations under the License.
// </copyright>

using System.Collections.Generic;
using System.Diagnostics;
using OpenTelemetry.Metrics;

namespace OpenTelemetry.Contrib.Instrumentation.EventCounters.Implementation
{
Expand All @@ -34,28 +32,18 @@ internal class MetricTelemetry
public string EventSource { get; set; }

/// <summary>
/// Gets a dictionary of application-defined property names and values providing additional information about this metric.
/// Gets or sets the values of the metric.
/// </summary>
public Dictionary<string, string> Properties { get; } = new Dictionary<string, string>();

/// <summary>
/// Gets or sets sum of the values of the metric samples.
/// </summary>
public double Sum { get; set; }

/// <summary>
/// Gets or sets the number of values in the sample set.
/// </summary>
public int? Count { get; set; }
public double Value { get; set; }

/// <summary>
/// Gets or sets the display name.
/// </summary>
public string DisplayName { get; set; }

/// <summary>
/// Gets or sets the metric type.
/// Gets or sets the instrumentation type.
/// </summary>
public MetricType Type { get; set; } = MetricType.LongSum;
public InstrumentationType Type { get; set; } = InstrumentationType.Counter;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// <copyright file="InstrumentationType.cs" company="OpenTelemetry Authors">
// 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.
// </copyright>

namespace OpenTelemetry.Contrib.Instrumentation.EventCounters
{
/// <summary>
/// Defines the type of the created instrumentation.
/// </summary>
public enum InstrumentationType
{
/// <summary>
/// Creates a counter instrumentation of long values which is an instrument that reports monotonically
/// increasing values.
/// </summary>
Counter = 0,

/// <summary>
/// Creates a counter instrumentation of double values which is an instrument that reports monotonically
/// increasing values.
/// </summary>
DoubleCounter = 1,

/// <summary>
/// Creates a gauge instrumentation of long values which is an instrument that reports
/// non-additive values. An example of a non-additive
/// value is the room temperature - it makes no sense to report the temperature value
/// from multiple rooms and sum them up.
/// </summary>
Gauge = 2,

/// <summary>
/// Creates a gauge instrumentation of double values which is an instrument that reports
/// non-additive values. An example of a non-additive
/// value is the room temperature - it makes no sense to report the temperature value
/// from multiple rooms and sum them up.
/// </summary>
DoubleGauge = 3,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ public static class OptionsExtensions
/// <param name="options">The options to check for the event source.</param>
/// <param name="eventSource">Name of the event source to check for existence.</param>
/// <returns>True if the event source was already added, otherwise false.</returns>
public static bool HasEventSource(this EventCountersOptions options, string eventSource) => options.Sources.Any(provider => provider.EventSourceName.Equals(eventSource, System.StringComparison.OrdinalIgnoreCase));
public static bool HasEventSource(this EventCountersOptions options, string eventSource)
{
return options.Sources.Any(provider => provider.EventSourceName.Equals(eventSource, StringComparison.OrdinalIgnoreCase));
}

/// <summary>
/// Adds a custom event source.
Expand Down Expand Up @@ -84,16 +87,16 @@ public static EventSourceOption WithCounters(this EventSourceOption eventSource,
/// <param name="eventSource">The option to add the event counter to.</param>
/// <param name="counterName">Name of the event counter.</param>
/// <param name="description">The metric description.</param>
/// <param name="metricType">The type of the metric.</param>
/// <param name="instrumentationType">The type of the instrumentation that will be created.</param>
/// <param name="metricName">Optional name of the published metric. Otherwise the counter name will be used.</param>
/// <returns>The event source instance to define event counters.</returns>
public static EventSourceOption With(this EventSourceOption eventSource, string counterName, string description, MetricType metricType, string? metricName = null)
public static EventSourceOption With(this EventSourceOption eventSource, string counterName, string description, InstrumentationType instrumentationType, string? metricName = null)
{
eventSource.EventCounters.Add(new EventCounter
{
Name = counterName,
Description = description,
Type = metricType,
Type = instrumentationType,
MetricName = metricName,
});

Expand Down
Loading