Skip to content

Types

ExceptionCallback module-attribute

ExceptionCallback = Callable[
    [ExceptionCallbackHelper], None
]

This is experimental and may change significantly in future releases.

Usage:

def my_callback(helper: logfire.types.ExceptionCallbackHelper):
    # Use `helper` here to customize how an exception is recorded on a span.
    ...

logfire.configure(advanced=logfire.AdvancedOptions(exception_callback=my_callback))

Examples:

Set the level:

helper.level = 'warning'

Make the issue fingerprint less granular:

if isinstance(helper.exception, MyCustomError):
    helper.issue_fingerprint_source = "MyCustomError"

Make the issue fingerprint more granular:

if helper.create_issue:
    helper.issue_fingerprint_source += str(helper.exception)

Create issues for all exceptions, even warnings:

helper.create_issue = True

Don't record the exception on the span:

helper.no_record_exception()

SpanLevel dataclass

SpanLevel(number: int)

A convenience class for comparing span/log levels.

Can be compared to log level names (strings) such as 'info' or 'error' using <, >, <=, or >=, so e.g. level >= 'error' is valid.

Will raise an exception if compared to a non-string or an invalid level name.

number instance-attribute

number: int

The raw numeric value of the level. Higher values are more severe.

name property

name: LevelName | None

The human-readable name of the level, or None if the number is invalid.

from_span classmethod

from_span(span: ReadableSpan) -> SpanLevel

Create a SpanLevel from an OpenTelemetry span.

If the span has no level set, defaults to 'info'.

Source code in logfire/types.py
36
37
38
39
40
41
42
43
44
45
46
@classmethod
def from_span(cls, span: ReadableSpan) -> SpanLevel:
    """Create a SpanLevel from an OpenTelemetry span.

    If the span has no level set, defaults to 'info'.
    """
    attributes = span.attributes or {}
    level = attributes.get(ATTRIBUTES_LOG_LEVEL_NUM_KEY)
    if not isinstance(level, int):
        level = LEVEL_NUMBERS['info']
    return cls(level)

ExceptionCallbackHelper dataclass

ExceptionCallbackHelper(
    span: Span,
    exception: BaseException,
    event_attributes: dict[str, AttributeValue],
    _issue_fingerprint_source: str | None = None,
    _create_issue: bool | None = None,
    _record_exception: bool = True,
)

Helper object passed to the exception callback.

This is experimental and may change significantly in future releases.

level property writable

level: SpanLevel

Convenient way to see and compare the level of the span.

  • When using logfire.span or logfire.exception, this is usually error.
  • Spans created directly by an OpenTelemetry tracer (e.g. from any logfire.instrument_*() method) typically don't have a level set, so this will return the default of info, but level_is_unset will be True.
  • FastAPI/Starlette 4xx HTTPExceptions are warnings.
  • Will be a different level if this is created by e.g. logfire.info(..., _exc_info=True).

level_is_unset property

level_is_unset: bool

Determine if the level has not been explicitly set on the span (yet).

For messy technical reasons, this is typically True for spans created directly by an OpenTelemetry tracer (e.g. from any logfire.instrument_*() method) although the level will usually still eventually be error by the time it's exported.

Spans created by logfire.span() get the level set to error immediately when an exception passes through, so this will be False in that case.

This is also typically True when calling span.record_exception() directly on any span instead of letting an exception bubble through.

parent_span property

parent_span: ReadableSpan | None

The parent span of the span the exception was recorded on.

This is None if there is no parent span, or if the parent span is in a different process.

issue_fingerprint_source property writable

issue_fingerprint_source: str

Returns a string that will be hashed to create the issue fingerprint.

By default this is a canonical representation of the exception traceback:

  • The source line is used, but not the line number, so that changes elsewhere in a file are irrelevant.
  • The module is used instead of the filename.
  • The same line appearing multiple times in a stack is ignored.
  • Exception group sub-exceptions are sorted and deduplicated.
  • If the exception has a cause or (not suppressed) context, it is included in the representation.
  • Cause and context are treated as different.

create_issue property writable

create_issue: bool

Whether to create an issue for this exception.

By default, issues are only created for exceptions on spans where:

  • The level is 'error' or higher or is unset (see level_is_unset for details),
  • No parent span exists in the current process,
  • The exception isn't handled by FastAPI, except if it's a 5xx HTTPException.
Example

if helper.create_issue: helper.issue_fingerprint_source = "MyCustomError"

no_record_exception

no_record_exception() -> None

Call this method to prevent recording the exception on the span.

This improves performance and reduces noise in Logfire. This will also prevent creating an issue for this exception. The span itself will still be recorded, just without the exception information. This doesn't affect the level of the span, it will still be 'error' by default. To still record exception info without creating an issue, use helper.create_issue = False instead. To still record the exception info but at a different level, use helper.level = 'warning' or some other level instead.

Source code in logfire/types.py
214
215
216
217
218
219
220
221
222
223
224
225
226
def no_record_exception(self) -> None:
    """Call this method to prevent recording the exception on the span.

    This improves performance and reduces noise in Logfire.
    This will also prevent creating an issue for this exception.
    The span itself will still be recorded, just without the exception information.
    This doesn't affect the level of the span, it will still be 'error' by default.
    To still record exception info without creating an issue, use `helper.create_issue = False` instead.
    To still record the exception info but at a different level, use `helper.level = 'warning'`
    or some other level instead.
    """
    self._record_exception = False
    self._create_issue = False