spdlog

C++向けの超高速ロギングライブラリ。ヘッダーオンリーで依存関係なし、優秀なfmtライブラリを使用した豊富なフォーマット機能を提供。マルチスレッド対応、ローテーション・日次ログファイル、カラーコンソール出力、バックトレースサポートを搭載。

ロギングライブラリC++高速非同期マルチスレッドヘッダーオンリーフォーマッタシンク

GitHub概要

gabime/spdlog

Fast C++ logging library.

スター26,769
ウォッチ444
フォーク4,838
作成日:2014年11月1日
言語:C++
ライセンス:Other

トピックス

cppcpp11header-onlyloggingspdlog

スター履歴

gabime/spdlog Star History
データ取得日時: 2025/7/17 08:20

ロギングライブラリ

spdlog

概要

spdlogは、C++向けの高速ロギングライブラリです。ヘッダーオンリーの設計により簡単に導入でき、非同期ロギングやマルチスレッド対応、豊富なシンク(出力先)の選択肢を提供します。fmt ライブラリを基盤とした強力なフォーマット機能と、パフォーマンスを重視した設計により、本格的なアプリケーションでの使用に適しています。

詳細

spdlogは2014年にGabriel Imeによって開発されたC++ロギングライブラリで、シンプルな統合と高性能を重視して設計されています。ヘッダーオンリーアプローチにより、別途ビルドする必要がなく、プロジェクトへの統合が非常に簡単です。

技術的特徴

  • 高速非同期ロギング: バックグラウンドスレッドプールによる高速処理
  • マルチシンクサポート: コンソール、ファイル、日次ローテーション、カスタムシンク等
  • fmt統合: 現代的なフォーマット構文による型安全な出力
  • スレッドセーフ: マルチスレッド環境での安全な並行利用
  • カスタマイズ可能: フォーマッタ、コンバータ、カスタムフラグの拡張
  • C++11対応: モダンC++機能の活用

アーキテクチャ

  • Logger: 中央制御とシンク管理
  • Sink: 出力先の抽象化(ファイル、コンソール、ネットワーク等)
  • Formatter: ログメッセージの書式設定
  • Thread Pool: 非同期ロギング用のワーカースレッド

メリット・デメリット

メリット

  • 優れたパフォーマンス: 最速クラスのC++ロギングライブラリ
  • ヘッダーオンリー: ビルド設定不要の簡単統合
  • 豊富なシンクオプション: 多様な出力先への対応
  • 型安全なフォーマット: fmtライブラリによる現代的な書式設定
  • 柔軟な設定: プログラムまたは設定ファイルでの構成
  • マルチプラットフォーム: Windows、Linux、macOS対応
  • メモリ効率: 最適化されたメモリ使用量

デメリット

  • ヘッダーサイズ: 大きなヘッダーファイルによるコンパイル時間増加
  • fmtライブラリ依存: 外部依存関係(内蔵版もあり)
  • 学習コスト: 高度な機能には設定の理解が必要
  • デバッグ情報: 最適化により詳細なデバッグ情報が制限される場合あり

参考ページ

書き方の例

基本的な使用方法

#include "spdlog/spdlog.h"

int main() {
    spdlog::info("spdlogへようこそ!");
    spdlog::error("エラーメッセージ: {}", 404);
    
    spdlog::warn("数値のパディング: {:08d}", 12);
    spdlog::critical("整数: {0:d}; 16進: {0:x}; 8進: {0:o}; 2進: {0:b}", 42);
    spdlog::info("浮動小数点: {:03.2f}", 1.23456);
    spdlog::info("位置指定: {1} {0}", "です", "こんにちは");
    
    // ログレベル設定
    spdlog::set_level(spdlog::level::debug);
    spdlog::debug("このメッセージが表示されます");
    
    // パターン変更
    spdlog::set_pattern("[%H:%M:%S %z] [%n] [%^---%L---%$] [thread %t] %v");
    
    return 0;
}

ファイルロギング

#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/sinks/daily_file_sink.h"

// 基本ファイルログ
void basic_file_logging() {
    try {
        auto logger = spdlog::basic_logger_mt("basic_logger", "logs/basic-log.txt");
        logger->info("基本ファイルログメッセージ");
    }
    catch (const spdlog::spdlog_ex &ex) {
        std::cout << "ログ初期化エラー: " << ex.what() << std::endl;
    }
}

// ローテーションファイルログ
void rotating_file_logging() {
    // 5MBサイズで最大3ファイルまでローテーション
    auto max_size = 1048576 * 5;
    auto max_files = 3;
    auto logger = spdlog::rotating_logger_mt("rotating_logger", "logs/rotating.txt", max_size, max_files);
    
    for (int i = 0; i < 10000; ++i) {
        logger->info("ローテーションテストメッセージ {}", i);
    }
}

// 日次ログ
void daily_logging() {
    // 毎日2:30 AMに新しいファイルを作成
    auto logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
    logger->info("日次ログメッセージ");
}

マルチシンクロガー

#include "spdlog/sinks/stdout_color_sinks.h"

