読み込み中...

Pythonでデバッグログを使いこなすための基本と活用8選

デバッグログ 徹底解説 Python
この記事は約30分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

●Pythonデバッグログとは?

プログラム開発において、バグを見つけ出す作業は避けて通れません。

Pythonでも、デバッグは重要な工程です。

その中で、デバッグログは開発者の強力な味方となります。

デバッグログは、プログラムの実行中に発生するイベントや状態を記録するメカニズムです。

プログラムの動作を追跡し、問題の原因を特定するのに役立ちます。

Pythonでは、標準ライブラリの「logging」モジュールがこの機能を提供します。

○デバッグログの重要性と基本概念

デバッグログが重要な理由は多岐にわたります。

まず、プログラムの実行フローを可視化できます。

どの関数がいつ呼び出されたのか、変数の値がどう変化したのかを追跡できます。

また、本番環境で発生した問題の調査にも役立ちます。

ユーザーの報告だけでは再現が難しい問題も、ログを見ることで原因を特定しやすくなります。

さらに、パフォーマンスの分析にも活用できます。

処理時間や資源使用量をログに記録することで、ボトルネックを見つけ出せます。

○loggingモジュールの概要と特徴

Pythonの標準ライブラリに含まれる「logging」モジュールは、柔軟で強力なログ機能です。

主な特徴として、次のようなものが挙げられます。

  1. ログレベルの設定 -> 情報の重要度に応じてログを分類できます。
  2. 出力先の選択 -> コンソール、ファイル、ネットワークなど、様々な場所にログを出力できます。
  3. フォーマットのカスタマイズ -> ログの書式を自由に設定できます。
  4. 階層的なロガー -> アプリケーションの構造に合わせてロガーを階層化できます。
  5. スレッドセーフ -> マルチスレッド環境でも安全に使用できます。

○サンプルコード1:基本的なログ出力

それでは、loggingモジュールを使った基本的なログ出力の例を見てみましょう。

import logging

# ロガーの設定
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')

# ログの出力
logging.debug('デバッグ情報')
logging.info('通常の情報')
logging.warning('警告')
logging.error('エラー')
logging.critical('致命的なエラー')

このコードを実行すると、次のような出力が得られます。

2024-08-05 12:34:56,789 - DEBUG - デバッグ情報
2024-08-05 12:34:56,789 - INFO - 通常の情報
2024-08-05 12:34:56,789 - WARNING - 警告
2024-08-05 12:34:56,789 - ERROR - エラー
2024-08-05 12:34:56,789 - CRITICAL - 致命的なエラー

このように、loggingモジュールを使うと、時刻、ログレベル、メッセージを簡単に出力できます。

ログレベルを変更することで、出力する情報を制御することもできます。

●loggingモジュールの使い方

loggingモジュールの基本を理解したところで、より詳細な使い方を見ていきましょう。

ログレベルの設定や、ロガーのカスタマイズなど、実践的なテクニックを紹介します。

○サンプルコード2:ログレベルの設定と使い分け

ログレベルは、出力する情報の重要度を表します。

Pythonのloggingモジュールには、DEBUG、INFO、WARNING、ERROR、CRITICALの5つの標準レベルがあります。

import logging

# ロガーの設定(INFOレベル以上を出力)
logging.basicConfig(level=logging.INFO)

logging.debug('デバッグ情報')  # 出力されない
logging.info('情報')
logging.warning('警告')
logging.error('エラー')
logging.critical('致命的なエラー')

実行結果

INFO:root:情報
WARNING:root:警告
ERROR:root:エラー
CRITICAL:root:致命的なエラー

ログレベルをINFOに設定したため、DEBUGレベルのログは出力されません。

開発中はDEBUGレベルを、本番環境ではWARNINGレベルを使うなど、状況に応じて使い分けると効果的です。

○サンプルコード3:loggerの生成とカスタマイズ

モジュールごとに異なるロガーを使用したい場合があります。

そんな時は、getLogger()関数を使ってロガーを生成します。

import logging

# ロガーの生成
logger = logging.getLogger('my_logger')

# ハンドラの作成(コンソール出力)
handler = logging.StreamHandler()

