# トレースユーティリティ (trace-util) 設計・実装ドキュメント

# 1 目的

- Linux / Windows の両環境で共通のインターフェースでトレース (ログ) を出力する。
- 出力先として OS トレース (Linux: syslog、Windows: ETW)、ファイル、stderr の 3 系統を独立したスレッショルドレベルで管理する。
- `trace-util.h` が唯一の公開インターフェースであり、呼び出し側は OS 固有の API を直接扱う必要がない。

# 2 アーキテクチャ

    Application
          |
          v
    trace-util.h  (共通 API ─ 唯一の公開インターフェース)
          |
    +-----+-------+---------+
    |             |         |
    OS トレース   File   stderr
    (Linux: syslog            (両OS)  (両OS)
     Windows: ETW)

OS トレース層の詳細は下位層ヘッダ (`trace-etw-util.h`, `trace-syslog-util.h`) に委ねており、利用者は意識する必要がありません。

# 3 トレースレベル

`enum trace_level` で定義される共通レベルです。重大度は上から下へ低下します。

値 | 数値 | 意味
--- | --- | ---
`TRACE_LV_CRITICAL` | 0 | 致命的エラー
`TRACE_LV_ERROR` | 1 | エラー
`TRACE_LV_WARNING` | 2 | 警告
`TRACE_LV_INFO` | 3 | 情報
`TRACE_LV_VERBOSE` | 4 | 詳細 (デバッグ)
`TRACE_LV_NONE` | 5 | 出力しない

各出力先はスレッショルドレベルを個別に設定でき、設定レベル以上の重大度のメッセージのみ出力されます。`TRACE_LV_NONE` を指定するとその出力先を完全に抑止します。

# 4 デフォルト設定

`trace_init()` 呼び出し直後の各出力先のデフォルトスレッショルドレベルは以下のとおりです。

出力先 | マクロ | デフォルト値
--- | --- | ---
OS トレース | `TRACE_DEFAULT_OS_LEVEL` | `TRACE_LV_INFO`
ファイル | `TRACE_DEFAULT_FILE_LEVEL` | `TRACE_LV_ERROR`
stderr | `TRACE_DEFAULT_STDERR_LEVEL` | `TRACE_LV_NONE`

ファイルトレースは `trace_init()` 直後はパス未指定のため無効です。`trace_modify_filetrc()` でパスを設定して初めて有効になります。

# 5 API 仕様

## 5.1 ライフサイクル

ハンドルは stopped と started の 2 状態を持ちます。

- stopped 状態: 初期状態。設定関数 (`trace_modify_*`) が使用可能。出力関数は -1 を返す。
- started 状態: `trace_start()` 後。出力関数が有効。設定関数は -1 を返す。

    trace_init()
        ↓ (stopped)
    trace_modify_name / trace_modify_ostrc / ...  ← stopped でのみ有効
        ↓
    trace_start()
        ↓ (started)
    trace_write / trace_writef / trace_hex_write / trace_hex_writef  ← started でのみ有効
        ↓
    trace_stop()
        ↓ (stopped)
    ... 設定変更・再開が可能 ...
        ↓
    trace_dispose()  ← started / stopped どちらからも呼び出し可能

## 5.2 `trace_init`

    trace_provider_t *trace_init(void);

トレースプロバイダを初期化する。

項目 | 説明
--- | ---
戻り値 (成功) | ハンドル (stopped 状態)
戻り値 (失敗) | NULL
初期識別名 | 自プロセスの実行ファイル名 (Linux: `/usr/bin/myapp` → `"myapp"`、Windows: `myapp.exe` → `"myapp.exe"`)。取得失敗時は `"unknown"`。
スレッド安全性 | スレッドセーフ。複数スレッドから並行して呼び出し可能。

## 5.3 `trace_dispose`

    void trace_dispose(trace_provider_t *handle);

トレースプロバイダを終了し、リソースを解放する。

項目 | 説明
--- | ---
handle が NULL | 何もしない
started 状態 | 内部で自動的に停止してから解放する
スレッド安全性 | スレッドセーフ。進行中の `trace_write` 等が完了するまで待機してから解放する。
呼び出し後 | handle は無効となる

## 5.4 `trace_start` / `trace_stop`

    int trace_start(trace_provider_t *handle);
    int trace_stop(trace_provider_t *handle);

項目 | `trace_start` | `trace_stop`
--- | --- | ---
動作 | ハンドルを started 状態へ遷移 | ハンドルを stopped 状態へ遷移
冪等性 | 既に started なら何もせず 0 を返す | 既に stopped なら何もせず 0 を返す
戻り値 | 成功 0 / 失敗 -1 | 成功 0 / 失敗 -1
handle が NULL | -1 を返す | -1 を返す
スレッド安全性 | スレッドセーフ (内部で排他制御) | スレッドセーフ (内部で排他制御)

## 5.5 `trace_write`

    int trace_write(trace_provider_t *handle, enum trace_level level, const char *message);

指定したトレースレベルでメッセージを書き込む。

項目 | 説明
--- | ---
戻り値 | 成功 0 / 失敗 -1
前提条件 | ハンドルが started 状態であること。stopped 状態では -1 を返す。
メッセージ上限 | `TRACE_MESSAGE_MAX_BYTES` (1,024 バイト、null 終端含む)。超過分は UTF-8 マルチバイト境界を考慮して切り詰める。
handle が NULL | 何もせず 0 を返す
message が NULL | 何もせず 0 を返す
スレッド安全性 | started 状態では複数スレッドから並行して呼び出し可能

## 5.6 `trace_writef`

    int trace_writef(trace_provider_t *handle, enum trace_level level, const char *format, ...);

printf 形式でトレースメッセージを書き込む。内部で `vsnprintf` を使用し、`TRACE_MESSAGE_MAX_BYTES` のバッファにフォーマットする。バッファを超える部分は切り詰められる。

項目 | 説明
--- | ---
戻り値 | 成功 0 / 失敗 -1
前提条件 | ハンドルが started 状態であること。stopped 状態では -1 を返す。
handle が NULL | 何もせず 0 を返す
format が NULL | 何もせず 0 を返す
スレッド安全性 | started 状態では複数スレッドから並行して呼び出し可能

    trace_writef(logger, TRACE_LV_INFO, "user=%s count=%d", username, count);

## 5.7 `trace_hex_write`

    int trace_hex_write(trace_provider_t *handle, enum trace_level level,
                        const void *data, size_t size, const char *message);

バイナリデータを大文字スペース区切りの HEX テキスト形式で書き込む。

項目 | 説明
--- | ---
戻り値 | 成功 0 / 失敗 -1
message | 非 NULL の場合ラベルとして先頭に付与 (`"ラベル: HH HH ..."`)。NULL の場合は HEX のみ。
データ上限 | ラベルなしで最大 `TRACE_HEX_MAX_DATA_BYTES` (341) バイト。ラベル指定時はラベル長 + `": "` (2 バイト) 分だけ減少。超過分は切り詰めて末尾に `"..."` を付与。
前提条件 | ハンドルが started 状態であること。stopped 状態では -1 を返す。
data / size が NULL / 0 | 何もせず 0 を返す
スレッド安全性 | started 状態では複数スレッドから並行して呼び出し可能

出力フォーマット:

    // message 指定あり:
    "Received data: 48 65 6C 6C 6F"

    // message が NULL:
    "48 65 6C 6C 6F"

    // データが収まらない場合:
    "Received data: 48 65 6C ..."

## 5.8 `trace_hex_writef`

    int trace_hex_writef(trace_provider_t *handle, enum trace_level level,
                         const void *data, size_t size, const char *format, ...);

`trace_hex_write` と同等だが、ラベル文字列を printf 形式で指定できる。

    trace_hex_writef(logger, TRACE_LV_VERBOSE, data, len, "packet[%d]", index);
    // → "packet[3]: 48 65 6C 6C 6F"

## 5.9 `trace_modify_name`

    int trace_modify_name(trace_provider_t *handle, const char *name, int64_t identifier);

識別名と識別番号を変更する。

項目 | 説明
--- | ---
戻り値 | 成功 0 / 失敗 -1
前提条件 | ハンドルが stopped 状態であること。started 状態では -1 を返す。
name が NULL | `trace_init()` と同様に実行ファイル名を使用
identifier == 0 | 識別名 = `name`
identifier > 0 | 識別名 = `"<name>-<identifier>"`
identifier < 0 | -1 を返す
スレッド安全性 | stopped 状態ではスレッドセーフ (内部で排他制御)

    trace_modify_name(logger, "worker", 2);
    // → 識別名 "worker-2"

