【Python】loggingでログ出力を実装する方法

当ページのリンクには広告が含まれています。
いずみ

こんな悩みを解決できる記事を書きました!

僕は現役フリーランスエンジニア(歴年)で、資格は個保有しています。

printデバッグから卒業して、Pythonできちんとしたログ出力を実装したい」とお考えではありませんか?

printを大量に書いたスクリプトは、リリース時に消して回る手間がかかります。

Python標準ライブラリのloggingを使えば、出力レベルの切り替えと出力先の分離をコード変更なしで管理できます

いずみ

標準ライブラリだけで完結するので、追加インストールは不要です。

ということで、本記事ではPythonのloggingでログ出力を実装する方法を解説します。

いずみ

すぐ読み終わるので、ぜひ最後まで読んでくださいませ。

スクロールできます
【当サイト】おすすめフリーランスエージェント3選
エージェント評価ポイント公式サイト
レバテックフリーランス

5.0
業界最大級のエージェント。
高単価案件が豊富。
公式
Midworks

4.8
満足度調査で
3年連続3冠を達成。
公式
ITプロパートナーズ

4.6
週2〜3向けの案件が豊富。公式
執筆者/監修者
  • フリーランスエンジニア(保有資格個、企業と直接契約
  • ブログ・アフィリエイト歴7年(2018年〜)
  • ブランドせどりで月利50万円⇨脱サラ
  • 投資(仮想通貨・FX)歴7年(2018年〜)
  • X(旧Twitter)フォロワー約1,900人
  • 運営者情報はこちら
いずみです
目次

【Python】loggingでログ出力を実装する方法

早速ですが、Pythonのloggingでログ出力を実装する手順を見ていきます。

printではなくloggingを使うメリット

printは標準出力へ文字列を送るだけで、重要度の区別ができません。

loggingはメッセージに重要度(ログレベル)を付けられます。

開発中はDEBUGまで表示し、本番ではINFO以上だけ残す、といった切り替えを設定1箇所で行えます。

出力先も画面・ファイル・外部サービスへ自由に分けられます。

タイムスタンプ・モジュール名・行番号を自動で付与できる点も、原因調査を速くします。

いずみ

printデバッグを消し忘れて本番に出てしまう事故も防げます。

loggingのログレベル

loggingには5段階のログレベルが用意されています。

  • DEBUG(数値10): 変数の中身や分岐など、開発中に追いたい詳細情報
  • INFO(数値20): 処理が想定どおり進んでいることを示す情報
  • WARNING(数値30): 停止するほどではないが注意が必要な事象
  • ERROR(数値40): 特定の処理が失敗したこと
  • CRITICAL(数値50): プログラム全体が継続できない深刻な事態

ロガーやハンドラに設定したレベル以上のメッセージだけが出力されます。

何も設定しない場合の初期レベルはWARNINGで、DEBUGとINFOは表示されません。

basicConfigで手早くログを出力する

まずは最小構成として、basicConfigでログを出力します。

STEP
basicConfigでレベルとフォーマットを指定する

スクリプトの冒頭で1回だけ呼び出します。

import logging

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(name)s %(message)s",
)

logging.info("処理を開始しました")
logging.warning("残り容量が少なくなっています")

levelにINFOを渡したので、DEBUGは出ずINFO以上が表示されます。

formatにfilenameへのパスを追加すると、画面ではなくファイルへ書き出せます。

STEP
basicConfigの制約を理解する

basicConfigはルートロガーへハンドラが未設定のときだけ効果を持ちます。

2回目以降の呼び出しは無視されるため、複数の出力先を細かく制御したい場合は次のハンドラ方式へ移行します。

いずみ

小さなスクリプトならbasicConfigだけで十分なことも多いです。

getLoggerでモジュールごとにロガーを分ける

実務では、モジュールごとに名前付きロガーを作るのが基本形です。

import logging

logger = logging.getLogger(__name__)


def run():
    logger.debug("デバッグ用の詳細情報")
    logger.info("正常に処理が進んでいます")
    try:
        1 / 0
    except ZeroDivisionError:
        logger.exception("ゼロ除算が発生しました")

getLoggerに__name__を渡すと、パッケージ階層に沿った名前のロガーが得られます。

