-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtrace_bridge_flow.rs
More file actions
143 lines (126 loc) · 5.23 KB
/
Copy pathtrace_bridge_flow.rs
File metadata and controls
143 lines (126 loc) · 5.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// SPDX-FileCopyrightText: 2025 Semiotic AI, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//! Example demonstrating OpenTelemetry span instrumentation for CCTP operations
//!
//! This example shows how spans are automatically created for bridge operations,
//! following production observability best practices.
//!
//! Run with tracing enabled:
//! ```bash
//! RUST_LOG=cctp_rs=debug cargo run --example trace_bridge_flow
//! ```
//!
//! For full trace output including all spans:
//! ```bash
//! RUST_LOG=trace cargo run --example trace_bridge_flow
//! ```
use alloy_chains::NamedChain;
use alloy_primitives::{FixedBytes, TxHash};
use alloy_provider::ProviderBuilder;
use cctp_rs::{Cctp, CctpError};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
#[tokio::main]
async fn main() -> Result<(), CctpError> {
// Initialize tracing subscriber with environment filter
// This will output structured logs with span context
tracing_subscriber::registry()
.with(EnvFilter::from_default_env())
.with(
tracing_subscriber::fmt::layer()
.with_target(true)
.with_level(true)
.with_thread_ids(false)
.with_thread_names(false),
)
.init();
tracing::info!("Starting CCTP bridge tracing example");
// Set up bridge configuration
let eth_provider = ProviderBuilder::new()
.connect_http("https://eth-mainnet.g.alchemy.com/v2/demo".parse().unwrap());
let arb_provider = ProviderBuilder::new()
.connect_http("https://arb-mainnet.g.alchemy.com/v2/demo".parse().unwrap());
let bridge = Cctp::builder()
.source_chain(NamedChain::Mainnet)
.destination_chain(NamedChain::Arbitrum)
.source_provider(eth_provider)
.destination_provider(arb_provider)
.recipient(
"0x742d35Cc6634C0532925a3b844Bc9e7595f8fA0d"
.parse()
.unwrap(),
)
.build();
tracing::info!(
source_chain = %bridge.source_chain(),
destination_chain = %bridge.destination_chain(),
"Bridge initialized"
);
// Example 1: Demonstrate get_message_sent_event span
println!("\n=== Example 1: Getting MessageSent event ===");
println!("This operation creates a span: cctp_rs.get_message_sent_event");
println!("With attributes: tx_hash, source_chain, destination_chain\n");
let example_tx_hash: TxHash =
"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
.parse()
.unwrap();
// This will fail since it's not a real tx, but demonstrates the span creation
match bridge.get_message_sent_event(example_tx_hash).await {
Ok((message, hash)) => {
tracing::info!(
message_length = message.len(),
message_hash = %hash,
"Successfully extracted MessageSent event"
);
}
Err(e) => {
// Expected to fail for demo purposes
tracing::warn!(error = %e, "Example transaction not found (expected)");
}
}
// Example 2: Demonstrate attestation polling spans
println!("\n=== Example 2: Attestation polling ===");
println!("This operation creates multiple nested spans:");
println!(" - cctp_rs.get_attestation_with_retry (parent)");
println!(" ├─ cctp_rs.get_attestation (for each attempt)");
println!(" └─ cctp_rs.process_attestation_response\n");
let message_hash: FixedBytes<32> = FixedBytes::from([42u8; 32]);
// Use minimal retries for demo purposes
match bridge
.get_attestation(
message_hash,
cctp_rs::PollingConfig::default()
.with_max_attempts(2)
.with_poll_interval_secs(5),
)
.await
{
Ok(attestation) => {
tracing::info!(
attestation_length = attestation.len(),
"Successfully retrieved attestation"
);
}
Err(e) => {
// Expected to fail for demo purposes
tracing::warn!(error = %e, "Attestation not found (expected for example data)");
}
}
println!("\n=== Span Hierarchy Demonstration Complete ===");
println!("\nKey Observability Features Demonstrated:");
println!("✓ Static span names: cctp_rs.operation_name");
println!("✓ Structured attributes: All dynamic data in fields");
println!("✓ Async-safe: Spans propagate across .await boundaries");
println!("✓ Parent-child relationships: Nested spans for complex operations");
println!("✓ Low cardinality: Span names are static, data in attributes");
println!("\n📊 In production, these spans would be:");
println!(" • Exported to Tempo/Jaeger via OTLP");
println!(" • Queryable via TraceQL");
println!(" • Visualized in Grafana dashboards");
println!("\n🔍 Example TraceQL queries:");
println!(" # Find all attestation polling operations");
println!(" {{ resource.service.name = \"cctp-rs\" && name = \"cctp_rs.get_attestation\" }}");
println!("\n # Find operations for specific chain pair");
println!(" {{ span.source_chain = \"Mainnet\" && span.destination_chain = \"Arbitrum\" }}");
Ok(())
}