## 5.10 `trace_modify_ostrc`

    int trace_modify_ostrc(trace_provider_t *handle, enum trace_level level);

OS トレース (syslog / ETW) のスレッショルドレベルを設定する。

項目 | 説明
--- | ---
戻り値 | 成功 0 / 失敗 -1
デフォルト | `TRACE_DEFAULT_OS_LEVEL` = `TRACE_LV_INFO`
`TRACE_LV_NONE` | OS トレース出力を完全に抑止
前提条件 | ハンドルが stopped 状態であること。started 状態では -1 を返す。
スレッド安全性 | stopped 状態ではスレッドセーフ

## 5.11 `trace_modify_filetrc`

    int trace_modify_filetrc(trace_provider_t *handle, const char *path,
                             enum trace_level level, size_t max_bytes, int generations);

ファイルトレースの出力先と設定を変更する。

引数 | 説明
--- | ---
`path` | 出力ファイルパス。NULL でファイルトレースを無効化 (既存プロバイダを解放)。
`level` | ファイルトレースのスレッショルドレベル
`max_bytes` | 1 ファイルあたりの最大バイト数。0 で既定値 (`TRACE_FILE_DEFAULT_MAX_BYTES` = 10 MB) を使用。
`generations` | 保持する旧世代数。0 以下で既定値 (`TRACE_FILE_DEFAULT_GENERATIONS` = 5) を使用。

項目 | 説明
--- | ---
戻り値 | 成功 0 / 失敗 -1
ローテーション | `path` → `path.1` → `path.2` → `path.N` 形式で世代管理
既存プロバイダ | 既にファイルトレースが有効な場合は既存プロバイダを解放してから新規初期化
前提条件 | ハンドルが stopped 状態であること。started 状態では -1 を返す。
スレッド安全性 | stopped 状態ではスレッドセーフ

## 5.12 `trace_modify_stderrtrc`

    int trace_modify_stderrtrc(trace_provider_t *handle, enum trace_level level);

stderr トレースのスレッショルドレベルを設定する。

項目 | 説明
--- | ---
戻り値 | 成功 0 / 失敗 -1
デフォルト | `TRACE_DEFAULT_STDERR_LEVEL` = `TRACE_LV_NONE` (無効)
出力フォーマット | `YYYY-MM-DD HH:MM:SS.mmm L メッセージ` (タイムスタンプは UTC、`L` はレベル文字 C/E/W/I/V)
`TRACE_LV_NONE` | stderr 出力を完全に抑止
前提条件 | ハンドルが stopped 状態であること。started 状態では -1 を返す。
スレッド安全性 | stopped 状態ではスレッドセーフ

stderr 出力フォーマット例:

    2026-04-02 12:34:56.789 I application started
    2026-04-02 12:34:56.790 E connection failed

## 5.13 `trace_get_ostrc` / `trace_get_filetrc` / `trace_get_stderrtrc`

    enum trace_level trace_get_ostrc(trace_provider_t *handle);
    enum trace_level trace_get_filetrc(trace_provider_t *handle);
    enum trace_level trace_get_stderrtrc(trace_provider_t *handle);

各出力先の現在のスレッショルドレベルを取得する。

項目 | 説明
--- | ---
戻り値 | 現在のスレッショルドレベル
handle が NULL | `TRACE_LV_NONE` を返す
ロックタイムアウト | `TRACE_LV_NONE` を返す
前提条件 | なし。started / stopped どちらの状態でも呼び出し可能。
スレッド安全性 | スレッドセーフ (共有ロックで保護)

# 6 DLL エクスポート / インポート制御マクロ

マクロ | 説明
--- | ---
`TRACE_UTIL_EXPORT` | DLL エクスポート / インポートを制御する。条件に応じて以下の値を取る。
`TRACE_UTIL_API` | 呼び出し規約を指定する。Windows では `__stdcall`、Linux では空。

`TRACE_UTIL_EXPORT` の展開ルール:

条件 | 値
--- | ---
Linux (非 Windows) | (空)
Windows / `__INTELLISENSE__` 定義時 | (空)
Windows / `TRACE_UTIL_STATIC` 定義時 (静的リンク) | (空)
Windows / `TRACE_UTIL_EXPORTS` 定義時 (DLL ビルド) | `__declspec(dllexport)`
Windows / `TRACE_UTIL_EXPORTS` 未定義時 (DLL 利用側) | `__declspec(dllimport)`

