コンテンツにスキップ

手動トレーシングの追加

スパン、ログ、およびトレース

Logfireを使用する簡単な例を次に示します。

import time

import logfire

logfire.configure()

with logfire.span('This is a span'):
    time.sleep(1)
    logfire.info('This is an info log')
    time.sleep(2)

これを実行すると、次のようなものが印刷されます。

Logfire project URL: https://logfire.pydantic.dev/my_username/my_project_name
21:02:55.078 This is a span
21:02:56.084   This is an info log

プロジェクトのURLを開くと、Liveビューに次のように表示されます。

ライブビューでの簡単な例

1+ が付いた青いボックスは、スパンに1つの直接子項目が含まれていることを示しています。このボックスをクリックすると、スパンを拡張して子項目を表示できます。

スパンを開いたライブビューの簡単な例

ご注意ください:

  1. with logfire.span(...): ブロックで作成されたスパンまたはログは、そのスパンのサブアイテムになります。これにより、構造化ツリーでログをうまく整理できます。この親子関係は、インデントベースのコンソールログでも確認できます。

  2. スパンには開始時間と終了時間があるため、持続時間があります。このスパンを完了するのに3秒かかります。

  3. ログの場合、開始時間と終了時間は同じなので、継続時間はありません。ただし、スパンの開始から1秒後、スパンの終了から2秒前にログが作成されていることはUIで確認できます。

上部のナビゲーションバーの[探索]リンクをクリックすると、次のようなSQLを記述してさらに探索できます。

エクスプローラビューのクエリ:選択抽出('秒'からend_timestamp-start_timestamp)として期間、種類、メッセージ、トレース_id、スパン_id、親_スパン_idレコードから順にstart_timestamp

注意:

  1. スパンとログは同じ 记录 テーブルに一緒に保存されます。

  2. ログ 的parent_span_id は span_id のスパンです。

  3. どちらも同じ trace_id を持っています。それをクリックすると、_が_を追跡するためにフィルタリングされたライブビューの新しいタブが開きます。

_トレース_は、同じスパン/ログツリーを共有します。アクティブなスパンなしで新しいスパン/ログが作成されるたびに、新しいトレースが作成されます。スパンの場合、そのスパンの子孫はすべて同じトレースの一部になります。 ログをトレースにうまく整理するには、Webサーバーのリクエストを処理するなど、高度な操作を表すスパンを最上位に作成するのが最適です。

プロパティ

スパンとログには、次のような構造化データを追加できます。

logfire.info('こんにちは', name='世界')

ライブビューで「Hello」ログをクリックすると、右側の詳細パネルに次の内容が表示されます。

Liveビューのname属性

このデータは、记录 テーブルの 属性 カラムにJSON形式で格納されます。たとえば、ライブビューの上部にあるSQLフィルタで attributes->>'name' = 'world' を使用すると、このログのみを表示できます。これは、记录 テーブルのSQLクエリの WHERE 句として使用されます。

spanもlogsも、必要に応じてJSONにインテリジェントにシリアル化される任意の値を含むプロパティを持つことができます。_ で始まらない限り、任意のキーワード引数を渡してプロパティを設定できます。 この名前空間は、logfire固有の意味を持つ他のキーワードパラメーター用に予約されています。

時々、スコープを作成した後でも、スコープが完成する前にプロパティをスコープに添付すると便利です。span.set_attribute メソッドを呼び出すことで、これを行うことができます。

with logfire.span('Calculating...') as span:
    result = 1 + 2
    span.set_attribute('result', result)

メッセージとスパン名

このコードを実行する場合:

import logfire

logfire.configure()

for name in ['Alice', 'Bob', 'Carol']:
    logfire.info('Hello {name}', name=name)

探索ビューでのクエリ: select span_name、属性->>'name'を名前として、レコードからのメッセージをstart_timestampで並べ替えます。

ここで見ることができます。

  1. 最初の引数 “Hello {name}” は span_name カラムの値になります。これを使用すると、SQLフィルタ span_name = 'Hello {name}' を使用するなど、メッセージが異なっていても、同じコードからすべてのレコードを検索できます。

  2. span名は str.format スタイルのテンプレートとしても使用され、プロパティを使用してフォーマットされ、消息 カラムが生成されます。メッセージは、コンソールログとライブビューに表示されます。

span.message は、スパンの開始後、スパンが完了する前に設定することもできます。

