I couldn't find a logging library that worked for my library, so I made one

2025/12/13 0:46

I couldn't find a logging library that worked for my library, so I made one

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

要約

Fedify(ActivityPub サーバーフレームワーク)は、適切なライブラリレベルのロギングソリューションを欠いていました。Winston、Pino、debug など既存の JavaScript ロガーはアプリケーション中心で、明示的な設定が必要だったり非構造化テキストを出力したりするため、ゼロオーバーヘッドデフォルトを必要とするライブラリには不向きでした。

著者は LogTape を作成しました。これはライブラリ専用に設計された軽量ロガーです。LogTape は階層的なカテゴリ(例:

fedify
federation inbox/outbox/http
sig http/ld/key
runtime docloader
webfinger lookup
)を定義し、
configure
API を通じて明示的に有効化されたときだけ構造化 JSON ログを出力します。デフォルトでは Fedify はログを生成せず、パフォーマンスオーバーヘッドを排除します。最小限の設定であれば、エラーレベルのロギングを全体に有効化できます。

LogTape は受信リクエストヘッダー(

X‑Request‑Id
Traceparent
)から抽出した
requestId
を各ログエントリに自動的にタグ付けします。これは
AsyncLocalStorage
を使用しており、暗黙のコンテキストとして機能します。開発者は
jq
などで
requestId
によってログをフィルタリングし、非同期境界間でイベントを相関させることができます。構造化 JSON ログはファイルや他のシンクに書き込むことができ、観測ツールとの統合を容易にします。

LogTape は Node.js、Deno、Bun、およびエッジ関数でネイティブに動作し、ポリフィルを必要とせず、Winston や Pino などのアプリケーションロガーに対するライブラリ中心の代替手段となります。

本文

はじめに

Fedify(ActivityPub サーバーのフレームワーク)を作り始めたとき、思いがけない問題に直面しました。それは「ロギングをどう追加すればいいか分からない」ということです。

ロギング自体が難しいわけではありません。JavaScript には成熟したロギングライブラリが数多く存在します。しかしそれらは主に アプリケーション 用に設計されており、ライブラリ が「目立たないままで済む」ような設計になっていませんでした。

数か月前にこの点について書いたとき、反応は控えめでした。興味を示す声もあれば懐疑的な声もあり、投稿が AI 生成かどうかという議論までも起きました。正直に言うと、英語は母国語ではないため LLM を使って文章を磨いていますが、アイデアや技術内容は私自身のものです。

読者からは理論よりも「実際の例」を見たいという声が多く寄せられました。そこでこの記事を書きます。


問題点

既存のロガーは「アプリケーションを作る前提」で設計されています。
Fedify は ActivityPub プロトコルを使ってフェデレーテッドなソーシャルアプリを構築するためのライブラリです。フェデレーションに慣れた開発者なら、デバッグがいかに面倒になるか知っています。あるアクティビティが配信できないときは、次のような疑問を解決しなければなりません。

  • HTTP リクエストは実際に送信されたか?
  • 署名は正しく生成されたか?
  • 遠隔サーバーが拒否した理由は何か?
  • レスポンスの解析で問題が起きたか?

これらは「HTTP ハンドリング」「暗号署名」「JSON‑LD 処理」「キュー管理」など複数のサブシステムにまたがります。十分なロギングが無ければ、デバッグは推測ゲームになってしまいます。

しかしライブラリ作成者として直面したジレンマは次の通りです。

  • 詳細ログを追加すると、Fedify の内部情報でコンソールが乱雑になる恐れがあります。
  • 何も出力しないと、ユーザーは問題を特定できず苦労します。

既存オプションを調べた結果:

ライブラリ仕組み
winston / Pino① Fedify 内でロガーを構成(自分の選択肢を押し付ける)
② ユーザーにロガーインスタンスを渡させる(余計なコードが必要)
debug用途は合致するが、構造化されたレベルベースのログを提供せず、環境変数依存で Deno など一部ランタイムでは制限されやすい

