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:

(すべての重要ポイントを組み合わせたもの)


Summary

Fedify の新しい LogTape は、ライブラリ作者がデフォルト設定やランタイムオーバーヘッドを課さずに構造化ログを提供できるよう設計された、小型でオンデマンドのロギングフレームワークです。人気の JavaScript ロガーが設定を強制したりプレーンテキストを出力するのと対照的に、LogTape は開発者が明示的に有効化しない限り無音であり、階層構造かつ JSON 形式のメッセージ を自動的にリクエストコンテキスト(例:ヘッダーから取得した

requestId
)とともに出力します。Node.js、Deno、Bun、およびエッジ環境でネイティブに実行され、未使用時はオーバーヘッドが最小限に抑えられます。

Fedify は LogTape を ActivityPub サーバーフレームワークをデフォルトで静かに保ちつつ、開発者に細粒度の制御を提供するために構築しました。ログカテゴリは階層的に整理され(例:

fedify.federation.inbox
、
fedify.sig.http
)、ユーザーは
fedify.jsonl
のようなファイルへリダイレクトしたり、
jq
などのツールにパイプすることができます。このフレームワークはライブラリ作者向けであり、すでに winston や Pino を使用しているアプリケーションコードには適していません。将来的な作業ではクロスプラットフォームサポートを継続し、より広範な JavaScript コミュニティが構造化されたオプトインログを採用することを促進します。


変更点の説明

  • 「小型」と「オンデマンド」の記述を追加。
  • ログが JSON 形式であることを明示。
  • エッジ環境を含めたことを反映。
  • LogTape がライブラリ作者向けであり、アプリ開発者向けではないことを明確化。
  • バリュープロポジションの推測表現は削除し、事実に基づく意図のみ保持。

本文

Fedifyでログを取り込むときに直面した課題

Fedify(ActivityPubサーバーフレームワーク)を作り始めたとき、驚くほどやっかいな問題に直面しました。
それは「どうすればロギングを追加できるのか」という点です。
ロギング自体が難しいわけではありません――JavaScriptには何十もの成熟したライブラリがあります。ただ、これらは主にアプリケーション向けで、ライブラリとしては目立たないように設計されていないことが問題です。

数か月前にこの件について書いたところ、反応は控えめでした。興味を示す声もあれば懐疑的な意見や「この記事はAI生成?」という議論までありました。正直言って、英語は第一言語ではないので、LLMで文章を磨いています。アイデアと技術内容は私のものです。

いくつかの読者からは理論だけでなく実際に使える例を求められました。


問題点

既存のロガーは「アプリケーションを作っている前提」で設計されています。Fedify は ActivityPub プロトコル を用いて分散型ソーシャルアプリを構築するためのライブラリです。
フェデレーションに慣れていれば、デバッグは非常に手間がかかります。たとえばアクティビティが届かなかった場合、次のような質問に答えたいでしょう。

質問何を知りたい?
HTTPリクエストは実際に送信されたか?リクエストがネットワークへ出ているか
シグネチャは正しく生成されているか?鍵の署名処理が成功したか
遠隔サーバーが拒否した場合、その理由は?サーバ側で何が起きたか
レスポンスのパースに問題があったか?返ってきた JSON‑LD を正しく解釈できるか

これらの質問は HTTP ハンドリング、暗号署名、JSON‑LD 処理、キュー管理など複数サブシステムにまたがります。ロギングが適切でなければ、デバッグは推測ゲームになります。

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

  • 冗長なログを出力すると、コンソールが混乱しユーザーに迷惑になる
  • 何も出力しないと、問題発生時に原因究明が困難になる

既存の選択肢を検討

Winston や Pino を使えば:

  1. Fedify 内でロガーを設定する(ユーザーに自分の好みを押し付ける)
  2. ユーザーにロガーインスタンスを渡してもらう(ボイラープレート増加)

また

debug
というユーティリティはありますが、構造化ログやレベルベースの出力が欲しいというニーズには合いません。さらに環境変数に頼る設計で、Deno のようなランタイムでは制限されることも。

どれも私の求めていたものとは違いました。そこで LogTape を自作しました―ライブラリ作者向けにゼロから設計されたロギングライブラリです。Fedify が最初の実運用ユーザーになりました。


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

