Slide 1

Slide 1 text

otelcol receiver 自作RTA id:arthur-1 株式会社はてな 2024-05-09 Pepabo Tech Conference #22 春のSREまつり LT 1

Slide 2

Slide 2 text

Arthurと申します 株式会社はてな アプリケーションエンジニア ポケカの練習仲間が欲しい 𝕏: @Arthur1__ 2

Slide 3

Slide 3 text

Mackerel作ってます 3 OTel対応もやってます

Slide 4

Slide 4 text

時間がないので早速 4

Slide 5

Slide 5 text

レギュレーション ● OpenTelemetry CollectorのReceiver(Scraper)を作る ○ Scraper: 一定間隔でデータを取りに行く ● sample.ultimate_answerという名前で、常に42という値を持つ メトリックを作る ○ configで渡したsample.answererを属性として持つ ● 任意のexporterでメトリックが確認できたらタイマーストップ ● LTの時間だと少々無理があるのでつくりおきOK ○ RTAというより3分クッキング 5

Slide 6

Slide 6 text

チャート ● metadata.ymlを記述 ● mdatagenでコード生成 ● configを実装 ● scraperを実装 ● factoryを実装 ● debug exporterと組み合わせてbuildして動作確認 6

Slide 7

Slide 7 text

以降の資料は投影しません Xの #pepabotech で 投稿したものをご参照ください 7

Slide 8

Slide 8 text

ディレクトリの準備 8 Componentごと階層を切る習慣がある sampleという名前の自作Receiverを作るなら receiver/samplereceiver という感じ $ mkdir receiver/samplereceiver $ go mod init samplereceiver

Slide 9

Slide 9 text