どれも「ライブラリ向けには不十分」でした。そこで私は LogTape をゼロから設計し、Fedify がその最初の実ユーザーとなりました。


解決策:階層化カテゴリとデフォルトで出力なし

鍵は「ライブラリがログを出力できるが、アプリ側が明示的に許可するまで何も表示しない」ことです。Fedify は LogTape の階層化カテゴリシステムを使い、ユーザーが細かく制御できます。

カテゴリ構成例

カテゴリログ対象
["fedify"]
ライブラリ全体
["fedify", "federation", "inbox"]
受信アクティビティ
["fedify", "federation", "outbox"]
発信アクティビティ
["fedify", "federation", "http"]
HTTP リクエスト/レスポンス
["fedify", "sig", "http"]
HTTP Signature 処理
["fedify", "sig", "ld"]
Linked Data Signature 処理
["fedify", "sig", "key"]
キー生成・取得
["fedify", "runtime", "docloader"]
JSON‑LD ドキュメント読み込み
["fedify", "webfinger", "lookup"]
WebFinger ルックアップ

ほぼ 10 種類のサブシステムを表しており、ユーザーは必要な部分だけを有効にできます。

await configure({
  sinks: { console: getConsoleSink() },
  loggers: [
    // Fedify 全体のエラーのみ表示
    { category: "fedify", sinks: ["console"], lowestLevel: "error" },

    // inbox 処理に関してはデバッグ情報を追加
    {
      category: ["fedify", "federation", "inbox"],
      sinks: ["console"],
      lowestLevel: "debug",
    },
  ],
});

エラーが発生したときだけ詳細ログが出力され、他のサブシステムは静かに保たれます。コードを変更する必要はなく、設定だけで済みます。


隠しコンテキストでリクエスト追跡

階層化カテゴリでフィルタリングは解決できましたが、非同期境界間でログを結びつける課題も残っていました。
フェデレーテッドシステムでは「1 つのユーザー操作」が複数の処理を連鎖させます(遠隔アクター取得 → 署名検証 → アクティビティ処理 → フォロワーへの配信)。失敗した際に、すべてのログエントリを一つの「リクエスト」に紐づける必要があります。

LogTape の implicit context 機能で、すべてのログエントリに自動的に

requestId
を付与します。

await configure({
  sinks: {
    file: getFileSink("fedify.jsonl", { formatter: jsonLinesFormatter }),
  },
  loggers: [{ category: "fedify", sinks: ["file"], lowestLevel: "info" }],
  contextLocalStorage: new AsyncLocalStorage(), // implicit contexts を有効化
});

この設定で、すべてのログに

requestId
が付加されます。特定リクエストをデバッグしたいときは次のように絞り込み可能です。

jq 'select(.properties.requestId == "abc-123")' fedify.jsonl

これで「同じリクエスト」に属するすべてのログが順序通りに表示され、手動で結びつける必要はありません。

requestId
X‑Request‑Id
Traceparent
など既存ヘッダーから自動取得できるため、観測基盤との統合もスムーズです。


実際にユーザーが見るもの

Fedify を使う人は次のような体験をします。

状況何が起こるか
LogTape 未設定出力なし。警告やデフォルト出力も無く、性能への影響はほぼゼロ。
エラーレベルのみ有効化Fedify 全体のエラーだけを 3 行の設定で確認可能。
特定サブシステムのデバッグ必要なカテゴリだけ
debug
レベルに切り替えることで詳細ログが取得できる。
本番環境で監視要求がある場合構造化 JSON ログを監視システムへ送信し、リクエスト ID による相関情報付きで収集可能。

Node.js・Deno・Bun・Edge Functions など、どのランタイムでも同じライブラリコードが動作します。ポリフィルやシムは不要です。