# フォーマッタの作成
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# ハンドラにフォーマッタを設定
handler.setFormatter(formatter)

# ロガーにハンドラを追加
logger.addHandler(handler)

# ログレベルの設定
logger.setLevel(logging.DEBUG)

# ログの出力
logger.debug('カスタムロガーからのデバッグメッセージ')
logger.info('カスタムロガーからの情報')

実行結果

2024-08-05 12:34:56,789 - my_logger - DEBUG - カスタムロガーからのデバッグメッセージ
2024-08-05 12:34:56,789 - my_logger - INFO - カスタムロガーからの情報

このように、カスタムロガーを使用することで、より細かな制御が可能になります。

モジュールごとに異なるログ設定を適用したり、出力形式を自由にカスタマイズしたりできます。

○サンプルコード4:ファイル出力の設定

ログをファイルに出力する方法を見てみましょう。

ファイルへの出力は、長期的なログの保存や、後から解析を行う際に役立ちます。

import logging

# ファイルハンドラの作成
file_handler = logging.FileHandler('app.log')

# ロガーの生成と設定
logger = logging.getLogger('file_logger')
logger.setLevel(logging.DEBUG)

# フォーマッタの作成
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)

# ロガーにファイルハンドラを追加
logger.addHandler(file_handler)

# ログの出力
logger.debug('デバッグ情報をファイルに記録')
logger.info('情報をファイルに記録')
logger.warning('警告をファイルに記録')

このコードを実行すると、カレントディレクトリに「app.log」というファイルが作成され、そこにログが記録されます。

ファイルの内容は次のようになります。

2024-08-05 12:34:56,789 - file_logger - DEBUG - デバッグ情報をファイルに記録
2024-08-05 12:34:56,789 - file_logger - INFO - 情報をファイルに記録
2024-08-05 12:34:56,789 - file_logger - WARNING - 警告をファイルに記録

ファイルへのログ出力は、プログラムの長期的な動作を追跡するのに適しています。

また、複数のハンドラを組み合わせることで、コンソールとファイルの両方にログを出力することも可能です。

●デバッグログのフォーマットとフィルタリング

デバッグログの真価は、適切なフォーマットとフィルタリングにあります。ログの見やすさは作業効率に直結します。

また、必要な情報だけを抽出できれば、問題解決の速度が格段に上がります。

○サンプルコード5:カスタムフォーマッタの作成

ログの形式をカスタマイズすると、必要な情報を一目で把握できるようになります。

Pythonのloggingモジュールでは、Formatterクラスを使ってログのフォーマットを自由に設定できます。

import logging
from logging import Formatter

# カスタムフォーマッタの定義
class ColoredFormatter(Formatter):
    COLORS = {
        'DEBUG': '\033[94m',  # 青
        'INFO': '\033[92m',   # 緑
        'WARNING': '\033[93m',  # 黄
        'ERROR': '\033[91m',  # 赤
        'CRITICAL': '\033[95m',  # マゼンタ
        'RESET': '\033[0m'   # リセット
    }

    def format(self, record):
        log_message = super().format(record)
        return f"{self.COLORS.get(record.levelname, self.COLORS['RESET'])}{log_message}{self.COLORS['RESET']}"

# ロガーの設定
logger = logging.getLogger('colored_logger')
logger.setLevel(logging.DEBUG)

# ハンドラの作成とフォーマッタの設定
handler = logging.StreamHandler()
formatter = ColoredFormatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)

# ログの出力
logger.debug('青色のデバッグメッセージ')
logger.info('緑色の情報メッセージ')
logger.warning('黄色の警告メッセージ')
logger.error('赤色のエラーメッセージ')
logger.critical('マゼンタ色の重大エラーメッセージ')

ColoredFormatterクラスは、ログレベルに応じて異なる色を適用します。

実行結果は、コンソール上で各ログメッセージが指定された色で表示されます。

視覚的に区別しやすくなり、重要なメッセージをすぐに識別できます。

○サンプルコード6:正規表現を用いたフィルタリング

大量のログから特定のパターンを持つメッセージだけを抽出したい場合があります。

正規表現を使ったフィルタリングが役立ちます。

import logging
import re

class RegexFilter(logging.Filter):
    def __init__(self, pattern):
        super().__init__()
        self.pattern = re.compile(pattern)

    def filter(self, record):
        return self.pattern.search(record.getMessage()) is not None

# ロガーの設定
logger = logging.getLogger('regex_filtered_logger')
logger.setLevel(logging.DEBUG)

# ハンドラとフィルタの設定
handler = logging.StreamHandler()
handler.addFilter(RegexFilter(r'error|warning'))
logger.addHandler(handler)

# ログの出力
logger.debug('デバッグメッセージ')
logger.info('情報メッセージ')
logger.warning('警告メッセージ')
logger.error('エラーメッセージ')
logger.critical('重大なエラーメッセージ')

RegexFilterクラスは、指定された正規表現パターンに一致するメッセージのみを通過させます。

実行結果では、「warning」または「error」を含むメッセージだけが出力されます。

WARNING:regex_filtered_logger:警告メッセージ
ERROR:regex_filtered_logger:エラーメッセージ

○サンプルコード7:特定条件下でのログ出力

時には、特定の条件を満たす場合にのみログを出力したいことがあります。

Pythonのloggingモジュールを使えば、条件付きのログ出力も簡単に実現できます。

import logging
from functools import wraps

def log_on_error(logger):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except Exception as e:
                logger.error(f"関数 {func.__name__} でエラーが発生: {str(e)}")
                raise
        return wrapper
    return decorator

# ロガーの設定
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger('conditional_logger')

# エラー時にのみログを出力する関数
@log_on_error(logger)
def divide(a, b):
    return a / b

# 正常なケース
result = divide(10, 2)
print(f"結果: {result}")

# エラーが発生するケース
try:
    result = divide(10, 0)
except ZeroDivisionError:
    print("ゼロ除算エラーが発生しました")

log_on_errorデコレータは、関数内でエラーが発生した場合にのみログを出力します。

実行結果は次のようになります。

結果: 5.0
ERROR:conditional_logger:関数 divide でエラーが発生: division by zero
ゼロ除算エラーが発生しました

正常なケースではログは出力されませんが、エラーが発生したケースではログが出力されています。

必要な時だけログを記録することで、ログファイルのサイズを抑えつつ、重要な情報を確実に捕捉できます。

●複数ハンドラの活用テクニック

複数のハンドラを組み合わせることで、ログの管理がより柔軟になります。

コンソールとファイルの両方にログを出力したり、重要度に応じて異なる処理を行ったりできます。

○サンプルコード8:FileHandlerとStreamHandlerの併用

開発中はコンソールでログを確認し、同時にファイルにも記録を残すことが有用です。

FileHandlerとStreamHandlerを併用すれば、容易に実現できます。

import logging

# ロガーの設定
logger = logging.getLogger('multi_handler_logger')
logger.setLevel(logging.DEBUG)

# ファイルハンドラの設定
file_handler = logging.FileHandler('app.log')
file_handler.setLevel(logging.WARNING)
file_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_handler.setFormatter(file_formatter)

# ストリームハンドラの設定
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.DEBUG)
stream_formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
stream_handler.setFormatter(stream_formatter)

# ロガーにハンドラを追加
logger.addHandler(file_handler)
logger.addHandler(stream_handler)

# ログの出力
logger.debug('デバッグメッセージ')
logger.info('情報メッセージ')
logger.warning('警告メッセージ')
logger.error('エラーメッセージ')

実行結果として、コンソールには全てのログレベルのメッセージが表示されますが、ファイル(app.log)にはWARNING以上のメッセージのみが記録されます。

コンソール出力

multi_handler_logger - DEBUG - デバッグメッセージ
multi_handler_logger - INFO - 情報メッセージ
multi_handler_logger - WARNING - 警告メッセージ
multi_handler_logger - ERROR - エラーメッセージ

app.logファイルの内容

2024-08-05 12:34:56,789 - multi_handler_logger - WARNING - 警告メッセージ
2024-08-05 12:34:56,789 - multi_handler_logger - ERROR - エラーメッセージ

○サンプルコード9:ログローテーションの実装

長期運用するアプリケーションでは、ログファイルが肥大化する問題に直面します。

ログローテーションを実装すれば、ファイルサイズを管理しつつ、過去のログも保持できます。

