web-dev-qa-db-ja.com

より良い条件付きデバッグパターン?

デバッグモードでのみログを記録する必要がある場合、最も簡単な方法は次の条件を使用することです。

def test(x, debug=False):
    if debug:
        print(x)

    # ...Some more code

    if debug:
        print("Something else")

    # ...More conditional logging

    return x * 2

これにより、実際の関数ロジックが乱雑になります。これを改善するために私が考えることができる最高のことは、それを関数の後ろに隠して混乱を少なくすることでした:

def _log_if_debug(info, debug):
    if debug:
        print(info)

def test(x, debug=False):
    _log_if_debug(x, debug)

    # ...Some more code

    _log_if_debug("Something else", debug)

    # ...More conditional logging
    return x * 2

これを行うためのより良いパターンはありますか?

6
Veneet Reddy

標準のログライブラリを使用

Pythonには、適切なパターンが1つだけあります:se standard logging moduleに従って official HowTo に従います。または、 for Python 3、this standard logging module and this HowTo 。これらのバージョン間に重要な違いはありません¹。

標準ライブラリを嫌う理由がある場合は、代替として、既存の置換の1つを使用するを使用できます。それらは異なる構成といくつかの拡張機能を持っていますが、基本的な使用法は類似または同一です。後で連絡します。いつでもそれらに切り替えるのは比較的簡単なはずなので、loggingは少なくとも良い出発点です。

モジュールでの使用法

コードは次のようになります。

import logging

logger = logging.getLogger(__name__)  # you can use other name

logger.info('Loading my cool module with cool logging')

    def coolFunction(x):
        logger.debug('Most of the time this message is really irrelevant')
        ...
        if something_suspicious:
            logger.warning('Something suspicious happened: nothing broken yet, but you probably want to know')
        ...
        if everything_is_wrong:
            logger.error('Everything is broken and this program just went nuts')

または、より単純な方法を使用することもできます。

logging.info(...)
logging.debug(...)

ロガーを作成する代わりに、この単一の行をどこにでも追加するのは十分簡単なようです。

さまざまなメッセージに使用するロギングレベルがわからない場合は、 this SO question を参考にして適切な回答を得ることができます。

構成

次に、あなたのcofigのどこかであなたは言う:

logging.basicConfig(filename='example.log', level=logging.INFO)

または

logging.basicConfig(filename='example.log', level=logging.DEBUG)

出力を設定し、エラーを適切にフィルタリングします。 stderrを使用したい場合は、

logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)

代わりに。

代替ハンドラー、外部サービスへのロギング

raven for Sentry のように、基本的なロガーの代わりに使用できるライブラリもいくつかあります。このようなサービスを利用するためにコードを変更する必要はありません。構成を変更するだけです。

代替ライブラリ

loggingを完全に置き換えるために使用できるライブラリがいくつかあります。それらは同様のパターン、中央ロギング構成に従い、次に各ファイルのロガーにアクセスし、ログレベルを使用してログを記録します。 ログブック は、ログ記録のほとんどがドロップインの代替手段であるようで、いくつかのニース機能が追加されています。他にもいくつか言及されています これでSO質問

最適化されたビルドからのロギングの削除

デバッグログが本番環境でパフォーマンスに大きな影響を与えるか、機密データをリークする可能性がある極端なケースでは、組み込みの __debug__ 定数を使用できます。

if __debug__:
    debug_info = some_complex_computation()
    logger.debug()

この場合、-oオプションを使用してコードをコンパイルすると、ステートメント全体が消去されます。ただし、このソリューションは醜く、ややもろいので、本当に必要な場合にのみ注意して使用する必要があります。ほとんどのアプリケーションでは、「どこにもない」を意味します。

その他の言語

他の言語の場合、見た目は同じ(Javaの場合など)またはわずかに異なる場合があり、多少異なる場合があります(すべての言語に1つの標準的な方法があるわけではありません)。しかし、一般的に、非常によく似たパターンが見つかります。

LOG(DEBUG, "Your message")

または

LOG_ERROR("Error message")

または

LOG(INFO) << "Some people like C++ streams' syntax"

¹知っておくべき唯一の違いは、Python 3にはstderrorにログを記録する「最後の手段」のロガーがあるため、設定を完全に省略しても、まだ。Python 2で、ログの設定ミスに関する警告が表示されます。

8
Frax

もちろん、メソッドをlog()だけで呼び出します。

ばかげているように聞こえますが、短いメソッド名をコード全体に散りばめることは、長いメソッド名よりも2倍読みやすくなっています。

次のレベルの読みやすさは、横断的な関心事をビジネスロジックから完全に分離し、ある種のアスペクト指向のツールでそれらを織り込むことです。しかし、それははるかに多くの努力です(確かに、より良い結果を得るために)。

3
Kilian Foth

閉鎖について聞いたことがありますか?

log = buildLog(debug)

...

log("Something ya wanna log")

これで、ロギングをグローバルに制御したり、有効なログ機能を現在必要ないくつかのログに渡すだけでローカルに制御したりできます。この小さなスキームは、デフォルトの引数とうまく結合します。

3
candied_orange