Slide 1

Slide 1 text

Perlアプリケーションで トレースを実装するまでの 工夫と苦労話 Hatena Engineer Seminar #34 オブザーバビリティの実現と運用編 2025/07/30 id:masayoshi

Slide 2

Slide 2 text

自己紹介 ● id:masayoshi ● 株式会社はてな ○ Platform SRE をしているよ 株式会社はてなでSREとして勤務。 自身の可観測性を高めるために、健康診断に行ったところ、高血圧にひっかかり健康に怯えて生 活をしている。 しかし、エラーバジェットポリシーが設定されていなかったため、食生活の改善は見られない。

Slide 3

Slide 3 text

今日話すこと ● Perlでトレースを使いたい! ○ OpenTelemetryの導入に関して色々な悩みポイントがあった ○ 今回はてなが選択したやり方を紹介するよ! ● 注意点! ○ 細かい話多め ○ Perl固有の話多め ○ パワープレイ多め ○ メジャーな言語ではそもそも問題になってない話題多め

Slide 4

Slide 4 text

(個人的)技術選定のときの心構え ● あったら使え! ○ 仕組みがあるのであれば逆らわずに使おう ● 組み合わせて使え! ○ 1個じゃ無理!でも合わせれば解決!ってパターン ● 足りなければ作れ! ○ どうしても足りないなら自分たちで付け足す ● 出来たら乗り換えろ! ○ 世の中は進化している。世の中に追いつかれたら乗り換える

Slide 5

Slide 5 text

あったら使え! ● 世の中は大OpenTelemetry時代、Perl向けOpenTelemetry SDKがあれば使いたい! ○ あった! ○ https://github.com/jjatria/perl-opentelemetry ● が、検討時 2024年春頃はまだいくつかの問題点があった ○ まだ実装途中のところも多く、破壊的変更が多い ○ OTLPのExporter周りの依存ライブラリやパフォーマンスの問題 ● OpenTelemetry SDKを導入して終了!というわけにいかなかった

Slide 6

Slide 6 text

組み合わせて使え! ● OpenTelemetry 以外の選択肢で AWS::XRay がある ○ https://github.com/fujiwara/AWS-XRay ○ 社内でも採用実績があり、AWS XRayに送っているチームもいた ■ トレースだけならXRayのままでも良い ■ 社内はMackerelで運用しており、OpenTelemetryに対応したトレース機能 の実装を検討していた ● OtelCollectorにXRayのトレースを受け取れる awsxrayreceiver がある ● XRay を OpenTelemetry に変換して使おう! 正確には「Vaxila」というサービスを事業譲受しており、Mackerelとの統合を検討していた

Slide 7

Slide 7 text

大まかな方針 ● PerlはXRayとしてトレースを取得、送信する ● OtelCollector ○ awsxrayreceiverでOpenTelemetryに変換 ○ transform processor で整形 ○ OTLP exporter でMackerelに送信

Slide 8

Slide 8 text

XRayの良いところ ● 仕様がシンプル! ○ 特定のJSONフォーマットを作ってUDPで投げるだけ ■ AWS::XRay も コア部分は500行以下のコードしかない ○ UDPなので、送信処理が同期的でもボトルネックになりにくい ■ TCPかつ、複雑なOTLPの処理と比較して軽量 ● よって、自分たちでコードの付け足しなどが容易 ○ OTLPの仕様やOpenTelemetry全体の仕様を把握するのは大変 ■ 変化も激しい ○ とりあえずJSONつくってUDPで送れれば良し!は相当楽

Slide 9

Slide 9 text

(参考)AWS::XRayと計装 ● Plack::Middleware::XRay ○ HTTPリクエストのspanを取るためのミドルウェア ● Devel::KYTProf::Logger::XRay ○ Devel::KYTProfというツールの出力をspanにするモジュール ● Devel::KYTProf::Profiler::DBI ○ XRayとは直接関係はないが、DBのsqlを表示してくれるモジュール ○ ↑のモジュールと合わせてXRayにDBのspanを送信できる ● 更に詳しく見たい人は実装者のスライドを参照 ○ https://speakerdeck.com/fujiwara3/yapc-tokyo-2019 XRay の segment = OpenTelemetry の span ここでは全部spanと呼ぶことにするよ

Slide 10

Slide 10 text

動いたが問題点もあり! ● アトリビュート関係 ○ 特定のアトリビュートのときに awsxrayreceiver でエラーになる ○ アトリビュートのキー名を自由に設定できない ● トレースIDの伝搬 ○ W3C Trace Context Headerに対応していない ● 自動計装 ○ 自動で計装されて欲しい

Slide 11

Slide 11 text

足りなければ作れ! ● 後述する自動計装の拡張などもあって、結局自分たちで計装を拡張 ○ AWS::XRay のwrapper ○ Devel::KYTProf::Logger::XRay の awsxrayreceiver 対応版 ○ Plack::Middleware::XRay の awsxrayreceiver 対応版 ● やりたいこと ○ Perlでアトリビュートを直感的に追加できる ○ トレースがOtel SDKとPerlのXRayで相互に伝搬できるようになる ○ 自動計装でサクセス!

Slide 12

Slide 12 text

XRayとawsxrayreceiverの仕様の違い { “hatena”: “waiwai”, "code": { "function.name": "test_func" } } ● awsxrayreceiver では map[string]map[string]any しか許容されない ● AWS XRay では map[string]string でも良い 赤字部分がエラーになる

Slide 13

Slide 13 text

awsxrayreceiverの変換方法が微妙 “code”: { “function.name”: “test_func”, “line.number”: 10, } aws.xray.metadata.code = {“function.name”:”test_func”, “line.number”:10} ● prefixが追加される ● 構造がフラットにならない

