opentelemetry-langfuse
Library Listed
OpenTelemetry components and utilities for Langfuse LLM observability
- Downloads
- 2,119
- Dependents
- 2
- Stars
- 4
- Forks
- 0
- Contributors
- 4
- Commits
- 148
- Latest release
- 0.7.2 ·
About
OpenTelemetry integration for Langfuse, the open-source LLM observability platform.
This crate provides OpenTelemetry components and utilities for integrating with Langfuse, enabling comprehensive observability for LLM applications. For more information about OpenTelemetry support in Langfuse, see the official Langfuse OpenTelemetry documentation.
Installation
[dependencies]
opentelemetry-langfuse = "0.7.0"
opentelemetry = { version = "0.33.1", features = ["trace"] }
opentelemetry_sdk = { version = "0.33.1", features = [
"trace",
"rt-tokio",
"experimental_trace_batch_span_processor_with_async_runtime"
]}
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
Cargo features
rt-tokio(default): enablesopentelemetry_sdk'srt-tokioand async-runtimeBatchSpanProcessorsupport. Usedefault-features = falseif you bring your own span processor and do not want the Tokio runtime pulled in.
Read the full README
This combination requires Rust 1.93.1 or later. ExporterBuilder::build()
returns opentelemetry_otlp::SpanExporter from the 0.33 series, implementing
opentelemetry_sdk::trace::SpanExporter from the 0.33 series. Use matching
0.33 opentelemetry and opentelemetry_sdk dependencies when constructing a
provider or creating spans for this exporter.
Using alongside openai-ergonomic
openai-ergonomic 0.6.0 uses OpenTelemetry 0.32 and declares Rust 1.88. It can
coexist in an application with this crate, but that application must meet this
crate's Rust 1.93.1 minimum. Cargo may then resolve both 0.32 and 0.33 SDKs.
Their exporter traits, providers, tracers, contexts, and spans are distinct Rust
types: do not pass this 0.33 exporter to a 0.32 provider, or pass a 0.33 provider
to an API that expects a 0.32 provider. Each OpenTelemetry version also has its
own global provider; setting the 0.33 global provider does not configure 0.32
instrumentation.
Use separate tracing pipelines with each library's matching SDK, or explicitly
align dependencies in a separately reviewed integration. This crate does not
bridge the two versions or require an openai-ergonomic upgrade. The
LangfuseContext helper example linked below illustrates attribute conventions;
it does not imply cross-version provider compatibility.
Migrating from the 0.6 dependency stack
Use Rust 1.93.1 or later, OpenTelemetry 0.33, and reqwest 0.13. The exporter
returns an OpenTelemetry 0.33 SpanExporter, and with_http_client now accepts
a reqwest 0.13 Client; clients and SDK types from the earlier versions are
not interchangeable. Update these dependencies together in your application.
Error::OpenTelemetry wraps opentelemetry_sdk::error::OTelSdkError, replacing
the removed TraceError type.
The integration tests and examples use langfuse-ergonomic 0.7.0 with
langfuse-client-base 0.15.0. In that API, a trace name is Option<String>
rather than Option<Option<String>>. Langfuse remains a test/example dependency;
the exporter itself sends OTLP directly.
Quick Start
use opentelemetry::global;
use opentelemetry::KeyValue;
use opentelemetry_langfuse::ExporterBuilder;
use opentelemetry_sdk::runtime::Tokio;
use opentelemetry_sdk::trace::span_processor_with_async_runtime::BatchSpanProcessor;
use opentelemetry_sdk::trace::SdkTracerProvider;
use opentelemetry_sdk::Resource;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create the Langfuse exporter
let exporter = ExporterBuilder::from_env()?.build()?;
// Build tracer provider with BatchSpanProcessor
// IMPORTANT: Explicitly provide Tokio runtime to avoid "no reactor running" panic
let provider = SdkTracerProvider::builder()
.with_resource(
Resource::builder()
.with_attributes([KeyValue::new("service.name", "my-service")])
.build(),
)
.with_span_processor(BatchSpanProcessor::builder(exporter, Tokio).build())
.build();
// Set as global provider
global::set_tracer_provider(provider.clone());
// Your application code here...
// Shutdown to ensure all spans are flushed
provider.shutdown()?;
Ok(())
}
This uses BatchSpanProcessor with the async runtime for efficient batched exports. This is validated in our integration tests.
Examples
The external consumer fixture has its own manifest and builds this crate as a path dependency, without the library's dev-dependencies. CI compiles and runs it on Rust 1.93.1. It starts a local fake OTLP endpoint, exports one span, verifies receipt, and explicitly shuts down the provider and runtime. No Langfuse service or credentials are needed:
cargo +1.93.1 check --manifest-path examples/external-consumer/Cargo.toml
cargo +1.93.1 run --manifest-path examples/external-consumer/Cargo.toml
cargo +1.93.1 tree --manifest-path examples/external-consumer/Cargo.toml -i opentelemetry_sdk
The fixture should resolve one 0.33 SDK. In an application using both libraries,
inspect cargo tree -d and cargo tree -i opentelemetry_sdk@0.33.1 (adjust the
patch version to the resolved version) to see which dependency uses each SDK.
The remaining examples/ use a Langfuse service and credentials:
sync_simple– minimal setup for development and quick demossync_batch– synchronous app that spins up a lightweight async runtime for batchingasync_batch– fully async application using Tokio; recommended for production loadscustom_config– advanced exporter configuration (custom HTTP clients, TLS, proxy, headers)
Configuration
The exporter can be configured using Langfuse-specific environment variables:
LANGFUSE_PUBLIC_KEY=pk-lf-... # Your public key (required)
LANGFUSE_SECRET_KEY=sk-lf-... # Your secret key (required)
LANGFUSE_HOST=https://cloud.langfuse.com # Optional: Defaults to cloud instance
Use ExporterBuilder::from_env() to load these variables:
use opentelemetry_langfuse::ExporterBuilder;
use std::time::Duration;
// Load from environment
let exporter = ExporterBuilder::from_env()?.build()?;
// Or load from environment and customize
let exporter = ExporterBuilder::from_env()?
.with_timeout(Duration::from_secs(30))
.build()?;
For real-time reads through Langfuse Cloud/v4's Observations API v2, add
.with_header("x-langfuse-ingestion-version", "4") before .build().
Langfuse documents this header in its Public API guide.
Without it, direct OTLP exports can take up to 15 minutes to appear in v2 reads.
Manual Configuration
You can also configure the exporter programmatically:
use opentelemetry_langfuse::ExporterBuilder;
use std::time::Duration;
let exporter = ExporterBuilder::new()
.with_host("https://cloud.langfuse.com")
.with_basic_auth("pk-lf-...", "sk-lf-...")
.with_timeout(Duration::from_secs(10))
.build()?;
Custom HTTP Client
By default, the OTLP exporter will use its own HTTP client with TLS support. You can provide a custom client for advanced configurations:
- Proxy settings
- Custom root certificates
- Connection pooling
- Custom timeout configurations
use opentelemetry_langfuse::ExporterBuilder;
use std::time::Duration;
let custom_client = reqwest::Client::builder()
.timeout(Duration::from_secs(30))
.proxy(reqwest::Proxy::http("http://proxy.example.com:8080")?)
.build()?;
let exporter = ExporterBuilder::new()
.with_host("https://cloud.langfuse.com")
.with_basic_auth("pk-lf-...", "sk-lf-...")
.with_http_client(custom_client)
.build()?;
Note on TLS: The opentelemetry-otlp crate's reqwest-client feature supplies
the async HTTP transport, and reqwest-rustls explicitly enables HTTPS. This
also applies when building the library without its test dependencies. Custom
clients use reqwest 0.13 and can configure their own TLS backend.
The default HTTP client uses OTLP's resolved request timeout (10 seconds unless
overridden by OTLP environment variables or with_timeout). Custom clients must
set their own reqwest::ClientBuilder::timeout, as in the example above:
the exporter's retry budget cannot interrupt an unbounded custom-client request.
Context Helpers
Similar to the langfuse-python SDK, this crate provides a LangfuseContext struct for managing trace-level attributes:
use opentelemetry_langfuse::LangfuseContext;
// Create a context instance
let context = LangfuseContext::new();
// Use fluent API for configuration
context
.set_session_id("session-123")
.set_user_id("user-456")
.add_tags(vec!["production".to_string(), "api-v2".to_string()])
.set_metadata(serde_json::json!({
"environment": "production",
"version": "1.0.0"
}));
// Get attributes to add to spans
let attributes = context.get_attributes();
Design Note: LangfuseContext uses an instance-based design (no global state). Create instances as needed for your use case.
For an example integration, see the openai-ergonomic library's LangfuseInterceptor.
Testing
Unit tests and the local HTTP transport/query regression tests do not need credentials:
cargo test --lib --test otlp_transport_test --test langfuse_query_test
cargo test --doc
The integration tests in tests/integration_test.rs are marked #[ignore] because they need live Langfuse credentials (LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY); run them with cargo test --all-features -- --ignored. They verify that traces are successfully exported to Langfuse and can be queried via the Langfuse API. The tests cover:
- SimpleSpanProcessor: Immediate (blocking) export
- BatchSpanProcessor (async runtime): Batched export with Tokio integration
To run the integration tests:
export LANGFUSE_PUBLIC_KEY="pk-lf-..."
export LANGFUSE_SECRET_KEY="sk-lf-..."
export LANGFUSE_HOST="https://cloud.langfuse.com"
cargo test --test integration_test
The live tests require Langfuse Cloud or self-hosted v4. They query the exact
exported trace ID, span ID, and name through Observations API v2, with a bounded
time range and a five-minute polling budget. They reuse the
langfuse-ergonomic client's
authenticated transport, respect Retry-After on rate limits, and fail immediately
on authentication errors. Both ingestion and verification use LANGFUSE_HOST.
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT license (LICENSE-MIT)
Contributing
See CONTRIBUTING.md for guidelines.
Resources
Compatibility
- Runs on
- GPU support unknown
What shows it
- no dependency or feature matches a backend row
- Native code
- None found
- No native code found
- Python bindings
- No Python binding crate found
- License
- Apache-2.0 OR MIT
Compare with similar projects
Order: strongest tier first, then most downloads, then name, with unmeasured values last. A library counts downloads over 30 days. An app counts binary downloads per release. An app with none counts its crate downloads over 30 days. ML Rust runs this catalogue, so its closest project always gets a row.
| Project | Downloads | Dependents | Stars | Latest release | Runs on (GPU) | Native code | License |
|---|---|---|---|---|---|---|---|
|
OpenTelemetry components and utilities for Langfuse LLM observability |
2,119 downloads over 30 days | 2 | 4 | 0.7.2 | GPU support unknown | No native code found | Apache-2.0 OR MIT |
|
Right-size LLM models to your system hardware. Interactive TUI and CLI to match models against available RAM, CPU, and GPU. |
3,821 binary downloads per release | Not applicable | 38,787 | 1.1.20 | Metal | No native code found | MIT |
|
Ship your code, on autopilot. An open source agent that lives on your machines 24/7 and keeps your apps running. 🦀 |
19,860 binary downloads per release | Not applicable | 1,859 | 0.3.88 | GPU support unknown | Binds native code: tree-sitter, tree-sitter-language, tikv-jemalloc-sys (feature jemalloc) | Apache-2.0 |
|
A CLI tool to convert your codebase into a single LLM prompt with source tree, prompt templating, and token counting. |
2,317 binary downloads per release | Not applicable | 7,756 | 4.3.0 | GPU support unknown | Binds native code: libgit2-sys, libz-sys | MIT |
|
LSP-AI is an open-source language server that serves as a backend for AI-powered functionality, designed to assist and empower software engineers, not replace them. |
2,314 binary downloads per release | Not applicable | 3,210 | 0.7.0 | CUDA, Metal | Binds native code: tree-sitter, tree-sitter-language, llama-cpp-sys-2 (feature cuda). Build uses a native toolchain: cc | MIT |
|
Inference server for LLMs, speech and embeddings: OpenAI-compatible routes with streaming, plus speech synthesis (TTS) and transcription (ASR). Serves Llama, Mistral, Qwen, Mamba2, MLA+MoE and hybrid models from SafeTensors, AWQ, GPTQ and GGUF. |
8 binary downloads per release | Not applicable | 7 | 0.7.1 | CUDA, WebGPU | Binds native code: ring (feature distributed) | Apache-2.0 |
|
TensorZero is an open-source LLMOps platform that unifies an LLM gateway, observability, evaluation, optimization, and experimentation. |
35 downloads over 30 days | Not applicable | 11,705 | 0.0.0 | GPU support unknown | No native code found | Apache-2.0 |
Why ListedNo archive, New or Featured rule places it, so it is Listed.
What it lacks for Featured
- It has 2 active dependents and 2 new dependents in 365 days. Featured needs 11 active dependents or 9 new dependents in 365 days. The repository route reads 4 stars, 0 forks and 4 contributors. It needs 4,539 stars, 434 forks and 79 contributors together.
What else the check found
- The last activity is on 7 Nov 2026, 2 days ago. The rules expect an update within 365 days. Dormancy rule
Exact rules: Listed, Featured library. The check on applied thresholds version 9.
Every rule outcome, as the check records it
expected-interval: version 0.7.2 base 300, raised to the 365-day floor: E = 365 daysdormancy: last activity 2026-11-07, 2 days ago, E = 365: activefeatured: not featured: active_users 2 < 11 and new_adopters 2 < 9 and repository route stars 4 (needs 4539), forks 0 (needs 434), contributors 4 (needs 79)listed: listed: no archive, new or featured rule applies
Measurements and sources
Each signal row shows the raw value, its source and the fetch date. The Sources list gathers every distinct source on this page. Movement needs more history.
Sources6 sources
- Description: the crates.io description
- crates.io database dump, fetched
- RustSec advisory database, fetched
- GitHub repository, fetched
- crates.io package, fetched
- GitHub contributors, fetched
Adoption2 active dependents, 2 new dependents in 365 days1 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Active dependents | 2 | crates.io database dump | Yes | |
| New dependents (365 days) | 2 | crates.io database dump | Yes | |
| Peak active dependents | 2 | crates.io database dump | Yes | |
| Active dependents as a share of the peak | 1 | crates.io database dump | Yes | |
| Binary downloads per release | Not measured | Yes |
MaintenanceLatest human commit: 2 days ago3 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Latest human commit | 2026-11-07 | GitHub repository | Yes | |
| Latest release | 2026-10-28 | crates.io database dump | Yes | |
| First release | 2025-08-31 | crates.io database dump | Yes | |
| Latest version | 0.7.2 | crates.io database dump | Yes | |
| Days the oldest outside issue waits for a reply | 0 | GitHub repository | Yes | |
| Maintainer replies over 365 days | 0 | GitHub repository | Yes | |
| Repository archived | false | GitHub repository | Yes | |
| Repository gone | false | GitHub repository | Yes | |
| Release commit or manifest in the repo | true | crates.io package | Yes | |
| Published docs | true | crates.io database dump | Yes | |
| Latest release fails cargo check | Not measured | Yes | ||
| Build check date | Not measured | Yes | ||
| Build check toolchain | Not measured | Yes |
SecurityUnpatched vulnerabilities: none
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Unpatched vulnerabilities past the grace window | none | RustSec advisory database | Yes | |
| RustSec unmaintained advisory | none | RustSec advisory database | Yes | |
| Deprecation notice | none | crates.io database dump | Yes | |
| Deprecated requirement | none | crates.io database dump | Yes |
Distribution8 releases, 2,119 downloads over 30 days5 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Releases | 8 | crates.io database dump | Yes | |
| Downloads over 30 days | 2119 | crates.io database dump | Yes | |
| Binary downloads over the last 3 releases | Not measured | Yes | ||
| Homebrew installs on request over 365 days | Not measured | Yes | ||
| Repology repository families | Not measured | Yes | ||
| Docker pull growth over 90 days | Not measured | Yes | ||
| Docker pulls at the growth baseline | Not measured | Yes | ||
| Every version a prerelease | false | crates.io database dump | Yes | |
| Every version 0.0.x | false | crates.io database dump | Yes | |
| Every version yanked | false | crates.io database dump | Yes | |
| Crate deleted from crates.io | false | crates.io database dump | Yes |
Repository4 stars, 0 forks, 4 contributors, 148 commits. Stars alone never qualify a project.
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| GitHub stars | 4 | GitHub repository | Yes — one part of the repository route | |
| GitHub forks | 0 | GitHub repository | Yes — one part of the repository route | |
| Contributors with a GitHub account | 4 | GitHub contributors | Yes — one part of the repository route | |
| Commits on the default branch | 148 | GitHub repository | No | |
| Repository's main crate left out of the entry | none | crates.io database dump | Yes |
Facts that never count
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| License | Apache-2.0 OR MIT | crates.io database dump | No | |
| Runs on, from listed crates and their direct dependencies | GPU support unknown | crates.io database dump | No | |
| What shows each backend | no dependency or feature matches a backend row | crates.io database dump | No | |
| Native code, from listed crates and their dependencies | No native code found | crates.io database dump | No | |
| Python bindings, from direct dependencies of listed crates | No Python binding crate found | crates.io database dump | No | |
| Crates that depend on a listed crate directly | 2 | crates.io database dump | No |
Corrections and review history
No correction applies to this entry.
Judgments
A judgment enters only through an approved issue and a merged pull request.
No judgment applies to this entry.