use chrono::Utc;
use langfuse_ergonomic::ClientBuilder;
use std::time::Duration;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
dotenvy::dotenv().ok();
tracing_subscriber::fmt::init();
let client = ClientBuilder::new()
.public_key("your-public-key")
.secret_key("your-secret-key")
.base_url("https://langfuse.your-domain.com".to_string()) .timeout(Duration::from_secs(30)) .connect_timeout(Duration::from_secs(5)) .user_agent("my-app/1.0.0".to_string()) .build()?;
match client.validate().await {
Ok(true) => println!("Successfully connected to self-hosted Langfuse"),
Ok(false) => println!("Connection established but validation failed"),
Err(e) => println!("Failed to connect: {}", e),
}
let env_client = ClientBuilder::from_env()
.and_then(|builder| builder.build())
.or_else(|e| {
println!("Failed to create client from env: {}", e);
println!("Using default cloud instance for demo");
ClientBuilder::new()
.public_key("demo-public-key")
.secret_key("demo-secret-key")
.build()
})?;
let trace_response = env_client
.trace()
.name("self-hosted-test")
.metadata(serde_json::json!({
"instance_type": "self-hosted",
"test_timestamp": Utc::now()
}))
.tags(vec![
"self-hosted".to_string(),
"connection-test".to_string(),
])
.input(serde_json::json!({
"test": "Testing connection to self-hosted instance"
}))
.output(serde_json::json!({
"status": "success",
"message": "Connection established"
}))
.call()
.await?;
println!("Created trace: {}", trace_response.id);
use langfuse_ergonomic::Batcher;
let batcher = Batcher::builder()
.client(env_client)
.max_events(20) .flush_interval(Duration::from_secs(10)) .max_retries(5) .build()
.await;
println!("Batcher configured for self-hosted instance");
use langfuse_client_base::models::{
ingestion_event_one_of::Type, IngestionEvent, IngestionEventOneOf, TraceBody,
};
use uuid::Uuid;
for i in 0..5 {
let trace_id = Uuid::new_v4().to_string();
let timestamp = Utc::now().to_rfc3339();
let trace_event = IngestionEvent::IngestionEventOneOf(Box::new(IngestionEventOneOf {
id: trace_id.clone(),
timestamp: timestamp.clone(),
r#type: Type::TraceCreate,
body: Box::new(TraceBody {
id: Some(Some(trace_id.clone())),
timestamp: Some(Some(timestamp)),
name: Some(Some(format!("self-hosted-trace-{}", i))),
metadata: Some(Some(serde_json::json!({
"index": i,
"instance": "self-hosted"
}))),
tags: Some(Some(vec!["batch".to_string(), "self-hosted".to_string()])),
environment: None,
..Default::default()
}),
metadata: None,
}));
batcher.add(trace_event).await?;
}
println!("Added 5 traces to batcher");
let response = batcher.flush().await?;
println!(
"Flush complete: {} succeeded, {} failed",
response.success_count, response.failure_count
);
let final_response = batcher.shutdown().await?;
println!(
"Batcher shutdown: {} total succeeded, {} total failed",
final_response.success_count, final_response.failure_count
);
println!("\nSelf-hosted configuration tips:");
println!("1. Ensure your Langfuse instance is accessible from this network");
println!("2. Use HTTPS in production for security");
println!("3. Configure appropriate timeouts based on your network latency");
println!("4. Monitor batch sizes if your instance has different limits");
println!("5. Consider implementing health checks for high-availability setups");
Ok(())
}