首页 > 解决方案 > 除非定义了新的侦听器或管道,否则不会在 EventListener 中使用 Dotnet EventCounter

问题描述

我们使用事件计数器来记录速率和计量指标,我们正在扩展IncrementingEventCounterPollingCounter使用它们,如下所示:

public sealed class GaugeCounter : PollingCounter
{
  public GaugeCounter(EventSource eventSource, string name,Func<double> metricProvider)
   : base(name.NotWhiteSpace(),eventSource,metricProvider)
        {}
}

public sealed class RateCounter : IncrementingEventCounter
{
   public RateCounter(EventSource eventSource,string name)
     : base(name.NotWhiteSpace(), eventSource)
     {}
}

public sealed class MetricsNamespace
{
  public MetricsNamespace(EventSource eventSource,string @namespace)
  {
    _eventSource = eventSource;
    _namespace = @namespace.NotWhiteSpace();
  }

  public GaugeCounter CreateGaugeCounter(string name,Func<double> metricProvider) =>
    new GaugeCounter(_eventSource,GetCounterName(name.NotWhiteSpace()),metricProvider);

  public RateCounter CreateRateCounter(string name) =>
    new RateCounter(_eventSource,GetCounterName(name.NotWhiteSpace()));
}

此外,我们实现了事件计数器侦听器,它实现了两个功能OnEventSourceCreated,并OnEventWritten在创建事件侦听器和编写事件时运行逻辑:

private void OnEventSourceCreated(object? sender,EventSourceCreatedEventArgs eventSourceCreatedEventArgs)
{
  EnableEvents(
    eventSourceCreatedEventArgs.EventSource,
    EventLevel.LogAlways,
    EventKeywords.None,
    new Dictionary<string, string?> { { "EventCounterIntervalSec", _sampleInterval.TotalSeconds.ToString(CultureInfo.InvariantCulture) } });
}

private void OnEventWritten(object? sender,EventWrittenEventArgs eventWrittenEventArgs)
{
  var eventPayload = (IDictionary<string, object>)eventWrittenEventArgs.Payload.NotNull()[0].NotNull();
  var metric = Metric.Parse(eventPayload);
  _metrics[$"{eventWrittenEventArgs.EventSource.Name}|{metric.Name}"] = metric.Value;
}

使用示例如下:

_hitRateCounter = metricsNamespace.CreateRateCounter(nameof(_hitRateCounter));
_hitRateCounter.Increment();

令人惊讶的是,当我们在构造函数中使用它时,代码工作正常,但是当函数中定义的计数器时,监听器没有消耗事件:

public class MyClass 
{

  public MyClass() 
  {
    // working
    _hitRateCounter = metricsNamespace.CreateRateCounter(nameof(_hitRateCounter));
    _hitRateCounter.Increment();
  }

  public async Task func() 
  {
    // not working
    _hitRateCounter = metricsNamespace.CreateRateCounter(nameof(_hitRateCounter));
    _hitRateCounter.Increment();
  }
}

我很好奇使用事件计数器有一些限制吗?我们应该总是在构造函数中定义它们吗?或者一段时间后事件源没有轮询新的计数器?

编辑:

我想通了,我正在为任何会遇到同样问题的人进行编辑。Dotnet 和 counters 作为Events&Event Source收集和解析事件 [counters],但是第一次我们声明一个计数器时,有第 3 类初始化和调用CounterGroup。此类负责从计数器中提取新事件。这项工作是在假设指标或计数器在程序开始时初始化并永远存在的情况下完成的。

因此,推荐的方法是在程序启动时创建一次指标(这里没有意外),如果您想在程序启动之外的某个时间创建和处理指标,请确保您至少创建启动时的一个计数器,他EventSource是您正在收听的事件源

附加代码片段作为示例:

public class MyClass 
{

  public MyClass() 
  {
   // dummy counter in order to initialize 
   metricsNamespace.CreateRateCounter(nameof(_hitRateCounter)).Dispose();
  }

  public async Task func() 
  {
    // working
    _hitRateCounter = metricsNamespace.CreateRateCounter(nameof(_hitRateCounter));
    _hitRateCounter.Increment();
  }
}

标签: c#.neteventsmetrics

解决方案


推荐阅读