import logging
from logging.handlers import RotatingFileHandler

# ロガーの設定
logger = logging.getLogger('rotating_logger')
logger.setLevel(logging.DEBUG)

# RotatingFileHandlerの設定
# 最大1MBのファイルを3つまで保持
handler = RotatingFileHandler('app.log', maxBytes=1_000_000, backupCount=3)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)

logger.addHandler(handler)

# ログの出力
for i in range(10000):
    logger.debug(f'デバッグログメッセージ {i}')
    logger.info(f'情報ログメッセージ {i}')
    logger.warning(f'警告ログメッセージ {i}')

RotatingFileHandlerを使用することで、ログファイルが1MBを超えると自動的に新しいファイルが作成されます。

古いファイルは「app.log.1」、「app.log.2」というように名前が変更されて保持されます。

実行後、カレントディレクトリに「app.log」、「app.log.1」、「app.log.2」、「app.log.3」というファイルが生成されます。

各ファイルには、設定したサイズ制限内でログが記録されています。

○サンプルコード10:メール通知機能の追加

重大なエラーが発生した際、即座に開発者に通知することが求められる場合があります。

SMTPHandlerを使用すれば、ログをメールで送信できます。

import logging
from logging.handlers import SMTPHandler
import smtplib

# SMTPハンドラの設定
smtp_handler = SMTPHandler(
    mailhost=('smtp.example.com', 587),
    fromaddr='sender@example.com',
    toaddrs=['receiver@example.com'],
    subject='アプリケーションエラー通知',
    credentials=('username', 'password'),
    secure=()
)
smtp_handler.setLevel(logging.ERROR)

# ロガーの設定
logger = logging.getLogger('email_logger')
logger.setLevel(logging.DEBUG)
logger.addHandler(smtp_handler)

# エラーログの出力(メールが送信される)
try:
    1 / 0
except ZeroDivisionError:
    logger.error('ゼロ除算エラーが発生しました', exc_info=True)

SMTPHandlerを使用することで、ERRORレベル以上のログメッセージが発生した際に自動的にメールが送信されます。

実際の運用では、SMTPサーバーの設定や認証情報を適切に設定する必要があります。

●よくあるエラーと対処法

Pythonのデバッグログを使いこなす上で、避けて通れないのがエラー対応です。

初心者からベテランまで、誰もが経験するエラーとその対処法を押さえておくことで、スムーズなデバッグ作業が可能になります。

○ファイルパーミッションによるログ書き込みエラー

ログファイルへの書き込みに失敗する。

この問題は、開発者を悩ませる代表的なエラーの一つです。

原因は多くの場合、ファイルやディレクトリのパーミッション設定にあります。

【対処法】

  1. ログファイルのパーミッションを確認します。
  2. ログを書き込むディレクトリのパーミッションも確認します。
  3. アプリケーションを実行するユーザーに適切な権限を付与します。

具体的には、次のようなコマンドでパーミッションを変更できます。

chmod 644 app.log
chmod 755 /path/to/log/directory

また、Pythonのコード内でログファイルを作成する際に、適切なモードを指定することも有効です。

import logging

logging.basicConfig(filename='app.log', filemode='w', level=logging.DEBUG)

ここで、filemodeを’w’に設定することで、ファイルを書き込みモードで開きます。

○ログレベル設定ミスによる出力漏れ

ログが期待通りに出力されない。

この問題は、ログレベルの設定ミスが原因であることがよくあります。

【対処法】

  1. ロガーとハンドラの両方のログレベルを確認します。
  2. 意図したログレベルよりも低いレベルのメッセージが出力されていないか確認します。

例えば、次のようなコードで、ロガーとハンドラのログレベルを明示的に設定できます。

import logging

logger = logging.getLogger('my_logger')
logger.setLevel(logging.DEBUG)  # ロガーのログレベルを設定

handler = logging.StreamHandler()
handler.setLevel(logging.INFO)  # ハンドラのログレベルを設定

logger.addHandler(handler)

logger.debug('デバッグメッセージ')  # 出力されない
logger.info('情報メッセージ')  # 出力される

このコードでは、ロガーのレベルはDEBUG、ハンドラのレベルはINFOに設定されています。