ログにモジュール名が表示されるので、どのファイルの出力かがすぐ分かります。

logger.exceptionはexceptブロック内で使うと、スタックトレースを自動で付けてERRORレベルで記録します。

いずみ

ライブラリ側のコードでは、ハンドラを足さず名前付きロガーへ出力するだけにしておくのが行儀の良い書き方です。

ハンドラとフォーマッタで出力先と書式を分ける

画面には要点だけ、ファイルには詳細まで、という分け方をハンドラで実現します。

STEP
ロガーにレベルを設定する

ロガー自体はDEBUGまで通し、絞り込みは各ハンドラ側で行います。

import logging
from logging.handlers import RotatingFileHandler

logger = logging.getLogger("myapp")
logger.setLevel(logging.DEBUG)
STEP
フォーマッタとハンドラを組み立てる
formatter = logging.Formatter(
    "%(asctime)s [%(levelname)s] %(name)s:%(lineno)d %(message)s"
)

stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.INFO)
stream_handler.setFormatter(formatter)

file_handler = RotatingFileHandler(
    "app.log", maxBytes=1_000_000, backupCount=3, encoding="utf-8"
)
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(formatter)

logger.addHandler(stream_handler)
logger.addHandler(file_handler)

StreamHandlerは画面へINFO以上、RotatingFileHandlerはファイルへDEBUGまで書き出します。

RotatingFileHandlerはmaxBytesを超えるとファイルを世代交代させ、backupCountの数だけ古いログを残します。

いずみ

ログファイルがディスクを圧迫し続ける問題を、ローテーションで避けられます。

dictConfigで設定を一括管理する

ハンドラを手続き的に組み立てる代わりに、辞書で宣言的に定義する方法がdictConfigです。

import logging.config

LOGGING_CONFIG = {
    "version": 1,
    "disable_existing_loggers": False,
    "formatters": {
        "standard": {
            "format": "%(asctime)s [%(levelname)s] %(name)s: %(message)s",
        },
    },
    "handlers": {
        "console": {
            "class": "logging.StreamHandler",
            "level": "INFO",
            "formatter": "standard",
        },
        "file": {
            "class": "logging.handlers.RotatingFileHandler",
            "level": "DEBUG",
            "formatter": "standard",
            "filename": "app.log",
            "maxBytes": 1000000,
            "backupCount": 3,
            "encoding": "utf-8",
        },
    },
    "root": {
        "level": "DEBUG",
        "handlers": ["console", "file"],
    },
}

logging.config.dictConfig(LOGGING_CONFIG)
logger = logging.getLogger(__name__)
logger.info("dictConfigでの設定が完了しました")

versionキーは常に1を指定します。

disable_existing_loggersをFalseにしておくと、定義前に作られたロガーが無効化されず安全です。

辞書はJSONやYAMLへ切り出せるので、開発と本番で設定ファイルだけ差し替える運用がしやすくなります。

いずみ

アプリの規模が大きくなったらdictConfigへ寄せておくと、設定変更のたびにコードを触らずに済みます。

スクロールできます
【当サイト】おすすめフリーランスエージェント3選
エージェント評価ポイント公式サイト
レバテックフリーランス

5.0
業界最大級のエージェント。
高単価案件が豊富。
公式
Midworks

4.8
満足度調査で
3年連続3冠を達成。
公式
ITプロパートナーズ

4.6
週2〜3向けの案件が豊富。公式

【厳選】フリーランスエンジニアにおすすめなエージェント3選

フリーランスエンジニアになるにはエージェントから案件をもらう必要があります。

僕が実際に利用しているおすすめエージェントを紹介しますね。

いずみ

エージェントは必ず複数登録してください。

担当者によっては「全然案件紹介してくれない…」みたいなこともあるので…

僕は実際に5つのエージェントを使い回していますよ。

フリーランスを始めるなら「

案件数マージン率単価
約88,000件非公開
初心者福利厚生申し込み
無料
Good Point
  • 業界最大級の案件数。
  • 業界トップクラスの高単価報酬、低マージン(平均年収862万円)。
  • 案件参画中のフォローの充実。

※詳細は「【業界最大手】レバテックフリーランスとは?メリットや利用手順を解説!」を参照。

は業界最大手のフリーランスエージェントです。

