この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:5
ページ更新者:atom
更新日時:2026-10-25 18:28:29

タイトル: ログ出力方法
SEOタイトル: djangoのログ出力方法

Djangoのアプリログは、名前・loggerの実効レベル・handlerのレベル・伝播先を分けて確認します。まずファイルを作らないstderrの最小例で経路を確認し、保存や収集の設定は別に設計します。

アプリのloggerからレベルとhandlerを経てstderrへ出力し、この例では親への伝播を止める流れ

LOGGINGを読む順序と起動時の注意

DjangoはPython標準loggingを使います。通常はsettings.pyのLOGGINGをdictConfig形式で宣言し、django.setup()が既定設定、その後に独自設定を適用します。settings.pyの読み込み中にlogger.infoを呼んでも、まだこの設定が有効とは限りません。loggerの取得をモジュール先頭で行うことと、そこで起動ログを出すことは別です。リクエストごとにdictConfig/basicConfig/addHandlerを呼ばず、起動手順で一度設定します。開発autoreloadや複数ワーカーではプロセスが複数になるため、起動ログの複数行を直ちにhandler重複と判断しません。

  • レベルはDEBUG → INFO → WARNING → ERROR → CRITICALの順です。発行元loggerがレコードを受け付けても、出力先handlerのしきい値やfilterで落ちることがあります。logger=DEBUG、handler=INFOならDEBUGはそのhandlerへ出ません。
  • 名前はドット区切りの階層です。logging_demo.viewsはlogging_demoの子ですが、myapp.viewsやdjango.requestは別系統です。NOTSETのloggerは祖先のレベルを使い、rootは名前のない最上位loggerです。新規Pythonのroot既定レベルはWARNINGです。
  • propagate=Trueなら祖先のhandlerへ渡ります。その際、祖先logger自身のレベル・filterは再判定されず、祖先handlerのレベル・filterは適用されます。同じ出力先を子と親の両方へ付けると二重になる場合があります。Falseはその先への伝播を止めるだけで、既に付けた複数handlerや収集側の重複を解消しません。
  • version=1は設定辞書のスキーマ版で、Djangoの版ではありません。disable_existing_loggers=Falseは既存ロガーを一括無効化しない指定です。dictConfigで省略すると通常Trueになり、名前のない既存ロガー等を無効化する可能性があります。Falseだけで全handler・レベルが保持されるわけではなく、明示したloggerやその子の再設定は別です。

stderrへ出す最小プロジェクト

Python 3.12 / Django 5.2用の隔離例です。新しい作業ディレクトリのlogging_demo内に空の__init__.pyと、次の3ファイルを作ります。既存プロジェクトへsettings.py全体を上書きしません。認証・DB・業務処理を持たない検証用で、SECRET_KEYの固定値は本番に使えません。

logging_demo/settings.py

SECRET_KEY = "isolated-example-only-not-for-deployment"
DEBUG = False
ALLOWED_HOSTS = ["testserver", "127.0.0.1"]
ROOT_URLCONF = "logging_demo.urls"
INSTALLED_APPS = []
MIDDLEWARE = []
DATABASES = {"default": {"ENGINE": "django.db.backends.dummy"}}

LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "formatters": {
        "app": {
            "format": "%(levelname)s %(name)s %(event_code)s %(message)s",
            "defaults": {"event_code": "-"},
        },
    },
    "handlers": {
        "app_stderr": {
            "class": "logging.StreamHandler",
            "stream": "ext://sys.stderr",
            "level": "INFO",
            "formatter": "app",
        },
    },
    "loggers": {
        "logging_demo": {
            "handlers": ["app_stderr"],
            "level": "INFO",
            "propagate": False,
        },
    },
}

この設定はlogging_demoだけにINFO以上のstderr出力を付け、propagate=Falseでrootへの重複を避けます。djangoやrootを明示的に変更せず、Djangoの既定通知を全面的に置換する例ではありません。StreamHandlerの既定もstderrですが、ここでは行先を明示しています。formatterのdefaultsはPython 3.12のdictConfigで扱え、event_codeを渡さない通常ログでも「-」で整形できます。必須のextraを全呼出元へ要求すると欠落時の整形エラーでログを失うため、既定値と異常時も検査します。

logging_demo/views.py

import logging