DEBUGメッセージはロガーを通過しますが、ハンドラで除外されるため、最終的に出力されません。

○マルチスレッド環境でのログ競合

複数のスレッドが同時にログを書き込もうとすると、ログメッセージが混在したり、一部のメッセージが失われたりする可能性があります。

【対処法】

  1. スレッドセーフなログハンドラを使用します。
  2. ログの出力をロックで保護します。

Pythonの標準ライブラリには、スレッドセーフなQueueHandlerが用意されています。

import logging
from logging.handlers import QueueHandler, QueueListener
from queue import Queue
import threading

# キューの作成
log_queue = Queue()

# QueueHandlerの設定
queue_handler = QueueHandler(log_queue)
logger = logging.getLogger()
logger.addHandler(queue_handler)
logger.setLevel(logging.DEBUG)

# QueueListenerの設定
stream_handler = logging.StreamHandler()
queue_listener = QueueListener(log_queue, stream_handler)

# リスナーの開始
queue_listener.start()

# マルチスレッド環境でのログ出力
def worker(name):
    for i in range(5):
        logger.info(f'Worker {name}: ログメッセージ {i}')

# スレッドの作成と実行
threads = []
for i in range(3):
    t = threading.Thread(target=worker, args=(f'Thread-{i}',))
    threads.append(t)
    t.start()

# スレッドの終了を待機
for t in threads:
    t.join()

# リスナーの停止
queue_listener.stop()

このコードでは、QueueHandlerとQueueListenerを使用して、マルチスレッド環境でのログ競合を回避しています。

各スレッドは安全にログを出力でき、メッセージの混在や損失を防ぐことができます。

●Pythonデバッグログの応用例

デバッグログの基本を押さえたら、次は実際のアプリケーション開発での活用方法を見ていきましょう。

様々な場面でデバッグログを効果的に使うことで、開発効率と製品品質を大幅に向上させることができます。

○サンプルコード11:ウェブアプリケーションでのログ実装

ウェブアプリケーションでは、ユーザーのリクエストや処理の流れを追跡することが重要です。

Flaskを使用した簡単なウェブアプリケーションでのログ実装例を見てみましょう。

from flask import Flask, request
import logging
from logging.handlers import RotatingFileHandler

app = Flask(__name__)

# ログの設定
handler = RotatingFileHandler('app.log', maxBytes=10000, backupCount=1)
handler.setLevel(logging.INFO)
app.logger.addHandler(handler)

@app.before_request
def log_request_info():
    app.logger.info('Headers: %s', request.headers)
    app.logger.info('Body: %s', request.get_data())

@app.route('/')
def hello():
    app.logger.info('Hello endpoint was called')
    return 'Hello, World!'

@app.route('/user/<username>')
def show_user_profile(username):
    app.logger.info('User %s profile was requested', username)
    return f'User {username}'

if __name__ == '__main__':
    app.run(debug=True)

このコードでは、RotatingFileHandlerを使用してログをファイルに記録し、ファイルサイズが大きくなりすぎないように制御しています。

また、@app.before_requestデコレータを使用して、全てのリクエストのヘッダとボディをログに記録しています。

各エンドポイントでも、特定の情報をログに記録しています。

例えば、ユーザープロフィールページへのアクセスがあった場合、そのユーザー名がログに記録されます。

○サンプルコード12:データ分析プロセスのログ記録

データ分析プロジェクトでは、処理の各段階を詳細にログに記録することで、後から結果を検証したり、問題が発生した箇所を特定したりすることができます。

import logging
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error

# ログの設定
logging.basicConfig(filename='data_analysis.log', level=logging.INFO,
                    format='%(asctime)s - %(levelname)s - %(message)s')

