LangfuseLangfuse Python SDK 4.15.4 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
38 small wins to finish your pathNext lesson

Observations from other libraries

By default the SDK exports only its own observations and LLM-related spans. Other OpenTelemetry spans are dropped, and their children lose their place in the tree.

Because Langfuse is built on OpenTelemetry, any library that records OpenTelemetry spans can appear in a trace: a database driver, an HTTP client, a framework. Lesson 15's hook sees any of them that are exported. This lesson is about which ones are.

Examplethird_party.py, after the setup lines with observe
from opentelemetry import trace

ORDERS = {"A17": "shipped on 3 March"}
database = trace.get_tracer("shop-db")


@observe(name="lookup-order", as_type="tool")
def lookup_order(order_id):
    with database.start_as_current_span("SELECT orders"):
        with langfuse.start_as_current_observation(name="parse-row"):
            return ORDERS.get(order_id, "not found")

trace.get_tracer is plain OpenTelemetry, the way a database library would record its queries. The query span sits inside the Langfuse tool, and a Langfuse observation sits inside the query.

Examplethird_party.py, continued
lookup_order("A17")

langfuse.flush()
local_langfuse.tree()
Example
python third_party.py

The query is missing, and parse-row appears as a root of its own. Its parent was the query span, which was filtered out, so the server has an observation whose parent never arrived. The default filter keeps observations created by the Langfuse SDK, spans with gen_ai.* attributes, and spans from a list of known LLM libraries; shop-db is none of these.

Keeping a library's spans

Examplethird_party.py, new setup lines
from langfuse import Langfuse, observe
from langfuse.span_filter import is_default_export_span

import local_langfuse


def keep(span):
    return is_default_export_span(span) or span.instrumentation_scope.name == "shop-db"


url = local_langfuse.start()
langfuse = Langfuse(public_key="pk-lf-local", secret_key="sk-lf-local", base_url=url, should_export_span=keep)
Example
python third_party.py

should_export_span replaces the default filter, so keep calls the default, is_default_export_span, and adds one scope. The tree is whole again. To find the name of a scope that is being dropped, turn on debug logging with debug=True or LANGFUSE_DEBUG=True and read the log.

Everything between your code and the server

This is what the five lessons of this part add up to: two gates that can drop a trace, a queue, and one hook that can change what is left.

What leaves your process, and what stops it
an observation endsa function, a block, a callis the trace sampled?sample_rate, from the trace idis the span exported?should_export_span decidesqueued in a batch5 seconds, or flush()maskedmask_otel_spans rewritessent to base_urlthe local server, here
Hover or tap a piece to see what it is and which lesson built it.
Follow one observation out

Pick one to watch it run, step by step.

Export only what you need to debug the LLM part of the application. Every extra scope is more data sent, and a database span's attributes can include the query text, with whatever values were in it.

Try it yourself
  • Pass should_export_span=lambda span: True and count what arrives.
  • Use langfuse.span_filter.is_langfuse_span as the filter and compare the tree.
  • Print span["scope"] for each observation the server received.

You understood something today that you didn't yesterday.