Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
breakoutModefull-width
languagec#
  public class MetricSample : BaseDevice<MetricSampleConfiguration>
  {
    private IHistogram m_SendDurationHistogram;   // measure the time taken to send the payload

    public override void Start()
    {
      // make sure you call InitializeMetrics
      InitializeMetrics();
    }
    protected override void InitializeMetrics()
    {
      // construct your metrics here
      m_SendDurationHistogram = GetOrCreateHistogram("MyDevice.send_duration_in_s",                           // name of your metric. See notes about X.y syntax
                                                     "The duration (in seconds) to send to the foo service",  // description
                                                     new HistogramConfiguration                               // configuration
                                                     {
                                                       LabelNames = new[] { "Group", "Tab", "Channel", "ChannelKey" },          // associate this metric with the owner channel
                                                       Buckets = new double[] { 0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5, 10 }  // buckets (in seconds)
                                                     }).WithLabels(MessageChannel.GroupName, MessageChannel.TabName, MessageChannel.ChannelName, MessageChannel.ChannelKeyString);
    }

    public override Task ProcessMessageAsync(IMessageContext context, CancellationToken cancellationToken)
    {
      // ...your code           
      using (m_SendDurationHistogram.NewTimer())    // the Histogram.NewTimer() method is used to measure the wrapped methods duration.
      { 
        await SendToFooServiceAsync(...).ConfigureAwait(false);
      }
      // ... your code
    }
  }
  • The histogram is defined on line 3 (using the interface type)

  • The InitializeMetrics() method is called in your Start method.

  • The histogram is created in the InitializeMetrics method.

  • The operation to be measured is wrapped with the .NewTimer() method. The NewTimer method is a specialized function of the histogram type for measuring duration (in seconds). Other operations (like size) are measured using the .Observe(X) method.

Info

The InitializeMetrics method is called by the base class any time a user changes the metrics configuration. By initializing your metrics in this override, your metric(s) will automatically enable and disable without requiring a service restart.

The GetOrCreateX methods all take a name, description, and configuration parameter. Names must be globally unique, so you should namespace your metric using the notation Namespace.metric_name. The portion in front of the . is the namespace and is displayed in the UI as a separate block. This is typically your device name. The portion after the . is the name as presented to Prometheus. connexion_ is automatically added to your name for ease of use within Grafana. Note that convention is to use all lower-case with underscore separators for the name (the namespace can be upper case and is removed from the Prometheus name).

...

The configuration object defines the labels and buckets for the histogram:

Code Block
languagec#
new HistogramConfiguration
{
  LabelNames = new[] { "Group", "Tab", "Channel", "ChannelKey" },          
  Buckets = new double[] { 0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5, 10 }
}).WithLabels(MessageChannel.GroupName,
              MessageChannel.TabName, 
              MessageChannel.ChannelName, 
              MessageChannel.ChannelKeyString);

The LabelNames collection defines the labels which will be supplied for this metric. It is convention to include Group, Tab, Channel, and ChannelKey labels. Add additional labels as needed. For example, a “TargetUri” label would enable you to break down metrics on a per-target basis.

The Buckets collection defines the buckets into which each metric will be placed. Duration is measured in seconds in Grafana, so our buckets are [up to 1ms], [1ms to 5ms], [5ms to 10ms]…[10 seconds]. Values greater than 10 seconds go into a special infinite bucket.

The .WithLabels(...) method creates a child metric with the given label values. In this case, the label values never change, so we can define our class-level histogram using the .WithLabels(...) method. In some cases, the label values will change dynamically. In this cases, you should define the class-level histogram without the .WithLabels(...) method, and then use the .WithLabels(...) each time you write a value.

Code Block
breakoutModefull-width
languagec#
m_SendDurationHistogram = new HistogramConfiguration
{
  LabelNames = new[] { "Group", "Tab", "Channel", "ChannelKey" },          
  Buckets = new double[] { 0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5, 10 }
});

public override Task ProcessMessageAsync(IMessageContext context, CancellationToken cancellationToken)
{
  // ...your code
  var dynamicValue = context.Message.SomeValueThatChangesWithEachMessage;
  using (m_SendDurationHistogram.WithLabels(MessageChannel.GroupName, MessageChannel.TabName, MessageChannel.ChannelName, MessageChannel.ChannelKeyString, dynamicValue).NewTimer())
  { 
    await SendToFooServiceAsync(...).ConfigureAwait(false);
  }
  // ... your code
}