Pythonのログレベルの説明

Pythonのログレベルの説明

アプリケーションの複雑さにより、適切なログの必要性が絶えず高まっています。 この必要性は、デバッグ目的だけでなく、アプリケーションのパフォーマンスと考えられる問題に関する洞察を収集するためにもあります。

Python標準ライブラリは、基本的なロギング機能のほとんどを提供する幅広い機能とモジュールです。 Pythonプログラマーは、他の方法では使用できないシステム機能にアクセスできます。 正しく設定されると、ログメッセージは、ログが起動された時間と場所、およびログのコンテキストに関する多くの有用な情報を引き出すことができます。

Pythonには、複雑なセットアップを必要とせずにアプリケーションの重要な可視性を提供するように設計された組み込みのロギングモジュールがあります。 企業が始めたばかりであろうと、Pythonのロギングモジュールに完全に没頭していようと、このモジュールの構成について学ぶことは常に新しく興味深いものです。 チームメンバーは、必要なすべてのデータを簡単にログに記録し、適切な場所にルーティングし、すべてのログを一元化して、重要なアプリケーションをより深く洞察することができます。

内容

Pythonロギングとは何ですか?

ロギングは、ITチームがソフトウェアアプリケーションの実行時に発生するイベントを追跡する方法です。 ロギングはソフトウェア開発の重要な部分です、デバッグ、および完成したプログラムのスムーズな実行。 開発段階の正確なログがないと、プログラムがクラッシュした場合、問題の原因を検出できる可能性は非常に低くなります。

なんらかの奇跡によって原因を突き止めることができれば、それは骨の折れる、時間のかかる試練となるでしょう。 ロギングを使用すると、問題の根本に簡単にたどることができるデジタルブレッドクラムトレイルが残ります。

Pythonには、ロギングモジュールが装備されています。 標準でありながら大規模なライブラリ これは、すべてのPythonプログラムからログメッセージを出力するための柔軟なフレームワークを提供します。 このPythonロギングモジュールはライブラリによって広く使用されており、ロギング時に多くの開発者にとって最初の頼りになるポイントになっています。

この不可欠なモジュールは、アプリケーションがさまざまなログハンドラーを構成するための最良の方法と、ログメッセージを正しいハンドラーにルーティングする方法を提供します。 これにより、さまざまなユースケースに対応できる非常に柔軟な構成が可能になります。

ログレベルは、ログの「重要性」に関連しています。 たとえば、「エラー」ログは最優先事項であり、「警告」ログよりも緊急性が高いと見なす必要があります。 「デバッグ」ログは通常、アプリケーションがデバッグされている場合にのみ役立ちます。

PythonにはXNUMXつのログレベルがあり、それぞれにログの重大度を示す特定の整数が割り当てられています。

  • NOTSET = 0
  • DEBUG = 10
  • INFO = 20
  • 警告= 30
  • エラー= 40
  • CRITICAL = 50

ログメッセージを送信するには、発信者は最初に名前付きロガーを要求する必要があります。 この名前は、アプリケーションがさまざまなロガーのさまざまなルールセットを構成するために使用できます。 次に、ロガーを使用して、さまざまなログレベル(DEBUG、INFO、ERRORなど)で単純な形式のメッセージを送信できます。アプリケーションは、これを使用して、重要度が高く、優先度が低いメッセージを処理できます。 これはかなり複雑に聞こえるかもしれませんが、それは本当に簡単です。

舞台裏では、メッセージはログレコードオブジェクトに転送されてから、このロガーに特別に登録されているハンドラーオブジェクトにルーティングされます。 次に、ハンドラーはフォーマッターを使用してログレコードを文字列に変換し、その文字列を送信します。

幸いなことに、ほとんどの場合、開発者は詳細を意識する必要はありません。 すべてがバックグラウンドでシームレスに行われます。

一部の開発者は、ステートメントが正しく実行されているかどうかを検証するために印刷方法を使用することを選択します。 ただし、印刷は理想的なソリューションではありません。 単純なスクリプトの問題は解決できるかもしれませんが、複雑なスクリプトの場合、印刷アプローチは適切ではありません。

印刷が不適切な理由

印刷がロギングの理想的なソリューションではない主な理由は、印刷ではエラーが発生したときのタイムスタンプが提供されないためです。

