🎁

telemetrygenでTail Sampling Processorの挙動をサクッと確認する

2024/03/03に公開

テレメトリーデータを効率的に管理するために、Sampling は重要な役割を果たします。Tail Sampling は Sampling の形式の一種で、ユーザーが指定した条件に合致する特別な Trace のみを Observability Backend に送信するという特徴があります。

Tail Sampling の実装は複数存在しますが、その内の 1 つとして、OpenTelemetry Collector (Tail Sampling Processor) が存在します。

https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/processor/tailsamplingprocessor/README.md

今回は、telemetrygen というツールを使用して、Tail Sampling Processor の挙動を簡単に確認する方法をご紹介します。

telemetrygenとは?

telemetrygen は、デモ・検証用に各種テレメトリーデータを生成するためのツールです。

This utility simulates a client generating traces, metrics, and logs. It is useful for testing and demonstration purposes.

https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/cmd/telemetrygen

https://opentelemetry.io/docs/collector/quick-start/ で紹介されているので、ご存じの方もいらっしゃるかもしれません。

今回は、Tail Sampling Processor の挙動の簡単な確認なので、telemetrygen でサクッと確認してみましょう。

※ アプリケーションの計装を踏まえた Tail Sampling の挙動をローカルで確認する場合は、計装済みのアプリケーションコンテナも起動して確認する方が確実かと思います。

telemetrygenを利用した動作確認

ここからは実際の動作確認の手順になります。

下記のような OpenTelemetry Collector の設定ファイルを用意します。tail_samplingの箇所には特定の Attribute を確認するポリシーとSpan Status (status code) を確認するポリシー、2 つのポリシーが定義されています。

今回は、ポリシーの評価結果を確認するために、debug exporter を利用しています。

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317

processors:
  tail_sampling:
    decision_wait: 10s
    num_traces: 10
    expected_new_traces_per_sec: 10
    policies:
      [
          {
            name: test-policy,
            type: string_attribute,
            string_attribute: {key: foo, values: [bar, baz]}
          },
          {
            name: test-policy-2,
            type: status_code,
            status_code: {status_codes: [ERROR, UNSET]}
          }
      ]

exporters:
  debug:
    verbosity: detailed

extensions:
  zpages: {}
service:
  telemetry:
    logs:
      level: "debug"
  extensions: [zpages]
  pipelines:
    traces:
      receivers: [otlp]
      processors: [tail_sampling]
      exporters: [debug]

この設定ファイルを読み込んだ上で、OpenTelemetry Collector を起動します。

$ docker run \
  -p 127.0.0.1:4317:4317 \
  --rm \
  -v ./otel-config.yaml:/etc/otelcol/config.yaml \
  otel/opentelemetry-collector-contrib:0.95.0 \
  --config=/etc/otelcol/config.yaml

続けて、別のターミナルを開いて、foo=barという Attribute を付与した trace を telemetrygen を用いて生成します。

この場合、生成された trace は policies で設定された 1 つ目の条件に合致するはずなので、正常に Sampling されるはずです。また、Span Status (status code) は未設定の時はデフォルトで UNSET になるので、2 つ目の条件にも合致します。

$ telemetrygen traces --otlp-insecure --traces 3 --telemetry-attributes foo=\"bar\"

OpenTelemetry Collector 側のログを確認すると "sampled": 6 となっており、Sampling されていることがわかります。

生成した trace の数より多い数字がログに出ていますが、これは trace が各ポリシーごとに評価された上で sampled / notSampledがカウントされているためです。

2024-03-03T05:14:36.165Z        debug   tailsamplingprocessor@v0.95.0/processor.go:202  Sampling Policy Evaluation ticked       {"kind": "processor", "name": "tail_sampling", "pipeline": "traces"}
2024-03-03T05:14:36.165Z        debug   sampling/string_tag_filter.go:95        Evaluting spans in string-tag filter    {"kind": "processor", "name": "tail_sampling", "pipeline": "traces", "policy": "string_attribute"}
2024-03-03T05:14:36.165Z        debug   sampling/status_code.go:54      Evaluating spans in status code filter  {"kind": "processor", "name": "tail_sampling", "pipeline": "traces", "policy": "status_code"}
2024-03-03T05:14:36.166Z        info    TracesExporter  {"kind": "exporter", "data_type": "traces", "name": "debug", "resource spans": 1, "spans": 2}
2024-03-03T05:14:36.166Z        info    ResourceSpans #0
Resource SchemaURL:
Resource attributes:
     -> service.name: Str(telemetrygen)
