mirror of
https://github.com/ruvnet/RuVector.git
synced 2026-05-26 07:44:05 +00:00
fix: Resolve unresolved imports in ruvector-tiny-dancer-core examples
- Export training module and types from lib.rs (TrainingConfig,
TrainingDataset, Trainer, TrainingMetrics, generate_teacher_predictions)
- Export RouterConfig and FastGRNNConfig from lib.rs
- Add From<std::io::Error> impl for TinyDancerError
- Update examples to work without external dependencies:
- admin-server.rs: Simplified to demonstrate health checks and
config inspection without axum/tokio
- full_observability.rs: Uses manual metrics tracking instead of
prometheus crate
- metrics_example.rs: Manual metrics collection and display
- tracing_example.rs: Simple timing-based example without
OpenTelemetry
Fixes #16
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
bc52ee6884
commit
65fa2c8c9d
6 changed files with 267 additions and 271 deletions
|
|
@ -1,79 +1,28 @@
|
|||
//! Admin server example for Tiny Dancer
|
||||
//! Admin and health check example for Tiny Dancer
|
||||
//!
|
||||
//! This example demonstrates how to run the admin API server for monitoring,
|
||||
//! health checks, and administration of the Tiny Dancer routing system.
|
||||
//! This example demonstrates how to implement health checks and
|
||||
//! administrative functionality for the Tiny Dancer routing system.
|
||||
//!
|
||||
//! ## Usage
|
||||
//!
|
||||
//! ```bash
|
||||
//! cargo run --example admin-server --features admin-api
|
||||
//! cargo run --example admin-server
|
||||
//! ```
|
||||
//!
|
||||
//! ## Endpoints
|
||||
//! This example shows:
|
||||
//! - Health check implementations
|
||||
//! - Configuration inspection
|
||||
//! - Circuit breaker status monitoring
|
||||
//! - Hot model reloading
|
||||
//!
|
||||
//! ### Health Checks
|
||||
//! - `GET /health` - Basic liveness probe
|
||||
//! - `GET /health/ready` - Readiness check (K8s compatible)
|
||||
//!
|
||||
//! ### Metrics
|
||||
//! - `GET /metrics` - Prometheus format metrics
|
||||
//!
|
||||
//! ### Admin
|
||||
//! - `POST /admin/reload` - Hot reload model
|
||||
//! - `GET /admin/config` - Get current configuration
|
||||
//! - `PUT /admin/config` - Update configuration
|
||||
//! - `GET /admin/circuit-breaker` - Get circuit breaker status
|
||||
//! - `POST /admin/circuit-breaker/reset` - Reset circuit breaker
|
||||
//!
|
||||
//! ### Info
|
||||
//! - `GET /info` - System information
|
||||
//!
|
||||
//! ## Testing Endpoints
|
||||
//!
|
||||
//! ```bash
|
||||
//! # Health check
|
||||
//! curl http://localhost:8080/health
|
||||
//!
|
||||
//! # Readiness check
|
||||
//! curl http://localhost:8080/health/ready
|
||||
//!
|
||||
//! # Metrics (Prometheus format)
|
||||
//! curl http://localhost:8080/metrics
|
||||
//!
|
||||
//! # System info
|
||||
//! curl http://localhost:8080/info
|
||||
//!
|
||||
//! # Reload model (requires auth if token is set)
|
||||
//! curl -X POST http://localhost:8080/admin/reload \
|
||||
//! -H "Authorization: Bearer your-token-here"
|
||||
//!
|
||||
//! # Get configuration
|
||||
//! curl http://localhost:8080/admin/config \
|
||||
//! -H "Authorization: Bearer your-token-here"
|
||||
//!
|
||||
//! # Circuit breaker status
|
||||
//! curl http://localhost:8080/admin/circuit-breaker \
|
||||
//! -H "Authorization: Bearer your-token-here"
|
||||
//! ```
|
||||
//! For a full HTTP admin server implementation, see the `api` module
|
||||
//! documentation which requires additional dependencies (axum, tokio).
|
||||
|
||||
use ruvector_tiny_dancer_core::api::{AdminServer, AdminServerConfig};
|
||||
use ruvector_tiny_dancer_core::router::Router;
|
||||
use ruvector_tiny_dancer_core::types::RouterConfig;
|
||||
use std::sync::Arc;
|
||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||
use ruvector_tiny_dancer_core::{Candidate, Router, RouterConfig, RoutingRequest};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Initialize tracing
|
||||
tracing_subscriber::registry()
|
||||
.with(
|
||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| "info,ruvector_tiny_dancer_core=debug".into()),
|
||||
)
|
||||
.with(tracing_subscriber::fmt::layer())
|
||||
.init();
|
||||
|
||||
tracing::info!("Starting Tiny Dancer Admin Server Example");
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("=== Tiny Dancer Admin Example ===\n");
|
||||
|
||||
// Create router with default configuration
|
||||
let router_config = RouterConfig {
|
||||
|
|
@ -86,55 +35,97 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
database_path: None,
|
||||
};
|
||||
|
||||
tracing::info!("Creating router with config: {:?}", router_config);
|
||||
let router = Router::new(router_config)?;
|
||||
let router = Arc::new(router);
|
||||
println!("Creating router with config:");
|
||||
println!(" Model path: {}", router_config.model_path);
|
||||
println!(" Confidence threshold: {}", router_config.confidence_threshold);
|
||||
println!(" Max uncertainty: {}", router_config.max_uncertainty);
|
||||
println!(" Circuit breaker: {}", router_config.enable_circuit_breaker);
|
||||
|
||||
// Configure admin server
|
||||
let admin_config = AdminServerConfig {
|
||||
bind_address: "127.0.0.1".to_string(),
|
||||
port: 8080,
|
||||
// Uncomment to enable authentication:
|
||||
// auth_token: Some("your-secret-token-here".to_string()),
|
||||
auth_token: None,
|
||||
enable_cors: true,
|
||||
let router = Router::new(router_config.clone())?;
|
||||
|
||||
// Health check implementation
|
||||
println!("\n--- Health Check ---");
|
||||
let health = check_health(&router);
|
||||
println!("Status: {}", if health { "healthy" } else { "unhealthy" });
|
||||
|
||||
// Readiness check
|
||||
println!("\n--- Readiness Check ---");
|
||||
let ready = check_readiness(&router);
|
||||
println!("Ready: {}", ready);
|
||||
|
||||
// Configuration info
|
||||
println!("\n--- Configuration ---");
|
||||
let config = router.config();
|
||||
println!("Current configuration: {:?}", config);
|
||||
|
||||
// Circuit breaker status
|
||||
println!("\n--- Circuit Breaker Status ---");
|
||||
match router.circuit_breaker_status() {
|
||||
Some(true) => println!("State: Closed (accepting requests)"),
|
||||
Some(false) => println!("State: Open (rejecting requests)"),
|
||||
None => println!("State: Disabled"),
|
||||
}
|
||||
|
||||
// Test routing to verify system works
|
||||
println!("\n--- Test Routing ---");
|
||||
let candidates = vec![
|
||||
Candidate {
|
||||
id: "test-1".to_string(),
|
||||
embedding: vec![0.5; 384],
|
||||
metadata: HashMap::new(),
|
||||
created_at: chrono::Utc::now().timestamp(),
|
||||
access_count: 10,
|
||||
success_rate: 0.95,
|
||||
},
|
||||
];
|
||||
|
||||
let request = RoutingRequest {
|
||||
query_embedding: vec![0.5; 384],
|
||||
candidates,
|
||||
metadata: None,
|
||||
};
|
||||
|
||||
tracing::info!(
|
||||
"Starting admin server on {}:{}",
|
||||
admin_config.bind_address,
|
||||
admin_config.port
|
||||
);
|
||||
tracing::info!(
|
||||
"Authentication: {}",
|
||||
if admin_config.auth_token.is_some() {
|
||||
"enabled"
|
||||
} else {
|
||||
"disabled"
|
||||
match router.route(request) {
|
||||
Ok(response) => {
|
||||
println!(
|
||||
"Test routing successful: {} candidates in {}μs",
|
||||
response.candidates_processed, response.inference_time_us
|
||||
);
|
||||
}
|
||||
);
|
||||
Err(e) => {
|
||||
println!("Test routing failed: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Create and start admin server
|
||||
let server = AdminServer::new(router, admin_config);
|
||||
// Model reload demonstration
|
||||
println!("\n--- Model Reload ---");
|
||||
println!("Attempting model reload...");
|
||||
match router.reload_model() {
|
||||
Ok(_) => println!("Model reload: Success"),
|
||||
Err(e) => println!("Model reload: {} (expected if model file doesn't exist)", e),
|
||||
}
|
||||
|
||||
println!("\n╔════════════════════════════════════════════════════════════════╗");
|
||||
println!("║ Tiny Dancer Admin Server Running ║");
|
||||
println!("╠════════════════════════════════════════════════════════════════╣");
|
||||
println!("║ Health Check: http://localhost:8080/health ║");
|
||||
println!("║ Readiness: http://localhost:8080/health/ready ║");
|
||||
println!("║ Metrics: http://localhost:8080/metrics ║");
|
||||
println!("║ System Info: http://localhost:8080/info ║");
|
||||
println!("║ ║");
|
||||
println!("║ Admin API: http://localhost:8080/admin/* ║");
|
||||
println!("║ - POST /admin/reload ║");
|
||||
println!("║ - GET /admin/config ║");
|
||||
println!("║ - PUT /admin/config ║");
|
||||
println!("║ - GET /admin/circuit-breaker ║");
|
||||
println!("║ - POST /admin/circuit-breaker/reset ║");
|
||||
println!("╚════════════════════════════════════════════════════════════════╝\n");
|
||||
|
||||
// Start server (blocking)
|
||||
server.serve().await?;
|
||||
println!("\n=== Admin Example Complete ===");
|
||||
println!("\nFor a full HTTP admin server, you would need:");
|
||||
println!("1. Add axum and tokio dependencies");
|
||||
println!("2. Enable the admin-api feature");
|
||||
println!("3. Use the AdminServer from the api module");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Basic health check - returns true if the router is operational
|
||||
fn check_health(router: &Router) -> bool {
|
||||
// A simple health check just verifies the router exists
|
||||
// In production, you might also check model availability
|
||||
router.config().model_path.len() > 0
|
||||
}
|
||||
|
||||
/// Readiness check - returns true if ready to accept traffic
|
||||
fn check_readiness(router: &Router) -> bool {
|
||||
// Check circuit breaker status
|
||||
match router.circuit_breaker_status() {
|
||||
Some(is_closed) => is_closed, // Ready only if circuit breaker is closed
|
||||
None => true, // Ready if circuit breaker is disabled
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,40 +1,20 @@
|
|||
//! Comprehensive observability example combining metrics and tracing
|
||||
//! Comprehensive observability example demonstrating routing performance
|
||||
//!
|
||||
//! This example demonstrates:
|
||||
//! - Prometheus metrics collection
|
||||
//! - OpenTelemetry distributed tracing
|
||||
//! - Structured logging
|
||||
//! - Circuit breaker monitoring
|
||||
//! - Performance tracking
|
||||
//!
|
||||
//! Prerequisites:
|
||||
//! - Jaeger (optional): docker run -d -p6831:6831/udp -p16686:16686 jaegertracing/all-in-one:latest
|
||||
//! - Prometheus (optional): Configure to scrape your metrics endpoint
|
||||
//! - Response statistics
|
||||
//! - Different load scenarios
|
||||
//!
|
||||
//! Run with: cargo run --example full_observability
|
||||
|
||||
use ruvector_tiny_dancer_core::{
|
||||
Candidate, Router, RouterConfig, RoutingRequest, TracingConfig, TracingSystem,
|
||||
};
|
||||
use ruvector_tiny_dancer_core::{Candidate, Router, RouterConfig, RoutingRequest, RoutingResponse};
|
||||
use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("=== Tiny Dancer Full Observability Example ===\n");
|
||||
|
||||
// Initialize tracing (optional, for demonstration)
|
||||
let tracing_config = TracingConfig {
|
||||
service_name: "tiny-dancer-full-observability".to_string(),
|
||||
service_version: "1.0.0".to_string(),
|
||||
jaeger_agent_endpoint: None, // Set to Some("localhost:6831") for Jaeger
|
||||
sampling_ratio: 1.0,
|
||||
enable_stdout: false,
|
||||
};
|
||||
|
||||
let tracing_system = TracingSystem::new(tracing_config);
|
||||
// Ignore error if Jaeger is not available
|
||||
let _ = tracing_system.init();
|
||||
|
||||
// Create router with full configuration
|
||||
let config = RouterConfig {
|
||||
model_path: "./models/fastgrnn.safetensors".to_string(),
|
||||
|
|
@ -48,6 +28,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
|
||||
let router = Router::new(config)?;
|
||||
|
||||
// Track metrics manually
|
||||
let mut total_requests = 0u64;
|
||||
let mut successful_requests = 0u64;
|
||||
let mut total_latency_us = 0u64;
|
||||
let mut lightweight_routes = 0usize;
|
||||
let mut powerful_routes = 0usize;
|
||||
|
||||
println!("\n=== Scenario 1: Normal Operations ===\n");
|
||||
|
||||
// Process normal requests
|
||||
|
|
@ -62,8 +49,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
)])),
|
||||
};
|
||||
|
||||
total_requests += 1;
|
||||
match router.route(request) {
|
||||
Ok(response) => {
|
||||
successful_requests += 1;
|
||||
total_latency_us += response.inference_time_us;
|
||||
let (lw, pw) = count_routes(&response);
|
||||
lightweight_routes += lw;
|
||||
powerful_routes += pw;
|
||||
print_response_summary(i + 1, &response);
|
||||
}
|
||||
Err(e) => {
|
||||
|
|
@ -88,8 +81,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
)])),
|
||||
};
|
||||
|
||||
total_requests += 1;
|
||||
match router.route(request) {
|
||||
Ok(response) => {
|
||||
successful_requests += 1;
|
||||
total_latency_us += response.inference_time_us;
|
||||
let (lw, pw) = count_routes(&response);
|
||||
lightweight_routes += lw;
|
||||
powerful_routes += pw;
|
||||
print_response_summary(i + 1, &response);
|
||||
}
|
||||
Err(e) => {
|
||||
|
|
@ -98,41 +97,24 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
}
|
||||
}
|
||||
|
||||
println!("\n=== Metrics Export ===\n");
|
||||
|
||||
// Export Prometheus metrics
|
||||
let metrics = router.export_metrics()?;
|
||||
|
||||
println!("Sample metrics (showing key metrics only):\n");
|
||||
for line in metrics.lines() {
|
||||
if line.starts_with("tiny_dancer_routing_requests_total")
|
||||
|| line.starts_with("tiny_dancer_routing_decisions_total")
|
||||
|| line.starts_with("tiny_dancer_circuit_breaker_state")
|
||||
|| line.starts_with("# HELP")
|
||||
|| line.starts_with("# TYPE")
|
||||
{
|
||||
println!("{}", line);
|
||||
}
|
||||
}
|
||||
|
||||
// Display statistics
|
||||
println!("\n=== Performance Statistics ===\n");
|
||||
display_statistics();
|
||||
|
||||
// Shutdown tracing
|
||||
tracing_system.shutdown();
|
||||
display_statistics(
|
||||
total_requests,
|
||||
successful_requests,
|
||||
total_latency_us,
|
||||
lightweight_routes,
|
||||
powerful_routes,
|
||||
&router,
|
||||
);
|
||||
|
||||
println!("\n=== Full Observability Example Complete ===");
|
||||
println!("\nObservability Stack:");
|
||||
println!("✓ Prometheus metrics collected");
|
||||
println!("✓ Distributed traces created");
|
||||
println!("✓ Structured logging enabled");
|
||||
println!("✓ Circuit breaker monitored");
|
||||
println!("\nNext steps:");
|
||||
println!("1. Deploy Prometheus to scrape metrics");
|
||||
println!("2. Connect Jaeger for trace visualization");
|
||||
println!("3. Set up Grafana dashboards");
|
||||
println!("4. Configure alerting rules");
|
||||
println!("\nMetrics Summary:");
|
||||
println!("- Total requests processed");
|
||||
println!("- Success/failure rates tracked");
|
||||
println!("- Latency statistics computed");
|
||||
println!("- Routing decisions categorized");
|
||||
println!("- Circuit breaker state monitored");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -153,13 +135,14 @@ fn create_candidates(offset: i32, count: usize) -> Vec<Candidate> {
|
|||
.collect()
|
||||
}
|
||||
|
||||
fn print_response_summary(request_num: i32, response: &ruvector_tiny_dancer_core::RoutingResponse) {
|
||||
let lightweight_count = response
|
||||
.decisions
|
||||
.iter()
|
||||
.filter(|d| d.use_lightweight)
|
||||
.count();
|
||||
let powerful_count = response.decisions.len() - lightweight_count;
|
||||
fn count_routes(response: &RoutingResponse) -> (usize, usize) {
|
||||
let lightweight = response.decisions.iter().filter(|d| d.use_lightweight).count();
|
||||
let powerful = response.decisions.len() - lightweight;
|
||||
(lightweight, powerful)
|
||||
}
|
||||
|
||||
fn print_response_summary(request_num: i32, response: &RoutingResponse) {
|
||||
let (lightweight_count, powerful_count) = count_routes(response);
|
||||
|
||||
println!(
|
||||
"Request {}: {}μs total, {}μs features, {} candidates",
|
||||
|
|
@ -181,16 +164,37 @@ fn print_response_summary(request_num: i32, response: &ruvector_tiny_dancer_core
|
|||
}
|
||||
}
|
||||
|
||||
fn display_statistics() {
|
||||
println!("Circuit Breaker: Closed");
|
||||
println!("Total Requests: 8");
|
||||
println!("Success Rate: 100%");
|
||||
println!("Avg Latency: <1ms");
|
||||
println!("\nMetric Types Collected:");
|
||||
println!("- tiny_dancer_routing_requests_total (counter)");
|
||||
println!("- tiny_dancer_routing_latency_seconds (histogram)");
|
||||
println!("- tiny_dancer_circuit_breaker_state (gauge)");
|
||||
println!("- tiny_dancer_routing_decisions_total (counter)");
|
||||
println!("- tiny_dancer_confidence_scores (histogram)");
|
||||
println!("- tiny_dancer_uncertainty_estimates (histogram)");
|
||||
fn display_statistics(
|
||||
total_requests: u64,
|
||||
successful_requests: u64,
|
||||
total_latency_us: u64,
|
||||
lightweight_routes: usize,
|
||||
powerful_routes: usize,
|
||||
router: &Router,
|
||||
) {
|
||||
let cb_state = match router.circuit_breaker_status() {
|
||||
Some(true) => "Closed",
|
||||
Some(false) => "Open",
|
||||
None => "Disabled",
|
||||
};
|
||||
|
||||
let success_rate = if total_requests > 0 {
|
||||
(successful_requests as f64 / total_requests as f64) * 100.0
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
let avg_latency = if successful_requests > 0 {
|
||||
total_latency_us / successful_requests
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
println!("Circuit Breaker: {}", cb_state);
|
||||
println!("Total Requests: {}", total_requests);
|
||||
println!("Successful Requests: {}", successful_requests);
|
||||
println!("Success Rate: {:.1}%", success_rate);
|
||||
println!("Avg Latency: {}μs", avg_latency);
|
||||
println!("Lightweight Routes: {}", lightweight_routes);
|
||||
println!("Powerful Routes: {}", powerful_routes);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
//! Example demonstrating Prometheus metrics collection with Tiny Dancer
|
||||
//! Example demonstrating metrics collection with Tiny Dancer
|
||||
//!
|
||||
//! This example shows how to:
|
||||
//! - Collect routing metrics
|
||||
//! - Export metrics in Prometheus format
|
||||
//! - Collect routing metrics manually
|
||||
//! - Monitor circuit breaker state
|
||||
//! - Track routing decisions and latencies
|
||||
//!
|
||||
|
|
@ -26,6 +25,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
|
||||
let router = Router::new(config)?;
|
||||
|
||||
// Track metrics manually
|
||||
let mut total_requests = 0u64;
|
||||
let mut total_candidates = 0u64;
|
||||
let mut total_latency_us = 0u64;
|
||||
let mut lightweight_count = 0u64;
|
||||
let mut powerful_count = 0u64;
|
||||
|
||||
// Process multiple routing requests
|
||||
println!("Processing routing requests...\n");
|
||||
|
||||
|
|
@ -65,13 +71,31 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
|
||||
match router.route(request) {
|
||||
Ok(response) => {
|
||||
total_requests += 1;
|
||||
total_candidates += response.candidates_processed as u64;
|
||||
total_latency_us += response.inference_time_us;
|
||||
|
||||
// Count routing decisions
|
||||
for decision in &response.decisions {
|
||||
if decision.use_lightweight {
|
||||
lightweight_count += 1;
|
||||
} else {
|
||||
powerful_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
println!(
|
||||
"Request {}: Processed {} candidates in {}μs",
|
||||
i + 1,
|
||||
response.candidates_processed,
|
||||
response.inference_time_us
|
||||
);
|
||||
println!(" Top decision: {:?}", response.decisions.first());
|
||||
if let Some(top) = response.decisions.first() {
|
||||
println!(
|
||||
" Top decision: {} (confidence: {:.3}, lightweight: {})",
|
||||
top.candidate_id, top.confidence, top.use_lightweight
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Error processing request {}: {}", i + 1, e);
|
||||
|
|
@ -79,36 +103,39 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
}
|
||||
}
|
||||
|
||||
// Export metrics
|
||||
println!("\n=== Prometheus Metrics ===\n");
|
||||
let metrics = router.export_metrics()?;
|
||||
println!("{}", metrics);
|
||||
// Display collected metrics
|
||||
println!("\n=== Collected Metrics ===\n");
|
||||
|
||||
// Parse and display key metrics
|
||||
println!("\n=== Key Metrics Summary ===\n");
|
||||
let cb_state = match router.circuit_breaker_status() {
|
||||
Some(true) => "closed",
|
||||
Some(false) => "open",
|
||||
None => "disabled",
|
||||
};
|
||||
|
||||
for line in metrics.lines() {
|
||||
if line.starts_with("tiny_dancer_routing_requests_total") {
|
||||
println!("{}", line);
|
||||
} else if line.starts_with("tiny_dancer_routing_decisions_total") {
|
||||
println!("{}", line);
|
||||
} else if line.starts_with("tiny_dancer_circuit_breaker_state") {
|
||||
println!("{}", line);
|
||||
} else if line.starts_with("tiny_dancer_candidates_processed_total") {
|
||||
println!("{}", line);
|
||||
}
|
||||
}
|
||||
let avg_latency = if total_requests > 0 {
|
||||
total_latency_us / total_requests
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
println!("tiny_dancer_routing_requests_total {}", total_requests);
|
||||
println!("tiny_dancer_candidates_processed_total {}", total_candidates);
|
||||
println!(
|
||||
"tiny_dancer_routing_decisions_total{{model_type=\"lightweight\"}} {}",
|
||||
lightweight_count
|
||||
);
|
||||
println!(
|
||||
"tiny_dancer_routing_decisions_total{{model_type=\"powerful\"}} {}",
|
||||
powerful_count
|
||||
);
|
||||
println!("tiny_dancer_avg_latency_us {}", avg_latency);
|
||||
println!("tiny_dancer_circuit_breaker_state {}", cb_state);
|
||||
|
||||
println!("\n=== Metrics Collection Complete ===");
|
||||
println!("\nTo visualize these metrics:");
|
||||
println!("1. Set up a Prometheus server");
|
||||
println!("2. Configure scraping from your application");
|
||||
println!("3. Use Grafana to create dashboards");
|
||||
println!("\nExample Prometheus configuration:");
|
||||
println!(" scrape_configs:");
|
||||
println!(" - job_name: 'tiny-dancer'");
|
||||
println!(" static_configs:");
|
||||
println!(" - targets: ['localhost:9090']");
|
||||
println!("\nThese metrics can be exported to monitoring systems:");
|
||||
println!("- Prometheus for time-series collection");
|
||||
println!("- Grafana for visualization");
|
||||
println!("- Custom dashboards for real-time monitoring");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,45 +1,20 @@
|
|||
//! Example demonstrating distributed tracing with OpenTelemetry and Jaeger
|
||||
//! Example demonstrating basic tracing with the Tiny Dancer routing system
|
||||
//!
|
||||
//! This example shows how to:
|
||||
//! - Initialize OpenTelemetry tracing
|
||||
//! - Create spans for routing operations
|
||||
//! - Propagate trace context
|
||||
//! - Export traces to Jaeger
|
||||
//!
|
||||
//! Prerequisites:
|
||||
//! - Run Jaeger: docker run -d -p6831:6831/udp -p16686:16686 jaegertracing/all-in-one:latest
|
||||
//! - Create and configure a router
|
||||
//! - Process routing requests
|
||||
//! - Monitor timing and performance
|
||||
//!
|
||||
//! Run with: cargo run --example tracing_example
|
||||
|
||||
use ruvector_tiny_dancer_core::{
|
||||
Candidate, Router, RouterConfig, RoutingRequest, TraceContext, TracingConfig, TracingSystem,
|
||||
};
|
||||
use ruvector_tiny_dancer_core::{Candidate, Router, RouterConfig, RoutingRequest};
|
||||
use std::collections::HashMap;
|
||||
use std::time::Instant;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("=== Tiny Dancer Distributed Tracing Example ===\n");
|
||||
println!("=== Tiny Dancer Routing Example with Timing ===\n");
|
||||
|
||||
// Initialize tracing with stdout exporter (for demonstration)
|
||||
// In production, use Jaeger endpoint
|
||||
let tracing_config = TracingConfig {
|
||||
service_name: "tiny-dancer-example".to_string(),
|
||||
service_version: "1.0.0".to_string(),
|
||||
jaeger_agent_endpoint: None, // Set to Some("localhost:6831") for Jaeger
|
||||
sampling_ratio: 1.0,
|
||||
enable_stdout: true, // Set to false when using Jaeger
|
||||
};
|
||||
|
||||
let tracing_system = TracingSystem::new(tracing_config);
|
||||
tracing_system.init()?;
|
||||
|
||||
println!("Tracing initialized (stdout mode for demonstration)\n");
|
||||
println!("To use Jaeger:");
|
||||
println!("1. Start Jaeger: docker run -d -p6831:6831/udp -p16686:16686 jaegertracing/all-in-one:latest");
|
||||
println!("2. Set jaeger_agent_endpoint to Some(\"localhost:6831\")");
|
||||
println!("3. Set enable_stdout to false");
|
||||
println!("4. Visit http://localhost:16686 to view traces\n");
|
||||
|
||||
// Create router
|
||||
// Create router with configuration
|
||||
let config = RouterConfig {
|
||||
model_path: "./models/fastgrnn.safetensors".to_string(),
|
||||
confidence_threshold: 0.85,
|
||||
|
|
@ -51,19 +26,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
|
||||
let router = Router::new(config)?;
|
||||
|
||||
// Process requests with tracing
|
||||
println!("Processing requests with distributed tracing...\n");
|
||||
// Process requests with timing
|
||||
println!("Processing requests with timing information...\n");
|
||||
|
||||
for i in 0..3 {
|
||||
let request_start = Instant::now();
|
||||
println!("Request {} - Processing", i + 1);
|
||||
|
||||
// Get trace context for propagation (requires OpenTelemetry to be initialized)
|
||||
if let Some(trace_ctx) = TraceContext::from_current() {
|
||||
println!(" Trace ID: {}", trace_ctx.trace_id);
|
||||
println!(" Span ID: {}", trace_ctx.span_id);
|
||||
println!(" W3C Traceparent: {}", trace_ctx.to_w3c_traceparent());
|
||||
}
|
||||
|
||||
// Create candidates
|
||||
let candidates = vec![
|
||||
Candidate {
|
||||
|
|
@ -90,14 +59,16 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
metadata: None,
|
||||
};
|
||||
|
||||
// Route with automatic span creation
|
||||
// Route request
|
||||
match router.route(request) {
|
||||
Ok(response) => {
|
||||
let total_time = request_start.elapsed();
|
||||
println!(
|
||||
"\nRequest {}: Processed {} candidates in {}μs",
|
||||
"\nRequest {}: Processed {} candidates in {}μs (total: {:?})",
|
||||
i + 1,
|
||||
response.candidates_processed,
|
||||
response.inference_time_us
|
||||
response.inference_time_us,
|
||||
total_time
|
||||
);
|
||||
|
||||
for decision in response.decisions.iter().take(2) {
|
||||
|
|
@ -115,17 +86,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
println!();
|
||||
}
|
||||
|
||||
// Shutdown tracing to flush remaining spans
|
||||
println!("\n=== Flushing traces ===");
|
||||
tracing_system.shutdown();
|
||||
|
||||
println!("\n=== Tracing Example Complete ===");
|
||||
println!("\nSpans created during execution:");
|
||||
println!("- routing_request (Router::route)");
|
||||
println!("- circuit_breaker_check");
|
||||
println!("- feature_engineering");
|
||||
println!("- model_inference (per candidate)");
|
||||
println!("- uncertainty_estimation (per candidate)");
|
||||
println!("\n=== Routing Example Complete ===");
|
||||
println!("\nTiming breakdown available in each response:");
|
||||
println!("- inference_time_us: Total inference time");
|
||||
println!("- feature_time_us: Feature engineering time");
|
||||
println!("- candidates_processed: Number of candidates evaluated");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,3 +54,9 @@ impl From<serde_json::Error> for TinyDancerError {
|
|||
TinyDancerError::SerializationError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for TinyDancerError {
|
||||
fn from(err: std::io::Error) -> Self {
|
||||
TinyDancerError::StorageError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
//! - Uncertainty quantification with conformal prediction
|
||||
//! - Circuit breaker patterns for graceful degradation
|
||||
//! - SQLite/AgentDB integration
|
||||
//! - Training infrastructure with knowledge distillation
|
||||
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![warn(missing_docs, rustdoc::broken_intra_doc_links)]
|
||||
|
|
@ -20,14 +21,16 @@ pub mod model;
|
|||
pub mod optimization;
|
||||
pub mod router;
|
||||
pub mod storage;
|
||||
pub mod training;
|
||||
pub mod types;
|
||||
pub mod uncertainty;
|
||||
|
||||
// Re-exports for convenience
|
||||
pub use error::{Result, TinyDancerError};
|
||||
pub use model::FastGRNN;
|
||||
pub use model::{FastGRNN, FastGRNNConfig};
|
||||
pub use router::Router;
|
||||
pub use types::{Candidate, RoutingDecision, RoutingRequest, RoutingResponse};
|
||||
pub use training::{generate_teacher_predictions, Trainer, TrainingConfig, TrainingDataset, TrainingMetrics};
|
||||
pub use types::{Candidate, RouterConfig, RoutingDecision, RoutingRequest, RoutingResponse, RoutingMetrics};
|
||||
|
||||
/// Version of the Tiny Dancer library
|
||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue