2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

はじめに

System.Diagnostics.Metricsの記事で軽く触れた、MetricsEventSourceなるものについて、こちらで解説を入れる。
System.Diagnostics.Metricsについての基本的なことについては上記記事を参照のこと。

MetricsEventSourceとは

簡単に言うと、 Metricsで各種Instrumentが出している値を、EventSourceのイベントとして出力しているクラス である。
EventSourceについてはdocs.microsoft.comの記事を参照。

普通InstrumentはMetricsListenerで拾うのが筋だが、外部ツール等で情報を一時的に収集したいときなどに使う。
dotnet-traceでEventSourceのイベントをEventPipe経由で収集できるので、MetricsEventSourceを指定して収集するというわけである。

使い方

サンプルプログラム

今回は例として以下のようなプログラムを走らせるとする。
このプログラムでは、

  • Meterの名前"appmeter"を作成
  • Counter<int>のカウンター"counter1"を作成
  • "counter1"の値2で、tag1=1とtag1=2となるイベントを交互に500msecの感覚で発生させる

ということを行っている。

using System.Diagnostics.Metrics;

{
    Console.WriteLine(System.Diagnostics.Process.GetCurrentProcess().Id);
    using var meter = new Meter("appmeter");
    var counter = meter.CreateCounter<int>("counter1", "unit", "desc");
    async Task CounterTask(CancellationToken ct)
    {
        int count = 2;
        int tagval = 1;
        while(!ct.IsCancellationRequested)
        {
            await Task.Delay(500).ConfigureAwait(false);
            if(counter.Enabled)
            {
                counter.Add(count,
                    new KeyValuePair<string, object?>("tag1", tagval)
                    );
            }
            tagval = tagval ^ 3;
        }
    }
    using var cts = new CancellationTokenSource();
    await Task.WhenAll(CounterTask(cts.Token), Task.Run(() =>
    {
        // エンターキーを押したら終了
        Console.ReadLine();
        cts.Cancel();
    }));
}

収集の開始

収集の開始はdotnet-trace collectを使用する。ここで指定するプロバイダはSystem.Diagnostics.Metricsで、簡単な例として以下のように指定する。

dotnet-trace collect -p [対象プロセスのPID] --providers "System.Diagnostics.Metrics:::Metrics=appmeter"

