2021年6月30日水曜日

Pythonで標準出力をログファイルに出力する

Pythonにはloggingというロギング機能があって、ファイルへのログ出力ができる(Pythonでログローテーションする)。通常はstr型の文字列などをファイルに出力できるが、importしたモジュールなどで標準出力されたメッセージをログファイルに出力しておきたいことがある。今回は、標準出力をログファイルに出力する方法をまとめておく。


環境


WSL2(Ubuntu20.04)。


サンプルデータの標準出力

まずはPandasのDataFrameを作成してinfo(DataFrame情報)とdescribe(記述統計)を標準出力してみる。

import numpy as np
import pandas as pd

N = 100
x = np.random.rand(N)
y = np.random.rand(N)
z = np.random.rand(N)

df = pd.DataFrame({'x': x, 'y': y, 'z': z})
df.info()
print('----------------')
print(df.describe())


標準出力をログファイルへ出力

次はinfoとdescribeをログファイルに出力してみる。

from logging import getLogger, FileHandler
import numpy as np
import pandas as pd

N = 100
x = np.random.rand(N)
y = np.random.rand(N)
z = np.random.rand(N)
df = pd.DataFrame({'x': x, 'y': y, 'z': z})

logger = getLogger(__name__)
handler = FileHandler(filename='test.log')
basicConfig(handlers=[handler], level='INFO')
logger.info(df.info())
logger.info('---------------')
logger.info(df.describe())

describeの結果は出力されているがinfoの結果はNoneになっている。これはinfoの結果は標準出力されるため。以下のようにredirect_stdoutで標準出力の出力先を一時的にバッファに変え、バッファの内容をログファイルに出力することでinfoの結果をログファイルに出力できる。このようにすることで、importしたモジュールで標準出力されるメッセージなどもログファイルに出力できる。

from logging import getLogger, FileHandler
import io
from contextlib import redirect_stdout
import numpy as np
import pandas as pd

N = 100
x = np.random.rand(N)
y = np.random.rand(N)
z = np.random.rand(N)
df = pd.DataFrame({'x': x, 'y': y, 'z': z})

logger = getLogger(__name__)
handler = FileHandler(filename='test.log')
basicConfig(handlers=[handler], level='INFO')
buf = io.StringIO()
with redirect_stdout(buf):
    df.info()
    logger.info(buf.getvalue())

ちなみに、infoメソッドにはbufというキーワード引数ががあり、これを使うとredirect_stdoutを使わずにログファイルに出力できる。

from logging import getLogger, FileHandler
import io
import numpy as np
import pandas as pd

N = 100
x = np.random.rand(N)
y = np.random.rand(N)
z = np.random.rand(N)
df = pd.DataFrame({'x': x, 'y': y, 'z': z})

logger = getLogger(__name__)
handler = FileHandler(filename='test.log')
basicConfig(handlers=[handler], level='INFO')
buf = io.StringIO()
df.info(buf=buf)
logger.info(buf.getvalue())


0 件のコメント:

コメントを投稿