学んだこと

  1. カテゴリ設計を早めに決定する
    階層化構造は「ユーザーが実際にログを絞り込みたい観点」を反映させるべきです。Fedify ではサブシステムごとに分けました。

  2. 構造化ロギングを採用する

    requestId
    activityId
    actorId
    などのプロパティは文字列補間よりも後で解析しやすく、運用上非常に有用です。

  3. implicit context が不可欠
    非同期境界を跨いだログの相関付けを手動で行う必要がなくなるため、分散処理のデバッグが格段に楽になります。ユーザーは 1 行の jq コマンドで全情報を取得できます。

  4. ユーザーを信頼する
    ライブラリ作者として「内部詳細を漏らすこと」を恐れるよりも、必要なときにだけ表示できる設計が重要です。オプトイン型にすることで、ユーザーは自由に選択できます。


ぜひ試してみてください

ライブラリ開発で「ロギングの量」「ユーザー制御」「ノイズを抑える方法」について悩んでいるなら、Fedify の実装を参考にすると良いでしょう。
Fedify のロギングドキュメントには詳細が記載されていますし、LogTape の設計哲学を知りたい方は私の以前の記事をご覧ください。

LogTape は「アプリケーション向けの winston や Pino を置き換える」ことを目的としたものではありません。
「ライブラリがユーザーに干渉せず、必要な時だけ活躍できるロギング」を提供するためのユニークな位置づけです。もしそのような要件をお持ちなら、従来のアプリ中心ロガーよりも LogTape が適しているかもしれません。

同じ日のほかのニュース

一覧に戻る →

2025/12/18 1:42

Gemini 3 Flash: Frontier intelligence built for speed

## Japanese Translation: > **概要:** > Google は、低コストで高速な AI モデル Gemini 3 Flash をリリースしました。これは Flash レベルのレイテンシーでプロ級の推論性能を提供します。Gemini アプリと Search の AI Mode では既にデフォルトエンジンとなり、Gemini 2.5 Flash は世界中で追加料金なしで即座に置き換えられます(Gemini 3 Pro が公開された直後)。ベンチマーク結果では、GPQA Diamond で 90.4 %、Humanity’s Last Exam(ツール無し)で 33.7 %、MMMU Pro で 81.2 %、SWE‑bench Verified で 78 % を獲得し、より大きなフロンティアモデルを上回ります。Gemini 3 Flash は Gemini 2.5 Pro より約30 %少ないトークン数で同等以上の性能を発揮します。価格は入力トークンあたり 0.50 USD、出力トークンあたり 3 USD(音声入力は 1 USD/百万トークン)です。JetBrains、Bridgewater Associates、Figma など多くの企業がこのモデルを活用し、コーディング、データ分析、設計ワークフローの高速化に役立てています。開発者は Gemini API(Google AI Studio)、Antigravity、Gemini CLI、Android Studio、Vertex AI、および Gemini Enterprise を通じて Gemini 3 Flash にアクセスできます。このモデルは Gemini アプリと Search 経由で全ユーザーへ展開されるほか、プレビュー API でも利用可能です。

2025/12/18 6:13

I got hacked: My Hetzner server started mining Monero