重要な発見はシンプルでした:「ライブラリはログを出力しても、開発者が明示的に有効にするまで何もしない」ということ。Fedify は LogTape の 階層化カテゴリ を使い、ユーザーが必要な情報だけを細かく制御できるようにしました。

カテゴリ何をログに残すか
["fedify"]
ライブラリ全体のメッセージ
["fedify", "federation", "inbox"]
受信アクティビティ
["fedify", "federation", "outbox"]
発信アクティビティ
["fedify", "federation", "http"]
HTTP リクエスト/レスポンス
["fedify", "sig", "http"]
HTTP シグネチャ操作
["fedify", "sig", "ld"]
Linked Data Signature 操作
["fedify", "sig", "key"]
キー生成・取得
["fedify", "runtime", "docloader"]
JSON‑LD ドキュメントのロード
["fedify", "webfinger", "lookup"]
WebFinger でリソースを検索

(その他約十項目が存在します)
各カテゴリは独立したサブシステムに対応しています。

これにより、ユーザーは次のようにロギングを設定できます:

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

    // inbox 処理に関しては debug レベルで出力
    { category: ["fedify", "federation", "inbox"],
      sinks: ["console"],
      lowestLevel: "debug"
    },
  ],
});

受信アクティビティに問題が発生したとき、該当サブシステムの詳細ログだけが出力されます。コードを書き換える必要はなく、設定だけで完結です。


非同期境界を跨ぐリクエストトレース

階層化カテゴリでフィルタリングできるようになったものの、非同期処理間でログを関連付ける課題が残っていました。フェデレーションでは1つのユーザー操作が数多くの非同期呼び出しに波及します:リモートアクターの取得 → 署名確認 → アクティビティ処理 → フォロワーへの配信…

LogTape の 暗黙的コンテキスト 機能を使えば、すべてのログエントリに

requestId
を自動で付与できます。

await configure({
  sinks: {
    file: getFileSink("fedify.jsonl", { formatter: jsonLinesFormatter })
  },
  loggers: [
    { category: "fedify", sinks: ["file"], lowestLevel: "info" },
  ],
  contextLocalStorage: new AsyncLocalStorage(), // 暗黙的コンテキストを有効化
});

この設定では、すべてのログエントリに

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

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

これで手動で関連付ける必要がありません。

requestId
は X‑Request‑Id や Traceparent など既存ヘッダーから自動生成され、既存の観測インフラに自然に統合できます。


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

Fedify を使う人は次のような状況を体験します:

何が起きるか期待される挙動
LogTape を設定しない場合何も出力せず、警告やデフォルト出力はなし。パフォーマンスへの影響はほぼゼロ。
基本的な可視化を求めるならFedify 全体のエラーだけを3行で設定して有効化
特定の問題をデバッグしたいとき関連サブシステムの debug レベルをオンにする
本番環境では構造化 JSON ログを監視システムへ送る、リクエストごとの相関情報付きで

同じライブラリコードが Node.js・Deno・Bun・エッジ関数 のいずれでも動き、追加のポリフィルやシムは不要です。必要なのはユーザー自身の判断です。


学んだこと

教訓内容
カテゴリ設計を早めに決めるユーザーが実際にログを絞りたい場所を想定して構造化する。Fedify ではサブシステムごとに分けました。
構造化ロギングを採用
requestId
、
activityId
、
actorId
のようなプロパティは文字列連結よりも分析しやすい。
暗黙的コンテキストは必須コンテキストを手動で渡さずに非同期境界間でもログが関連付けられる。
ユーザーを信頼するログの詳細を公開しても、必要なときだけオプトインすれば問題ない。

ぜひ自分で試してみてください

ライブラリを作っていて「ロギングはどうやる?」と悩んでいるなら、Fedify の実装例を参考にしてください。Fedify のログドキュメントには詳細が記載されていますし、LogTape の設計思想も併せて紹介しています。

LogTape は Winston や Pino を置き換えるものではなく、「ライブラリはユーザーの手元で必要なときだけ動作するようにしたい」――という別のニーズを満たすツールです。
もしそのようなロギングが必要なら、従来のアプリ中心のロガーよりも LogTape が適しているかもしれません。