void multi_sink_example() {
    // コンソールシンク(警告以上)
    auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
    console_sink->set_level(spdlog::level::warn);
    console_sink->set_pattern("[multi_sink] [%^%l%$] %v");

    // ファイルシンク(全てのレベル)
    auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/multisink.txt", true);
    file_sink->set_level(spdlog::level::trace);

    // マルチシンクロガー作成
    spdlog::logger logger("multi_sink", {console_sink, file_sink});
    logger.set_level(spdlog::level::debug);
    
    logger.warn("コンソールとファイル両方に出力");
    logger.info("ファイルのみに出力(コンソールには表示されない)");
}

非同期ロギング

#include "spdlog/async.h"
#include "spdlog/sinks/basic_file_sink.h"

void async_logging_example() {
    // デフォルトのスレッドプール設定を変更(初期化前)
    spdlog::init_thread_pool(8192, 1); // キューサイズ8K、バックグラウンドスレッド1個
    
    // 非同期ファイルロガー作成
    auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt");
    
    // または別の書き方
    // auto async_file = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt");
    
    for (int i = 0; i < 100; ++i) {
        async_file->info("非同期ログメッセージ {}", i);
    }
}

// 複数シンク非同期ロガー
void multi_sink_async_example() {
    spdlog::init_thread_pool(8192, 1);
    
    auto stdout_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
    auto rotating_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>("mylog.txt", 1024*1024*10, 3);
    
    std::vector<spdlog::sink_ptr> sinks {stdout_sink, rotating_sink};
    auto logger = std::make_shared<spdlog::async_logger>("async_multi", sinks.begin(), sinks.end(), 
                                                         spdlog::thread_pool(), spdlog::async_overflow_policy::block);
    spdlog::register_logger(logger);
    
    logger->info("マルチシンク非同期ログ");
}

カスタムフォーマッタとバックトレース

#include "spdlog/stopwatch.h"

// カスタムフォーマッタフラグ
class my_formatter_flag : public spdlog::custom_flag_formatter {
public:
    void format(const spdlog::details::log_msg &, const std::tm &, spdlog::memory_buf_t &dest) override {
        std::string custom_text = "custom-flag";
        dest.append(custom_text.data(), custom_text.data() + custom_text.size());
    }

    std::unique_ptr<custom_flag_formatter> clone() const override {
        return spdlog::details::make_unique<my_formatter_flag>();
    }
};

void custom_formatter_example() {
    auto formatter = std::make_unique<spdlog::pattern_formatter>();
    formatter->add_flag<my_formatter_flag>('*').set_pattern("[%n] [%*] [%^%l%$] %v");
    spdlog::set_formatter(std::move(formatter));
    
    spdlog::info("カスタムフラグ付きメッセージ");
}

// バックトレース機能
void backtrace_example() {
    // 最新32メッセージをバッファに保存
    spdlog::enable_backtrace(32);
    
    for(int i = 0; i < 100; i++) {
        spdlog::debug("バックトレースメッセージ {}", i); // まだログされない
    }
    
    // エラー発生時にダンプ
    spdlog::dump_backtrace(); // 最新32メッセージを表示
}

// ストップウォッチ機能
void stopwatch_example() {
    spdlog::stopwatch sw;
    
    // 重い処理のシミュレーション
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    
    spdlog::debug("経過時間 {}", sw);
    spdlog::debug("経過時間(3桁精度) {:.3}", sw);
}

高度な機能

#include "spdlog/sinks/callback_sink.h"
#include "spdlog/mdc.h"

// コールバックシンク
void callback_sink_example() {
    auto callback_sink = std::make_shared<spdlog::sinks::callback_sink_mt>([](const spdlog::details::log_msg &msg) {
        // エラー発生時にメール通知などの処理
        if (msg.level >= spdlog::level::err) {
            // アラート処理
            std::cout << "アラート: 重要なエラーが発生しました!" << std::endl;
        }
    });
    callback_sink->set_level(spdlog::level::err);

    auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
    spdlog::logger logger("custom_callback_logger", {console_sink, callback_sink});

    logger.info("通常の情報ログ");
    logger.error("重要な問題"); // アラート通知される
}

// MDC(Mapped Diagnostic Context)
void mdc_example() {
    spdlog::mdc::put("user_id", "12345");
    spdlog::mdc::put("session_id", "abcdef");
    
    // パターンに %& を含めてMDCデータを表示
    spdlog::set_pattern("[%H:%M:%S] [%^%L%$] [%&] %v");
    
    spdlog::info("ユーザー操作ログ");
    spdlog::error("セッション関連エラー");
}

// 定期的なフラッシュ
void flush_example() {
    // 全ての登録済みスレッドセーフロガーを3秒毎にフラッシュ
    spdlog::flush_every(std::chrono::seconds(3));
    
    // 手動フラッシュ
    spdlog::info("重要なメッセージ");
    spdlog::get("default")->flush(); // 即座にフラッシュ
}

// エラーハンドラー
void error_handler_example() {
    spdlog::set_error_handler([](const std::string &msg) { 
        spdlog::get("console")->error("*** ロガーエラー ***: {}", msg); 
    });
    
    // 意図的にエラーを発生
    spdlog::get("console")->info("無効なメッセージでエラー発生 {}{}{}{}", 3);
}