from django.http import JsonResponse
from django.views.decorators.http import require_GET

logger = logging.getLogger(__name__)


@require_GET
def health(request):
    logger.info("health_check", extra={"event_code": "HEALTH_OK"})
    return JsonResponse({"ok": True})

logging_demo/urls.py

from django.urls import path

from .views import health

urlpatterns = [path("health/", health)]

この作業ディレクトリで、Django導入済みの専用仮想環境から python -m django runserver 127.0.0.1:8080 --settings=logging_demo.settings --noreload を起動し、PC内の http://127.0.0.1:8080/health/ へGETします。開発用であり本番サーバーではありません。app側は INFO logging_demo.views HEALTH_OK health_check を1行出し、JSONのokがtrueになります。開発サーバーのアクセス行は別に出ます。確認後はCtrl+Cで停止します。DBへ接続せず、ファイルも作らない例です。

元のコードと設定の記録

旧コード表も完成例の近くに置いて比較します。色分けを保持していますが、そのまま実行せず各直前の訂正を確認してください。

この記事の要点
  • Django のログ出力方法
  • 基本: import logging → logger = logging.getLogger(__name__) → logger.info(...)
  • 設定は settings.py の LOGGING ディクショナリで定義(ハンドラ・フォーマッタ・レベル)
  • print() よりログを使うほうが本番でも残せて検索しやすい

 

ビューでログ出力

旧例の注意:この黒い旧例は省略断片です。logger.infoと省略記号のインデントがgetの本体になっておらず、そのまま実行できません。Viewのimport・HttpResponse等の戻り値も必要です。__name__が実際にmyappで始まるか確認してください。完成例は「stderrへ出す最小プロジェクト」にあります。

import logging


class TestView(View):

    def get(self, request, *args, **kwargs):

    logger = logging.getLogger(__name__)

    logger.info('Hello World!')

    ...

 

ログ設定

旧例の注意:旧本文のsetting.pyは通常settings.pyの誤記です。下の黒い旧設定にはosのimportとLOG_DIRの定義がなく、無指定のディレクトリを自動作成するものでもありません。BASE_DIRがPathなら文字列との加算はできません。ファイル出力先・権限・複数ワーカーの条件を満たさずに転用しないでください。myappのDEBUGでもconsoleはINFOなのでDEBUGはconsoleへ出ず、propagate=Trueでrootにもhandlerがあると重複する可能性があります。

設定ファイルは 「プロジェクト名/setting.py」 にあります。

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'file': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': os.path.join(LOG_DIR, 'app.log'),
            # 'filename': '/var/log/myapp/app.log',
            'maxBytes': 1024 * 1024 * 10,  # 10 MB
            'backupCount': 50,
            'formatter': 'verbose'
        },
    },
    'loggers': {
        'django': {
            'handlers': ['console', 'file'],
            'level': 'INFO',
            'propagate': True,
        },
        'myapp': {
            'handlers': ['console', 'file'],
            'level': 'DEBUG',
            'propagate': True,
        },
    },
    'formatters': {
        'simple': {
            'format': '%(asctime)s [%(levelname)s] %(message)s'
        },
        'verbose': {
            'format': '%(asctime)s [%(levelname)s] %(name)s %(lineno)d: %(message)s'
        }
    }
}

 

アプリ・リクエスト・開発サーバー・SQLを分ける

ロガー用途と確認点
logging_demo.views等自分が呼んだlogger.info等です。settings.DEBUG=Falseでも、この例のINFOは出ます。DEBUG設定とlogging.DEBUGというレベルは別物です。
django / django.requestdjango.requestはリクエスト処理の4xxをWARNING、5xxをERRORで記録します。全200アクセスを記録するものではありません。SuspiciousOperationの400等はdjango.security系になる場合があります。
django.serverrunserverの応答ログです。既定でINFO以上をconsoleへ出し、propagate=Falseです。本番WSGI/ASGIやリバースプロキシのアクセスログとは別で、後者はサーバー側の設定を確認します。
django.db.backendsSQLとパラメータを含み得ます。通常のSQL診断はsettings.DEBUG=Trueと適切なログレベルが前提で、handlerをDEBUGにするだけでは有効になりません。これはアプリのINFOがDEBUG=Falseで出ないという意味ではありません。