エラーがいつ発生したかを正確に知ることは、アプリケーションをデバッグする際の重要な要素であることがわかります。 リアルタイムで実行およびテストできるコードの小さなパケットにとってはそれほど重要ではないかもしれませんが、エラータイムスタンプのない大きなアプリケーションはいくつかの深刻な結果をもたらします。 XNUMXつのオプションは、その追加情報の日時モジュールを追加することですが、これは非常に厄介なコードベースを作成します。 この方法を避けるべき他のいくつかの理由は次のとおりです。 

  • 印刷メッセージをすべての種類のファイルに保存できるわけではありません。
  • 印刷メッセージは最初にテキスト文字列に変換されます。 開発者は、印刷でfile引数を使用して、メッセージをファイルに保存できます。 ただし、バイナリファイルにメッセージを書き込むことはできないため、write(文字列)メソッドを持つオブジェクトである必要があります。
  • 印刷ステートメントは分類が困難です。

たとえば、多種多様な印刷ステートメントを含むログファイルを考えてみましょう。 アプリケーションが開発のさまざまな段階を経て本番環境に移行すると、これらの印刷ステートメントを分類してデバッグすることはほぼ不可能です。 printステートメントは、さまざまな段階に合わせて追加情報を提供するように変更できますが、これにより、コードベースに無用なデータの負荷が追加され、その印刷に適していない、または実行するように構築されていないことを強制しようとします。

レベルに応じたPythonロギングのベストプラクティス

Pythonの標準ライブラリには、柔軟なロギングモジュールが組み込まれているため、開発者はさまざまなロギングのニーズに合わせてさまざまな構成を作成できます。 このモジュールに含まれる関数は、開発者がさまざまな宛先にログを記録できるように設計されています。 これは、特定のハンドラーを定義し、指定されたハンドラーにログメッセージを送信することによって行われます。

ログレベルは、ログエントリの検索、フィルタリング、および分類を目的としてログエントリに追加されるラベルです。 これは、情報の粒度を管理するのに役立ちます。 標準のログライブラリを使用してログレベルを設定すると、そのレベル以上のイベントのみが記録されます。

各ログエントリのタイムスタンプを常に含めることが重要です。 いつイベントが発生したかを知ることは、イベントについてまったく知らないことよりもはるかに優れているわけではありません。 この情報は、トラブルシューティングだけでなく、分析用途のより良い洞察にも役立ちます。

残念ながら、タイムスタンプに使用する形式について人々が常に同意しているわけではありません。 最初の本能は、原産国の標準を使用することですが、アプリケーションが世界中で利用可能である場合、これは非常に混乱する可能性があります。 推奨される形式はISO-8601と呼ばれます。 これは国際的に認められた標準であり、YYYY-MM-DDの後に時刻が続きます(2021-07-14T14:00-02:00)。

Pythonロギングモジュールの利点

Pythonロギングモジュールは、これらすべての問題に対するインテリジェントなソリューションを提供します。

ログに記録されるメッセージの形式は簡単に制御できます。 モジュールには、ログに含めたり、ログから除外したりできるさまざまな便利な属性が備わっています。 これにより、開発段階のクリーンで有益なログが残ります。

メッセージは、分類を容易にするために、さまざまなレベルの緊急性または警告情報とともにログに記録できます。 ログが適切に分類されていると、アプリケーションのデバッグも簡単になります。 さらに、ログの宛先は、ソケットを含め、何にでも設定できます。

適切に構成されたPythonアプリケーションは、ほとんどの場合、複数のモジュールで構成されています。 場合によっては、これらのモジュールを他のプログラムで使用することを意図していますが、開発者がアプリケーション内で再利用可能なモジュールを意図的に設計しない限り、ユーザーはPython PackageIndexから入手可能なモジュールと開発者が作成したモジュールを使用している可能性があります。特に特定のアプリケーション向けです。

通常、モジュールはベストプラクティスとしてのみログメッセージを生成し、それらのメッセージの処理方法を構成しません。 アプリケーションはその部分に責任があります。

