Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Perlアプリケーションで トレースを実装するまでの 工夫と苦労話

Perlアプリケーションで トレースを実装するまでの 工夫と苦労話

Hatena Engineer Seminar #34 オブザーバビリティの実現と運用編 の登壇資料です
https://hatena.connpass.com/event/361495/

Avatar for masayoshi

masayoshi

July 29, 2025
Tweet

More Decks by masayoshi

Other Decks in Technology

Transcript

  1. 自己紹介 • id:masayoshi • 株式会社はてな ◦ Platform SRE をしているよ 株式会社はてなでSREとして勤務。

    自身の可観測性を高めるために、健康診断に行ったところ、高血圧にひっかかり健康に怯えて生 活をしている。 しかし、エラーバジェットポリシーが設定されていなかったため、食生活の改善は見られない。
  2. 今日話すこと • Perlでトレースを使いたい! ◦ OpenTelemetryの導入に関して色々な悩みポイントがあった ◦ 今回はてなが選択したやり方を紹介するよ! • 注意点! ◦

    細かい話多め ◦ Perl固有の話多め ◦ パワープレイ多め ◦ メジャーな言語ではそもそも問題になってない話題多め
  3. (個人的)技術選定のときの心構え • あったら使え! ◦ 仕組みがあるのであれば逆らわずに使おう • 組み合わせて使え! ◦ 1個じゃ無理!でも合わせれば解決!ってパターン •

    足りなければ作れ! ◦ どうしても足りないなら自分たちで付け足す • 出来たら乗り換えろ! ◦ 世の中は進化している。世の中に追いつかれたら乗り換える
  4. あったら使え! • 世の中は大OpenTelemetry時代、Perl向けOpenTelemetry SDKがあれば使いたい! ◦ あった! ◦ https://github.com/jjatria/perl-opentelemetry • が、検討時

    2024年春頃はまだいくつかの問題点があった ◦ まだ実装途中のところも多く、破壊的変更が多い ◦ OTLPのExporter周りの依存ライブラリやパフォーマンスの問題 • OpenTelemetry SDKを導入して終了!というわけにいかなかった
  5. 組み合わせて使え! • OpenTelemetry 以外の選択肢で AWS::XRay がある ◦ https://github.com/fujiwara/AWS-XRay ◦ 社内でも採用実績があり、AWS

    XRayに送っているチームもいた ▪ トレースだけならXRayのままでも良い ▪ 社内はMackerelで運用しており、OpenTelemetryに対応したトレース機能 の実装を検討していた • OtelCollectorにXRayのトレースを受け取れる awsxrayreceiver がある • XRay を OpenTelemetry に変換して使おう! 正確には「Vaxila」というサービスを事業譲受しており、Mackerelとの統合を検討していた
  6. XRayの良いところ • 仕様がシンプル! ◦ 特定のJSONフォーマットを作ってUDPで投げるだけ ▪ AWS::XRay も コア部分は500行以下のコードしかない ◦

    UDPなので、送信処理が同期的でもボトルネックになりにくい ▪ TCPかつ、複雑なOTLPの処理と比較して軽量 • よって、自分たちでコードの付け足しなどが容易 ◦ OTLPの仕様やOpenTelemetry全体の仕様を把握するのは大変 ▪ 変化も激しい ◦ とりあえずJSONつくってUDPで送れれば良し!は相当楽
  7. (参考)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と呼ぶことにするよ
  8. 足りなければ作れ! • 後述する自動計装の拡張などもあって、結局自分たちで計装を拡張 ◦ AWS::XRay のwrapper ◦ Devel::KYTProf::Logger::XRay の awsxrayreceiver

    対応版 ◦ Plack::Middleware::XRay の awsxrayreceiver 対応版 • やりたいこと ◦ Perlでアトリビュートを直感的に追加できる ◦ トレースがOtel SDKとPerlのXRayで相互に伝搬できるようになる ◦ 自動計装でサクセス!
  9. XRayとawsxrayreceiverの仕様の違い { “hatena”: “waiwai”, "code": { "function.name": "test_func" } }

    • awsxrayreceiver では map[string]map[string]any しか許容されない • AWS XRay では map[string]string でも良い 赤字部分がエラーになる
  10. awsxrayreceiverの変換方法が微妙 “code”: { “function.name”: “test_func”, “line.number”: 10, } aws.xray.metadata.code =

    {“function.name”:”test_func”, “line.number”:10} • prefixが追加される • 構造がフラットにならない
  11. (参考)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")
  12. 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: 実際には他にも仕様があるけど関係あるところを最低限抜き出してます
  13. (参考)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; } 文字列処理ならまかせろり!
  14. 自動計装 • 楽しいモンキーパッチ方式! ◦ 自動計装モジュールを読み込んだら自動で計装をインジェクトする • ①メジャーなライブラリを読み込んだときに専用の計装を有効にする ◦ Plack::Buiderがあったら、Plack::Middleware::XRay を有効

    ◦ ロードされるパッケージを確認して読み込み時にコードをインジェクト • ②関数名などを指定したら自動的にSpanを追加してくれる ◦ 今回はパッケージ変数で @TRACE_ENABLE という配列に入っている 関数にSpanをインジェクトする
  15. (参考)自動計装の雰囲気 ~パターン ①~ # 利用側のコード # たったの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; }; 本来追加すべきコードを 勝手に入れて有効にしてくれる 設定値は環境変数で設定可能にする
  16. (参考)自動計装の雰囲気 ~パターン ②~ 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 “手動は大変”; }; };
  17. (参考)Perl豆知識 ~Perlは自由~ my $orig_code = "MyPackage"->can("my_func"); *{"MyPackage::my_func"} = sub {

    my @args = @_; # 前処理 # 本来のコード実行 $orig_code->(@args); # 後処理 }; MyPackage の my_funcの 実行前後に処理を追加する例 すっごい気軽に書き換えられるよ!! 気軽に書き換えてはいけない
  18. 実装した結果 • プロダクション環境でもすでに使われている ◦ GigaViewerやカクヨムで一部のコードが利用されている ◦ はてなの他のサービスでも順次トレースの利用が開始される予定 • トレースの伝搬がOtel ⇔

    XRayでシームレスになった ◦ TypeScriptやScala、GoなどのOtel SDKとAWS::XRayで実績あり • 自動計装は現状あんまり使われていない ◦ 手動計装で細かく制御したい人が多い ◦ 工数があまりないプロダクトでは自動計装で片付けられるかも? はてなブックマーク、はてなブログなど https://speakerdeck.com/7474/gigaviewerniokerumackerel-apmdao-ru-noli-ce
  19. 今後の展望 • 更に拡張するぞ!と言いたいところだが ◦ 出来たら乗り換えろ!ということで ここ1,2年でPerlのOpenTelemetry SDKの実装がだいぶ進んだ ◦ 問題ないならこれらのコードを捨てて乗り換えたい •

    社内オレオレライブラリのメンテより、OpenTelemetry SDKにコント リビュートしたほうが世の中のため、自分たちのためになる • とはいえ、まだまだPerlのトレースは発展途上、 バランスを見ながら取捨選択していきたい