## Japanese Translation: ヘツナー VPS 上で Coolify をホストし、Next.js ベースの Umami アナリティクスを含む複数コンテナを実行していた。12 月 7 日に、Umami コンテナ内に Monero マイニングボット(`javae`/`xmrig`)が出現し、CPU スパイクが約 15 倍に増大した。著者はマイナーをコンテナに追跡し、CVE‑2025‑66478 ― Next.js の React Server Components “Flight” プロトコルにおける不安全なデシリアライゼーション(Puppeteer を介さずリモートコード実行が可能)を特定した。HTTP リクエストを巧妙に作成することで RCE が発動し、マイナーがインストールされた。ホストファイルシステムのチェック(`/tmp/.XIN-unix/javae`)ではエスケープは確認できず、コンテナは非 root の `nextjs` ユーザーとして実行され、特権モードやボリュームマウントも無いため、すべての悪意あるプロセスは名前空間内に留まった。 著者は侵害されたコンテナを停止・削除し、CPU 負荷を通常状態へ戻した。UFW をデフォルトで受信トラフィックを拒否するよう設定し、SSH、HTTP、および HTTPS のみ許可することで、オープンな PostgreSQL / RabbitMQ ポートを効果的に遮断した。ヘツナーは 2025‑12‑17 にネットワークスキャン検知後、アブズケース警告を送付し、著者が侵害と対策を説明するとともにチケットはクローズされた。 重要な教訓として、十分に隔離されているコンテナでも基盤フレームワークに脆弱性がある場合は突破可能であり、「Next.js を使っていない」状態が第三者ツールの依存関係によって偽りになるケースがあることを指摘した。この事例は、ファイアウォールルール、非 root ユーザー設定、特権モード無し、監視・ fail2ban の導入、およびタイムリーなパッチ適用という防御層の重要性を強調した。 ## 行動計画 - Umami を廃止する - すべてのコンテナに対してユーザー権限とマウントを監査する - SSH アクセスを強化し、アラートを設定する - セキュリティパッチを定期的に適用し、将来のインシデントを防止する ---

2025/12/18 3:15

How SQLite is tested

## Japanese Translation: > **SQLiteのテストインフラは網羅的で、コードベース全体にわたって完全な分岐カバレッジを実現しています。** > プロジェクトには約155.8 KSLOCのCソースがありますが、テストコードは92 M KSLOC以上――約590倍の量――で、すべての行が実行されることを保証しています。4つの独立したハーネスがカバレッジを提供します: > • **TCL**(27.2 KSLOC、1,390個のスクリプトファイル)で51,445件の異なるケースと数百万回の実行があります; > • **TH3**(1,055.4 KSLOC、約76.9 MBのバイナリ)で50,362件の異なるケース、完全カバレッジに必要な2.4 Mインスタンス、および約248.5 Mテストを実行するソークテストがあります; > • **SQL Logic Test (SLT)** はSQLiteとPostgreSQL、MySQL、MS SQL Server、Oracle 10gを比較し、7.2 Mクエリと1.12 GBのデータで検証します; > • **dbsqlfuzz**(libFuzzerベース)はSQLとデータベースファイルの両方を変異させ、約336個のシードファイルから16コアで1日あたり約500 Mテストを提供します。 > 追加の軽量ハーネスには `speedtest1.c`、`mptester.c`、`threadtest3.c`、`fuzzershell.c`、およびJSONBファズラ `jfuzz` が含まれます。 > 異常テストではメモリ不足、I/O障害、クラッシュ/電源損失、およびカスタムmalloc/VFSフックを使用した複合故障をシミュレートし、各障害後に整合性チェックが実行されます。 > ファズリングの歴史はAFL(2014‑2019)からOSS Fuzz(2016年以降)、その後dbsqlfuzz(2018年末)とjfuzz(2024年1月)へ進化しました。`fuzzcheck` スクリプトは毎回ビルド時に興味深いケースを再実行し、新しいバグが自動的にリグレッションテストとして生成されることを保証します。 > リソースリーク検出はTCL/TH3ハーネスに組み込まれており、メモリリーク、ファイルディスクリプタ枯渇、および不要なスレッドが自動的に監視されます。 > カバレッジは `gcov` を使用して100 %の分岐カバレッジと変異テストで達成され、マクロ(`ALWAYS`、`NEVER`、`testcase`)がMC/DCを強制し、コメント(`/*OPTIMIZATION‑IF‑TRUE/FALSE*/`)は偽陽性を防ぎます。 > 結果として、継続的に拡張される高い信頼性のテストスイートが実現し、ユーザーにSQLiteの安定性への確信を提供し、セキュリティ脆弱性から保護し、オープンソースデータベース品質保証のベンチマークとなります。

I couldn't find a logging library that worked for my library, so I made one | そっか~ニュース