diff --git a/implementations/rust/ockam/ockam_abac/src/policy/policies.rs b/implementations/rust/ockam/ockam_abac/src/policy/policies.rs
index 655c7a1398e..8d257fa6b6f 100644
--- a/implementations/rust/ockam/ockam_abac/src/policy/policies.rs
+++ b/implementations/rust/ockam/ockam_abac/src/policy/policies.rs
@@ -9,7 +9,7 @@ use ockam_core::compat::vec::Vec;
 use ockam_core::Result;
 use ockam_identity::{Identifier, IdentitiesAttributes};
 use strum::IntoEnumIterator;
-use tracing::{debug, instrument};
+use tracing::{debug, instrument, Level};
 
 #[derive(Clone)]
 pub struct Policies {
@@ -28,7 +28,7 @@ impl Policies {
         }
     }
 
-    #[instrument(skip_all, fields(resource = %resource, action = %action, env = %env, authority = ?authority))]
+    #[instrument(skip_all, fields(resource = %resource, action = %action, env = %env, authority = ?authority), level = Level::TRACE)]
     pub fn make_policy_access_control(
         &self,
         identities_attributes: Arc<IdentitiesAttributes>,
diff --git a/implementations/rust/ockam/ockam_api/src/authenticator/credential_issuer/credential_issuer.rs b/implementations/rust/ockam/ockam_api/src/authenticator/credential_issuer/credential_issuer.rs
index 5931d5c6bbd..2c3906f2bd6 100644
--- a/implementations/rust/ockam/ockam_api/src/authenticator/credential_issuer/credential_issuer.rs
+++ b/implementations/rust/ockam/ockam_api/src/authenticator/credential_issuer/credential_issuer.rs
@@ -7,6 +7,7 @@ use ockam::identity::utils::AttributesBuilder;
 use ockam::identity::{Attributes, Credentials, Identifier, IdentitiesAttributes};
 use ockam_core::compat::sync::Arc;
 use ockam_core::Result;
+use tracing::Level;
 
 /// Legacy value, should be removed when all clients are updated to the latest version
 pub const TRUST_CONTEXT_ID: &[u8] = b"trust_context_id";
@@ -32,7 +33,7 @@ pub struct CredentialIssuer {
 impl CredentialIssuer {
     /// Create a new credentials issuer
     #[allow(clippy::too_many_arguments)]
-    #[instrument(skip_all, fields(issuer = %issuer, project_identifier = project_identifier.clone(), credential_ttl = credential_ttl.map_or("n/a".to_string(), |d| d.as_secs().to_string())))]
+    #[instrument(skip_all, fields(issuer = %issuer, project_identifier = project_identifier.clone(), credential_ttl = credential_ttl.map_or("n/a".to_string(), |d| d.as_secs().to_string())), level = Level::TRACE)]
     pub fn new(
         members: Arc<dyn AuthorityMembersRepository>,
         identities_attributes: Arc<IdentitiesAttributes>,
@@ -66,7 +67,7 @@ impl CredentialIssuer {
         }
     }
 
-    #[instrument(skip_all, fields(subject = %subject))]
+    #[instrument(skip_all, fields(subject = %subject), level = Level::TRACE)]
     pub async fn issue_credential(
         &self,
         subject: &Identifier,
diff --git a/implementations/rust/ockam/ockam_api/src/authenticator/direct/direct_authenticator.rs b/implementations/rust/ockam/ockam_api/src/authenticator/direct/direct_authenticator.rs
index 999e47b29bc..4f4f8b55895 100644
--- a/implementations/rust/ockam/ockam_api/src/authenticator/direct/direct_authenticator.rs
+++ b/implementations/rust/ockam/ockam_api/src/authenticator/direct/direct_authenticator.rs
@@ -1,5 +1,6 @@
 use either::Either;
 use std::collections::{BTreeMap, HashMap};
+use tracing::Level;
 
 use ockam::identity::utils::now;
 use ockam::identity::Identifier;
@@ -76,7 +77,7 @@ impl DirectAuthenticator {
         }
     }
 
-    #[instrument(skip_all, fields(enroller = %enroller, identifier = %identifier))]
+    #[instrument(skip_all, fields(enroller = %enroller, identifier = %identifier), level = Level::TRACE)]
     pub async fn add_member(
         &self,
         enroller: &Identifier,
@@ -141,7 +142,7 @@ impl DirectAuthenticator {
         Ok(Either::Left(()))
     }
 
-    #[instrument(skip_all, fields(enroller = %enroller))]
+    #[instrument(skip_all, fields(enroller = %enroller), level = Level::TRACE)]
     pub async fn show_member(
         &self,
         enroller: &Identifier,
@@ -183,7 +184,7 @@ impl DirectAuthenticator {
         }
     }
 
-    #[instrument(skip_all, fields(enroller = %enroller))]
+    #[instrument(skip_all, fields(enroller = %enroller), level = Level::TRACE)]
     pub async fn list_members(
         &self,
         enroller: &Identifier,
@@ -220,7 +221,7 @@ impl DirectAuthenticator {
         Ok(Either::Left(res))
     }
 
-    #[instrument(skip_all, fields(enroller = %enroller))]
+    #[instrument(skip_all, fields(enroller = %enroller), level = Level::TRACE)]
     pub async fn delete_all_members(
         &self,
         enroller: &Identifier,
@@ -238,7 +239,7 @@ impl DirectAuthenticator {
         }
     }
 
-    #[instrument(skip_all, fields(enroller = %enroller, identifier = %identifier))]
+    #[instrument(skip_all, fields(enroller = %enroller, identifier = %identifier), level = Level::TRACE)]
     pub async fn delete_member(
         &self,
         enroller: &Identifier,
diff --git a/implementations/rust/ockam/ockam_api/src/authenticator/enrollment_tokens/acceptor.rs b/implementations/rust/ockam/ockam_api/src/authenticator/enrollment_tokens/acceptor.rs
index 88c91848211..85ed840c650 100644
--- a/implementations/rust/ockam/ockam_api/src/authenticator/enrollment_tokens/acceptor.rs
+++ b/implementations/rust/ockam/ockam_api/src/authenticator/enrollment_tokens/acceptor.rs
@@ -1,4 +1,6 @@
 use either::Either;
+use tracing::Level;
+
 use ockam::identity::utils::now;
 use ockam::identity::Identifier;
 use ockam_core::compat::sync::Arc;
@@ -33,7 +35,7 @@ impl EnrollmentTokenAcceptor {
         }
     }
 
-    #[instrument(skip_all, fields(from = %from))]
+    #[instrument(skip_all, fields(from = %from), level = Level::TRACE)]
     pub async fn accept_token(
         &mut self,
         otc: OneTimeCode,
diff --git a/implementations/rust/ockam/ockam_api/src/authenticator/enrollment_tokens/acceptor_client.rs b/implementations/rust/ockam/ockam_api/src/authenticator/enrollment_tokens/acceptor_client.rs
index 4c4fe21fe76..eaf6d703679 100644
--- a/implementations/rust/ockam/ockam_api/src/authenticator/enrollment_tokens/acceptor_client.rs
+++ b/implementations/rust/ockam/ockam_api/src/authenticator/enrollment_tokens/acceptor_client.rs
@@ -1,4 +1,5 @@
 use miette::IntoDiagnostic;
+use tracing::Level;
 
 use ockam_core::api::Request;
 use ockam_core::async_trait;
@@ -15,7 +16,7 @@ pub trait TokenAcceptor {
 
 #[async_trait]
 impl TokenAcceptor for AuthorityNodeClient {
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn present_token(&self, ctx: &Context, token: OneTimeCode) -> miette::Result<()> {
         let req = Request::post("/").body(token);
         self.get_secure_client()
diff --git a/implementations/rust/ockam/ockam_api/src/authenticator/enrollment_tokens/issuer.rs b/implementations/rust/ockam/ockam_api/src/authenticator/enrollment_tokens/issuer.rs
index f5f4caff198..ca5a6f94205 100644
--- a/implementations/rust/ockam/ockam_api/src/authenticator/enrollment_tokens/issuer.rs
+++ b/implementations/rust/ockam/ockam_api/src/authenticator/enrollment_tokens/issuer.rs
@@ -2,6 +2,7 @@ use either::Either;
 use rand::distributions::Alphanumeric;
 use rand::Rng;
 use std::collections::BTreeMap;
+use tracing::Level;
 
 use ockam::identity::utils::now;
 use ockam::identity::{Identifier, IdentitiesAttributes};
@@ -50,7 +51,7 @@ impl EnrollmentTokenIssuer {
         }
     }
 
-    #[instrument(skip_all, fields(enroller = %enroller, token_duration = token_duration.map_or("n/a".to_string(), |d| d.as_secs().to_string()), ttl_count = ttl_count.map_or("n/a".to_string(), |t| t.to_string())))]
+    #[instrument(skip_all, fields(enroller = %enroller, token_duration = token_duration.map_or("n/a".to_string(), |d| d.as_secs().to_string()), ttl_count = ttl_count.map_or("n/a".to_string(), |t| t.to_string())), level = Level::TRACE)]
     pub async fn issue_token(
         &self,
         enroller: &Identifier,
diff --git a/implementations/rust/ockam/ockam_api/src/cli_state/enrollments.rs b/implementations/rust/ockam/ockam_api/src/cli_state/enrollments.rs
index 43f08b4e78c..12fb126dbdc 100644
--- a/implementations/rust/ockam/ockam_api/src/cli_state/enrollments.rs
+++ b/implementations/rust/ockam/ockam_api/src/cli_state/enrollments.rs
@@ -14,11 +14,12 @@ use serde::{Deserialize, Serialize};
 use std::fmt::{Display, Formatter};
 use std::str::FromStr;
 use time::OffsetDateTime;
+use tracing::Level;
 
 /// The following CliState methods help keeping track of
 /// the enrollment status of identities.
 impl CliState {
-    #[instrument(skip_all, fields(name = name.clone()))]
+    #[instrument(skip_all, fields(name = name.clone()), level = Level::TRACE)]
     pub async fn is_identity_enrolled(&self, name: &Option<String>) -> Result<bool> {
         let repository = self.enrollment_repository();
 
@@ -28,7 +29,7 @@ impl CliState {
         }
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn is_default_identity_enrolled(&self) -> Result<bool> {
         Ok(self
             .enrollment_repository()
@@ -36,7 +37,7 @@ impl CliState {
             .await?)
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn identity_should_enroll(&self, name: &Option<String>, force: bool) -> Result<bool> {
         if force {
             return Ok(true);
@@ -51,7 +52,7 @@ impl CliState {
         Ok(!self.is_identity_enrolled(name).await?)
     }
 
-    #[instrument(skip_all, fields(identifier = %identifier))]
+    #[instrument(skip_all, fields(identifier = %identifier), level = Level::TRACE)]
     pub async fn set_identifier_as_enrolled(
         &self,
         identifier: &Identifier,
@@ -67,7 +68,7 @@ impl CliState {
     ///
     ///  - all the currently enrolled entities
     ///  - all the known identities and their corresponding enrollment state
-    #[instrument(skip_all, fields(filter = %filter))]
+    #[instrument(skip_all, fields(filter = %filter), level = Level::TRACE)]
     pub async fn get_identity_enrollments(
         &self,
         filter: EnrollmentFilter,
@@ -93,7 +94,7 @@ impl CliState {
     /// Return true if the user is enrolled.
     /// At the moment this check only verifies that there is a default project.
     /// This project should be the project that is created at the end of the enrollment procedure
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn is_enrolled(&self) -> miette::Result<bool> {
         if !self.is_default_identity_enrolled().await? {
             return Ok(false);
diff --git a/implementations/rust/ockam/ockam_api/src/cli_state/identities.rs b/implementations/rust/ockam/ockam_api/src/cli_state/identities.rs
index 695f2d3df33..554da157d17 100644
--- a/implementations/rust/ockam/ockam_api/src/cli_state/identities.rs
+++ b/implementations/rust/ockam/ockam_api/src/cli_state/identities.rs
@@ -4,6 +4,7 @@ use ockam::identity::{Identifier, Identity};
 use ockam_core::errcode::{Kind, Origin};
 use ockam_core::Error;
 use ockam_vault::{HandleToSecret, SigningSecretKeyHandle};
+use tracing::Level;
 
 use crate::cli_state::{random_name, CliState, Result};
 use crate::colors::color_primary;
@@ -28,7 +29,7 @@ use crate::{fmt_log, fmt_ok};
 impl CliState {
     /// Create an identity associated with a name and a specific vault name
     /// If there is already an identity with that name, return its identifier
-    #[instrument(skip_all, fields(name = %name, vault_name = %vault_name))]
+    #[instrument(skip_all, fields(name = %name, vault_name = %vault_name), level = Level::TRACE)]
     pub async fn create_identity_with_name_and_vault(
         &self,
         name: &str,
@@ -64,7 +65,7 @@ impl CliState {
 
     /// Create an identity associated with a name, using the default vault
     /// If there is already an identity with that name, return its identifier
-    #[instrument(skip_all, fields(name = %name))]
+    #[instrument(skip_all, fields(name = %name), level = Level::TRACE)]
     pub async fn create_identity_with_name(&self, name: &str) -> Result<NamedIdentity> {
         let vault = self.get_or_create_default_named_vault().await?;
         self.create_identity_with_name_and_vault(name, &vault.name())
@@ -74,7 +75,7 @@ impl CliState {
     /// Create an identity with specific key id.
     /// This method is used when the vault is a KMS vault and we just need to store a key id
     /// for the identity key existing in the KMS
-    #[instrument(skip_all, fields(name = %name, vault_name = %vault_name, key_id = %key_id))]
+    #[instrument(skip_all, fields(name = %name, vault_name = %vault_name, key_id = %key_id), level = Level::TRACE)]
     pub async fn create_identity_with_key_id(
         &self,
         name: &str,
@@ -123,13 +124,13 @@ impl CliState {
 ///
 impl CliState {
     /// Return all named identities
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn get_named_identities(&self) -> Result<Vec<NamedIdentity>> {
         Ok(self.identities_repository().get_named_identities().await?)
     }
 
     /// Return a named identity given its name
-    #[instrument(skip_all, fields(name = %name))]
+    #[instrument(skip_all, fields(name = %name), level = Level::TRACE)]
     pub async fn get_named_identity(&self, name: &str) -> Result<NamedIdentity> {
         let repository = self.identities_repository();
         match repository.get_named_identity(name).await? {
@@ -151,7 +152,7 @@ impl CliState {
     }
 
     /// Return a named identity given its name or the default named identity
-    #[instrument(skip_all, fields(name = name.clone()))]
+    #[instrument(skip_all, fields(name = name.clone()), level = Level::TRACE)]
     pub async fn get_named_identity_or_default(
         &self,
         name: &Option<String>,
@@ -171,7 +172,7 @@ impl CliState {
 
     /// Return the identifier for identity given an optional name.
     /// If that name is None, then we return the identifier of the default identity
-    #[instrument(skip_all, fields(name = name.clone()))]
+    #[instrument(skip_all, fields(name = name.clone()), level = Level::TRACE)]
     pub async fn get_identifier_by_optional_name(
         &self,
         name: &Option<String>,
@@ -190,7 +191,7 @@ impl CliState {
 
     /// Return a full identity from its name
     /// Use the default identity if no name is given
-    #[instrument(skip_all, fields(name = name.clone()))]
+    #[instrument(skip_all, fields(name = name.clone()), level = Level::TRACE)]
     pub async fn get_identity_by_optional_name(&self, name: &Option<String>) -> Result<Identity> {
         let named_identity = match name {
             Some(name) => {
@@ -222,7 +223,7 @@ impl CliState {
     }
 
     /// Return the identity with the given identifier
-    #[instrument(skip_all, fields(identifier = %identifier))]
+    #[instrument(skip_all, fields(identifier = %identifier), level = Level::TRACE)]
     pub async fn get_identity(&self, identifier: &Identifier) -> Result<Identity> {
         match self
             .change_history_repository()
@@ -242,14 +243,14 @@ impl CliState {
 
     /// Return the name of the default identity.
     /// This function creates the default identity if it does not exist!
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn get_default_identity_name(&self) -> Result<String> {
         Ok(self.get_or_create_default_named_identity().await?.name())
     }
 
     /// Return the default named identity
     /// This function creates the default identity if it does not exist!
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn get_or_create_default_named_identity(&self) -> Result<NamedIdentity> {
         match self
             .identities_repository()
@@ -271,7 +272,7 @@ impl CliState {
     /// Return:
     /// - the given name if defined
     /// - or the name of the default identity (which is created if it does not already exist!)
-    #[instrument(skip_all, fields(name = name.clone()))]
+    #[instrument(skip_all, fields(name = name.clone()), level = Level::TRACE)]
     pub async fn get_identity_name_or_default(&self, name: &Option<String>) -> Result<String> {
         match name {
             Some(name) => Ok(name.clone()),
@@ -280,7 +281,7 @@ impl CliState {
     }
 
     /// Return the named identity with the given identifier
-    #[instrument(skip_all, fields(identifier = %identifier))]
+    #[instrument(skip_all, fields(identifier = %identifier), level = Level::TRACE)]
     pub async fn get_named_identity_by_identifier(
         &self,
         identifier: &Identifier,
@@ -300,7 +301,7 @@ impl CliState {
     }
 
     /// Return true if there is an identity with that name and it is the default one
-    #[instrument(skip_all, fields(name = %name))]
+    #[instrument(skip_all, fields(name = %name), level = Level::TRACE)]
     pub async fn is_default_identity_by_name(&self, name: &str) -> Result<bool> {
         Ok(self
             .identities_repository()
@@ -315,7 +316,7 @@ impl CliState {
 impl CliState {
     /// Set a named identity as the default
     /// Return an error if that identity does not exist
-    #[instrument(skip_all, fields(name = %name))]
+    #[instrument(skip_all, fields(name = %name), level = Level::TRACE)]
     pub async fn set_as_default_identity(&self, name: &str) -> Result<()> {
         Ok(self.identities_repository().set_as_default(name).await?)
     }
@@ -326,7 +327,7 @@ impl CliState {
     ///  - then remove the the name association to the identity
     ///  - and remove the identity change history
     ///
-    #[instrument(skip_all, fields(name = %name))]
+    #[instrument(skip_all, fields(name = %name), level = Level::TRACE)]
     pub async fn delete_identity_by_name(&self, name: &str) -> Result<()> {
         let nodes = self.get_nodes_by_identity_name(name).await?;
         if nodes.is_empty() {
@@ -350,7 +351,7 @@ impl CliState {
     }
 
     /// Update the name associated to an identifier
-    #[instrument(skip_all, fields(identifier = %identifier, name = %name))]
+    #[instrument(skip_all, fields(identifier = %identifier, name = %name), level = Level::TRACE)]
     pub async fn update_named_identity_name(
         &self,
         identifier: &Identifier,
@@ -367,7 +368,7 @@ impl CliState {
 impl CliState {
     /// Once a identity has been created, store it.
     /// If there is no previous default identity we set it as the default identity
-    #[instrument(skip_all, fields(name = %name, identifier = %identifier, vault_name = %vault_name))]
+    #[instrument(skip_all, fields(name = %name, identifier = %identifier, vault_name = %vault_name), level = Level::TRACE)]
     pub async fn store_named_identity(
         &self,
         identifier: &Identifier,
@@ -391,7 +392,7 @@ impl CliState {
     }
 
     /// Return the change history of a persisted identity
-    #[instrument(skip_all, fields(identifier = %identifier))]
+    #[instrument(skip_all, fields(identifier = %identifier), level = Level::TRACE)]
     async fn get_change_history(&self, identifier: &Identifier) -> Result<ChangeHistory> {
         match self
             .change_history_repository()
diff --git a/implementations/rust/ockam/ockam_api/src/cli_state/journeys/attributes.rs b/implementations/rust/ockam/ockam_api/src/cli_state/journeys/attributes.rs
index dec32b07225..0dc465f78af 100644
--- a/implementations/rust/ockam/ockam_api/src/cli_state/journeys/attributes.rs
+++ b/implementations/rust/ockam/ockam_api/src/cli_state/journeys/attributes.rs
@@ -34,7 +34,7 @@ pub fn default_attributes<'a>() -> HashMap<&'a Key, String> {
 ///  - The next 25 characters identify the host
 ///  - The last 6 characters are the 'now' date as YYMMDD
 ///
-pub(crate) fn make_host_trace_id(now: DateTime<Utc>) -> TraceId {
+pub fn make_host_trace_id(now: DateTime<Utc>) -> TraceId {
     let machine = adjust(make_host(), 25, '1');
     // date as a 6 characters string
     let now = now_as_string(now);
@@ -54,7 +54,7 @@ pub(crate) fn make_host_trace_id(now: DateTime<Utc>) -> TraceId {
 ///    This allows to bucket all the spans in the same trace, even if the spans come from  different machines which
 ///    can start their own project journey trace independently.
 ///
-pub(crate) fn make_project_trace_id(project_id: &str, now: DateTime<Utc>) -> TraceId {
+pub fn make_project_trace_id(project_id: &str, now: DateTime<Utc>) -> TraceId {
     // take the whole project without '-' as the base for the trace id
     // make sure that there exactly 25 characters
     let project_id_trace_id = adjust(project_id.to_string().replace('-', ""), 25, '1');
diff --git a/implementations/rust/ockam/ockam_api/src/cli_state/journeys/journeys.rs b/implementations/rust/ockam/ockam_api/src/cli_state/journeys/journeys.rs
index 18c03eab3c1..c6df03f051c 100644
--- a/implementations/rust/ockam/ockam_api/src/cli_state/journeys/journeys.rs
+++ b/implementations/rust/ockam/ockam_api/src/cli_state/journeys/journeys.rs
@@ -8,11 +8,13 @@ use crate::{CliState, Result};
 use chrono::{DateTime, Utc};
 use either::Either;
 use ockam_core::{OpenTelemetryContext, OCKAM_TRACER_NAME};
-use opentelemetry::trace::{Link, SpanBuilder, SpanId, TraceContextExt, TraceId, Tracer};
+use opentelemetry::trace::{Link, Span, SpanBuilder, SpanId, TraceContextExt, TraceId, Tracer};
 use opentelemetry::{global, Context, Key, KeyValue};
 use std::collections::HashMap;
+use std::fmt::{Display, Formatter};
 use std::ops::Add;
 use std::time::{Duration, SystemTime};
+use tracing::Level;
 
 pub const USER_NAME: &Key = &Key::from_static_str("app.user_name");
 pub const USER_EMAIL: &Key = &Key::from_static_str("app.user_email");
@@ -38,6 +40,8 @@ pub const APPLICATION_EVENT_PROJECT_AUTHORITY_IDENTIFIER: &Key =
     &Key::from_static_str("app.event.project.authority_identifier");
 
 pub const APPLICATION_EVENT_NODE_NAME: &Key = &Key::from_static_str("app.event.node_name");
+pub const APPLICATION_EVENT_NODE_IDENTIFIER: &Key =
+    &Key::from_static_str("app.event.node_identifier");
 pub const APPLICATION_EVENT_OCKAM_DEVELOPER: &Key =
     &Key::from_static_str("app.event.ockam_developer");
 pub const APPLICATION_EVENT_TRACE_ID: &Key = &Key::from_static_str("app.event.trace_id");
@@ -51,6 +55,22 @@ pub const APPLICATION_EVENT_OCKAM_HOME: &Key = &Key::from_static_str("app.event.
 pub const APPLICATION_EVENT_OCKAM_VERSION: &Key = &Key::from_static_str("app.event.ockam_version");
 pub const APPLICATION_EVENT_OCKAM_GIT_HASH: &Key =
     &Key::from_static_str("app.event.ockam_git_hash");
+pub const APPLICATION_EVENT_TRACE_TYPE: &Key = &Key::from_static_str("app.event.trace_type");
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum TraceType {
+    Host,
+    Project,
+}
+
+impl Display for TraceType {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        match self {
+            TraceType::Host => f.write_str("host"),
+            TraceType::Project => f.write_str("project"),
+        }
+    }
+}
 
 /// Journey events have a fixed duration
 pub const EVENT_DURATION: Duration = Duration::from_secs(100);
@@ -76,17 +96,17 @@ const DEFAULT_JOURNEY_MAX_DURATION: Duration = Duration::from_secs(5 * 86400);
 ///
 impl CliState {
     /// This method adds a successful event to the project/host journeys
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn add_journey_event(
         &self,
         event: JourneyEvent,
         attributes: HashMap<&Key, String>,
     ) -> Result<()> {
-        self.add_a_journey_event(event, attributes).await
+        self.add_a_journey_event(event, attributes, None).await
     }
 
     /// This method adds an error event to the project/host journeys
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn add_journey_error(
         &self,
         command_name: &str,
@@ -94,8 +114,9 @@ impl CliState {
         attributes: HashMap<&Key, String>,
     ) -> Result<()> {
         self.add_a_journey_event(
-            JourneyEvent::error(command_name.to_string(), message),
+            JourneyEvent::error(command_name.to_string(), message.clone()),
             attributes,
+            Some(message),
         )
         .await
     }
@@ -108,34 +129,73 @@ impl CliState {
         &self,
         event: JourneyEvent,
         attributes: HashMap<&Key, String>,
+        error_message: Option<String>,
     ) -> Result<()> {
         if !self.is_tracing_enabled() {
             return Ok(());
         }
 
+        let project = self.projects().get_default_project().await.ok();
+        let (host_journey, project_journey) = self
+            .get_journeys(project.clone().map(|p| p.project_id().to_string()))
+            .await?;
+        self.make_span_from_journey(
+            &project,
+            &event,
+            &attributes,
+            &error_message,
+            host_journey,
+            "host",
+        )
+        .await?;
+        if let Some(project_journey) = project_journey {
+            self.make_span_from_journey(
+                &project,
+                &event,
+                &attributes,
+                &error_message,
+                project_journey,
+                "project",
+            )
+            .await?;
+        }
+        Ok(())
+    }
+
+    /// Create a span that will get its trace_id from the journey context
+    /// The trace_type is used to differentiate between the host and the project journeys.
+    /// We can later on use this information to filter all the spans for a given host, or all the spans
+    /// for a given project.
+    async fn make_span_from_journey(
+        &self,
+        project: &Option<Project>,
+        event: &JourneyEvent,
+        attributes: &HashMap<&Key, String>,
+        error_message: &Option<String>,
+        journey: Journey,
+        trace_type: &str,
+    ) -> Result<()> {
         // get the journey context
         let tracer = global::tracer(OCKAM_TRACER_NAME);
         let event_span_context = Context::current().span().span_context().clone();
-        let project = self.projects().get_default_project().await.ok();
 
         // for both the host and the project journey create a span with a fixed duration
         // and add attributes to the span
         let start_time = SystemTime::from(Utc::now());
         let end_time = start_time.add(EVENT_DURATION);
 
-        let journeys = self
-            .get_journeys(project.clone().map(|p| p.project_id().to_string()))
-            .await?;
-        for journey in journeys {
-            let span_builder = SpanBuilder::from_name(event.to_string())
-                .with_start_time(start_time)
-                .with_end_time(end_time)
-                .with_links(vec![Link::new(event_span_context.clone(), vec![], 0)]);
-            let span = tracer.build_with_context(span_builder, &journey.extract_context());
-            let cx = Context::current_with_span(span);
-            let _guard = cx.attach();
-            self.set_current_span_attributes(&event, &attributes, &project)
+        let span_builder = SpanBuilder::from_name(event.to_string())
+            .with_start_time(start_time)
+            .with_end_time(end_time)
+            .with_links(vec![Link::new(event_span_context.clone(), vec![], 0)]);
+        let mut span = tracer.build_with_context(span_builder, &journey.extract_context());
+        if let Some(message) = error_message {
+            span.set_status(opentelemetry::trace::Status::error(message.clone()));
         }
+        let cx = Context::current_with_span(span);
+        let _guard = cx.attach();
+        self.set_current_span_attributes(event, attributes, project);
+        CurrentSpan::set_attribute(APPLICATION_EVENT_TRACE_TYPE, trace_type);
         Ok(())
     }
 
@@ -217,15 +277,13 @@ impl CliState {
     }
 
     /// Return a list of journeys for which we want to add spans
-    async fn get_journeys(&self, project_id: Option<String>) -> Result<Vec<Journey>> {
+    async fn get_journeys(&self, project_id: Option<String>) -> Result<(Journey, Option<Journey>)> {
         let now = *Context::current()
             .get::<DateTime<Utc>>()
             .unwrap_or(&Utc::now());
 
-        let mut result = vec![];
-
         let max_duration = DEFAULT_JOURNEY_MAX_DURATION;
-        let journey = match self.get_host_journey(now, max_duration).await? {
+        let host_journey = match self.get_host_journey(now, max_duration).await? {
             Some(Either::Right(journey)) => journey,
             Some(Either::Left(journey)) => {
                 self.create_host_journey(Some(journey.opentelemetry_context()), now)
@@ -233,9 +291,8 @@ impl CliState {
             }
             None => self.create_host_journey(None, now).await?,
         };
-        result.push(journey);
 
-        if let Some(project_id) = project_id {
+        let project_journey = if let Some(project_id) = project_id {
             let journey = match self
                 .get_project_journey(&project_id, now, max_duration)
                 .await?
@@ -251,10 +308,12 @@ impl CliState {
                 }
                 None => self.create_project_journey(&project_id, None, now).await?,
             };
-            result.push(journey.to_journey());
+            Some(journey.to_journey())
+        } else {
+            None
         };
 
-        Ok(result)
+        Ok((host_journey, project_journey))
     }
 
     /// When a project is deleted the project journeys need to be restarted
diff --git a/implementations/rust/ockam/ockam_api/src/cli_state/nodes.rs b/implementations/rust/ockam/ockam_api/src/cli_state/nodes.rs
index 5bf39cc7f6c..9ed887067b9 100644
--- a/implementations/rust/ockam/ockam_api/src/cli_state/nodes.rs
+++ b/implementations/rust/ockam/ockam_api/src/cli_state/nodes.rs
@@ -15,6 +15,7 @@ use std::path::PathBuf;
 use std::process;
 use std::time::Duration;
 use sysinfo::{Pid, ProcessStatus, ProcessesToUpdate, System};
+use tracing::Level;
 
 use crate::cli_state::{random_name, NamedVault, Result};
 use crate::cli_state::{CliState, CliStateError};
@@ -26,7 +27,7 @@ use crate::{fmt_warn, ConnectionStatus};
 /// The methods below support the creation and update of local nodes
 impl CliState {
     /// Create a node, with some optional associated values, and start it
-    #[instrument(skip_all, fields(node_name = node_name, identity_name = identity_name.clone()))]
+    #[instrument(skip_all, fields(node_name = node_name, identity_name = identity_name.clone()), level = Level::TRACE)]
     pub async fn start_node_with_optional_values(
         &self,
         node_name: &str,
@@ -51,7 +52,7 @@ impl CliState {
     }
 
     /// Create a node, with an optional identity name. That identity is used by the `NodeManager` to create secure channels
-    #[instrument(skip_all, fields(node_name = node_name, identity_name = identity_name.clone()))]
+    #[instrument(skip_all, fields(node_name = node_name, identity_name = identity_name.clone()), level = Level::TRACE)]
     pub async fn create_node_with_optional_identity(
         &self,
         node_name: &str,
@@ -69,7 +70,7 @@ impl CliState {
 
     /// This method creates a node with an associated identity
     /// The vault used to create the identity is the default vault
-    #[instrument(skip_all, fields(node_name = node_name))]
+    #[instrument(skip_all, fields(node_name = node_name), level = Level::TRACE)]
     pub async fn create_node(&self, node_name: &str) -> Result<NodeInfo> {
         let identity = self.create_identity_with_name(&random_name()).await?;
         self.create_node_with_identifier(node_name, &identity.identifier())
@@ -103,7 +104,7 @@ impl CliState {
     /// Delete a node
     ///  - first stop it if it is running
     ///  - then remove it from persistent storage
-    #[instrument(skip_all, fields(node_name = node_name))]
+    #[instrument(skip_all, fields(node_name = node_name), level = Level::TRACE)]
     pub async fn delete_node(&self, node_name: &str) -> Result<()> {
         self.stop_node(node_name).await?;
         self.remove_node(node_name).await?;
@@ -111,7 +112,7 @@ impl CliState {
     }
 
     /// Delete all created nodes
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn delete_all_nodes(&self) -> Result<()> {
         let nodes = self.nodes_repository().get_nodes().await?;
         for node in nodes {
@@ -129,7 +130,7 @@ impl CliState {
     ///
     ///  - remove it from the repository
     ///  - remove the node log files
-    #[instrument(skip_all, fields(node_name = node_name))]
+    #[instrument(skip_all, fields(node_name = node_name), level = Level::TRACE)]
     pub async fn remove_node(&self, node_name: &str) -> Result<()> {
         // remove the node from the database
         let repository = self.nodes_repository();
@@ -151,7 +152,7 @@ impl CliState {
     }
 
     /// Stop a background node
-    #[instrument(skip_all, fields(node_name = node_name))]
+    #[instrument(skip_all, fields(node_name = node_name), level = Level::TRACE)]
     pub async fn stop_node(&self, node_name: &str) -> Result<()> {
         debug!(name=%node_name, "stopping node...");
         let node = self.get_node(node_name).await?;
@@ -262,13 +263,13 @@ impl CliState {
     }
 
     /// Set a node as the default node
-    #[instrument(skip_all, fields(node_name = node_name))]
+    #[instrument(skip_all, fields(node_name = node_name), level = Level::TRACE)]
     pub async fn set_default_node(&self, node_name: &str) -> Result<()> {
         Ok(self.nodes_repository().set_default_node(node_name).await?)
     }
 
     /// Set a TCP listener address on a node when the TCP listener has been started
-    #[instrument(skip_all, fields(node_name = node_name, address = %address))]
+    #[instrument(skip_all, fields(node_name = node_name, address = %address), level = Level::TRACE)]
     pub async fn set_tcp_listener_address(
         &self,
         node_name: &str,
@@ -280,7 +281,7 @@ impl CliState {
         Ok(())
     }
 
-    #[instrument(skip_all, fields(node_name = node_name, address = %address))]
+    #[instrument(skip_all, fields(node_name = node_name, address = %address), level = Level::TRACE)]
     pub async fn set_node_http_server_addr(
         &self,
         node_name: &str,
@@ -295,7 +296,7 @@ impl CliState {
     /// Specify that a node is an authority node
     /// This is used to display the node status since if the node TCP listener is not accessible
     /// without a secure channel
-    #[instrument(skip_all, fields(node_name = node_name))]
+    #[instrument(skip_all, fields(node_name = node_name), level = Level::TRACE)]
     pub async fn set_as_authority_node(&self, node_name: &str) -> Result<()> {
         Ok(self
             .nodes_repository()
@@ -305,7 +306,7 @@ impl CliState {
 
     /// Set the current process id on a background node
     /// Keeping track of a background node process id allows us to kill its process when stopping the node
-    #[instrument(skip_all, fields(node_name = node_name, pid = %pid))]
+    #[instrument(skip_all, fields(node_name = node_name, pid = %pid), level = Level::TRACE)]
     pub async fn set_node_pid(&self, node_name: &str, pid: u32) -> Result<()> {
         Ok(self.nodes_repository().set_node_pid(node_name, pid).await?)
     }
@@ -314,7 +315,7 @@ impl CliState {
 /// The following methods return nodes data
 impl CliState {
     /// Return a node by name
-    #[instrument(skip_all, fields(node_name = node_name))]
+    #[instrument(skip_all, fields(node_name = node_name), level = Level::TRACE)]
     pub async fn get_node(&self, node_name: &str) -> Result<NodeInfo> {
         if let Some(node) = self.nodes_repository().get_node(node_name).await? {
             Ok(node)
@@ -327,13 +328,13 @@ impl CliState {
     }
 
     /// Return all the created nodes
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn get_nodes(&self) -> Result<Vec<NodeInfo>> {
         Ok(self.nodes_repository().get_nodes().await?)
     }
 
     /// Return information about the default node (if there is one)
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn get_default_node(&self) -> Result<NodeInfo> {
         Ok(self
             .nodes_repository()
@@ -343,7 +344,7 @@ impl CliState {
     }
 
     /// Return the node information for the given node name, otherwise for the default node
-    #[instrument(skip_all, fields(node_name = node_name.clone()))]
+    #[instrument(skip_all, fields(node_name = node_name.clone()), level = Level::TRACE)]
     pub async fn get_node_or_default(&self, node_name: &Option<String>) -> Result<NodeInfo> {
         match node_name {
             Some(name) => self.get_node(name).await,
@@ -352,7 +353,7 @@ impl CliState {
     }
 
     /// Return the stdout log file used by a node
-    #[instrument(skip_all, fields(node_name = node_name))]
+    #[instrument(skip_all, fields(node_name = node_name), level = Level::TRACE)]
     pub fn stdout_logs(&self, node_name: &str) -> Result<PathBuf> {
         let node_dir = self.create_node_dir(node_name)?;
         let current_log_file = std::fs::read_dir(node_dir)?
@@ -379,7 +380,7 @@ impl CliState {
 /// Private functions
 impl CliState {
     /// This method creates a node
-    #[instrument(skip_all, fields(node_name = node_name, identifier = %identifier))]
+    #[instrument(skip_all, fields(node_name = node_name, identifier = %identifier), level = Level::TRACE)]
     pub async fn create_node_with_identifier(
         &self,
         node_name: &str,
@@ -414,7 +415,7 @@ impl CliState {
     }
 
     /// Return the nodes using a given identity
-    #[instrument(skip_all, fields(identity_name = identity_name))]
+    #[instrument(skip_all, fields(identity_name = identity_name), level = Level::TRACE)]
     pub(super) async fn get_nodes_by_identity_name(
         &self,
         identity_name: &str,
@@ -427,7 +428,7 @@ impl CliState {
     }
 
     /// Return the vault which was used to create the identity associated to a node
-    #[instrument(skip_all, fields(node_name = node_name))]
+    #[instrument(skip_all, fields(node_name = node_name), level = Level::TRACE)]
     pub(super) async fn get_node_vault(&self, node_name: &str) -> Result<NamedVault> {
         let identifier = self.get_node(node_name).await?.identifier();
         let identity = self.get_named_identity_by_identifier(&identifier).await?;
diff --git a/implementations/rust/ockam/ockam_api/src/cli_state/projects.rs b/implementations/rust/ockam/ockam_api/src/cli_state/projects.rs
index 97d08cae26d..2cdd2e3d28b 100644
--- a/implementations/rust/ockam/ockam_api/src/cli_state/projects.rs
+++ b/implementations/rust/ockam/ockam_api/src/cli_state/projects.rs
@@ -1,6 +1,7 @@
 use ockam::identity::{Identifier, IdentitiesVerification};
 use std::collections::HashMap;
 use std::sync::Arc;
+use tracing::Level;
 
 use ockam_core::errcode::{Kind, Origin};
 use ockam_core::Error;
@@ -30,13 +31,13 @@ impl Projects {
         }
     }
 
-    #[instrument(skip_all, fields(project_id = project_model.id))]
+    #[instrument(skip_all, fields(project_id = project_model.id), level = Level::TRACE)]
     pub async fn import_and_store_project(&self, project_model: ProjectModel) -> Result<Project> {
         let project = Project::import(project_model.clone()).await?;
         self.store_project(project).await
     }
 
-    #[instrument(skip_all, fields(project_id = project.project_id()))]
+    #[instrument(skip_all, fields(project_id = project.project_id()), level = Level::TRACE)]
     pub async fn store_project(&self, project: Project) -> Result<Project> {
         if let Some(project_identity) = project.project_identity() {
             self.identities_verification
@@ -54,19 +55,19 @@ impl Projects {
         Ok(project)
     }
 
-    #[instrument(skip_all, fields(project_id = project.id))]
+    #[instrument(skip_all, fields(project_id = project.id), level = Level::TRACE)]
     pub async fn store_project_model(&self, project: &ProjectModel) -> Result<()> {
         self.projects_repository.store_project(project).await?;
         Ok(())
     }
 
-    #[instrument(skip_all, fields(project_id = project_id))]
+    #[instrument(skip_all, fields(project_id = project_id), level = Level::TRACE)]
     pub async fn delete_project(&self, project_id: &str) -> Result<()> {
         self.projects_repository.delete_project(project_id).await?;
         Ok(())
     }
 
-    #[instrument(skip_all, fields(project_id = project_id))]
+    #[instrument(skip_all, fields(project_id = project_id), level = Level::TRACE)]
     pub async fn set_default_project(&self, project_id: &str) -> Result<()> {
         self.projects_repository
             .set_default_project(project_id)
@@ -74,7 +75,7 @@ impl Projects {
         Ok(())
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn get_default_project(&self) -> Result<Project> {
         match self.projects_repository.get_default_project().await? {
             Some(project) => Ok(Project::import(project).await?),
@@ -86,7 +87,7 @@ impl Projects {
         }
     }
 
-    #[instrument(skip_all, fields(name = name))]
+    #[instrument(skip_all, fields(name = name), level = Level::TRACE)]
     pub async fn get_project_by_name(&self, name: &str) -> Result<Project> {
         match self.projects_repository.get_project_by_name(name).await? {
             Some(project) => Ok(Project::import(project).await?),
@@ -98,7 +99,7 @@ impl Projects {
         }
     }
 
-    #[instrument(skip_all, fields(project_id = project_id))]
+    #[instrument(skip_all, fields(project_id = project_id), level = Level::TRACE)]
     pub async fn get_project(&self, project_id: &str) -> Result<Project> {
         match self.projects_repository.get_project(project_id).await? {
             Some(project) => Ok(Project::import(project).await?),
@@ -110,7 +111,7 @@ impl Projects {
         }
     }
 
-    #[instrument(skip_all, fields(project_name = project_name.clone()))]
+    #[instrument(skip_all, fields(project_name = project_name.clone()), level = Level::TRACE)]
     pub async fn get_project_by_name_or_default(
         &self,
         project_name: &Option<String>,
@@ -121,7 +122,7 @@ impl Projects {
         }
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn get_projects(&self) -> Result<Vec<Project>> {
         let project_models = self.projects_repository.get_projects().await?;
 
@@ -134,7 +135,7 @@ impl Projects {
         Ok(projects)
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn get_projects_grouped_by_name(&self) -> Result<HashMap<String, Project>> {
         let mut projects = HashMap::new();
         for project in self.get_projects().await? {
diff --git a/implementations/rust/ockam/ockam_api/src/cli_state/spaces.rs b/implementations/rust/ockam/ockam_api/src/cli_state/spaces.rs
index c33571acbd6..12b8f0c6c98 100644
--- a/implementations/rust/ockam/ockam_api/src/cli_state/spaces.rs
+++ b/implementations/rust/ockam/ockam_api/src/cli_state/spaces.rs
@@ -1,5 +1,6 @@
 use ockam_core::errcode::{Kind, Origin};
 use ockam_core::Error;
+use tracing::Level;
 
 use crate::cli_state::CliState;
 use crate::orchestrator::space::Space;
@@ -8,7 +9,7 @@ use crate::orchestrator::subscription::Subscription;
 use super::Result;
 
 impl CliState {
-    #[instrument(skip_all, fields(space_id = space_id, space_name = space_name))]
+    #[instrument(skip_all, fields(space_id = space_id, space_name = space_name), level = Level::TRACE)]
     pub async fn store_space(
         &self,
         space_id: &str,
@@ -28,7 +29,7 @@ impl CliState {
         Ok(space)
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn get_default_space(&self) -> Result<Space> {
         match self.spaces_repository().get_default_space().await? {
             Some(space) => Ok(space),
@@ -40,7 +41,7 @@ impl CliState {
         }
     }
 
-    #[instrument(skip_all, fields(name = name))]
+    #[instrument(skip_all, fields(name = name), level = Level::TRACE)]
     pub async fn get_space_by_name(&self, name: &str) -> Result<Space> {
         match self.spaces_repository().get_space_by_name(name).await? {
             Some(space) => Ok(space),
@@ -52,7 +53,7 @@ impl CliState {
         }
     }
 
-    #[instrument(skip_all, fields(name = name))]
+    #[instrument(skip_all, fields(name = name), level = Level::TRACE)]
     pub async fn get_space_by_name_or_default(&self, name: &Option<String>) -> Result<Space> {
         match name {
             Some(name) => self.get_space_by_name(name.as_str()).await,
@@ -60,19 +61,19 @@ impl CliState {
         }
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn get_spaces(&self) -> Result<Vec<Space>> {
         Ok(self.spaces_repository().get_spaces().await?)
     }
 
-    #[instrument(skip_all, fields(space_id = space_id))]
+    #[instrument(skip_all, fields(space_id = space_id), level = Level::TRACE)]
     pub async fn delete_space(&self, space_id: &str) -> Result<()> {
         let repository = self.spaces_repository();
         repository.delete_space(space_id).await?;
         Ok(())
     }
 
-    #[instrument(skip_all, fields(space_id = space_id))]
+    #[instrument(skip_all, fields(space_id = space_id), level = Level::TRACE)]
     pub async fn set_space_as_default(&self, space_id: &str) -> Result<()> {
         Ok(self.spaces_repository().set_default_space(space_id).await?)
     }
diff --git a/implementations/rust/ockam/ockam_api/src/cli_state/tcp_portals.rs b/implementations/rust/ockam/ockam_api/src/cli_state/tcp_portals.rs
index 82d041ee0a9..252d9e53836 100644
--- a/implementations/rust/ockam/ockam_api/src/cli_state/tcp_portals.rs
+++ b/implementations/rust/ockam/ockam_api/src/cli_state/tcp_portals.rs
@@ -7,10 +7,11 @@ use ockam_core::Address;
 use ockam_multiaddr::MultiAddr;
 use ockam_transport_core::HostnamePort;
 use std::net::SocketAddr;
+use tracing::Level;
 
 impl CliState {
     /// Create a TCP inlet
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn create_tcp_inlet(
         &self,
         node_name: &str,
@@ -27,7 +28,7 @@ impl CliState {
     }
 
     /// Get a TCP inlet by node name and alias
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn get_tcp_inlet(&self, node_name: &str, alias: &str) -> Result<TcpInlet> {
         Ok(self
             .tcp_portals_repository()
@@ -43,7 +44,7 @@ impl CliState {
     }
 
     /// Delete a TCP inlet
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn delete_tcp_inlet(&self, node_name: &str, alias: &str) -> Result<()> {
         Ok(self
             .tcp_portals_repository()
@@ -52,7 +53,7 @@ impl CliState {
     }
 
     /// Create a TCP outlet
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn create_tcp_outlet(
         &self,
         node_name: &str,
@@ -71,7 +72,7 @@ impl CliState {
     }
 
     /// Delete a TCP outlet
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn delete_tcp_outlet(&self, node_name: &str, worker_addr: &Address) -> Result<()> {
         Ok(self
             .tcp_portals_repository()
diff --git a/implementations/rust/ockam/ockam_api/src/cli_state/trust.rs b/implementations/rust/ockam/ockam_api/src/cli_state/trust.rs
index c1317c2c225..fb1e7476cc0 100644
--- a/implementations/rust/ockam/ockam_api/src/cli_state/trust.rs
+++ b/implementations/rust/ockam/ockam_api/src/cli_state/trust.rs
@@ -10,6 +10,7 @@ use ockam_core::errcode::{Kind, Origin};
 use ockam_core::{Error, Result};
 use ockam_multiaddr::MultiAddr;
 use ockam_vault::SoftwareVaultForVerifyingSignatures;
+use tracing::Level;
 
 impl CliState {
     async fn retrieve_trust_options_explicit_project_authority(
@@ -187,7 +188,7 @@ impl CliState {
     ///  1. Either we explicitly know the Authority identity that we trust, and optionally route to its node to request
     ///     a new credential
     ///  2. Or we know the project name (or have default one) that contains identity and route to the Authority node
-    #[instrument(skip_all, fields(project_name = project_name.clone(), authority_identity = authority_identity.as_ref().map(|a| a.to_string()).unwrap_or("n/a".to_string()), authority_route = authority_route.clone().map_or("n/a".to_string(), |r| r.to_string())))]
+    #[instrument(skip_all, fields(project_name = project_name.clone(), authority_identity = authority_identity.as_ref().map(|a| a.to_string()).unwrap_or("n/a".to_string()), authority_route = authority_route.clone().map_or("n/a".to_string(), |r| r.to_string())), level = Level::TRACE)]
     pub async fn retrieve_trust_options(
         &self,
         project_name: &Option<String>,
diff --git a/implementations/rust/ockam/ockam_api/src/cli_state/users.rs b/implementations/rust/ockam/ockam_api/src/cli_state/users.rs
index 9ba48066b93..8436388a910 100644
--- a/implementations/rust/ockam/ockam_api/src/cli_state/users.rs
+++ b/implementations/rust/ockam/ockam_api/src/cli_state/users.rs
@@ -1,5 +1,6 @@
 use ockam_core::errcode::{Kind, Origin};
 use ockam_core::Error;
+use tracing::Level;
 
 use crate::cli_state::CliState;
 use crate::cli_state::Result;
@@ -7,20 +8,20 @@ use crate::orchestrator::email_address::EmailAddress;
 use crate::orchestrator::enroll::auth0::UserInfo;
 
 impl CliState {
-    #[instrument(skip_all, fields(user = %user))]
+    #[instrument(skip_all, fields(user = %user), level = Level::TRACE)]
     pub async fn store_user(&self, user: &UserInfo) -> Result<()> {
         let repository = self.users_repository();
         repository.store_user(user).await?;
         Ok(())
     }
 
-    #[instrument(skip_all, fields(email = %email))]
+    #[instrument(skip_all, fields(email = %email), level = Level::TRACE)]
     pub async fn set_default_user(&self, email: &EmailAddress) -> Result<()> {
         self.users_repository().set_default_user(email).await?;
         Ok(())
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn get_default_user(&self) -> Result<UserInfo> {
         let repository = self.users_repository();
         match repository.get_default_user().await? {
diff --git a/implementations/rust/ockam/ockam_api/src/cli_state/vaults.rs b/implementations/rust/ockam/ockam_api/src/cli_state/vaults.rs
index bd624f34233..8ba673cced5 100644
--- a/implementations/rust/ockam/ockam_api/src/cli_state/vaults.rs
+++ b/implementations/rust/ockam/ockam_api/src/cli_state/vaults.rs
@@ -12,6 +12,7 @@ use std::fmt::{Debug, Display, Formatter};
 use std::fs::OpenOptions;
 use std::path::{Path, PathBuf};
 use std::sync::Arc;
+use tracing::Level;
 
 static DEFAULT_VAULT_NAME: &str = "default";
 
@@ -26,7 +27,7 @@ impl CliState {
     /// If the path is not specified then:
     ///   - if this is the first vault then secrets are persisted in the main database
     ///   - if this is a new vault then secrets are persisted in $OCKAM_HOME/vault_name
-    #[instrument(skip_all, fields(vault_name = vault_name.clone()))]
+    #[instrument(skip_all, fields(vault_name = vault_name.clone()), level = Level::TRACE)]
     pub async fn create_named_vault(
         &self,
         vault_name: Option<String>,
@@ -74,7 +75,7 @@ impl CliState {
     }
 
     /// Delete an existing vault
-    #[instrument(skip_all, fields(vault_name = vault_name))]
+    #[instrument(skip_all, fields(vault_name = vault_name), level = Level::TRACE)]
     pub async fn delete_named_vault(&self, vault_name: &str) -> Result<()> {
         // first check that no identity is using the vault
         let identities_repository = self.identities_repository();
@@ -115,7 +116,7 @@ impl CliState {
     }
 
     /// Delete all named identities
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn delete_all_named_identities(&self) -> Result<()> {
         let identities_repository = self.identities_repository();
         let identities = identities_repository.get_named_identities().await?;
@@ -134,7 +135,7 @@ impl CliState {
     }
 
     /// Delete all vaults and their files
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn delete_all_named_vaults(&self) -> Result<()> {
         let vaults = self.vaults_repository().get_named_vaults().await?;
         for vault in vaults {
@@ -152,14 +153,14 @@ impl CliState {
 /// The methods below provide an API to query named vaults.
 impl CliState {
     /// Return all the named vaults
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn get_named_vaults(&self) -> Result<Vec<NamedVault>> {
         Ok(self.vaults_repository().get_named_vaults().await?)
     }
 
     /// Return the vault with a given name
     /// and raise an error if the vault is not found
-    #[instrument(skip_all, fields(vault_name = vault_name))]
+    #[instrument(skip_all, fields(vault_name = vault_name), level = Level::TRACE)]
     pub async fn get_named_vault(&self, vault_name: &str) -> Result<NamedVault> {
         let result = self.vaults_repository().get_named_vault(vault_name).await?;
         Ok(result.ok_or_else(|| {
@@ -174,7 +175,7 @@ impl CliState {
     /// Return a vault if it already exists, otherwise
     /// Create a new vault using a default path: either the database path for the first vault
     /// or a path using the vault name
-    #[instrument(skip_all, fields(vault_name = vault_name))]
+    #[instrument(skip_all, fields(vault_name = vault_name), level = Level::TRACE)]
     pub async fn get_or_create_named_vault(&self, vault_name: &str) -> Result<NamedVault> {
         let vaults_repository = self.vaults_repository();
 
@@ -229,7 +230,7 @@ impl CliState {
     /// Return the existing vault if there is only one
     /// If it doesn't exist, the vault is created with the name 'default'
     /// If there are more than one vaults, return an error
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn get_or_create_default_named_vault(&self) -> Result<NamedVault> {
         let vaults = self.vaults_repository().get_named_vaults().await?;
         match &vaults[..] {
@@ -248,7 +249,7 @@ impl CliState {
 
     /// Return either the default vault or a vault with the given name
     /// If the default vault is required and does not exist it is created.
-    #[instrument(skip_all, fields(vault_name = vault_name.clone()))]
+    #[instrument(skip_all, fields(vault_name = vault_name.clone()), level = Level::TRACE)]
     pub async fn get_named_vault_or_default(
         &self,
         vault_name: &Option<String>,
@@ -261,7 +262,7 @@ impl CliState {
 
     /// Move a vault file to another location if the vault is not the default vault
     /// contained in the main database
-    #[instrument(skip_all, fields(vault_name = vault_name, path = path.to_string_lossy().to_string()))]
+    #[instrument(skip_all, fields(vault_name = vault_name, path = path.to_string_lossy().to_string()), level = Level::TRACE)]
     pub async fn move_vault(&self, vault_name: &str, path: &Path) -> Result<()> {
         let repository = self.vaults_repository();
         let vault = self.get_named_vault(vault_name).await?;
@@ -292,7 +293,7 @@ impl CliState {
     }
 
     /// Make a concrete vault based on the NamedVault metadata
-    #[instrument(skip_all, fields(vault_name = named_vault.name))]
+    #[instrument(skip_all, fields(vault_name = named_vault.name), level = Level::TRACE)]
     pub async fn make_vault(&self, named_vault: NamedVault) -> Result<Vault> {
         let db = match named_vault.vault_type {
             VaultType::DatabaseVault { .. } => self.database(),
diff --git a/implementations/rust/ockam/ockam_api/src/echoer.rs b/implementations/rust/ockam/ockam_api/src/echoer.rs
index 1f33e3f1665..1ded7a3c88e 100644
--- a/implementations/rust/ockam/ockam_api/src/echoer.rs
+++ b/implementations/rust/ockam/ockam_api/src/echoer.rs
@@ -1,6 +1,7 @@
 use ockam::{Any, Context, Result, Routed, Worker};
 use ockam_core::NeutralMessage;
 use tracing as log;
+use tracing::Level;
 
 pub struct Echoer;
 
@@ -9,7 +10,7 @@ impl Worker for Echoer {
     type Context = Context;
     type Message = Any;
 
-    #[instrument(skip_all, name = "Echoer::handle_message")]
+    #[instrument(skip_all, name = "Echoer::handle_message", level = Level::TRACE)]
     async fn handle_message(&mut self, ctx: &mut Context, msg: Routed<Any>) -> Result<()> {
         log::debug!(src = %msg.src_addr(), from = %msg.sender()?, to = %msg.return_route().next()?, "echoing back");
         let msg = msg.into_local_message();
diff --git a/implementations/rust/ockam/ockam_api/src/enroll/enrollment.rs b/implementations/rust/ockam/ockam_api/src/enroll/enrollment.rs
index 04def5b1b77..2195a1f9514 100644
--- a/implementations/rust/ockam/ockam_api/src/enroll/enrollment.rs
+++ b/implementations/rust/ockam/ockam_api/src/enroll/enrollment.rs
@@ -8,6 +8,7 @@ use ockam::identity::SecureClient;
 use ockam_core::api::{Reply, Request, Status};
 use ockam_core::async_trait;
 use ockam_node::Context;
+use tracing::Level;
 
 const TARGET: &str = "ockam_api::cloud::enroll";
 
@@ -80,7 +81,7 @@ impl<T: HasSecureClient + Send + Sync> Enrollment for T {
 // FiXME: this has duplicate with AuthorityNodeClient
 #[async_trait]
 impl Enrollment for SecureClient {
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn enroll_with_oidc_token(
         &self,
         ctx: &Context,
@@ -105,7 +106,7 @@ impl Enrollment for SecureClient {
         }
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn enroll_with_oidc_token_okta(
         &self,
         ctx: &Context,
@@ -120,7 +121,7 @@ impl Enrollment for SecureClient {
             .into_diagnostic()
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn present_token(
         &self,
         ctx: &Context,
@@ -148,7 +149,7 @@ impl Enrollment for SecureClient {
         }
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn issue_credential(&self, ctx: &Context) -> miette::Result<CredentialAndPurposeKey> {
         let req = Request::post("/");
         trace!(target: TARGET, "getting a credential");
diff --git a/implementations/rust/ockam/ockam_api/src/enroll/oidc_service.rs b/implementations/rust/ockam/ockam_api/src/enroll/oidc_service.rs
index e1877691423..48b61cb379a 100644
--- a/implementations/rust/ockam/ockam_api/src/enroll/oidc_service.rs
+++ b/implementations/rust/ockam/ockam_api/src/enroll/oidc_service.rs
@@ -8,6 +8,7 @@ use serde::de::DeserializeOwned;
 use tiny_http::{HTTPVersion, Header, Response, Server};
 use tokio::time::Duration;
 use tokio_retry::{strategy::ExponentialBackoff, Retry};
+use tracing::Level;
 use tracing::{error, info};
 
 use crate::enroll::ockam_oidc_provider::{authenticator_endpoint, OckamOidcProvider};
@@ -52,7 +53,7 @@ impl OidcService {
 
     /// Request an authorization token with a PKCE flow
     /// See the full protocol here: https://datatracker.ietf.org/doc/html/rfc7636
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn get_token_with_pkce(&self) -> Result<OidcToken> {
         let code_verifier = self.create_code_verifier();
         let authorization_code = self.authorization_code(&code_verifier).await?;
@@ -247,18 +248,18 @@ impl OidcService {
                     // avoiding the browser to send multiple requests
                     // to the same server instance
                     let mut writer = request.into_writer();
-                    response.raw_print( &mut writer,
-                        HTTPVersion(1, 0),
-                        &[],
-                        true,
-                        None
-                    ).and_then(|_|writer.flush())
+                    response.raw_print(&mut writer,
+                                       HTTPVersion(1, 0),
+                                       &[],
+                                       true,
+                                       None,
+                    ).and_then(|_| writer.flush())
                         .map_err(|e| {
-                        ApiError::message(
-                            format!("error while trying to send a response to a request on {server_url}: {e}"),
-                        )
-                    })
-                },
+                            ApiError::message(
+                                format!("error while trying to send a response to a request on {server_url}: {e}"),
+                            )
+                        })
+                }
                 Ok(None) => Err(ApiError::message(
                     format!("timeout while trying to receive a request on {server_url} (waited for {redirect_timeout:?})"),
                 )),
diff --git a/implementations/rust/ockam/ockam_api/src/influxdb/lease_issuer/worker.rs b/implementations/rust/ockam/ockam_api/src/influxdb/lease_issuer/worker.rs
index 6f635b107ea..ab81b18ef22 100644
--- a/implementations/rust/ockam/ockam_api/src/influxdb/lease_issuer/worker.rs
+++ b/implementations/rust/ockam/ockam_api/src/influxdb/lease_issuer/worker.rs
@@ -17,6 +17,7 @@ use std::sync::Arc;
 use std::time::Duration;
 use time::OffsetDateTime;
 use tokio::sync::RwLock;
+use tracing::Level;
 
 #[derive(Clone)]
 pub(crate) struct InfluxDBTokenLessorWorker {
@@ -46,7 +47,7 @@ impl InfluxDBTokenLessorWorker {
         Ok(_self)
     }
 
-    #[instrument(skip_all, fields(method = ?request.header().method(), path = request.header().path()))]
+    #[instrument(skip_all, fields(method = ?request.header().method(), path = request.header().path()), level = Level::TRACE)]
     async fn handle_request(
         &mut self,
         _ctx: &mut Context,
@@ -98,7 +99,7 @@ impl Worker for InfluxDBTokenLessorWorker {
         Ok(())
     }
 
-    #[instrument(skip_all, name = "InfluxDBTokenLessorWorker::handle_message")]
+    #[instrument(skip_all, name = "InfluxDBTokenLessorWorker::handle_message", level = Level::TRACE)]
     async fn handle_message(
         &mut self,
         ctx: &mut Context,
diff --git a/implementations/rust/ockam/ockam_api/src/influxdb/portal.rs b/implementations/rust/ockam/ockam_api/src/influxdb/portal.rs
index ed26fdaad5b..8ba8828e334 100644
--- a/implementations/rust/ockam/ockam_api/src/influxdb/portal.rs
+++ b/implementations/rust/ockam/ockam_api/src/influxdb/portal.rs
@@ -25,6 +25,7 @@ use ockam_transport_tcp::{
 };
 use std::sync::Arc;
 use std::time::Duration;
+use tracing::Level;
 
 impl NodeManagerWorker {
     pub(crate) async fn start_influxdb_outlet_service(
@@ -333,7 +334,7 @@ pub trait InfluxDBPortals {
 
 #[async_trait]
 impl InfluxDBPortals for BackgroundNodeClient {
-    #[instrument(skip(self, ctx))]
+    #[instrument(skip(self, ctx), level = Level::TRACE)]
     #[allow(clippy::too_many_arguments)]
     async fn create_influxdb_outlet(
         &self,
@@ -354,7 +355,7 @@ impl InfluxDBPortals for BackgroundNodeClient {
         self.ask(ctx, req).await
     }
 
-    #[instrument(skip(self, ctx))]
+    #[instrument(skip(self, ctx), level = Level::TRACE)]
     #[allow(clippy::too_many_arguments)]
     async fn create_influxdb_inlet(
         &self,
diff --git a/implementations/rust/ockam/ockam_api/src/logs/setup.rs b/implementations/rust/ockam/ockam_api/src/logs/setup.rs
index 11db57fb430..abc6441ca47 100644
--- a/implementations/rust/ockam/ockam_api/src/logs/setup.rs
+++ b/implementations/rust/ockam/ockam_api/src/logs/setup.rs
@@ -8,7 +8,9 @@ use crate::logs::{
     OckamUserLogFormat, TelemetryEndpoint,
 };
 use crate::logs::{LogFormat, OckamSpanExporter};
+use crate::CliState;
 use gethostname::gethostname;
+use ockam_core::OCKAM_TRACER_NAME;
 use ockam_node::Context;
 use opentelemetry::trace::TracerProvider;
 use opentelemetry::{global, KeyValue};
@@ -22,6 +24,7 @@ use opentelemetry_sdk::trace::{BatchConfig, BatchConfigBuilder, BatchSpanProcess
 use opentelemetry_sdk::{logs, Resource};
 use opentelemetry_semantic_conventions::attribute;
 use std::io::{empty, stdout};
+use std::sync::Arc;
 use tonic::codec::CompressionEncoding;
 use tonic::metadata::*;
 use tracing_appender::non_blocking::NonBlocking;
@@ -45,29 +48,29 @@ impl LoggingTracing {
     ///
     /// The TracingGuard is used to flush all events when dropped.
     pub fn setup(
+        cli_state: Arc<CliState>,
         logging_configuration: &LoggingConfiguration,
         exporting_configuration: &ExportingConfiguration,
         app_name: &str,
-        node_name: Option<String>,
         ctx: &Context,
     ) -> TracingGuard {
         if exporting_configuration.is_enabled() && logging_configuration.is_enabled() {
             // set-up logging and tracing
             Self::setup_with_exporters(
+                cli_state,
                 create_span_exporter(exporting_configuration, ctx),
                 create_log_exporter(exporting_configuration, ctx),
                 logging_configuration,
                 exporting_configuration,
                 app_name,
-                node_name,
             )
         } else if exporting_configuration.is_enabled() {
             Self::setup_tracing_only(
+                cli_state,
                 create_span_exporter(exporting_configuration, ctx),
                 logging_configuration,
                 exporting_configuration,
                 app_name,
-                node_name,
             )
         } else {
             Self::setup_local_logging_only(logging_configuration)
@@ -81,12 +84,12 @@ impl LoggingTracing {
         T: SpanExporter + Send + 'static,
         L: LogExporter + Send + 'static,
     >(
+        cli_state: Arc<CliState>,
         span_exporter: T,
         log_exporter: L,
         logging_configuration: &LoggingConfiguration,
         exporting_configuration: &ExportingConfiguration,
         app_name: &str,
-        node_name: Option<String>,
     ) -> TracingGuard {
         // configure the logging layer exporting OpenTelemetry log records
         let (logging_layer, logger_provider) =
@@ -94,8 +97,8 @@ impl LoggingTracing {
 
         // configure the tracing layer exporting OpenTelemetry spans
         let (tracing_layer, tracer_provider) = create_opentelemetry_tracing_layer(
+            cli_state,
             app_name,
-            node_name,
             exporting_configuration,
             span_exporter,
         );
@@ -168,15 +171,15 @@ impl LoggingTracing {
     ///  - the LoggingConfiguration is used to filter spans (via its EnvFilter) and configure the global error handler
     ///  - the Exporting configuration is used to send spans and log records to an OpenTelemetry collector
     pub fn setup_tracing_only<T: SpanExporter + Send + 'static>(
+        cli_state: Arc<CliState>,
         span_exporter: T,
         logging_configuration: &LoggingConfiguration,
         exporting_configuration: &ExportingConfiguration,
         app_name: &str,
-        node_name: Option<String>,
     ) -> TracingGuard {
         let (tracing_layer, tracer_provider) = create_opentelemetry_tracing_layer(
+            cli_state,
             app_name,
-            node_name,
             exporting_configuration,
             span_exporter,
         );
@@ -262,8 +265,8 @@ fn create_opentelemetry_tracing_layer<
     R: Subscriber + Send + 'static + for<'a> LookupSpan<'a>,
     S: SpanExporter + Send + 'static,
 >(
+    cli_state: Arc<CliState>,
     app_name: &str,
-    node_name: Option<String>,
     exporting_configuration: &ExportingConfiguration,
     span_exporter: S,
 ) -> (
@@ -284,8 +287,8 @@ fn create_opentelemetry_tracing_layer<
         app,
         batch_config,
         OckamSpanExporter::new(
+            cli_state,
             span_exporter,
-            node_name,
             is_ockam_developer,
             span_export_cutoff,
         ),
@@ -402,7 +405,7 @@ fn create_tracer<S: SpanExporter + 'static>(
         .with_resource(make_resource(app_name))
         .build();
 
-    let tracer = provider.tracer("ockam");
+    let tracer = provider.tracer(OCKAM_TRACER_NAME);
     let _ = global::set_tracer_provider(provider.clone());
     (tracer, provider)
 }
diff --git a/implementations/rust/ockam/ockam_api/src/logs/span_exporters.rs b/implementations/rust/ockam/ockam_api/src/logs/span_exporters.rs
index 48e720a7f7f..5c0c21cca23 100644
--- a/implementations/rust/ockam/ockam_api/src/logs/span_exporters.rs
+++ b/implementations/rust/ockam/ockam_api/src/logs/span_exporters.rs
@@ -1,9 +1,20 @@
-use crate::cli_state::journeys::{APPLICATION_EVENT_NODE_NAME, APPLICATION_EVENT_OCKAM_DEVELOPER};
+use crate::cli_state::journeys::attributes::make_host;
+use crate::cli_state::journeys::{
+    APPLICATION_EVENT_HOST, APPLICATION_EVENT_NODE_IDENTIFIER, APPLICATION_EVENT_NODE_NAME,
+    APPLICATION_EVENT_OCKAM_DEVELOPER, APPLICATION_EVENT_PROJECT_ID,
+    APPLICATION_EVENT_PROJECT_NAME,
+};
+use crate::cli_state::NodeInfo;
+use crate::orchestrator::project::Project;
+use crate::CliState;
 use futures::future::BoxFuture;
+use futures::FutureExt;
 use ockam_core::async_trait;
 use opentelemetry::KeyValue;
 use opentelemetry_sdk::export::trace::{ExportResult, SpanData, SpanExporter};
+use std::sync::Arc;
 use std::time::Duration;
+use tokio::sync::Mutex;
 
 /// This exporter can be used to intercept the spans sent to an OpenTelemetry collector
 #[derive(Debug)]
@@ -38,22 +49,46 @@ impl<S: SpanExporter> DecoratedSpanExporter<S> {
 /// This exporter can be used to intercept the spans sent to an OpenTelemetry collector
 /// and add custom attributes
 #[derive(Debug)]
-pub struct OckamSpanExporter<S: SpanExporter> {
-    exporter: S,
-    node_name: Option<String>,
+pub struct OckamSpanExporter<S: SpanExporter + 'static> {
+    cli_state: Arc<CliState>,
+    exporter: Arc<Mutex<S>>,
     is_ockam_developer: bool,
     span_export_cutoff: Option<Duration>,
+    span_attributes: Arc<Mutex<Option<SpanAttributes>>>,
 }
 
 #[async_trait]
-impl<S: SpanExporter> SpanExporter for OckamSpanExporter<S> {
+impl<S: SpanExporter + 'static> SpanExporter for OckamSpanExporter<S> {
     fn export(&mut self, batch: Vec<SpanData>) -> BoxFuture<'static, ExportResult> {
-        let f = self.exporter.export(self.add_attributes(
-            batch,
-            self.node_name.clone(),
-            self.is_ockam_developer,
-        ));
+        let cli_state = self.cli_state.clone();
+        let is_ockam_developer = self.is_ockam_developer;
         let span_export_cutoff = self.span_export_cutoff;
+        let exporter = self.exporter.clone();
+        let span_attributes = self.span_attributes.clone();
+
+        let f = async move {
+            let mut exporter = exporter.lock().await;
+
+            // initialize span attributes from local data if they haven't been initialized yet.
+            let mut span_attributes = span_attributes.lock().await;
+            let attributes = if span_attributes.is_none() {
+                SpanAttributes {
+                    node_info: cli_state.get_default_node().await.ok(),
+                    project: cli_state.projects().get_default_project().await.ok(),
+                }
+            } else {
+                SpanAttributes::default()
+            };
+            *span_attributes = Some(attributes.clone());
+
+            exporter
+                .export(
+                    Self::add_attributes(&attributes, Self::filter(batch), is_ockam_developer)
+                        .await,
+                )
+                .await
+        }
+        .boxed();
 
         Box::pin(async move {
             match span_export_cutoff {
@@ -68,58 +103,102 @@ impl<S: SpanExporter> SpanExporter for OckamSpanExporter<S> {
 
     fn shutdown(&mut self) {
         debug!("shutting down the span exporter");
-        self.exporter.shutdown()
+        let mut exporter = self.exporter.blocking_lock();
+        exporter.shutdown();
     }
 
     fn force_flush(&mut self) -> BoxFuture<'static, ExportResult> {
         debug!("flushing the span exporter");
-        self.exporter.force_flush()
+        let exporter = self.exporter.clone();
+        async move {
+            let mut exporter = exporter.lock().await;
+            exporter.force_flush().await
+        }
+        .boxed()
     }
 }
 
 impl<S: SpanExporter> OckamSpanExporter<S> {
     pub fn new(
+        cli_state: Arc<CliState>,
         exporter: S,
-        node_name: Option<String>,
         is_ockam_developer: bool,
         span_export_cutoff: Option<Duration>,
     ) -> OckamSpanExporter<S> {
         OckamSpanExporter {
-            exporter,
-            node_name,
+            cli_state,
+            exporter: Arc::new(Mutex::new(exporter)),
             is_ockam_developer,
             span_export_cutoff,
+            span_attributes: Arc::new(Mutex::new(None)),
         }
     }
 
-    fn add_attributes(
-        &self,
+    async fn add_attributes(
+        span_attributes: &SpanAttributes,
         batch: Vec<SpanData>,
-        node_name: Option<String>,
         is_ockam_developer: bool,
     ) -> Vec<SpanData> {
-        batch
-            .into_iter()
-            .map(|s| self.add_attributes_to_span(s, node_name.clone(), is_ockam_developer))
-            .collect()
+        let mut result = vec![];
+        for span in batch.into_iter() {
+            result
+                .push(Self::add_attributes_to_span(span_attributes, span, is_ockam_developer).await)
+        }
+        result
     }
 
-    fn add_attributes_to_span(
-        &self,
+    async fn add_attributes_to_span(
+        span_attributes: &SpanAttributes,
         mut span: SpanData,
-        node_name: Option<String>,
         is_ockam_developer: bool,
     ) -> SpanData {
-        if let Some(node_name) = node_name {
+        if let Some(node_info) = &span_attributes.node_info {
             span.attributes.push(KeyValue::new(
                 APPLICATION_EVENT_NODE_NAME.clone(),
-                node_name,
+                node_info.name(),
+            ));
+            span.attributes.push(KeyValue::new(
+                APPLICATION_EVENT_NODE_IDENTIFIER.clone(),
+                node_info.identifier().to_string(),
             ));
         };
+
+        if let Some(project) = &span_attributes.project {
+            span.attributes.push(KeyValue::new(
+                APPLICATION_EVENT_PROJECT_ID.clone(),
+                project.project_id().to_string(),
+            ));
+            span.attributes.push(KeyValue::new(
+                APPLICATION_EVENT_PROJECT_NAME.clone(),
+                project.name().to_string(),
+            ));
+        };
+
         span.attributes.push(KeyValue::new(
             APPLICATION_EVENT_OCKAM_DEVELOPER.clone(),
             is_ockam_developer,
         ));
+        span.attributes
+            .push(KeyValue::new(APPLICATION_EVENT_HOST.clone(), make_host()));
         span
     }
+
+    fn filter(batch: Vec<SpanData>) -> Vec<SpanData> {
+        batch
+            .into_iter()
+            .filter_map(|s| Self::filter_span(s))
+            .collect()
+    }
+
+    fn filter_span(mut span: SpanData) -> Option<SpanData> {
+        // drop span events since they are log messages that we already send as logs records.
+        span.events.events = vec![];
+        Some(span)
+    }
+}
+
+#[derive(Debug, Clone, Eq, PartialEq, Default)]
+struct SpanAttributes {
+    node_info: Option<NodeInfo>,
+    project: Option<Project>,
 }
diff --git a/implementations/rust/ockam/ockam_api/src/nodes/service/background_node_client.rs b/implementations/rust/ockam/ockam_api/src/nodes/service/background_node_client.rs
index b29a89fc44a..99947ecec97 100644
--- a/implementations/rust/ockam/ockam_api/src/nodes/service/background_node_client.rs
+++ b/implementations/rust/ockam/ockam_api/src/nodes/service/background_node_client.rs
@@ -20,7 +20,7 @@ use crate::nodes::NODEMANAGER_ADDR;
 /// and expect responses with a value of type `R`
 #[derive(Clone)]
 pub struct BackgroundNodeClient {
-    cli_state: CliState,
+    cli_state: Arc<CliState>,
     node_name: String,
     to: Route,
     timeout: Option<Duration>,
@@ -36,7 +36,7 @@ impl BackgroundNodeClient {
     /// a node specified by the user or the default node if no node name is given.
     pub async fn create(
         ctx: &Context,
-        cli_state: &CliState,
+        cli_state: Arc<CliState>,
         node_name: &Option<String>,
     ) -> miette::Result<BackgroundNodeClient> {
         let node_name = match node_name.clone() {
@@ -48,7 +48,7 @@ impl BackgroundNodeClient {
 
     pub fn create_to_node(
         ctx: &Context,
-        cli_state: &CliState,
+        cli_state: Arc<CliState>,
         node_name: &str,
     ) -> miette::Result<BackgroundNodeClient> {
         let tcp_transport = TcpTransport::get_or_create(ctx).into_diagnostic()?;
@@ -57,7 +57,7 @@ impl BackgroundNodeClient {
 
     pub async fn create_to_node_with_tcp(
         tcp: &TcpTransport,
-        cli_state: &CliState,
+        cli_state: Arc<CliState>,
         node_name: &str,
     ) -> miette::Result<BackgroundNodeClient> {
         BackgroundNodeClient::new(tcp, cli_state, node_name)
@@ -66,7 +66,7 @@ impl BackgroundNodeClient {
     /// Create a new client to send requests to a running background node
     pub fn new(
         tcp_transport: &TcpTransport,
-        cli_state: &CliState,
+        cli_state: Arc<CliState>,
         node_name: &str,
     ) -> miette::Result<BackgroundNodeClient> {
         Ok(BackgroundNodeClient {
diff --git a/implementations/rust/ockam/ockam_api/src/nodes/service/in_memory_node.rs b/implementations/rust/ockam/ockam_api/src/nodes/service/in_memory_node.rs
index 5937434aead..a5e73c24dec 100644
--- a/implementations/rust/ockam/ockam_api/src/nodes/service/in_memory_node.rs
+++ b/implementations/rust/ockam/ockam_api/src/nodes/service/in_memory_node.rs
@@ -3,6 +3,7 @@ use std::time::Duration;
 
 use futures::executor;
 use miette::IntoDiagnostic;
+use tracing::Level;
 
 use ockam::identity::models::ChangeHistory;
 use ockam::identity::{Identifier, SecureChannels};
@@ -83,14 +84,14 @@ impl InMemoryNode {
     }
 
     /// Start an in memory node
-    pub async fn start(ctx: &Context, cli_state: &CliState) -> miette::Result<Self> {
+    pub async fn start(ctx: &Context, cli_state: Arc<CliState>) -> miette::Result<Self> {
         Self::start_with_project_name(ctx, cli_state, None).await
     }
 
     /// Start an in memory node with some project
     pub async fn start_with_project_name(
         ctx: &Context,
-        cli_state: &CliState,
+        cli_state: Arc<CliState>,
         project_name: Option<String>,
     ) -> miette::Result<Self> {
         let default_identity_name = cli_state
@@ -112,7 +113,7 @@ impl InMemoryNode {
     /// Start an in memory node with some identity and project
     pub async fn start_with_identity_and_project_name(
         ctx: &Context,
-        cli_state: &CliState,
+        cli_state: Arc<CliState>,
         identity: Option<String>,
         project_name: Option<String>,
     ) -> miette::Result<Self> {
@@ -123,7 +124,7 @@ impl InMemoryNode {
     /// Start an in memory node with a specific identity
     pub async fn start_with_identity(
         ctx: &Context,
-        cli_state: &CliState,
+        cli_state: Arc<CliState>,
         identity: Option<String>,
     ) -> miette::Result<InMemoryNode> {
         let identity = cli_state.get_identity_name_or_default(&identity).await?;
@@ -131,10 +132,10 @@ impl InMemoryNode {
     }
 
     /// Start an in memory node
-    #[instrument(name = "start in-memory node", skip_all)]
+    #[instrument(name = "start in-memory node", skip_all, level = Level::TRACE)]
     pub async fn start_node(
         ctx: &Context,
-        cli_state: &CliState,
+        cli_state: Arc<CliState>,
         identity_name: &str,
         status_endpoint: Option<BindAddress>,
         project_name: Option<String>,
@@ -215,7 +216,7 @@ impl InMemoryNode {
     }
 
     /// Create a new in memory node with various options
-    #[instrument(name = "new in-memory node", skip_all, fields(node_name = general_options.node_name))]
+    #[instrument(name = "new in-memory node", skip_all, fields(node_name = general_options.node_name), level = Level::TRACE)]
     pub async fn new(
         ctx: &Context,
         general_options: NodeManagerGeneralOptions,
@@ -344,12 +345,12 @@ mod tests {
 
     #[ockam::test]
     async fn test_start_twice(ctx: &mut Context) -> Result<()> {
-        let cli = CliState::test().await?;
+        let cli = Arc::new(CliState::test().await?);
 
-        let node_manager1 = InMemoryNode::start(ctx, &cli).await;
+        let node_manager1 = InMemoryNode::start(ctx, cli.clone()).await;
         assert!(node_manager1.is_ok());
 
-        let node_manager2 = InMemoryNode::start(ctx, &cli).await;
+        let node_manager2 = InMemoryNode::start(ctx, cli).await;
         if let Err(e) = node_manager2 {
             panic!("cannot start the node manager a second time: {e:?}");
         }
diff --git a/implementations/rust/ockam/ockam_api/src/nodes/service/manager.rs b/implementations/rust/ockam/ockam_api/src/nodes/service/manager.rs
index a1dbead07d1..fe9a8a65a27 100644
--- a/implementations/rust/ockam/ockam_api/src/nodes/service/manager.rs
+++ b/implementations/rust/ockam/ockam_api/src/nodes/service/manager.rs
@@ -44,6 +44,7 @@ use ockam_node::Context;
 use std::net::SocketAddr;
 use std::sync::Arc;
 use std::time::Duration;
+use tracing::Level;
 
 /// Node manager provides high-level operations to
 ///  - send messages
@@ -51,7 +52,7 @@ use std::time::Duration;
 ///  - configure the trust
 ///  - manage persistent data
 pub struct NodeManager {
-    pub(crate) cli_state: CliState,
+    pub(crate) cli_state: Arc<CliState>,
     pub(super) node_name: String,
     pub(super) node_identifier: Identifier,
     pub(crate) api_transport_flow_control_ids: Vec<FlowControlId>,
@@ -66,7 +67,7 @@ pub struct NodeManager {
 
 impl NodeManager {
     /// Create a new NodeManager with the node name from the ockam CLI
-    #[instrument(name = "create_node_manager", skip_all, fields(node_name = general_options.node_name))]
+    #[instrument(name = "create_node_manager", skip_all, fields(node_name = general_options.node_name), level = Level::TRACE)]
     pub async fn create(
         ctx: &Context,
         general_options: NodeManagerGeneralOptions,
@@ -438,7 +439,7 @@ impl NodeManager {
 
     /// Wait until the project is ready to be used
     /// At this stage the project authority node must be up and running
-    #[instrument(skip_all, fields(project_id = project.project_id()))]
+    #[instrument(skip_all, fields(project_id = project.project_id()), level = Level::TRACE)]
     pub async fn wait_until_project_is_ready(
         &self,
         ctx: &Context,
@@ -668,7 +669,7 @@ impl NodeManager {
 
 #[derive(Debug)]
 pub struct NodeManagerGeneralOptions {
-    pub(super) cli_state: CliState,
+    pub(super) cli_state: Arc<CliState>,
     pub(super) node_name: String,
     pub(super) start_default_services: bool,
     pub(super) status_endpoint: Option<BindAddress>,
@@ -677,7 +678,7 @@ pub struct NodeManagerGeneralOptions {
 
 impl NodeManagerGeneralOptions {
     pub fn new(
-        cli_state: CliState,
+        cli_state: Arc<CliState>,
         node_name: String,
         start_default_services: bool,
         status_endpoint: Option<BindAddress>,
diff --git a/implementations/rust/ockam/ockam_api/src/nodes/service/messages.rs b/implementations/rust/ockam/ockam_api/src/nodes/service/messages.rs
index 0af0293f042..2742ac659e0 100644
--- a/implementations/rust/ockam/ockam_api/src/nodes/service/messages.rs
+++ b/implementations/rust/ockam/ockam_api/src/nodes/service/messages.rs
@@ -9,6 +9,7 @@ use ockam_multiaddr::MultiAddr;
 use ockam_node::{Context, MessageSendReceiveOptions};
 use std::str::FromStr;
 use std::time::Duration;
+use tracing::Level;
 
 const TARGET: &str = "ockam_api::message";
 
@@ -25,7 +26,7 @@ pub trait Messages {
 
 #[async_trait]
 impl Messages for NodeManager {
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn send_message<T: Message, R: Message>(
         &self,
         ctx: &Context,
@@ -56,7 +57,7 @@ impl Messages for NodeManager {
 
 #[async_trait]
 impl Messages for BackgroundNodeClient {
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn send_message<T: Message, R: Message>(
         &self,
         ctx: &Context,
diff --git a/implementations/rust/ockam/ockam_api/src/nodes/service/node_services.rs b/implementations/rust/ockam/ockam_api/src/nodes/service/node_services.rs
index 770d749f623..e7154b81124 100644
--- a/implementations/rust/ockam/ockam_api/src/nodes/service/node_services.rs
+++ b/implementations/rust/ockam/ockam_api/src/nodes/service/node_services.rs
@@ -4,6 +4,7 @@ use ockam::{Address, Context, Result};
 use ockam_abac::{Action, Resource, ResourceType};
 use ockam_core::api::{Error, Response};
 use ockam_node::WorkerBuilder;
+use tracing::Level;
 
 use crate::echoer::Echoer;
 use crate::error::ApiError;
@@ -79,7 +80,7 @@ impl NodeManagerWorker {
         Ok(Response::ok().body(ServiceStatusList(self.node_manager.list_services())))
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub(super) async fn get_node_status(&self) -> Result<Response<NodeStatus>, Response<Error>> {
         match self.node_manager.get_node_status().await {
             Ok(node_status) => Ok(Response::ok().body(node_status)),
@@ -87,7 +88,7 @@ impl NodeManagerWorker {
         }
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub(super) async fn get_node_resources(
         &self,
     ) -> Result<Response<NodeResources>, Response<Error>> {
diff --git a/implementations/rust/ockam/ockam_api/src/nodes/service/projects.rs b/implementations/rust/ockam/ockam_api/src/nodes/service/projects.rs
index ce013745d37..db1376898cb 100644
--- a/implementations/rust/ockam/ockam_api/src/nodes/service/projects.rs
+++ b/implementations/rust/ockam/ockam_api/src/nodes/service/projects.rs
@@ -4,10 +4,11 @@ use crate::orchestrator::project::models::{AdminInfo, OrchestratorVersionInfo};
 use crate::orchestrator::project::{Project, ProjectsOrchestratorApi};
 use ockam_core::async_trait;
 use ockam_node::Context;
+use tracing::Level;
 
 #[async_trait]
 impl ProjectsOrchestratorApi for InMemoryNode {
-    #[instrument(skip_all, fields(project_name = project_name, space_name = space_name))]
+    #[instrument(skip_all, fields(project_name = project_name, space_name = space_name), level = Level::TRACE)]
     async fn create_project(
         &self,
         ctx: &Context,
@@ -28,7 +29,7 @@ impl ProjectsOrchestratorApi for InMemoryNode {
         Ok(project)
     }
 
-    #[instrument(skip_all, fields(project_id = project_id))]
+    #[instrument(skip_all, fields(project_id = project_id), level = Level::TRACE)]
     async fn get_project(&self, ctx: &Context, project_id: &str) -> miette::Result<Project> {
         let controller = self.create_controller().await?;
 
@@ -46,7 +47,7 @@ impl ProjectsOrchestratorApi for InMemoryNode {
         }
     }
 
-    #[instrument(skip_all, fields(project_name = project_name))]
+    #[instrument(skip_all, fields(project_name = project_name), level = Level::TRACE)]
     async fn get_project_by_name_or_default(
         &self,
         ctx: &Context,
@@ -62,7 +63,7 @@ impl ProjectsOrchestratorApi for InMemoryNode {
         self.get_project(ctx, &project_id).await
     }
 
-    #[instrument(skip_all, fields(project_name = project_name))]
+    #[instrument(skip_all, fields(project_name = project_name), level = Level::TRACE)]
     async fn get_project_by_name(
         &self,
         ctx: &Context,
@@ -78,7 +79,7 @@ impl ProjectsOrchestratorApi for InMemoryNode {
         self.get_project(ctx, &project_id).await
     }
 
-    #[instrument(skip_all, fields(project_id = project_id, space_id = space_id))]
+    #[instrument(skip_all, fields(project_id = project_id, space_id = space_id), level = Level::TRACE)]
     async fn delete_project(
         &self,
         ctx: &Context,
@@ -91,7 +92,7 @@ impl ProjectsOrchestratorApi for InMemoryNode {
         Ok(self.cli_state.projects().delete_project(project_id).await?)
     }
 
-    #[instrument(skip_all, fields(project_name = project_name, space_name = space_name))]
+    #[instrument(skip_all, fields(project_name = project_name, space_name = space_name), level = Level::TRACE)]
     async fn delete_project_by_name(
         &self,
         ctx: &Context,
@@ -108,7 +109,7 @@ impl ProjectsOrchestratorApi for InMemoryNode {
             .await
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn get_orchestrator_version_info(
         &self,
         ctx: &Context,
@@ -120,7 +121,7 @@ impl ProjectsOrchestratorApi for InMemoryNode {
             .await?)
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn get_admin_projects(&self, ctx: &Context) -> miette::Result<Vec<Project>> {
         // If there is no user in the database, the identity used an enrollment ticket
         // but it didn't enroll to the Orchestrator. Therefore, it won't have any admin projects.
@@ -151,7 +152,7 @@ impl ProjectsOrchestratorApi for InMemoryNode {
 
     /// Wait until the operation associated with the project creation is complete
     /// At this stage the project node must be up and running
-    #[instrument(skip_all, fields(project_id = project.project_id()))]
+    #[instrument(skip_all, fields(project_id = project.project_id()), level = Level::TRACE)]
     async fn wait_until_project_creation_operation_is_complete(
         &self,
         ctx: &Context,
@@ -172,7 +173,7 @@ impl ProjectsOrchestratorApi for InMemoryNode {
 
     /// Wait until the project is ready to be used
     /// At this stage the project authority node must be up and running
-    #[instrument(skip_all, fields(project_id = project.project_id()))]
+    #[instrument(skip_all, fields(project_id = project.project_id()), level = Level::TRACE)]
     async fn wait_until_project_is_ready(
         &self,
         ctx: &Context,
diff --git a/implementations/rust/ockam/ockam_api/src/nodes/service/tcp_inlets/in_memory_node.rs b/implementations/rust/ockam/ockam_api/src/nodes/service/tcp_inlets/in_memory_node.rs
index a4bc8c7f611..51e4bf41987 100644
--- a/implementations/rust/ockam/ockam_api/src/nodes/service/tcp_inlets/in_memory_node.rs
+++ b/implementations/rust/ockam/ockam_api/src/nodes/service/tcp_inlets/in_memory_node.rs
@@ -6,13 +6,14 @@ use ockam_multiaddr::MultiAddr;
 use ockam_node::Context;
 use ockam_transport_core::HostnamePort;
 use std::time::Duration;
+use tracing::Level;
 
 use crate::nodes::models::portal::InletStatus;
 use crate::nodes::InMemoryNode;
 
 impl InMemoryNode {
     #[allow(clippy::too_many_arguments)]
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn create_inlet(
         &self,
         ctx: &Context,
diff --git a/implementations/rust/ockam/ockam_api/src/nodes/service/tcp_inlets/node_manager.rs b/implementations/rust/ockam/ockam_api/src/nodes/service/tcp_inlets/node_manager.rs
index bb8fd70c0f1..39805fb9564 100644
--- a/implementations/rust/ockam/ockam_api/src/nodes/service/tcp_inlets/node_manager.rs
+++ b/implementations/rust/ockam/ockam_api/src/nodes/service/tcp_inlets/node_manager.rs
@@ -1,5 +1,6 @@
 use std::sync::Arc;
 use std::time::Duration;
+use tracing::Level;
 
 use crate::address::get_free_address_for;
 use ockam::identity::Identifier;
@@ -22,7 +23,7 @@ use crate::session::session::{AdditionalSessionOptions, Session};
 
 impl NodeManager {
     #[allow(clippy::too_many_arguments)]
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn create_inlet(
         self: &Arc<Self>,
         ctx: &Context,
diff --git a/implementations/rust/ockam/ockam_api/src/nodes/service/tcp_inlets/node_manager_worker.rs b/implementations/rust/ockam/ockam_api/src/nodes/service/tcp_inlets/node_manager_worker.rs
index ce30fe500c9..484a6c1f611 100644
--- a/implementations/rust/ockam/ockam_api/src/nodes/service/tcp_inlets/node_manager_worker.rs
+++ b/implementations/rust/ockam/ockam_api/src/nodes/service/tcp_inlets/node_manager_worker.rs
@@ -1,6 +1,7 @@
 use ockam::{route, Result};
 use ockam_core::api::{Error, Response};
 use ockam_node::Context;
+use tracing::Level;
 
 use crate::nodes::models::portal::{CreateInlet, InletStatus, InletStatusList};
 use crate::nodes::NodeManagerWorker;
@@ -11,7 +12,7 @@ impl NodeManagerWorker {
         Ok(Response::ok().body(InletStatusList(inlets)))
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub(crate) async fn create_inlet(
         &self,
         ctx: &Context,
diff --git a/implementations/rust/ockam/ockam_api/src/nodes/service/tcp_outlets.rs b/implementations/rust/ockam/ockam_api/src/nodes/service/tcp_outlets.rs
index 1cebe54df49..85d46f08eb1 100644
--- a/implementations/rust/ockam/ockam_api/src/nodes/service/tcp_outlets.rs
+++ b/implementations/rust/ockam/ockam_api/src/nodes/service/tcp_outlets.rs
@@ -6,6 +6,7 @@ use ockam_core::api::{Error, Request, Response};
 use ockam_core::async_trait;
 use ockam_core::errcode::{Kind, Origin};
 use ockam_node::Context;
+use tracing::Level;
 
 use crate::nodes::models::portal::{
     CreateOutlet, OutletAccessControl, OutletStatus, OutletStatusList,
@@ -17,7 +18,7 @@ use crate::nodes::BackgroundNodeClient;
 use super::{NodeManager, NodeManagerWorker};
 
 impl NodeManagerWorker {
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub(super) async fn create_outlet(
         &self,
         ctx: &Context,
@@ -94,7 +95,7 @@ impl NodeManagerWorker {
 
 impl NodeManager {
     #[allow(clippy::too_many_arguments)]
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn create_outlet(
         &self,
         ctx: &Context,
@@ -266,7 +267,7 @@ pub trait Outlets {
 
 #[async_trait]
 impl Outlets for BackgroundNodeClient {
-    #[instrument(skip_all, fields(to = % to, from = ? from))]
+    #[instrument(skip_all, fields(to = % to, from = ? from), level = Level::TRACE)]
     async fn create_outlet(
         &self,
         ctx: &Context,
diff --git a/implementations/rust/ockam/ockam_api/src/nodes/service/worker.rs b/implementations/rust/ockam/ockam_api/src/nodes/service/worker.rs
index f67b1e1052c..54c9af94168 100644
--- a/implementations/rust/ockam/ockam_api/src/nodes/service/worker.rs
+++ b/implementations/rust/ockam/ockam_api/src/nodes/service/worker.rs
@@ -9,6 +9,7 @@ use ockam_core::{Address, Decodable, Result, Routed, Worker};
 use ockam_node::Context;
 use std::error::Error;
 use std::sync::Arc;
+use tracing::Level;
 
 #[derive(Clone)]
 pub struct NodeManagerWorker {
@@ -31,7 +32,7 @@ impl NodeManagerWorker {
 impl NodeManagerWorker {
     //////// Request matching and response handling ////////
 
-    #[instrument(skip_all, fields(method = ?request.header().method(), path = request.header().path()))]
+    #[instrument(skip_all, fields(method = ?request.header().method(), path = request.header().path()), level = Level::TRACE)]
     async fn handle_request(
         &mut self,
         ctx: &mut Context,
diff --git a/implementations/rust/ockam/ockam_api/src/orchestrator/addon.rs b/implementations/rust/ockam/ockam_api/src/orchestrator/addon.rs
index a52359d623d..23cb3989cdb 100644
--- a/implementations/rust/ockam/ockam_api/src/orchestrator/addon.rs
+++ b/implementations/rust/ockam/ockam_api/src/orchestrator/addon.rs
@@ -2,6 +2,7 @@ use miette::IntoDiagnostic;
 use minicbor::{CborLen, Decode, Encode};
 use serde::{Deserialize, Serialize};
 use std::fmt::Write;
+use tracing::Level;
 
 use crate::orchestrator::operation::CreateOperationResponse;
 use crate::orchestrator::project::models::{InfluxDBTokenLeaseManagerConfig, OktaConfig};
@@ -165,7 +166,7 @@ pub trait Addons {
 
 #[async_trait]
 impl Addons for ControllerClient {
-    #[instrument(skip_all, fields(project_id = project_id))]
+    #[instrument(skip_all, fields(project_id = project_id), level = Level::TRACE)]
     async fn list_addons(&self, ctx: &Context, project_id: &str) -> miette::Result<Vec<Addon>> {
         trace!(project_id, "listing addons");
         let req = Request::get(format!("/v0/{project_id}/addons"));
@@ -178,7 +179,7 @@ impl Addons for ControllerClient {
         Ok(addon_list.0)
     }
 
-    #[instrument(skip_all, fields(project_id = project_id))]
+    #[instrument(skip_all, fields(project_id = project_id), level = Level::TRACE)]
     async fn configure_confluent_addon(
         &self,
         ctx: &Context,
@@ -197,7 +198,7 @@ impl Addons for ControllerClient {
             .miette_success("configure kafka addon")
     }
 
-    #[instrument(skip_all, fields(project_id = project_id))]
+    #[instrument(skip_all, fields(project_id = project_id), level = Level::TRACE)]
     async fn configure_okta_addon(
         &self,
         ctx: &Context,
@@ -214,7 +215,7 @@ impl Addons for ControllerClient {
             .miette_success("configure okta addon")
     }
 
-    #[instrument(skip_all, fields(project_id = project_id))]
+    #[instrument(skip_all, fields(project_id = project_id), level = Level::TRACE)]
     async fn configure_influxdb_addon(
         &self,
         ctx: &Context,
@@ -234,7 +235,7 @@ impl Addons for ControllerClient {
             .miette_success("configure influxdb addon")
     }
 
-    #[instrument(skip_all, fields(project_id = project_id, addon_id = addon_id))]
+    #[instrument(skip_all, fields(project_id = project_id, addon_id = addon_id), level = Level::TRACE)]
     async fn disable_addon(
         &self,
         ctx: &Context,
diff --git a/implementations/rust/ockam/ockam_api/src/orchestrator/operation.rs b/implementations/rust/ockam/ockam_api/src/orchestrator/operation.rs
index ca08f50cbfa..a4e528a3a86 100644
--- a/implementations/rust/ockam/ockam_api/src/orchestrator/operation.rs
+++ b/implementations/rust/ockam/ockam_api/src/orchestrator/operation.rs
@@ -8,7 +8,7 @@ use ockam_node::Context;
 use serde::{Deserialize, Serialize};
 use tokio_retry::strategy::FixedInterval;
 use tokio_retry::Retry;
-use tracing::trace;
+use tracing::{trace, Level};
 
 #[derive(Encode, Decode, CborLen, Serialize, Deserialize, Debug, Clone, Message)]
 #[cbor(map)]
@@ -92,7 +92,7 @@ const API_SERVICE: &str = "projects";
 
 #[async_trait]
 impl Operations for ControllerClient {
-    #[instrument(skip_all, fields(operation_id = operation_id))]
+    #[instrument(skip_all, fields(operation_id = operation_id), level = Level::TRACE)]
     async fn get_operation(
         &self,
         ctx: &Context,
@@ -108,7 +108,7 @@ impl Operations for ControllerClient {
             .into_diagnostic()
     }
 
-    #[instrument(skip_all, fields(operation_id = operation_id))]
+    #[instrument(skip_all, fields(operation_id = operation_id), level = Level::TRACE)]
     async fn wait_until_operation_is_complete(
         &self,
         ctx: &Context,
diff --git a/implementations/rust/ockam/ockam_api/src/orchestrator/project/controller_client.rs b/implementations/rust/ockam/ockam_api/src/orchestrator/project/controller_client.rs
index 97551939c37..c8fdb439409 100644
--- a/implementations/rust/ockam/ockam_api/src/orchestrator/project/controller_client.rs
+++ b/implementations/rust/ockam/ockam_api/src/orchestrator/project/controller_client.rs
@@ -8,6 +8,7 @@ use super::models::AdminInfo;
 use miette::{miette, IntoDiagnostic};
 use tokio_retry::strategy::FixedInterval;
 use tokio_retry::Retry;
+use tracing::Level;
 
 use crate::orchestrator::email_address::EmailAddress;
 use crate::orchestrator::project::Project;
@@ -203,7 +204,7 @@ impl ControllerClient {
         Ok(())
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn list_projects(&self, ctx: &Context) -> miette::Result<Vec<ProjectModel>> {
         let req = Request::get("/v0");
         let project_model_list: ProjectModelList = self
diff --git a/implementations/rust/ockam/ockam_api/src/orchestrator/project/operations.rs b/implementations/rust/ockam/ockam_api/src/orchestrator/project/operations.rs
index 415f6ed2331..29ac9abd8ac 100644
--- a/implementations/rust/ockam/ockam_api/src/orchestrator/project/operations.rs
+++ b/implementations/rust/ockam/ockam_api/src/orchestrator/project/operations.rs
@@ -2,10 +2,11 @@ use crate::nodes::InMemoryNode;
 use crate::orchestrator::operation::{Operation, Operations};
 use ockam_core::async_trait;
 use ockam_node::Context;
+use tracing::Level;
 
 #[async_trait]
 impl Operations for InMemoryNode {
-    #[instrument(skip_all, fields(operation_id = operation_id))]
+    #[instrument(skip_all, fields(operation_id = operation_id), level = Level::TRACE)]
     async fn get_operation(
         &self,
         ctx: &Context,
@@ -17,7 +18,7 @@ impl Operations for InMemoryNode {
             .await
     }
 
-    #[instrument(skip_all, fields(operation_id = operation_id))]
+    #[instrument(skip_all, fields(operation_id = operation_id), level = Level::TRACE)]
     async fn wait_until_operation_is_complete(
         &self,
         ctx: &Context,
diff --git a/implementations/rust/ockam/ockam_api/src/orchestrator/project/project.rs b/implementations/rust/ockam/ockam_api/src/orchestrator/project/project.rs
index 5b0ceeed0ff..271c22f5fac 100644
--- a/implementations/rust/ockam/ockam_api/src/orchestrator/project/project.rs
+++ b/implementations/rust/ockam/ockam_api/src/orchestrator/project/project.rs
@@ -18,7 +18,7 @@ use ockam_core::{Error, Result};
 use ockam_multiaddr::MultiAddr;
 use ockam_node::tokio;
 
-#[derive(Debug, Clone, Serialize)]
+#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
 pub struct Project {
     #[serde(flatten)]
     model: ProjectModel,
diff --git a/implementations/rust/ockam/ockam_api/src/orchestrator/secure_clients.rs b/implementations/rust/ockam/ockam_api/src/orchestrator/secure_clients.rs
index 218094fdc5b..413c364c1cd 100644
--- a/implementations/rust/ockam/ockam_api/src/orchestrator/secure_clients.rs
+++ b/implementations/rust/ockam/ockam_api/src/orchestrator/secure_clients.rs
@@ -1,6 +1,7 @@
 use std::fmt::{Display, Formatter};
 use std::str::FromStr;
 use std::time::Duration;
+use tracing::Level;
 
 use ockam::identity::{
     get_default_timeout, CredentialRetrieverCreator, Identifier, SecureChannels, SecureClient,
@@ -44,7 +45,7 @@ impl Display for CredentialsEnabled {
 }
 
 impl NodeManager {
-    #[instrument(skip_all, fields(authority_identifier = %authority_identifier.clone(), authority_route = %authority_route.clone(), caller = %caller_identifier.clone()))]
+    #[instrument(skip_all, fields(authority_identifier = %authority_identifier.clone(), authority_route = %authority_route.clone(), caller = %caller_identifier.clone()), level = Level::TRACE)]
     pub(crate) async fn make_authority_node_client(
         &self,
         authority_identifier: &Identifier,
@@ -63,7 +64,8 @@ impl NodeManager {
         .await
     }
 
-    #[instrument(skip_all, fields(project_identifier = %project_identifier.clone(), project_multiaddr = %project_multiaddr.clone(), caller = %caller_identifier.clone(), credentials_enabled = %credentials_enabled))]
+    #[instrument(skip_all, fields(project_identifier = %project_identifier.clone(), project_multiaddr = %project_multiaddr.clone(), caller = %caller_identifier.clone(), credentials_enabled = %credentials_enabled
+    ), level = Level::TRACE)]
     pub(crate) async fn make_project_node_client(
         &self,
         project_identifier: &Identifier,
@@ -89,7 +91,8 @@ impl NodeManager {
         .await
     }
 
-    #[instrument(skip_all, fields(identifier = %identifier.clone(), multiaddr = %multiaddr.clone(), caller = %caller_identifier.clone()))]
+    #[instrument(skip_all, fields(identifier = %identifier.clone(), multiaddr = %multiaddr.clone(), caller = %caller_identifier.clone()
+    ), level = Level::TRACE)]
     pub async fn make_secure_client(
         &self,
         identifier: &Identifier,
@@ -106,7 +109,7 @@ impl NodeManager {
         .await
     }
 
-    #[instrument(skip_all, fields(caller = %caller_identifier.clone()))]
+    #[instrument(skip_all, fields(caller = %caller_identifier.clone()), level = Level::TRACE)]
     pub async fn controller_node_client(
         &self,
         tcp_transport: &TcpTransport,
@@ -130,7 +133,8 @@ impl NodeManager {
         })
     }
 
-    #[instrument(skip_all, fields(authority_identifier = %authority_identifier.clone(), authority_route = %authority_route.clone(), caller = %caller_identifier.clone()))]
+    #[instrument(skip_all, fields(authority_identifier = %authority_identifier.clone(), authority_route = %authority_route.clone(), caller = %caller_identifier.clone()
+    ), level = Level::TRACE)]
     pub async fn authority_node_client(
         tcp_transport: Arc<TcpTransport>,
         secure_channels: Arc<SecureChannels>,
@@ -164,7 +168,8 @@ impl NodeManager {
         })
     }
 
-    #[instrument(skip_all, fields(project_identifier = %project_identifier.clone(), project_multiaddr = %project_multiaddr.clone(), caller = %caller_identifier.clone()))]
+    #[instrument(skip_all, fields(project_identifier = %project_identifier.clone(), project_multiaddr = %project_multiaddr.clone(), caller = %caller_identifier.clone()
+    ), level = Level::TRACE)]
     pub async fn project_node_client(
         tcp_transport: &TcpTransport,
         secure_channels: Arc<SecureChannels>,
diff --git a/implementations/rust/ockam/ockam_api/src/orchestrator/share/create.rs b/implementations/rust/ockam/ockam_api/src/orchestrator/share/create.rs
index 0c8141f8183..2195aa1948f 100644
--- a/implementations/rust/ockam/ockam_api/src/orchestrator/share/create.rs
+++ b/implementations/rust/ockam/ockam_api/src/orchestrator/share/create.rs
@@ -1,5 +1,6 @@
 use minicbor::{CborLen, Decode, Encode};
 use serde::{Deserialize, Serialize};
+use std::sync::Arc;
 
 use crate::Result;
 
@@ -67,7 +68,7 @@ impl Decodable for CreateServiceInvitation {
 
 impl CreateServiceInvitation {
     pub async fn new<S: AsRef<str>>(
-        cli_state: &CliState,
+        cli_state: Arc<CliState>,
         expires_at: Option<String>,
         project_name: S,
         recipient_email: EmailAddress,
diff --git a/implementations/rust/ockam/ockam_api/src/orchestrator/space.rs b/implementations/rust/ockam/ockam_api/src/orchestrator/space.rs
index c3814f64326..4dcf0e532dc 100644
--- a/implementations/rust/ockam/ockam_api/src/orchestrator/space.rs
+++ b/implementations/rust/ockam/ockam_api/src/orchestrator/space.rs
@@ -2,6 +2,7 @@ use miette::IntoDiagnostic;
 use minicbor::{CborLen, Decode, Encode};
 use serde::Serialize;
 use std::fmt::{Display, Formatter, Write};
+use tracing::Level;
 
 use ockam::Message;
 use ockam_core::api::Request;
@@ -220,7 +221,7 @@ pub trait Spaces {
 
 #[async_trait]
 impl Spaces for InMemoryNode {
-    #[instrument(skip_all, fields(space_name = name))]
+    #[instrument(skip_all, fields(space_name = name), level = Level::TRACE)]
     async fn create_space(
         &self,
         ctx: &Context,
@@ -240,7 +241,7 @@ impl Spaces for InMemoryNode {
         Ok(space)
     }
 
-    #[instrument(skip_all, fields(space_id = space_id))]
+    #[instrument(skip_all, fields(space_id = space_id), level = Level::TRACE)]
     async fn get_space(&self, ctx: &Context, space_id: &str) -> miette::Result<Space> {
         let controller = self.create_controller().await?;
         let space = controller.get_space(ctx, space_id).await?;
@@ -255,7 +256,7 @@ impl Spaces for InMemoryNode {
         Ok(space)
     }
 
-    #[instrument(skip_all, fields(space_name = space_name))]
+    #[instrument(skip_all, fields(space_name = space_name), level = Level::TRACE)]
     async fn get_space_by_name(&self, ctx: &Context, space_name: &str) -> miette::Result<Space> {
         let space_id = self
             .cli_state
@@ -265,7 +266,7 @@ impl Spaces for InMemoryNode {
         self.get_space(ctx, &space_id).await
     }
 
-    #[instrument(skip_all, fields(space_id = space_id))]
+    #[instrument(skip_all, fields(space_id = space_id), level = Level::TRACE)]
     async fn delete_space(&self, ctx: &Context, space_id: &str) -> miette::Result<()> {
         let space_projects = self
             .cli_state
@@ -286,7 +287,7 @@ impl Spaces for InMemoryNode {
         Ok(())
     }
 
-    #[instrument(skip_all, fields(space_name = space_name))]
+    #[instrument(skip_all, fields(space_name = space_name), level = Level::TRACE)]
     async fn delete_space_by_name(&self, ctx: &Context, space_name: &str) -> miette::Result<()> {
         let space_id = self
             .cli_state
@@ -296,7 +297,7 @@ impl Spaces for InMemoryNode {
         self.delete_space(ctx, &space_id).await
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn get_spaces(&self, ctx: &Context) -> miette::Result<Vec<Space>> {
         let controller = self.create_controller().await?;
         let spaces = controller.list_spaces(ctx).await?;
diff --git a/implementations/rust/ockam/ockam_api/src/orchestrator/subscription.rs b/implementations/rust/ockam/ockam_api/src/orchestrator/subscription.rs
index 8c3f60c0f11..4f64a1d3cbb 100644
--- a/implementations/rust/ockam/ockam_api/src/orchestrator/subscription.rs
+++ b/implementations/rust/ockam/ockam_api/src/orchestrator/subscription.rs
@@ -18,6 +18,7 @@ use serde::{Deserialize, Serialize};
 use std::fmt::{Display, Formatter, Write};
 use std::str::FromStr;
 use strum::{Display, EnumString};
+use tracing::Level;
 use url::Url;
 
 const API_SERVICE: &str = "subscriptions";
@@ -363,7 +364,7 @@ pub trait Subscriptions {
 
 #[async_trait]
 impl Subscriptions for ControllerClient {
-    #[instrument(skip_all, fields(space_id = space_id, subscription_data = subscription_data))]
+    #[instrument(skip_all, fields(space_id = space_id, subscription_data = subscription_data), level = Level::TRACE)]
     async fn activate_subscription(
         &self,
         ctx: &Context,
@@ -379,7 +380,7 @@ impl Subscriptions for ControllerClient {
             .miette_success("subscription legacy")
     }
 
-    #[instrument(skip_all, fields(subscription_id = subscription_id))]
+    #[instrument(skip_all, fields(subscription_id = subscription_id), level = Level::TRACE)]
     async fn unsubscribe(
         &self,
         ctx: &Context,
@@ -393,7 +394,7 @@ impl Subscriptions for ControllerClient {
             .miette_success("subscription legacy")
     }
 
-    #[instrument(skip_all, fields(subscription_id = subscription_id, contact_info = contact_info))]
+    #[instrument(skip_all, fields(subscription_id = subscription_id, contact_info = contact_info), level = Level::TRACE)]
     async fn update_subscription_contact_info(
         &self,
         ctx: &Context,
@@ -408,7 +409,7 @@ impl Subscriptions for ControllerClient {
             .miette_success("subscription legacy")
     }
 
-    #[instrument(skip_all, fields(subscription_id = subscription_id, new_space_id = new_space_id))]
+    #[instrument(skip_all, fields(subscription_id = subscription_id, new_space_id = new_space_id), level = Level::TRACE)]
     async fn update_subscription_space(
         &self,
         ctx: &Context,
@@ -424,7 +425,7 @@ impl Subscriptions for ControllerClient {
             .miette_success("subscription legacy")
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn get_subscriptions(&self, ctx: &Context) -> miette::Result<Vec<SubscriptionLegacy>> {
         trace!("listing subscriptions");
         let req = Request::get("/v0/");
@@ -433,7 +434,7 @@ impl Subscriptions for ControllerClient {
         Ok(subscription_legacy_list.success()?.0)
     }
 
-    #[instrument(skip_all, fields(subscription_id = subscription_id))]
+    #[instrument(skip_all, fields(subscription_id = subscription_id), level = Level::TRACE)]
     async fn get_subscription(
         &self,
         ctx: &Context,
@@ -446,7 +447,7 @@ impl Subscriptions for ControllerClient {
         Ok(reply.found()?)
     }
 
-    #[instrument(skip_all, fields(space_id = space_id))]
+    #[instrument(skip_all, fields(space_id = space_id), level = Level::TRACE)]
     async fn get_subscription_by_space_id(
         &self,
         ctx: &Context,
diff --git a/implementations/rust/ockam/ockam_api/src/test_utils/mod.rs b/implementations/rust/ockam/ockam_api/src/test_utils/mod.rs
index fdc8d187c82..65f8b6af6d3 100644
--- a/implementations/rust/ockam/ockam_api/src/test_utils/mod.rs
+++ b/implementations/rust/ockam/ockam_api/src/test_utils/mod.rs
@@ -35,7 +35,7 @@ use crate::nodes::{NodeManagerWorker, NODEMANAGER_ADDR};
 ///   temporary directory, and possibly of sub-processes.
 /// - useful access to the NodeManager
 pub struct NodeManagerHandle {
-    pub cli_state: CliState,
+    pub cli_state: Arc<CliState>,
     pub node_manager: Arc<InMemoryNode>,
     pub tcp: Arc<TcpTransport>,
     pub secure_channels: Arc<SecureChannels>,
@@ -67,7 +67,7 @@ pub async fn start_manager_for_tests(
         )
         .await?;
 
-    let cli_state = CliState::system().await?;
+    let cli_state = Arc::new(CliState::system().await?);
 
     let node_name = random_name();
     cli_state
diff --git a/implementations/rust/ockam/ockam_api/src/ui/terminal/notification.rs b/implementations/rust/ockam/ockam_api/src/ui/terminal/notification.rs
index 5762df9d7c8..dc87319bf13 100644
--- a/implementations/rust/ockam/ockam_api/src/ui/terminal/notification.rs
+++ b/implementations/rust/ockam/ockam_api/src/ui/terminal/notification.rs
@@ -74,7 +74,7 @@ pub struct NotificationHandler<T: TerminalWriter + Debug + Send + 'static> {
 impl<T: TerminalWriter + Debug + Send + 'static> NotificationHandler<T> {
     /// Create a new NotificationsProgress without progress bar.
     /// The notifications are printed as they arrive and stay on screen
-    pub fn start(cli_state: &CliState, terminal: Terminal<T>) -> NotificationHandle {
+    pub fn start(cli_state: Arc<CliState>, terminal: Terminal<T>) -> NotificationHandle {
         let stop = Arc::new(AtomicBool::new(false));
         let _self = NotificationHandler {
             rx: cli_state.subscribe_to_notifications(),
diff --git a/implementations/rust/ockam/ockam_api/src/uppercase.rs b/implementations/rust/ockam/ockam_api/src/uppercase.rs
index 450e9973ba0..8b59a4f3210 100644
--- a/implementations/rust/ockam/ockam_api/src/uppercase.rs
+++ b/implementations/rust/ockam/ockam_api/src/uppercase.rs
@@ -1,4 +1,5 @@
 use ockam::{Context, Result, Routed, Worker};
+use tracing::Level;
 
 pub struct Uppercase;
 
@@ -7,7 +8,7 @@ impl Worker for Uppercase {
     type Message = String;
     type Context = Context;
 
-    #[instrument(skip_all, name = "Uppercase::handle_message")]
+    #[instrument(skip_all, name = "Uppercase::handle_message", level = Level::TRACE)]
     async fn handle_message(&mut self, ctx: &mut Context, msg: Routed<String>) -> Result<()> {
         let return_route = msg.return_route().clone();
         ctx.send(return_route.clone(), msg.into_body()?.to_uppercase())
diff --git a/implementations/rust/ockam/ockam_api/tests/journeys.rs b/implementations/rust/ockam/ockam_api/tests/journeys.rs
index d7acb815f31..c1333686f1b 100644
--- a/implementations/rust/ockam/ockam_api/tests/journeys.rs
+++ b/implementations/rust/ockam/ockam_api/tests/journeys.rs
@@ -2,6 +2,7 @@ use chrono::Utc;
 use ockam_api::cli_state::journeys::{
     JourneyEvent, APPLICATION_EVENT_TIMESTAMP, EVENT_DURATION, USER_EMAIL, USER_NAME,
 };
+use ockam_api::cli_state::{random_name, CliStateMode};
 use ockam_api::logs::{
     get_https_endpoint, ExportingConfiguration, ExportingEnabled, LoggingConfiguration,
     LoggingTracing,
@@ -14,8 +15,7 @@ use opentelemetry_sdk::testing::logs::InMemoryLogExporter;
 use opentelemetry_sdk::testing::trace::InMemorySpanExporter;
 use std::collections::HashMap;
 use std::ops::Add;
-
-use ockam_api::cli_state::{random_name, CliStateMode};
+use std::sync::Arc;
 use tempfile::NamedTempFile;
 
 /// This test needs to be an integration test
@@ -25,15 +25,18 @@ use tempfile::NamedTempFile;
 async fn test_create_journey_event() {
     let db_file = NamedTempFile::new().unwrap();
     let cli_state_directory = db_file.path().parent().unwrap().join(random_name());
-    let cli = CliState::create(CliStateMode::Persistent(cli_state_directory))
-        .await
-        .unwrap()
-        .set_tracing_enabled(true);
+    let cli_state = Arc::new(
+        CliState::create(CliStateMode::Persistent(cli_state_directory))
+            .await
+            .unwrap()
+            .set_tracing_enabled(true),
+    );
 
     let span_exporter = InMemorySpanExporter::default();
     let log_exporter = InMemoryLogExporter::default();
     let endpoint = get_https_endpoint().unwrap();
     let tracing_guard = LoggingTracing::setup_with_exporters(
+        cli_state.clone(),
         span_exporter.clone(),
         log_exporter.clone(),
         &LoggingConfiguration::off()
@@ -45,7 +48,6 @@ async fn test_create_journey_event() {
         )
         .unwrap(),
         "test",
-        None,
     );
     let tracer = global::tracer("ockam-test");
     let span = tracer.start("user event");
@@ -56,15 +58,18 @@ async fn test_create_journey_event() {
     let mut map = HashMap::new();
     map.insert(USER_EMAIL, "etorreborre@yahoo.com".to_string());
     map.insert(USER_NAME, "eric".to_string());
-    cli.add_journey_event(JourneyEvent::Enrolled, map.clone())
+    cli_state
+        .add_journey_event(JourneyEvent::Enrolled, map.clone())
         .with_context(cx.clone())
         .await
         .unwrap();
-    cli.add_journey_event(JourneyEvent::PortalCreated, map)
+    cli_state
+        .add_journey_event(JourneyEvent::PortalCreated, map)
         .with_context(cx.clone())
         .await
         .unwrap();
-    cli.add_journey_error("command", "sorry".to_string(), HashMap::default())
+    cli_state
+        .add_journey_error("command", "sorry".to_string(), HashMap::default())
         .with_context(cx.clone())
         .await
         .unwrap();
diff --git a/implementations/rust/ockam/ockam_api/tests/logging_tracing.rs b/implementations/rust/ockam/ockam_api/tests/logging_tracing.rs
index af5aa61cfcf..1f10ad09a00 100644
--- a/implementations/rust/ockam/ockam_api/tests/logging_tracing.rs
+++ b/implementations/rust/ockam/ockam_api/tests/logging_tracing.rs
@@ -8,9 +8,11 @@ use opentelemetry::trace::Tracer;
 use opentelemetry_sdk::testing::logs::InMemoryLogExporter;
 use opentelemetry_sdk::testing::trace::InMemorySpanExporter;
 use std::fs;
+use std::sync::Arc;
 use tempfile::NamedTempFile;
 
 use ockam_api::cli_state::random_name;
+use ockam_api::CliState;
 use tracing::{error, info};
 use tracing_core::Level;
 
@@ -25,6 +27,7 @@ async fn test_log_and_traces() {
     let log_exporter = InMemoryLogExporter::default();
     let endpoint = get_https_endpoint().unwrap();
     let guard = LoggingTracing::setup_with_exporters(
+        Arc::new(CliState::test().await.unwrap()),
         span_exporter.clone(),
         log_exporter.clone(),
         &make_configuration()
@@ -36,7 +39,6 @@ async fn test_log_and_traces() {
         )
         .unwrap(),
         "test",
-        None,
     );
 
     let tracer = global::tracer("ockam-test");
diff --git a/implementations/rust/ockam/ockam_app_lib/src/incoming_services/state.rs b/implementations/rust/ockam/ockam_app_lib/src/incoming_services/state.rs
index b32cc51c625..76ccf9c2a80 100644
--- a/implementations/rust/ockam/ockam_app_lib/src/incoming_services/state.rs
+++ b/implementations/rust/ockam/ockam_app_lib/src/incoming_services/state.rs
@@ -330,6 +330,7 @@ mod tests {
     use ockam_api::orchestrator::share::{
         InvitationWithAccess, ReceivedInvitation, RoleInShare, ServiceAccessDetails, ShareScope,
     };
+    use std::sync::Arc;
 
     use crate::incoming_services::PersistentIncomingService;
     use crate::state::AppState;
@@ -375,7 +376,7 @@ mod tests {
     async fn test_inlet_data_from_invitation(context: &mut Context) -> ockam::Result<()> {
         // in this test we want to validate data loading from the accepted invitation
         // as well as using the related persistent data
-        let app_state = AppState::test(context, CliState::test().await?).await;
+        let app_state = AppState::test(context, Arc::new(CliState::test().await?)).await;
 
         let mut invitation = create_invitation_with(None);
 
diff --git a/implementations/rust/ockam/ockam_app_lib/src/invitations/mod.rs b/implementations/rust/ockam/ockam_app_lib/src/invitations/mod.rs
index 40fc55c5f47..184492809f5 100644
--- a/implementations/rust/ockam/ockam_app_lib/src/invitations/mod.rs
+++ b/implementations/rust/ockam/ockam_app_lib/src/invitations/mod.rs
@@ -34,7 +34,7 @@ impl AppState {
         let project = cli_state.projects().get_default_project().await?;
 
         Ok(CreateServiceInvitation::new(
-            &cli_state,
+            cli_state,
             None,
             project.name().to_string(),
             recipient_email.clone(),
diff --git a/implementations/rust/ockam/ockam_app_lib/src/log.rs b/implementations/rust/ockam/ockam_app_lib/src/log.rs
index 5a1c949c5ad..aeaedb1ed9f 100644
--- a/implementations/rust/ockam/ockam_app_lib/src/log.rs
+++ b/implementations/rust/ockam/ockam_app_lib/src/log.rs
@@ -30,6 +30,7 @@ impl AppState {
             .unwrap()
             .add_crates(vec!["ockam_app_lib"]);
         let tracing_guard = LoggingTracing::setup(
+            state.clone(),
             &logging_configuration(
                 level_and_crates,
                 Some(node_dir),
@@ -42,7 +43,6 @@ impl AppState {
                 .await
                 .unwrap(),
             "portals",
-            Some("portals".to_string()),
             ctx,
         );
         self.tracing_guard
diff --git a/implementations/rust/ockam/ockam_app_lib/src/shared_service/relay/create.rs b/implementations/rust/ockam/ockam_app_lib/src/shared_service/relay/create.rs
index 3627e5a8df8..4f3efb61067 100644
--- a/implementations/rust/ockam/ockam_app_lib/src/shared_service/relay/create.rs
+++ b/implementations/rust/ockam/ockam_app_lib/src/shared_service/relay/create.rs
@@ -34,8 +34,8 @@ impl AppState {
             self.publish_state().await;
 
             debug!("Not enrolled, skipping relay creation");
-            match get_relay(&node_manager, &cli_state).await {
-                Ok(_) => match delete_relay(&node_manager, &cli_state).await {
+            match get_relay(&node_manager, cli_state.clone()).await {
+                Ok(_) => match delete_relay(&node_manager, cli_state.clone()).await {
                     Ok(_) => {
                         info!("Relay deleted");
                     }
@@ -51,7 +51,7 @@ impl AppState {
         }
 
         let result = self
-            .create_relay_impl(&context, &cli_state, node_manager.clone())
+            .create_relay_impl(&context, cli_state, node_manager.clone())
             .await;
 
         if let Err(e) = result {
@@ -65,13 +65,13 @@ impl AppState {
     async fn create_relay_impl(
         &self,
         context: &Context,
-        cli_state: &CliState,
+        cli_state: Arc<CliState>,
         node_manager: Arc<InMemoryNode>,
     ) -> Result<()> {
         trace!("Creating relay");
         match cli_state.projects().get_default_project().await {
             Ok(project) => {
-                if let Some(_relay) = get_relay(&node_manager, cli_state).await? {
+                if let Some(_relay) = get_relay(&node_manager, cli_state.clone()).await? {
                     debug!(project = %project.name(), "Relay already exists");
                     self.update_orchestrator_status(OrchestratorStatus::Connected);
                     self.publish_state().await;
@@ -108,16 +108,19 @@ impl AppState {
     }
 }
 
-async fn delete_relay(node_manager: &InMemoryNode, cli_state: &CliState) -> ockam_core::Result<()> {
+async fn delete_relay(
+    node_manager: &InMemoryNode,
+    cli_state: Arc<CliState>,
+) -> ockam_core::Result<()> {
     let remote_address = relay_remote_address(cli_state).await?;
     node_manager.delete_relay(&remote_address).await
 }
 
 async fn get_relay(
     node_manager: &InMemoryNode,
-    cli_state: &CliState,
+    cli_state: Arc<CliState>,
 ) -> ockam::Result<Option<RelayInfo>> {
-    let relay_alias = relay_alias(cli_state).await?;
+    let relay_alias = relay_alias(cli_state.clone()).await?;
     Ok(node_manager
         .get_relays()
         .await
@@ -125,12 +128,12 @@ async fn get_relay(
         .find(|r| r.name() == relay_alias))
 }
 
-async fn relay_remote_address(cli_state: &CliState) -> ockam::Result<String> {
+async fn relay_remote_address(cli_state: Arc<CliState>) -> ockam::Result<String> {
     let bare_relay_name = relay_alias(cli_state).await?;
     Ok(format!("forward_to_{bare_relay_name}"))
 }
 
-async fn relay_alias(cli_state: &CliState) -> ockam::Result<String> {
+async fn relay_alias(cli_state: Arc<CliState>) -> ockam::Result<String> {
     Ok(cli_state
         .get_or_create_default_named_identity()
         .await?
diff --git a/implementations/rust/ockam/ockam_app_lib/src/state/mod.rs b/implementations/rust/ockam/ockam_app_lib/src/state/mod.rs
index fbfb13da2fb..56c5954baf9 100644
--- a/implementations/rust/ockam/ockam_app_lib/src/state/mod.rs
+++ b/implementations/rust/ockam/ockam_app_lib/src/state/mod.rs
@@ -59,7 +59,7 @@ pub const PROJECT_NAME: &str = "default";
 #[derive(Clone)]
 pub struct AppState {
     context: Arc<Context>,
-    state: Arc<RwLock<CliState>>,
+    state: Arc<RwLock<Arc<CliState>>>,
     orchestrator_status: Arc<Mutex<OrchestratorStatus>>,
     model_state: Arc<RwLock<ModelState>>,
     model_state_repository: Arc<RwLock<Arc<dyn ModelStateRepository>>>,
@@ -79,7 +79,7 @@ pub struct AppState {
     pub(crate) tracing_guard: Arc<OnceLock<TracingGuard>>,
 }
 
-async fn create_node_manager(ctx: Arc<Context>, cli_state: &CliState) -> Arc<InMemoryNode> {
+async fn create_node_manager(ctx: Arc<Context>, cli_state: Arc<CliState>) -> Arc<InMemoryNode> {
     match make_node_manager(ctx.clone(), cli_state).await {
         Ok(w) => w,
         Err(e) => {
@@ -111,7 +111,7 @@ impl AppState {
                 context,
                 Some(application_state_callback),
                 Some(notification_callback),
-                cli_state,
+                Arc::new(cli_state),
             )
             .await
         };
@@ -121,7 +121,7 @@ impl AppState {
 
     /// Creates a new AppState for testing purposes
     #[cfg(test)]
-    pub async fn test(context: &Context, cli_state: CliState) -> AppState {
+    pub async fn test(context: &Context, cli_state: Arc<CliState>) -> AppState {
         Self::make(
             Arc::new(context.try_clone().unwrap()),
             None,
@@ -135,11 +135,11 @@ impl AppState {
         context: Arc<Context>,
         application_state_callback: Option<ApplicationStateCallback>,
         notification_callback: Option<NotificationCallback>,
-        cli_state: CliState,
+        cli_state: Arc<CliState>,
     ) -> AppState {
         // create the application state and its dependencies
-        let node_manager = create_node_manager(context.clone(), &cli_state).await;
-        let model_state_repository = create_model_state_repository(&cli_state);
+        let node_manager = create_node_manager(context.clone(), cli_state.clone()).await;
+        let model_state_repository = create_model_state_repository(cli_state.clone());
         let model_state = model_state_repository
             .load(&node_manager.node_name())
             .await
@@ -284,7 +284,7 @@ impl AppState {
             let mut writer = self.model_state.write().await;
             *writer = ModelState::default();
         }
-        let cli_state = &self.state().await;
+        let cli_state = self.state().await;
         let new_state_repository = create_model_state_repository(cli_state);
         {
             let mut writer = self.model_state_repository.write().await;
@@ -300,7 +300,7 @@ impl AppState {
         let mut state = self.state.write().await;
         match state.recreate().await {
             Ok(s) => {
-                *state = s;
+                *state = s.into();
                 info!("reset the cli state");
             }
             Err(e) => error!("Failed to reset the state {e:?}"),
@@ -325,7 +325,7 @@ impl AppState {
         }
         info!("stopped all the ctx workers");
 
-        let new_node_manager = make_node_manager(self.context.clone(), &self.state().await).await?;
+        let new_node_manager = make_node_manager(self.context.clone(), self.state().await).await?;
         *node_manager = new_node_manager;
         info!("set a new node manager");
         Ok(())
@@ -359,7 +359,7 @@ impl AppState {
 
     /// Return the application cli state
     /// This can be used to manage the on-disk state for projects, identities, vaults, etc...
-    pub async fn state(&self) -> CliState {
+    pub async fn state(&self) -> Arc<CliState> {
         let state = self.state.read().await;
         state.clone()
     }
@@ -391,7 +391,7 @@ impl AppState {
     pub async fn background_node(&self, node_name: &str) -> Result<BackgroundNodeClient> {
         let tcp = self.node_manager.read().await.tcp_transport().try_clone()?;
         Ok(
-            BackgroundNodeClient::create_to_node_with_tcp(&tcp, &self.state().await, node_name)
+            BackgroundNodeClient::create_to_node_with_tcp(&tcp, self.state().await, node_name)
                 .await?,
         )
     }
@@ -684,7 +684,7 @@ impl AppState {
 /// Make a node manager with a default node called "default"
 pub(crate) async fn make_node_manager(
     ctx: Arc<Context>,
-    cli_state: &CliState,
+    cli_state: Arc<CliState>,
 ) -> miette::Result<Arc<InMemoryNode>> {
     let tcp = TcpTransport::get_or_create(&ctx).into_diagnostic()?;
     let options = TcpListenerOptions::new();
@@ -729,6 +729,6 @@ pub(crate) async fn make_node_manager(
 }
 
 /// Create the repository containing the model state
-fn create_model_state_repository(state: &CliState) -> Arc<dyn ModelStateRepository> {
+fn create_model_state_repository(state: Arc<CliState>) -> Arc<dyn ModelStateRepository> {
     Arc::new(ModelStateSqlxDatabase::new(state.database()))
 }
diff --git a/implementations/rust/ockam/ockam_command/src/admin/subscription.rs b/implementations/rust/ockam/ockam_command/src/admin/subscription.rs
index 5b34e0b4c60..87cc092dfed 100644
--- a/implementations/rust/ockam/ockam_command/src/admin/subscription.rs
+++ b/implementations/rust/ockam/ockam_command/src/admin/subscription.rs
@@ -136,7 +136,7 @@ impl SubscriptionCommand {
     }
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
-        let node = InMemoryNode::start(ctx, &opts.state).await?;
+        let node = InMemoryNode::start(ctx, opts.state.clone()).await?;
         let controller = node.create_controller().await?;
 
         match &self.subcommand {
diff --git a/implementations/rust/ockam/ockam_command/src/command.rs b/implementations/rust/ockam/ockam_command/src/command.rs
index 2e55692567a..d248eae4451 100644
--- a/implementations/rust/ockam/ockam_command/src/command.rs
+++ b/implementations/rust/ockam/ockam_command/src/command.rs
@@ -24,7 +24,8 @@ use opentelemetry::global;
 use opentelemetry::trace::{FutureExt, Link, SpanBuilder, TraceContextExt, Tracer};
 use opentelemetry::Context as OtelContext;
 use std::process::exit;
-use tracing::{debug, info, instrument, warn};
+use std::sync::Arc;
+use tracing::{debug, info, instrument, warn, Level};
 
 const ABOUT: &str = include_str!("./static/about.txt");
 const LONG_ABOUT: &str = include_str!("./static/long_about.txt");
@@ -102,6 +103,7 @@ impl OckamCommand {
     /// If the node is a background node we always enable logging, regardless of environment variables
     fn setup_logging_tracing(
         &self,
+        cli_state: Arc<CliState>,
         logging_configuration: &LoggingConfiguration,
         exporting_configuration: &ExportingConfiguration,
         ctx: &Context,
@@ -110,16 +112,16 @@ impl OckamCommand {
             return None;
         };
 
-        let app_name = if self.subcommand.is_background_node() {
+        let app_name = if self.subcommand.is_local_node() {
             "local node"
         } else {
             "cli"
         };
         let tracing_guard = LoggingTracing::setup(
+            cli_state,
             logging_configuration,
             exporting_configuration,
             app_name,
-            self.subcommand.node_name(),
             ctx,
         );
 
@@ -212,16 +214,26 @@ impl OckamCommand {
             let cli_state = self.init_cli_state(in_memory).await;
             let exporting_configuration =
                 self.make_exporting_configuration(&cli_state, ctx).await?;
-            let tracing_guard =
-                self.setup_logging_tracing(&logging_configuration, &exporting_configuration, ctx);
             let cli_state = cli_state.set_tracing_enabled(exporting_configuration.is_enabled());
+            let cli_state = Arc::new(cli_state);
+            let tracing_guard = self.setup_logging_tracing(
+                cli_state.clone(),
+                &logging_configuration,
+                &exporting_configuration,
+                ctx,
+            );
 
             (exporting_configuration, tracing_guard, Some(cli_state))
         } else {
             // Allows having logging enabled before initializing CliState
             let exporting_configuration = ExportingConfiguration::off().into_diagnostic()?;
-            let tracing_guard =
-                self.setup_logging_tracing(&logging_configuration, &exporting_configuration, ctx);
+            let cli_state = self.init_cli_state(true).await;
+            let tracing_guard = self.setup_logging_tracing(
+                Arc::new(cli_state),
+                &logging_configuration,
+                &exporting_configuration,
+                ctx,
+            );
 
             (exporting_configuration, tracing_guard, None)
         };
@@ -248,16 +260,17 @@ impl OckamCommand {
         } else {
             tracer.start(command_name.clone())
         };
+
         let cx = OtelContext::current_with_span(span);
 
-        // TODO: Add another span here?
         let cli_state = match cli_state {
             Some(cli_state) => cli_state,
-            None => self
-                .init_cli_state(in_memory)
-                .with_context(cx.clone())
-                .await
-                .set_tracing_enabled(exporting_configuration.is_enabled()),
+            None => Arc::new(
+                self.init_cli_state(in_memory)
+                    .with_context(cx.clone())
+                    .await
+                    .set_tracing_enabled(exporting_configuration.is_enabled()),
+            ),
         };
 
         let terminal = Terminal::new(
@@ -307,7 +320,7 @@ impl OckamCommand {
         result
     }
 
-    #[instrument(skip_all, fields(command = self.subcommand.name()))]
+    #[instrument(skip_all, fields(command = self.subcommand.name()), level = Level::TRACE)]
     async fn run_command(
         self,
         ctx: &Context,
diff --git a/implementations/rust/ockam/ockam_command/src/command_events.rs b/implementations/rust/ockam/ockam_command/src/command_events.rs
index 74fd361f958..4b62a6090fc 100644
--- a/implementations/rust/ockam/ockam_command/src/command_events.rs
+++ b/implementations/rust/ockam/ockam_command/src/command_events.rs
@@ -1,22 +1,16 @@
 use ockam_api::cli_state::journeys::{JourneyEvent, APPLICATION_EVENT_COMMAND};
 use ockam_api::CliState;
-use ockam_core::OCKAM_TRACER_NAME;
-use opentelemetry::trace::{FutureExt, Span, TraceContextExt, Tracer};
-use opentelemetry::{global, Context};
 use std::collections::HashMap;
+use std::sync::Arc;
 use tracing::warn;
 
 /// This function creates a journey event describing the execution of a command
 pub async fn add_command_event(
-    cli_state: CliState,
+    cli_state: Arc<CliState>,
     command: &str,
     command_arguments: String,
 ) -> miette::Result<()> {
     let command_name = command.to_string();
-    let tracer = global::tracer(OCKAM_TRACER_NAME);
-
-    let span = tracer.start(command_name.clone());
-    let ctx = Context::current_with_span(span);
 
     let mut attributes = HashMap::new();
     attributes.insert(
@@ -25,7 +19,6 @@ pub async fn add_command_event(
     );
     if let Err(e) = cli_state
         .add_journey_event(JourneyEvent::ok(command_name), attributes)
-        .with_context(ctx)
         .await
     {
         warn!("cannot save a journey event: {}", e);
@@ -36,17 +29,13 @@ pub async fn add_command_event(
 
 /// This function creates a journey event describing the error resulting from the execution of a command
 pub async fn add_command_error_event(
-    cli_state: CliState,
+    cli_state: Arc<CliState>,
     command_name: &str,
     message: &str,
     command_arguments: String,
 ) -> miette::Result<()> {
     let message = message.to_string();
     let command = command_name.to_string();
-    let tracer = global::tracer(OCKAM_TRACER_NAME);
-    let mut span = tracer.start(format!("'{}' error", command));
-    span.set_status(opentelemetry::trace::Status::error(message.clone()));
-    let ctx = Context::current_with_span(span);
 
     let mut attributes = HashMap::new();
     attributes.insert(
@@ -55,12 +44,10 @@ pub async fn add_command_error_event(
     );
     if let Err(e) = cli_state
         .add_journey_error(&command, message, attributes)
-        .with_context(ctx)
         .await
     {
         warn!("cannot save a journey event: {}", e);
     }
-
     Ok(())
 }
 
diff --git a/implementations/rust/ockam/ockam_command/src/command_global_opts.rs b/implementations/rust/ockam/ockam_command/src/command_global_opts.rs
index 6038abd0b9a..9e1e9794987 100644
--- a/implementations/rust/ockam/ockam_command/src/command_global_opts.rs
+++ b/implementations/rust/ockam/ockam_command/src/command_global_opts.rs
@@ -1,4 +1,5 @@
 use console::Term;
+use std::sync::Arc;
 use tracing::debug;
 
 use crate::subcommand::OckamSubcommand;
@@ -18,7 +19,7 @@ pub struct CommandGlobalOpts {
     pub global_args: GlobalArgs,
     // TODO: This is not the place for it. We could propagate it more granularly and even avoid
     //  creating it for some commands.
-    pub state: CliState,
+    pub state: Arc<CliState>,
     pub terminal: Terminal<TerminalStream<Term>>,
 }
 
@@ -31,7 +32,7 @@ impl CommandGlobalOpts {
     ///
     pub fn new(
         global_args: GlobalArgs,
-        state: CliState,
+        state: Arc<CliState>,
         terminal: Terminal<TerminalStream<Term>>,
     ) -> Self {
         Self {
diff --git a/implementations/rust/ockam/ockam_command/src/enroll/command.rs b/implementations/rust/ockam/ockam_command/src/enroll/command.rs
index bc1723b9b9e..842f7bbae4c 100644
--- a/implementations/rust/ockam/ockam_command/src/enroll/command.rs
+++ b/implementations/rust/ockam/ockam_command/src/enroll/command.rs
@@ -13,7 +13,7 @@ use r3bl_tui::{
 };
 use tokio::sync::Mutex;
 use tokio::try_join;
-use tracing::{error, info, instrument, warn};
+use tracing::{error, info, instrument, warn, Level};
 
 use crate::enroll::OidcServiceExt;
 use crate::error::Error;
@@ -102,11 +102,11 @@ impl EnrollCommand {
         authorization_code_flow = % self.authorization_code_flow,
         force = % self.force,
         skip_orchestrator_resources_creation = % self.skip_orchestrator_resources_creation,
-        ))]
+        ), level = Level::TRACE)]
     async fn run_impl(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
         ctrlc_handler(opts.clone());
 
-        if self.is_already_enrolled(&opts.state, &opts).await? {
+        if self.is_already_enrolled(opts.state.clone(), &opts).await? {
             return Ok(());
         }
 
@@ -114,7 +114,7 @@ impl EnrollCommand {
 
         let identity = {
             let _notification_handler =
-                NotificationHandler::start(&opts.state, opts.terminal.clone());
+                NotificationHandler::start(opts.state.clone(), opts.terminal.clone());
             opts.state
                 .get_named_identity_or_default(&self.identity)
                 .await?
@@ -122,8 +122,9 @@ impl EnrollCommand {
 
         let identity_name = identity.name();
         let identifier = identity.identifier();
-        let node = InMemoryNode::start_with_identity(ctx, &opts.state, Some(identity_name.clone()))
-            .await?;
+        let node =
+            InMemoryNode::start_with_identity(ctx, opts.state.clone(), Some(identity_name.clone()))
+                .await?;
 
         let user_info = self.enroll_identity(ctx, &opts, &node).await?;
 
@@ -198,7 +199,7 @@ impl EnrollCommand {
     /// Check if the identity is already enrolled and display a message to the user.
     async fn is_already_enrolled(
         &self,
-        cli_state: &CliState,
+        cli_state: Arc<CliState>,
         opts: &CommandGlobalOpts,
     ) -> miette::Result<bool> {
         let mut is_already_enrolled = !cli_state
@@ -347,7 +348,7 @@ fn ctrlc_handler(opts: CommandGlobalOpts) {
         .expect("Error setting Ctrl-C handler");
 }
 
-#[instrument(skip_all)]
+#[instrument(skip_all, level = Level::TRACE)]
 async fn retrieve_user_space_and_project(
     opts: &CommandGlobalOpts,
     ctx: &Context,
diff --git a/implementations/rust/ockam/ockam_command/src/enroll/oidc_service.rs b/implementations/rust/ockam/ockam_command/src/enroll/oidc_service.rs
index 8c5b2a0f41a..1baa8f75df0 100644
--- a/implementations/rust/ockam/ockam_command/src/enroll/oidc_service.rs
+++ b/implementations/rust/ockam/ockam_command/src/enroll/oidc_service.rs
@@ -8,7 +8,7 @@ use console::Term;
 use miette::{miette, IntoDiagnostic};
 use reqwest::StatusCode;
 use tokio::time::{sleep, Duration};
-use tracing::{debug, instrument};
+use tracing::{debug, instrument, Level};
 
 use ockam_api::colors::{color_email, color_uri, OckamColor};
 use ockam_api::enroll::oidc_service::OidcService;
@@ -51,7 +51,7 @@ pub trait OidcServiceExt {
 
 #[async_trait]
 impl OidcServiceExt for OidcService {
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn get_token_interactively(&self, opts: &CommandGlobalOpts) -> Result<OidcToken> {
         let device_code = self.device_code().await?;
 
@@ -138,7 +138,7 @@ impl OidcServiceExt for OidcService {
         self.get_token_from_browser(opts, dc, uri).await
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn wait_for_email_verification(
         &self,
         token: &OidcToken,
diff --git a/implementations/rust/ockam/ockam_command/src/entry_point.rs b/implementations/rust/ockam/ockam_command/src/entry_point.rs
index 0545faab5a9..40ff99ead40 100644
--- a/implementations/rust/ockam/ockam_command/src/entry_point.rs
+++ b/implementations/rust/ockam/ockam_command/src/entry_point.rs
@@ -1,7 +1,7 @@
-use std::process::exit;
-
 use clap::{Command, Parser};
 use miette::IntoDiagnostic;
+use std::process::exit;
+use std::sync::Arc;
 
 use crate::branding::BrandingCompileEnvVars;
 use crate::{
@@ -99,13 +99,15 @@ async fn handle_invalid_command(
             LogFormat::Default,
             logging_enabled()?,
         );
+        let exporting_configuration = ExportingConfiguration::foreground(&cli_state, ctx)
+            .await
+            .into_diagnostic()?;
+        let cli_state = Arc::new(cli_state);
         let _guard = LoggingTracing::setup(
+            cli_state.clone(),
             &logging_configuration.into_diagnostic()?,
-            &ExportingConfiguration::foreground(&cli_state, ctx)
-                .await
-                .into_diagnostic()?,
+            &exporting_configuration,
             "local node",
-            None,
             ctx,
         );
 
diff --git a/implementations/rust/ockam/ockam_command/src/flow_control/add_consumer.rs b/implementations/rust/ockam/ockam_command/src/flow_control/add_consumer.rs
index cb5844ac095..f8a41d3d857 100644
--- a/implementations/rust/ockam/ockam_command/src/flow_control/add_consumer.rs
+++ b/implementations/rust/ockam/ockam_command/src/flow_control/add_consumer.rs
@@ -28,7 +28,8 @@ impl AddConsumerCommand {
     }
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &self.node_opts.at_node).await?;
+        let node =
+            BackgroundNodeClient::create(ctx, opts.state.clone(), &self.node_opts.at_node).await?;
         node.tell(
             ctx,
             api::add_consumer(self.flow_control_id.clone(), self.address.clone()),
diff --git a/implementations/rust/ockam/ockam_command/src/identity/create.rs b/implementations/rust/ockam/ockam_command/src/identity/create.rs
index 919ed42cef0..d52acffede5 100644
--- a/implementations/rust/ockam/ockam_command/src/identity/create.rs
+++ b/implementations/rust/ockam/ockam_command/src/identity/create.rs
@@ -46,7 +46,8 @@ impl Command for CreateCommand {
     const NAME: &'static str = "identity create";
 
     async fn run(self, _ctx: &Context, opts: CommandGlobalOpts) -> crate::Result<()> {
-        let _notification_handler = NotificationHandler::start(&opts.state, opts.terminal.clone());
+        let _notification_handler =
+            NotificationHandler::start(opts.state.clone(), opts.terminal.clone());
         let vault = match &self.vault {
             Some(vault_name) => opts.state.get_or_create_named_vault(vault_name).await?,
             None => opts.state.get_or_create_default_named_vault().await?,
diff --git a/implementations/rust/ockam/ockam_command/src/influxdb/inlet/create.rs b/implementations/rust/ockam/ockam_command/src/influxdb/inlet/create.rs
index cc9c66d217b..847a76d2b47 100644
--- a/implementations/rust/ockam/ockam_command/src/influxdb/inlet/create.rs
+++ b/implementations/rust/ockam/ockam_command/src/influxdb/inlet/create.rs
@@ -26,6 +26,7 @@ use ockam_core::api::{Reply, Status};
 use ockam_multiaddr::{proto, MultiAddr, Protocol};
 use ockam_node::compat::asynchronous::resolve_peer;
 use std::str::FromStr;
+use std::sync::Arc;
 use std::time::Duration;
 use tracing::trace;
 
@@ -163,7 +164,7 @@ impl Command for CreateCommand {
         initialize_default_node(ctx, &opts).await?;
         let cmd = self.parse_args(&opts).await?;
 
-        let mut node = BackgroundNodeClient::create(ctx, &opts.state, &cmd.at).await?;
+        let mut node = BackgroundNodeClient::create(ctx, opts.state.clone(), &cmd.at).await?;
         cmd.timeout.timeout.map(|t| node.set_timeout_mut(t));
 
         let inlet_status = {
@@ -187,7 +188,7 @@ impl Command for CreateCommand {
                         cmd.connection_wait,
                         !cmd.no_connection_wait,
                         &cmd
-                            .secure_channel_identifier(&opts.state)
+                            .secure_channel_identifier(opts.state.clone())
                             .await?,
                         cmd.udp || cmd.from.is_udp(),
                         cmd.no_tcp_fallback,
@@ -288,7 +289,7 @@ impl CreateCommand {
         port_is_free_guard(&from)?;
 
         self.to = crate::tcp::inlet::create::CreateCommand::parse_arg_to(
-            &opts.state,
+            opts.state.clone(),
             self.to,
             self.via.as_ref(),
         )
@@ -329,7 +330,7 @@ impl CreateCommand {
 
     pub async fn secure_channel_identifier(
         &self,
-        state: &CliState,
+        state: Arc<CliState>,
     ) -> miette::Result<Option<Identifier>> {
         if let Some(identity_name) = self.identity.as_ref() {
             Ok(Some(state.get_identifier_by_name(identity_name).await?))
diff --git a/implementations/rust/ockam/ockam_command/src/influxdb/outlet/create.rs b/implementations/rust/ockam/ockam_command/src/influxdb/outlet/create.rs
index d0492283dfa..305603d192e 100644
--- a/implementations/rust/ockam/ockam_command/src/influxdb/outlet/create.rs
+++ b/implementations/rust/ockam/ockam_command/src/influxdb/outlet/create.rs
@@ -116,7 +116,7 @@ impl Command for CreateCommand {
             ))?;
         };
 
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &cmd.at).await?;
+        let node = BackgroundNodeClient::create(ctx, opts.state.clone(), &cmd.at).await?;
         let outlet_status = {
             let pb = opts.terminal.spinner();
             if let Some(pb) = pb.as_ref() {
diff --git a/implementations/rust/ockam/ockam_command/src/kafka/inlet/create.rs b/implementations/rust/ockam/ockam_command/src/kafka/inlet/create.rs
index d233e0c8876..1fead57be1c 100644
--- a/implementations/rust/ockam/ockam_command/src/kafka/inlet/create.rs
+++ b/implementations/rust/ockam/ockam_command/src/kafka/inlet/create.rs
@@ -152,7 +152,8 @@ impl Command for CreateCommand {
             }
 
             let node =
-                BackgroundNodeClient::create(ctx, &opts.state, &cmd.node_opts.at_node).await?;
+                BackgroundNodeClient::create(ctx, opts.state.clone(), &cmd.node_opts.at_node)
+                    .await?;
 
             let consumer_resolution;
             if let Some(route) = &cmd.consumer {
@@ -242,7 +243,7 @@ impl CreateCommand {
             ));
         }
 
-        self.to = process_nodes_multiaddr(&self.to, &opts.state).await?;
+        self.to = process_nodes_multiaddr(&self.to, opts.state.clone()).await?;
         Ok(self)
     }
 
diff --git a/implementations/rust/ockam/ockam_command/src/kafka/inlet/delete.rs b/implementations/rust/ockam/ockam_command/src/kafka/inlet/delete.rs
index a7bf235f24c..a0a022b2019 100644
--- a/implementations/rust/ockam/ockam_command/src/kafka/inlet/delete.rs
+++ b/implementations/rust/ockam/ockam_command/src/kafka/inlet/delete.rs
@@ -59,7 +59,8 @@ impl DeleteTui {
         opts: CommandGlobalOpts,
         cmd: DeleteCommand,
     ) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &cmd.node_opts.at_node).await?;
+        let node =
+            BackgroundNodeClient::create(ctx, opts.state.clone(), &cmd.node_opts.at_node).await?;
         let tui = Self {
             ctx: ctx.try_clone()?,
             opts,
diff --git a/implementations/rust/ockam/ockam_command/src/kafka/inlet/list.rs b/implementations/rust/ockam/ockam_command/src/kafka/inlet/list.rs
index e0399ef1ded..e148db5fc61 100644
--- a/implementations/rust/ockam/ockam_command/src/kafka/inlet/list.rs
+++ b/implementations/rust/ockam/ockam_command/src/kafka/inlet/list.rs
@@ -25,7 +25,8 @@ impl Command for ListCommand {
     const NAME: &'static str = "kafka-inlet list";
 
     async fn run(self, ctx: &Context, opts: CommandGlobalOpts) -> crate::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &self.node_opts.at_node).await?;
+        let node =
+            BackgroundNodeClient::create(ctx, opts.state.clone(), &self.node_opts.at_node).await?;
         let services: ServiceStatusList = node
             .ask(
                 ctx,
diff --git a/implementations/rust/ockam/ockam_command/src/kafka/inlet/show.rs b/implementations/rust/ockam/ockam_command/src/kafka/inlet/show.rs
index 99b13d9d3e4..ba7360c251c 100644
--- a/implementations/rust/ockam/ockam_command/src/kafka/inlet/show.rs
+++ b/implementations/rust/ockam/ockam_command/src/kafka/inlet/show.rs
@@ -46,7 +46,8 @@ impl<'a> ShowTui<'a> {
         opts: CommandGlobalOpts,
         cmd: &'a ShowCommand,
     ) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &cmd.node_opts.at_node).await?;
+        let node =
+            BackgroundNodeClient::create(ctx, opts.state.clone(), &cmd.node_opts.at_node).await?;
         let tui = Self {
             ctx,
             opts,
diff --git a/implementations/rust/ockam/ockam_command/src/kafka/outlet/create.rs b/implementations/rust/ockam/ockam_command/src/kafka/outlet/create.rs
index 4ed4331a479..125f8b54b93 100644
--- a/implementations/rust/ockam/ockam_command/src/kafka/outlet/create.rs
+++ b/implementations/rust/ockam/ockam_command/src/kafka/outlet/create.rs
@@ -78,7 +78,8 @@ impl Command for CreateCommand {
             }
 
             let node =
-                BackgroundNodeClient::create(ctx, &opts.state, &cmd.node_opts.at_node).await?;
+                BackgroundNodeClient::create(ctx, opts.state.clone(), &cmd.node_opts.at_node)
+                    .await?;
             let _res: OutletStatus = node
                 .create_kafka_outlet(
                     ctx,
diff --git a/implementations/rust/ockam/ockam_command/src/kafka/outlet/delete.rs b/implementations/rust/ockam/ockam_command/src/kafka/outlet/delete.rs
index c6275a610a5..53a1e6507b2 100644
--- a/implementations/rust/ockam/ockam_command/src/kafka/outlet/delete.rs
+++ b/implementations/rust/ockam/ockam_command/src/kafka/outlet/delete.rs
@@ -56,7 +56,8 @@ impl DeleteTui {
         opts: CommandGlobalOpts,
         cmd: DeleteCommand,
     ) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &cmd.node_opts.at_node).await?;
+        let node =
+            BackgroundNodeClient::create(ctx, opts.state.clone(), &cmd.node_opts.at_node).await?;
         let tui = Self {
             ctx: ctx.try_clone()?,
             opts,
diff --git a/implementations/rust/ockam/ockam_command/src/kafka/outlet/list.rs b/implementations/rust/ockam/ockam_command/src/kafka/outlet/list.rs
index ef472d7264e..cb784ba7fec 100644
--- a/implementations/rust/ockam/ockam_command/src/kafka/outlet/list.rs
+++ b/implementations/rust/ockam/ockam_command/src/kafka/outlet/list.rs
@@ -23,7 +23,8 @@ impl Command for ListCommand {
     const NAME: &'static str = "kafka-outlet list";
 
     async fn run(self, ctx: &Context, opts: CommandGlobalOpts) -> crate::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &self.node_opts.at_node).await?;
+        let node =
+            BackgroundNodeClient::create(ctx, opts.state.clone(), &self.node_opts.at_node).await?;
         let services: ServiceStatusList = node
             .ask(
                 ctx,
diff --git a/implementations/rust/ockam/ockam_command/src/kafka/outlet/show.rs b/implementations/rust/ockam/ockam_command/src/kafka/outlet/show.rs
index 5cfada97d32..7f7f0639e82 100644
--- a/implementations/rust/ockam/ockam_command/src/kafka/outlet/show.rs
+++ b/implementations/rust/ockam/ockam_command/src/kafka/outlet/show.rs
@@ -46,7 +46,8 @@ impl<'a> ShowTui<'a> {
         opts: CommandGlobalOpts,
         cmd: &'a ShowCommand,
     ) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &cmd.node_opts.at_node).await?;
+        let node =
+            BackgroundNodeClient::create(ctx, opts.state.clone(), &cmd.node_opts.at_node).await?;
         let tui = Self {
             ctx,
             opts,
diff --git a/implementations/rust/ockam/ockam_command/src/lease/create.rs b/implementations/rust/ockam/ockam_command/src/lease/create.rs
index 7eaa13c6cc6..9ad1bbe3d5c 100644
--- a/implementations/rust/ockam/ockam_command/src/lease/create.rs
+++ b/implementations/rust/ockam/ockam_command/src/lease/create.rs
@@ -39,7 +39,7 @@ impl Command for CreateCommand {
 
         let node = InMemoryNode::start_with_identity_and_project_name(
             ctx,
-            &opts.state,
+            opts.state.clone(),
             cmd.identity_opts.identity_name.clone(),
             cmd.trust_opts.project_name.clone(),
         )
@@ -71,7 +71,7 @@ impl Command for CreateCommand {
 
 impl CreateCommand {
     async fn parse_args(mut self, opts: &CommandGlobalOpts) -> crate::Result<Self> {
-        self.at = super::resolve_at_arg(&self.at, &opts.state).await?;
+        self.at = super::resolve_at_arg(&self.at, opts.state.clone()).await?;
         Ok(self)
     }
 }
diff --git a/implementations/rust/ockam/ockam_command/src/lease/list.rs b/implementations/rust/ockam/ockam_command/src/lease/list.rs
index af415adc702..26dc7f2830e 100644
--- a/implementations/rust/ockam/ockam_command/src/lease/list.rs
+++ b/implementations/rust/ockam/ockam_command/src/lease/list.rs
@@ -38,7 +38,7 @@ impl Command for ListCommand {
 
         let node = InMemoryNode::start_with_identity_and_project_name(
             ctx,
-            &opts.state,
+            opts.state.clone(),
             cmd.identity_opts.identity_name.clone(),
             cmd.trust_opts.project_name.clone(),
         )
@@ -48,7 +48,7 @@ impl Command for ListCommand {
         opts.terminal
             .write_line(fmt_log!("Listing influxdb tokens...\n"))?;
 
-        let (at, _meta) = clean_nodes_multiaddr(&cmd.at, &opts.state).await?;
+        let (at, _meta) = clean_nodes_multiaddr(&cmd.at, opts.state.clone()).await?;
         let res = node.list_tokens(ctx, &at).await?;
 
         let plain = &opts.terminal.build_list(&res, "No tokens found")?;
@@ -65,7 +65,7 @@ impl Command for ListCommand {
 
 impl ListCommand {
     async fn parse_args(mut self, opts: &CommandGlobalOpts) -> crate::Result<Self> {
-        self.at = super::resolve_at_arg(&self.at, &opts.state).await?;
+        self.at = super::resolve_at_arg(&self.at, opts.state.clone()).await?;
         Ok(self)
     }
 }
diff --git a/implementations/rust/ockam/ockam_command/src/lease/mod.rs b/implementations/rust/ockam/ockam_command/src/lease/mod.rs
index 40fab2b3e4b..64611280e2c 100644
--- a/implementations/rust/ockam/ockam_command/src/lease/mod.rs
+++ b/implementations/rust/ockam/ockam_command/src/lease/mod.rs
@@ -8,11 +8,11 @@ pub use list::ListCommand;
 pub use show::ShowCommand;
 
 use miette::IntoDiagnostic;
-use std::str::FromStr;
-
 use ockam_api::CliState;
 use ockam_multiaddr::MultiAddr;
 use ockam_node::Context;
+use std::str::FromStr;
+use std::sync::Arc;
 
 mod create;
 mod list;
@@ -60,7 +60,7 @@ fn lease_at_default_value() -> MultiAddr {
         .expect("Invalid default value for at")
 }
 
-async fn resolve_at_arg(at: &MultiAddr, state: &CliState) -> miette::Result<MultiAddr> {
+async fn resolve_at_arg(at: &MultiAddr, state: Arc<CliState>) -> miette::Result<MultiAddr> {
     let mut at = at.to_string();
     if at.contains("<default_project_name>") {
         let project_name = state
diff --git a/implementations/rust/ockam/ockam_command/src/lease/revoke.rs b/implementations/rust/ockam/ockam_command/src/lease/revoke.rs
index 6f229231c18..d2ecdd91437 100644
--- a/implementations/rust/ockam/ockam_command/src/lease/revoke.rs
+++ b/implementations/rust/ockam/ockam_command/src/lease/revoke.rs
@@ -44,7 +44,7 @@ impl Command for RevokeCommand {
 
         let node = InMemoryNode::start_with_identity_and_project_name(
             ctx,
-            &opts.state,
+            opts.state.clone(),
             cmd.identity_opts.identity_name.clone(),
             cmd.trust_opts.project_name.clone(),
         )
@@ -54,7 +54,7 @@ impl Command for RevokeCommand {
         opts.terminal
             .write_line(fmt_log!("Revoking influxdb token {}...\n", cmd.token_id))?;
 
-        let (at, _meta) = clean_nodes_multiaddr(&cmd.at, &opts.state).await?;
+        let (at, _meta) = clean_nodes_multiaddr(&cmd.at, opts.state.clone()).await?;
         node.revoke_token(ctx, &at, &cmd.token_id).await?;
 
         opts.terminal
@@ -73,7 +73,7 @@ impl Command for RevokeCommand {
 
 impl RevokeCommand {
     async fn parse_args(mut self, opts: &CommandGlobalOpts) -> crate::Result<Self> {
-        self.at = super::resolve_at_arg(&self.at, &opts.state).await?;
+        self.at = super::resolve_at_arg(&self.at, opts.state.clone()).await?;
         Ok(self)
     }
 }
diff --git a/implementations/rust/ockam/ockam_command/src/lease/show.rs b/implementations/rust/ockam/ockam_command/src/lease/show.rs
index a1941cf5262..d906f60f90f 100644
--- a/implementations/rust/ockam/ockam_command/src/lease/show.rs
+++ b/implementations/rust/ockam/ockam_command/src/lease/show.rs
@@ -43,7 +43,7 @@ impl Command for ShowCommand {
 
         let node = InMemoryNode::start_with_identity_and_project_name(
             ctx,
-            &opts.state,
+            opts.state.clone(),
             cmd.identity_opts.identity_name.clone(),
             cmd.trust_opts.project_name.clone(),
         )
@@ -53,7 +53,7 @@ impl Command for ShowCommand {
         opts.terminal
             .write_line(fmt_log!("Retrieving influxdb token...\n"))?;
 
-        let (at, _meta) = clean_nodes_multiaddr(&cmd.at, &opts.state).await?;
+        let (at, _meta) = clean_nodes_multiaddr(&cmd.at, opts.state.clone()).await?;
         let res = node.get_token(ctx, &at, &cmd.token_id).await?;
 
         opts.terminal
@@ -69,7 +69,7 @@ impl Command for ShowCommand {
 
 impl ShowCommand {
     async fn parse_args(mut self, opts: &CommandGlobalOpts) -> crate::Result<Self> {
-        self.at = super::resolve_at_arg(&self.at, &opts.state).await?;
+        self.at = super::resolve_at_arg(&self.at, opts.state.clone()).await?;
         Ok(self)
     }
 }
diff --git a/implementations/rust/ockam/ockam_command/src/message/send.rs b/implementations/rust/ockam/ockam_command/src/message/send.rs
index 1ecff009f87..d24d71afde3 100644
--- a/implementations/rust/ockam/ockam_command/src/message/send.rs
+++ b/implementations/rust/ockam/ockam_command/src/message/send.rs
@@ -66,7 +66,7 @@ impl Command for SendCommand {
 
     async fn run(self, ctx: &Context, opts: CommandGlobalOpts) -> crate::Result<()> {
         // Process `--to` Multiaddr
-        let (to, meta) = clean_nodes_multiaddr(&self.to, &opts.state)
+        let (to, meta) = clean_nodes_multiaddr(&self.to, opts.state.clone())
             .await
             .context("Argument '--to' is invalid")
             .map_err(Error::Retry)?;
@@ -74,7 +74,8 @@ impl Command for SendCommand {
         // Setup environment depending on whether we are sending the message from a background node
         // or an in-memory node
         let result = if let Some(node) = &self.from {
-            let client = BackgroundNodeClient::create_to_node(ctx, &opts.state, node.as_str())?;
+            let client =
+                BackgroundNodeClient::create_to_node(ctx, opts.state.clone(), node.as_str())?;
             self.send_message(&client, ctx, &to).await?
         } else {
             let identity_name = opts
@@ -86,7 +87,7 @@ impl Command for SendCommand {
 
             let node_manager = InMemoryNode::start_node(
                 ctx,
-                &opts.state,
+                opts.state.clone(),
                 &identity_name,
                 None,
                 self.trust_opts.project_name.clone(),
diff --git a/implementations/rust/ockam/ockam_command/src/node/create.rs b/implementations/rust/ockam/ockam_command/src/node/create.rs
index 5e95f803074..bb438183474 100644
--- a/implementations/rust/ockam/ockam_command/src/node/create.rs
+++ b/implementations/rust/ockam/ockam_command/src/node/create.rs
@@ -25,7 +25,7 @@ use regex::Regex;
 use std::fmt::Write;
 use std::net::Ipv4Addr;
 use std::{path::PathBuf, str::FromStr};
-use tracing::instrument;
+use tracing::{instrument, Level};
 
 pub mod background;
 pub mod config;
@@ -202,7 +202,7 @@ impl Default for CreateCommand {
 impl Command for CreateCommand {
     const NAME: &'static str = "node create";
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn run(mut self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
         self.parse_args(&opts).await?;
 
@@ -390,7 +390,8 @@ impl CreateCommand {
         opts: &CommandGlobalOpts,
         identity_name: &Option<String>,
     ) -> Result<String> {
-        let _notification_handler = NotificationHandler::start(&opts.state, opts.terminal.clone());
+        let _notification_handler =
+            NotificationHandler::start(opts.state.clone(), opts.terminal.clone());
         Ok(match identity_name {
             Some(name) => {
                 if let Ok(identity) = opts.state.get_named_identity(name).await {
@@ -428,6 +429,7 @@ mod tests {
     use ockam_api::output::{OutputBranding, OutputFormat};
     use ockam_api::terminal::{LoggingOptions, Terminal};
     use ockam_api::CliState;
+    use std::sync::Arc;
 
     #[test]
     fn command_can_be_parsed_from_name() {
@@ -554,7 +556,7 @@ mod tests {
     #[tokio::test]
     async fn get_default_node_name_no_previous_state() {
         let opts = CommandGlobalOpts {
-            state: CliState::test().await.unwrap(),
+            state: Arc::new(CliState::test().await.unwrap()),
             terminal: Terminal::new(
                 LoggingOptions {
                     enabled: false,
@@ -615,7 +617,7 @@ mod tests {
         _ctx: &mut Context,
     ) -> ockam_core::Result<()> {
         let opts = CommandGlobalOpts {
-            state: CliState::test().await.unwrap(),
+            state: Arc::new(CliState::test().await.unwrap()),
             terminal: Terminal::new(
                 LoggingOptions {
                     enabled: false,
diff --git a/implementations/rust/ockam/ockam_command/src/node/create/background.rs b/implementations/rust/ockam/ockam_command/src/node/create/background.rs
index 953a62d4e47..54feffea291 100644
--- a/implementations/rust/ockam/ockam_command/src/node/create/background.rs
+++ b/implementations/rust/ockam/ockam_command/src/node/create/background.rs
@@ -1,5 +1,5 @@
 use miette::miette;
-use tracing::{debug, instrument};
+use tracing::{debug, instrument, Level};
 
 use ockam_api::cli_state::journeys::{JourneyEvent, NODE_NAME};
 use ockam_api::logs::CurrentSpan;
@@ -12,7 +12,7 @@ use crate::CommandGlobalOpts;
 
 impl CreateCommand {
     // Create a new node running in the background (i.e. another, new OS process)
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub(crate) async fn background_mode(&self, opts: CommandGlobalOpts) -> miette::Result<()> {
         let node_name = self.name.clone();
         debug!(%node_name, "creating node in background mode");
diff --git a/implementations/rust/ockam/ockam_command/src/node/create/config.rs b/implementations/rust/ockam/ockam_command/src/node/create/config.rs
index 14055a594f2..809e4c3de3a 100644
--- a/implementations/rust/ockam/ockam_command/src/node/create/config.rs
+++ b/implementations/rust/ockam/ockam_command/src/node/create/config.rs
@@ -12,7 +12,7 @@ use ockam_api::cli_state::random_name;
 use ockam_core::{OpenTelemetryContext, TryClone};
 use ockam_node::Context;
 use serde::{Deserialize, Serialize};
-use tracing::{debug, instrument, trace, Span};
+use tracing::{debug, instrument, trace, Level, Span};
 
 pub const ENROLLMENT_TICKET: &str = "ENROLLMENT_TICKET";
 
@@ -34,7 +34,8 @@ pub struct ConfigArgs {
     /// The variables passed here will have precedence over global environment variables.
     /// This argument can be used multiple times, each time adding a new key-value pair.
     /// Example: `--variable KEY1=VALUE1 --variable KEY2=VALUE2`
-    #[arg(long = "variable", value_name = "VARIABLE", value_parser = parse_key_val::<String, String>)]
+    #[arg(long = "variable", value_name = "VARIABLE", value_parser = parse_key_val::<String, String>
+    )]
     pub variables: Vec<(String, String)>,
 
     /// A flag used internally to indicate that the node was started from a configuration file.
@@ -44,7 +45,7 @@ pub struct ConfigArgs {
 
 impl CreateCommand {
     /// Run the creation of a node using a node configuration
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn run_config(self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
         debug!("running node create with a node config");
         let mut node_config = self.parse_node_config().await?;
@@ -93,7 +94,7 @@ impl CreateCommand {
     ///  - a local path to a configuration file
     ///  - an inline configuration
     /// or read the `configuration` argument
-    #[instrument(skip_all, fields(app.event.command.configuration_file))]
+    #[instrument(skip_all, fields(app.event.command.configuration_file), level = Level::TRACE)]
     async fn parse_node_config(&self) -> miette::Result<NodeConfig> {
         let contents = self.get_node_config_contents().await?;
         // Set environment variables from the cli command args
diff --git a/implementations/rust/ockam/ockam_command/src/node/create/foreground.rs b/implementations/rust/ockam/ockam_command/src/node/create/foreground.rs
index 18e37bd3eea..3e631fdf009 100644
--- a/implementations/rust/ockam/ockam_command/src/node/create/foreground.rs
+++ b/implementations/rust/ockam/ockam_command/src/node/create/foreground.rs
@@ -23,10 +23,10 @@ use ockam_core::LOCAL;
 use ockam_multiaddr::MultiAddr;
 use std::sync::Arc;
 use tokio::time::{sleep, Duration};
-use tracing::{debug, error, info, instrument};
+use tracing::{debug, error, info, instrument, Level};
 
 impl CreateCommand {
-    #[instrument(skip_all, fields(node_name = self.name))]
+    #[instrument(skip_all, fields(node_name = self.name), level = Level::TRACE)]
     pub(super) async fn foreground_mode(
         &mut self,
         ctx: &Context,
@@ -64,7 +64,7 @@ impl CreateCommand {
         } else {
             // Enable the notifications only on explicit foreground nodes.
             Some(NotificationHandler::start(
-                &opts.state,
+                opts.state.clone(),
                 opts.terminal.clone(),
             ))
         };
diff --git a/implementations/rust/ockam/ockam_command/src/node/delete.rs b/implementations/rust/ockam/ockam_command/src/node/delete.rs
index d42eb629809..d8bd6401872 100644
--- a/implementations/rust/ockam/ockam_command/src/node/delete.rs
+++ b/implementations/rust/ockam/ockam_command/src/node/delete.rs
@@ -58,7 +58,8 @@ pub struct DeleteTui {
 
 impl DeleteTui {
     pub async fn run(opts: CommandGlobalOpts, cmd: DeleteCommand) -> miette::Result<()> {
-        let _notification_handler = NotificationHandler::start(&opts.state, opts.terminal.clone());
+        let _notification_handler =
+            NotificationHandler::start(opts.state.clone(), opts.terminal.clone());
         let tui = Self { opts, cmd };
         tui.delete().await
     }
diff --git a/implementations/rust/ockam/ockam_command/src/node/show.rs b/implementations/rust/ockam/ockam_command/src/node/show.rs
index f193b3d1fd9..e927450c64d 100644
--- a/implementations/rust/ockam/ockam_command/src/node/show.rs
+++ b/implementations/rust/ockam/ockam_command/src/node/show.rs
@@ -1,4 +1,5 @@
 use async_trait::async_trait;
+use std::sync::Arc;
 use std::time::Duration;
 
 use clap::Args;
@@ -97,10 +98,14 @@ impl ShowCommandTui for ShowTui {
     }
 
     async fn show_single(&self, item_name: &str) -> miette::Result<()> {
-        let mut node =
-            BackgroundNodeClient::create(&self.ctx, &self.opts.state, &Some(item_name.to_string()))
-                .await?;
-        let node_resources = get_node_resources(&self.ctx, &self.opts.state, &mut node).await?;
+        let mut node = BackgroundNodeClient::create(
+            &self.ctx,
+            self.opts.state.clone(),
+            &Some(item_name.to_string()),
+        )
+        .await?;
+        let node_resources =
+            get_node_resources(&self.ctx, self.opts.state.clone(), &mut node).await?;
         self.opts
             .terminal
             .clone()
@@ -114,7 +119,7 @@ impl ShowCommandTui for ShowTui {
 
 pub async fn get_node_resources(
     ctx: &Context,
-    cli_state: &CliState,
+    cli_state: Arc<CliState>,
     node: &mut BackgroundNodeClient,
 ) -> miette::Result<NodeResources> {
     match node
diff --git a/implementations/rust/ockam/ockam_command/src/node/start.rs b/implementations/rust/ockam/ockam_command/src/node/start.rs
index 90cd9582b4f..c58641fae7f 100644
--- a/implementations/rust/ockam/ockam_command/src/node/start.rs
+++ b/implementations/rust/ockam/ockam_command/src/node/start.rs
@@ -121,7 +121,7 @@ async fn start_single_node(
     }
 
     let mut node = run_node(node_name, ctx, &opts).await?;
-    let node_status = get_node_resources(ctx, &opts.state, &mut node).await?;
+    let node_status = get_node_resources(ctx, opts.state.clone(), &mut node).await?;
     opts.terminal
         .to_stdout()
         .plain(&node_status)
@@ -181,7 +181,7 @@ async fn run_node(
     let handle = spawn_node(opts, cmd)?;
     wait_for_node_callback(handle, node_callback).await?;
 
-    let node = BackgroundNodeClient::create_to_node(ctx, &opts.state, node_name)?;
+    let node = BackgroundNodeClient::create_to_node(ctx, opts.state.clone(), node_name)?;
 
     Ok(node)
 }
diff --git a/implementations/rust/ockam/ockam_command/src/policy/create.rs b/implementations/rust/ockam/ockam_command/src/policy/create.rs
index 2556e97863f..c72d3ab83f2 100644
--- a/implementations/rust/ockam/ockam_command/src/policy/create.rs
+++ b/implementations/rust/ockam/ockam_command/src/policy/create.rs
@@ -67,7 +67,7 @@ impl Command for CreateCommand {
         let resource = ResourceTypeOrName::new(self.resource_type.as_ref(), self.resource.as_ref())
             .into_diagnostic()?;
 
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &self.at).await?;
+        let node = BackgroundNodeClient::create(ctx, opts.state.clone(), &self.at).await?;
         node.add_policy(ctx, &resource, &Action::HandleMessage, &self.allow)
             .await?;
         opts.terminal
diff --git a/implementations/rust/ockam/ockam_command/src/policy/delete.rs b/implementations/rust/ockam/ockam_command/src/policy/delete.rs
index 36e3824868e..f6587d688aa 100644
--- a/implementations/rust/ockam/ockam_command/src/policy/delete.rs
+++ b/implementations/rust/ockam/ockam_command/src/policy/delete.rs
@@ -54,7 +54,7 @@ impl DeleteTui {
         opts: CommandGlobalOpts,
         cmd: DeleteCommand,
     ) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &cmd.at).await?;
+        let node = BackgroundNodeClient::create(ctx, opts.state.clone(), &cmd.at).await?;
         let tui = Self {
             ctx: ctx.try_clone().into_diagnostic()?,
             opts,
diff --git a/implementations/rust/ockam/ockam_command/src/policy/list.rs b/implementations/rust/ockam/ockam_command/src/policy/list.rs
index 8176db56593..fdb10f96337 100644
--- a/implementations/rust/ockam/ockam_command/src/policy/list.rs
+++ b/implementations/rust/ockam/ockam_command/src/policy/list.rs
@@ -25,7 +25,7 @@ impl ListCommand {
     }
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &self.at).await?;
+        let node = BackgroundNodeClient::create(ctx, opts.state.clone(), &self.at).await?;
         let is_finished: Mutex<bool> = Mutex::new(false);
 
         let output_messages = if self.resource.is_none() {
diff --git a/implementations/rust/ockam/ockam_command/src/policy/show.rs b/implementations/rust/ockam/ockam_command/src/policy/show.rs
index 789cd4d7cc9..8b0be905081 100644
--- a/implementations/rust/ockam/ockam_command/src/policy/show.rs
+++ b/implementations/rust/ockam/ockam_command/src/policy/show.rs
@@ -49,7 +49,7 @@ impl ShowTui {
         opts: CommandGlobalOpts,
         cmd: ShowCommand,
     ) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &cmd.at).await?;
+        let node = BackgroundNodeClient::create(ctx, opts.state.clone(), &cmd.at).await?;
         let tui = Self {
             ctx: ctx.try_clone().into_diagnostic()?,
             opts,
diff --git a/implementations/rust/ockam/ockam_command/src/project/addon/configure_influxdb.rs b/implementations/rust/ockam/ockam_command/src/project/addon/configure_influxdb.rs
index 74034743b20..53ea14df994 100644
--- a/implementations/rust/ockam/ockam_command/src/project/addon/configure_influxdb.rs
+++ b/implementations/rust/ockam/ockam_command/src/project/addon/configure_influxdb.rs
@@ -146,7 +146,7 @@ impl AddonConfigureInfluxdbSubcommand {
             self.admin_access_role.clone(),
         );
 
-        let node = InMemoryNode::start(ctx, &opts.state).await?;
+        let node = InMemoryNode::start(ctx, opts.state.clone()).await?;
         let controller = node.create_controller().await?;
 
         let response = controller
diff --git a/implementations/rust/ockam/ockam_command/src/project/addon/configure_kafka.rs b/implementations/rust/ockam/ockam_command/src/project/addon/configure_kafka.rs
index 7bc25dbde3b..1caf60fd271 100644
--- a/implementations/rust/ockam/ockam_command/src/project/addon/configure_kafka.rs
+++ b/implementations/rust/ockam/ockam_command/src/project/addon/configure_kafka.rs
@@ -77,7 +77,7 @@ impl AddonConfigureKafkaSubcommand {
             .to_string();
         let config = KafkaConfig::new(self.config.bootstrap_server.clone());
 
-        let node = InMemoryNode::start(ctx, &opts.state).await?;
+        let node = InMemoryNode::start(ctx, opts.state.clone()).await?;
         let controller = node.create_controller().await?;
 
         let response = controller
diff --git a/implementations/rust/ockam/ockam_command/src/project/addon/configure_okta.rs b/implementations/rust/ockam/ockam_command/src/project/addon/configure_okta.rs
index e5255b951fa..dcfe415c701 100644
--- a/implementations/rust/ockam/ockam_command/src/project/addon/configure_okta.rs
+++ b/implementations/rust/ockam/ockam_command/src/project/addon/configure_okta.rs
@@ -122,7 +122,7 @@ impl AddonConfigureOktaSubcommand {
         auth0.validate_provider_config().await?;
 
         // Do request
-        let node = InMemoryNode::start(ctx, &opts.state).await?;
+        let node = InMemoryNode::start(ctx, opts.state.clone()).await?;
         let controller = node.create_controller().await?;
 
         let response = controller
diff --git a/implementations/rust/ockam/ockam_command/src/project/addon/disable.rs b/implementations/rust/ockam/ockam_command/src/project/addon/disable.rs
index d94f6c8821e..346ba009cb5 100644
--- a/implementations/rust/ockam/ockam_command/src/project/addon/disable.rs
+++ b/implementations/rust/ockam/ockam_command/src/project/addon/disable.rs
@@ -45,7 +45,7 @@ impl AddonDisableSubcommand {
             .await?
             .project_id()
             .to_string();
-        let node = InMemoryNode::start(ctx, &opts.state).await?;
+        let node = InMemoryNode::start(ctx, opts.state.clone()).await?;
         let controller = node.create_controller().await?;
 
         let response = controller
diff --git a/implementations/rust/ockam/ockam_command/src/project/addon/list.rs b/implementations/rust/ockam/ockam_command/src/project/addon/list.rs
index 443c597c0f1..28430e8a32d 100644
--- a/implementations/rust/ockam/ockam_command/src/project/addon/list.rs
+++ b/implementations/rust/ockam/ockam_command/src/project/addon/list.rs
@@ -35,7 +35,7 @@ impl AddonListSubcommand {
             .project_id()
             .to_string();
 
-        let node = InMemoryNode::start(ctx, &opts.state).await?;
+        let node = InMemoryNode::start(ctx, opts.state.clone()).await?;
         let controller = node.create_controller().await?;
 
         let addons = controller.list_addons(ctx, &project_id).await?;
diff --git a/implementations/rust/ockam/ockam_command/src/project/create.rs b/implementations/rust/ockam/ockam_command/src/project/create.rs
index ce5dd105085..93494c4b80c 100644
--- a/implementations/rust/ockam/ockam_command/src/project/create.rs
+++ b/implementations/rust/ockam/ockam_command/src/project/create.rs
@@ -41,7 +41,7 @@ impl CreateCommand {
     }
 
     pub(crate) async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
-        let node = InMemoryNode::start(ctx, &opts.state).await?;
+        let node = InMemoryNode::start(ctx, opts.state.clone()).await?;
         let project = node
             .create_project(ctx, &self.space_name, &self.project_name, vec![])
             .await?;
diff --git a/implementations/rust/ockam/ockam_command/src/project/delete.rs b/implementations/rust/ockam/ockam_command/src/project/delete.rs
index ed8a71c85bd..edfc09d7aae 100644
--- a/implementations/rust/ockam/ockam_command/src/project/delete.rs
+++ b/implementations/rust/ockam/ockam_command/src/project/delete.rs
@@ -45,7 +45,7 @@ impl DeleteCommand {
             self.yes,
             "Are you sure you want to delete this project?",
         )? {
-            let node = InMemoryNode::start(ctx, &opts.state).await?;
+            let node = InMemoryNode::start(ctx, opts.state.clone()).await?;
 
             node.delete_project_by_name(ctx, &self.space_name, &self.project_name)
                 .await?;
diff --git a/implementations/rust/ockam/ockam_command/src/project/enroll.rs b/implementations/rust/ockam/ockam_command/src/project/enroll.rs
index d644670c886..02abfc32f1b 100644
--- a/implementations/rust/ockam/ockam_command/src/project/enroll.rs
+++ b/implementations/rust/ockam/ockam_command/src/project/enroll.rs
@@ -116,7 +116,7 @@ impl Command for EnrollCommand {
             .await?;
         let node = InMemoryNode::start_with_project_name(
             ctx,
-            &opts.state,
+            opts.state.clone(),
             Some(project.name().to_string()),
         )
         .await?
diff --git a/implementations/rust/ockam/ockam_command/src/project/info.rs b/implementations/rust/ockam/ockam_command/src/project/info.rs
index 0fcd3fae56d..ac5521cc947 100644
--- a/implementations/rust/ockam/ockam_command/src/project/info.rs
+++ b/implementations/rust/ockam/ockam_command/src/project/info.rs
@@ -27,7 +27,7 @@ impl InfoCommand {
     }
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
-        let node = InMemoryNode::start(ctx, &opts.state).await?;
+        let node = InMemoryNode::start(ctx, opts.state.clone()).await?;
         let project = node.get_project_by_name(ctx, &self.name).await?;
         opts.terminal
             .to_stdout()
diff --git a/implementations/rust/ockam/ockam_command/src/project/list.rs b/implementations/rust/ockam/ockam_command/src/project/list.rs
index 445e8e69cfa..3847e5a4f0a 100644
--- a/implementations/rust/ockam/ockam_command/src/project/list.rs
+++ b/implementations/rust/ockam/ockam_command/src/project/list.rs
@@ -33,7 +33,7 @@ impl ListCommand {
     }
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
-        let node = InMemoryNode::start(ctx, &opts.state).await?;
+        let node = InMemoryNode::start(ctx, opts.state.clone()).await?;
         let is_finished: Mutex<bool> = Mutex::new(false);
         let get_projects = async {
             let projects = node.get_admin_projects(ctx).await?;
diff --git a/implementations/rust/ockam/ockam_command/src/project/show.rs b/implementations/rust/ockam/ockam_command/src/project/show.rs
index f89920c2f5c..ed58cef2ec8 100644
--- a/implementations/rust/ockam/ockam_command/src/project/show.rs
+++ b/implementations/rust/ockam/ockam_command/src/project/show.rs
@@ -1,7 +1,7 @@
 use async_trait::async_trait;
 use clap::Args;
 use miette::IntoDiagnostic;
-use tracing::instrument;
+use tracing::{instrument, Level};
 
 use ockam::Context;
 use ockam_api::nodes::InMemoryNode;
@@ -60,7 +60,7 @@ impl ShowTui {
         opts: CommandGlobalOpts,
         project_name: Option<String>,
     ) -> miette::Result<()> {
-        let node = InMemoryNode::start(&ctx, &opts.state).await?;
+        let node = InMemoryNode::start(&ctx, opts.state.clone()).await?;
         let tui = Self {
             ctx,
             opts,
@@ -107,7 +107,7 @@ impl ShowCommandTui for ShowTui {
         Ok(project)
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn show_single(&self, item_name: &str) -> miette::Result<()> {
         let project = self
             .node
diff --git a/implementations/rust/ockam/ockam_command/src/project/ticket.rs b/implementations/rust/ockam/ockam_command/src/project/ticket.rs
index 9387c5a2628..2ba37074ee2 100644
--- a/implementations/rust/ockam/ockam_command/src/project/ticket.rs
+++ b/implementations/rust/ockam/ockam_command/src/project/ticket.rs
@@ -100,7 +100,7 @@ impl Command for TicketCommand {
 
         let node = InMemoryNode::start_with_project_name(
             ctx,
-            &opts.state,
+            opts.state.clone(),
             cmd.trust_opts.project_name.clone(),
         )
         .await?;
diff --git a/implementations/rust/ockam/ockam_command/src/project/version.rs b/implementations/rust/ockam/ockam_command/src/project/version.rs
index bbe858293ab..c6d49b51876 100644
--- a/implementations/rust/ockam/ockam_command/src/project/version.rs
+++ b/implementations/rust/ockam/ockam_command/src/project/version.rs
@@ -31,7 +31,7 @@ impl VersionCommand {
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
         // Send request
-        let node = InMemoryNode::start(ctx, &opts.state).await?;
+        let node = InMemoryNode::start(ctx, opts.state.clone()).await?;
         let controller = node.create_controller().await?;
         let project_version = controller.get_orchestrator_version_info(ctx).await?;
 
diff --git a/implementations/rust/ockam/ockam_command/src/project_admin/add.rs b/implementations/rust/ockam/ockam_command/src/project_admin/add.rs
index 4d41e980fbe..b99209fd751 100644
--- a/implementations/rust/ockam/ockam_command/src/project_admin/add.rs
+++ b/implementations/rust/ockam/ockam_command/src/project_admin/add.rs
@@ -37,7 +37,7 @@ impl Command for AddCommand {
             .await?;
         let node = InMemoryNode::start_with_identity_and_project_name(
             ctx,
-            &opts.state,
+            opts.state.clone(),
             self.identity_opts.identity_name,
             Some(project.project_name().to_string()),
         )
diff --git a/implementations/rust/ockam/ockam_command/src/project_admin/delete.rs b/implementations/rust/ockam/ockam_command/src/project_admin/delete.rs
index da146da6278..3ca59bfea50 100644
--- a/implementations/rust/ockam/ockam_command/src/project_admin/delete.rs
+++ b/implementations/rust/ockam/ockam_command/src/project_admin/delete.rs
@@ -69,7 +69,7 @@ impl DeleteTui {
             .await?;
         let node = InMemoryNode::start_with_identity_and_project_name(
             ctx,
-            &opts.state,
+            opts.state.clone(),
             cmd.identity_opts.identity_name.clone(),
             Some(project.project_name().to_string()),
         )
diff --git a/implementations/rust/ockam/ockam_command/src/project_admin/list.rs b/implementations/rust/ockam/ockam_command/src/project_admin/list.rs
index 13b619f171b..ef7190eb12d 100644
--- a/implementations/rust/ockam/ockam_command/src/project_admin/list.rs
+++ b/implementations/rust/ockam/ockam_command/src/project_admin/list.rs
@@ -29,7 +29,7 @@ impl Command for ListCommand {
             .await?;
         let node = InMemoryNode::start_with_identity_and_project_name(
             ctx,
-            &opts.state,
+            opts.state.clone(),
             self.identity_opts.identity_name,
             Some(project.project_name().to_string()),
         )
diff --git a/implementations/rust/ockam/ockam_command/src/project_member/mod.rs b/implementations/rust/ockam/ockam_command/src/project_member/mod.rs
index cabb28ae8fe..b5bf53513c2 100644
--- a/implementations/rust/ockam/ockam_command/src/project_member/mod.rs
+++ b/implementations/rust/ockam/ockam_command/src/project_member/mod.rs
@@ -1,15 +1,12 @@
 use std::collections::BTreeMap;
 
+use add::{AddCommand, OCKAM_RELAY_ATTRIBUTE};
 use clap::Args;
 use clap::Subcommand;
-use miette::miette;
-use serde::Serialize;
-use std::fmt::Write;
-
-use add::{AddCommand, OCKAM_RELAY_ATTRIBUTE};
 use delete::DeleteCommand;
 use list::ListCommand;
 use list_ids::ListIdsCommand;
+use miette::miette;
 use ockam::identity::{AttributesEntry, Identifier};
 use ockam_api::authenticator::direct::{
     OCKAM_ROLE_ATTRIBUTE_ENROLLER_VALUE, OCKAM_ROLE_ATTRIBUTE_KEY,
@@ -22,6 +19,9 @@ use ockam_api::output::Output;
 use ockam_api::terminal::fmt;
 use ockam_api::CliState;
 use ockam_node::Context;
+use serde::Serialize;
+use std::fmt::Write;
+use std::sync::Arc;
 
 use crate::project_member::show::ShowCommand;
 use crate::shared_args::IdentityOpts;
@@ -90,15 +90,15 @@ pub(super) async fn authority_client(
     identity_opts: &IdentityOpts,
     project_name: &Option<String>,
 ) -> crate::Result<(AuthorityNodeClient, String)> {
-    let node =
-        InMemoryNode::start_with_project_name(ctx, &opts.state, project_name.clone()).await?;
+    let node = InMemoryNode::start_with_project_name(ctx, opts.state.clone(), project_name.clone())
+        .await?;
     let project = opts
         .state
         .projects()
         .get_project_by_name_or_default(project_name)
         .await?;
     Ok((
-        create_authority_client(ctx, &node, &opts.state, identity_opts, &project).await?,
+        create_authority_client(ctx, &node, opts.state.clone(), identity_opts, &project).await?,
         project.name().to_string(),
     ))
 }
@@ -106,7 +106,7 @@ pub(super) async fn authority_client(
 pub(super) async fn create_authority_client(
     ctx: &Context,
     node: &NodeManager,
-    cli_state: &CliState,
+    cli_state: Arc<CliState>,
     identity_opts: &IdentityOpts,
     project: &Project,
 ) -> crate::Result<AuthorityNodeClient> {
diff --git a/implementations/rust/ockam/ockam_command/src/relay/create.rs b/implementations/rust/ockam/ockam_command/src/relay/create.rs
index a50dc027f58..87a9e51bf5d 100644
--- a/implementations/rust/ockam/ockam_command/src/relay/create.rs
+++ b/implementations/rust/ockam/ockam_command/src/relay/create.rs
@@ -1,9 +1,9 @@
 use async_trait::async_trait;
-use std::str::FromStr;
-
 use clap::Args;
 use colorful::Colorful;
 use miette::{miette, IntoDiagnostic};
+use std::str::FromStr;
+use std::sync::Arc;
 use tracing::debug;
 
 use ockam::identity::Identifier;
@@ -91,7 +91,7 @@ impl Command for CreateCommand {
         let alias = cmd.relay_name();
         let return_timing = cmd.return_timing();
 
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &cmd.to).await?;
+        let node = BackgroundNodeClient::create(ctx, opts.state.clone(), &cmd.to).await?;
         let relay_info = {
             if at.starts_with(Project::CODE) && cmd.authorized.is_some() {
                 return Err(miette!(
@@ -201,14 +201,15 @@ impl CreateCommand {
             .await
             .ok()
             .map(|p| p.name().to_string());
-        let at = Self::parse_arg_at(&opts.state, self.at, default_project_name.as_deref()).await?;
+        let at = Self::parse_arg_at(opts.state.clone(), self.at, default_project_name.as_deref())
+            .await?;
         self.project_relay |= at.starts_with(Project::CODE);
         self.at = at.to_string();
         Ok(self)
     }
 
     async fn parse_arg_at(
-        state: &CliState,
+        state: Arc<CliState>,
         at: impl Into<String>,
         default_project_name: Option<&str>,
     ) -> Result<MultiAddr> {
@@ -249,38 +250,39 @@ mod tests {
 
     #[ockam_macros::test(crate = "ockam")]
     async fn test_parse_arg_at(ctx: &mut Context) -> ockam::Result<()> {
-        let state = CliState::test().await?;
+        let state = Arc::new(CliState::test().await?);
         let default_project_name = Some("p1");
 
         // Invalid values
-        CreateCommand::parse_arg_at(&state, "/alice/service", default_project_name)
+        CreateCommand::parse_arg_at(state.clone(), "/alice/service", default_project_name)
             .await
             .expect_err("Invalid protocol");
-        CreateCommand::parse_arg_at(&state, "my/project", default_project_name)
+        CreateCommand::parse_arg_at(state.clone(), "my/project", default_project_name)
             .await
             .expect_err("Invalid protocol");
-        CreateCommand::parse_arg_at(&state, "alice", default_project_name)
+        CreateCommand::parse_arg_at(state.clone(), "alice", default_project_name)
             .await
             .expect_err("Node doesn't exist");
 
         // The placeholder is replaced when using the arg's default value
-        let res = CreateCommand::parse_arg_at(&state, default_at_addr(), default_project_name)
-            .await
-            .unwrap()
-            .to_string();
+        let res =
+            CreateCommand::parse_arg_at(state.clone(), default_at_addr(), default_project_name)
+                .await
+                .unwrap()
+                .to_string();
         assert_eq!(res, "/project/p1");
 
         // The user provides a full project route
         let addr = "/project/p1";
-        let res = CreateCommand::parse_arg_at(&state, addr, default_project_name)
+        let res = CreateCommand::parse_arg_at(state.clone(), addr, default_project_name)
             .await
             .unwrap()
             .to_string();
         assert_eq!(res, addr);
 
         // The user provides the name of a node
-        let node = InMemoryNode::start(ctx, &state).await.unwrap();
-        let res = CreateCommand::parse_arg_at(&state, &node.node_name(), default_project_name)
+        let node = InMemoryNode::start(ctx, state.clone()).await.unwrap();
+        let res = CreateCommand::parse_arg_at(state, &node.node_name(), default_project_name)
             .await
             .unwrap()
             .to_string();
diff --git a/implementations/rust/ockam/ockam_command/src/relay/delete.rs b/implementations/rust/ockam/ockam_command/src/relay/delete.rs
index cc6cc826a93..48d5ace97dc 100644
--- a/implementations/rust/ockam/ockam_command/src/relay/delete.rs
+++ b/implementations/rust/ockam/ockam_command/src/relay/delete.rs
@@ -60,7 +60,7 @@ impl DeleteTui {
         opts: CommandGlobalOpts,
         cmd: DeleteCommand,
     ) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(&ctx, &opts.state, &cmd.at).await?;
+        let node = BackgroundNodeClient::create(&ctx, opts.state.clone(), &cmd.at).await?;
         let tui = Self {
             ctx,
             opts,
diff --git a/implementations/rust/ockam/ockam_command/src/relay/list.rs b/implementations/rust/ockam/ockam_command/src/relay/list.rs
index b2b08700309..6a80144aef1 100644
--- a/implementations/rust/ockam/ockam_command/src/relay/list.rs
+++ b/implementations/rust/ockam/ockam_command/src/relay/list.rs
@@ -33,7 +33,7 @@ impl ListCommand {
     }
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &self.to).await?;
+        let node = BackgroundNodeClient::create(ctx, opts.state.clone(), &self.to).await?;
         let relays: RelayInfoList = {
             let pb = opts.terminal.spinner();
             if let Some(pb) = pb {
diff --git a/implementations/rust/ockam/ockam_command/src/relay/show.rs b/implementations/rust/ockam/ockam_command/src/relay/show.rs
index a3a3123bc3c..9c9755e5d81 100644
--- a/implementations/rust/ockam/ockam_command/src/relay/show.rs
+++ b/implementations/rust/ockam/ockam_command/src/relay/show.rs
@@ -63,7 +63,7 @@ impl ShowTui {
         opts: CommandGlobalOpts,
         cmd: ShowCommand,
     ) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(&ctx, &opts.state, &cmd.at).await?;
+        let node = BackgroundNodeClient::create(&ctx, opts.state.clone(), &cmd.at).await?;
         let tui = Self {
             ctx,
             opts,
diff --git a/implementations/rust/ockam/ockam_command/src/rendezvous/create/foreground.rs b/implementations/rust/ockam/ockam_command/src/rendezvous/create/foreground.rs
index 74220b182fe..f858560bfb2 100644
--- a/implementations/rust/ockam/ockam_command/src/rendezvous/create/foreground.rs
+++ b/implementations/rust/ockam/ockam_command/src/rendezvous/create/foreground.rs
@@ -1,5 +1,5 @@
 use miette::IntoDiagnostic;
-use tracing::{error, info, instrument};
+use tracing::{error, info, instrument, Level};
 
 use crate::rendezvous::create::CreateCommand;
 use crate::util::foreground_args::wait_for_exit_signal;
@@ -10,7 +10,7 @@ use ockam::Context;
 use ockam_api::{DefaultAddress, RendezvousHealthcheck};
 
 impl CreateCommand {
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub(super) async fn foreground_mode(
         &self,
         ctx: &Context,
diff --git a/implementations/rust/ockam/ockam_command/src/reset/mod.rs b/implementations/rust/ockam/ockam_command/src/reset/mod.rs
index ba8e95a2066..915f4e05d13 100644
--- a/implementations/rust/ockam/ockam_command/src/reset/mod.rs
+++ b/implementations/rust/ockam/ockam_command/src/reset/mod.rs
@@ -81,7 +81,7 @@ impl ResetCommand {
         }
         {
             let _notification_handler =
-                NotificationHandler::start(&opts.state, opts.terminal.clone());
+                NotificationHandler::start(opts.state.clone(), opts.terminal.clone());
             opts.state.reset().await?;
         }
 
@@ -100,7 +100,7 @@ async fn delete_orchestrator_resources_impl(
     ctx: &Context,
     opts: CommandGlobalOpts,
 ) -> miette::Result<()> {
-    let node = InMemoryNode::start(ctx, &opts.state).await?;
+    let node = InMemoryNode::start(ctx, opts.state.clone()).await?;
     let spaces = node
         .get_spaces(ctx)
         .await
diff --git a/implementations/rust/ockam/ockam_command/src/run/mod.rs b/implementations/rust/ockam/ockam_command/src/run/mod.rs
index 1a800db2eb0..9a7179da6ca 100644
--- a/implementations/rust/ockam/ockam_command/src/run/mod.rs
+++ b/implementations/rust/ockam/ockam_command/src/run/mod.rs
@@ -6,7 +6,7 @@ pub use config::Config;
 use ockam::Context;
 use ockam_api::cli_state::journeys::APPLICATION_EVENT_COMMAND_CONFIGURATION_FILE;
 use std::path::PathBuf;
-use tracing::{instrument, Span};
+use tracing::{instrument, Level, Span};
 
 use crate::{docs, CommandGlobalOpts};
 
@@ -37,7 +37,7 @@ impl RunCommand {
         "run".to_string()
     }
 
-    #[instrument(skip_all, fields(app.event.command.configuration_file))]
+    #[instrument(skip_all, fields(app.event.command.configuration_file), level = Level::TRACE)]
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
         let contents = match &self.inline {
             Some(contents) => contents.to_string(),
diff --git a/implementations/rust/ockam/ockam_command/src/secure_channel/create.rs b/implementations/rust/ockam/ockam_command/src/secure_channel/create.rs
index 29ed38163f4..4d32e8b0de6 100644
--- a/implementations/rust/ockam/ockam_command/src/secure_channel/create.rs
+++ b/implementations/rust/ockam/ockam_command/src/secure_channel/create.rs
@@ -73,7 +73,7 @@ impl CreateCommand {
         ctx: &Context,
         node: &BackgroundNodeClient,
     ) -> miette::Result<MultiAddr> {
-        let (to, meta) = clean_nodes_multiaddr(&self.to, &opts.state)
+        let (to, meta) = clean_nodes_multiaddr(&self.to, opts.state.clone())
             .await
             .wrap_err(format!("Could not convert {} into route", &self.to))?;
         let identity_name = opts
@@ -95,7 +95,7 @@ impl CreateCommand {
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
         initialize_default_node(ctx, &opts).await?;
-        let node = BackgroundNodeClient::create_to_node(ctx, &opts.state, &self.from)?;
+        let node = BackgroundNodeClient::create_to_node(ctx, opts.state.clone(), &self.from)?;
 
         opts.terminal
             .write_line(fmt_log!("Creating Secure Channel...\n"))?;
diff --git a/implementations/rust/ockam/ockam_command/src/secure_channel/delete.rs b/implementations/rust/ockam/ockam_command/src/secure_channel/delete.rs
index b700ab8e8bf..1710b4d4469 100644
--- a/implementations/rust/ockam/ockam_command/src/secure_channel/delete.rs
+++ b/implementations/rust/ockam/ockam_command/src/secure_channel/delete.rs
@@ -132,7 +132,7 @@ impl DeleteCommand {
             self.yes,
             "Are you sure you want to delete this secure channel?",
         )? {
-            let node = BackgroundNodeClient::create(ctx, &opts.state, &self.at).await?;
+            let node = BackgroundNodeClient::create(ctx, opts.state.clone(), &self.at).await?;
             let address = &self.address;
             let response: DeleteSecureChannelResponse =
                 node.ask(ctx, api::delete_secure_channel(address)).await?;
diff --git a/implementations/rust/ockam/ockam_command/src/secure_channel/list.rs b/implementations/rust/ockam/ockam_command/src/secure_channel/list.rs
index 1431d582a2b..7b4f1ad8383 100644
--- a/implementations/rust/ockam/ockam_command/src/secure_channel/list.rs
+++ b/implementations/rust/ockam/ockam_command/src/secure_channel/list.rs
@@ -31,7 +31,7 @@ impl Command for ListCommand {
     const NAME: &'static str = "secure-channel list";
 
     async fn run(self, ctx: &Context, opts: CommandGlobalOpts) -> crate::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &self.at).await?;
+        let node = BackgroundNodeClient::create(ctx, opts.state.clone(), &self.at).await?;
 
         let spinner = opts.terminal.spinner();
         if let Some(spinner) = &spinner {
diff --git a/implementations/rust/ockam/ockam_command/src/secure_channel/listener/create.rs b/implementations/rust/ockam/ockam_command/src/secure_channel/listener/create.rs
index b3a108b7b5f..bea167b9c0e 100644
--- a/implementations/rust/ockam/ockam_command/src/secure_channel/listener/create.rs
+++ b/implementations/rust/ockam/ockam_command/src/secure_channel/listener/create.rs
@@ -49,7 +49,8 @@ impl CreateCommand {
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
         initialize_default_node(ctx, &opts).await?;
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &self.node_opts.at_node).await?;
+        let node =
+            BackgroundNodeClient::create(ctx, opts.state.clone(), &self.node_opts.at_node).await?;
         let req = Request::post("/node/secure_channel_listener").body(
             CreateSecureChannelListenerRequest::new(
                 &self.address,
diff --git a/implementations/rust/ockam/ockam_command/src/secure_channel/listener/delete.rs b/implementations/rust/ockam/ockam_command/src/secure_channel/listener/delete.rs
index c0d46fc9857..6096ed4592d 100644
--- a/implementations/rust/ockam/ockam_command/src/secure_channel/listener/delete.rs
+++ b/implementations/rust/ockam/ockam_command/src/secure_channel/listener/delete.rs
@@ -35,7 +35,8 @@ impl DeleteCommand {
     }
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &self.node_opts.at_node).await?;
+        let node =
+            BackgroundNodeClient::create(ctx, opts.state.clone(), &self.node_opts.at_node).await?;
         let req = api::delete_secure_channel_listener(&self.address);
         let response: DeleteSecureChannelListenerResponse = node.ask(ctx, req).await?;
         let addr = response.addr;
diff --git a/implementations/rust/ockam/ockam_command/src/secure_channel/listener/list.rs b/implementations/rust/ockam/ockam_command/src/secure_channel/listener/list.rs
index 728757f245f..b787ed6f8d3 100644
--- a/implementations/rust/ockam/ockam_command/src/secure_channel/listener/list.rs
+++ b/implementations/rust/ockam/ockam_command/src/secure_channel/listener/list.rs
@@ -37,7 +37,8 @@ impl ListCommand {
     }
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &self.node_opts.at_node).await?;
+        let node =
+            BackgroundNodeClient::create(ctx, opts.state.clone(), &self.node_opts.at_node).await?;
         let is_finished: Mutex<bool> = Mutex::new(false);
 
         let get_listeners = async {
diff --git a/implementations/rust/ockam/ockam_command/src/secure_channel/listener/show.rs b/implementations/rust/ockam/ockam_command/src/secure_channel/listener/show.rs
index 67112f078f9..81b7a340bdc 100644
--- a/implementations/rust/ockam/ockam_command/src/secure_channel/listener/show.rs
+++ b/implementations/rust/ockam/ockam_command/src/secure_channel/listener/show.rs
@@ -34,7 +34,8 @@ impl ShowCommand {
     }
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &self.node_opts.at_node).await?;
+        let node =
+            BackgroundNodeClient::create(ctx, opts.state.clone(), &self.node_opts.at_node).await?;
         let address = &self.address;
         let req = api::show_secure_channel_listener(address);
         node.tell(ctx, req).await?;
diff --git a/implementations/rust/ockam/ockam_command/src/secure_channel/show.rs b/implementations/rust/ockam/ockam_command/src/secure_channel/show.rs
index baf20d011b2..2c9f2ed0760 100644
--- a/implementations/rust/ockam/ockam_command/src/secure_channel/show.rs
+++ b/implementations/rust/ockam/ockam_command/src/secure_channel/show.rs
@@ -1,6 +1,7 @@
 use async_trait::async_trait;
 use clap::Args;
 use miette::miette;
+use std::sync::Arc;
 
 use ockam::Context;
 use ockam_api::nodes::models::secure_channel::ShowSecureChannelResponse;
@@ -44,59 +45,64 @@ impl Command for ShowCommand {
     const NAME: &'static str = "secure-channel show";
 
     async fn run(self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
-        let response = match extract_node_name_and_service_from_multiaddr(&self.at, &opts.state)
-            .await?
-        {
-            // Get the secure channel from a local node
-            Some((node_name, sc_address)) => {
-                let node = BackgroundNodeClient::create(ctx, &opts.state, &Some(node_name)).await?;
-                let response: ShowSecureChannelResponse =
-                    node.ask(ctx, api::show_secure_channel(&sc_address)).await?;
-                response
-            }
-            // Get the secure channel given a multiaddr
-            None => {
-                let identity = opts
-                    .state
-                    .get_named_identity_or_default(&self.identity_opts.identity_name)
-                    .await?;
-
-                let node =
-                    InMemoryNode::start_with_identity(ctx, &opts.state, Some(identity.name()))
+        let response =
+            match extract_node_name_and_service_from_multiaddr(&self.at, opts.state.clone()).await?
+            {
+                // Get the secure channel from a local node
+                Some((node_name, sc_address)) => {
+                    let node =
+                        BackgroundNodeClient::create(ctx, opts.state.clone(), &Some(node_name))
+                            .await?;
+                    let response: ShowSecureChannelResponse =
+                        node.ask(ctx, api::show_secure_channel(&sc_address)).await?;
+                    response
+                }
+                // Get the secure channel given a multiaddr
+                None => {
+                    let identity = opts
+                        .state
+                        .get_named_identity_or_default(&self.identity_opts.identity_name)
                         .await?;
 
-                let secure_channel = node
-                    .create_secure_channel(
+                    let node = InMemoryNode::start_with_identity(
                         ctx,
-                        self.at.clone(),
+                        opts.state.clone(),
                         Some(identity.name()),
-                        None,
-                        None,
-                        Some(self.timeout.timeout),
-                        SecureChannelType::KeyExchangeAndMessages,
                     )
                     .await?;
 
-                let peer_identifier = secure_channel.their_identifier();
+                    let secure_channel = node
+                        .create_secure_channel(
+                            ctx,
+                            self.at.clone(),
+                            Some(identity.name()),
+                            None,
+                            None,
+                            Some(self.timeout.timeout),
+                            SecureChannelType::KeyExchangeAndMessages,
+                        )
+                        .await?;
 
-                let change_history = node
-                    .secure_channels()
-                    .identities()
-                    .get_change_history(peer_identifier)
-                    .await?;
+                    let peer_identifier = secure_channel.their_identifier();
+
+                    let change_history = node
+                        .secure_channels()
+                        .identities()
+                        .get_change_history(peer_identifier)
+                        .await?;
 
-                ShowSecureChannelResponse {
-                    address: ReverseLocalConverter::convert_address(
-                        secure_channel.encryptor_address(),
-                    )?,
-                    route: self.at,
-                    authorized_identifiers: None,
-                    flow_control_id: secure_channel.flow_control_id().clone(),
-                    their_identifier: secure_channel.their_identifier().clone(),
-                    their_change_history: Some(change_history.export_as_string()?),
+                    ShowSecureChannelResponse {
+                        address: ReverseLocalConverter::convert_address(
+                            secure_channel.encryptor_address(),
+                        )?,
+                        route: self.at,
+                        authorized_identifiers: None,
+                        flow_control_id: secure_channel.flow_control_id().clone(),
+                        their_identifier: secure_channel.their_identifier().clone(),
+                        their_change_history: Some(change_history.export_as_string()?),
+                    }
                 }
-            }
-        };
+            };
 
         opts.terminal
             .to_stdout()
@@ -114,7 +120,7 @@ impl Command for ShowCommand {
 ///     `/node/n1/service/1234` -> `(n1, 1234)`
 async fn extract_node_name_and_service_from_multiaddr(
     addr: &MultiAddr,
-    cli_state: &CliState,
+    cli_state: Arc<CliState>,
 ) -> miette::Result<Option<(String, Address)>> {
     let mut iter = addr.iter();
     if let Some(proto) = iter.next() {
@@ -148,12 +154,12 @@ mod tests {
 
     #[tokio::test]
     async fn test_extract_node_name_and_service_from_multiaddr_valid() -> Result<()> {
-        let cli_state = CliState::test().await?;
+        let cli_state = Arc::new(CliState::test().await?);
         cli_state.create_node("n1").await?;
 
         let multiaddr: MultiAddr = "/node/n1/service/1234".parse()?;
 
-        let result = extract_node_name_and_service_from_multiaddr(&multiaddr, &cli_state).await?;
+        let result = extract_node_name_and_service_from_multiaddr(&multiaddr, cli_state).await?;
         assert!(result.is_some());
         let (node_name, address) = result.unwrap();
         assert_eq!(node_name, "n1");
@@ -163,20 +169,20 @@ mod tests {
 
     #[tokio::test]
     async fn test_extract_node_name_and_service_from_multiaddr_invalid_node() -> Result<()> {
-        let cli_state = CliState::test().await?;
+        let cli_state = Arc::new(CliState::test().await?);
         let multiaddr: MultiAddr = "/node/invalid/service/1234".parse()?;
 
-        let result = extract_node_name_and_service_from_multiaddr(&multiaddr, &cli_state).await;
+        let result = extract_node_name_and_service_from_multiaddr(&multiaddr, cli_state).await;
         assert!(result.is_err());
         Ok(())
     }
 
     #[tokio::test]
     async fn test_extract_node_name_and_service_from_multiaddr_no_node() -> Result<()> {
-        let cli_state = CliState::test().await?;
+        let cli_state = Arc::new(CliState::test().await?);
         let multiaddr: MultiAddr = "/service/1234".parse()?;
 
-        let result = extract_node_name_and_service_from_multiaddr(&multiaddr, &cli_state).await?;
+        let result = extract_node_name_and_service_from_multiaddr(&multiaddr, cli_state).await?;
         assert!(result.is_none());
         Ok(())
     }
diff --git a/implementations/rust/ockam/ockam_command/src/service/list.rs b/implementations/rust/ockam/ockam_command/src/service/list.rs
index e823cc44755..44ecdd042b8 100644
--- a/implementations/rust/ockam/ockam_command/src/service/list.rs
+++ b/implementations/rust/ockam/ockam_command/src/service/list.rs
@@ -26,7 +26,8 @@ impl ListCommand {
     }
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &self.node_opts.at_node).await?;
+        let node =
+            BackgroundNodeClient::create(ctx, opts.state.clone(), &self.node_opts.at_node).await?;
         let is_finished: Mutex<bool> = Mutex::new(false);
 
         let get_services = async {
diff --git a/implementations/rust/ockam/ockam_command/src/service/start.rs b/implementations/rust/ockam/ockam_command/src/service/start.rs
index 5d4571d0cd7..b4a5725e3ef 100644
--- a/implementations/rust/ockam/ockam_command/src/service/start.rs
+++ b/implementations/rust/ockam/ockam_command/src/service/start.rs
@@ -41,7 +41,8 @@ impl StartCommand {
     }
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &self.node_opts.at_node).await?;
+        let node =
+            BackgroundNodeClient::create(ctx, opts.state.clone(), &self.node_opts.at_node).await?;
         let addr = match &self.create_subcommand {
             StartSubCommand::Hop { addr, .. } => {
                 start_hop_service(ctx, &node, addr).await?;
diff --git a/implementations/rust/ockam/ockam_command/src/share/accept.rs b/implementations/rust/ockam/ockam_command/src/share/accept.rs
index 8111c1c767f..64ffa7d6a44 100644
--- a/implementations/rust/ockam/ockam_command/src/share/accept.rs
+++ b/implementations/rust/ockam/ockam_command/src/share/accept.rs
@@ -29,7 +29,7 @@ impl AcceptCommand {
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
         let is_finished: Mutex<bool> = Mutex::new(false);
-        let node = InMemoryNode::start(ctx, &opts.state).await?;
+        let node = InMemoryNode::start(ctx, opts.state.clone()).await?;
         let controller = node.create_controller().await?;
 
         let get_accepted_invitation = async {
diff --git a/implementations/rust/ockam/ockam_command/src/share/create.rs b/implementations/rust/ockam/ockam_command/src/share/create.rs
index 5e5b1b45006..e7485543dd5 100644
--- a/implementations/rust/ockam/ockam_command/src/share/create.rs
+++ b/implementations/rust/ockam/ockam_command/src/share/create.rs
@@ -41,7 +41,7 @@ impl CreateCommand {
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
         let is_finished: Mutex<bool> = Mutex::new(false);
-        let node = InMemoryNode::start(ctx, &opts.state).await?;
+        let node = InMemoryNode::start(ctx, opts.state.clone()).await?;
         let controller = node.create_controller().await?;
 
         let get_sent_invitation = async {
diff --git a/implementations/rust/ockam/ockam_command/src/share/list.rs b/implementations/rust/ockam/ockam_command/src/share/list.rs
index d5b60c22b0e..688ca952606 100644
--- a/implementations/rust/ockam/ockam_command/src/share/list.rs
+++ b/implementations/rust/ockam/ockam_command/src/share/list.rs
@@ -30,7 +30,7 @@ impl ListCommand {
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
         let is_finished: Mutex<bool> = Mutex::new(false);
-        let node = InMemoryNode::start(ctx, &opts.state).await?;
+        let node = InMemoryNode::start(ctx, opts.state.clone()).await?;
         let controller = node.create_controller().await?;
 
         let get_invitations = async {
diff --git a/implementations/rust/ockam/ockam_command/src/share/service.rs b/implementations/rust/ockam/ockam_command/src/share/service.rs
index 0a0e37b1c3d..52e648504d9 100644
--- a/implementations/rust/ockam/ockam_command/src/share/service.rs
+++ b/implementations/rust/ockam/ockam_command/src/share/service.rs
@@ -48,7 +48,7 @@ impl ServiceCreateCommand {
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
         let is_finished: Mutex<bool> = Mutex::new(false);
-        let node = InMemoryNode::start(ctx, &opts.state).await?;
+        let node = InMemoryNode::start(ctx, opts.state.clone()).await?;
         let controller = node.create_controller().await?;
 
         let get_sent_invitation = async {
diff --git a/implementations/rust/ockam/ockam_command/src/share/show.rs b/implementations/rust/ockam/ockam_command/src/share/show.rs
index 73337887783..50474c56c32 100644
--- a/implementations/rust/ockam/ockam_command/src/share/show.rs
+++ b/implementations/rust/ockam/ockam_command/src/share/show.rs
@@ -31,7 +31,7 @@ impl ShowCommand {
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
         let is_finished: Mutex<bool> = Mutex::new(false);
-        let node = InMemoryNode::start(ctx, &opts.state).await?;
+        let node = InMemoryNode::start(ctx, opts.state.clone()).await?;
         let controller = node.create_controller().await?;
 
         let get_invitation_with_access = async {
diff --git a/implementations/rust/ockam/ockam_command/src/space/create.rs b/implementations/rust/ockam/ockam_command/src/space/create.rs
index 8ee9d38e4a2..db7968c1e28 100644
--- a/implementations/rust/ockam/ockam_command/src/space/create.rs
+++ b/implementations/rust/ockam/ockam_command/src/space/create.rs
@@ -50,7 +50,7 @@ impl Command for CreateCommand {
             ));
         };
 
-        let node = InMemoryNode::start(ctx, &opts.state).await?;
+        let node = InMemoryNode::start(ctx, opts.state.clone()).await?;
 
         let space = {
             let pb = opts.terminal.spinner();
diff --git a/implementations/rust/ockam/ockam_command/src/space/delete.rs b/implementations/rust/ockam/ockam_command/src/space/delete.rs
index 09450c0295d..2eb22639769 100644
--- a/implementations/rust/ockam/ockam_command/src/space/delete.rs
+++ b/implementations/rust/ockam/ockam_command/src/space/delete.rs
@@ -62,7 +62,7 @@ impl DeleteTui {
         opts: CommandGlobalOpts,
         cmd: DeleteCommand,
     ) -> miette::Result<()> {
-        let node = InMemoryNode::start(ctx, &opts.state).await?;
+        let node = InMemoryNode::start(ctx, opts.state.clone()).await?;
         let tui = Self {
             ctx: ctx.try_clone()?,
             opts,
diff --git a/implementations/rust/ockam/ockam_command/src/space/list.rs b/implementations/rust/ockam/ockam_command/src/space/list.rs
index 8fba67f0e11..ea8235c1659 100644
--- a/implementations/rust/ockam/ockam_command/src/space/list.rs
+++ b/implementations/rust/ockam/ockam_command/src/space/list.rs
@@ -29,7 +29,7 @@ impl Command for ListCommand {
     const NAME: &'static str = "space list";
 
     async fn run(self, ctx: &Context, opts: CommandGlobalOpts) -> crate::Result<()> {
-        let node = InMemoryNode::start(ctx, &opts.state).await?;
+        let node = InMemoryNode::start(ctx, opts.state.clone()).await?;
 
         let spaces = {
             let pb = opts.terminal.spinner();
diff --git a/implementations/rust/ockam/ockam_command/src/space/show.rs b/implementations/rust/ockam/ockam_command/src/space/show.rs
index 25944e3b1d7..54172613295 100644
--- a/implementations/rust/ockam/ockam_command/src/space/show.rs
+++ b/implementations/rust/ockam/ockam_command/src/space/show.rs
@@ -55,7 +55,7 @@ impl<'a> ShowTui<'a> {
         opts: CommandGlobalOpts,
         cmd: ShowCommand,
     ) -> miette::Result<()> {
-        let node = InMemoryNode::start(ctx, &opts.state).await?;
+        let node = InMemoryNode::start(ctx, opts.state.clone()).await?;
         let tui = Self {
             ctx,
             opts,
diff --git a/implementations/rust/ockam/ockam_command/src/space_admin/add.rs b/implementations/rust/ockam/ockam_command/src/space_admin/add.rs
index 7dfd72f7b68..2b4cf172b05 100644
--- a/implementations/rust/ockam/ockam_command/src/space_admin/add.rs
+++ b/implementations/rust/ockam/ockam_command/src/space_admin/add.rs
@@ -31,9 +31,12 @@ impl Command for AddCommand {
 
     async fn run(self, ctx: &Context, opts: CommandGlobalOpts) -> crate::Result<()> {
         let space = opts.state.get_space_by_name_or_default(&self.name).await?;
-        let node =
-            InMemoryNode::start_with_identity(ctx, &opts.state, self.identity_opts.identity_name)
-                .await?;
+        let node = InMemoryNode::start_with_identity(
+            ctx,
+            opts.state.clone(),
+            self.identity_opts.identity_name,
+        )
+        .await?;
         let admin = node
             .add_space_admin(ctx, &space.space_id(), &self.email)
             .await?;
diff --git a/implementations/rust/ockam/ockam_command/src/space_admin/delete.rs b/implementations/rust/ockam/ockam_command/src/space_admin/delete.rs
index 4ec28267969..a13d3382691 100644
--- a/implementations/rust/ockam/ockam_command/src/space_admin/delete.rs
+++ b/implementations/rust/ockam/ockam_command/src/space_admin/delete.rs
@@ -66,7 +66,7 @@ impl DeleteTui {
         let space = opts.state.get_space_by_name_or_default(&cmd.name).await?;
         let node = InMemoryNode::start_with_identity(
             ctx,
-            &opts.state,
+            opts.state.clone(),
             cmd.identity_opts.identity_name.clone(),
         )
         .await?;
diff --git a/implementations/rust/ockam/ockam_command/src/space_admin/list.rs b/implementations/rust/ockam/ockam_command/src/space_admin/list.rs
index 9bc943932af..1745ab6a627 100644
--- a/implementations/rust/ockam/ockam_command/src/space_admin/list.rs
+++ b/implementations/rust/ockam/ockam_command/src/space_admin/list.rs
@@ -23,9 +23,12 @@ impl Command for ListCommand {
 
     async fn run(self, ctx: &Context, opts: CommandGlobalOpts) -> crate::Result<()> {
         let space = opts.state.get_space_by_name_or_default(&self.name).await?;
-        let node =
-            InMemoryNode::start_with_identity(ctx, &opts.state, self.identity_opts.identity_name)
-                .await?;
+        let node = InMemoryNode::start_with_identity(
+            ctx,
+            opts.state.clone(),
+            self.identity_opts.identity_name,
+        )
+        .await?;
         let admins = node.list_space_admins(ctx, &space.space_id()).await?;
 
         let list = &opts.terminal.build_list(&admins, "No admins found")?;
diff --git a/implementations/rust/ockam/ockam_command/src/status/mod.rs b/implementations/rust/ockam/ockam_command/src/status/mod.rs
index 96e351b627f..9315d9c6c0c 100644
--- a/implementations/rust/ockam/ockam_command/src/status/mod.rs
+++ b/implementations/rust/ockam/ockam_command/src/status/mod.rs
@@ -46,7 +46,7 @@ impl Command for StatusCommand {
     async fn run(self, ctx: &Context, opts: CommandGlobalOpts) -> Result<()> {
         let identities_details = self.get_identities_details(&opts).await?;
         let nodes = self.get_nodes_resources(ctx, &opts).await?;
-        let node = InMemoryNode::start(ctx, &opts.state)
+        let node = InMemoryNode::start(ctx, opts.state.clone())
             .await?
             .with_timeout(self.timeout.timeout);
         let controller = node.create_controller().await?;
@@ -97,8 +97,8 @@ impl StatusCommand {
                 pb.set_message(format!("Retrieving node {}...", node.name()));
             }
             let mut node =
-                BackgroundNodeClient::create(ctx, &opts.state, &Some(node.name())).await?;
-            nodes_resources.push(get_node_resources(ctx, &opts.state, &mut node).await?);
+                BackgroundNodeClient::create(ctx, opts.state.clone(), &Some(node.name())).await?;
+            nodes_resources.push(get_node_resources(ctx, opts.state.clone(), &mut node).await?);
         }
         if let Some(ref pb) = pb {
             pb.finish_and_clear();
diff --git a/implementations/rust/ockam/ockam_command/src/subcommand.rs b/implementations/rust/ockam/ockam_command/src/subcommand.rs
index e6caeed19de..05ea43291ba 100644
--- a/implementations/rust/ockam/ockam_command/src/subcommand.rs
+++ b/implementations/rust/ockam/ockam_command/src/subcommand.rs
@@ -254,28 +254,33 @@ impl OckamSubcommand {
         }
     }
 
-    /// Return the node name for an ockam node create command
-    pub fn node_name(&self) -> Option<String> {
+    /// Return true if this command represents the execution of a local node
+    pub fn is_local_node(&self) -> bool {
         match self {
             OckamSubcommand::Node(cmd) => match &cmd.subcommand {
                 NodeSubcommand::Create(cmd) => {
-                    if cmd.foreground_args.child_process {
-                        Some(cmd.name.clone())
-                    } else {
-                        None
-                    }
+                    cmd.foreground_args.foreground || cmd.foreground_args.child_process
                 }
+                _ => false,
+            },
+
+            OckamSubcommand::Authority(cmd) => match &cmd.subcommand {
+                AuthoritySubcommand::Create(cmd) => cmd.foreground || cmd.child_process,
+            },
+            _ => false,
+        }
+    }
+
+    /// Return the node name for an ockam node create command
+    pub fn node_name(&self) -> Option<String> {
+        match self {
+            OckamSubcommand::Node(cmd) => match &cmd.subcommand {
+                NodeSubcommand::Create(cmd) => Some(cmd.name.clone()),
                 _ => None,
             },
 
             OckamSubcommand::Authority(cmd) => match &cmd.subcommand {
-                AuthoritySubcommand::Create(cmd) => {
-                    if cmd.child_process {
-                        Some(cmd.node_name())
-                    } else {
-                        None
-                    }
-                }
+                AuthoritySubcommand::Create(cmd) => Some(cmd.node_name()),
             },
             _ => None,
         }
diff --git a/implementations/rust/ockam/ockam_command/src/subscription.rs b/implementations/rust/ockam/ockam_command/src/subscription.rs
index 02d271d3d5c..3ae1fa45f1f 100644
--- a/implementations/rust/ockam/ockam_command/src/subscription.rs
+++ b/implementations/rust/ockam/ockam_command/src/subscription.rs
@@ -53,7 +53,7 @@ impl SubscriptionCommand {
     }
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
-        let node = InMemoryNode::start(ctx, &opts.state).await?;
+        let node = InMemoryNode::start(ctx, opts.state.clone()).await?;
         let controller = node.create_controller().await?;
 
         match &self.subcommand {
diff --git a/implementations/rust/ockam/ockam_command/src/tcp/connection/create.rs b/implementations/rust/ockam/ockam_command/src/tcp/connection/create.rs
index b8372bafbe0..3d5b3ec07be 100644
--- a/implementations/rust/ockam/ockam_command/src/tcp/connection/create.rs
+++ b/implementations/rust/ockam/ockam_command/src/tcp/connection/create.rs
@@ -41,7 +41,7 @@ impl Command for CreateCommand {
 
     async fn run(self, ctx: &Context, opts: CommandGlobalOpts) -> crate::Result<()> {
         initialize_default_node(ctx, &opts).await?;
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &self.from).await?;
+        let node = BackgroundNodeClient::create(ctx, opts.state.clone(), &self.from).await?;
         let payload = models::transport::CreateTcpConnection::new(self.address.clone());
         let request = Request::post("/node/tcp/connection").body(payload);
         let transport_status: TransportStatus = node.ask(ctx, request).await?;
diff --git a/implementations/rust/ockam/ockam_command/src/tcp/connection/delete.rs b/implementations/rust/ockam/ockam_command/src/tcp/connection/delete.rs
index 7352e186370..7ab8234c14e 100644
--- a/implementations/rust/ockam/ockam_command/src/tcp/connection/delete.rs
+++ b/implementations/rust/ockam/ockam_command/src/tcp/connection/delete.rs
@@ -36,7 +36,8 @@ impl DeleteCommand {
             "Are you sure you want to delete this TCP connection?",
         )? {
             let node =
-                BackgroundNodeClient::create(ctx, &opts.state, &self.node_opts.at_node).await?;
+                BackgroundNodeClient::create(ctx, opts.state.clone(), &self.node_opts.at_node)
+                    .await?;
             let address = self.address.clone();
             let req = Request::delete("/node/tcp/connection")
                 .body(models::transport::DeleteTransport::new(address.clone()));
diff --git a/implementations/rust/ockam/ockam_command/src/tcp/connection/list.rs b/implementations/rust/ockam/ockam_command/src/tcp/connection/list.rs
index 4d9493c7937..acc7ad43d4d 100644
--- a/implementations/rust/ockam/ockam_command/src/tcp/connection/list.rs
+++ b/implementations/rust/ockam/ockam_command/src/tcp/connection/list.rs
@@ -31,7 +31,8 @@ impl ListCommand {
     }
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &self.node_opts.at_node).await?;
+        let node =
+            BackgroundNodeClient::create(ctx, opts.state.clone(), &self.node_opts.at_node).await?;
         let is_finished: Mutex<bool> = Mutex::new(false);
 
         let get_transports = async {
diff --git a/implementations/rust/ockam/ockam_command/src/tcp/connection/show.rs b/implementations/rust/ockam/ockam_command/src/tcp/connection/show.rs
index 75729a2d632..0c3361f3b74 100644
--- a/implementations/rust/ockam/ockam_command/src/tcp/connection/show.rs
+++ b/implementations/rust/ockam/ockam_command/src/tcp/connection/show.rs
@@ -33,7 +33,8 @@ impl ShowCommand {
     }
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &self.node_opts.at_node).await?;
+        let node =
+            BackgroundNodeClient::create(ctx, opts.state.clone(), &self.node_opts.at_node).await?;
         let transport_status: TransportStatus = node
             .ask(
                 ctx,
diff --git a/implementations/rust/ockam/ockam_command/src/tcp/inlet/create.rs b/implementations/rust/ockam/ockam_command/src/tcp/inlet/create.rs
index 2bb572c0bc7..0ad31274d9b 100644
--- a/implementations/rust/ockam/ockam_command/src/tcp/inlet/create.rs
+++ b/implementations/rust/ockam/ockam_command/src/tcp/inlet/create.rs
@@ -36,6 +36,7 @@ use ockam_node::compat::asynchronous::resolve_peer;
 
 use std::collections::HashMap;
 use std::str::FromStr;
+use std::sync::Arc;
 use std::time::Duration;
 use tracing::trace;
 
@@ -190,7 +191,7 @@ impl Command for CreateCommand {
         initialize_default_node(ctx, &opts).await?;
         let cmd = self.parse_args(&opts).await?;
 
-        let mut node = BackgroundNodeClient::create(ctx, &opts.state, &cmd.at).await?;
+        let mut node = BackgroundNodeClient::create(ctx, opts.state.clone(), &cmd.at).await?;
         cmd.timeout.timeout.map(|t| node.set_timeout_mut(t));
 
         let inlet_status = {
@@ -250,7 +251,7 @@ impl Command for CreateCommand {
                         &cmd.allow,
                         cmd.connection_wait,
                         !cmd.no_connection_wait,
-                        &cmd.secure_channel_identifier(&opts.state).await?,
+                        &cmd.secure_channel_identifier(opts.state.clone()).await?,
                         cmd.udp || cmd.from.is_udp(),
                         cmd.no_tcp_fallback,
                         cmd.privileged,
@@ -347,7 +348,7 @@ impl CreateCommand {
 
     pub async fn secure_channel_identifier(
         &self,
-        state: &CliState,
+        state: Arc<CliState>,
     ) -> miette::Result<Option<Identifier>> {
         if let Some(identity_name) = self.identity.as_ref() {
             Ok(Some(state.get_identifier_by_name(identity_name).await?))
@@ -398,7 +399,7 @@ impl CreateCommand {
             .into_diagnostic()?;
         port_is_free_guard(&from)?;
 
-        self.to = Self::parse_arg_to(&opts.state, self.to, self.via.as_ref()).await?;
+        self.to = Self::parse_arg_to(opts.state.clone(), self.to, self.via.as_ref()).await?;
         if self.to().matches(0, &[proto::Project::CODE.into()]) && self.authorized.is_some() {
             return Err(miette!(
                 "--authorized can not be used with project addresses"
@@ -420,7 +421,7 @@ impl CreateCommand {
     }
 
     pub(crate) async fn parse_arg_to(
-        state: &CliState,
+        state: Arc<CliState>,
         to: impl Into<String>,
         via: Option<&String>,
     ) -> miette::Result<String> {
@@ -502,8 +503,8 @@ mod tests {
     #[ockam_macros::test]
     async fn parse_arg_to(ctx: &mut Context) -> ockam_core::Result<()> {
         // Setup
-        let state = CliState::test().await.unwrap();
-        let node = InMemoryNode::start(ctx, &state).await.unwrap();
+        let state = Arc::new(CliState::test().await.unwrap());
+        let node = InMemoryNode::start(ctx, state.clone()).await.unwrap();
         let node_name = node.node_name();
         let node_port = state
             .get_node(&node_name)
@@ -528,13 +529,13 @@ mod tests {
         // Invalid "to" values throw an error
         let cases = ["/alice/service", "alice/relay"];
         for to in cases {
-            CreateCommand::parse_arg_to(&state, to, None)
+            CreateCommand::parse_arg_to(state.clone(), to, None)
                 .await
                 .expect_err("Invalid multiaddr");
         }
 
         // "to" default value
-        let res = CreateCommand::parse_arg_to(&state, tcp_inlet_default_to_addr(), None)
+        let res = CreateCommand::parse_arg_to(state.clone(), tcp_inlet_default_to_addr(), None)
             .await
             .unwrap();
         assert_eq!(
@@ -549,13 +550,15 @@ mod tests {
             (&format!("/node/{node_name}/service/myoutlet"), Some(format!("/ip4/127.0.0.1/tcp/{node_port}/service/myoutlet"))),
         ];
         for (to, expected) in cases {
-            let res = CreateCommand::parse_arg_to(&state, to, None).await.unwrap();
+            let res = CreateCommand::parse_arg_to(state.clone(), to, None)
+                .await
+                .unwrap();
             let expected = expected.unwrap_or(to.to_string());
             assert_eq!(res, expected);
         }
 
         // "to" argument accepts the name of the service
-        let res = CreateCommand::parse_arg_to(&state, "myoutlet", None)
+        let res = CreateCommand::parse_arg_to(state.clone(), "myoutlet", None)
             .await
             .unwrap();
         assert_eq!(
@@ -577,7 +580,7 @@ mod tests {
             ),
         ];
         for (to, via, expected) in cases {
-            let res = CreateCommand::parse_arg_to(&state, &to, Some(&via.to_string()))
+            let res = CreateCommand::parse_arg_to(state.clone(), &to, Some(&via.to_string()))
                 .await
                 .unwrap();
             assert_eq!(res, expected.to_string());
@@ -585,7 +588,7 @@ mod tests {
 
         // if "to" is passed as a full route and also "via" is passed, return an error
         let to = "/project/p1/service/forward_to_n1/secure/api/service/outlet";
-        CreateCommand::parse_arg_to(&state, to, Some(&"myrelay".to_string()))
+        CreateCommand::parse_arg_to(state.clone(), to, Some(&"myrelay".to_string()))
             .await
             .expect_err("'via' can't be passed if 'to' is a full route");
 
diff --git a/implementations/rust/ockam/ockam_command/src/tcp/inlet/delete.rs b/implementations/rust/ockam/ockam_command/src/tcp/inlet/delete.rs
index e63503a0ac0..cc191c4c444 100644
--- a/implementations/rust/ockam/ockam_command/src/tcp/inlet/delete.rs
+++ b/implementations/rust/ockam/ockam_command/src/tcp/inlet/delete.rs
@@ -65,7 +65,8 @@ impl DeleteTui {
         opts: CommandGlobalOpts,
         cmd: DeleteCommand,
     ) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &cmd.node_opts.at_node).await?;
+        let node =
+            BackgroundNodeClient::create(ctx, opts.state.clone(), &cmd.node_opts.at_node).await?;
         let tui = Self {
             ctx: ctx.try_clone()?,
             opts,
diff --git a/implementations/rust/ockam/ockam_command/src/tcp/inlet/list.rs b/implementations/rust/ockam/ockam_command/src/tcp/inlet/list.rs
index 83e2d22df24..2a26df9f182 100644
--- a/implementations/rust/ockam/ockam_command/src/tcp/inlet/list.rs
+++ b/implementations/rust/ockam/ockam_command/src/tcp/inlet/list.rs
@@ -27,7 +27,8 @@ impl ListCommand {
     }
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &self.node.at_node).await?;
+        let node =
+            BackgroundNodeClient::create(ctx, opts.state.clone(), &self.node.at_node).await?;
         let inlets: InletStatusList = {
             let pb = opts.terminal.spinner();
             if let Some(pb) = pb.as_ref() {
diff --git a/implementations/rust/ockam/ockam_command/src/tcp/inlet/show.rs b/implementations/rust/ockam/ockam_command/src/tcp/inlet/show.rs
index 7d597abc64c..b231cf83a80 100644
--- a/implementations/rust/ockam/ockam_command/src/tcp/inlet/show.rs
+++ b/implementations/rust/ockam/ockam_command/src/tcp/inlet/show.rs
@@ -54,7 +54,7 @@ impl ShowTui {
         opts: CommandGlobalOpts,
         mut cmd: ShowCommand,
     ) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(&ctx, &opts.state, &cmd.at).await?;
+        let node = BackgroundNodeClient::create(&ctx, opts.state.clone(), &cmd.at).await?;
         cmd.at = Some(node.node_name().to_string());
 
         let tui = Self {
diff --git a/implementations/rust/ockam/ockam_command/src/tcp/listener/create.rs b/implementations/rust/ockam/ockam_command/src/tcp/listener/create.rs
index 4d05f476e12..0cab634ff4f 100644
--- a/implementations/rust/ockam/ockam_command/src/tcp/listener/create.rs
+++ b/implementations/rust/ockam/ockam_command/src/tcp/listener/create.rs
@@ -35,7 +35,7 @@ impl CreateCommand {
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
         initialize_default_node(ctx, &opts).await?;
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &self.at).await?;
+        let node = BackgroundNodeClient::create(ctx, opts.state.clone(), &self.at).await?;
         let transport_status: TransportStatus = node
             .ask(
                 ctx,
diff --git a/implementations/rust/ockam/ockam_command/src/tcp/listener/delete.rs b/implementations/rust/ockam/ockam_command/src/tcp/listener/delete.rs
index 023890fc353..b9d0d6e9008 100644
--- a/implementations/rust/ockam/ockam_command/src/tcp/listener/delete.rs
+++ b/implementations/rust/ockam/ockam_command/src/tcp/listener/delete.rs
@@ -33,7 +33,8 @@ impl DeleteCommand {
     }
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &self.node_opts.at_node).await?;
+        let node =
+            BackgroundNodeClient::create(ctx, opts.state.clone(), &self.node_opts.at_node).await?;
 
         // Check if there an TCP listener with the provided address exists
         let address = self.address.clone();
diff --git a/implementations/rust/ockam/ockam_command/src/tcp/listener/list.rs b/implementations/rust/ockam/ockam_command/src/tcp/listener/list.rs
index 761db796c2c..4aafbb63e8b 100644
--- a/implementations/rust/ockam/ockam_command/src/tcp/listener/list.rs
+++ b/implementations/rust/ockam/ockam_command/src/tcp/listener/list.rs
@@ -32,7 +32,8 @@ impl ListCommand {
     }
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &self.node_opts.at_node).await?;
+        let node =
+            BackgroundNodeClient::create(ctx, opts.state.clone(), &self.node_opts.at_node).await?;
         let is_finished: Mutex<bool> = Mutex::new(false);
 
         let get_transports = async {
diff --git a/implementations/rust/ockam/ockam_command/src/tcp/listener/show.rs b/implementations/rust/ockam/ockam_command/src/tcp/listener/show.rs
index 4e3727e9ec0..7c6362eca85 100644
--- a/implementations/rust/ockam/ockam_command/src/tcp/listener/show.rs
+++ b/implementations/rust/ockam/ockam_command/src/tcp/listener/show.rs
@@ -31,7 +31,8 @@ impl ShowCommand {
     }
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &self.node_opts.at_node).await?;
+        let node =
+            BackgroundNodeClient::create(ctx, opts.state.clone(), &self.node_opts.at_node).await?;
         let transport_status: TransportStatus = node
             .ask(
                 ctx,
diff --git a/implementations/rust/ockam/ockam_command/src/tcp/outlet/create.rs b/implementations/rust/ockam/ockam_command/src/tcp/outlet/create.rs
index 3e4704c03c0..0358938fa1f 100644
--- a/implementations/rust/ockam/ockam_command/src/tcp/outlet/create.rs
+++ b/implementations/rust/ockam/ockam_command/src/tcp/outlet/create.rs
@@ -93,7 +93,7 @@ impl Command for CreateCommand {
         initialize_default_node(ctx, &opts).await?;
         let cmd = self.parse_args(&opts).await?;
 
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &cmd.at).await?;
+        let node = BackgroundNodeClient::create(ctx, opts.state.clone(), &cmd.at).await?;
         let node_name = node.node_name();
         let outlet_status = {
             let pb = opts.terminal.spinner();
diff --git a/implementations/rust/ockam/ockam_command/src/tcp/outlet/delete.rs b/implementations/rust/ockam/ockam_command/src/tcp/outlet/delete.rs
index 22ab0ec08e9..4f28ec73e50 100644
--- a/implementations/rust/ockam/ockam_command/src/tcp/outlet/delete.rs
+++ b/implementations/rust/ockam/ockam_command/src/tcp/outlet/delete.rs
@@ -70,7 +70,8 @@ impl DeleteTui {
         opts: CommandGlobalOpts,
         cmd: DeleteCommand,
     ) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &cmd.node_opts.at_node).await?;
+        let node =
+            BackgroundNodeClient::create(ctx, opts.state.clone(), &cmd.node_opts.at_node).await?;
         let tui = Self {
             ctx: ctx.try_clone()?,
             opts,
diff --git a/implementations/rust/ockam/ockam_command/src/tcp/outlet/list.rs b/implementations/rust/ockam/ockam_command/src/tcp/outlet/list.rs
index e634b5569af..898724231c3 100644
--- a/implementations/rust/ockam/ockam_command/src/tcp/outlet/list.rs
+++ b/implementations/rust/ockam/ockam_command/src/tcp/outlet/list.rs
@@ -34,7 +34,8 @@ impl ListCommand {
     }
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &self.node_opts.at_node).await?;
+        let node =
+            BackgroundNodeClient::create(ctx, opts.state.clone(), &self.node_opts.at_node).await?;
 
         let is_finished: Mutex<bool> = Mutex::new(false);
 
diff --git a/implementations/rust/ockam/ockam_command/src/tcp/outlet/show.rs b/implementations/rust/ockam/ockam_command/src/tcp/outlet/show.rs
index b5b223d175a..35ab74748ad 100644
--- a/implementations/rust/ockam/ockam_command/src/tcp/outlet/show.rs
+++ b/implementations/rust/ockam/ockam_command/src/tcp/outlet/show.rs
@@ -82,7 +82,7 @@ impl ShowTui {
         opts: CommandGlobalOpts,
         mut cmd: ShowCommand,
     ) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(&ctx, &opts.state, &cmd.at).await?;
+        let node = BackgroundNodeClient::create(&ctx, opts.state.clone(), &cmd.at).await?;
         cmd.at = Some(node.node_name().to_string());
 
         let tui = Self {
diff --git a/implementations/rust/ockam/ockam_command/src/util/mod.rs b/implementations/rust/ockam/ockam_command/src/util/mod.rs
index 2bbd4c6f2c7..7df9f561122 100644
--- a/implementations/rust/ockam/ockam_command/src/util/mod.rs
+++ b/implementations/rust/ockam/ockam_command/src/util/mod.rs
@@ -1,8 +1,3 @@
-use std::{
-    net::{SocketAddr, TcpListener},
-    path::Path,
-};
-
 use colorful::Colorful;
 use miette::miette;
 use ockam_api::cli_state::CliState;
@@ -11,6 +6,11 @@ use ockam_api::config::lookup::{InternetAddress, LookupMeta};
 use ockam_api::fmt_warn;
 use ockam_multiaddr::proto::{DnsAddr, Ip4, Ip6, Project, Space, Tcp};
 use ockam_multiaddr::{proto::Node, MultiAddr, Protocol};
+use std::sync::Arc;
+use std::{
+    net::{SocketAddr, TcpListener},
+    path::Path,
+};
 
 use crate::{CommandGlobalOpts, Result};
 
@@ -33,7 +33,10 @@ pub fn print_path(p: &Path) -> String {
 /// Example:
 ///     if n1 has address of 127.0.0.1:1234
 ///     `/node/n1` -> `/ip4/127.0.0.1/tcp/1234`
-pub async fn process_nodes_multiaddr(addr: &MultiAddr, cli_state: &CliState) -> Result<MultiAddr> {
+pub async fn process_nodes_multiaddr(
+    addr: &MultiAddr,
+    cli_state: Arc<CliState>,
+) -> Result<MultiAddr> {
     let mut processed_addr = MultiAddr::default();
     for proto in addr.iter() {
         match proto.code() {
@@ -56,7 +59,7 @@ pub async fn process_nodes_multiaddr(addr: &MultiAddr, cli_state: &CliState) ->
 /// qualified address to the target
 pub async fn clean_nodes_multiaddr(
     input: &MultiAddr,
-    cli_state: &CliState,
+    cli_state: Arc<CliState>,
 ) -> Result<(MultiAddr, LookupMeta)> {
     let mut new_ma = MultiAddr::default();
     let mut lookup_meta = LookupMeta::default();
@@ -139,7 +142,7 @@ mod tests {
 
     #[ockam_macros::test(crate = "ockam")]
     async fn test_process_multi_addr(_ctx: &mut Context) -> ockam::Result<()> {
-        let cli_state = CliState::test().await?;
+        let cli_state = Arc::new(CliState::test().await?);
 
         cli_state.create_node("n1").await?;
 
@@ -165,13 +168,15 @@ mod tests {
         ];
         for (ma, expected) in test_cases {
             if let Ok(addr) = expected {
-                let result = process_nodes_multiaddr(&ma, &cli_state)
+                let result = process_nodes_multiaddr(&ma, cli_state.clone())
                     .await
                     .unwrap()
                     .to_string();
                 assert_eq!(result, addr);
             } else {
-                assert!(process_nodes_multiaddr(&ma, &cli_state).await.is_err());
+                assert!(process_nodes_multiaddr(&ma, cli_state.clone())
+                    .await
+                    .is_err());
             }
         }
         Ok(())
diff --git a/implementations/rust/ockam/ockam_command/src/worker/list.rs b/implementations/rust/ockam/ockam_command/src/worker/list.rs
index 9e05a4b9d62..027e3c02ad7 100644
--- a/implementations/rust/ockam/ockam_command/src/worker/list.rs
+++ b/implementations/rust/ockam/ockam_command/src/worker/list.rs
@@ -36,7 +36,7 @@ impl ListCommand {
     }
 
     pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
-        let node = BackgroundNodeClient::create(ctx, &opts.state, &self.at).await?;
+        let node = BackgroundNodeClient::create(ctx, opts.state.clone(), &self.at).await?;
         let is_finished: Mutex<bool> = Mutex::new(false);
 
         let get_workers = async {
diff --git a/implementations/rust/ockam/ockam_core/src/routing/message/local_message.rs b/implementations/rust/ockam/ockam_core/src/routing/message/local_message.rs
index 80d30d09175..e7797aa2441 100644
--- a/implementations/rust/ockam/ockam_core/src/routing/message/local_message.rs
+++ b/implementations/rust/ockam/ockam_core/src/routing/message/local_message.rs
@@ -209,53 +209,12 @@ impl LocalMessage {
 
         cfg_if! {
             if #[cfg(feature = "std")] {
-                // make sure to pass the latest tracing context
-                let new_tracing_context = Self::start_new_tracing_context(self.tracing_context.update(), "TransportMessage");
-                transport_message.with_tracing_context(new_tracing_context)
+                transport_message.with_tracing_context(self.tracing_context.to_string())
             } else {
                 transport_message
             }
         }
     }
-
-    /// - A new trace is started
-    /// - The previous trace and the new trace are linked together
-    ///
-    /// We start a new trace here in order to make sure that each transport message is always
-    /// associated to a globally unique trace id and then cannot be correlated with another transport
-    /// message that would leave the same node for example.
-    ///
-    /// We can still navigate the two created traces as one thanks to their link.
-    #[cfg(feature = "std")]
-    pub fn start_new_tracing_context(
-        tracing_context: OpenTelemetryContext,
-        span_prefix: &str,
-    ) -> String {
-        use crate::OCKAM_TRACER_NAME;
-        use opentelemetry::trace::{Link, SpanBuilder, TraceContextExt, Tracer};
-        use opentelemetry::{global, Context};
-
-        // start a new trace for this transport message, and link it to the previous trace, via the current tracing context
-        let tracer = global::tracer(OCKAM_TRACER_NAME);
-        let span_builder = SpanBuilder::from_name(format!("{}::start_trace", span_prefix))
-            .with_links(vec![Link::new(
-                tracing_context.extract().span().span_context().clone(),
-                vec![],
-                0,
-            )]);
-        let span = tracer.build_with_context(span_builder, &Context::default());
-        let cx = Context::current_with_span(span);
-
-        // create a span to close the previous trace and link it to the new trace
-        let span_builder = SpanBuilder::from_name(format!("{}::end_trace", span_prefix))
-            .with_links(vec![Link::new(cx.span().span_context().clone(), vec![], 0)]);
-        let _ = tracer.build_with_context(span_builder, &tracing_context.extract());
-
-        // create the new opentelemetry context
-        let new_tracing_context = OpenTelemetryContext::inject(&cx);
-
-        new_tracing_context.to_string()
-    }
 }
 
 impl Default for LocalMessage {
diff --git a/implementations/rust/ockam/ockam_identity/src/identities/identities_attributes.rs b/implementations/rust/ockam/ockam_identity/src/identities/identities_attributes.rs
index d2f7cdafaea..4d4532bd668 100644
--- a/implementations/rust/ockam/ockam_identity/src/identities/identities_attributes.rs
+++ b/implementations/rust/ockam/ockam_identity/src/identities/identities_attributes.rs
@@ -2,6 +2,7 @@ use crate::utils::now;
 use crate::{AttributesEntry, Identifier, IdentityAttributesRepository};
 use ockam_core::compat::sync::Arc;
 use ockam_core::Result;
+use tracing::Level;
 use tracing_attributes::instrument;
 
 /// This struct provides access to the identities attributes stored on a node.
@@ -26,7 +27,7 @@ impl IdentitiesAttributes {
     /// Return the attributes for a given pair subject/attesting authority
     /// If there are expired attributes for any subject, they are deleted before retrieving the attributes for the
     /// current subject.
-    #[instrument(skip_all, fields(subject = %subject, attested_by = %attested_by))]
+    #[instrument(skip_all, fields(subject = %subject, attested_by = %attested_by), level = Level::TRACE)]
     pub async fn get_attributes(
         &self,
         subject: &Identifier,
@@ -38,7 +39,7 @@ impl IdentitiesAttributes {
 
     /// Set the attributes associated with the given identity identifier.
     /// Previous values gets overridden.
-    #[instrument(skip_all, fields(subject = %subject, entry = %entry))]
+    #[instrument(skip_all, fields(subject = %subject, entry = %entry), level = Level::TRACE)]
     pub async fn put_attributes(&self, subject: &Identifier, entry: AttributesEntry) -> Result<()> {
         self.repository.put_attributes(subject, entry).await
     }
diff --git a/implementations/rust/ockam/ockam_identity/src/secure_channel/decryptor.rs b/implementations/rust/ockam/ockam_identity/src/secure_channel/decryptor.rs
index 82984807479..17e335b60aa 100644
--- a/implementations/rust/ockam/ockam_identity/src/secure_channel/decryptor.rs
+++ b/implementations/rust/ockam/ockam_identity/src/secure_channel/decryptor.rs
@@ -18,7 +18,7 @@ use crate::{
 
 use crate::secure_channel::encryptor_worker::SecureChannelSharedState;
 use ockam_vault::{AeadSecretKeyHandle, VaultForSecureChannels};
-use tracing::{debug, info, trace, warn};
+use tracing::{debug, info, trace, warn, Level};
 use tracing_attributes::instrument;
 
 pub(crate) struct DecryptorHandler {
@@ -63,7 +63,7 @@ impl DecryptorHandler {
         }
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub(crate) async fn handle_decrypt_api(
         &mut self,
         ctx: &mut Context,
@@ -182,7 +182,7 @@ impl DecryptorHandler {
         Ok(())
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub(crate) async fn handle_decrypt(
         &mut self,
         ctx: &mut Context,
@@ -248,7 +248,7 @@ impl Decryptor {
         }
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn decrypt<'a>(&mut self, payload: &'a mut [u8]) -> Result<(&'a [u8], Nonce)> {
         if payload.len() < NOISE_NONCE_LEN {
             return Err(IdentityError::InvalidNonce)?;
@@ -303,7 +303,7 @@ impl Decryptor {
     }
 
     /// Remove the channel keys on shutdown
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub(crate) async fn shutdown(&self) -> Result<()> {
         self.vault
             .delete_aead_secret_key(self.key_tracker.current_key.clone())
diff --git a/implementations/rust/ockam/ockam_identity/src/secure_channel/encryptor.rs b/implementations/rust/ockam/ockam_identity/src/secure_channel/encryptor.rs
index b7e7db73b28..94ea23b1761 100644
--- a/implementations/rust/ockam/ockam_identity/src/secure_channel/encryptor.rs
+++ b/implementations/rust/ockam/ockam_identity/src/secure_channel/encryptor.rs
@@ -2,6 +2,7 @@ use ockam_core::compat::sync::Arc;
 use ockam_core::errcode::{Kind, Origin};
 use ockam_core::{Error, Result};
 use ockam_vault::{AeadSecretKeyHandle, VaultForSecureChannels};
+use tracing::Level;
 use tracing_attributes::instrument;
 
 use crate::secure_channel::handshake::handshake::AES_GCM_TAGSIZE;
@@ -20,7 +21,7 @@ pub(crate) struct Encryptor {
 pub(crate) const KEY_RENEWAL_INTERVAL: u64 = 32;
 
 impl Encryptor {
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn rekey(
         vault: &Arc<dyn VaultForSecureChannels>,
         key: &AeadSecretKeyHandle,
@@ -42,7 +43,7 @@ impl Encryptor {
         vault.convert_secret_buffer_to_aead_key(buffer).await
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub async fn encrypt(&mut self, payload: &mut [u8]) -> Result<()> {
         let current_nonce = self.nonce;
 
@@ -85,7 +86,7 @@ impl Encryptor {
         }
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub(crate) async fn shutdown(&self) -> Result<()> {
         if !self.vault.delete_aead_secret_key(self.key.clone()).await? {
             Err(Error::new(
diff --git a/implementations/rust/ockam/ockam_identity/src/secure_channel/encryptor_worker.rs b/implementations/rust/ockam/ockam_identity/src/secure_channel/encryptor_worker.rs
index aa7c8238c01..d05ab5b5444 100644
--- a/implementations/rust/ockam/ockam_identity/src/secure_channel/encryptor_worker.rs
+++ b/implementations/rust/ockam/ockam_identity/src/secure_channel/encryptor_worker.rs
@@ -1,6 +1,6 @@
 use core::sync::atomic::{AtomicBool, Ordering};
 
-use tracing::{debug, error, info, trace, warn};
+use tracing::{debug, error, info, trace, warn, Level};
 use tracing_attributes::instrument;
 
 use ockam_core::compat::boxed::Box;
@@ -127,7 +127,7 @@ impl EncryptorWorker {
         }
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn handle_encrypt_api(
         &mut self,
         ctx: &mut <Self as Worker>::Context,
@@ -184,7 +184,7 @@ impl EncryptorWorker {
         Ok(())
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn handle_encrypt(
         &mut self,
         ctx: &mut <Self as Worker>::Context,
@@ -234,7 +234,7 @@ impl EncryptorWorker {
 
     /// Asks credential retriever for a new credential and presents it to the other side, including
     /// the latest change_history
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn handle_refresh_credentials(&mut self, ctx: &<Self as Worker>::Context) -> Result<()> {
         trace!(
             "Started credentials refresh for {}",
@@ -360,7 +360,7 @@ impl Worker for EncryptorWorker {
         Ok(())
     }
 
-    #[instrument(skip_all, name = "EncryptorWorker::handle_message", fields(worker = % ctx.primary_address()))]
+    #[instrument(skip_all, name = "EncryptorWorker::handle_message", fields(worker = % ctx.primary_address()), level = Level::TRACE)]
     async fn handle_message(
         &mut self,
         ctx: &mut Self::Context,
@@ -387,7 +387,7 @@ impl Worker for EncryptorWorker {
         Ok(())
     }
 
-    #[instrument(skip_all, name = "EncryptorWorker::shutdown")]
+    #[instrument(skip_all, name = "EncryptorWorker::shutdown", level = Level::TRACE)]
     async fn shutdown(&mut self, context: &mut Self::Context) -> Result<()> {
         if let Some(credential_retriever) = &self.credential_retriever {
             credential_retriever.unsubscribe(&self.addresses.encryptor_internal)?;
diff --git a/implementations/rust/ockam/ockam_identity/src/secure_channel/handshake/handshake_worker.rs b/implementations/rust/ockam/ockam_identity/src/secure_channel/handshake/handshake_worker.rs
index 010942aa99b..c2295868ded 100644
--- a/implementations/rust/ockam/ockam_identity/src/secure_channel/handshake/handshake_worker.rs
+++ b/implementations/rust/ockam/ockam_identity/src/secure_channel/handshake/handshake_worker.rs
@@ -11,7 +11,7 @@ use ockam_core::{Result, Worker};
 use ockam_node::callback::CallbackSender;
 use ockam_node::{Context, WorkerBuilder};
 use ockam_vault::AeadSecretKeyHandle;
-use tracing::{debug, error, info, trace, warn};
+use tracing::{debug, error, info, trace, warn, Level};
 use tracing_attributes::instrument;
 
 use crate::models::Identifier;
@@ -261,7 +261,7 @@ impl HandshakeWorker {
     ///   - one for decryption
     ///
     /// See also the handle_decrypt method.
-    #[instrument(skip_all, name = "HandshakeWorker::handle_message")]
+    #[instrument(skip_all, name = "HandshakeWorker::handle_message", level = Level::TRACE)]
     async fn handle_handshake(
         &mut self,
         context: &mut Context,
@@ -321,7 +321,7 @@ impl HandshakeWorker {
     ///
     /// In reality, there's only one worker, the HandshakeWorker, serves as both a worker for handshakes
     /// and for decryption.
-    #[instrument(skip_all, name = "DecryptorWorker::handle_message")]
+    #[instrument(skip_all, name = "DecryptorWorker::handle_message", level = Level::TRACE)]
     async fn handle_decrypt(&mut self, context: &mut Context, message: Routed<Any>) -> Result<()> {
         trace!(
             remote_route = ?self.remote_route,
diff --git a/implementations/rust/ockam/ockam_identity/src/secure_channel/key_tracker.rs b/implementations/rust/ockam/ockam_identity/src/secure_channel/key_tracker.rs
index d0c48339e65..4d1cf2f34aa 100644
--- a/implementations/rust/ockam/ockam_identity/src/secure_channel/key_tracker.rs
+++ b/implementations/rust/ockam/ockam_identity/src/secure_channel/key_tracker.rs
@@ -1,6 +1,6 @@
 use ockam_core::Result;
 use ockam_vault::AeadSecretKeyHandle;
-use tracing::{trace, warn};
+use tracing::{trace, warn, Level};
 use tracing_attributes::instrument;
 
 use crate::{IdentityError, Nonce};
@@ -39,7 +39,7 @@ impl KeyTracker {
     ///      - if the the nonce falls before the previous interval
     ///      - if it the previous nonce but is not set
     ///      - we reached the maximum number of rekeyings
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub(crate) fn get_key(&self, nonce: Nonce) -> Result<Option<&AeadSecretKeyHandle>> {
         trace!(
             "The current number of rekeys is {}, the rekey interval is {}",
@@ -89,7 +89,7 @@ impl KeyTracker {
     }
 
     // Update the key if a key renewal happened
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub(crate) fn update_key(
         &mut self,
         decryption_key: &AeadSecretKeyHandle,
diff --git a/implementations/rust/ockam/ockam_identity/src/secure_channel/nonce_tracker.rs b/implementations/rust/ockam/ockam_identity/src/secure_channel/nonce_tracker.rs
index a313711c06d..4d5ff7ffc30 100644
--- a/implementations/rust/ockam/ockam_identity/src/secure_channel/nonce_tracker.rs
+++ b/implementations/rust/ockam/ockam_identity/src/secure_channel/nonce_tracker.rs
@@ -1,5 +1,6 @@
 use crate::secure_channel::encryptor::KEY_RENEWAL_INTERVAL;
 use crate::{IdentityError, Nonce};
+use tracing::Level;
 use tracing_attributes::instrument;
 
 /// fails compilation if [`KEY_RENEWAL_INTERVAL`] + 1 is bigger than [`BitmapType::BITS`].
@@ -24,7 +25,7 @@ impl NonceTracker {
     }
 
     /// Mark a nonce as received, reject all invalid nonce values
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub(crate) fn mark(&self, nonce: Nonce) -> ockam_core::Result<NonceTracker> {
         let new_tracker = if nonce > self.current_nonce {
             // normal case, we increase the nonce and move the window
diff --git a/implementations/rust/ockam/ockam_node/src/context/context.rs b/implementations/rust/ockam/ockam_node/src/context/context.rs
index 8c55d27eee9..3baa4683337 100644
--- a/implementations/rust/ockam/ockam_node/src/context/context.rs
+++ b/implementations/rust/ockam/ockam_node/src/context/context.rs
@@ -18,6 +18,8 @@ use core::fmt::{Debug, Formatter};
 use ockam_core::compat::sync::Weak;
 use ockam_core::errcode::{Kind, Origin};
 use ockam_transport_core::Transport;
+#[cfg(feature = "std")]
+use opentelemetry::trace::{Span, TraceContextExt};
 
 /// A default timeout in seconds
 pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
@@ -148,6 +150,14 @@ impl Context {
     pub fn set_tracing_context(&mut self, tracing_context: OpenTelemetryContext) {
         self.tracing_context = tracing_context
     }
+
+    /// Set the current tracing context from a started span
+    #[cfg(feature = "std")]
+    pub fn set_tracing_context_from_span(&mut self, span: impl Span) {
+        let context =
+            opentelemetry::Context::new().with_remote_span_context(span.span_context().clone());
+        self.tracing_context = OpenTelemetryContext::inject(&context)
+    }
 }
 
 impl Context {
diff --git a/implementations/rust/ockam/ockam_transport_tcp/src/portal/inlet_listener.rs b/implementations/rust/ockam/ockam_transport_tcp/src/portal/inlet_listener.rs
index a184191bcd1..50e387b1bdf 100644
--- a/implementations/rust/ockam/ockam_transport_tcp/src/portal/inlet_listener.rs
+++ b/implementations/rust/ockam/ockam_transport_tcp/src/portal/inlet_listener.rs
@@ -16,7 +16,7 @@ use std::time::Duration;
 use tokio::net::TcpListener;
 use tokio::time::Instant;
 use tokio_rustls::{TlsAcceptor, TlsStream};
-use tracing::{debug, error, instrument};
+use tracing::{debug, error, instrument, Level};
 
 /// A TCP Portal Inlet listen processor
 ///
@@ -46,7 +46,7 @@ impl TcpInletListenProcessor {
     }
 
     /// Start a new `TcpInletListenProcessor`
-    #[instrument(skip_all, name = "TcpInletListenProcessor::start")]
+    #[instrument(skip_all, name = "TcpInletListenProcessor::start", level = Level::TRACE)]
     pub(crate) async fn start(
         ctx: &Context,
         registry: TcpRegistry,
@@ -158,7 +158,7 @@ const DEFAULT_TIMEOUT: Duration = Duration::from_secs(2 * 60);
 impl Processor for TcpInletListenProcessor {
     type Context = Context;
 
-    #[instrument(skip_all, name = "TcpInletListenProcessor::initialize")]
+    #[instrument(skip_all, name = "TcpInletListenProcessor::initialize", level = Level::TRACE)]
     async fn initialize(&mut self, ctx: &mut Self::Context) -> Result<()> {
         self.registry
             .add_inlet_listener_processor(ctx.primary_address());
@@ -166,7 +166,7 @@ impl Processor for TcpInletListenProcessor {
         Ok(())
     }
 
-    #[instrument(skip_all, name = "TcpInletListenProcessor::shutdown")]
+    #[instrument(skip_all, name = "TcpInletListenProcessor::shutdown", level = Level::TRACE)]
     async fn shutdown(&mut self, ctx: &mut Self::Context) -> Result<()> {
         self.registry
             .remove_inlet_listener_processor(ctx.primary_address());
@@ -174,7 +174,7 @@ impl Processor for TcpInletListenProcessor {
         Ok(())
     }
 
-    #[instrument(skip_all, name = "TcpInletListenProcessor::process")]
+    #[instrument(skip_all, name = "TcpInletListenProcessor::process", level = Level::TRACE)]
     async fn process(&mut self, ctx: &mut Self::Context) -> Result<bool> {
         let (stream, socket_addr) = self.inner.accept().await.map_err(TransportError::from)?;
 
diff --git a/implementations/rust/ockam/ockam_transport_tcp/src/portal/outlet_listener.rs b/implementations/rust/ockam/ockam_transport_tcp/src/portal/outlet_listener.rs
index 48b96655dbf..e7513cd0b65 100644
--- a/implementations/rust/ockam/ockam_transport_tcp/src/portal/outlet_listener.rs
+++ b/implementations/rust/ockam/ockam_transport_tcp/src/portal/outlet_listener.rs
@@ -7,7 +7,7 @@ use ockam_core::{
 };
 use ockam_node::{Context, WorkerBuilder};
 use ockam_transport_core::{HostnamePort, TransportError};
-use tracing::{debug, instrument};
+use tracing::{debug, instrument, Level};
 
 /// A TCP Portal Outlet listen worker
 ///
@@ -32,7 +32,7 @@ impl TcpOutletListenWorker {
         }
     }
 
-    #[instrument(skip_all, name = "TcpOutletListenWorker::start")]
+    #[instrument(skip_all, name = "TcpOutletListenWorker::start", level = Level::TRACE)]
     pub(crate) fn start(
         ctx: &Context,
         registry: TcpRegistry,
@@ -82,7 +82,7 @@ impl Worker for TcpOutletListenWorker {
     type Context = Context;
     type Message = NeutralMessage;
 
-    #[instrument(skip_all, name = "TcpOutletListenWorker::initialize")]
+    #[instrument(skip_all, name = "TcpOutletListenWorker::initialize", level = Level::TRACE)]
     async fn initialize(&mut self, ctx: &mut Self::Context) -> Result<()> {
         self.registry
             .add_outlet_listener_worker(ctx.primary_address());
@@ -90,7 +90,7 @@ impl Worker for TcpOutletListenWorker {
         Ok(())
     }
 
-    #[instrument(skip_all, name = "TcpOutletListenWorker::shutdown")]
+    #[instrument(skip_all, name = "TcpOutletListenWorker::shutdown", level = Level::TRACE)]
     async fn shutdown(&mut self, ctx: &mut Self::Context) -> Result<()> {
         self.registry
             .remove_outlet_listener_worker(ctx.primary_address());
@@ -98,7 +98,7 @@ impl Worker for TcpOutletListenWorker {
         Ok(())
     }
 
-    #[instrument(skip_all, name = "TcpOutletListenWorker::handle_message")]
+    #[instrument(skip_all, name = "TcpOutletListenWorker::handle_message", level = Level::TRACE)]
     async fn handle_message(
         &mut self,
         ctx: &mut Self::Context,
diff --git a/implementations/rust/ockam/ockam_transport_tcp/src/portal/portal_message.rs b/implementations/rust/ockam/ockam_transport_tcp/src/portal/portal_message.rs
index 5ae69225766..4b2ed954e62 100644
--- a/implementations/rust/ockam/ockam_transport_tcp/src/portal/portal_message.rs
+++ b/implementations/rust/ockam/ockam_transport_tcp/src/portal/portal_message.rs
@@ -65,6 +65,16 @@ impl<'de> PortalMessage<'de> {
     pub fn to_neutral_message(self) -> ockam_core::Result<NeutralMessage> {
         Ok(NeutralMessage::from(self.encode()?))
     }
+
+    /// Return true for a disconnect message
+    pub fn is_disconnect(&self) -> bool {
+        match self {
+            PortalMessage::Disconnect => true,
+            PortalMessage::Ping => false,
+            PortalMessage::Pong => false,
+            PortalMessage::Payload(_, _) => false,
+        }
+    }
 }
 
 impl Encodable for PortalMessage<'_> {
diff --git a/implementations/rust/ockam/ockam_transport_tcp/src/portal/portal_receiver.rs b/implementations/rust/ockam/ockam_transport_tcp/src/portal/portal_receiver.rs
index 1caae0d149a..2555be8c0a2 100644
--- a/implementations/rust/ockam/ockam_transport_tcp/src/portal/portal_receiver.rs
+++ b/implementations/rust/ockam/ockam_transport_tcp/src/portal/portal_receiver.rs
@@ -1,16 +1,14 @@
-use crate::portal::addresses::Addresses;
+use crate::portal::addresses::{Addresses, PortalType};
 use crate::{PortalInternalMessage, PortalMessage, TcpRegistry};
 use ockam_core::compat::vec::Vec;
-use ockam_core::{
-    async_trait, Encodable, LocalMessage, OpenTelemetryContext, Route, OCKAM_TRACER_NAME,
-};
+use ockam_core::{async_trait, Encodable, LocalMessage, Route, OCKAM_TRACER_NAME};
 use ockam_core::{route, Processor, Result};
 use ockam_node::Context;
-use opentelemetry::global;
-use opentelemetry::trace::Tracer;
+use opentelemetry::trace::{Span, Tracer};
+use opentelemetry::{global, KeyValue};
 use tokio::io::AsyncRead;
 use tokio::io::AsyncReadExt;
-use tracing::{debug, error, instrument};
+use tracing::{debug, error, instrument, Level};
 
 /// A TCP Portal receiving message processor
 ///
@@ -52,7 +50,7 @@ impl<R: AsyncRead + Unpin + Send + Sync + 'static> TcpPortalRecvProcessor<R> {
 impl<R: AsyncRead + Unpin + Send + Sync + 'static> Processor for TcpPortalRecvProcessor<R> {
     type Context = Context;
 
-    #[instrument(skip_all, name = "TcpPortalRecvProcessor::initialize")]
+    #[instrument(skip_all, name = "TcpPortalRecvProcessor::initialize", level = Level::TRACE)]
     async fn initialize(&mut self, ctx: &mut Self::Context) -> Result<()> {
         self.registry
             .add_portal_receiver_processor(ctx.primary_address());
@@ -60,7 +58,7 @@ impl<R: AsyncRead + Unpin + Send + Sync + 'static> Processor for TcpPortalRecvPr
         Ok(())
     }
 
-    #[instrument(skip_all, name = "TcpPortalRecvProcessor::shutdown")]
+    #[instrument(skip_all, name = "TcpPortalRecvProcessor::shutdown", level = Level::TRACE)]
     async fn shutdown(&mut self, ctx: &mut Self::Context) -> Result<()> {
         self.registry
             .remove_portal_receiver_processor(ctx.primary_address());
@@ -68,7 +66,6 @@ impl<R: AsyncRead + Unpin + Send + Sync + 'static> Processor for TcpPortalRecvPr
         Ok(())
     }
 
-    #[instrument(skip_all, name = "TcpPortalRecvProcessor::process")]
     async fn process(&mut self, ctx: &mut Context) -> Result<bool> {
         self.buf.clear();
 
@@ -80,14 +77,8 @@ impl<R: AsyncRead + Unpin + Send + Sync + 'static> Processor for TcpPortalRecvPr
             }
         };
 
-        let tracer = global::tracer(OCKAM_TRACER_NAME);
-        let tracing_context = tracer.in_span("TcpPortalRecvProcessor::forward_message", |cx| {
-            OpenTelemetryContext::inject(&cx)
-        });
-
         if self.buf.is_empty() {
             // Notify Sender that connection was closed
-            ctx.set_tracing_context(tracing_context.clone());
             if let Err(err) = ctx
                 .send_from_address(
                     route![self.addresses.sender_internal.clone()],
@@ -101,31 +92,22 @@ impl<R: AsyncRead + Unpin + Send + Sync + 'static> Processor for TcpPortalRecvPr
                     err
                 );
             }
+            return self.disconnect(ctx).await;
+        };
 
-            if let Err(err) = ctx
-                .forward_from_address(
-                    LocalMessage::new()
-                        .with_tracing_context(tracing_context.clone())
-                        .with_onward_route(self.onward_route.clone())
-                        .with_return_route(route![self.addresses.sender_remote.clone()])
-                        .with_payload(PortalMessage::Disconnect.encode()?),
-                    self.addresses.receiver_remote.clone(),
-                )
-                .await
-            {
-                debug!(
-                    "Error notifying the other side of the portal about dropped connection {}",
-                    err
-                );
-            }
+        self.send_message(ctx).await
+    }
+}
 
-            return Ok(false);
-        }
+impl<R: AsyncRead + Unpin + Send + Sync + 'static> TcpPortalRecvProcessor<R> {
+    async fn send_message(&mut self, ctx: &mut Context) -> Result<bool> {
+        let span = self.start_span(ctx)?;
+        ctx.set_tracing_context_from_span(span);
 
         // Loop just in case buf was extended (should not happen though)
         for chunk in self.buf.chunks(self.portal_payload_length) {
             let msg = LocalMessage::new()
-                .with_tracing_context(tracing_context.clone())
+                .with_tracing_context(ctx.tracing_context())
                 .with_onward_route(self.onward_route.clone())
                 .with_return_route(route![self.addresses.sender_remote.clone()])
                 .with_payload(
@@ -139,4 +121,51 @@ impl<R: AsyncRead + Unpin + Send + Sync + 'static> Processor for TcpPortalRecvPr
 
         Ok(true)
     }
+
+    async fn disconnect(&mut self, ctx: &mut Context) -> Result<bool> {
+        if let Err(err) = ctx
+            .forward_from_address(
+                LocalMessage::new()
+                    .with_onward_route(self.onward_route.clone())
+                    .with_return_route(route![self.addresses.sender_remote.clone()])
+                    .with_payload(PortalMessage::Disconnect.encode()?),
+                self.addresses.receiver_remote.clone(),
+            )
+            .await
+        {
+            debug!(
+                "Error notifying the other side of the portal about dropped connection {}",
+                err
+            );
+        }
+
+        Ok(false)
+    }
+
+    fn start_span(&self, ctx: &Context) -> Result<impl Span> {
+        let name = match self.addresses.portal_type {
+            PortalType::Inlet { .. } => "receive_tcp_message_at_inlet",
+            PortalType::Outlet => "receive_tcp_message_at_outlet",
+            PortalType::PrivilegedInlet { .. } => "receive_tcp_message_at_privileged_inlet",
+            PortalType::PrivilegedOutlet => "receive_tcp_message_at_privileged_outlet",
+        };
+        let tracer = global::tracer(OCKAM_TRACER_NAME);
+        let span = tracer
+            .span_builder(name)
+            .with_attributes(vec![
+                KeyValue::new("portal_type", self.addresses.portal_type.to_string()),
+                KeyValue::new("onward_route", self.onward_route.to_string()),
+                KeyValue::new("worker_address", ctx.primary_address().to_string()),
+                KeyValue::new(
+                    "worker_other_addresses",
+                    ctx.additional_addresses()
+                        .map(|a| a.to_string())
+                        .collect::<Vec<String>>()
+                        .join(",")
+                        .to_string(),
+                ),
+            ])
+            .start(&tracer);
+        Ok(span)
+    }
 }
diff --git a/implementations/rust/ockam/ockam_transport_tcp/src/portal/portal_worker.rs b/implementations/rust/ockam/ockam_transport_tcp/src/portal/portal_worker.rs
index 44a5fb50197..238be46308a 100644
--- a/implementations/rust/ockam/ockam_transport_tcp/src/portal/portal_worker.rs
+++ b/implementations/rust/ockam/ockam_transport_tcp/src/portal/portal_worker.rs
@@ -4,21 +4,25 @@ use crate::portal::portal_worker::ReadHalfMaybeTls::{ReadHalfNoTls, ReadHalfWith
 use crate::portal::portal_worker::WriteHalfMaybeTls::{WriteHalfNoTls, WriteHalfWithTls};
 use crate::transport::{connect, connect_tls};
 use crate::{portal::TcpPortalRecvProcessor, PortalInternalMessage, PortalMessage, TcpRegistry};
+use core::fmt::{Display, Formatter};
 use ockam_core::compat::{boxed::Box, sync::Arc};
 use ockam_core::{
     async_trait, AllowAll, AllowOnwardAddress, AllowSourceAddress, Decodable, DenyAll,
     IncomingAccessControl, LocalInfoIdentifier, Mailbox, Mailboxes, OutgoingAccessControl,
-    SecureChannelLocalInfo,
+    SecureChannelLocalInfo, OCKAM_TRACER_NAME,
 };
 use ockam_core::{Any, Result, Route, Routed, Worker};
 use ockam_node::{Context, ProcessorBuilder, WorkerBuilder, WorkerShutdownPriority};
 use ockam_transport_core::{HostnamePort, TransportError};
+use opentelemetry::global::BoxedSpan;
+use opentelemetry::trace::{Span, Tracer};
+use opentelemetry::{global, KeyValue};
 use std::time::Duration;
 use tokio::io::{AsyncRead, AsyncWriteExt, ReadHalf, WriteHalf};
 use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf};
 use tokio::net::TcpStream;
 use tokio_rustls::TlsStream;
-use tracing::{debug, info, instrument, trace, warn};
+use tracing::{debug, info, instrument, trace, warn, Level};
 
 /// Enumerate all `TcpPortalWorker` states
 ///
@@ -26,7 +30,7 @@ use tracing::{debug, info, instrument, trace, warn};
 ///
 /// `Outlet`: `SendPong` -> `Initialized`
 /// `Inlet`: `SendPing` -> `ReceivePong` -> `Initialized`
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 enum State {
     SendPing { ping_route: Route },
     SendPong { pong_route: Route },
@@ -34,6 +38,17 @@ enum State {
     Initialized,
 }
 
+impl Display for State {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
+        match self {
+            State::SendPing { .. } => f.write_str("send-ping"),
+            State::SendPong { .. } => f.write_str("send-pong"),
+            State::ReceivePong => f.write_str("receive-pong"),
+            State::Initialized => f.write_str("initialized"),
+        }
+    }
+}
+
 pub(crate) enum HandshakeMode {
     Regular,
     Skip {
@@ -77,7 +92,7 @@ pub(crate) enum WriteHalfMaybeTls {
 
 impl TcpPortalWorker {
     /// Start a new `TcpPortalWorker` of type [`TypeName::Inlet`]
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     #[allow(clippy::too_many_arguments)]
     pub(super) fn start_new_inlet(
         ctx: &Context,
@@ -118,7 +133,7 @@ impl TcpPortalWorker {
 
     /// Start a new `TcpPortalWorker` of type [`TypeName::Outlet`]
     #[allow(clippy::too_many_arguments)]
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub(super) fn start_new_outlet(
         ctx: &Context,
         registry: TcpRegistry,
@@ -151,7 +166,7 @@ impl TcpPortalWorker {
 
     /// Start a new `TcpPortalWorker` of type [`TypeName::Outlet`]
     #[allow(clippy::too_many_arguments)]
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     pub(super) fn start_new_outlet_no_handshake(
         ctx: &Context,
         registry: TcpRegistry,
@@ -188,7 +203,7 @@ impl TcpPortalWorker {
 
     /// Start a new `TcpPortalWorker`
     #[allow(clippy::too_many_arguments)]
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     fn start(
         ctx: &Context,
         registry: TcpRegistry,
@@ -274,7 +289,7 @@ impl TcpPortalWorker {
     }
 
     /// Start a `TcpPortalRecvProcessor`
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     fn start_receiver(&mut self, ctx: &Context, onward_route: Route) -> Result<()> {
         if let Some(rx) = self.read_half.take() {
             match rx {
@@ -323,7 +338,7 @@ impl TcpPortalWorker {
         Ok(())
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn notify_remote_about_disconnection(&mut self, ctx: &Context) {
         // Notify the other end
         let remote_route = if let Some(remote_route) = self.remote_route.take() {
@@ -358,7 +373,7 @@ impl TcpPortalWorker {
         }
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     fn stop_receiver(&self, ctx: &Context) {
         match ctx.stop_address(&self.addresses.receiver_remote) {
             Ok(_) => {
@@ -372,13 +387,13 @@ impl TcpPortalWorker {
         }
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     fn stop_sender(&self, ctx: &Context) -> Result<()> {
         ctx.stop_address(&self.addresses.sender_internal)
     }
 
     /// Start the portal disconnection process
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn start_disconnection(
         &mut self,
         ctx: &Context,
@@ -430,7 +445,7 @@ impl TcpPortalWorker {
         Ok(())
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn handle_send_ping(&mut self, ctx: &Context, ping_route: Route) -> Result<State> {
         // Force creation of Outlet on the other side
         ctx.send_from_address(
@@ -468,7 +483,7 @@ impl TcpPortalWorker {
         Ok(())
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn handle_send_pong(&mut self, ctx: &Context, pong_route: Route) -> Result<State> {
         if self.write_half.is_some() {
             // Should not happen
@@ -501,7 +516,7 @@ impl Worker for TcpPortalWorker {
     type Context = Context;
     type Message = Any;
 
-    #[instrument(skip_all, name = "TcpPortalWorker::initialize")]
+    #[instrument(skip_all, name = "TcpPortalWorker::initialize", level = Level::TRACE)]
     async fn initialize(&mut self, ctx: &mut Self::Context) -> Result<()> {
         match &self.state {
             State::SendPing { ping_route } => {
@@ -547,7 +562,7 @@ impl Worker for TcpPortalWorker {
         Ok(())
     }
 
-    #[instrument(skip_all, name = "TcpPortalWorker::shutdown")]
+    #[instrument(skip_all, name = "TcpPortalWorker::shutdown", level = Level::TRACE)]
     async fn shutdown(&mut self, _ctx: &mut Self::Context) -> Result<()> {
         if let HandshakeMode::Skip { map } = &mut self.handshake_mode {
             if let Some((map_key, outlet_listener_registry)) = map.take() {
@@ -567,7 +582,7 @@ impl Worker for TcpPortalWorker {
 
     // TcpSendWorker will receive messages from the TcpRouter to send
     // across the TcpStream to our friend
-    #[instrument(skip_all, name = "TcpPortalWorker::handle_message")]
+    // #[instrument(skip_all, name = "TcpPortalWorker::handle_message_root", fields(state, actual_identifier, expected_identifier), level = Level::INFO)]
     async fn handle_message(&mut self, ctx: &mut Context, msg: Routed<Any>) -> Result<()> {
         if self.is_disconnecting {
             return Ok(());
@@ -584,24 +599,21 @@ impl Worker for TcpPortalWorker {
         }
 
         let remote_packet = recipient != self.addresses.sender_internal;
-        if remote_packet {
-            let their_identifier = SecureChannelLocalInfo::find_info_from_list(&msg.local_info)
-                .map(|l| l.their_identifier())
-                .ok();
-
-            if their_identifier != self.their_identifier {
-                debug!(
-                    "identifier changed from {:?} to {:?}",
-                    self.their_identifier.as_ref().map(|i| i.to_string()),
-                    their_identifier.as_ref().map(|i| i.to_string()),
-                );
-                return Err(TransportError::IdentifierChanged)?;
-            }
+        let their_identifier = SecureChannelLocalInfo::find_info_from_list(&msg.local_info)
+            .map(|l| l.their_identifier())
+            .ok();
+
+        if remote_packet && their_identifier != self.their_identifier {
+            debug!(
+                "identifier changed from {:?} to {:?}",
+                self.their_identifier.as_ref().map(|i| i.to_string()),
+                their_identifier.as_ref().map(|i| i.to_string()),
+            );
+            return Err(TransportError::IdentifierChanged)?;
         }
 
         let return_route = msg.return_route;
         let payload = msg.payload;
-
         match &self.state {
             State::ReceivePong => {
                 if !remote_packet {
@@ -620,6 +632,10 @@ impl Worker for TcpPortalWorker {
 
                 if remote_packet {
                     let msg = PortalMessage::decode(&payload)?;
+                    if !msg.is_disconnect() {
+                        let span = self.start_span(ctx, &their_identifier)?;
+                        ctx.set_tracing_context_from_span(span);
+                    }
                     // Send to Tcp stream
                     match msg {
                         PortalMessage::Payload(payload, packet_counter) => {
@@ -647,7 +663,7 @@ impl Worker for TcpPortalWorker {
 }
 
 impl TcpPortalWorker {
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     fn handle_receive_pong(&mut self, ctx: &Context, return_route: Route) -> Result<()> {
         self.start_receiver(ctx, return_route.clone())?;
         debug!(portal_type = %self.addresses.portal_type, sender_internal = %self.addresses.sender_internal, "received pong");
@@ -656,7 +672,7 @@ impl TcpPortalWorker {
         Ok(())
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn handle_disconnect(&mut self, ctx: &Context) -> Result<()> {
         let (portal_type, listener_address) = match &self.addresses.portal_type {
             PortalType::Inlet { listener_address }
@@ -681,7 +697,7 @@ impl TcpPortalWorker {
             .await
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn handle_payload(
         &mut self,
         ctx: &Context,
@@ -712,7 +728,7 @@ impl TcpPortalWorker {
         Ok(())
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn check_packet_counter(
         &mut self,
         ctx: &Context,
@@ -738,4 +754,43 @@ impl TcpPortalWorker {
         };
         Ok(())
     }
+
+    fn start_span(
+        &self,
+        ctx: &Context,
+        their_identifier: &Option<LocalInfoIdentifier>,
+    ) -> Result<BoxedSpan> {
+        let name = match self.addresses.portal_type {
+            PortalType::Inlet { .. } => "receive_ockam_message_from_outlet",
+            PortalType::Outlet => "receive_ockam_message_from_inlet",
+            PortalType::PrivilegedInlet { .. } => "receive_ockam_message_from_privileged_outlet",
+            PortalType::PrivilegedOutlet => "receive_ockam_message_from_privileged_inlet",
+        };
+        let tracer = global::tracer(OCKAM_TRACER_NAME);
+        let mut span = tracer
+            .span_builder(name)
+            .with_attributes(vec![
+                KeyValue::new("portal_state", self.state.to_string()),
+                KeyValue::new("hostname_port", self.hostname_port.to_string()),
+                KeyValue::new("portal_type", self.addresses.portal_type.to_string()),
+                KeyValue::new("worker_address", ctx.primary_address().to_string()),
+                KeyValue::new(
+                    "worker_other_addresses",
+                    ctx.additional_addresses()
+                        .map(|a| a.to_string())
+                        .collect::<Vec<String>>()
+                        .join(",")
+                        .to_string(),
+                ),
+            ])
+            .start(&tracer);
+
+        if let Some(i) = self.their_identifier.as_ref() {
+            span.set_attribute(KeyValue::new("expected_identifier", i.to_string()))
+        }
+        if let Some(i) = their_identifier.as_ref() {
+            span.set_attribute(KeyValue::new("actual_identifier", i.to_string()))
+        }
+        Ok(span)
+    }
 }
diff --git a/implementations/rust/ockam/ockam_transport_tcp/src/privileged_portal/privileged_portals.rs b/implementations/rust/ockam/ockam_transport_tcp/src/privileged_portal/privileged_portals.rs
index 9e3fd34849e..f21642e9d32 100644
--- a/implementations/rust/ockam/ockam_transport_tcp/src/privileged_portal/privileged_portals.rs
+++ b/implementations/rust/ockam/ockam_transport_tcp/src/privileged_portal/privileged_portals.rs
@@ -15,6 +15,7 @@ use std::net::IpAddr;
 use tokio::net::TcpListener;
 use tokio::sync::mpsc::channel;
 use tracing::instrument;
+use tracing::Level;
 
 impl TcpTransport {
     /// Check if privileged portals can be run with current permissions
@@ -54,7 +55,7 @@ impl TcpTransport {
     }
 
     /// Create a Privileged Inlet
-    #[instrument(skip(self), fields(outlet_route=?outlet_route.clone()))]
+    #[instrument(skip(self), fields(outlet_route=?outlet_route.clone()), level = Level::TRACE)]
     pub async fn create_privileged_inlet(
         &self,
         bind_addr: impl Into<String> + Clone + Debug,
@@ -141,7 +142,7 @@ impl TcpTransport {
     }
 
     /// Stop the Privileged Inlet
-    #[instrument(skip(self), fields(port=port))]
+    #[instrument(skip(self), fields(port=port), level = Level::TRACE)]
     pub fn stop_privileged_inlet(&self, port: Port) -> Result<()> {
         self.ebpf_support.inlet_registry.delete_inlet(port);
 
@@ -149,7 +150,7 @@ impl TcpTransport {
     }
 
     /// Create a Privileged Outlet
-    #[instrument(skip(self), fields(address = ? address.clone().into(), peer=peer.clone().to_string()))]
+    #[instrument(skip(self), fields(address = ? address.clone().into(), peer=peer.clone().to_string()), level = Level::TRACE)]
     pub async fn create_privileged_outlet(
         &self,
         address: impl Into<Address> + Clone + Debug,
@@ -219,7 +220,7 @@ impl TcpTransport {
     }
 
     /// Stop the Privileged Inlet
-    #[instrument(skip(self), fields(address = % address))]
+    #[instrument(skip(self), fields(address = % address), level = Level::TRACE)]
     pub fn stop_privileged_outlet(&self, address: &Address) -> Result<()> {
         self.ctx().stop_address(address)?;
 
diff --git a/implementations/rust/ockam/ockam_transport_tcp/src/transport/common.rs b/implementations/rust/ockam/ockam_transport_tcp/src/transport/common.rs
index 9155369602c..13be9028b9b 100644
--- a/implementations/rust/ockam/ockam_transport_tcp/src/transport/common.rs
+++ b/implementations/rust/ockam/ockam_transport_tcp/src/transport/common.rs
@@ -11,10 +11,10 @@ use tokio::net::TcpStream;
 use tokio_rustls::rustls::pki_types::ServerName;
 use tokio_rustls::rustls::{ClientConfig, RootCertStore};
 use tokio_rustls::{TlsConnector, TlsStream};
-use tracing::{debug, instrument};
+use tracing::{debug, instrument, Level};
 
 /// Connect to a socket address via a regular TcpStream
-#[instrument(skip_all)]
+#[instrument(skip_all, level = Level::TRACE)]
 pub(crate) async fn connect(
     to: &HostnamePort,
     enable_nagle: bool,
@@ -80,7 +80,7 @@ pub(crate) async fn create_tcp_stream(
 
 /// Connect to a socket address via a TlsStream
 #[allow(clippy::type_complexity)]
-#[instrument(skip_all)]
+#[instrument(skip_all, level = Level::TRACE)]
 pub(crate) async fn connect_tls(
     to: &HostnamePort,
     enable_nagle: bool,
diff --git a/implementations/rust/ockam/ockam_transport_tcp/src/transport/lifecycle.rs b/implementations/rust/ockam/ockam_transport_tcp/src/transport/lifecycle.rs
index 01a30c61404..8479aae707b 100644
--- a/implementations/rust/ockam/ockam_transport_tcp/src/transport/lifecycle.rs
+++ b/implementations/rust/ockam/ockam_transport_tcp/src/transport/lifecycle.rs
@@ -6,7 +6,7 @@ use ockam_transport_core::Transport;
 use std::any::Any;
 use std::net::SocketAddr;
 use std::sync::Arc;
-use tracing::instrument;
+use tracing::{instrument, Level};
 
 impl TcpTransport {
     /// Create a TCP transport
@@ -19,7 +19,7 @@ impl TcpTransport {
     /// let tcp = TcpTransport::get_or_create(&ctx)?;
     /// # Ok(()) }
     /// ```
-    #[instrument(name = "get or create tcp transport", skip_all)]
+    #[instrument(name = "get or create tcp transport", skip_all, level = Level::TRACE)]
     pub fn get_or_create(ctx: &Context) -> Result<Arc<TcpTransport>> {
         // don't register the TCP transport twice
         match ctx.get_transport(TCP) {
diff --git a/implementations/rust/ockam/ockam_transport_tcp/src/transport/portals.rs b/implementations/rust/ockam/ockam_transport_tcp/src/transport/portals.rs
index 30c5f0602d7..b36f2bb3aea 100644
--- a/implementations/rust/ockam/ockam_transport_tcp/src/transport/portals.rs
+++ b/implementations/rust/ockam/ockam_transport_tcp/src/transport/portals.rs
@@ -8,7 +8,7 @@ use ockam_core::flow_control::FlowControls;
 use ockam_core::{Address, Result, Route};
 use ockam_node::Context;
 use ockam_transport_core::{parse_socket_addr, HostnamePort};
-use tracing::{debug, instrument};
+use tracing::{debug, instrument, Level};
 
 impl TcpTransport {
     /// Create Tcp Inlet that listens on bind_addr, transforms Tcp stream into Ockam Routable
@@ -29,7 +29,7 @@ impl TcpTransport {
     /// # tcp.stop_inlet(&address)?;
     /// # Ok(()) }
     /// ```
-    #[instrument(skip(self), fields(address = ? bind_addr.clone().into(), outlet_route = ? outlet_route.clone()))]
+    #[instrument(skip(self), fields(address = ? bind_addr.clone().into(), outlet_route = ? outlet_route.clone()), level = Level::TRACE)]
     pub async fn create_inlet(
         &self,
         bind_addr: impl Into<String> + Clone + Debug,
@@ -62,7 +62,7 @@ impl TcpTransport {
     /// tcp.stop_inlet(&address)?;
     /// # Ok(()) }
     /// ```
-    #[instrument(skip(self), fields(address = ? address))]
+    #[instrument(skip(self), fields(address = ? address), level = Level::TRACE)]
     pub fn stop_inlet(&self, address: &Address) -> Result<()> {
         self.ctx.stop_address(address)?;
 
@@ -89,7 +89,7 @@ impl TcpTransport {
     /// # tcp.stop_outlet(&address)?;
     /// # Ok(()) }
     /// ```
-    #[instrument(skip(self), fields(address = ? address.clone().into(), peer=peer.clone().to_string()))]
+    #[instrument(skip(self), fields(address = ? address.clone().into(), peer=peer.clone().to_string()), level = Level::TRACE)]
     pub fn create_outlet(
         &self,
         address: impl Into<Address> + Clone + Debug,
@@ -122,7 +122,7 @@ impl TcpTransport {
     /// tcp.stop_outlet(&address)?;
     /// # Ok(()) }
     /// ```
-    #[instrument(skip(self), fields(address = % address))]
+    #[instrument(skip(self), fields(address = % address), level = Level::TRACE)]
     pub fn stop_outlet(&self, address: &Address) -> Result<()> {
         self.ctx.stop_address(address)
     }
diff --git a/implementations/rust/ockam/ockam_transport_tcp/src/transport_message.rs b/implementations/rust/ockam/ockam_transport_tcp/src/transport_message.rs
index 10ab6f94963..fd6dbcffe7a 100644
--- a/implementations/rust/ockam/ockam_transport_tcp/src/transport_message.rs
+++ b/implementations/rust/ockam/ockam_transport_tcp/src/transport_message.rs
@@ -55,7 +55,12 @@ impl From<TcpTransportMessage<'_>> for LocalMessage {
         let local_message = LocalMessage::new();
 
         #[cfg(feature = "std")]
-        let local_message = local_message.with_tracing_context(value.tracing_context());
+        let local_message =
+            if let Some(tc) = value.tracing_context.and_then(|tc| tc.try_into().ok()) {
+                local_message.with_tracing_context(tc)
+            } else {
+                local_message
+            };
 
         local_message
             .with_onward_route(value.onward_route)
@@ -75,9 +80,7 @@ impl From<LocalMessage> for TcpTransportMessage<'_> {
 
         cfg_if! {
             if #[cfg(feature = "std")] {
-                // make sure to pass the latest tracing context
-                let new_tracing_context = LocalMessage::start_new_tracing_context(value.tracing_context.update(), "TcpTransportMessage");
-                transport_message.with_tracing_context(new_tracing_context)
+                transport_message.with_tracing_context(value.tracing_context.to_string())
             } else {
                 transport_message
             }
diff --git a/implementations/rust/ockam/ockam_transport_tcp/src/workers/listener.rs b/implementations/rust/ockam/ockam_transport_tcp/src/workers/listener.rs
index 7ea6a71d0da..755466487a1 100644
--- a/implementations/rust/ockam/ockam_transport_tcp/src/workers/listener.rs
+++ b/implementations/rust/ockam/ockam_transport_tcp/src/workers/listener.rs
@@ -5,7 +5,7 @@ use ockam_core::{Address, Processor, Result};
 use ockam_node::{Context, ProcessorBuilder, WorkerShutdownPriority};
 use ockam_transport_core::TransportError;
 use tokio::net::TcpListener;
-use tracing::{debug, instrument};
+use tracing::{debug, instrument, Level};
 
 /// A TCP Listen processor
 ///
@@ -20,7 +20,7 @@ pub(crate) struct TcpListenProcessor {
 }
 
 impl TcpListenProcessor {
-    #[instrument(skip_all, name = "TcpListenProcessor::start")]
+    #[instrument(skip_all, name = "TcpListenProcessor::start", level = Level::TRACE)]
     pub(crate) async fn start(
         ctx: &Context,
         registry: TcpRegistry,
@@ -56,7 +56,7 @@ impl TcpListenProcessor {
 impl Processor for TcpListenProcessor {
     type Context = Context;
 
-    #[instrument(skip_all, name = "TcpListenProcessor::initialize")]
+    #[instrument(skip_all, name = "TcpListenProcessor::initialize", level = Level::TRACE)]
     async fn initialize(&mut self, ctx: &mut Context) -> Result<()> {
         self.registry.add_listener_processor(TcpListenerInfo::new(
             ctx.primary_address().clone(),
@@ -67,7 +67,7 @@ impl Processor for TcpListenProcessor {
         Ok(())
     }
 
-    #[instrument(skip_all, name = "TcpListenProcessor::shutdown")]
+    #[instrument(skip_all, name = "TcpListenProcessor::shutdown", level = Level::TRACE)]
     async fn shutdown(&mut self, ctx: &mut Self::Context) -> Result<()> {
         self.registry
             .remove_listener_processor(ctx.primary_address());
@@ -75,7 +75,7 @@ impl Processor for TcpListenProcessor {
         Ok(())
     }
 
-    #[instrument(skip_all, name = "TcpListenProcessor::process")]
+    #[instrument(skip_all, name = "TcpListenProcessor::process", level = Level::TRACE)]
     async fn process(&mut self, ctx: &mut Self::Context) -> Result<bool> {
         debug!("Waiting for incoming TCP connection...");
 
diff --git a/implementations/rust/ockam/ockam_transport_tcp/src/workers/receiver.rs b/implementations/rust/ockam/ockam_transport_tcp/src/workers/receiver.rs
index 4ff08d1a38b..b9a2445535b 100644
--- a/implementations/rust/ockam/ockam_transport_tcp/src/workers/receiver.rs
+++ b/implementations/rust/ockam/ockam_transport_tcp/src/workers/receiver.rs
@@ -15,7 +15,7 @@ use ockam_core::{
 use ockam_core::{Processor, Result};
 use ockam_node::{Context, ProcessorBuilder, WorkerShutdownPriority};
 use tokio::{io::AsyncReadExt, net::tcp::OwnedReadHalf};
-use tracing::{debug, instrument, trace};
+use tracing::{debug, instrument, trace, Level};
 
 /// A TCP receiving message processor
 ///
@@ -57,7 +57,7 @@ impl TcpRecvProcessor {
     }
 
     #[allow(clippy::too_many_arguments)]
-    #[instrument(skip_all, name = "TcpRecvProcessor::start")]
+    #[instrument(skip_all, name = "TcpRecvProcessor::start", level = Level::TRACE)]
     pub fn start(
         ctx: &Context,
         registry: TcpRegistry,
@@ -119,7 +119,7 @@ impl TcpRecvProcessor {
 impl Processor for TcpRecvProcessor {
     type Context = Context;
 
-    #[instrument(skip_all, name = "TcpRecvProcessor::initialize")]
+    #[instrument(skip_all, name = "TcpRecvProcessor::initialize", level = Level::TRACE)]
     async fn initialize(&mut self, ctx: &mut Context) -> Result<()> {
         self.registry.add_receiver_processor(TcpReceiverInfo::new(
             ctx.primary_address().clone(),
@@ -156,7 +156,7 @@ impl Processor for TcpRecvProcessor {
         Ok(())
     }
 
-    #[instrument(skip_all, name = "TcpRecvProcessor::shutdown")]
+    #[instrument(skip_all, name = "TcpRecvProcessor::shutdown", level = Level::TRACE)]
     async fn shutdown(&mut self, ctx: &mut Self::Context) -> Result<()> {
         self.registry
             .remove_receiver_processor(ctx.primary_address());
@@ -175,7 +175,7 @@ impl Processor for TcpRecvProcessor {
     ///    Context to avoid spawning a zombie task.
     /// 3. We must also stop the TcpReceive loop when the worker gets
     ///    killed by the user or node.
-    #[instrument(skip_all, name = "TcpRecvProcessor::process", fields(worker = %ctx.primary_address()))]
+    #[instrument(skip_all, name = "TcpRecvProcessor::process", fields(worker = %ctx.primary_address()), level = Level::TRACE)]
     async fn process(&mut self, ctx: &mut Context) -> Result<bool> {
         // Read the message length
         let len = match self.read_half.read_u32().await {
diff --git a/implementations/rust/ockam/ockam_transport_tcp/src/workers/sender.rs b/implementations/rust/ockam/ockam_transport_tcp/src/workers/sender.rs
index 053244c07fc..c4d20e6d4c5 100644
--- a/implementations/rust/ockam/ockam_transport_tcp/src/workers/sender.rs
+++ b/implementations/rust/ockam/ockam_transport_tcp/src/workers/sender.rs
@@ -15,7 +15,7 @@ use ockam_transport_core::TransportError;
 use serde::{Deserialize, Serialize};
 use tokio::io::AsyncWriteExt;
 use tokio::net::tcp::OwnedWriteHalf;
-use tracing::{debug, instrument, trace, warn};
+use tracing::{debug, instrument, trace, warn, Level};
 
 #[derive(Serialize, Deserialize, Message, Clone)]
 pub(crate) enum TcpSendWorkerMsg {
@@ -80,7 +80,7 @@ impl TcpSendWorker {
     /// Create a `(TcpSendWorker, TcpRecvProcessor)` pair that opens and
     /// manages the connection with the given peer
     #[allow(clippy::too_many_arguments)]
-    #[instrument(skip_all, name = "TcpSendWorker::start")]
+    #[instrument(skip_all, name = "TcpSendWorker::start", level = Level::TRACE)]
     pub(crate) fn start(
         ctx: &Context,
         registry: TcpRegistry,
@@ -127,7 +127,7 @@ impl TcpSendWorker {
         Ok(())
     }
 
-    #[instrument(skip_all, name = "TcpSendWorker::stop")]
+    #[instrument(skip_all, name = "TcpSendWorker::stop", level = Level::TRACE)]
     fn stop(&self, ctx: &Context) -> Result<()> {
         ctx.stop_primary_address()
     }
@@ -178,7 +178,7 @@ impl Worker for TcpSendWorker {
     type Context = Context;
     type Message = Any;
 
-    #[instrument(skip_all, name = "TcpSendWorker::initialize")]
+    #[instrument(skip_all, name = "TcpSendWorker::initialize", level = Level::TRACE)]
     async fn initialize(&mut self, ctx: &mut Self::Context) -> Result<()> {
         self.registry.add_sender_worker(TcpSenderInfo::new(
             self.addresses.sender_address().clone(),
@@ -207,7 +207,7 @@ impl Worker for TcpSendWorker {
         Ok(())
     }
 
-    #[instrument(skip_all, name = "TcpSendWorker::shutdown")]
+    #[instrument(skip_all, name = "TcpSendWorker::shutdown", level = Level::TRACE)]
     async fn shutdown(&mut self, ctx: &mut Self::Context) -> Result<()> {
         self.registry
             .remove_sender_worker(self.addresses.sender_address());
@@ -221,7 +221,7 @@ impl Worker for TcpSendWorker {
 
     // TcpSendWorker will receive messages from the TcpRouter to send
     // across the TcpStream to our friend
-    #[instrument(skip_all, name = "TcpSendWorker::handle_message", fields(worker = %ctx.primary_address()))]
+    #[instrument(skip_all, name = "TcpSendWorker::handle_message", fields(worker = %ctx.primary_address()), level = Level::TRACE)]
     async fn handle_message(
         &mut self,
         ctx: &mut Context,
diff --git a/implementations/rust/ockam/ockam_transport_udp/src/messages/routing_message.rs b/implementations/rust/ockam/ockam_transport_udp/src/messages/routing_message.rs
index e6f9edb16f5..9b7c2cfb202 100644
--- a/implementations/rust/ockam/ockam_transport_udp/src/messages/routing_message.rs
+++ b/implementations/rust/ockam/ockam_transport_udp/src/messages/routing_message.rs
@@ -86,9 +86,7 @@ impl From<LocalMessage> for UdpRoutingMessage<'_> {
 
         cfg_if! {
             if #[cfg(feature = "std")] {
-                // make sure to pass the latest tracing context
-                let new_tracing_context = LocalMessage::start_new_tracing_context(value.tracing_context.update(), "UdpRoutingMessage");
-                routing_message.with_tracing_context(new_tracing_context)
+                routing_message.with_tracing_context(value.tracing_context.to_string())
             } else {
                 routing_message
             }
diff --git a/implementations/rust/ockam/ockam_transport_udp/src/transport/lifecycle.rs b/implementations/rust/ockam/ockam_transport_udp/src/transport/lifecycle.rs
index 79010370c78..d039cbb22fe 100644
--- a/implementations/rust/ockam/ockam_transport_udp/src/transport/lifecycle.rs
+++ b/implementations/rust/ockam/ockam_transport_udp/src/transport/lifecycle.rs
@@ -5,6 +5,7 @@ use ockam_transport_core::Transport;
 use std::any::Any;
 use std::sync::Arc;
 use tracing::instrument;
+use tracing::Level;
 
 use crate::UdpBindArguments;
 use crate::{UdpBindOptions, UdpTransport, UDP};
@@ -20,7 +21,7 @@ impl UdpTransport {
     /// let udp = UdpTransport::get_or_create(&ctx)?;
     /// # Ok(()) }
     /// ```
-    #[instrument(name = "get or create udp transport", skip_all)]
+    #[instrument(name = "get or create udp transport", skip_all, level = Level::TRACE)]
     pub fn get_or_create(ctx: &Context) -> Result<Arc<UdpTransport>> {
         // don't register the UDP transport twice
         match ctx.get_transport(UDP) {
diff --git a/implementations/rust/ockam/ockam_vault/src/software/vault_for_secure_channels/vault_for_secure_channels.rs b/implementations/rust/ockam/ockam_vault/src/software/vault_for_secure_channels/vault_for_secure_channels.rs
index 0cce4e24ef5..ea3630bf9f7 100644
--- a/implementations/rust/ockam/ockam_vault/src/software/vault_for_secure_channels/vault_for_secure_channels.rs
+++ b/implementations/rust/ockam/ockam_vault/src/software/vault_for_secure_channels/vault_for_secure_channels.rs
@@ -1,5 +1,6 @@
 use sha2::{Digest, Sha256};
 use tracing::instrument;
+use tracing::Level;
 
 use ockam_core::compat::boxed::Box;
 use ockam_core::compat::collections::BTreeMap;
@@ -279,7 +280,7 @@ impl VaultForSecureChannels for SoftwareVaultForSecureChannels {
         Ok(HkdfOutput(Sha256HkdfOutput(output)))
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn aead_encrypt(
         &self,
         secret_key_handle: &AeadSecretKeyHandle,
@@ -292,7 +293,7 @@ impl VaultForSecureChannels for SoftwareVaultForSecureChannels {
         aes.encrypt_message(plain_text, nonce, aad)
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn aead_decrypt<'a>(
         &self,
         secret_key_handle: &AeadSecretKeyHandle,
@@ -307,7 +308,7 @@ impl VaultForSecureChannels for SoftwareVaultForSecureChannels {
         Ok(plaintext)
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn persist_aead_key(&self, secret_key_handle: &AeadSecretKeyHandle) -> Result<()> {
         let secret = self.get_aead_secret(secret_key_handle).await?;
         self.secrets_repository
@@ -315,7 +316,7 @@ impl VaultForSecureChannels for SoftwareVaultForSecureChannels {
             .await
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn load_aead_key(&self, secret_key_handle: &AeadSecretKeyHandle) -> Result<()> {
         let Some(secret) = self
             .secrets_repository
@@ -428,7 +429,7 @@ impl VaultForSecureChannels for SoftwareVaultForSecureChannels {
         Ok(handle)
     }
 
-    #[instrument(skip_all)]
+    #[instrument(skip_all, level = Level::TRACE)]
     async fn delete_aead_secret_key(&self, secret_key_handle: AeadSecretKeyHandle) -> Result<bool> {
         Ok(self
             .ephemeral_aead_secrets
diff --git a/tools/stress-test/src/main.rs b/tools/stress-test/src/main.rs
index 33890545d9b..238f70e7d9a 100644
--- a/tools/stress-test/src/main.rs
+++ b/tools/stress-test/src/main.rs
@@ -138,6 +138,7 @@ impl State {
                 .await
                 .expect("cannot create cli state")
         });
+        let cli_state = Arc::new(cli_state);
         let builder = if log {
             NodeBuilder::new()
         } else {
@@ -148,7 +149,7 @@ impl State {
 
         let runtime = context.runtime().clone();
         let node_manager = runtime
-            .block_on(Self::make_node_manager(context.clone(), &cli_state))
+            .block_on(Self::make_node_manager(context.clone(), cli_state))
             .expect("cannot create node manager");
 
         Self {
@@ -168,7 +169,7 @@ impl State {
 
     async fn make_node_manager(
         ctx: Arc<Context>,
-        cli_state: &CliState,
+        cli_state: Arc<CliState>,
     ) -> ockam::Result<Arc<InMemoryNode>> {
         let tcp = TcpTransport::get_or_create(&ctx)?;
         let options = TcpListenerOptions::new();