Skip to content

Artifacts

Artifacts let you attach a binary blob — an image, audio clip, PDF, or a large JSON payload — to a span. The blob is stored separately from your telemetry, so it is not subject to span attribute size limits and does not bloat your traces. The span itself carries only a small reference; Logfire uploads the blob out of band.

Logging an artifact

Wrap your data in logfire.Artifact and pass it as a span or log attribute:

import logfire

logfire.configure()

with open('chart.png', 'rb') as f:
    image_bytes = f.read()

logfire.info('chart generated', chart=logfire.Artifact(image_bytes, content_type='image/png'))

The chart argument renders as an image preview on the trace in the Logfire UI, with a download link — not as a wall of base64.

From a file or a file handle

Artifact.from_file reads a path lazily (no need to load the bytes yourself), and Artifact.from_file_handle accepts any open binary handle, including temporary files:

import logfire

logfire.configure()

# From a path — the content type is guessed from the extension.
logfire.info('report ready', report=logfire.Artifact.from_file('report.pdf'))

# From an open binary handle.
with open('clip.mp3', 'rb') as handle:
    logfire.info('audio processed', clip=logfire.Artifact.from_file_handle(handle))

When the upload happens

Each artifact chooses when its bytes are uploaded, via the upload argument:

  • background (the default) — the upload is handed to a background thread and the logging call never blocks. If uploads cannot keep up, queued artifacts are dropped with a warning rather than stalling your program.
  • sync — the upload runs inline; the logging call returns only once the blob is stored. Use this when you need delivery guaranteed, or when you want to free the source bytes/file immediately afterwards.
import logfire

logfire.configure()

# Block until this artifact is uploaded.
logfire.info('critical input', data=logfire.Artifact(payload, upload='sync'))

How it works

Artifacts are content-addressed: an artifact's identity is the sha256 of its bytes. The same blob logged repeatedly — within a project — is uploaded and stored only once. The reference embedded in the span looks like:

{
  "type": "logfire.artifact",
  "sha256": "9f86d0818...",
  "filename": "chart.png",
  "content_type": "image/png",
  "size_bytes": 28421
}

The blob never travels through the telemetry pipeline. On SaaS the SDK uploads it directly to object storage via a signed URL; self-hosted deployments route it through the Logfire backend.

Viewing artifacts

Open a span in the Logfire UI: any artifact-valued argument renders inline — images, audio, video, and PDFs as previews, everything else as a download link — alongside its filename, content type, and size.