with logfire.span('Calculating...') as span:
    result = 1 + 2
    span.message = f'Calculated: {result}'

“Hello%”之类的消息 などの関連レコードをフィルタリングするために 消息 を使用することもできますが、span_name カラムをフィルタリングする方がインデックス化されているので効率的です。繰り返しになりますが、message = 'Hello Alice' よりも span_name = 'Hello {name}' 和 attributes->>'name' = 'Alice' の方が優れています。

関連するレコードを効率的にフィルタリングできるようにするには、スパン名の_基数_を低くする必要があります。つまり、あまり変更しないでください。たとえば、次のようになります。

name = get_username()
logfire.info('Hello ' + name, name=name)

現在、span_name 列はユーザー名ごとに異なる値を持つようになりました。しかし、これは問題ありません:

現在、span_name カラムには2つの値('Goodbye {name}' と 'Hello {name}')しかなく、span_name = '{word} {name}' 和 attributes->>'word' = 'Hello' よりも span_name = 'Hello {name}' をフィルタリングする方が簡単で効率的です。

メッセージテンプレートとは異なるスパン名が必要な場合は、_span_name パラメータを使用できます。

word = 'Goodbye' if leaving else 'Hello'
logfire.info(word + ' {name}', name=name)

これにより、span_name が “Hello” に、消息 が “Hello world”。 に設定されます。_span_name パラメーターは、プロパティと区別するために下線で始まることに注意してください。

logfire.info('Hello {name}', name='world', _span_name='Hello')

f文字列


代わりに:

logfire.info('Hello {name}', name=name)

NAME を3回繰り返さないようにするには、F-Stringを使用する方がはるかに便利です。

logfire.info(f'Hello {name}')

前のセクションとは対照的に、これはPython 3.11+の_で_にうまく機能します。これは、Logfireが特別な魔法を使用して span_name を “Hello {name}” に設定し、name プロパティを name 変数の値に設定するため、前のコードスニペットと同等です 以下はあなたが理解する必要がある内容です:

  • この機能はPython 3.11+ではデフォルトで有効になっています。[logfire.configure(inspect_arguments=False) ][logfire.configure(inspect_arguments)]で無効にできます。Python 3.9や3.10でも有効にできますが、正常に動作しない可能性が高くなります。

  • 通常の状況では、チェックパラメータは常に有効である必要があります。ソースコードが利用可能である必要があるため、たとえば .pyc ファイルのみをデプロイすると失敗することに注意してください。

  • 引数のチェックに失敗すると警告が表示され、f-string引数が書式テンプレートとして使用されます。これは、“Hello Alice” のような基数スパンの高い名前を取得し、名称 属性を持たないことを意味しますが、情報が完全に失われることはありません。

  • 引数のチェックを有効にすると、f文字列を使っているかどうかに関係なく引数がチェックされます。そのため、logfire.info('Hello {name}', name=name) を記述して引数のチェックに失敗した場合でも警告が表示されます。

  • f-stringsの値はLogfireによって再度計算され、フォーマットされます。つまり、get_username()(またはそれが返す文字列変換)が高価であるか、副作用がある場合は、logfire.info(f'Hello {get_username()}') のようなコードを使用しないでください。

  • 最初の引数は実際のf文字列でなければなりません。logfire.info(f'Hello {name}') は動作しますが、message = f'Hello {name}'; logfire.info(message) は動作しませんし、logfire.info('Hello ' + name) も動作しません。

  • 検査パラメータは、同じf文字列を繰り返し検査するためのパフォーマンスオーバーヘッドが最小になるようにキャッシュされます。ただし、最初にパラメータを検査する必要がある場合、大きなソースファイルを解析すると無視できないオーバーヘッドが発生します。 いずれにせよ、このオーバーヘッドを回避するには、f文字列を回避するだけでなく、チェックパラメータを完全に無効にする必要があります。

異常です

logfire.span コンテキストマネージャは、終了の原因となった例外を自動的に記録します。

import logfire

logfire.configure()

with logfire.span('This is a span'):
    raise ValueError('This is an error')

ライブビューで[スパン]をクリックすると、右側のパネルに[例外トラックバック]タブが表示されます。

UIのトレースバック

キャプチャされたが再スローされなかった例外は、次のように記録されません。

with logfire.span('This is a span'):
    try:
        raise ValueError('This is an acceptable error not worth recording')
    except ValueError:
        pass

処理された例外を記録するには、span.record_exception メソッドを使用します。