ScopeSpans #0
ScopeSpans SchemaURL:
InstrumentationScope telemetrygen
Span #0
    Trace ID       : a987128b2b4126afb053543628c7c042
    Parent ID      : 659af8c8738b4adf
    ID             : c284897f1e183fb0
    Name           : okey-dokey-0
    Kind           : Server
    Start time     : 2024-03-03 05:14:26.047258 +0000 UTC
    End time       : 2024-03-03 05:14:26.047381 +0000 UTC
    Status code    : Unset
    Status message :
Attributes:
     -> net.peer.ip: Str(1.2.3.4)
     -> peer.service: Str(telemetrygen-client)
     -> foo: Str(bar)
Span #1
    Trace ID       : a987128b2b4126afb053543628c7c042
    Parent ID      :
    ID             : 659af8c8738b4adf
    Name           : lets-go
    Kind           : Client
    Start time     : 2024-03-03 05:14:26.047258 +0000 UTC
    End time       : 2024-03-03 05:14:26.047381 +0000 UTC
    Status code    : Unset
    Status message :
Attributes:
     -> net.peer.ip: Str(1.2.3.4)
     -> peer.service: Str(telemetrygen-server)
     -> foo: Str(bar)
        {"kind": "exporter", "data_type": "traces", "name": "debug"}
...
2024-03-03T05:14:36.166Z        debug   tailsamplingprocessor@v0.95.0/processor.go:232  Sampling policy evaluation completed    {"kind": "processor", "name": "tail_sampling", "pipeline": "traces", "batch.len": 3, "sampled": 6, "notSampled": 0, "droppedPriorToEvaluation": 0, "policyEvaluationErrors": 0}

1 つ目のポリシー (test-policy) に合致しない Attribute を定義して trace を生成すると、"sampled": 3, "notSampled": 3という風にログに出力されます。

$ telemetrygen traces --otlp-insecure --traces 3 --telemetry-attributes foo=\"notSampled\"
2024-03-03T06:12:37.720Z        debug   sampling/status_code.go:54      Evaluating spans in status code filter  {"kind": "processor", "name": "tail_sampling", "pipeline": "traces", "policy": "status_code"}
2024-03-03T06:12:37.721Z        info    TracesExporter  {"kind": "exporter", "data_type": "traces", "name": "debug", "resource spans": 1, "spans": 2}
2024-03-03T06:12:37.721Z        info    ResourceSpans #0
Resource SchemaURL:
Resource attributes:
     -> service.name: Str(telemetrygen)
ScopeSpans #0
ScopeSpans SchemaURL:
InstrumentationScope telemetrygen
Span #0
    Trace ID       : 4335c416994d3d99e249c9724b9d8e9b
    Parent ID      : 9c267ca5f50814d4
    ID             : 670873572e816a65
    Name           : okey-dokey-0
    Kind           : Server
    Start time     : 2024-03-03 06:12:27.354395 +0000 UTC
    End time       : 2024-03-03 06:12:27.354518 +0000 UTC
    Status code    : Unset
    Status message :
Attributes:
     -> net.peer.ip: Str(1.2.3.4)
     -> peer.service: Str(telemetrygen-client)
     -> foo: Str(notSampled)
Span #1
    Trace ID       : 4335c416994d3d99e249c9724b9d8e9b
    Parent ID      :
    ID             : 9c267ca5f50814d4
    Name           : lets-go
    Kind           : Client
    Start time     : 2024-03-03 06:12:27.354395 +0000 UTC
    End time       : 2024-03-03 06:12:27.354518 +0000 UTC
    Status code    : Unset
    Status message :
Attributes:
     -> net.peer.ip: Str(1.2.3.4)
     -> peer.service: Str(telemetrygen-server)
     -> foo: Str(notSampled)
        {"kind": "exporter", "data_type": "traces", "name": "debug"}
...
2024-03-03T06:12:37.722Z        debug   tailsamplingprocessor@v0.95.0/processor.go:232  Sampling policy evaluation completed    {"kind": "processor", "name": "tail_sampling", "pipeline": "traces", "batch.len": 3, "sampled": 3, "notSampled": 3, "droppedPriorToEvaluation": 0, "policyEvaluationErrors": 0}

いかがだったでしょうか?

今回の検証では簡単なポリシーを定義した上で動作確認を行いましたが、Tail Sampling Processor では正規表現を利用した Attribute のチェックや policy の AND 条件など他にも様々な条件を設定することができます。

複雑なポリシーを定義するとポリシーが意図通りに評価されているか確認したくなると思いますが、そんな時の検証手段として telemetrygen を一考いただけるといいかと思います。

参考

Discussion