とにかく案件数が多いので、とりあえず登録しておけば間違いないエージェントです!

いずみ

僕もはじめてフリーランスの案件を貰ったのはです。

保有している案件数が多いので、業務経験がなくても何かしらの案件は紹介してもらえますよ(僕はJavaの経験3年でも案件を貰えました)。

手厚い保障を重視したいなら「

案件数マージン率単価
約10,000件非公開
初心者福利厚生申し込み
無料
Good Point
  • 手厚い保障で正社員並みの安心感。
  • 還元率60%超え&単価公開でクリアな契約。
  • 給与保障制度(審査あり)。

は手厚い保障が特徴のフリーランスエージェントです。

フリーランスを目指しているけど不安な方や保障を重視したい方におすすめです。

いずみ

僕も何度か案件を紹介してもらいました。

自分のスキルに合った案件を紹介してもらえましたし、電話のやり取りも非常に丁寧でした。

週2〜3日の案件探しなら「

案件数マージン率単価
約5,000件非公開
初心者福利厚生申し込み
経験者向け無料
Good Point
  • IT案件に特化したフリーランスエージェント。
  • 週2〜3日の案件が豊富。
  • リモート案件が多く、直エンドなので単価も高い。

※詳細は「【週2・3案件】ITプロパートナーズとは?メリットや利用手順を解説!」を参照。

はIT案件に特化したフリーランスエージェントです。

週2〜3日から参画できる案件が豊富なので、起業したい人にもおすすめです。

いずみ

週2〜3日の案件はある程度スキルがないと紹介してもらえない印象です。

とはいえ、週5の案件ももちろんありますし、僕が利用した時は迅速・丁寧に対応していただきました!

よくある質問

ルートロガーと名前付きロガーはどちらを使うべきですか?

アプリ側のコードではlogging.getLogger(__name__)で名前付きロガーを使うのが基本です。

ハンドラの登録はエントリーポイントでルートロガーへまとめて行い、各モジュールは出力するだけにすると管理が楽になります。

ログが二重に出力されてしまいます。

同じロガーへaddHandlerを複数回呼んでいるか、ルートロガーと子ロガーの両方にハンドラを付けているのが原因です。

ハンドラ登録を1箇所に集約し、必要なら子ロガーのpropagateをFalseにすると重複が止まります。

本番環境ではどのログレベルにすべきですか?

通常はINFOかWARNINGを基準にします。

ログレベルは環境変数や設定ファイルから読み込めるようにしておき、障害調査のときだけDEBUGへ下げられる構成にすると便利です。

まとめ

今回は、Pythonのloggingでログ出力を実装する方法について解説しました。

以下が本記事のまとめになります。

まとめ
  • loggingはメッセージにレベルを付けられ、出力先の切り替えを設定1箇所で管理できる。
  • 小規模ならbasicConfig、モジュール構成ではgetLogger(__name__)を基本形にする。
  • ハンドラとフォーマッタで画面とファイルの書式・レベルを分けられる。
  • 規模が大きくなったらdictConfigで設定を宣言的にまとめ、外部ファイルへ切り出す。
まとめ
  • おすすめ本
¥2,970 (2023/07/25 22:48時点 | Amazon調べ)
\楽天ポイント4倍セール!/
楽天市場

Pythonの勉強なら「」が体系的に学べるのでおすすめですよ♪

いずみ

最後までお読みいただき、ありがとうございました!

スクロールできます
【当サイト】おすすめフリーランスエージェント3選
エージェント評価ポイント公式サイト
レバテックフリーランス

5.0
業界最大級のエージェント。
高単価案件が豊富。
公式
Midworks

4.8
満足度調査で
3年連続3冠を達成。
公式
ITプロパートナーズ

4.6
週2〜3向けの案件が豊富。公式
  • クソおすすめ本
¥4,480 (2024/06/01 23:28時点 | Amazon調べ)
\楽天ポイント4倍セール!/
楽天市場
いずみ

海外のエンジニアがどういった思考で働いているかが理解できます。

海外に行く気はないけど海外エンジニアの動向が気になる雑魚エンジニアにおすすめです(本当におすすめな本しか紹介しないのでご安心を)。

この記事が気に入ったら
フォローしてね!

シェアしてね!
  • URLをコピーしました!
目次