# 7 内部設計

## 7.1 `trace_provider` 構造体

内部状態として以下のフィールドを保持します。

フィールド | 型 | 説明
--- | --- | ---
`identifier` | `int64_t` | 識別番号
`service_name` (Windows) | `char *` | 識別名文字列
`syslog_handle` (Linux) | `syslog_provider_t *` | syslog プロバイダハンドル
`os_level` | `enum trace_level` | OS トレースのスレッショルドレベル
`file_level` | `enum trace_level` | ファイルトレースのスレッショルドレベル
`stderr_level` | `enum trace_level` | stderr のスレッショルドレベル
`running` | `volatile int` | 実行状態フラグ (0: stopped、1: started)
`config_rwlock` | SRWLOCK (Win) / pthread_rwlock_t (Linux) | 状態保護用読み書きロック

## 7.2 スレッド安全機構

- 設定変更 (`trace_modify_*`, `trace_start`, `trace_stop`): 排他ロック (write lock) で保護。
- 出力 (`trace_write` 等) / レベル参照 (`trace_get_*`): 共有ロック (read lock) を最大 100ms のタイムアウト付きで取得し、複数スレッドからの並行実行を許容する。
- `trace_dispose`: ロック取得後に `running` を 0 にしてから解放処理を行い、進行中の書き込みと競合しない。

## 7.3 Windows: ETW プロバイダ共有

同一プロセス内で複数の `trace_provider_t` ハンドルが存在する場合、ETW プロバイダ登録 (TraceLogging) は参照カウント機構で共有されます。最後のハンドルが `trace_dispose()` されたときに登録が解除されます。

# 8 使用例

## 8.1 基本的な使い方

    #include <trace-util.h>

    trace_provider_t *logger = trace_init();
    trace_modify_name(logger, "myapp", 0);
    trace_start(logger);

    trace_write(logger, TRACE_LV_INFO, "application started");
    trace_writef(logger, TRACE_LV_WARNING, "retry count=%d", count);

    trace_stop(logger);
    trace_dispose(logger);

## 8.2 ファイルトレースを有効にする

    trace_provider_t *logger = trace_init();
    trace_modify_name(logger, "myapp", 0);
    trace_modify_ostrc(logger, TRACE_LV_WARNING);          /* OS トレースは WARNING 以上 */
    trace_modify_filetrc(logger, "/var/log/myapp.log",
                         TRACE_LV_INFO, 0, 0);             /* ファイルに INFO 以上を記録 */
    trace_modify_stderrtrc(logger, TRACE_LV_CRITICAL);     /* stderr に CRITICAL のみ */
    trace_start(logger);

    trace_writef(logger, TRACE_LV_INFO, "pid=%d started", getpid());

    trace_stop(logger);
    trace_dispose(logger);

## 8.3 識別番号付きの使い方 (複数インスタンス管理)

    trace_provider_t *logger = trace_init();
    trace_modify_name(logger, "worker", 2);  /* 識別名 "worker-2" */
    trace_start(logger);
    trace_write(logger, TRACE_LV_INFO, "worker-2 running");
    trace_dispose(logger);                   /* started 状態でも解放可能 */

## 8.4 バイナリデータの HEX ダンプ

    uint8_t buf[16] = { 0x48, 0x65, 0x6C, 0x6C, 0x6F };

    trace_hex_write(logger, TRACE_LV_VERBOSE, buf, 5, "Received");
    /* → "Received: 48 65 6C 6C 6F" */

    trace_hex_writef(logger, TRACE_LV_VERBOSE, buf, 5, "packet[%d]", idx);
    /* → "packet[0]: 48 65 6C 6C 6F" */

# 9 実装ファイル一覧

ファイル | 役割
--- | ---
`prod/util/include/trace-util.h` | 公開ヘッダー (唯一の公開インターフェース)
`prod/util/libsrc/util/trace-provider.c` | コア実装 (状態管理・ロック・出力振り分け)
`prod/util/include/trace-file-util.h` | ファイル出力プロバイダ (ローテーション機能付き)
`prod/util/include/trace-etw-util.h` | Windows ETW 下位層ヘッダー (詳細は同ヘッダ参照)
`prod/util/include/trace-syslog-util.h` | Linux syslog 下位層ヘッダー (詳細は同ヘッダ参照)
`prod/util/docs/trace-util.md` | このファイル