このコマンドの--providersの引数でMetricsEventSourceの監視対象や監視間隔を指定できる。この--providersの引数の構造だが、
[EventSource名]:[監視フラグ(デフォルト0xffffffff=全て]:[レベル(デフォルト5=Verbose)]:[EventSource固有の引数(';'区切りのA=B形式)]のようになっている。
つまり、上記コマンドの意味は、

  • System.Diagnostics.Metricsという名前のEventSource名の
  • イベントの監視フラグを全て立て
  • 監視レベルを5にして
  • System.Diagnostics.Metricsへの引数としてMetrics=appmeterというキーと値を渡す

という意味になる。
System.Diagnostics.Metricsへ渡せるパラメーターとして、以下のようなものがある

  • SessionId
    • トレースセッションを判別するためのID
    • 一つのトレース開始から終了まで保持され、各MetricsEventSourceで発生するイベントに値が付与される
    • デフォルトはランダムなGUID
  • Metrics
    • 何のInstrumentを監視するか指定する
    • 形式は[Meter名]あるいは[Meter名]\[カウンタ名]の二つがある
    • 複数監視する場合は";"で区切る
      • dotnet-traceの引数リストは;で分ける仕様なので、値部分を二重引用符(")で囲むこと
  • RefreshInterval
    • カウンタの値をとる間隔(sec)
    • doubleなので、0.5秒のような指定も可
    • MetricsEventSourceは記録された値を保持する処理をするものがあるので、メモリ制約にも気を付けること
  • MaxTimeSeries
    • 一つのセッションで記録されるInstrumentの数
    • 早い者勝ち
    • デフォルトは1000
    • 超えた場合、
    • ここで保持のためのメモリを消費するのはMeterを保持している側なので注意
  • MaxHistograms
    • 一つのセッションで記録されるHistograms/ObservableGaugeの数
    • デフォルトは20
    • 超えた場合、HistogramLimitReachedイベントが起こり、それ以降Histogram系メトリックが作成されても新規追加されなくなる

イベントキーワード

EventSourceには、キーワードというフラグのようなものがあり、これを指定することによってカテゴリごとに収集するかしないかを指定できる。実際はenumなので、指定するときは数値型に直して指定することになる。

MetricsEventSourceで指定できるキーワードは以下

  • Messages(0x1) : 主にデバッグ用途で発生されるイベントのキーワード
  • TimeSeriesValues(0x2) : 実際の値が収集されたイベントのキーワード
  • InstrumentPublishing(0x4) : Instrumentが作成されたときに発生するイベントのキーワード

発生しうるイベント

Message(1)

Keyword=Messages

主にデバッグ用途で使われるその他のメッセージ。
パラメーターはstring messageのみ

CollectionStart(2)

Keyword=TimeSeriesValue

RefreshIntervalで設定された秒数ごとに発生する、メトリックの収集開始イベント
渡されてくるパラメーターは、

  • string sessionId : セッションID(イベントパラメーターSessionIdの値)
  • DateTime intervalStartTime : 収集開始時刻
  • DateTime intervalEndTime : 次の収集開始時刻

の三つ

CollectionStop(3)

Keyword=TimeSeriesValue

メトリック収集が終わったら発生するイベント。渡される引数はCollectionStartと同一

CounterRateValuePublished(4)

Keyword=TimeSeriesValue

Counter<T> と、 ObservableCounter<T> の値を収集したときに発生するイベント。
パラメーターは以下

  • string sessionId : セッションID
  • string meterName : Meter 作成時に指定した名前
  • string meterVersion : Meter 作成時に指定した名前
  • string instrumentName : Instrumentを作成時に指定した名前
  • string unit : Instrument作成時に指定した単位
  • string tags : 収集時に追加されたタグの、 , 区切りのキーと値のペア(なければ空文字列)
  • string rate : 増分(少数と整数両方の場合が存在)

rateには Counter<T> は、前回収集された時点からAddされた値の総計値が渡される。
ObservableCounter<T> は、 [その時収集した値] - [前回収集した値] の値が渡される。

実際の出力(CSV)

GaugeValuePublished(5)

Keyword=TimeSeriesValue

ObservableGauge<T> の値を収集したときに発生するイベント。
パラメーターは以下

  • string sessionId : セッションID
  • string meterName : Meter 作成時に指定した名前
  • string meterVersion : Meter 作成時に指定した名前
  • string instrumentName : Instrumentを作成時に指定した名前
  • string unit : Instrument作成時に指定した単位
  • string tags : 収集時に追加されたタグの、 , 区切りのキーと値のペア(なければ空文字列)
  • string lastValue : その時収集された値

実際の出力(CSV)

HistogramValuePublished(6)

Keyword=TimeSeriesValue

Histogram<T> の値を収集したときに発生するイベント
パラメーターは以下

  • string sessionId : セッションID
  • string meterName : Meter 作成時に指定した名前
  • string meterVersion : Meter 作成時に指定した名前
  • string instrumentName : Instrumentを作成時に指定した名前
  • string unit : Instrument作成時に指定した単位
  • string tags : 収集時に追加されたタグの、 , 区切りのキーと値のペア(なければ空文字列)
  • string quantiles : 前回収集された後に発行されたRecord(value)の値の50%ile、95%ile、99%ileの値を、以下の形式でフォーマットしたもの(高い値の方が1に近くなる)
    • 0.5=[50%ileの値];0.95=[95%ileの値];0.99=[99%ileの値]

実際の出力(CSV)

BeginInstrumentReporting(7)/EndInstrumentReporting(8)

Keyword=TimeSeriesValue

Instrumentの監視を開始/終了したときに発生する。
パラメーターは以下

  • string sessionId : セッションID
  • string meterName : Meter 作成時に指定した名前
  • string meterVersion : Meter 作成時に指定した名前
  • string instrumentName : Instrumentを作成時に指定した名前
  • string instrumentType : Instrumentの型
  • string unit : Instrument作成時に指定した単位
  • string description : Instrument作成時に指定した概要

Error(9)

Keyword=TimeSeriesValues | Messages | InstrumentPublishing

なにがしかの例外が、Instrument監視中に内部で発生したときに発生するイベント
パラメーターは以下

  • string sessionId : セッションID
  • string errorMessage : エラーメッセージ

InitialInstrumentEnumerationComplete(10)

Keyword=TimeSeriesValues | InstrumentPublishing

セッションの初期化が終わって、監視を開始する時に発生するイベント
パラメーターは以下

  • string sessionId : セッションID

InstrumentPublished(11)

Keyword=InstrumentPublishing

Instrumentが作成されて、セッションに捕捉されたときに発生するイベント。
セッションの開始以前に作られたInstrumentは初期化後にこのイベントが発生し、監視対象に入れられる

TimeSeriesLimitReached(12)

Keyword=TimeSeriesValues

監視されるInstrumentの数がMaxTimeSeriesに到達したときに発生するイベント。
パラメーターは string sessionId のみ。

これ以後新規に発生するメトリックに関しては、イベントパラメーターMetricsに合致しても無視される。

なお、タグの値が別でも別物として扱われることに注意。
(tag1=aとtag1=bのメトリックがあると、それぞれTimeSeriesとしては別物として扱われる)

HistogramLimitReached(13)

Keyword=TimeSeriesValues

監視されるHistogram<T>の数が上限に達したときに発生するイベント。
パラメーターはstring sessionIdのみ。

これ以後新規に発生するHistogram<T>のメトリックに関しては無視される。

Histogramのカウントに現在バグがあるので、MaxHistogramsの値は必ず超えないようにすること。
なお、修正PRはマージされているので遅くともnet7.0にはこの問題は解消する。

ObservableInstrumentCallbackError(14)

Keyword=TimeSeriesValues

ObservableInstrument<T> のコールバックの中で例外が発生したときに呼ばれる。
パラメーターは以下。

  • string sessionId : セッションID
  • string errorMessage : エラーメッセージ

MultipleSessionsNotSupportedError(15)

Keyword=TimeSeriesValues | Messages | InstrumentPublishing

MetricsEventSourceは 現在二つ以上のセッションを同時展開することはできない仕様となっている。
このイベントは、セッションを追加しようとしたときに発生するエラーイベントとなる。
引数はstring sessionIdのみ

注意点

執筆時点の最新版リリースでは以下の問題がある

終わりに

Metricsの監視をアプリに組み込む場合は普通にMetricsListenerで処理すればいい話なので、MetricsEventSourceを使う機会は少ないかもしれない。
しかし、こういうものが存在するということがわかっていれば、例えば開発中や、あるいは緊急対応の時などにアドホックに値を監視することによって、トラブルシューティングの役に立つかもしれない。

注意点を最後に挙げたが、これは修正され次第また記事を更新することにする。

参考リンク

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?