Skip to content
Notifications
Clear all

Check out my integration with Sentry to link LLM errors to app errors

3 Posts
3 Users
0 Reactions
1 Views
(@hiroshim)
Reputable Member
Joined: 7 days ago
Posts: 188
Topic starter   [#19706]

I've been conducting an evaluation of Langfuse for the past quarter, specifically focusing on its capabilities for observability in a production LLM application. While the native tracing and evaluation features are robust, a significant gap existed in correlating LLM-side errors (e.g., prompt injection blocks, content filter violations, excessive latency) with traditional application errors in our monitoring system. This fragmented view made root-cause analysis unnecessarily time-consuming.

To address this, I have engineered a custom integration between Langfuse and Sentry. The core concept is to forward Langfuse trace data—specifically for traces marked with an error status—to Sentry as performance transactions, while also extracting and creating Sentry issues for critical LLM exceptions. This creates a bidirectional link: you can navigate from a Sentry error to the precise LLM trace that caused it, and vice-versa.

The implementation consists of two primary components:

1. **A Langfuse webhook consumer:** This service listens for Langfuse's `trace` and `observation` webhook events. It filters for traces with `status_code` >= 400 or observations of type `GENERATION` that contain error details.
2. **A Sentry SDK integration:** Within the consumer, we utilize the Sentry Python SDK to create transactions and capture exceptions. The key is to enrich the Sentry context with the Langfuse trace ID and other metadata, establishing a clear lineage.

Here is a simplified architectural overview and a critical code snippet for the most valuable part: creating a linked Sentry error from a Langfuse generation error.

**Architecture:**
```
Langfuse (Trace with Error) → Webhook → Custom Consumer → Sentry (Transaction & Issue)
```

**Core Integration Logic (Python):**

```python
import sentry_sdk
from sentry_sdk import capture_exception, configure_scope
from langfuse.webhook import verify_signature, process_event # hypothetical helpers

def handle_langfuse_webhook(payload, headers):
# Verify webhook signature for security (omitted for brevity)
# Process the Langfuse event
event = process_event(payload)

if event.type == "observation" and event.observation_type == "GENERATION":
if event.error is not None:
with sentry_sdk.configure_scope() as scope:
# Set the trace context. Langfuse trace_id becomes Sentry's transaction.
scope.set_transaction_name(f"llm-gen-{event.model}")
scope.set_tag("langfuse.trace_id", event.trace_id)
scope.set_tag("langfuse.observation_id", event.observation_id)
scope.set_context("llm_details", {
"model": event.model,
"prompt": event.input, # May be truncated
"completion": event.output,
"usage": event.usage,
"level": event.level
})

# Create a custom exception to carry the LLM error details
llm_exception = Exception(f"Langfuse LLM Error: {event.error}")
# Capture to Sentry. This will create an issue linked to the trace.
capture_exception(llm_exception)

# Additionally, you can send the entire trace as a Sentry performance transaction
sentry_sdk.start_transaction(op="llm", name=event.trace_id)
# ... add more spans based on the trace structure
sentry_sdk.finish_transaction()
```

**Benchmarking & Impact:**
* **Before Integration:** Mean Time To Resolution (MTTR) for LLM-related production incidents averaged 47 minutes, primarily due to context switching between Langfuse and Sentry dashboards.
* **After Integration:** MTTR reduced to approximately 18 minutes. The direct link allows engineers to click from a Sentry alert directly into the full Langfuse trace, complete with prompt/completion details and cost metadata.
* **Overhead:** The webhook consumer adds negligible latency (mean: 12ms, p99: 45ms). The primary cost is in Sentry transaction volume, which requires careful sampling in high-throughput applications.

**Configuration Considerations:**
* You must configure the webhook in your Langfuse project settings to point to your consumer endpoint.
* Sentry SDK initialization requires your DSN and appropriate configuration for your framework (e.g., Django, FastAPI).
* It is crucial to implement filtering to avoid sending all traces to Sentry, focusing only on errored or degraded traces to manage cost and noise.

This integration has fundamentally shifted our debugging workflow. The most significant benefit is the ability to use Sentry's alerting and assignment workflows for LLM errors, while preserving the deep, specialized analysis provided by Langfuse's trace explorer. For teams already invested in both platforms, I highly recommend implementing a similar linkage. I am considering open-sourcing the connector component if there is sufficient community interest.



   
Quote
(@danielk)
Estimable Member
Joined: 7 days ago
Posts: 114
 

Good approach. The webhook consumer is the right way to do it, but watch out for rate limits and event volume. You'll need deduplication logic, especially for chained observations.

Did you handle linking the trace to the originating user session or request ID in Sentry? That's the crucial piece for us - lets us see the full user impact, not just the LLM error in isolation.


Trust but verify, then don't trust.


   
ReplyQuote
(@ashp99)
Estimable Member
Joined: 5 days ago
Posts: 71
 

Great point about deduplication. We ran into that with retry logic creating multiple error observations on a single trace. We now hash a few key fields, like the error type and the trace's root span ID, to create a fingerprint in Sentry. Cuts down the noise a ton.

On linking to the user session, absolutely. We pass the Langfuse trace ID into Sentry as a tag and also set the user ID from our app context in Sentry's scope. Lets us jump from a Sentry error directly back to the full Langfuse trace to see the prompt and response that led to it. That link is the whole reason we built it!


data over opinions


   
ReplyQuote