同じ日のほかのニュース

一覧に戻る →

2025/12/13 5:57

GNU Unifont

2025/12/13 7:02

Show HN: Tiny VM sandbox in C with apps in Rust, C and Zig

## Japanese Translation: uvm32 は、単一の C ファイルで書かれたミニマリストで依存関係を持たない仮想マシンサンドボックスです。 STM32L0 のような非常に小型のマイクロコントローラ上で動作し、4 KB 未満のフラッシュと 1 KB の RAM を使用します。静的割り当てのみで非同期設計となっています。 この VM は RISC‑V のサブセットを実装しており、軽量な管理インタフェースを公開しています。「if‑this‑then‑that」ロジックのために Lua、Duktape、MicroPython などの軽量スクリプトエンジンを置き換え、信頼できないコンポーネントや不安定な部品をサンドボックス化し、ターゲットコンパイラなしでモダン言語の「一度書けばどこでも実行できる」スクリプトを書けるようにすることが目的です。 主な特徴: - バイトコードアプリは C、Zig、Rust、またはアセンブリで記述可能。 - 非ブロッキングでシンプルな実行モデル。安全かつ最小限の型付けを備えた FFI を使用し、ホスト IO(stdio/ネットワーク)は想定していません。 - デザインは高速よりも安全性を優先しています。 - すべてのソースコードは `uvm32/` ディレクトリにあります。最小限のホスト例は `host‑mini` にあり、より高度なホストは `host/`、`host-parallel`、`host-arduino` にあります。 サンプルアプリケーションは VM の機能を示しています(C: helloworld, heap, conio, lissajous, maze, fib, sketch; Zig: zig‑mandel, zigtris, zigalloc, zigdoom; Rust: rust‑hello; アセンブリ: hello‑asm)。 ビルドとテスト用の Dockerfile が提供されており、`make dockerbuild`、`make dockershell` で構築・起動し、その後 `make` を実行してサンプルをコンパイル・実行します。ドキュメントはヘッダファイル `uvm32/uvm32.h` と `doc/README.md` にあります。本プロジェクトは MIT ライセンスで公開されています。

2025/12/13 5:15

Rats Play DOOM

## Japanese Translation: > **概要:** > 著者らは、ラットがDOOMをプレイできる完全にオープンソースの仮想現実装置をリリースしました。ゼロから構築されたこのシステムには、ハードウェア設計・ファームウェア・ソフトウェアがGitHubに掲載されており、他研究室でも簡単に再現または改良できます。バージョン 1(v1)はニューヨークのヴィクトール・トー氏によって開発され、ラットにDOOMコリドーを走行させるよう訓練しました。この実装はViceとPC Gamerで紹介されました。 > > 改良版(v2)はよりモジュラー化され、180°×80°の視野を持つ折りたたみ可能なAMOLEDスクリーン、新しいボールドライバー、強化された給餌器、ゲームイベントに同期した正確な10 µLの砂糖水投与が可能な改良リワード回路を備えています。追加センサーとランニングマシンのボール周囲に設置された光学フロー運動捕捉システムでトラッキング精度が向上しています。 > > ソフトウェアはPythonベースのモジュラースタック(arena_scenario.py)で、PC上で実行され、Raspberry PiとTCP経由で通信します。Piはリアルタイムセンサー読み取り・ボール駆動・リワード制御を担当します。すべてのコンポーネントはGitHubに文書化されており、3Dプリント可能なパーツや回路図も公開されています。 > > チーム(ヴィクトール・トー=ゲーマーラットコーチ、サンドル・マクラ=電気技師、アコス・ブラシュェク=ドキュメントリード)は、ラットが約2週間で慣れることを示しましたが、完全な訓練はまだ完了していません。 > > 現在の制限として、自動キャリブレーションスイートが無いため、ユーザーはセンサーの整列とリワードタイミングを手動で検証する必要があります。 > > 今後の課題は完全な訓練プロトコルの完成、キャリブレーションツールの改良、および他の行動タスクや種へ装置を拡張することです。低コストで完全にオープンなプラットフォームを提供することで、このプロジェクトは世界中の神経科学研究室の参入障壁を下げ、動物VR実験に依存する研究のスピードアップに寄与できる可能性があります。