refactor init tracer and use of tracing_opentelemetry span for async tracing

This commit is contained in:
Floriane TUERNAL SABOTINOV
2025-10-17 11:27:45 +02:00
parent 12f7f7b669
commit 32f1ebebf9
17 changed files with 597 additions and 205 deletions
Generated
+1
View File
@@ -5811,6 +5811,7 @@ dependencies = [
"time",
"tokio",
"tracing",
"tracing-opentelemetry",
"tungstenite 0.20.1",
"wasmtimer",
"zeroize",
+16 -2
View File
@@ -5,6 +5,7 @@ use opentelemetry_sdk::{propagation::TraceContextPropagator, trace::IdGenerator}
use tracing_opentelemetry::OpenTelemetrySpanExt;
use std::collections::HashMap;
use std::fmt::Display;
use tracing::instrument;
/// Make a Carrier for context propagation
pub struct ContextCarrier {
@@ -93,6 +94,7 @@ pub struct ManualContextPropagator {
}
impl ManualContextPropagator {
#[instrument(skip_all, level = "debug")]
pub fn new(name: &str, context: HashMap<String, String>) -> Self {
let carrier = ContextCarrier::new_with_data(context);
let trace_id = match carrier.extract_trace_id() {
@@ -101,7 +103,6 @@ impl ManualContextPropagator {
};
let root_span_builder = new_span_context_with_id(trace_id.clone());
let _guard = root_span_builder.clone().attach();
let root_span = tracing::info_span!("trace_root", name = %name, trace_id = %trace_id);
root_span.set_parent(root_span_builder);
@@ -112,9 +113,9 @@ impl ManualContextPropagator {
}
}
#[instrument(skip_all, level = "debug")]
pub fn new_from_tid(name: &str, trace_id: TraceId) -> Self {
let root_span_builder = new_span_context_with_id(trace_id.clone());
let _guard = root_span_builder.clone().attach();
let root_span = tracing::info_span!("trace_root", name = %name, trace_id = %trace_id);
root_span.set_parent(root_span_builder);
@@ -125,8 +126,13 @@ impl ManualContextPropagator {
}
}
pub fn root_span(&self) -> &tracing::Span {
&self.root_span
}
}
#[instrument(skip_all, level = "debug")]
pub fn new_span_context_with_id(trace_id: TraceId) -> Context {
let id_gen = opentelemetry_sdk::trace::RandomIdGenerator::default();
let span_id = id_gen.new_span_id();
@@ -139,4 +145,12 @@ pub fn new_span_context_with_id(trace_id: TraceId) -> Context {
);
Context::current().with_remote_span_context(span_context)
}
#[instrument(skip_all, level = "debug")]
pub fn extract_trace_id_from_tracing_cx() -> TraceId {
let cx = tracing::Span::current().context();
let binding = cx.span();
let trace_id = binding.span_context().trace_id();
trace_id
}
+169 -42
View File
@@ -53,23 +53,30 @@ pub(crate) fn granual_filtered_env() -> Result<tracing_subscriber::filter::EnvFi
Ok(filter)
}
pub fn setup_tracing_logger(service_name: String) -> Result<(), TracingError> {
pub fn setup_tracing_logger(service_name: String) -> Result<TracerProviderGuard, TracingError> {
if tracing::dispatcher::has_been_set() {
// It shouldn't be - this is really checking that it is torn down between async command executions
return Err(TracingError::TracingLoggerAlreadyInitialised);
}
let key =
std::env::var("SIGNOZ_INGESTION_KEY".to_string()).expect("SIGNOZ_INGESTION_KEY not set");
// define ingestion points
let endpoint = std::env::var("SIGNOZ_ENDPOINT").expect("SIGNOZ_ENDPOINT not set");
let key = std::env::var("SIGNOZ_INGESTION_KEY").expect("SIGNOZ_INGESTION_KEY not set");
let mut metadata = MetadataMap::new();
metadata.insert(
"signoz-ingestion-key",
key.parse().expect("Could not parse signoz ingestion key"),
);
let tracer_provider = init_tracer_provider(metadata.clone(), service_name.clone())?;
let meter_provider = init_meter_provider(metadata.clone(), service_name.clone())?;
let tracer = tracer_provider.tracer("tracing-otel-subscriber");
// Build resources
let resource = build_resource(&service_name);
// Initialize tracer and meter providers
let tracer_provider = init_tracer_provider(&endpoint, metadata.clone(), resource.clone())?;
let meter_provider = init_meter_provider(&endpoint, metadata.clone(), resource.clone())?;
// Bridge tracing and opentelemetry
let tracer = tracer_provider.tracer("otel-subscriber");
let fmt_layer = fmt::layer()
.json()
.with_writer(std::io::stderr)
@@ -78,36 +85,26 @@ pub fn setup_tracing_logger(service_name: String) -> Result<(), TracingError> {
.with_current_span(true)
.event_format(trace_id_format::TraceIdFormat);
cfg_if::cfg_if! {if #[cfg(feature = "tokio-console")] {
// instrument tokio console subscriber needs RUSTFLAGS="--cfg tokio_unstable" at build time
let console_layer = console_subscriber::spawn();
let registry = tracing_subscriber::registry()
.with(fmt_layer)
.with(granual_filtered_env()?)
.with(tracing_subscriber::filter::LevelFilter::from_level(Level::INFO))
.with(MetricsLayer::new(meter_provider.clone()))
.with(OpenTelemetryLayer::new(tracer));
tracing_subscriber::registry()
.with(console_layer)
.with(fmt_layer)
.with(granual_filtered_env()?)
.with(tracing_subscriber::filter::LevelFilter::from_level(Level::INFO))
.with(MetricsLayer::new(meter_provider))
.with(OpenTelemetryLayer::new(tracer))
.try_init()
.map_err(|e| TracingError::TracingTryInitError(e))?;
} else {
tracing_subscriber::registry()
.with(fmt_layer)
.with(granual_filtered_env()?)
.with(tracing_subscriber::filter::LevelFilter::from_level(Level::INFO))
.with(MetricsLayer::new(meter_provider))
.with(OpenTelemetryLayer::new(tracer))
.try_init()
.map_err(|e| TracingError::TracingTryInitError(e))?;
}}
registry.try_init().map_err(TracingError::TracingTryInitError)?;
Ok(())
global::set_tracer_provider(tracer_provider.clone());
global::set_meter_provider(meter_provider.clone());
info!("Tracing initialized with service name: {}", service_name);
Ok(TracerProviderGuard(Some(tracer_provider)))
}
fn resource(service_name: String) -> Resource {
fn build_resource(service_name: &str) -> Resource {
Resource::builder()
.with_service_name(service_name)
.with_service_name(service_name.to_string())
.with_schema_url(
[
KeyValue::new(SERVICE_VERSION, env!("CARGO_PKG_VERSION")),
@@ -118,14 +115,15 @@ fn resource(service_name: String) -> Resource {
.build()
}
fn init_tracer_provider(metadata: MetadataMap, service_name: String) -> Result<SdkTracerProvider, TracingError> {
let endpoint = std::env::var("SIGNOZ_ENDPOINT".to_string()).expect("SIGNOZ_ENDPOINT not set");
info!("SIGNOZ_ENDPOINT = {}", endpoint);
fn init_tracer_provider(
endpoint: &str,
metadata: MetadataMap,
resource: Resource,
) -> Result<SdkTracerProvider, TracingError> {
let mut exporter_builder = opentelemetry_otlp::SpanExporter::builder()
.with_tonic()
.with_metadata(metadata)
.with_endpoint(&endpoint);
.with_endpoint(endpoint);
if endpoint.starts_with("https://") {
exporter_builder =
@@ -139,7 +137,7 @@ fn init_tracer_provider(metadata: MetadataMap, service_name: String) -> Result<S
1.0,
))))
.with_id_generator(Compact13BytesIdGenerator)
.with_resource(resource(service_name))
.with_resource(resource)
.with_batch_exporter(exporter)
.build();
@@ -147,13 +145,15 @@ fn init_tracer_provider(metadata: MetadataMap, service_name: String) -> Result<S
Ok(tracer)
}
fn init_meter_provider(metadata: MetadataMap, service_name: String) -> Result<SdkMeterProvider, TracingError> {
let endpoint = std::env::var("SIGNOZ_ENDPOINT".to_string()).expect("SIGNOZ_ENDPOINT not set");
fn init_meter_provider(
endpoint: &str,
metadata: MetadataMap,
resource: Resource,
) -> Result<SdkMeterProvider, TracingError> {
let mut exporter_builder = opentelemetry_otlp::MetricExporter::builder()
.with_tonic()
.with_metadata(metadata)
.with_endpoint(&endpoint)
.with_endpoint(endpoint)
.with_temporality(opentelemetry_sdk::metrics::Temporality::default());
if endpoint.starts_with("https://") {
@@ -170,7 +170,7 @@ fn init_meter_provider(metadata: MetadataMap, service_name: String) -> Result<Sd
PeriodicReader::builder(opentelemetry_stdout::MetricExporter::default()).build();
let meter_provider = MeterProviderBuilder::default()
.with_resource(resource(service_name))
.with_resource(resource)
.with_reader(reader)
.with_reader(stdout_reader)
.build();
@@ -179,3 +179,130 @@ fn init_meter_provider(metadata: MetadataMap, service_name: String) -> Result<Sd
Ok(meter_provider)
}
// pub fn setup_tracing_logger(service_name: String) -> Result<(), TracingError> {
// if tracing::dispatcher::has_been_set() {
// // It shouldn't be - this is really checking that it is torn down between async command executions
// return Err(TracingError::TracingLoggerAlreadyInitialised);
// }
// let key =
// std::env::var("SIGNOZ_INGESTION_KEY".to_string()).expect("SIGNOZ_INGESTION_KEY not set");
// let mut metadata = MetadataMap::new();
// metadata.insert(
// "signoz-ingestion-key",
// key.parse().expect("Could not parse signoz ingestion key"),
// );
// let tracer_provider = init_tracer_provider(metadata.clone(), service_name.clone())?;
// let meter_provider = init_meter_provider(metadata.clone(), service_name.clone())?;
// let tracer = tracer_provider.tracer("tracing-otel-subscriber");
// let fmt_layer = fmt::layer()
// .json()
// .with_writer(std::io::stderr)
// .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
// .with_span_list(false)
// .with_current_span(true)
// .event_format(trace_id_format::TraceIdFormat);
// cfg_if::cfg_if! {if #[cfg(feature = "tokio-console")] {
// // instrument tokio console subscriber needs RUSTFLAGS="--cfg tokio_unstable" at build time
// let console_layer = console_subscriber::spawn();
// tracing_subscriber::registry()
// .with(console_layer)
// .with(fmt_layer)
// .with(granual_filtered_env()?)
// .with(tracing_subscriber::filter::LevelFilter::from_level(Level::INFO))
// .with(MetricsLayer::new(meter_provider))
// .with(OpenTelemetryLayer::new(tracer))
// .try_init()
// .map_err(|e| TracingError::TracingTryInitError(e))?;
// } else {
// tracing_subscriber::registry()
// .with(fmt_layer)
// .with(granual_filtered_env()?)
// .with(tracing_subscriber::filter::LevelFilter::from_level(Level::INFO))
// .with(MetricsLayer::new(meter_provider))
// .with(OpenTelemetryLayer::new(tracer))
// .try_init()
// .map_err(|e| TracingError::TracingTryInitError(e))?;
// }}
// Ok(())
// }
// fn resource(service_name: String) -> Resource {
// Resource::builder()
// .with_service_name(service_name)
// .with_schema_url(
// [
// KeyValue::new(SERVICE_VERSION, env!("CARGO_PKG_VERSION")),
// KeyValue::new(DEPLOYMENT_ENVIRONMENT_NAME, "develop"),
// ],
// SCHEMA_URL,
// )
// .build()
// }
// fn init_tracer_provider(metadata: MetadataMap, service_name: String) -> Result<SdkTracerProvider, TracingError> {
// let endpoint = std::env::var("SIGNOZ_ENDPOINT".to_string()).expect("SIGNOZ_ENDPOINT not set");
// info!("SIGNOZ_ENDPOINT = {}", endpoint);
// let mut exporter_builder = opentelemetry_otlp::SpanExporter::builder()
// .with_tonic()
// .with_metadata(metadata)
// .with_endpoint(&endpoint);
// if endpoint.starts_with("https://") {
// exporter_builder =
// exporter_builder.with_tls_config(ClientTlsConfig::new().with_enabled_roots());
// }
// let exporter = exporter_builder.build()?;
// let tracer = SdkTracerProvider::builder()
// .with_sampler(Sampler::ParentBased(Box::new(Sampler::TraceIdRatioBased(
// 1.0,
// ))))
// .with_id_generator(Compact13BytesIdGenerator)
// .with_resource(resource(service_name))
// .with_batch_exporter(exporter)
// .build();
// global::set_tracer_provider(tracer.clone());
// Ok(tracer)
// }
// fn init_meter_provider(metadata: MetadataMap, service_name: String) -> Result<SdkMeterProvider, TracingError> {
// let endpoint = std::env::var("SIGNOZ_ENDPOINT".to_string()).expect("SIGNOZ_ENDPOINT not set");
// let mut exporter_builder = opentelemetry_otlp::MetricExporter::builder()
// .with_tonic()
// .with_metadata(metadata)
// .with_endpoint(&endpoint)
// .with_temporality(opentelemetry_sdk::metrics::Temporality::default());
// if endpoint.starts_with("https://") {
// exporter_builder = exporter_builder.with_tls_config(ClientTlsConfig::new().with_enabled_roots());
// }
// let exporter = exporter_builder.build()?;
// let reader = PeriodicReader::builder(exporter)
// .with_interval(std::time::Duration::from_secs(30))
// .build();
// let stdout_reader =
// PeriodicReader::builder(opentelemetry_stdout::MetricExporter::default()).build();
// let meter_provider = MeterProviderBuilder::default()
// .with_resource(resource(service_name))
// .with_reader(reader)
// .with_reader(stdout_reader)
// .build();
// global::set_meter_provider(meter_provider.clone());
// Ok(meter_provider)
// }
+2
View File
@@ -36,6 +36,7 @@ nym-credentials-interface = { path = "../credentials-interface" }
opentelemetry = { workspace = true, features = ["trace"], optional = true }
opentelemetry_sdk = { workspace = true, optional = true }
tracing-opentelemetry = { workspace = true, optional = true }
tracing = { workspace = true, features = ["std", "attributes", "tracing-attributes"] }
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio]
@@ -62,4 +63,5 @@ otel = [
"nym-bin-common/otel",
"opentelemetry",
"opentelemetry_sdk",
"tracing-opentelemetry",
]
@@ -164,11 +164,18 @@ impl ClientControlRequest {
#[cfg(feature = "otel")]
let context_carrier = {
let otel_context = opentelemetry::Context::current();
use nym_bin_common::opentelemetry::context::extract_trace_id_from_tracing_cx;
let trace_id = extract_trace_id_from_tracing_cx();
tracing::info!("[DEBUG] Trace id in new_authenticate_v2: {:?}", trace_id);
use tracing_opentelemetry::OpenTelemetrySpanExt;
let current_span = tracing::Span::current();
let otel_context = current_span.context();
ContextCarrier::new_with_current_context(otel_context).into_map()
};
#[cfg(not(feature = "otel"))]
let context_carrier = None;
let context_carrier: HashMap<String, String> = HashMap::new();
Ok(ClientControlRequest::AuthenticateV2(Box::new(
AuthenticateRequest::new(
@@ -152,7 +152,7 @@ pub(crate) struct AuthenticatedHandler<R, S> {
is_active_request_receiver: IsActiveRequestReceiver,
is_active_ping_pending_reply: Option<(u64, IsActiveResultSender)>,
#[cfg(feature = "otel")]
otel_propagator: Option<ManualContextPropagator>,
pub otel_propagator: Option<ManualContextPropagator>,
}
// explicitly remove handle from the global store upon being dropped
@@ -337,6 +337,7 @@ impl<R, S> AuthenticatedHandler<R, S> {
let remaining_bandwidth = self
.bandwidth_storage_manager
.try_use_bandwidth(required_bandwidth)
.in_current_span()
.await?;
self.forward_packet(mix_packet);
@@ -374,7 +375,7 @@ impl<R, S> AuthenticatedHandler<R, S> {
// currently only a single type exists
BinaryRequest::ForwardSphinx { packet }
| BinaryRequest::ForwardSphinxV2 { packet } => {
self.handle_forward_sphinx(packet).await.into_ws_message()
self.handle_forward_sphinx(packet).in_current_span().await.into_ws_message()
}
_ => RequestHandlingError::UnknownBinaryRequest.into_error_message(),
},
@@ -391,6 +392,7 @@ impl<R, S> AuthenticatedHandler<R, S> {
.shared_state()
.storage()
.handle_forget_me(self.client.address)
.in_current_span()
.await?;
}
Ok(SensitiveServerResponse::ForgetMeAck {}.encrypt(&self.client.shared_keys)?)
@@ -451,9 +453,9 @@ impl<R, S> AuthenticatedHandler<R, S> {
hkdf_salt,
derived_key_digest,
} => self.handle_key_upgrade(hkdf_salt, derived_key_digest).await,
ClientRequest::ForgetMe { client, stats } => self.handle_forget_me(client, stats).await,
ClientRequest::ForgetMe { client, stats } => self.handle_forget_me(client, stats).in_current_span().await,
ClientRequest::RememberMe { session_type } => {
self.handle_remember_me(session_type).await
self.handle_remember_me(session_type).in_current_span().await
}
_ => Err(RequestHandlingError::UnknownEncryptedTextRequest),
}
@@ -486,10 +488,10 @@ impl<R, S> AuthenticatedHandler<R, S> {
match request {
ClientControlRequest::EncryptedRequest { ciphertext, nonce } => {
self.handle_encrypted_text_request(ciphertext, nonce).await
self.handle_encrypted_text_request(ciphertext, nonce).in_current_span().await
}
ClientControlRequest::EcashCredential { enc_credential, iv } => {
self.handle_ecash_bandwidth(enc_credential, iv).await
self.handle_ecash_bandwidth(enc_credential, iv).in_current_span().await
}
ClientControlRequest::BandwidthCredential { .. } => {
Err(RequestHandlingError::IllegalRequest {
@@ -578,10 +580,10 @@ impl<R, S> AuthenticatedHandler<R, S> {
// them and let's test that claim. If that's not the case, just copy code from
// desktop nym-client websocket as I've manually handled everything there
match raw_request {
Message::Binary(bin_msg) => Some(self.handle_binary(bin_msg).await),
Message::Text(text_msg) => Some(self.handle_text(text_msg).await),
Message::Binary(bin_msg) => Some(self.handle_binary(bin_msg).in_current_span().await),
Message::Text(text_msg) => Some(self.handle_text(text_msg).in_current_span().await),
Message::Pong(msg) => {
self.handle_pong(msg).await;
self.handle_pong(msg).in_current_span().await;
None
}
_ => None,
@@ -675,7 +677,7 @@ impl<R, S> AuthenticatedHandler<R, S> {
ping_timeout = None.into();
self.handle_ping_timeout().await;
},
socket_msg = self.inner.read_websocket_message() => {
socket_msg = self.inner.read_websocket_message().in_current_span() => {
#[cfg(feature = "otel")]
let span = {
let span = match &self.otel_propagator {
@@ -700,7 +702,7 @@ impl<R, S> AuthenticatedHandler<R, S> {
break;
}
if let Some(response) = self.handle_request(socket_msg).await {
if let Some(response) = self.handle_request(socket_msg).in_current_span().await {
if let Err(err) = self.inner.send_websocket_message(response).await {
debug!(
"Failed to send message over websocket: {err}. Assuming the connection is dead.",
@@ -709,7 +711,7 @@ impl<R, S> AuthenticatedHandler<R, S> {
}
}
},
mix_messages = self.mix_receiver.next() => {
mix_messages = self.mix_receiver.next().in_current_span() => {
#[cfg(feature = "otel")]
let span = {
let span = match &self.otel_propagator {
@@ -47,7 +47,7 @@ use tokio::time::timeout;
use tokio_tungstenite::tungstenite::{protocol::Message, Error as WsError};
#[cfg(feature = "otel")]
use tracing::info_span;
use tracing::{debug, error, info, instrument, warn};
use tracing::{debug, error, info, instrument, Instrument, warn};
@@ -171,6 +171,7 @@ impl<R, S> FreshHandler<R, S> {
/// Attempts to perform websocket handshake with the remote and upgrades the raw TCP socket
/// to the framed WebSocket.
#[instrument(skip_all)]
pub(crate) async fn perform_websocket_handshake(&mut self) -> Result<(), WsError>
where
S: AsyncRead + AsyncWrite + Unpin,
@@ -180,7 +181,7 @@ impl<R, S> FreshHandler<R, S> {
SocketStream::RawTcp(conn) => {
// TODO: perhaps in the future, rather than panic here (and uncleanly shut tcp stream)
// return a result with an error?
let ws_stream = Box::new(tokio_tungstenite::accept_async(conn).await?);
let ws_stream = Box::new(tokio_tungstenite::accept_async(conn).in_current_span().await?);
SocketStream::UpgradedWebSocket(ws_stream)
}
other => other,
@@ -194,6 +195,7 @@ impl<R, S> FreshHandler<R, S> {
/// # Arguments
///
/// * `init_msg`: a client handshake init message which should contain its identity public key as well as an ephemeral key.
#[instrument(skip_all)]
async fn perform_registration_handshake(
&mut self,
init_msg: Vec<u8>,
@@ -212,6 +214,7 @@ impl<R, S> FreshHandler<R, S> {
init_msg,
self.shutdown.clone(),
)
.in_current_span()
.await
}
_ => unreachable!(),
@@ -225,7 +228,7 @@ impl<R, S> FreshHandler<R, S> {
S: AsyncRead + AsyncWrite + Unpin,
{
match self.socket_connection {
SocketStream::UpgradedWebSocket(ref mut ws_stream) => ws_stream.next().await,
SocketStream::UpgradedWebSocket(ref mut ws_stream) => ws_stream.next().in_current_span().await,
_ => panic!("impossible state - websocket handshake was somehow reverted"),
}
}
@@ -247,7 +250,7 @@ impl<R, S> FreshHandler<R, S> {
// TODO: more closely investigate difference between `Sink::send` and `Sink::send_all`
// it got something to do with batching and flushing - it might be important if it
// turns out somehow we've got a bottleneck here
SocketStream::UpgradedWebSocket(ref mut ws_stream) => ws_stream.send(msg.into()).await,
SocketStream::UpgradedWebSocket(ref mut ws_stream) => ws_stream.send(msg.into()).in_current_span().await,
_ => panic!("impossible state - websocket handshake was somehow reverted"),
}
}
@@ -261,6 +264,7 @@ impl<R, S> FreshHandler<R, S> {
S: AsyncRead + AsyncWrite + Unpin + Send,
{
self.send_websocket_message(ServerResponse::new_error(err.to_string()))
.in_current_span()
.await
}
@@ -713,18 +717,20 @@ impl<R, S> FreshHandler<R, S> {
self.shared_state
.storage
.update_last_used_authentication_timestamp(client_id, session_request_start)
.in_current_span()
.await?;
// push any old stored messages to the client
// (this will be removed soon)
self.push_stored_messages_to_client(address, &shared_key.key)
.in_current_span()
.await?;
// finally check and retrieve client's bandwidth
let available_bandwidth = self.get_registered_available_bandwidth(client_id).await?;
let bandwidth_remaining = if available_bandwidth.expired() {
self.shared_state.storage.reset_bandwidth(client_id).await?;
self.shared_state.storage.reset_bandwidth(client_id).in_current_span().await?;
0
} else {
available_bandwidth.bytes
@@ -826,8 +832,8 @@ impl<R, S> FreshHandler<R, S> {
return Err(InitialAuthenticationError::DuplicateConnection);
}
let shared_keys = self.perform_registration_handshake(init_data).await?;
let client_id = self.register_client(remote_address, &shared_keys).await?;
let shared_keys = self.perform_registration_handshake(init_data).in_current_span().await?;
let client_id = self.register_client(remote_address, &shared_keys).in_current_span().await?;
debug!(client_id = %client_id, "managed to finalize client registration");
@@ -877,15 +883,11 @@ impl<R, S> FreshHandler<R, S> {
S: AsyncRead + AsyncWrite + Unpin + Send,
R: CryptoRng + RngCore + Send,
{
#[cfg(not(feature = "otel"))]
info!("[DEBUG] received initial client request no otel");
#[cfg(feature = "otel")]
info!("[DEBUG] received initial client request with otel");
// extract and set up opentelemetry context if provided
#[cfg(feature = "otel")]
let (context_propagator, otel_ctx) = if let ClientControlRequest::AuthenticateV2(ref auth_req) = request {
if let Some(otel_context) = &auth_req.otel_context {
warn!("OpenTelemetry context provided in the request: {otel_context:?}");
warn!("=== OpenTelemetry context provided in the request: {otel_context:?} ===");
(Some(ManualContextPropagator::new("handling_initial_client_request_with_otel", otel_context.clone())), Some(otel_context.clone()))
} else {
warn!("No OpenTelemetry context provided in the request");
@@ -915,18 +917,19 @@ impl<R, S> FreshHandler<R, S> {
otel_context: _,
} => {
self.handle_legacy_authenticate(protocol_version, address, enc_address, iv)
.in_current_span()
.await
}
#[cfg(feature = "otel")]
ClientControlRequest::AuthenticateV2(req) => self.handle_authenticate_v2(req, otel_ctx).await,
ClientControlRequest::AuthenticateV2(req) => self.handle_authenticate_v2(req, otel_ctx).in_current_span().await,
#[cfg(not(feature = "otel"))]
ClientControlRequest::AuthenticateV2(req) => self.handle_authenticate_v2(req).await,
ClientControlRequest::AuthenticateV2(req) => self.handle_authenticate_v2(req).in_current_span().await,
ClientControlRequest::RegisterHandshakeInitRequest {
protocol_version,
data,
} => self.handle_register(protocol_version, data).await,
} => self.handle_register(protocol_version, data).in_current_span().await,
ClientControlRequest::SupportedProtocol { .. } => {
self.handle_reply_supported_protocol_request().await;
self.handle_reply_supported_protocol_request().in_current_span().await;
return Ok(None);
}
_ => {
@@ -944,7 +947,7 @@ impl<R, S> FreshHandler<R, S> {
}
other => debug!("authentication failure: {other}"),
}
self.send_and_forget_error_response(&err).await;
self.send_and_forget_error_response(&err).in_current_span().await;
return Err(err);
}
};
@@ -979,21 +982,21 @@ impl<R, S> FreshHandler<R, S> {
R: CryptoRng + RngCore + Send,
{
loop {
let req = self.wait_for_initial_message().await;
let req = self.wait_for_initial_message().in_current_span().await;
let initial_request = match req {
Ok(req) => req,
Err(err) => {
self.send_and_forget_error_response(err).await;
self.send_and_forget_error_response(err).in_current_span().await;
return None;
}
};
// see if we managed to register the client through this request
let maybe_auth_res = match self.handle_initial_client_request(initial_request).await {
let maybe_auth_res = match self.handle_initial_client_request(initial_request).in_current_span().await {
Ok(maybe_auth_res) => maybe_auth_res,
Err(err) => {
debug!("initial client request handling error: {err}");
self.send_and_forget_error_response(err).await;
self.send_and_forget_error_response(err).in_current_span().await;
return None;
}
};
@@ -1015,6 +1018,7 @@ impl<R, S> FreshHandler<R, S> {
mix_receiver,
is_active_request_receiver,
)
.in_current_span()
.await
.inspect_err(|err| error!("failed to upgrade client handler: {err}"))
.ok();
@@ -1030,7 +1034,7 @@ impl<R, S> FreshHandler<R, S> {
where
S: AsyncRead + AsyncWrite + Unpin + Send,
{
let msg = match timeout(INITIAL_MESSAGE_TIMEOUT, self.read_websocket_message()).await {
let msg = match timeout(INITIAL_MESSAGE_TIMEOUT, self.read_websocket_message()).in_current_span().await {
Ok(Some(Ok(msg))) => msg,
Ok(Some(Err(source))) => {
debug!("failed to obtain message from websocket stream! stopping connection handler: {source}");
@@ -1086,7 +1090,7 @@ impl<R, S> FreshHandler<R, S> {
_ = shutdown.cancelled() => {
tracing::trace!("received cancellation")
}
_ = super::handle_connection(self) => {
_ = super::handle_connection(self).instrument(tracing::debug_span!("connection_handler", remote = %remote)) => {
tracing::debug!("finished connection handler for {remote}")
}
}
@@ -13,7 +13,7 @@ use std::time::Duration;
use time::OffsetDateTime;
use tokio::io::{AsyncRead, AsyncWrite};
use tokio_tungstenite::WebSocketStream;
use tracing::{debug, instrument, trace, warn};
use tracing::{debug, instrument, Instrument, trace, warn};
pub(crate) use self::authenticated::AuthenticatedHandler;
pub(crate) use self::fresh::FreshHandler;
@@ -108,7 +108,7 @@ where
{
match tokio::time::timeout(
WEBSOCKET_HANDSHAKE_TIMEOUT,
handle.perform_websocket_handshake(),
handle.perform_websocket_handshake().in_current_span(),
)
.await
{
@@ -125,8 +125,24 @@ where
trace!("managed to perform websocket handshake!");
if let Some(auth_handle) = handle.handle_until_authenticated_or_failure().await {
auth_handle.listen_for_requests().await
if let Some(auth_handle) = handle.handle_until_authenticated_or_failure().in_current_span().await {
#[cfg(feature = "otel")]
{
let from_client_span = {
let parent = match auth_handle.otel_propagator.as_ref() {
Some(propagator) => propagator.root_span(),
None => &tracing::Span::current(), // fallback to current span if no propagator
};
tracing::info_span!(parent: parent, "listening for requests")
};
auth_handle.listen_for_requests()
.instrument(from_client_span)
.await
}
#[cfg(not(feature = "otel"))]
{
auth_handle.listen_for_requests().await;
}
}
trace!("the handler is done!");
@@ -92,7 +92,7 @@ impl Listener {
let metrics_ref = handle.shared_state.metrics.clone();
// 4.1. handle all client requests until connection gets terminated
handle.start_handling().await;
handle.start_handling().in_current_span().await;
// 4.2. decrement the connection counter
metrics_ref.network.disconnected_ingress_websocket_client();
@@ -125,7 +125,7 @@ impl Listener {
trace!("client_handling::Listener: received shutdown");
break
}
connection = tcp_listener.accept() => {
connection = tcp_listener.accept().in_current_span() => {
self.try_handle_accepted_connection(connection)
}
}
+2 -2
View File
@@ -8,7 +8,7 @@ use crate::node::mixnet::packet_forwarding::global::is_global_ip;
use crate::node::NymNode;
use std::fs;
use std::net::IpAddr;
use tracing::{debug, info, instrument, trace, warn};
use tracing::{debug, info, instrument, Instrument, trace, warn};
mod args;
@@ -125,5 +125,5 @@ pub(crate) async fn execute(mut args: Args) -> Result<(), NymNodeError> {
return Ok(());
}
nym_node.run().await
nym_node.run().in_current_span().await
}
+83 -26
View File
@@ -17,7 +17,9 @@ use nym_bin_common::logging::error::TracingError;
#[cfg(feature = "otel")]
use nym_bin_common::opentelemetry::setup_tracing_logger;
#[cfg(feature = "otel")]
use opentelemetry::{Context, global, trace::{TraceContextExt, Tracer}};
use opentelemetry::{global, trace::{TraceContextExt, Tracer}};
#[cfg(feature = "otel")]
use tracing::Instrument;
use std::future::Future;
use std::sync::OnceLock;
use tracing::instrument;
@@ -92,48 +94,103 @@ impl Cli {
// SigNoz/OTEL run in async context
Commands::BondingInformation(args) => Self::execute_async(async move {
#[cfg(feature = "otel")]
setup_tracing_logger("nym-node".to_string())
.map_err(TracingError::from)?;
{
let _guard = setup_tracing_logger("nym-node".to_string())
.map_err(TracingError::from)?;
let main_span = tracing::info_span!("startup", service = "nym-node");
async {
bonding_information::execute(args).in_current_span().await?;
Ok::<(), anyhow::Error>(())
}
.instrument(main_span)
.await
}
#[cfg(not(feature = "otel"))]
setup_no_otel_logger().expect("failed to initialize logging");
bonding_information::execute(args).await?;
Ok::<(), anyhow::Error>(())
{
setup_no_otel_logger().expect("failed to initialize logging");
bonding_information::execute(args).await?;
Ok::<(), anyhow::Error>(())
}
})??,
Commands::NodeDetails(args) => Self::execute_async(async move {
#[cfg(feature = "otel")]
setup_tracing_logger("nym-node".to_string())
.map_err(TracingError::from)?;
{
let _guard = setup_tracing_logger("nym-node".to_string())
.map_err(TracingError::from)?;
let main_span = tracing::info_span!("startup", service = "nym-node");
async {
node_details::execute(args).in_current_span().await?;
Ok::<(), anyhow::Error>(())
}
.instrument(main_span)
.await
}
#[cfg(not(feature = "otel"))]
setup_no_otel_logger().expect("failed to initialize logging");
node_details::execute(args).await?;
Ok::<(), anyhow::Error>(())
{
setup_no_otel_logger().expect("failed to initialize logging");
node_details::execute(args).await?;
Ok::<(), anyhow::Error>(())
}
})??,
Commands::Run(args) => Self::execute_async(async move {
#[cfg(feature = "otel")]
setup_tracing_logger("nym-node".to_string())
.map_err(TracingError::from)?;
{
let _guard = setup_tracing_logger("nym-node".to_string())
.map_err(TracingError::from)?;
let main_span = tracing::info_span!("startup", service = "nym-node");
async {
run::execute(*args).in_current_span().await?;
Ok::<(), anyhow::Error>(())
}
.instrument(main_span)
.await
}
#[cfg(not(feature = "otel"))]
setup_no_otel_logger().expect("failed to initialize logging");
run::execute(*args).await?;
Ok::<(), anyhow::Error>(())
{
setup_no_otel_logger().expect("failed to initialize logging");
run::execute(*args).await?;
Ok::<(), anyhow::Error>(())
}
})??,
Commands::Sign(args) => Self::execute_async(async move {
#[cfg(feature = "otel")]
setup_tracing_logger("nym-node".to_string())
.map_err(TracingError::from)?;
{
let _guard = setup_tracing_logger("nym-node".to_string())
.map_err(TracingError::from)?;
let main_span = tracing::info_span!("startup", service = "nym-node");
async {
sign::execute(args).in_current_span().in_current_span().await?;
Ok::<(), anyhow::Error>(())
}
.instrument(main_span)
.await
}
#[cfg(not(feature = "otel"))]
setup_no_otel_logger().expect("failed to initialize logging");
sign::execute(args).await?;
Ok::<(), anyhow::Error>(())
{
setup_no_otel_logger().expect("failed to initialize logging");
sign::execute(args).await?;
Ok::<(), anyhow::Error>(())
}
})??,
Commands::UnsafeResetSphinxKeys(args) => Self::execute_async(async move {
#[cfg(feature = "otel")]
setup_tracing_logger("nym-node".to_string())
.map_err(TracingError::from)?;
{
let _guard = setup_tracing_logger("nym-node".to_string())
.map_err(TracingError::from)?;
let main_span = tracing::info_span!("startup", service = "nym-node");
async {
reset_sphinx_keys::execute(args).in_current_span().await?;
Ok::<(), anyhow::Error>(())
}
.instrument(main_span)
.await
}
#[cfg(not(feature = "otel"))]
setup_no_otel_logger().expect("failed to initialize logging");
reset_sphinx_keys::execute(args).await?;
Ok::<(), anyhow::Error>(())
{
setup_no_otel_logger().expect("failed to initialize logging");
reset_sphinx_keys::execute(args).await?;
Ok::<(), anyhow::Error>(())
}
})??,
}
Ok(())
+6 -3
View File
@@ -20,7 +20,7 @@ use std::net::SocketAddr;
use tokio::net::TcpStream;
use tokio::time::Instant;
use tokio_util::codec::Framed;
use tracing::{debug, error, instrument, trace, warn};
use tracing::{debug, error, instrument, trace, warn, Instrument};
struct PendingReplayCheckPackets {
// map of rotation id used for packet creation to the packets
@@ -446,6 +446,7 @@ impl ConnectionHandler {
// if it's a sphinx packet attempt to do pre-processing and replay detection
if packet.is_sphinx() && !self.shared.replay_protection_filter.disabled() {
self.handle_received_packet_with_replay_detection(now, packet)
.in_current_span()
.await;
} else {
// otherwise just skip that whole procedure and go straight to payload unwrapping
@@ -463,7 +464,7 @@ impl ConnectionHandler {
)
)]
pub(crate) async fn handle_connection(&mut self, socket: TcpStream) {
let noise_stream = match upgrade_noise_responder(socket, &self.shared.noise_config).await {
let noise_stream = match upgrade_noise_responder(socket, &self.shared.noise_config).in_current_span().await {
Ok(noise_stream) => noise_stream,
Err(err) => {
error!(
@@ -478,9 +479,11 @@ impl ConnectionHandler {
self.remote_address
);
self.handle_stream(Framed::new(noise_stream, NymCodec))
.in_current_span()
.await
}
#[instrument(skip_all)]
pub(crate) async fn handle_stream(
&mut self,
mut mixnet_connection: Framed<Connection<TcpStream>, NymCodec>,
@@ -494,7 +497,7 @@ impl ConnectionHandler {
}
maybe_framed_nym_packet = mixnet_connection.next() => {
match maybe_framed_nym_packet {
Some(Ok(packet)) => self.handle_received_nym_packet(packet).await,
Some(Ok(packet)) => self.handle_received_nym_packet(packet).in_current_span().await,
Some(Err(err)) => {
debug!("connection got corrupted with: {err}");
return
+3 -3
View File
@@ -4,7 +4,7 @@
use crate::node::mixnet::SharedData;
use nym_task::ShutdownToken;
use std::net::SocketAddr;
use tracing::{debug, error, info, trace};
use tracing::{debug, error, info, instrument, Instrument, trace};
pub(crate) struct Listener {
bind_address: SocketAddr,
@@ -18,7 +18,7 @@ impl Listener {
shared_data,
}
}
#[instrument(skip_all, level = "debug")]
pub(crate) async fn run(&mut self, shutdown: ShutdownToken) {
info!("attempting to run mixnet listener on {}", self.bind_address);
@@ -38,7 +38,7 @@ impl Listener {
trace!("mixnet listener: received shutdown");
break
}
connection = tcp_listener.accept() => {
connection = tcp_listener.accept().in_current_span() => {
self.shared_data.try_handle_connection(connection);
}
}
+3 -2
View File
@@ -23,7 +23,7 @@ use std::time::Duration;
use tokio::net::TcpStream;
use tokio::task::JoinHandle;
use tokio::time::Instant;
use tracing::{debug, error};
use tracing::{debug, error, instrument, Instrument};
pub(crate) mod final_hop;
@@ -164,6 +164,7 @@ impl SharedData {
}
}
#[instrument(skip_all)]
pub(super) fn try_handle_connection(
&self,
accepted: io::Result<(TcpStream, SocketAddr)>,
@@ -173,7 +174,7 @@ impl SharedData {
debug!("accepted incoming mixnet connection from: {remote_addr}");
let mut handler = ConnectionHandler::new(self, remote_addr);
let join_handle =
tokio::spawn(async move { handler.handle_connection(socket).await });
tokio::spawn(async move { handler.handle_connection(socket).in_current_span().await });
self.log_connected_clients();
Some(join_handle)
}
+10 -5
View File
@@ -66,7 +66,7 @@ use std::ops::Deref;
use std::path::Path;
use std::sync::Arc;
use tokio::sync::mpsc;
use tracing::{debug, info, instrument, trace};
use tracing::{debug, info, instrument, Instrument, trace};
use zeroize::Zeroizing;
pub mod bonding_information;
@@ -638,7 +638,7 @@ impl NymNode {
.build_websocket_listener(active_clients_store.clone())
.await?;
self.shutdown_tracker()
.try_spawn_named(async move { websocket.run().await }, "EntryWebsocket");
.try_spawn_named(async move { websocket.run().in_current_span().await }, "EntryWebsocket");
} else {
info!("node not running in entry mode: the websocket will remain closed");
}
@@ -681,7 +681,9 @@ impl NymNode {
let authenticator = gateway_tasks_builder
.build_wireguard_authenticator(topology_provider)
.await?;
let started_authenticator = authenticator.start_service_provider().await?;
let started_authenticator = authenticator.start_service_provider()
.in_current_span()
.await?;
active_clients_store.insert_embedded(started_authenticator.handle);
info!(
@@ -691,6 +693,7 @@ impl NymNode {
gateway_tasks_builder
.try_start_wireguard()
.in_current_span()
.await
.map_err(NymNodeError::GatewayTasksStartupFailure)?;
} else {
@@ -1119,7 +1122,7 @@ impl NymNode {
let shutdown_token = self.shutdown_token();
self.shutdown_tracker().try_spawn_named(
async move { mixnet_listener.run(shutdown_token).await },
async move { mixnet_listener.run(shutdown_token).in_current_span().await },
"MixnetListener",
);
@@ -1159,7 +1162,7 @@ impl NymNode {
);
debug!("config: {:#?}", self.config);
let http_server = self.build_http_server().await?;
let http_server = self.build_http_server().in_current_span().await?;
let bind_address = self.config.http.bind_address;
let server_shutdown = self.shutdown_manager.clone_shutdown_token();
@@ -1198,6 +1201,7 @@ impl NymNode {
network_refresher.routing_filter(),
noise_config,
)
.in_current_span()
.await?;
let metrics_sender = self.setup_metrics_backend(
@@ -1211,6 +1215,7 @@ impl NymNode {
active_clients_store,
mix_packet_sender,
)
.in_current_span()
.await?;
self.setup_key_rotation(nym_apis_client, bloomfilters_manager)
+223 -68
View File
@@ -6,34 +6,106 @@ use nym_sdk::DebugConfig;
use opentelemetry::trace::{TraceContextExt, Tracer};
#[cfg(feature = "otel")]
use opentelemetry::{global, Context};
#[cfg(feature = "otel")]
use tracing_opentelemetry::OpenTelemetrySpanExt;
use tracing::warn;
use tracing::instrument;
#[cfg(feature = "otel")]
use tracing::Instrument;
#[tokio::main]
#[instrument(name = "sdk-example-surb-reply", skip_all)]
async fn main() {
// Setup OpenTelemetry tracing
#[cfg(feature = "otel")]
let _guard = {
nym_bin_common::opentelemetry::setup_tracing_logger("sdk-example-surb-reply".to_string()).unwrap();
{
let _guard = nym_bin_common::opentelemetry::setup_tracing_logger("sdk-example-surb-reply".to_string()).unwrap();
let main_span = tracing::info_span!("startup", service = "sdk-example-surb-reply");
async {
let tracing_context = tracing::Span::current();
tracing::info!("Current tracing context: {:?}", tracing_context);
let cx = tracing::Span::current().context();
let sc = cx.span();
let spcx = sc.span_context();
tracing::info!("Current OTEL context: {:?}, trace_id: {:?}", cx, spcx.trace_id());
let tracer = global::tracer("sdk-example-surb-reply");
let span = tracer.start("client-root-span");
let cx = Context::current_with_span(span);
let _guard = cx.clone().attach();
// Ignore performance requirements for the sake of the example
let mut debug_config = DebugConfig::default();
debug_config.cover_traffic.disable_loop_cover_traffic_stream = true;
debug_config
.traffic
.disable_main_poisson_packet_distribution = true;
let trace_id = cx.span().span_context().trace_id();
warn!("Main TRACE_ID: {:?}", trace_id);
debug_config.topology.minimum_mixnode_performance = 0;
debug_config.topology.minimum_gateway_performance = 0;
let context = Context::current();
println!("Current OTEL context: {:?}", context);
_guard
};
// Create a mixnet client which connect to a specific node
let client_builder = MixnetClientBuilder::new_ephemeral();
let mixnet_client = client_builder
.debug_config(debug_config)
.request_gateway("FtR9Mb9y9EViYU3at6Qf7MzNHaMw8gofMicwqoscMBMP".to_string())
.build()
.unwrap();
// Now we connect to the mixnet, using keys now stored in the paths provided.
// let mut client = client.connect_to_mixnet().await.unwrap();
let mut client = mixnet_client.connect_to_mixnet().await.unwrap();
// Be able to get our client address
let our_address = client.nym_address();
println!("\nOur client nym address is: {our_address}");
// Send a message through the mixnet to ourselves using our nym address
client
.send_plain_message(*our_address, "hello there")
.await
.unwrap();
// we're going to parse the sender_tag (AnonymousSenderTag) from the incoming message and use it to 'reply' to ourselves instead of our Nym address.
// we know there will be a sender_tag since the sdk sends SURBs along with messages by default.
println!("Waiting for message\n");
// get the actual message - discard the empty vec sent along with a potential SURB topup request
let mut message: Vec<ReconstructedMessage> = Vec::new();
while let Some(new_message) = client.wait_for_messages().await {
if new_message.is_empty() {
continue;
}
message = new_message;
break;
}
let mut parsed = String::new();
if let Some(r) = message.first() {
parsed = String::from_utf8(r.message.clone()).unwrap();
}
// parse sender_tag: we will use this to reply to sender without needing their Nym address
let return_recipient: AnonymousSenderTag = message[0].sender_tag.unwrap();
println!(
"\nReceived the following message: {parsed} \nfrom sender with surb bucket {return_recipient}"
);
// reply to self with it: note we use `send_str_reply` instead of `send_str`
println!("Replying with using SURBs");
client
.send_reply(return_recipient, "hi an0n!")
.await
.unwrap();
println!("Waiting for message (once you see it, ctrl-c to exit)\n");
client
.on_messages(|msg| println!("\nReceived: {}", String::from_utf8_lossy(&msg.message)))
.await;
}.instrument(main_span).await;
}
// due to the way instrumentation works in async contexts, the totality of the async code we want to trace needs to be under the same block
// This is ugly and unfortunate but cannot think of another way around it right now.
#[cfg(not(feature = "otel"))]
nym_bin_common::logging::setup_no_otel_logger().expect("failed to initialize logging");
// Ignore performance requirements for the sake of the example
{
nym_bin_common::logging::setup_no_otel_logger().expect("failed to initialize logging");
let mut debug_config = DebugConfig::default();
debug_config.cover_traffic.disable_loop_cover_traffic_stream = true;
debug_config
@@ -43,62 +115,145 @@ async fn main() {
debug_config.topology.minimum_mixnode_performance = 0;
debug_config.topology.minimum_gateway_performance = 0;
// Create a mixnet client which connect to a specific node
let client_builder = MixnetClientBuilder::new_ephemeral();
let mixnet_client = client_builder
.debug_config(debug_config)
.request_gateway("FtR9Mb9y9EViYU3at6Qf7MzNHaMw8gofMicwqoscMBMP".to_string())
.build()
.unwrap();
let client_builder = MixnetClientBuilder::new_ephemeral();
let mixnet_client = client_builder
.debug_config(debug_config)
.request_gateway("FtR9Mb9y9EViYU3at6Qf7MzNHaMw8gofMicwqoscMBMP".to_string())
.build()
.unwrap();
// Now we connect to the mixnet, using keys now stored in the paths provided.
// let mut client = client.connect_to_mixnet().await.unwrap();
let mut client = mixnet_client.connect_to_mixnet().await.unwrap();
let mut client = mixnet_client.connect_to_mixnet().await.unwrap();
let our_address = client.nym_address();
println!("\nOur client nym address is: {our_address}");
// Be able to get our client address
let our_address = client.nym_address();
println!("\nOur client nym address is: {our_address}");
client
.send_plain_message(*our_address, "hello there")
.await
.unwrap();
println!("Waiting for message\n");
// Send a message through the mixnet to ourselves using our nym address
client
.send_plain_message(*our_address, "hello there")
.await
.unwrap();
// we're going to parse the sender_tag (AnonymousSenderTag) from the incoming message and use it to 'reply' to ourselves instead of our Nym address.
// we know there will be a sender_tag since the sdk sends SURBs along with messages by default.
println!("Waiting for message\n");
// get the actual message - discard the empty vec sent along with a potential SURB topup request
let mut message: Vec<ReconstructedMessage> = Vec::new();
while let Some(new_message) = client.wait_for_messages().await {
if new_message.is_empty() {
continue;
let mut message: Vec<ReconstructedMessage> = Vec::new();
while let Some(new_message) = client.wait_for_messages().await {
if new_message.is_empty() {
continue;
}
message = new_message;
break;
}
message = new_message;
break;
let mut parsed = String::new();
if let Some(r) = message.first() {
parsed = String::from_utf8(r.message.clone()).unwrap();
}
let return_recipient: AnonymousSenderTag = message[0].sender_tag.unwrap();
println!(
"\nReceived the following message: {parsed} \nfrom sender with surb bucket {return_recipient}"
);
println!("Replying with using SURBs");
client
.send_reply(return_recipient, "hi an0n!")
.await
.unwrap();
println!("Waiting for message (once you see it, ctrl-c to exit)\n");
client
.on_messages(|msg| println!("\nReceived: {}", String::from_utf8_lossy(&msg.message)))
.await;
}
let mut parsed = String::new();
if let Some(r) = message.first() {
parsed = String::from_utf8(r.message.clone()).unwrap();
}
// parse sender_tag: we will use this to reply to sender without needing their Nym address
let return_recipient: AnonymousSenderTag = message[0].sender_tag.unwrap();
println!(
"\nReceived the following message: {parsed} \nfrom sender with surb bucket {return_recipient}"
);
// reply to self with it: note we use `send_str_reply` instead of `send_str`
println!("Replying with using SURBs");
client
.send_reply(return_recipient, "hi an0n!")
.await
.unwrap();
println!("Waiting for message (once you see it, ctrl-c to exit)\n");
client
.on_messages(|msg| println!("\nReceived: {}", String::from_utf8_lossy(&msg.message)))
.await;
}
// #[tokio::main]
// #[instrument(name = "sdk-example-surb-reply", skip_all)]
// async fn main() {
// // Setup OpenTelemetry tracing
// #[cfg(feature = "otel")]
// let _guard = nym_bin_common::opentelemetry::setup_tracing_logger("sdk-example-surb-reply".to_string()).unwrap();
// #[cfg(feature = "otel")]
// let main_span = tracing::info_span!("startup", service = "sdk-example-surb-reply");
// #[cfg(feature = "otel")]
// let _main_span_guard = main_span.enter();
// #[cfg(feature = "otel")]
// let tracing_context = tracing::Span::current();
// #[cfg(feature = "otel")]
// tracing::info!("Current tracing context: {:?}", tracing_context);
// #[cfg(feature = "otel")]
// let otel_context = Context::current();
// #[cfg(feature = "otel")]
// tracing::info!("Current OTEL context: {:?}", otel_context);
// #[cfg(not(feature = "otel"))]
// nym_bin_common::logging::setup_no_otel_logger().expect("failed to initialize logging");
// // Ignore performance requirements for the sake of the example
// let mut debug_config = DebugConfig::default();
// debug_config.cover_traffic.disable_loop_cover_traffic_stream = true;
// debug_config
// .traffic
// .disable_main_poisson_packet_distribution = true;
// debug_config.topology.minimum_mixnode_performance = 0;
// debug_config.topology.minimum_gateway_performance = 0;
// // Create a mixnet client which connect to a specific node
// let client_builder = MixnetClientBuilder::new_ephemeral();
// let mixnet_client = client_builder
// .debug_config(debug_config)
// .request_gateway("FtR9Mb9y9EViYU3at6Qf7MzNHaMw8gofMicwqoscMBMP".to_string())
// .build()
// .unwrap();
// // Now we connect to the mixnet, using keys now stored in the paths provided.
// // let mut client = client.connect_to_mixnet().await.unwrap();
// let mut client = mixnet_client.connect_to_mixnet().await.unwrap();
// // Be able to get our client address
// let our_address = client.nym_address();
// println!("\nOur client nym address is: {our_address}");
// // Send a message through the mixnet to ourselves using our nym address
// client
// .send_plain_message(*our_address, "hello there")
// .await
// .unwrap();
// // we're going to parse the sender_tag (AnonymousSenderTag) from the incoming message and use it to 'reply' to ourselves instead of our Nym address.
// // we know there will be a sender_tag since the sdk sends SURBs along with messages by default.
// println!("Waiting for message\n");
// // get the actual message - discard the empty vec sent along with a potential SURB topup request
// let mut message: Vec<ReconstructedMessage> = Vec::new();
// while let Some(new_message) = client.wait_for_messages().await {
// if new_message.is_empty() {
// continue;
// }
// message = new_message;
// break;
// }
// let mut parsed = String::new();
// if let Some(r) = message.first() {
// parsed = String::from_utf8(r.message.clone()).unwrap();
// }
// // parse sender_tag: we will use this to reply to sender without needing their Nym address
// let return_recipient: AnonymousSenderTag = message[0].sender_tag.unwrap();
// println!(
// "\nReceived the following message: {parsed} \nfrom sender with surb bucket {return_recipient}"
// );
// // reply to self with it: note we use `send_str_reply` instead of `send_str`
// println!("Replying with using SURBs");
// client
// .send_reply(return_recipient, "hi an0n!")
// .await
// .unwrap();
// println!("Waiting for message (once you see it, ctrl-c to exit)\n");
// client
// .on_messages(|msg| println!("\nReceived: {}", String::from_utf8_lossy(&msg.message)))
// .await;
// }
+7 -9
View File
@@ -5,15 +5,13 @@ use crate::mixnet::{AnonymousSenderTag, IncludedSurbs, Recipient};
use crate::Result;
use async_trait::async_trait;
use nym_client_core::client::inbound_messages::InputMessage;
#[cfg(feature = "otel"
)]
use nym_bin_common::opentelemetry::compact_id_generator::compress_trace_id;
#[cfg(feature = "otel")]
use nym_bin_common::opentelemetry::{
compact_id_generator::compress_trace_id,
context::extract_trace_id_from_tracing_cx,
};
use nym_sphinx::params::PacketType;
use nym_task::connections::TransmissionLane;
#[cfg(feature = "otel")]
use opentelemetry::trace::TraceContextExt;
#[cfg(feature = "otel")]
use opentelemetry::Context;
use tracing::instrument;
// defined to guarantee common interface regardless of whether you're using the full client
@@ -83,8 +81,8 @@ pub trait MixnetMessageSender {
// in the 12 bytes format
#[cfg(feature = "otel")]
let trace_id = {
let context = Context::current();
let trace_id = context.span().span_context().trace_id();
let trace_id = extract_trace_id_from_tracing_cx();
tracing::info!("[DEBUG] Trace id in send_message: {:?}", trace_id);
Some(compress_trace_id(&trace_id))
};
#[cfg(not(feature = "otel"))]