ऑब्ज़र्वेबिलिटी Rust डेवलपर के लिए एक सुपरपावर क्यों है
\n\nकल्पना करें: आपकी Rust सेवा production में चल रही है, लेकिन अचानक latency आसमान छूने लगती है। लॉग चुप हैं, मेट्रिक्स 200 OK दिखा रहे हैं, और उपयोगकर्ता शिकायत कर रहे हैं। परिचित लगता है? यह एक क्लासिक "ब्लैक बॉक्स" है। Rust में ऑब्ज़र्वेबिलिटी के बिना, आप अंधे हैं।
\n\nऑब्ज़र्वेबिलिटी सिर्फ "लॉग + मेट्रिक्स" नहीं है। यह सिस्टम से कोई भी प्रश्न पूछने की क्षमता है, बिना नया कोड लिखे। Rust में, प्रदर्शन और विश्वसनीयता पर इसके जोर के साथ, ऑब्ज़र्वेबिलिटी production-grade अनुप्रयोगों के लिए एक अनिवार्य घटक बन जाता है।
\n\nइस लेख में, हम Rust में ऑब्ज़र्वेबिलिटी के तीन स्तंभों को समझेंगे: ट्रेसिंग, मेट्रिक्स और लॉग। आपको tracing, OpenTelemetry और Prometheus के साथ तैयार कोड उदाहरण मिलेंगे, जिन्हें आप तुरंत अपने प्रोजेक्ट में लागू कर सकते हैं।
Rust में ट्रेसिंग: सिस्टम के माध्यम से अनुरोध की यात्रा
\n\nट्रेसिंग एक अनुरोध की जीवन कहानी है। बिखरे हुए लॉग के बजाय, आपको एक जुड़ा हुआ पथ मिलता है: API में प्रवेश से लेकर डेटाबेस क्वेरी और क्लाइंट को प्रतिक्रिया तक। Rust के लिए सबसे अच्छा टूल Tokio समुदाय का tracing क्रेट है।
Rust एप्लिकेशन में tracing सेटअप करना
\n\nबुनियादी सेटअप से शुरू करते हैं। Cargo.toml में जोड़ें:
[dependencies]\ntracing = "0.1"\ntracing-subscriber = "0.3"\ntracing-opentelemetry = "0.23"\nopentelemetry = "0.22"\nopentelemetry-otlp = "0.15"\n\nअब main.rs में ट्रेसर को इनिशियलाइज़ करें:
use tracing_subscriber::{fmt, prelude::*, EnvFilter};\nuse opentelemetry::{global, KeyValue};\nuse opentelemetry_otlp::WithExportConfig;\n\nfn init_tracer() -> Result<(), Box<dyn std::error::Error>> {\n global::set_text_map_propagator(opentelemetry_jaeger::Propagator::new());\n \n let tracer = opentelemetry_otlp::new_pipeline()\n .tracing()\n .with_exporter(\n opentelemetry_otlp::new_exporter()\n .tonic()\n .with_endpoint("http://localhost:4317")\n )\n .with_trace_config(\n opentelemetry::sdk::trace::config()\n .with_resource(opentelemetry::sdk::Resource::new(vec![\n KeyValue::new("service.name", "rust-observability-demo")\n ]))\n )\n .install_simple()?;\n\n // tracing को OpenTelemetry से जोड़ना\n let telemetry = tracing_opentelemetry::layer().with_tracer(tracer);\n let subscriber = fmt::Subscriber::builder()\n .with_env_filter(EnvFilter::from_default_env())\n .finish()\n .with(telemetry);\n\n tracing::subscriber::set_global_default(subscriber)?;\n Ok(())\n}\n\nस्पैन और ट्रेस बनाना
\n\nअब बिज़नेस लॉजिक में ट्रेसिंग जोड़ें:
\n\nuse tracing::{span, Span, Level, instrument};\n\n#[instrument]\nasync fn handle_request(user_id: u64) -> Result<String, Box<dyn std::error::Error>> {\n let user_data = get_user_data(user_id).await?;\n let processed = process_data(&user_data).await?;\n Ok(processed)\n}\n\n#[instrument(skip(db_pool))]\nasync fn get_user_data(user_id: u64) -> Result<User, Box<dyn std::error::Error>> {\n // DB क्वेरी का अनुकरण\n let span = Span::current();\n span.record("db.query", "SELECT * FROM users WHERE id = $1");\n \n tokio::time::sleep(std::time::Duration::from_millis(50)).await;\n Ok(User { id: user_id, name: "Alice".into() })\n}\n\n#[instrument]\nasync fn process_data(user: &User) -> Result<String, Box<dyn std::error::Error>> {\n let result = format!("Processed user: {}", user.name);\n tracing::info!(user_id = user.id, "Data processed successfully");\n Ok(result)\n}\n\n#[instrument] एट्रीब्यूट स्वचालित रूप से फ़ंक्शन के लिए एक span बनाता है और सभी आर्गुमेंट्स रिकॉर्ड करता है। Jaege