クイックダウンロード
Pythonのログレベルは、ログのノイズを除去し、イベントを重大度に基づいて優先順位付けし、分散システムにおける根本原因分析を改善するのに役立ちます。
-
Pythonのログレベル(DEBUG > CRITICAL)は、重大度に基づいたログのフィルタリングと優先順位付けを可能にし、ノイズを減らし、イベントの可視性を向上させます。
-
ロギングはロガー、ハンドラー、フォーマッターを介して行われ、メッセージは出力される前にレベルチェックを通過する必要があります。
-
適切なログ記録(印刷ではなく)を使用することで、アプリケーション全体にわたって構造化された、拡張性のある、一元化された可視性が得られます。
-
推奨事項: 環境間でログレベルと構成を標準化することで、本番環境で一貫性のある実用的なインサイトを得ることができます。
Pythonのログレベルは、記録するイベントとその重要度を制御し、ノイズを減らしてアプリケーションで重要な情報に集中できるようにするのに役立ちます。
システムが複雑化するにつれて、デバッグ、パフォーマンスの把握、問題の特定、信頼性の維持にはログ記録が不可欠になります。Pythonの組み込みログモジュールは、追加の設定を必要とせずにこの情報を柔軟に取得する方法を提供します。
この記事では、Pythonの各ログレベルの意味、さまざまなユースケースに合わせてログレベルを設定する方法、ロガーとハンドラーのレベルがどのように連携して動作するか、そして実際のシナリオで各レベルをいつ使用すべきかについて学びます。
Pythonロギングとは何ですか?
Pythonのログ記録とは、アプリケーションの実行中に発生するイベントを記録するプロセスです。これらの記録は、チームが動作を監視したり、問題をトラブルシューティングしたり、システムが時間とともにどのような動作をしているかを把握したりするのに役立ちます。
Pythonには、ログメッセージの生成とルーティングのための柔軟なフレームワークを提供する組み込みのロギングモジュールが含まれています。これにより、開発者はアプリケーションのさまざまな部分からメッセージをキャプチャし、コンソール、ファイル、外部システム(ログ管理プラットフォームなど)といった適切な宛先に送信できます。
ログメッセージを出力するために、アプリケーションはまず名前付きロガーを使用します。そのロガーはログレコードを作成し、それがハンドラーに渡されます(直接渡す場合と、上位ロガーへの伝播を介して渡す場合があります)。各ハンドラーはフォーマッターを使用して最終出力を構造化します。
実際の動作を簡略化するために、ログ記録プロセスは次の流れに従います。
- ロガーはあなたのメッセージからログレコードを作成します
- ロガーはレベルをチェックして、メッセージを処理する必要があるかどうかを判断します。
- 有効にすると、ログレコードはロガーにアタッチされたハンドラー(および、伝播に応じてオプションでその上位ハンドラー)に渡されます。
- ハンドラは自身のレベルをチェックして、メッセージを出力するかどうかを決定します。
- フォーマッタは、メッセージがコンソールやファイルなどの宛先に送信される前に、メッセージをフォーマットします。
ほとんどの開発者は、これらすべてを手動で管理する必要はありません。ログ記録の設定が完了すれば、プロセスはバックグラウンドで実行されます。
印刷が不適切な理由
この方法を避けるべき主な理由は以下のとおりです。
- Print関数はファイルライクオブジェクトへの書き込みは可能ですが、構造化ログ、複数の出力先、高度な出力制御といった機能は標準ではサポートされていません。
- 印刷メッセージはまずテキスト文字列に変換されます。開発者はprint関数のfile引数を使用してメッセージをファイルに保存できます。ただし、file引数はwrite(string)メソッドを持つオブジェクトである必要があります。print関数はテキスト出力を行うため、バイナリログ記録や構造化データの処理には対応していません。
- 印刷ステートメントは分類が困難です。
例えば、多種多様なprint文を含むログファイルがあるとします。アプリケーションが開発の様々な段階を経て本番環境に投入されると、これらのprint文を分類してデバッグすることはほぼ不可能になります。
print文は、さまざまな段階に合わせて変更したり、追加情報を提供したりすることもできますが、そうすると、print文に本来の目的とは異なる、あるいは設計意図とは異なる動作を強制しようとして、コードベースに大量の不要なデータが追加されることになります。
違いをよりよく理解するために、print文、ログ記録、および最新のオブザーバビリティツールを簡単に比較してみましょう。
| アプローチ | ベスト | 製品制限 | 典型的な使用例 |
|---|
| print() | 小規模スクリプトでの迅速なデバッグ | 階層構造やメタデータが組み込まれておらず、大規模な管理が困難である。 | 簡単なスクリプトのテストや単発のデバッグ |
| ロギングモジュール | アプリケーションの監視とデバッグ | 設定が必要であり、大規模システムや分散システムでは複雑になる可能性がある。 | 運用アプリケーション、デバッグ、およびシステム動作の追跡 |
| 監視/可観測性ツール | 大規模システムおよび分散環境 | セットアップ、外部ツール、および費用が必要です | ログ、アラート、ダッシュボード(ELK、Datadogなど)、およびログ、メトリクス、トレース間の相関関係を一元的に管理する。 |
レベルに応じたPythonロギングのベストプラクティス
ログレベルは、アプリケーションが実行される環境に基づいて設定する必要があります。
- 開発: DEBUGを使用して詳細な実行フローをキャプチャし、問題を迅速に診断します。
- ステージング/テスト: テスト中にどの程度の可視性が必要かに応じて、DEBUGまたはINFOを使用してください。
- 製造: INFOまたはWARNINGを使用してノイズを減らし、重要なイベントに焦点を当ててください。
- 重要システム: 緊急の問題を即座に検出するには、ERROR と CRITICAL をアラートと組み合わせて使用してください。
Pythonロギングモジュールの利点
Pythonのloggingモジュールは、アプリケーションログの取得と管理のための柔軟な組み込み機能を提供します。主な利点は以下のとおりです。
- 柔軟なフォーマット: タイムスタンプ、レベル、ファイル名、その他のコンテキスト情報を使用してログ出力をカスタマイズします。
- ログレベルの制御: メッセージを重要度(DEBUG、INFO、WARNINGなど)で分類してノイズを減らし、重要な情報に集中しましょう。
- 複数の目的地: 統合機能(ソケット、HTTPハンドラー、サードパーティツールなど)を介して、ログをコンソール、ファイル、その他のシステムなどの異なる出力先にルーティングします。
- モジュール式伐採設計: 各モジュールは、グローバル設定を管理する必要なく、独自の名前付きロガーを使用して独立してログを生成できます。
- 集中管理: アプリケーションは、モジュールレベルのコードをシンプルに保ちながら、ログ記録の動作をグローバルに設定できます。
Pythonのログ記録機能は階層構造もサポートしています。
- ロガーは命名階層に従います(例:app、app.database、app.api)。
- 子ロガーは、明示的に上書きされない限り、レベルやハンドラーなどの設定を親ロガーから継承できます。
- これにより、大規模アプリケーションや複数モジュール構成のアプリケーションにおけるログ管理が容易になります。
Pythonのログはどこに書き込むべきか?(ファイルか標準出力か)
ファイルベースのログ記録は、スタンドアロンサーバー上で動作するアプリケーションや、ローカルでの永続性が重要な環境に適しています。
しかし、コンテナ化された環境やクラウドネイティブ環境(DockerやKubernetesなど)では、標準出力(stdout)または標準エラー出力(stderr)にログを出力することが一般的に推奨されます。これにより、オーケストレーションプラットフォームやログエージェントがログを自動的に収集、集約、一元管理できるようになります。
ログファイルのサイズを長期的に管理することも重要です。
Pythonには、RotatingFileHandler(ファイルサイズに基づいてログをローテーションするハンドラ)やTimedRotatingFileHandler(一定時間間隔でログをローテーションするハンドラ)などの組み込みハンドラが用意されています。多くの運用環境では、ログの保持期間を管理し、ディスク容量の問題を回避するために、これらのハンドラと併用または代替として、logrotateなどの外部ツールが使用されています。
Pythonのログレベルとは何ですか?
ログ記録レベルは、イベントの深刻度を示す5つの主要なレベルと、継承動作に使用されるNotsetレベルで構成されています。
- 設定されていない = 0: これは、ログが作成されたときの初期デフォルト設定です。実際には重要ではなく、ほとんどの開発者はこのカテゴリにすら注意を払わないでしょう。多くの分野では、すでに必須ではなくなっています。通常、これはロガーが親ロガーから実効レベルを継承することを意味します。ルートログはデフォルトでレベルWARNINGで初期化されます。
- デバッグ = 10: このレベルでは詳細な情報が得られますが、問題の診断時のみ役立ちます。
- 情報= 20: これは、すべてが正常に機能していることを確認するために使用されます。
- 警告= 30: このレベルは、予期しないことが発生したか、近い将来に何らかの問題が発生しようとしていることを示します。
- エラー= 40: 文字通り、エラーが発生しました。ソフトウェアが機能を実行できませんでした。
- クリティカル = 50: 重大なエラーが発生しました。プログラム自体がシャットダウンするか、正常に動作しなくなる可能性があります。
注意: デフォルトでは、ルートロガーはWARNINGに設定されています。つまり、ログレベルが明示的に設定されていない限り、DEBUGおよびINFOメッセージは表示されません。
クイック概要
実際に各ログレベルをいつ使用すべきかについての簡単な参考資料を以下に示します。
| レベル | に使用します | サンプルメッセージ |
|---|
| DEBUG | 詳細な診断とトラブルシューティング機能。通常は開発時またはデバッグ時にのみ有効になります。 | 「構成Xを使用してデータベースに接続しています」 |
| INFO
| アプリケーションの正常な動作と主要な状態変化を確認する | 「ユーザーが正常にログインしました」 |
| 警告 | アプリの動作には影響しないものの、注意が必要となる可能性のある予期せぬ事象 | 「ディスク容量が不足しています」 |
| ERROR | 特定の操作または要求の機能に影響を与える障害 | 「データベース接続に失敗しました」 |
| CRITICAL | システムを混乱させる可能性のある、または即時の介入を必要とする重大な障害 | システム障害発生 - サービス利用不可 |
開発者はレベルを独自に定義できますが、これは推奨される方法ではありません。このモジュールのレベルは、長年の実務経験に基づいて作成されており、必要なすべての要件を網羅するように設計されています。
プログラマーがカスタムレベルを作成する必要性を感じた場合、特にライブラリを開発する際には、結果が必ずしも理想的とは限らないため、細心の注意を払う必要がある。
これは、複数のライブラリ作成者がそれぞれ独自のログレベルを定義すると、数値の意味が異なる可能性があるため、ライブラリを使用する開発者がログ出力を制御したり理解したりすることがほぼ不可能になるためです。
Pythonのログレベルを独自に作成すべきでしょうか?
Pythonでは、数値値を割り当て、logging.addLevelName()を使用して名前を登録することで、カスタムログレベルを定義できます。例:
NOTICE_LEVEL = 25
logging.addLevelName(NOTICE_LEVEL, "NOTICE")
カスタムレベルを完全に利用するには、対応するメソッド(例:logger.notice())を定義するか、logger.log() をカスタムレベル値とともに使用する必要があります。
ただし、カスタムレベルは一般的に推奨されません。標準レベル(DEBUG、INFO、WARNING、ERROR、CRITICAL)でほとんどのユースケースをカバーできるため、新しいレベルを導入すると、特にチーム間や共有ライブラリにおいて、ログの理解と管理が難しくなる可能性があります。
ロギング機能、つまりロガーの動作方法を設定する最も簡単な方法は、loggingモジュールのbasicConfig()メソッドを使用することです。ただし、Pythonのドキュメントによると、アプリケーション内の各モジュールごとに個別のロガーを作成することが推奨されています。
モジュールごとに個別のロガーを構成することは、basicConfig()だけでは難しい場合があります。 そのため、ほとんどのアプリケーションは、代わりにファイルまたは辞書のログ構成に基づいてシステムを自動的に使用します。
basicConfig() の主なパラメータ
basicConfig()のXNUMXつの主要なパラメーターは次のとおりです。
- レベル: レベルは、ログに記録するメッセージの最小優先度レベルを決定します。 メッセージは重大度の高い順にログに記録されます。DEBUGは最も脅威が少なく、INFOもそれほど脅威ではなく、WARNINGは注意が必要で、ERRORはすぐに注意が必要です。CRITICALは「すべてを削除して何が問題なのかを見つける」ことを意味します。 デフォルトの開始点はWARNINGです。これは、ロギングモジュールがDEBUGまたはINFOメッセージを自動的に除外することを意味します。
- ハンドラ: このパラメータは、ログの出力先を決定します。出力先が明示的に指定されていない限り、ログライブラリはデフォルトでStreamHandlerを使用し、すべてのログメッセージをsys.stderr(通常はコンソール)に出力します。
- フォーマット: メッセージをログに記録するためのデフォルト設定は次のとおりです。 : : 。
例えば、ルートロガーを設定して、すべてのメッセージ(DEBUGメッセージを含む)を表示するようにするには、次のようにします。
import logging
logging.basicConfig(level=logging.DEBUG)
logging.debug("This debug message will now appear")
これにより、デフォルトのしきい値がWARNINGからDEBUGに変更され、重要度の低いログも取得できるようになります。
ロギングモジュールはデフォルトで警告および高レベルのログのみをキャプチャするため、優先度の低いログに関する可視性が不足している可能性があります。 根本原因分析 必要とされている。
メインアプリケーションは、すべてのログメッセージが正しい場所に送信されるように、サブシステム内のログを構成できる必要があります。 Pythonのロギングモジュールは、これを微調整できる多くの方法を提供しますが、ほとんどすべてのアプリケーションで、構成は通常非常に単純です。
一般的に、構成は、ルートロガーへのフォーマッターとハンドラーの追加で構成されます。 これは非常に一般的な方法であるため、ロギングモジュールには、ほとんどのユースケースを処理するbasicConfigと呼ばれる標準化されたユーティリティ関数が装備されています。
より複雑なアプリケーションでは、ルートロガーだけに頼るのではなく、カスタムロガーを使用するのが一般的です。
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
logger.info("This is an info message from a custom logger")
カスタムロガーを使用すると、異なるモジュールが独立したログ記録動作を実現しながらも、共有のログ階層に参加し、伝播が無効になっていない限り、親ロガーから設定(ハンドラーなど)を継承することができます。
同じロガーに対して、異なるログレベルを持つ複数のハンドラーを設定することもできます。
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)
file_handler = logging.FileHandler("app.log")
file_handler.setLevel(logging.ERROR)
logger.addHandler(console_handler)
logger.addHandler(file_handler)
logger.debug("Debug message (console only)")
logger.error("Error message (console and file)")
この設定では、デバッグメッセージはコンソールに表示され、エラーメッセージのみがファイルに書き込まれます。
ログメッセージは出力される前に2つのチェックを通過する必要があります。まず、ロガーのレベルを満たしている必要があり、次にハンドラーのレベルを満たしている必要があります。これにより、ログに記録される内容と送信先をきめ細かく制御できます。
アプリケーションは、プロセスのできるだけ早い段階でログを構成する必要があります。 起動時にログメッセージが失われないように、これがアプリケーションが最初に行うことであることが望ましい。
アプリケーションは、メインアプリケーションコードをtryブロックとexceptブロックで囲むように設計し、例外が発生した場合は標準エラー出力ではなくログ出力インターフェースを通して送信するように指示する必要があります。
注意: basicConfig() はルートロガーを一度だけ設定します。ハンドラーが既に設定されている場合、force=True を指定しない限り、再度呼び出しても効果はありません。
ロガーのレベルが NOTSET に設定されている場合、そのロガーは親ロガーから実効レベルを継承します。この継承動作を反映した実際のレベルは、logger.getEffectiveLevel() を使用して確認できます。
logging.disable() を使用して、ログ記録をグローバルに無効にすることもできます。たとえば、logging.disable(logging.WARNING) は、WARNING レベル以下のすべてのメッセージ (WARNING、INFO、DEBUG など) を抑制します。
Pythonのログフォーマッタは、ログメッセージにコンテキストを追加します。これは、送信時刻、宛先、ファイル名、行番号、メソッド、その他のログ情報が必要な場合に非常に便利です。また、スレッドとプロセスを追加することは、マルチスレッドアプリケーションのデバッグ時に非常に役立ちます。
ログフォーマッタを介して送信されたときにログ「helloworld」がどうなるかの簡単な例を次に示します。
“%(asctime)s — %(name)s — %(levelname)s — %(funcName)s:%(lineno)d — %(message)s”
turns into:
2018-02-07 19:47:41,864 – a.b.c – WARNING – <module>:1 – hello world
以下は、Pythonで最もよく使用されるログフォーマットフィールドです。
| フィールド | 詳細説明 |
|---|
| %(昇順時間)s | ログが作成された日時を示すタイムスタンプ(フォーマッタのdatefmt設定に基づいてフォーマットされます) |
| %(レベル名)s | ログレベル(DEBUG、INFOなど) |
| %(名前) | 伐採者の名前 |
| %(lineno)d | ログがトリガーされた行番号 |
| %(funcName)s | ログが生成された関数名 |
| %(メッセージ)s | 実際のログメッセージ |
現代のアプリケーションでは、ログはプレーンテキストではなく、構造化された形式になっていることが多い。
JSON形式などの構造化ログを使用することで、ログを機械可読形式にすることができ、ELK、Datadog、Splunkなどのログ集約システムでの検索、フィルタリング、分析が容易になります。これは、複数のサービス間でログを関連付ける必要がある分散システムにおいて非常に役立ちます。
出力形式ごとに異なるフォーマッターを使用することもできます。
例えば、コンソール出力にはシンプルなフォーマット、ファイルログにはより詳細なフォーマットを用いる。
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# Console handler (simple format)
console_handler = logging.StreamHandler()
console_handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
# File handler (detailed format)
file_handler = logging.FileHandler("app.log")
file_handler.setFormatter(logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s"))
logger.addHandler(console_handler)
logger.addHandler(file_handler)
logger.info("Application started")
このアプローチにより、コンソールログを読む開発者と詳細なログファイルを処理するシステムなど、異なる対象者向けにログ出力をカスタマイズできる柔軟性が得られます。
特にPythonのログ記録を扱う場合、適切な文字列フォーマット方法を選択する必要があります。ログ呼び出しでは、%s形式のフォーマットが好まれることがよくあります。これは、ログレベルのチェックによってメッセージが実際に出力されるかどうかが決定され、ログシステムがメッセージを処理するまで文字列の補間が延期されるためです。
これにより、低レベルのログ(DEBUGなど)がフィルタリングされる際に発生する不要なパフォーマンスオーバーヘッドを回避できます。
Pythonロギングフォーマッタを使用すると、文字列のフォーマットが簡単になります。
古い Pythonの禅 「Pythonで何かをするための明白な方法がXNUMXつあるべきだ」と述べています。 現在、Pythonで文字列フォーマットを行うにはXNUMXつの主要な方法があります。
Pythonの文字列には、開発者が%演算子を使ってアクセスできる独自の組み込み操作が用意されています。これにより、素早く簡単に位置指定による書式設定を行うことができます。C言語のprintf関数に慣れている方なら、この操作の仕組みをすぐに理解できるでしょう。
具体的な例を挙げますと、以下の通りです。
>>> 'こんにちは、%s'%name
「こんにちは、マイク」
%s形式指定子は、名前の値をこの場所で置き換えて文字列として表す必要があることをPythonに通知します。
ログ記録においては、このスタイルは一般的に次のように使用されます。
logger.debug(“ユーザー %s がログインしました”, username)
つまり、ログレベルで処理が許可されている場合にのみ、文字列がフォーマットされるということです。
プログラマーが出力形式をより細かく制御できるように、他の書式指定子も用意されています。例えば、設計者は数値を16進数表記に変換したり、余白を追加してカスタム形式の表やレポートを作成したりすることができます。
文字列フォーマット構文の「旧式」形式は、1つの文字列内で複数の置換を行う場合、若干変更されます。%演算子は1つの引数しか受け付けないため、右辺をタプルで囲む必要があります。
Python 3では、文字列の書式設定を行う新しい方法が導入されましたが、これも後でPython2.7にアップグレードされました。 この「新しいスタイル」の文字列フォーマットにより、特別な構文%演算子は使用されなくなり、文字列フォーマットの構文がより規則的になります。 文字列オブジェクトのフォーマットは、.format()を呼び出すことで処理されるようになりました。
format() コマンドは、「旧式」の書式設定と同様の単純な位置指定タスクに使用できるほか、名前で指定され、任意の順序で使用される変数置換として参照することもできます。
DevOpsに携わる人なら、これは非常に強力な機能だと同意するでしょう。なぜなら、format()に渡される引数を変更することなく、表示順序を簡単に並べ替えることができるからです。
>>> '{name}さん、0x {errno:x}エラーが発生しました!'。format(
…name = name、errno = errno)
「ねえマイク、0xbadc0ffeeエラーがあります!」
この例は、int変数をXNUMX進文字列としてフォーマットする構文が変更されていることも示しています。 今必要なのはフォーマットスペックパスです。これは😡サフィックスを追加することで実現できます。 即座に、フォーマット文字列の構文はより強力になり、より単純なユースケースはより複雑になりませんでした。
Python 3を使用する場合は、「新しいスタイル」の文字列フォーマットを強くお勧めします。これは、%スタイルのフォーマットよりも優先する必要があります。 「古いスタイル」のフォーマットは、すべてを網羅するものとして強調されなくなりましたが、非推奨にはなりませんでした。 Pythonは、最新バージョンでもこのスタイルをサポートしています。
3)文字列補間
Python 3.6の導入により、文字列フォーマットの新しい方法が追加されました。 これは、フォーマットされた文字列リテラルまたは単に「f文字列」と呼ばれます。 文字列をフォーマットするこの新しいアプローチにより、開発者は文字列定数内に埋め込まれたPython式を使用できます。 これは、この機能がどのように感じられるかの簡単な例です。
>>> f 'こんにちは、{名前}!'
「こんにちは、マイク!」
F文字列は一般的なPythonコードで広く使用されていますが、ログ出力においては、ログメッセージが出力されない場合でも文字列が常に評価されるため、効率が低下する可能性があります。
文字列定数の前に文字「f」が付いていることは明らかです。そのため、「f-strings」と呼ばれています。 この強力な新しいフォーマット構文により、プログラマーは複雑な数学の問題を含む任意のPython式を埋め込むことができます。 Pythonによって作成された新しいフォーマット済み文字列リテラルは、f文字列を一連の文字列定数と式に変換するために作成された独自のパーサー機能と見なされます。 次に、接続して最終的な文字列を作成します。
f文字列を含むこのgreet()関数を見てください。
>>> def greet(name、question):
…returnf”こんにちは、{名前}! {質問}お元気ですか?」
...
>>> greet( 'Mike'、 'are you')
「こんにちは、マイク! 大丈夫?"
4)テンプレート文字列
Pythonで文字列をフォーマットするためのもうXNUMXつの優れたツールは、テンプレート文字列メソッドです。 これは単純ですが、それほど強力ではありませんが、機能に関しては、開発者が探している答えになる可能性があります。 この簡単な挨拶を見てください:
>>>文字列インポートテンプレートから
>>> t = Template( 'Hey、$ name!')
>>> t.substitute(name = name)
「ねえ、マイク!
Pythonの組み込み文字列モジュールのテンプレートクラスをインポートする必要がありました。 テンプレートはこのコードをすばやく簡単に作成しました。 テンプレート文字列はコア言語機能ではありませんが、標準のPythonライブラリの文字列モジュールによって提供されます。
このフォーマットを他のフォーマットと区別するもうXNUMXつの要因は、テンプレート文字列がフォーマット指定子を許可しないことです。 これは、前のエラー文字列の例が機能するためには、intエラー番号を手動でXNUMX進文字列に変換する必要があることを意味します。
では、Pythonプログラムでテンプレート文字列を使用するのはいつ良い考えですか? テンプレート文字列を使用する必要がある場合の最良のケースは、プログラムのユーザーが生成したフォーマット済み文字列の処理が必要な場合です。 それらはそれほど複雑ではないので、初心者の聴衆に食料調達するとき、テンプレート文字列はしばしばはるかに安全な選択です。
ログ記録に最適な選択肢: ほとんどのログ記録シナリオでは、不要な計算を回避し、loggingモジュールと直接統合できるため、%s形式のフォーマットが推奨されます。F文字列と.format()は一般的なPythonコードでは依然として有用ですが、ログ記録量の多いアプリケーションやパフォーマンスが重視されるアプリケーションでは慎重に使用する必要があります。
Python処理のエラーと例外
構文エラーまたは解析エラーは、最も一般的なアラートです。 パーサーは誤った行を繰り返し、エラーが最初に検出された場所を指し示します。 これは、不足しているデータを入力するだけで簡単に修正できます。
実行中にエラーが検出されると、例外が発生します。 ステートメントは構文的に正しい可能性がありますが、関数を完了できませんでした。 これは致命的なエラーではないため、簡単に処理できます。 ただし、プログラムは問題を自動的に処理しません。 プログラマーは間違いのある行を見つけて手動で解決する必要があります。
または、特定の予測可能な例外を処理するようにプログラムを作成することもできます。 ユーザーは有効な整数を入力するように求められます。 ただし、ユーザーはControl-Cコマンドまたは tryステートメント.
Pythonで例外をログに記録する方法
ロギングを行う際は、デバッグを容易にするために、例外を十分なコンテキストとともに記録してください。そのためには、Pythonのloggingモジュールの組み込みメソッドを使用できます。これらのメソッドは、エラーメッセージと完全なスタックトレースの両方をキャプチャします。
logging.exception() と logging.error(…, exc_info=True) の比較
どちらの方法もスタックトレース情報を含みますが、使用方法は若干異なります。
import logging
try:
result = 10 / 0
except Exception:
logging.exception("An error occurred") # Automatically includes stack trace
import logging
try:
result = 10 / 0
except Exception:
logging.error("An error occurred", exc_info=True) # Explicitly includes stack trace
logging.exception() は ERROR レベルでログを記録するショートカットであり、except ブロック内で使用することを想定しています。一方、logging.error(…, exc_info=True) はより柔軟性があり、他のコンテキストでも使用できます。
例外処理における変数とコンテキストのログ記録
実際のアプリケーションでは、エラーメッセージだけをログに記録するだけでは不十分な場合が多い。デバッグを大幅に効率化するために、ユーザーID、リクエストID、入力値などの関連する変数やコンテキストを含める必要がある。
import logging
user_id = 123
filename = "data.csv"
try:
open(filename)
except Exception:
logging.error(
"Failed to process file for user_id=%s, filename=%s",
user_id,
filename,
exc_info=True
)
このアプローチでは、問題の原因を理解するために必要なスタックトレースとランタイムコンテキストの両方が提供されます。
適切なPythonログレベルを選択して適用する
効果的なログ記録の鍵は、何を、なぜ記録するのかを意図的に決めることです。ログレベルは、さまざまな環境におけるシステムの動作を反映するべきであり、ハンドラーとフォーマットは、実際に重要なシグナルを容易に抽出できるようにする必要があります。
アプリケーションの規模が大きくなるにつれて、ログはシステム動作を理解する上で重要な要素となります。実際、適切に構造化されたログがあれば、実行フローの追跡、問題の診断、パフォーマンスの監視が容易になり、不要なノイズに惑わされることなく、自信を持って問題に対応できるようになります。
ログレベルを、その情報に基づいて実際にアクションを起こせるシステムに接続します。
ログだけでは、物語の一部しか語れません。メトリクス、アラート、 自動相関により、システム動作を理解し、問題を解決するための強力なツールになります。 問題をより迅速に解決する。
よくあるご質問
1. Pythonのデフォルトのログレベルは何ですか?
Python のデフォルトのログレベルは 警告つまり、明示的に設定を変更しない限り、警告、エラー、および重大レベルのメッセージのみが表示されます。
2. ロガーレベルとハンドラーレベルの違いは何ですか?
ログメッセージが渡される必要がある 2つのフィルター 出力前に:
- その ロガーレベル メッセージがそもそも処理されるかどうかを決定する
- その ハンドラーレベル 特定の宛先に送信されるかどうかを決定します
メッセージが表示されるには、両方の条件を満たす必要があります。
3. DEBUG、INFO、ERRORはそれぞれどのような場合に使い分けるべきですか?
意図に基づいてログレベルを使用する:
- DEBUG開発のための詳細な診断
- INFO
: 通常のアプリケーション動作と主要イベント
- 警告機能に影響を与えない予期せぬ状況
- ERROR特定の操作に影響を与える障害
- CRITICALアプリケーションを停止させる可能性のある深刻な問題
4. Pythonのログ記録はスレッドセーフですか?
はい、Python の logging モジュールは デフォルトでスレッドセーフ複数のスレッドからのログメッセージが互いに干渉しないように、内部ロックを使用しています。
5. デバッグにはログ出力とプリント出力のどちらを使うべきですか?
ロギング print() 単純なスクリプト以外のあらゆる用途に対応します。ログには以下の情報が含まれています。
- 重症度レベル
- 構造化された出力
- 柔軟な出力先(コンソール、ファイル、外部システム)
- 本番環境における拡張性の向上
6. 本番システムにおけるログの構造はどのようにすべきですか?
本番環境では、ログは 構造化され、一貫性がある:
- 機械可読性を高めるためにJSONなどのフォーマットを使用する
- コンテキスト情報(リクエストID、ユーザーIDなど)を含める
- サービス間でログレベルを標準化する
これにより、ログの検索、フィルタリング、分析が容易になります。
はい。Pythonログは、以下の方法で監視プラットフォームや可観測性プラットフォームと統合できます。
- ログを書き込む 標準出力/標準エラー出力 (容器によく見られる)
- ログシッパーを使用する FluentdまたはLogstash
- ログを次のようなプラットフォームに送信する ELK、Datadog、またはLogicMonitor
これにより、メトリクスやトレースとの関連付け、ログ記録、アラート設定を一元的に行うことが可能になります。
© LogicMonitor 2026 | 無断複写・転載を禁じます。 | ここで言及されているすべての商標、商号、サービス マーク、およびロゴは、それぞれの会社に帰属します。