モジュールが持つべき唯一の責任は、アプリケーションがログメッセージを簡単にルーティングできるようにすることです。 これが、各モジュールがモジュール自体と同じ名前のロガーを使用することが標準である理由です。 このように、アプリケーションが異なるモジュールを異なる方法でルーティングするのは簡単ですが、それでもモジュール内のログコードは単純に保ちます。 このモジュールでは、ロギングを設定して、という名前のロガーを使用するためにXNUMX行の簡単な行が必要です。

Pythonからファイルへ

ロギングモジュールを使用してイベントをファイルに記録するのは簡単で簡単です。 モジュールは単にライブラリからインポートされます。 その後、必要に応じてロガーを作成および構成できます。 複数の境界を設定できますが、イベントを記録するファイルの名前を渡すことが重要です。

ここでロガーのフォーマットも設定できます。 デフォルトは追加モードに設定されていますが、必要に応じて書き込みモードに変更できます。 また、この時点でロガーレベルを設定することができます。 これは、各レベルに割り当てられた値に基づいて、追跡目的のしきい値として機能します。 いくつかの属性をパラメーターとして渡すことができます。 パラメータのリストはPythonライブラリで入手できます。 属性は要件に応じて選択されます。

ファイルにログを記録する主な利点のXNUMXつは、外部の宛先にログをストリーミングしているときに、ネットワークに関連するエラーが発生する可能性をアプリケーションが必ずしも考慮する必要がないことです。 ネットワークを介してログをストリーミングするときに問題が発生した場合でも、ログはすべて各サーバーにローカルに保存されるため、それらのログへのアクセスが失われることはありません。 ファイルにログを記録するもうXNUMXつの利点は、完全にカスタマイズ可能なログ設定を作成できることです。 さまざまなタイプのログを個別のファイルにルーティングしてから、ログ監視サービスを使用して調整および一元化できます。

Pythonのログレベルとは何ですか?

必要なロギングモジュールは、すでにPython標準ライブラリの一部です。 したがって、ITチームはログをインポートするだけで、すべてが順調に進みます。 デフォルトには、イベントの重大度を示すXNUMXつの標準ログレベルが含まれています。 これらは:

  • 設定されていない = 0:これは、ログが作成されたときのログの初期デフォルト設定です。 これは実際には関係がなく、ほとんどの開発者はこのカテゴリに気付くことさえありません。 多くのサークルでは、それはすでに不要になっています。 ルートログは通常、レベルWARNINGで作成されます。
  • デバッグ= 10:このレベルは詳細情報を提供し、問題が診断されている場合にのみ役立ちます。
  • 情報= 20: これは、すべてが正常に機能していることを確認するために使用されます。
  • 警告= 30: このレベルは、予期しないことが発生したか、近い将来に何らかの問題が発生しようとしていることを示します。
  • エラー= 40: それが意味するように、エラーが発生しました。 ソフトウェアは一部の機能を実行できませんでした。
  • クリティカル= 50:重大なエラーが発生しました。 プログラム自体がシャットダウンしたり、正常に実行を継続できなくなったりする場合があります。

開発者はレベルを定義できますが、これは推奨される方法ではありません。 モジュールのレベルは、長年の実務経験を通じて作成されており、必要なすべてのベースをカバーするように設計されています。 プログラマーがカスタムレベルを作成する必要性を感じた場合、特にライブラリを開発する場合、結果が理想的とは言えない可能性があるため、細心の注意を払う必要があります。 これは、複数のライブラリ作成者がカスタムレベルを定義する場合、数値は異なる意味を持つ可能性があるため、ライブラリを使用する開発者がログ出力を制御または理解することはほぼ不可能になるためです。

Pythonロギングを構成する方法

開発者が必要とするロギングモジュールは、Python標準ライブラリにすでに含まれています。つまり、何もインストールしなくても、ロギング機能をすぐに実装できます。 ロガーが想定されている方法でロギング機能を構成する最も簡単な方法は、ロギングモジュールのbasicConfig()メソッドを使用することです。 ただし、Pythonのドキュメントによると、アプリケーションのモジュールごとに個別のロガーを作成することをお勧めします。

モジュールごとに個別のロガーを構成することは、basicConfig()だけでは難しい場合があります。 そのため、ほとんどのアプリケーションは、代わりにファイルまたは辞書のログ構成に基づいてシステムを自動的に使用します。

basicConfig()のXNUMXつの主要なパラメーターは次のとおりです。

  • レベル: レベルは、ログに記録するメッセージの最小優先度レベルを決定します。 メッセージは重大度の高い順にログに記録されます。DEBUGは最も脅威が少なく、INFOもそれほど脅威ではなく、WARNINGは注意が必要で、ERRORはすぐに注意が必要です。CRITICALは「すべてを削除して何が問題なのかを見つける」ことを意味します。 デフォルトの開始点はWARNINGです。これは、ロギングモジュールがDEBUGまたはINFOメッセージを自動的に除外することを意味します。
  • ハンドラ: このパラメーターは、ログをルーティングする場所を決定します。 宛先が明確に特定されていない限り、ロギングライブラリは本能的にStreamHandlerを使用して、ログに記録されたすべてのメッセージをsys.stderr(通常はコンソール)に送信します。
  • フォーマット: メッセージをログに記録するためのデフォルト設定は次のとおりです。 : : 。

ロギングモジュールはデフォルトで警告および高レベルのログのみをキャプチャするため、優先度の低いログに関する可視性が不足している可能性があります。 根本原因分析 必要とされている。

メインアプリケーションは、すべてのログメッセージが正しい場所に送信されるように、サブシステム内のログを構成できる必要があります。 Pythonのロギングモジュールは、これを微調整できる多くの方法を提供しますが、ほとんどすべてのアプリケーションで、構成は通常非常に単純です。

一般的に、構成は、ルートロガーへのフォーマッターとハンドラーの追加で構成されます。 これは非常に一般的な方法であるため、ロギングモジュールには、ほとんどのユースケースを処理するbasicConfigと呼ばれる標準化されたユーティリティ関数が装備されています。

アプリケーションは、プロセスのできるだけ早い段階でログを構成する必要があります。 起動時にログメッセージが失われないように、これがアプリケーションが最初に行うことであることが望ましい。

アプリケーションは、例外がstderrではなくロギングインターフェイスを介して送信されるように指示するメインアプリケーションコードの周りにtry andexceptブロックをラップするように設計する必要があります。

Pythonロギングフォーマット

Pythonロギングフォーマッタは、ログメッセージを強化するためにコンテキスト情報を追加します。 これは、送信時刻、宛先、ファイル名、行番号、メソッド、およびログに関するその他の情報が必要な場合に非常に役立ちます。 また、スレッドとプロセスを追加すると、マルチスレッドアプリケーションをデバッグするときに非常に役立ちます。

ログフォーマッタを介して送信されたときにログ「helloworld」がどうなるかの簡単な例を次に示します。

「%(asctime)s —%(name)s —%(levelname)s —%(funcName)s:%(lineno)d —%(message)s」

に変わる:

2018-02-07 19:47:41,864 – abc –警告– :1 – Hello world

Pythonでの文字列フォーマット

Pythonロギングフォーマッタを使用すると、文字列のフォーマットが簡単になります。

古い Pythonの禅 「Pythonで何かをするための明白な方法がXNUMXつあるべきだ」と述べています。 現在、Pythonで文字列フォーマットを行うにはXNUMXつの主要な方法があります。

1)「古いスタイル」のPython文字列フォーマット

Pythonの文字列は、開発者が%操作でアクセスできる独自の組み込み操作で設計されています。 これにより、すばやく簡単な位置フォーマットが可能になります。 Cのprintfスタイルの関数に精通している人は、この操作がどのように機能するかをすぐに理解できます。

例:

>>> 'こんにちは、%s'%name

「こんにちは、マイク」

%s形式指定子は、名前の値をこの場所で置き換えて文字列として表す必要があることをPythonに通知します。

プログラマーが出力フォーマットをより細かく制御できるようにするために、他のフォーマット指定子を使用できます。 たとえば、設計者は、数値をXNUMX進表記に変換したり、小さな空白のパディングを追加して、カスタム形式のテーブルやレポートを作成したりできます。

文字列形式の構文の「古いスタイル」の形式は、XNUMXつの孤立した文字列で複数の置換を行う必要がある場合にわずかに変化します。 %演算子はXNUMXつの引数にしか応答しないため、タプルの右側を折り返す必要があります。 

2)Python3は「新しいスタイル」の文字列フォーマットを導入します

Python 3では、文字列の書式設定を行う新しい方法が導入されましたが、これも後でPython2.7にアップグレードされました。 この「新しいスタイル」の文字列フォーマットにより、特別な構文%演算子は使用されなくなり、文字列フォーマットの構文がより規則的になります。 文字列オブジェクトのフォーマットは、.format()を呼び出すことで処理されるようになりました。

format()コマンドは、「古いスタイル」のフォーマットのタスクと同じように単純な位置タスクに使用できます。または、名前で指定され、任意の順序で使用される変数置換と呼ばれることもあります。 DevOpsで作業している人は、format()に渡される引数を変更せずに表示の順序を簡単に再配置できるため、これが非常に強力な機能であることに同意します。

>>> '{name}さん、0x {errno:x}エラーが発生しました!'。format(

…name = name、errno = errno)

「ねえマイク、0xbadc0ffeeエラーがあります!」

この例は、int変数をXNUMX進文字列としてフォーマットする構文が変更されていることも示しています。 今必要なのはフォーマットスペックパスです。これは😡サフィックスを追加することで実現できます。 即座に、フォーマット文字列の構文はより強力になり、より単純なユースケースはより複雑になりませんでした。

Python 3を使用する場合は、「新しいスタイル」の文字列フォーマットを強くお勧めします。これは、%スタイルのフォーマットよりも優先する必要があります。 「古いスタイル」のフォーマットは、すべてを網羅するものとして強調されなくなりましたが、非推奨にはなりませんでした。 Pythonは、最新バージョンでもこのスタイルをサポートしています。

Python開発メーリングリストとPython開発バグトラッカーの最近の問題でこの問題について議論している分野の専門家によると、「古い」%フォーマットはすぐになくなることはありません。 それはまだかなり長い間存在するでしょう。 Python 3の公式ドキュメントは、この意見を支持していないか、「古いスタイル」のフォーマットについてあまりにも高く評価しています。

「ここで説明するフォーマット操作は、いくつかの一般的なエラー(タプルと辞書を正しく表示できないなど)につながるさまざまな癖を示しています。 新しいフォーマットの文字列リテラルまたはstr.format()インターフェイスを使用すると、これらのエラーを回避できます。 これらの代替手段は、テキストをフォーマットするためのより強力で、柔軟性があり、拡張可能なアプローチも提供します。」 出典:Python 3

これが、開発者の大多数が新しいコードのstr.formatに忠誠を誓うことを好む理由です。 現在、Python 3.6以降、文字列をフォーマットするためのさらに別の革新的な方法があります。

3)文字列補間

Python 3.6の導入により、文字列フォーマットの新しい方法が追加されました。 これは、フォーマットされた文字列リテラルまたは単に「f文字列」と呼ばれます。 文字列をフォーマットするこの新しいアプローチにより、開発者は文字列定数内に埋め込まれたPython式を使用できます。 これは、この機能がどのように感じられるかの簡単な例です。

>>> f 'こんにちは、{名前}!'

「こんにちは、マイク!」

文字列定数の前に文字「f」が付いていることは明らかです。そのため、「f-strings」と呼ばれています。 この強力な新しいフォーマット構文により、プログラマーは複雑な数学の問題を含む任意のPython式を埋め込むことができます。 Pythonによって作成された新しいフォーマット済み文字列リテラルは、f文字列を一連の文字列定数と式に変換するために作成された独自のパーサー機能と見なされます。 次に、接続して最終的な文字列を作成します。

f文字列を含むこのgreet()関数を見てください。

>>> def greet(name、question):

…returnf”こんにちは、{名前}! {質問}お元気ですか?」

...

>>> greet( 'Mike'、 'are you')

「こんにちは、マイク! 大丈夫?"

関数を逆アセンブルし、舞台裏で何が起こっているかを調べることで、関数内のf文字列が次のように変換されていることが簡単にわかります。

>>> def greet(name、question):

…「こんにちは」+名前+「! 」+質問+「?」はどうですか

実際の実装は、最適化としてBUILD_STRINGオペコードを使用するため、それよりもわずかに高速です。 ただし、機能的には、概念は同じです。

4)テンプレート文字列

