Help us understand the problem. What is going on with this article?

C++のLoggingライブラリ plog

More than 1 year has passed since last update.

札幌C++勉強会の もくもく会#10でもくもくと調べていたことをここに記す。本家Readme.mdを読んで、そのままメモっただけ。

Plog - portable and simple log for C++

小さくまとまっているログ出力ライブラリ。

インストール

header-onlyなのでgithubからダウンロードしてインクルードパス通すだけです。

$ git clone https://github.com/SergiusTheBest/plog.git

たとえばビルドツールにSConstructを使うなら

SConstruct
 # SConstruct
 Program("hello_plog", "hello_plog.cpp", CPPPATH="plog/include")
hello_plog.cpp
#include<plog/Log.h>

int main() {
    plog::init(plog::debug, "Output.txt");

    LOG_DEBUG << "Hello, plog!";
    return 0;
}

コンパイル

$ scons

出力はこんな感じになります

Output.txt
2016-02-15 20:34:51.006 DEBUG [14279] [main@6] Hello, plog!

日付、ログタイプ(この例ではDEBUG)、行番号、メッセージがでます。
他にCSV形式とかカスタムフォーマットも作れるみたいです。

Severityの指定

Severityを指定することで、指定したレベル以上のログだけを出すことができます。
Severityは次のものがあります。

enum Severity
{
    none = 0,
    fatal = 1,
    error = 2,
    warning = 3,
    info = 4,
    debug = 5,
    verbose = 6
};

(Severityだとfatalの数値の方が大きくなるべきなんじゃないかなあ・・)

ログ出力時におけるSeverityレベルの指定方法は、次の3つです。

  1. shortマクロ
  2. longマクロ
  3. 関数っぽく引数で指定
#include<plog/Log.h>
int main() {
        plog::init(plog::debug, "Output.txt");
        LOGD << "Hello, plog!";             // 1. shortマクロ
        LOG_DEBUG << "Hello, plog!";        // 2. longマクロ
        LOG(plog::debug) << "Hello, plog!"; // 3. 関数っぽく引数で指定
        return 0;
}

DEBUG以外のSeverityを指定するときは、Longマクロなら(DEBUGも含めSeverityの順に)

LOG_VERBOSE, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_FATAL

で、これらに対応するShortマクロは

LOGV, LOGD, LOGI, LOGW, LOGE, LOGF

です。

出力したいSeverityのレベルはplogの初期化時に指定します。
例えば、

#include<plog/Log.h>
int main() {
        plog::init(plog::warning, "Output.txt"); // warning以上を出力させる。
        LOGV << "verbose";
        LOGD << "debug";
        LOGI << "info";
        LOGW << "warning";
        LOGE << "error";
        LOGF << "fatal";
        return 0;
}

というコードを書くと、出力は

Output.txt
2016-02-15 21:32:12.920 WARN  [14455] [main@7] warning
2016-02-15 21:32:12.920 ERROR [14455] [main@8] error
2016-02-15 21:32:12.920 FATAL [14455] [main@9] fatal

となります。Severityがwarning以上のログだけが出ていますね。

CSV形式での出力

出力ファイル名の拡張子を.csvにするとCSV形式で出力してくれます。ただし(デフォルトの)区切り文字はカンマではなくセミコロンです。

plog::init(plog::warning, "Output.csv");
// 他は上記コードと同じ
Output.csv
Date;Time;Severity;TID;This;Function;Message
2016/02/15;21:38:51.297;WARN;14492;0;main@7;"warning"
2016/02/15;21:38:51.298;ERROR;14492;0;main@8;"error"
2016/02/15;21:38:51.298;FATAL;14492;0;main@9;"fatal"

ちなみに、拡張子を変えてフォーマットが変わるのは.csvだけです。

条件式でログ出力を切り替える

条件式付きでログ出力することができます。

LOG_DEBUG_IF(cond) << "debug";         // longマクロ
LOGD_IF(cond) << "debug";              // shortマクロ
LOG_IF(plog::debug, cond) << "debug";  // 関数っぽく

plogのソース追っていくと結局

if (condition) LOG_(instance, severity)

とif文に展開するマクロに落ちていたので、ありがたみがあるかは人それぞれな気もします。。

複数のログを出したいときは、スコープでまとめることができます。

IF_LOG(plog::debug) // Severityがdebug以上のときはこのスコープ内を実行する
{
    for (int i = 0; i < vec.size(); ++i)
    {
        LOGD << "vec[" << i << "]: " << vec[i];
    }
}

やっぱりif文に展開するマクロに、、(ry

途中でログファイルに出力するSeverityレベルを変える場合

通常は初期化時にログの出力レベルを指定します

plog::init(plog::warning, "Output.txt");

しかし、初期化時以外で指定したかったり、途中で変更したい時があるかもしれません。そういうときは、次のようにします。

plog::get()->setMaxSeverity(plog::debug);

ログをターミナル(コンソール)に出力したい場合。

ログの出力先をファイルではなく、標準出力にしたいことがあるかもしれません。そんな時は初期化でファイル名ではなく、Appenderを指定します。コンソールに色付きで出力するAppenderは次のように指定します。

#include<plog/Log.h>
#include<plog/Appenders/ColorConsoleAppender.h>

int main() {
    static plog::ColorConsoleAppender<plog::TxtFormatter> consoleAppender;
    plog::init(plog::debug, &consoleAppender);
    LOGD << "debug message to stdout with color";
    return 0;
}

注意! このようにAppenderはstaticで宣言すべきです。
出力がカラーである必要がない場合は、ConsoleAppenderもあります。

複数の出力先を指定したい場合

コンソールとファイルの両方に出力したい場合もあるかもしれません。そんな時はAppenderを追加することができます。

#include<plog/Log.h>
#include<plog/Appenders/ColorConsoleAppender.h>

int main() {
    static plog::ColorConsoleAppender<plog::TxtFormatter> consoleAppender;
    static plog::RollingFileAppender<plog::TxtFormatter> fileAppender("Output.txt");
    plog::init(plog::debug, &consoleAppender).addAppender(&fileAppender);
    LOGD << "debug message to stdout and file";
    return 0;
}

その他

もくもく会の終了時刻になったためこれで終わり。

ignis_fatuus
C++とPythonを主に使ってます。あとFortranも。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした