🌝

otelcol-contrib を printf デバッグする方法。または、パッチをあてた receiver を含むバイナリをビルドする方法

に公開

opentelemetry-collector はプラグイン機構を備えていることが魅力の一つです。様々な送信先・受信元に対応するためにビルド時点で、何からの受信・送信ができるバイナリを作るかを YAML で設定出来るようになっています。
主なプラグインは opentelemetry-collector-contrib というレポジトリにありますが、この中で管理されているモジュールたちは、たくさんのコントリビューターが寄贈したものであって、クオリティやできる事もまちまちで、玉石混淆という感じです。

otelcol-contrib にあるモジュールを printf debug したくなったときや、パッチを当てたカスタムバージョンを使いたくなったときにどうすればいいかを本稿では解説します。

どのようにビルドするか

普通のプロジェクトであれば、 open-telemetry/opentelemetry-collector-contrib を git clone してきてビルドすれば良いのですが、このレポジトリをサッとみても、どうやってビルドしたら良いのかを理解するのは難しいです。

実は公式ドキュメントに Building a custom collector
というドキュメントがあるのでこれを参考にすれば良いです。

カスタムバイナリを作るための方法を紹介するためのドキュメントとしてよく紹介されている本ドキュメントですが、デバッグをするときにもこのドキュメントを参考にします。

otelcol のビルドは mac 環境などでも手元で行えますが、ちょっといじるぐらいなら、docker container としてビルドしてしまったほうが楽なので、僕はそうしてしまいます。

以下のように Dockerfile を置きます。
ここで、ocb というツールを利用するのですが、このバージョンは builder-config.yaml に書くバージョンと合わせないといけない事に注意。

FROM alpine:3.19 AS certs
RUN apk --update add ca-certificates

FROM golang:1.25.0 AS build-stage
WORKDIR /build

COPY ./builder-config.yaml builder-config.yaml

RUN --mount=type=cache,target=/root/.cache/go-build GO111MODULE=on go install go.opentelemetry.io/collector/cmd/builder@v0.140.0
RUN --mount=type=cache,target=/root/.cache/go-build builder --config builder-config.yaml

FROM gcr.io/distroless/base:latest

ARG USER_UID=10001
USER ${USER_UID}

COPY ./collector-config.yaml /otelcol/collector-config.yaml
COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY --chmod=755 --from=build-stage /build/otelcol-dev /otelcol

ENTRYPOINT ["/otelcol/otelcol-dev"]
CMD ["--config", "/otelcol/collector-config.yaml"]

EXPOSE 4317 4318 12001

builder-config.yaml は以下のように書く。

 
dist:
  name: otelcol-dev
  description: Basic OTel Collector distribution for Developers
  output_path: ./otelcol-dev

exporters:
  - gomod: go.opentelemetry.io/collector/exporter/debugexporter v0.140.0

processors:
  - gomod: go.opentelemetry.io/collector/processor/batchprocessor v0.140.0

receivers:
  - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver v0.131.0

providers:
  - gomod: go.opentelemetry.io/collector/confmap/provider/envprovider v1.18.0
  - gomod: go.opentelemetry.io/collector/confmap/provider/fileprovider v1.18.0
  - gomod: go.opentelemetry.io/collector/confmap/provider/httpprovider v1.18.0
  - gomod: go.opentelemetry.io/collector/confmap/provider/httpsprovider v1.18.0
  - gomod: go.opentelemetry.io/collector/confmap/provider/yamlprovider v1.18.0

ここで、go.opentelemetry.io/collector/ が書いてある行に書いてあるバージョンは ocb のバージョンと合わせないとビルド出来ない、ということです。

最後に collector-config.yaml をおいたらビルド出来ます。

receivers:
  hostmetrics:
    scrapers:
      cpu:

exporters:
  debug:
    verbosity: detailed

service:
  pipelines:
    metrics:
      receivers: [hostmetrics]
      exporters: [debug]

docker build -f Dockerfile -t myotelcol . とかするとビルド出来ます。
docker run --rm myotelcol とかで起動できる感じ。

どのように既存コードを置換するか

ここでは hostmetrics のコードを置換することを考えます。

opentelemetry-collector-contrib のレポジトリをクローンしてきて、v0.140.0 をチェックアウトします。ここでも ocb のバージョンと合わせる必要があることに注意してください。
./receiver/hostmetrics にコピーを入れます。

つぎに builder-config.yaml に replaces: セクションを入れます。

dist:
  name: otelcol-dev
  description: Basic OTel Collector distribution for Developers
  output_path: ./otelcol-dev

exporters:
  - gomod: go.opentelemetry.io/collector/exporter/debugexporter v0.140.0

processors:
  - gomod: go.opentelemetry.io/collector/processor/batchprocessor v0.140.0

receivers:
  - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver v0.131.0

providers:
  - gomod: go.opentelemetry.io/collector/confmap/provider/envprovider v1.18.0
  - gomod: go.opentelemetry.io/collector/confmap/provider/fileprovider v1.18.0
  - gomod: go.opentelemetry.io/collector/confmap/provider/httpprovider v1.18.0
  - gomod: go.opentelemetry.io/collector/confmap/provider/httpsprovider v1.18.0
  - gomod: go.opentelemetry.io/collector/confmap/provider/yamlprovider v1.18.0

replaces: # ここ
  - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver => ../receiver/hostmetricsreceiver

これにより、hostmetricsreceiver がローカルのものに差し替えられます。

Dockerfile の中で receiver をコピーするようにします。

FROM alpine:3.19 AS certs
RUN apk --update add ca-certificates

FROM golang:1.25.0 AS build-stage
WORKDIR /build

COPY ./builder-config.yaml builder-config.yaml
# ここ
COPY ./receiver/ ./receiver/

RUN --mount=type=cache,target=/root/.cache/go-build GO111MODULE=on go install go.opentelemetry.io/collector/cmd/builder@v0.140.0
RUN --mount=type=cache,target=/root/.cache/go-build builder --config builder-config.yaml

FROM gcr.io/distroless/base:latest

ARG USER_UID=10001
USER ${USER_UID}

COPY ./collector-config.yaml /otelcol/collector-config.yaml
COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY --chmod=755 --from=build-stage /build/otelcol-dev /otelcol

ENTRYPOINT ["/otelcol/otelcol-dev"]
CMD ["--config", "/otelcol/collector-config.yaml"]

EXPOSE 4317 4318 12001

最後に以下のようにデバッグメッセージをいれて docker build します。

diff --git receiver/hostmetricsreceiver/factory.go receiver/hostmetricsreceiver/factory.go
index 6df9c0d..300ff94 100644
--- receiver/hostmetricsreceiver/factory.go
+++ receiver/hostmetricsreceiver/factory.go
@@ -64,6 +64,7 @@ func mustMakeFactories(factories ...scraper.Factory) map[component.Type]scraper.

 // NewFactory creates a new factory for host metrics receiver.
 func NewFactory() receiver.Factory {
+       fmt.Printf("NewFactory!!!!!!!!!!!!!!!\n\n")
        return receiver.NewFactory(
                metadata.Type,
                createDefaultConfig,

そうすると、以下のようなメッセージが出ます。

まとめ

ocb を使ってカスタムビルドするときに replaces を使うことでソースコードを差し替えられるので、コレを使ってどんどん開発していきましょう!

さくらインターネット株式会社

Discussion