Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Deep dive into log/slog package
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Pana
December 11, 2024
Programming
810
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Deep dive into log/slog package
Go Conference mini 2023 Winter IN KYOTOでの登壇資料になります
Pana
December 11, 2024
More Decks by Pana
See All by Pana
Go1.25新機能 testing/synctest で高速&確実な並行テストを実現する方法
k3forx
0
690
Other Decks in Programming
See All in Programming
AIエージェント時代のコードレビューを設計する
nogu66
6
2.6k
Oxlintはいいぞ(続)
yug1224
1
560
kubernetes コンポーネント開発入門 / 新卒N年目の勉強会&交流会!〜〇〇への誘い〜 #n_study
mazrean
0
180
RSSとCodexを使ってX投稿自動化してみた
ochtum
0
110
LoopHub - ローカルで動く GitHub で、AI と共同開発
jugyo
1
470
Webの地図
yosuke_furukawa
PRO
3
3k
Family mrubyの進捗
kishima
1
100
初心者DevRelとして参加者だった私が、DevRel Talks!#2に登壇するまでにしてきたこと
sokohirai
0
350
Seeing Through Serverless: Observability for AWS Lambda with ADOT and CloudWatch Application Signals
seike460
PRO
1
130
個人開発基盤をまるごとCloudflareに引っ越して爆速で総合的体験を向上させた話
tinykitten
0
140
新人はどこまで自力でやり、どこからAIに頼るべきか/エンジニア育成に向き合う_先輩たちの悩みと知見共有会
toppan_digital_dev
1
580
GKE で Pod の見方を変えたら、スケールアウト時の挙動を真に捉えられた話
stkk
0
100
Featured
See All Featured
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
1
2.8k
Designing Powerful Visuals for Engaging Learning
tmiket
1
530
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
780
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
360
30k
A Soul's Torment
seathinner
7
3.6k
How to Ace a Technical Interview
jacobian
281
24k
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
320
A designer walks into a library…
pauljervisheath
211
25k
Measuring & Analyzing Core Web Vitals
bluesmoon
9
990
How to build a perfect <img>
jonoalderson
1
6k
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Mind Mapping
helmedeiros
1
350
Transcript
Deep dive into log/slog package Pana@Go Conference mini 2023 Winter
IN KYOTO
本日のトークの内容 • 自己紹介 • log/slogパッケージの概要 • 基本的なAPI • パフォーマンスに関して
自己紹介 • 宮鼻 (Pana) • 株式会社SODAでWebエンジニア ◦ 2年くらいGoを書いている ◦ Zennに記事を書いている
• 好き ◦ コーヒー ☕ ◦ つけ麺 • GitHub ◦ k3forx
本日話すこと/話さないこと • 話すこと ◦ log/slogが実装/導入された背景や目的 ◦ 公開されているAPIの概要/内部のアーキテクチャ ◦ パフォーマンス観点での詳細な実装/設計 •
話さないこと ◦ log/slogのAPIの詳細な使い方 ◦ Webアプリケーションとの連携
log/slogパッケージの概要
log/slogパッケージとは • Go1.21のリリースで開発された構造化ログのための標準ライブラリ ◦ 現時点 (2023/11時点) ではテキスト形式とJSON形式での出力をサポートしてい る • 他のロギングパッケージは?
◦ logrus, zap, zerologなど色々ある
なぜlog/slogパッケージが開発された? • 色々なパッケージが開発された結果 ◦ 巨大なアプリケーションでは依存関係を通して様々なロギングパッケージに依存し ている • 何を解決したかった? ◦ ログを統一的に扱えるようできる
◦ ユーザーがカスタマイズ可能な ”バックエンド” を定義した ◦ 将来的に色々なロギングパッケージがこの “バックエンド” を受け付ける (実装す る) ようになることを期待 ◦ より高品質なバックエンドを作成するためにGoのコミュニティが協力し合える ◦ 詳細は Proposal: Structured Logging#what-does-success-look-like に記載があ る
基本的なアーキテクチャ • Logger構造体 ◦ ユーザー (開発者) から呼ばれる関数を定義 ◦ Record構造体を生成しHandlerにわたす •
Record構造体 ◦ ログの内容を構造体として保持する • Handlerインターフェイス ◦ Record構造体を受け取り処理する
基本的なAPI (使い方)
Infoメソッドをみてみる Output: • time, levelが出力 (デフォルト) • 第一引数はmsgのvalueとして出力 (デフォルト) •
その後の引数はkey-valueとして出力 (なくても良い) ソースの位置の出力有 無などが設定できる
内部の構造を見てみる 1. Record構造体を生成 + argsを追加 2. Hanlderインターフェイスに 渡す ログレベル
同じ情報を固定で出力させる Output: • Withメソッドを使えば同じメッセージを出力できる
同じような情報をまとめて出力 Output: • WithGroupメソッドを使えば、オプションのkey-valueをまとめて出力できる
パフォーマンスに関して
随所に現れるパフォーマンスを意識した設計 • log/slogでいうパフォーマンスとは? ◦ 主にメモリアロケーションのこと ◦ つまり、メモリのアロケーションをできるだけ少なくしている
どこに現れるか? • 色々な構造体/インターフェイス/型に現れている!! ◦ Logger構造体 ◦ Handlerインターフェイス ◦ Record構造体 ▪
Add関数 ◦ Attr (Value) 構造体 ◦ etc…
どこに現れるか? • 色々な構造体/インターフェイスに現れている!! ◦ Logger構造体 ◦ Handlerインターフェイス ◦ Record構造体 ⭐
▪ Add関数 ⭐ ◦ Attr (Value) 構造体 ⭐ ◦ etc…
関数の呼び出し (インライン展開) • インライン展開とは? ◦ 関数を呼び出す側に呼び出される側の関数のコードを展開し、関 数への制御転送をしないようにする方法。これにより関数呼び出し に伴うオーバーヘッドを削減する (Wikipediaより抜粋) •
コンパイラがいい感じにインライン展開してくれる • インライン展開できるかどうかは細かい条件がある ◦ https://github.com/golang/go/wiki/CompilerOptimizations#fun ction-inlining
関数の呼び出し (直接 vs 間接) • 試してみる • ビルドの最適化オプションを有効化
関数の呼び出し (直接 vs 間接) • 試してみる • 実行ファイルを逆アセンブルする
関数の呼び出し (直接 vs 間接) • インターフェイス経由でのメソッド呼び出しはインライン展開されない場 合がある (されることもある) ◦ 関数呼び出しにオーバーヘッドが生じるのでパフォーマンスに影響
する可能性がある • log/slogではどこで意識されているのか? ◦ Loggerはインターフェイスではなく構造体 になっている ▪ 呼び出し側でインターフェイスによる間接的なメソッド呼び出し にならないようにしている ◦ Infoメソッドなどはインターフェイス経由ではなく直接呼び出せる よ うになっている
Logger構造体のパフォーマンスメモ ✍ インライン展開されるようにインターフェースで はなく構造体として定義されている
Handlerインターフェイス Handleメソッド以外はパフォーマンス (最適 化) のためのメソッド
Handlerインターフェイス (Enabledメソッド) メソッドの最初に呼ばれる →早期リターン
Enabledメソッドのパフォーマンスメモ ✍ 無駄にログを出力しないように関数の一番最初 に呼ばれるようになっている
Handlerインターフェイス (WithAttrsメソッド) • WithAttrメソッドは引数のattrsを[]byteに変換した後、新しいHandler を生成する ◦ Handlerは内部にhandlerStateを持つ ◦ bufの型の*buffer.Bufferは実際には[]byte型 •
さらに[]byteはsync.Poolを使用
sync.Poolとは? • GoDocをみてみる ◦ 「... Pool’s purpose is to cache
allocated but unused items for later reuse, relieving pressure on the garbage collector. …」
sync.Poolとは? • GoDocをみてみる ◦ 「プールの目的は、割り当てられたが未使用のアイテムをキャッシュ し、後で再利用することで、ガベージ・コレクターの負担を軽減する ことである。」 • → 一時的に何かしらの値を保持して後で使いたい時
/確保のコス トが高いものをあらかじめに用意しておきたい時に便利 • log/slogパッケージ以外では、fmtパッケージやencoding/jsonパッケー ジでも使用されている • パフォーマンスに関するベンチマーク等の話はたくさん記事が出ている のでここでは割愛
sync.Poolの基本的な使い方 • GoDocのExampleをみてみる 1. 再利用したいアイテムを定義 2. アイテムを利用したい場合は Get メソッドを呼ぶ 3.
アイテムを更新した後は Putメ ソッドを呼ぶ
log/slogパッケージではどう使われているか? • 実装 Freeメソッドで空にした後に Putメ ソッドを呼ぶ ある程度大きい初期化を行うことで appendによるメモリの再確保を避け る
log/slogパッケージではどう使われているか? Handleメソッドでは書き込む内容を bufにつめ て、出力したのちにFreeメソッドを呼ぶ → bufは常に空に初期化される WithAttrsメソッドでは引数のattrsをbufにつ めて、新しいhandlerを返すような処理 → 元々のHandlerに影響を出さずに、引数
のattrsを高速に出力できるような仕組み
WithAttrsメソッドのパフォーマンスメモ ✍ • sync.Poolを使うことによって Handlerのメソッド を呼ぶたびに都度メモリを確保しないようになっ ている • 引数のattrsはbufに保存され、新しい Handler
ではその保存された bufを内部的に保持してい る
Record構造体 (Addメソッド) anyの可変長引数をAttrに 変換してる
Attr構造体 (Value構造体) uint64とanyのみでGoの型を表現 している
こう思いました... Valueフィールドの型はanyだとダメなのか?
結論は... Valueの方がanyより少しだけメモリ効率が良い →文字列 (string型) を例に考えてみる
(おさらい) Goにおけるany型とstring型
stringをanyで表現しようとすると... stringへのポインタ (anyが持つ) + byteへのポインタ (stringが持つ)
Value構造体でのstringの表現を見てみる 文字列の長さ byteへのポインタ anyの場合
Value構造体でのstringの表現を見てみる 文字列の長さ byteへのポインタ Valueの場合
Attr (Value) 構造体のパフォーマンスメモ ✍ Value構造体を定義することで anyをそのまま扱う より少しだけメモリ効率が良い設計になっている
Record構造体 (Addメソッド) なんかちょっと複雑なことをやってい るように見える...なぜ?
Record構造体 最初に長さ5の配列が初期化される
Record構造体 (Addメソッド) 最初 (nFront=0, len(r.Front)=5) は初期化済みの5つの配列にAttrを 詰める 配列が埋まったあとは、残りの argsを (Attr単位で)
カウントして、最初にそ の容量を確保している (appendによる 再確保はない)
なぜ nAttrsInline = 5となっているのか? A. zapを使っているコードを調べたところ9割くらいのロガーが5個の key-valueを出力していた (https://youtu.be/8rnI2xLrdeM?si=oCuKdvPQcrW08dXF から)
Record構造体のAdd関数のパフォーマンスメモ ✍ • zapの使い方から使用される key-valueペアの個 数を調査していた • 最初にその個数分のメモリだけ初期化し、追加 でメモリの再確保が可能な限り起きないように なっていた
(起きたとしても 1回)
まとめ
log/slogパッケージまとめ • 構造化ログを生成する初の標準パッケージ • パフォーマンスについて色々な工夫が見られた ◦ メモリのアロケーションを何回も行わない工夫が見られた • 突き詰めて実装コードを読んでみると、意外と難しいことはやっていない ように思えた
◦ Goの言語仕様をきちんと理解した上の設計/実装になっていた • Logger構造体やHandlerインターフェイスのパフォーマンスに関する調 査は後日ブログで公開予定
ありがとうございました