Django既定のdjangoロガーはINFO以上で、DEBUG=True時はconsoleのfilterが通り、DEBUG=False時はERROR以上をAdminEmailHandlerへ渡します。実際の送信にはADMINSとメール設定等が必要です。django.serverはDEBUGと独立しています。この最小例は既定通知を残すため、本番で全Djangoエラーが必ずstderrへ残る設定ではありません。通知先と収集の要件を決め、既存handlerを確認して個別に設計します。調査のために本番DEBUGをTrueにしません。

秘密値を出さない設計と、例外ログの限界

このhealth例が出すのは固定メッセージと固定event_codeだけです。request.GET/POST/body、Cookie、Authorization、セッション、メールアドレス・ユーザーID、URLのクエリ、SQLの値をそのまま記録しません。外部入力をevent_codeや改行付きメッセージへ流し込まず、許可したイベント名・必要最小限の検証済みメタデータを選びます。引数形式のlogger.infoであっても内容の匿名化や改行対策は自動ではありません。

except内のlogger.exceptionやexc_info=Trueはトレースバックと例外メッセージを含み、そこで秘密値が漏れる可能性があります。Djangoのエラーレポート用sensitive_post_parameters/sensitive_variablesは、任意のloggingメッセージを一律に伏字化する機能ではありません。requestがextraに入るフレームワークログを別handlerが扱う場合もあります。この例や単体テストだけで全ログの秘匿を保証せず、アプリ・Django通知・Webサーバー・収集基盤を別々にレビューします。実秘密値を検証用ログへ流しません。

stderrとファイル保存・ローテートの選択

stderrは永続保存を保証しません。コンテナやサービス管理・収集基盤側で行の取得、アクセス制御、保持期限、容量、欠落/重複時の扱いを決めます。標準出力と標準エラーの収集経路が別なら、実行プロセスのstderrを確認します。ログ閲覧や共有も個人情報を扱う操作です。

FileHandler等を使う場合は、公開DocumentRootの外に専用ディレクトリを配備時に用意し、実行ユーザーのディレクトリ通過・書込権限、既存ファイル所有者、空き容量、文字コードを確認します。親ディレクトリは自動作成されず、既定ではhandler構築時にファイルを開くので、パス/権限不備でDjango起動自体が失敗し得ます。777や管理者起動で回避しません。コンテナのread-only filesystemや永続ボリュームも区別します。

標準RotatingFileHandler/TimedRotatingFileHandlerで複数ワーカーが同じファイルをローテートすると競合し得ます。stderrからの外部収集、またはQueueHandler等から単一の書込担当へ集約する構成を検討します。logrotateとWatchedFileHandlerを組み合わせてもプロセス間の書込直列化を保証せず、Unix向けの再open動作・所有権・切替時の欠落等を別途検証します。兄弟のローテート設定はパラメータの参考であり、「classを変えるだけ」「安全」という一般化はしません。SQLログの確認も秘密値・負荷・権限を別途審査し、掲載の本番DB設定変更をこの例の続きとして実行しません。

ログが出ない・二重になるときの確認

  1. 起動中のsettingsモジュールとプロセス、logger.name、disabled/isEnabledFor、実効レベルを確認します。設定の再読込が必要なプロセスと、開発autoreloadを分けます。
  2. 接続されたhandler、handler.level/filter、formatterの欠落項目、propagateと祖先/rootのhandlerを確認します。名前の不一致をファイル権限の変更で直そうとしません。
  3. 出力先stderr・収集側と、ファイルのパス/権限/容量を確認します。INFOが消えた理由をDEBUG設定だけで断定しません。
  4. 固定のテストイベントで1回/複数回を数えます。業務リクエストの再実行で外部副作用を重複させたり、ログ全文をそのまま共有したりしません。

内容確認:2026年10月26日。Python 3.12.10 / Django 5.2.18の隔離環境でdictConfig、Client、ログ捕捉を検査しています。実DB・本番ログ/設定・メール送信・本番収集・ファイル権限・複数プロセスのローテートは検証していません。親のDjango、本番配備も参照してください。

公式資料:Django loggingの設定と呼出し、Django既定設定とlogger一覧、Python loggingの階層とレベル、dictConfigのスキーマとdefaults、複数プロセスのログ設計、Djangoエラーレポートの機微情報、Pythonのファイルhandler。