mdatagenのインストール mdatagen: メタデータを記述したYAMLからCollectorに関する コード生成をしてくれるCLIツール v0.100.0現在、通常のgo install・go runが失敗する(#9281) ため、ソースコードを手元に用意してinstallしよう 9 $ git clone [email protected]:open-telemetry/opentelemetry-collector.git $ cd opentelemetry-collector/cmd/mdatagen $ go install . $ mdatagen -h

Slide 10

Slide 10 text

metadata.yaml 10 type: sample status: class: receiver stability: development: [metrics] codeowners: active: [Arthur1] attributes: sample.answerer.name: type: string description: Answerer name metrics: sample.ultimate_answer: enabled: true description: Ultimate Answer unit: 1 gauge: value_type: double attributes: [sample.answerer.name] レギュレーションに書かれていた 内容を大体ここで定義している

Slide 11

Slide 11 text

metadata.yamlのスキーマ 11 (少なくとも私の環境では)GCP Blueprint Metadataファイル だと誤検知されて、エラーが出まくって困る

Slide 12

Slide 12 text

metadata.yamlのスキーマ 12 otelcolのリポジトリでオレオレフォーマットのスキーマは公開されている が、これではエディタの支援を受けられなくて困る そこで、自家製JSON Schemaをつくりおきしておきました https://github.com/Arthur1/otelcol-metadata-schema

Slide 13

Slide 13 text

コード生成 13 generate.goを作成してコマンドを記述 go generate ./… でコード生成 直接mdatagenを叩くと生成コードのpackage名が定まらないから かエラーになる package samplereceiver //go:generate mdatagen metadata.yaml

Slide 14

Slide 14 text

生成結果 14 テストコード内でNewFactoryがないよと怒られる → これを自分で実装しないといけない

Slide 15

Slide 15 text

NewFactoryには何が必要か 15 こういう依存関係なので、まずConfigから作ろう NewFactory create MetricsReceiver Config Scraper

Slide 16

Slide 16 text

Configの実装 16 要はotelcolのconfigファイルに何を書かせてどう読むかという定義 structを定義して、Default Configを生成する関数を作る type config struct { scraperhelper.ControllerConfig `mapstructure:",squash"` metadata.MetricsBuilderConfig `mapstructure:",squash"` AnswererName string `mapstructure:"answerer_name"` } func defaultConfig() component.Config { cc := scraperhelper.NewDefaultControllerConfig() mbc := metadata.DefaultMetricsBuilderConfig() return &config{ ControllerConfig: cc, MetricsBuilderConfig: mbc, AnswererName: "", } }

Slide 17

Slide 17 text

Scraperの実装 17 type sampleScraper struct { cfg *config mb *metadata.MetricsBuilder } func newScraper(cfg *config, settings receiver.CreateSettings) *sampleScraper { return &sampleScraper{ cfg: cfg, mb: metadata.NewMetricsBuilder(cfg.MetricsBuilderConfig, settings), } } func (s *sampleScraper) scrape(ctx context.Context) (pmetric.Metrics, error) { ts := pcommon.NewTimestampFromTime(time.Now()) s.mb.RecordSampleUltimateAnswerDataPoint(ts, float64(42), s.cfg.AnswererName) return s.mb.Emit(), nil } metadata.yamlから生成したコードに 特定のメトリックを作る関数が含まれている

Slide 18

Slide 18 text

createMetricsReceiverの実装 18 receiver.CreateMetricsFuncという型を満たす関数を作る 先ほど作ったScraperをwrapするイメージ func createMetricsReceiver( _ context.Context, settings receiver.CreateSettings, cfg component.Config, consumer consumer.Metrics, ) (receiver.Metrics, error) { c, ok := cfg.(*config) if !ok { return nil, fmt.Errorf("error") } s := newScraper(c, settings) scraper, err := scraperhelper.NewScraper(metadata.Type.String(), s.scrape) if err != nil { return nil, err } return scraperhelper.NewScraperControllerReceiver( &c.ControllerConfig, settings, consumer, scraperhelper.AddScraper(scraper), ) }

Slide 19

Slide 19 text

NewFactoryの実装 19 ようやく当初の目的のNewFactoryにたどり着いた func NewFactory() receiver.Factory { return receiver.NewFactory( metadata.Type, defaultConfig, receiver.WithMetrics( createMetricsReceiver, metadata.MetricsStability, ), ) } ここまでできたら、生成されたテストコードを動かして 通ることを確認しよう ✅

Slide 20

Slide 20 text

ocbのインストール 20 Receiverの実装はこれにて完結 次はOTel Collectorに作ったReceiverを混ぜてビルドしていく ocb (builder): OTel CollectorをビルドするためのCLIツール YAMLを書いてコード&バイナリ生成 $ go install go.opentelemetry.io/collector/cmd/builder@latest $ builder version # コマンドの名前がデカすぎて固定資産税かかりそうだな! ocb version v0.100.0

Slide 21

Slide 21 text

ocbのYAMLを書く 21 dist: module: my-opentelemetry-collector output_path: ./ version: 0.0.0 receivers: - gomod: samplereceiver v0.0.0 exporters: - gomod: go.opentelemetry.io/collector/exporter/debugexporter v0.100.0 replaces: - samplereceiver => ./receiver/samplereceiver receiverに先ほど作ったpackageを、exporterにdebugexporterを指定 ローカルのコードを参照するのでreplaces(go.modのreplaceディレク ティブに相当)を忘れずに

Slide 22

Slide 22 text

ビルド go.modやmain.goなどがコード生成され、 最終的にotelcol-customというバイナリができる 22 $ # Receiverのコーディングはもう終わってるのでプロジェクトのルートに戻る $ test -d receiver/samplereceiver $ builder --config ./builder-config.yaml 2024-05-07T09:56:29.124+0900 INFO internal/command.go:125 OpenTelemetry Collector Builder {"version": "", "date": "unknown"} … $ test -f ./otelcol-custom

Slide 23

Slide 23 text

実行 ここまで来たらもう少し (残りは利用者目線) otelcolのconfigを書いて 実行しよう 23 receivers: sample: answerer_name: arthur-1 collection_interval: 30s exporters: debug: verbosity: detailed service: pipelines: metrics: receivers: [sample] exporters: [debug] $ ./otelcol-custom --config otelcol-config.yaml

Slide 24

Slide 24 text

実行結果 24 debugexporterは、メトリックの中身をログに出力してくれる

Slide 25

Slide 25 text

ここでタイマーストップ 25

Slide 26

Slide 26 text

完走した感想を話す 26

Slide 27

Slide 27 text

これまで作った自作receiver https://github.com/Arthur1/opentelemetry-collector- arthur1 リポジトリで公開中 ● runnreceiver ○ runnで実行したシナリオテストの結果をメトリック として送る ● cloudflaremetricsreceiver ○ Cloudflareの分析メトリック(ゾーンへのHTTPリク エスト数とか)を収集する 27

Slide 28

Slide 28 text

THE END 28 最後までご清聴いただき ありがとうございました