Slide 1

Slide 1 text

Typescript での Contextual な構造化ロギングと 社内全体への導入! 2024/05/11 TSKaigi レバレジーズ株式会社 瀬尾 光希

Slide 2

Slide 2 text

| © Leverages inc. 2 今日は何の話? レバテックの裏側。 Typescriptでのマイクロサービス運用。 ● どうロギングすれば運用しやすくなるか ● どうTypescriptで実現するか ● 導入してどうだったか を考えて、改善に取り組んだことのお話!

Slide 3

Slide 3 text

| © Leverages inc. 3 ● 所属 ○ レバテック開発部/案件ドメインユニット ● 経歴 ○ 2022年07月〜 レバレジーズ株式会社 ○ バックエンドエンジニア ○ 技術広報(テックブログと勉強会の運営) ● 最近 ○ ユーフォ3期が生きがい ○ プレーリーカード作った => 瀬尾 光希(せお こうき) 自己紹介 これは自分で描いた卵かけご飯 まあまあ美味そう

Slide 4

Slide 4 text

| © Leverages inc. 4 会社紹介|     サービス紹介 申し訳程度の IT事業 若年層事業 医療/介護事業 海外事業 ほか事業

Slide 5

Slide 5 text

| © Leverages inc. 5 会社紹介|使用言語 申し訳程度の フロントエンドも バックエンドも 使ってます! なども使ってます

Slide 6

Slide 6 text

| © Leverages inc. 6 会社紹介|技術広報 申し訳程度の カンファレンススポンサー や テックブログ に力を入れてます!  もフォローしてね! etc.

Slide 7

Slide 7 text

| © Leverages inc. 7 目次 1. ロギングのベストプラクティス 2. Typescript での実現 3. レバテックシステムへの全体導入 4. 導入してうれしかったこと 5. 導入する前に決めておきたかったこと

Slide 8

Slide 8 text

| © Leverages inc. 8 目次 1. ロギングのベストプラクティス 2. Typescript での実現 3. レバテックシステムへの全体導入 4. 導入してうれしかったこと 5. 導入する前に決めておきたかったこと

Slide 9

Slide 9 text

| © Leverages inc. 9 1. ライブラリを使おう! ○ ログに出すべき情報を自動で出してくれるようなものがあります 2. 正しいログレベルをつけよう! ○ 用途ごとに適切な設定をすべし(INFO, WARN, ERROR, …) 3. 集中管理できる場所に集めよう! ○ DatadogやNewRelicなど 4. 構造化されたフォーマットでロギングしよう! ○ ログは膨大な量になるので、人間より機械が読みやすいことの方が優先 ○ DatadogやNewRelicでは、JSONは自動でパースされる 5. ログメッセージと共に Context を記録しよう! ○ ログを読むときの目的を考えて、それ応じた関連情報を含めておきたい 6. 実行ごとに一意な識別子(Request ID)を含めよう! ○ リクエストを同時に処理するとログが混在してどれがどれだかわからんなる… ロギングのベストプラクティス(受け売り) ロギングのベストプラクティス

Slide 10

Slide 10 text

| © Leverages inc. 10 もともとレバテックのシステムは… ロギングのベストプラクティス 1. ライブラリを使おう! ○ 2. 正しいログレベルをつけよう! ○ 3. 集中管理できる場所に集めよう! ○ 4. 構造化されたフォーマットでロギングしよう! ○ 5. ログメッセージと共に Context を記録しよう! ○ 6. 実行ごとに一意な識別子(Request ID)を含めよう! ○ 微妙… そらこんな顔なるわ

Slide 11

Slide 11 text

| © Leverages inc. 11 決意 ロギングのベストプラクティス 俺がやるしか……

Slide 12

Slide 12 text

| © Leverages inc. 12 目次 1. ロギングのベストプラクティス 2. Typescript での実現 3. レバテックシステムへの全体導入 4. 導入してうれしかったこと 5. 導入する前に決めておきたかったこと

Slide 13

Slide 13 text

| © Leverages inc. 13 ● Node.js が提供する API ● (Deno や Bun にも互換の API がある) ● 非同期処理においてスレッドローカル変数 のようなものを実現  AsyncLocalStorage Typescriptでの実現 公式ドキュメントより引用 実行ごとにストレージを作り、 使いまわしたい情報を格納しておける!

Slide 14

Slide 14 text

| © Leverages inc. 14 AsyncLocalStorage の簡単な使い方 Typescriptでの実現 run() 中で実行される非同期関数内では、 getStore() によっていつでも ”TestText” を取得できる Controller から Usecase を呼び出す際に run() でラップして RequestID を実現