Slide 14

Slide 14 text

実際のアトリビュート変換の流れ map[string]map[string]any を満たすJSON

Slide 15

Slide 15 text

(参考)transform processorの設定 processors: transform/for_awsxray: error_mode: ignore trace_statements: # aws.xray.metadata.* の prefix を削除 - replace_all_patterns(span.attributes, "key", "^aws\\.xray\\.metadata\\.(.*)", "$$1") # {"":"value"} の場合 value に展開 - replace_all_patterns(span.attributes, "value", "{\"\":\"?([^\"]*)\"?}", "$$1") # {"":["value"]} の場合 ["value"] に展開 - replace_all_patterns(span.attributes, "value", "{\"\":(\\[.*\\])}", "$$1") # エスケープされた改行(\\n)を改行(\n)に戻す - replace_all_patterns(span.attributes, "value", "\\\\n", "\n")

Slide 16

Slide 16 text

TraceIDの伝搬 ● OpenTelemetryで一般的なW3C Trace Context 形式に対応したい ● XRayは X-Amzn-Trace-Id Header形式なので相互変換が必要 ○ W3C Trace Context Header ⇔ X-Amzn-Trace-Id Header

Slide 17

Slide 17 text

TraceIDの伝搬 ● W3C Trace Context Header ⇔ X-Amzn-Trace-Id Header 相互変換 00-0123456789abcdef0123456789abcdef-01234567890abcdef-01 Root=1-01234567-89abcdef0123456789abcdef;Parent=01234567890abcdef;Sampled=1 8桁 24桁 32桁 Trace ID 16桁 16桁 Parent ID (親のSpanID) Flags traceparent: X-Amzn-Trace-Id: 実際には他にも仕様があるけど関係あるところを最低限抜き出してます

Slide 18

Slide 18 text

(参考)Perl豆知識 ~正規表現処理~ my $pattern = qr/^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/; my $traceparent = +{}; if ($header =~ $pattern) { $traceparent->{version} = $1; $traceparent->{trace_id} = $2; $traceparent->{parent_id} = $3; $traceparent->{trace_flags} = $4; return $traceparent; } else { return undef; } 文字列処理ならまかせろり!

Slide 19

Slide 19 text

自動計装 ● 楽しいモンキーパッチ方式! ○ 自動計装モジュールを読み込んだら自動で計装をインジェクトする ● ①メジャーなライブラリを読み込んだときに専用の計装を有効にする ○ Plack::Buiderがあったら、Plack::Middleware::XRay を有効 ○ ロードされるパッケージを確認して読み込み時にコードをインジェクト ● ②関数名などを指定したら自動的にSpanを追加してくれる ○ 今回はパッケージ変数で @TRACE_ENABLE という配列に入っている 関数にSpanをインジェクトする

Slide 20

Slide 20 text

(参考)自動計装の雰囲気 ~パターン ①~ # 利用側のコード # たったの1行! use XRay::AutoInstrument; builder { # enable # "+Plack::Middleware::XRay", # name => "MyApp", # sampling_rate => 1.0, # ; enable "Session", store => "File"; enable "Debug", panels => [ qw(DBITrace Memory Timer) ]; enable "+My::Plack::Middleware"; $app; }; 本来追加すべきコードを 勝手に入れて有効にしてくれる 設定値は環境変数で設定可能にする

Slide 21

Slide 21 text

(参考)自動計装の雰囲気 ~パターン ②~ package Hatena::De::Wasshoi365; use v5.40; our @TRACE_ENABLE = qw/slow_function function_1/; sub slow_function () { }; sub function_1 () { }; 手動計装でやる例 capture でwrapする必要がある sub function_1 () { capture “span_name”, sub () { /* 処理 */ return “手動は大変”; }; };

Slide 22

Slide 22 text

(参考)Perl豆知識 ~Perlは自由~ my $orig_code = "MyPackage"->can("my_func"); *{"MyPackage::my_func"} = sub { my @args = @_; # 前処理 # 本来のコード実行 $orig_code->(@args); # 後処理 }; MyPackage の my_funcの 実行前後に処理を追加する例 すっごい気軽に書き換えられるよ!! 気軽に書き換えてはいけない

Slide 23

Slide 23 text

実装した結果 ● プロダクション環境でもすでに使われている ○ GigaViewerやカクヨムで一部のコードが利用されている ○ はてなの他のサービスでも順次トレースの利用が開始される予定 ● トレースの伝搬がOtel ⇔ XRayでシームレスになった ○ TypeScriptやScala、GoなどのOtel SDKとAWS::XRayで実績あり ● 自動計装は現状あんまり使われていない ○ 手動計装で細かく制御したい人が多い ○ 工数があまりないプロダクトでは自動計装で片付けられるかも? はてなブックマーク、はてなブログなど https://speakerdeck.com/7474/gigaviewerniokerumackerel-apmdao-ru-noli-ce

Slide 24

Slide 24 text

今後の展望 ● 更に拡張するぞ!と言いたいところだが ○ 出来たら乗り換えろ!ということで ここ1,2年でPerlのOpenTelemetry SDKの実装がだいぶ進んだ ○ 問題ないならこれらのコードを捨てて乗り換えたい ● 社内オレオレライブラリのメンテより、OpenTelemetry SDKにコント リビュートしたほうが世の中のため、自分たちのためになる ● とはいえ、まだまだPerlのトレースは発展途上、 バランスを見ながら取捨選択していきたい

Slide 25

Slide 25 text

OpenTelemetryやo11yに興味ある エンジニアを募集しております