with logfire.span('This is a span') as span:
    try:
        raise ValueError('Catch this error, but record it')
    except ValueError as e:
        span.record_exception(e)

または、例外のみを記録し、通常のスパンを作成しない場合は、logfire.exception を使用できます。

try:
    raise ValueError('This is an error')
except ValueError:
    logfire.exception('Something went wrong')

logfire.exception(...) は logfire.error(..., _exc_info=True)。 と等価です。エラーレベル以外のバックトラックをログに記録したい場合は、_exc_info を他のログ記録メソッドと組み合わせて使用することもできます。例外オブジェクトが処理中のオブジェクトでない場合は、_exc_info を例外オブジェクトに設定できます。先頭にアンダースコアを付けることを忘れないでください!

@logfire.instrument による便利な機能スパン

通常、関数全体を1つのスパンでラップしたいと思います。そうする代わりに:

def my_function(x, y):
    with logfire.span('my_function', x=x, y=y):
        ...

@logfire.instrument デコレータを使用できます:

デフォルトでは、この関数の引数はspanに属性として追加されます。この機能を無効にするには(たとえば、引数が収集する価値のない大きなオブジェクトである場合)、 instrument(extract_args=False)。

デフォルトのスパン名は、 Calling module_name.my_function を選択します。スペアスパン名を最初のパラメーターとして渡すことができます instrument それも、パラメータとしてテンプレートをフォーマットすることができます。

@logfire.instrument('Applying my_function to {x=} and {y=}')
def my_function(x, y):
    ...

my_function(3, 4)
# Logs: Applying my_function to x=3 and y=4

注意する

  • '@logfire. ument' デコレータは最初に、つまり他のデコレータの下に適用する必要があります。
  • 関数のソースコードはアクセス可能でなければなりません。

ログレベル

さまざまなレベルのログを作成する方法は次のとおりです。

  • logfire.trace
  • logfire.debug
  • logfire.info
  • logfire.notice(日志火灾通知)
  • logfire.warn
  • logfire.error
  • logfire.fatal

デフォルトでは、跟踪 と 调试 のログは非表示になっています。この設定を変更するには、ライブビューの「デフォルトレベル」ドロップダウンリストをクリックします。

デフォルトレベルのドロップダウン

logfire.configure を使用して、コンソールログの最小レベルを設定することもできます。

import logfire

logfire.configure(console=logfire.ConsoleOptions(min_log_level='debug'))

変数レベルのメッセージを記録するには、logfire.log を使用できます。たとえば、logfire.log('info', 'This is an info log') は logfire.info('This is an info log')。 と同等です

デフォルトでは、スパンはレベル 信息 です。このパラメータを変更するには、使用 logfire.span('This is a debug span', _level='debug'): などの _level パラメータを使用します。また、スパンの開始後、スパンが完了する前にspan.set_level を使用してレベルを変更することもできます。[Logfire Span. set_level]の例:

with logfire.span('Doing a thing') as span:
    success = do_thing()
    if not success:
        span.set_level('error')

ライブビューでは、スパンは、最上位レベルとその子孫に基づいてを色付けします。たとえば、次のコード:

import logfire

logfire.configure()

with logfire.span('Outer span'):
    with logfire.span('Inner span'):
        logfire.info('This is an info message')
        logfire.error('This is an error message')

次のように表示されます。

レベルで色付けされたスパン

ここでは、スパン自体のレベルはまだ 默认 情報に設定されていますが、エラーログが含まれているため、青ではなく赤で塗りつぶされています。

スパンが未処理の例外で終了した場合、上記のようにレコードのバックトラックに加えて、スパンのログレベルも 错误 に設定されます。span.record_exception を使用している場合は、このようなことは起こりません。Logfire Span. Record_例外]メソッド。

データベースでは、ログレベルは 级别 カラムに数値として格納されます。これらの値はOpenTelemometryに基づいています。たとえば、info は 9 です。level_num SQL関数を使用して、レベル名を数値に変換できます。たとえば、级别 > level_num('info') はすべての「例外」レコードを検索します。 level_name SQL関数を使用して数値を名前に変換することもできます。たとえば、SELECT level_name(level)、... は探索ビューで人間が読めるレベルを表示します。level カラムはインデックスが付けられているため、level = level_num('error') のフィルタリングは有効ですが、level_name(level) = 'error' のフィルタリングは無効です。


本文总阅读量次