try:
    # データの読み込み
    logging.info('データの読み込みを開始')
    data = pd.read_csv('sample_data.csv')
    logging.info(f'データの読み込みが完了。shape: {data.shape}')

    # 前処理
    logging.info('前処理を開始')
    data = data.dropna()
    logging.info(f'欠損値の削除が完了。新しいshape: {data.shape}')

    # 特徴量とターゲットの分割
    X = data.drop('target', axis=1)
    y = data['target']
    logging.info(f'特徴量の数: {X.shape[1]}')

    # データの分割
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
    logging.info(f'訓練データのサイズ: {X_train.shape[0]}, テストデータのサイズ: {X_test.shape[0]}')

    # モデルの訓練
    logging.info('モデルの訓練を開始')
    model = LinearRegression()
    model.fit(X_train, y_train)
    logging.info('モデルの訓練が完了')

    # 予測と評価
    y_pred = model.predict(X_test)
    mse = mean_squared_error(y_test, y_pred)
    logging.info(f'平均二乗誤差: {mse}')

except Exception as e:
    logging.error(f'エラーが発生しました: {str(e)}', exc_info=True)

このコードでは、データ分析の各段階(データ読み込み、前処理、モデル訓練、評価)でログを記録しています。

エラーが発生した場合は、エラーの詳細情報もログに記録されます。

○サンプルコード13:システムパフォーマンスのモニタリング

システムのパフォーマンスを継続的にモニタリングすることは、問題を早期に発見し、対応するために重要です。

Pythonのpsutilライブラリを使用して、システムリソースの使用状況をログに記録する例を見てみましょう。

import psutil
import time
import logging
from logging.handlers import TimedRotatingFileHandler

# ログの設定
handler = TimedRotatingFileHandler('system_monitor.log', when="midnight", interval=1, backupCount=7)
logging.basicConfig(handlers=[handler], level=logging.INFO,
                    format='%(asctime)s - %(levelname)s - %(message)s')

def log_system_stats():
    cpu_percent = psutil.cpu_percent()
    memory = psutil.virtual_memory()
    disk = psutil.disk_usage('/')

    logging.info(f"CPU使用率: {cpu_percent}%")
    logging.info(f"メモリ使用率: {memory.percent}%")
    logging.info(f"ディスク使用率: {disk.percent}%")

# 1分ごとにシステム状態をログに記録
try:
    while True:
        log_system_stats()
        time.sleep(60)
except KeyboardInterrupt:
    logging.info("モニタリングを終了します")

このコードでは、TimedRotatingFileHandlerを使用して、毎日午前0時にログファイルをローテーションしています。

1分ごとにCPU、メモリ、ディスクの使用率を記録し、システムの状態を継続的にモニタリングします。

○サンプルコード14:セキュリティ監査ログの実装

セキュリティ関連のイベントを詳細にログに記録することは、システムのセキュリティを維持する上で非常に重要です。

ここでは、ユーザーの認証試行をログに記録する簡単な例を紹介します。

import logging
from logging.handlers import RotatingFileHandler
import hashlib
from datetime import datetime

# セキュリティログの設定
security_logger = logging.getLogger('security_logger')
security_logger.setLevel(logging.INFO)

handler = RotatingFileHandler('security.log', maxBytes=10000000, backupCount=5)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
security_logger.addHandler(handler)

def hash_password(password):
    return hashlib.sha256(password.encode()).hexdigest()

def authenticate(username, password):
    # 実際のアプリケーションでは、データベースなどで認証を行います
    users = {'alice': hash_password('password123'), 'bob': hash_password('securepass')}

    if username in users and users[username] == hash_password(password):
        security_logger.info(f'認証成功: ユーザー {username}')
        return True
    else:
        security_logger.warning(f'認証失敗: ユーザー {username}')
        return False

# 認証の試行
authenticate('alice', 'password123')  # 成功
authenticate('bob', 'wrongpassword')  # 失敗
authenticate('eve', 'hackpassword')   # 存在しないユーザー

このコードでは、ユーザーの認証試行を全てログに記録しています。

認証に成功した場合はINFOレベル、失敗した場合はWARNINGレベルでログを記録します。

また、RotatingFileHandlerを使用してログファイルのサイズを管理し、古いログは自動的に削除されるようになっています。

まとめ

Pythonのデバッグログは、開発者にとって欠かせません。

適切に使用することで、問題の早期発見と解決、システムの安定性向上、セキュリティの強化が可能になります。

切に設計されたログシステムは、アプリケーションの動作を可視化し、問題の根本原因を素早く特定するために強力です。

後付けでログを追加するよりも、設計段階から適切なログ戦略を立てることで、より効果的なデバッグと問題解決が可能になります。