Slide 15

Slide 15 text

| © Leverages inc. 15 ロギングのライブラリ Typescriptでの実現 がおすすめ ● JSON形式に構造化されたログ出力できる ● hostname, UTC などをデフォルトで出力できる ● 任意のオブジェクトをJSONに要素追加できる ● 軽いらしい ● プロパティを指定して個人情報などを伏せ字にすること もできる ● ロギング時にトリガーしてJSONに要素追加する mixin 関数を設定できる → getStore() をロギングごとに仕込める

Slide 16

Slide 16 text

| © Leverages inc. 16 目次 1. ロギングのベストプラクティス 2. Typescript での実現 3. レバテックシステムへの全体導入 4. 導入してうれしかったこと 5. 導入する前に決めておきたかったこと

Slide 17

Slide 17 text

| © Leverages inc. 17 前提: ● システム ○ ロギングでは、社内ライブラリとして log4js のラッパーが浸透していた ○ 大半のシステムは gRPC で通信している(そうじゃないのもある) ○ gRPCアプリの Controller は 秘伝の社内ライブラリ によって proto から自動生成されていた ● 人 ○ 全員にログを改善していこうという意識があるわけではなかった 
 どうすれば皆が楽に恩恵を受けられるか: ● log4js ラッパーからの Migration が楽であること ● 特に使い方を意識せずとも、移行するだけで Contextual な構造化ロギングが実現されること 導入に向けて レバテックシステムへの全体導入

Slide 18

Slide 18 text

| © Leverages inc. 18 1. 社内ライブラリとして Pino のラッパーを新調 ○ 共通設定の初期化のみ行う(ログレベル, 時間のフォーマットなど) 2. 秘伝ライブラリに AsyncLocalStorage の処理を追加 ○ 自動生成される Controller が Usecase を呼び出す部分をラップする感じ ○ Node.js v12 以降で使用する前提なので許される ○ 皆が苦労せず恩恵を受けるには、今までの自動生成に紛れ込ますのがよいと考えた 3. 秘伝ライブラリで Controller と一緒に1のラッパーを生成 ○ mixin 関数で、生成した AsyncLocalStorage から RequestID の値を要素に追加するラッパー ○ 自動生成されるコードへの新たな依存(暗黙知)を作らないように気をつけた結果でした ○ gRPC と秘伝ライブラリの利用者はここから import すれば自動で RequestID が付与される 結論どうしたか レバテックシステムへの全体導入

Slide 19

Slide 19 text

| © Leverages inc. 19 目次 1. ロギングのベストプラクティス 2. Typescript での実現 3. レバテックシステムへの全体導入 4. 導入してうれしかったこと 5. 導入する前に決めておきたかったこと

Slide 20

Slide 20 text

| © Leverages inc. 20 ログが自動でパースされる 導入してうれしかったこと Request ID Massage Name パースを頑張らなくても(重要) ログの要素がDatadog側で全てパースされている状態 全てのログにRequest IDが含まれていて めっちゃ検索しやすい

Slide 21

Slide 21 text

| © Leverages inc. 21 好きなだけログ分析できた 導入してうれしかったこと ● ドメインロジックの結果集計 ● 特定の呼び出し数とエラー発生の相関調査 ● レスポンスタイム算出 ● … 無限の可能性

Slide 22

Slide 22 text

| © Leverages inc. 22 俺自身が best practice になる事だ めでたしめでたし 1. ライブラリを使おう! ○ 2. 正しいログレベルをつけよう! ○ 3. 集中管理できる場所に集めよう! ○ 4. 構造化されたフォーマットでロギングしよう! ○ 5. ログメッセージと共に Context を記録しよう! ○ 6. 実行ごとに一意な識別子(Request ID)を含めよう! ○ ログおじいさんとログおばあさん

Slide 23

Slide 23 text

| © Leverages inc. 23 目次 1. ロギングのベストプラクティス 2. Typescript での実現 3. レバテックシステムへの全体導入 4. 導入してうれしかったこと 5. 導入する前に決めておきたかったこと

Slide 24

Slide 24 text

| © Leverages inc. 24 JSON 要素追加のルールを作っておけばよかった おまけ程度ですが 例えばこういったDatadogのWidgetは、ログのJSON要素に追加したオブジェクトを集計して作っている。 自チームではルールを決めて要素追加していた(というより僕が主導しただけ)が 他チームにはロガーのことしか展開してなかった。 ルールも一緒に展開していれば、Widgetも一緒に横展開できたりしたかも…と少し後悔しました。

Slide 25

Slide 25 text

We Are Hiring! ブースに遊びに来てください〜