opentelemetry-langfuse

Library Listed

OpenTelemetry components and utilities for Langfuse LLM observability

Checked · Sources

Downloads
2,119
Dependents
2
Stars
4
Forks
0
Contributors
4
Commits
148
Latest release
0.7.2 ·

About

From the project README ·

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): enables opentelemetry_sdk's rt-tokio and async-runtime BatchSpanProcessor support. Use default-features = false if 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 demos
  • sync_batch – synchronous app that spins up a lightweight async runtime for batching
  • async_batch – fully async application using Tokio; recommended for production loads
  • custom_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:

Contributing

See CONTRIBUTING.md for guidelines.

Resources

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.

opentelemetry-langfuse beside the projects that share a topic with it
ProjectDownloadsDependentsStarsLatest releaseRuns on (GPU)Native codeLicense
opentelemetry-langfuse This page Listed

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
llmfit App Featured

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
agent App Listed

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
code2prompt App Listed

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 App Listed Dormant

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
blazr App Listed

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 App Archived

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 days
  • dormancy: last activity 2026-11-07, 2 days ago, E = 365: active
  • featured: 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
Adoption2 active dependents, 2 new dependents in 365 days1 not measured
Adoption measurements
SignalValueSourceFetchedCounts
Active dependents2crates.io database dumpYes
New dependents (365 days)2crates.io database dumpYes
Peak active dependents2crates.io database dumpYes
Active dependents as a share of the peak1crates.io database dumpYes
Binary downloads per releaseNot measuredYes
MaintenanceLatest human commit: 2 days ago3 not measured
Maintenance measurements
SignalValueSourceFetchedCounts
Latest human commit2026-11-07GitHub repositoryYes
Latest release2026-10-28crates.io database dumpYes
First release2025-08-31crates.io database dumpYes
Latest version0.7.2crates.io database dumpYes
Days the oldest outside issue waits for a reply0GitHub repositoryYes
Maintainer replies over 365 days0GitHub repositoryYes
Repository archivedfalseGitHub repositoryYes
Repository gonefalseGitHub repositoryYes
Release commit or manifest in the repotruecrates.io packageYes
Published docstruecrates.io database dumpYes
Latest release fails cargo checkNot measuredYes
Build check dateNot measuredYes
Build check toolchainNot measuredYes
SecurityUnpatched vulnerabilities: none
Security measurements
SignalValueSourceFetchedCounts
Unpatched vulnerabilities past the grace windownoneRustSec advisory databaseYes
RustSec unmaintained advisorynoneRustSec advisory databaseYes
Deprecation noticenonecrates.io database dumpYes
Deprecated requirementnonecrates.io database dumpYes
Distribution8 releases, 2,119 downloads over 30 days5 not measured
Distribution measurements
SignalValueSourceFetchedCounts
Releases8crates.io database dumpYes
Downloads over 30 days2119crates.io database dumpYes
Binary downloads over the last 3 releasesNot measuredYes
Homebrew installs on request over 365 daysNot measuredYes
Repology repository familiesNot measuredYes
Docker pull growth over 90 daysNot measuredYes
Docker pulls at the growth baselineNot measuredYes
Every version a prereleasefalsecrates.io database dumpYes
Every version 0.0.xfalsecrates.io database dumpYes
Every version yankedfalsecrates.io database dumpYes
Crate deleted from crates.iofalsecrates.io database dumpYes
Repository4 stars, 0 forks, 4 contributors, 148 commits. Stars alone never qualify a project.
Repository measurements
SignalValueSourceFetchedCounts
GitHub stars4GitHub repositoryYes — one part of the repository route
GitHub forks0GitHub repositoryYes — one part of the repository route
Contributors with a GitHub account4GitHub contributorsYes — one part of the repository route
Commits on the default branch148GitHub repositoryNo
Repository's main crate left out of the entrynonecrates.io database dumpYes
Facts that never count
Facts that never count measurements
SignalValueSourceFetchedCounts
LicenseApache-2.0 OR MITcrates.io database dumpNo
Runs on, from listed crates and their direct dependenciesGPU support unknowncrates.io database dumpNo
What shows each backendno dependency or feature matches a backend rowcrates.io database dumpNo
Native code, from listed crates and their dependenciesNo native code foundcrates.io database dumpNo
Python bindings, from direct dependencies of listed cratesNo Python binding crate foundcrates.io database dumpNo
Crates that depend on a listed crate directly2crates.io database dumpNo

Corrections and review history

Report a correction

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.