Pythonで文字列をフォーマットするためのもうXNUMXつの優れたツールは、テンプレート文字列メソッドです。 これは単純ですが、それほど強力ではありませんが、機能に関しては、開発者が探している答えになる可能性があります。 この簡単な挨拶を見てください:

>>>文字列インポートテンプレートから

>>> t = Template( 'Hey、$ name!')

>>> t.substitute(name = name)

「ねえ、マイク!

Pythonの組み込み文字列モジュールのテンプレートクラスをインポートする必要がありました。 テンプレートはこのコードをすばやく簡単に作成しました。 テンプレート文字列はコア言語機能ではありませんが、標準のPythonライブラリの文字列モジュールによって提供されます。

このフォーマットを他のフォーマットと区別するもうXNUMXつの要因は、テンプレート文字列がフォーマット指定子を許可しないことです。 これは、前のエラー文字列の例が機能するためには、intエラー番号を手動でXNUMX進文字列に変換する必要があることを意味します。

では、Pythonプログラムでテンプレート文字列を使用するのはいつ良い考えですか? テンプレート文字列を使用する必要がある場合の最良のケースは、プログラムのユーザーが生成したフォーマット済み文字列の処理が必要な場合です。 それらはそれほど複雑ではないので、初心者の聴衆に食料調達するとき、テンプレート文字列はしばしばはるかに安全な選択です。

Python処理のエラーと例外

構文エラーまたは解析エラーは、最も一般的なアラートです。 パーサーは誤った行を繰り返し、エラーが最初に検出された場所を指し示します。 これは、不足しているデータを入力するだけで簡単に修正できます。

実行中にエラーが検出されると、例外が発生します。 ステートメントは構文的に正しい可能性がありますが、関数を完了できませんでした。 これは致命的なエラーではないため、簡単に処理できます。 ただし、プログラムは問題を自動的に処理しません。 プログラマーは間違いのある行を見つけて手動で解決する必要があります。

または、特定の予測可能な例外を処理するようにプログラムを作成することもできます。 ユーザーは有効な整数を入力するように求められます。 ただし、ユーザーはControl-Cコマンドまたは tryステートメント.

tryステートメントの仕組みは次のとおりです。

  • 最初に、「try句」(tryキーワードとexceptキーワードの間のステートメント)が実行されます。
  • 例外が発生しない場合、except句は無視され、try句の実行部分が完了します。
  • try句の実行中に例外が発生した場合、句の他のすべての部分はスキップされます。 指定されたexceptキーワードの後に​​ある名前付き例外とタイプが一致する場合、except句が実行されます。 その後、try句の後に実行が続行されます。
  • 例外句で指定された例外と一致しない例外が発生した場合、それは外部のtryステートメントに渡されます。 ハンドラーが見つからない場合は、未処理の例外となり、実行フェーズが停止し、エラーメッセージが表示されます。

tryステートメントには、さまざまな例外のハンドラーをより適切に指定するために、多くの場合、複数のexcept句が含まれます。 ただし、最大でも、実行プロセスはXNUMXつのハンドラーに対してのみ行われます。 ハンドラーは、対応するtryステートメント内で発生する例外のみを処理し、同じtryステートメントの他のハンドラーで発生する例外は処理しません。 例外句は、多くの場合、括弧で囲まれたタプルとして囲まれた複数の例外に名前を付けます。

まとめ

Pythonは、使いやすく、非常に用途が広く、サードパーティツールの大規模なエコシステムを提供するため、非常に人気のある言語です。 Webアプリケーションからデータサイエンスライブラリ、SysAdminスクリプト、その他多くの種類のプログラムまで、さまざまなケースシナリオに対応するのに十分な汎用性があります。

Pythonロギングは、標準ライブラリに組み込まれた強力なロギングフレームワークにより、シンプルで十分に標準化されています。

すべてのモジュールは、モジュール名ごとにすべてをロガーレコードに記録するだけです。 これを行うことにより、アプリケーションがさまざまなモジュールのすべてのログメッセージを適切な場所にルーティングするのが簡単になります。

その後、アプリケーションはログを構成するための最適なオプションを選択できます。 ただし、最新のインフラストラクチャでは、ベストプラクティスに従うことで、プロセス全体が大幅に簡素化されます。