#[cfg(feature = "otel-keys")]
mod keys;
mod span_context;
#[cfg(feature = "otel-keys")]
pub use keys::OtlpKeys;
pub use span_context::SpanContext;
pub mod attr_keys {
pub const TEAM: &str = "gt.team";
pub const CUSTOMER_ID: &str = "gt.customer_id";
pub const DEPLOYMENT_ID: &str = "gt.deployment_id";
pub const BUNDLE_ID: &str = "gt.bundle_id";
pub const REVISION_ID: &str = "gt.revision_id";
pub const PACK_ID: &str = "gt.pack_id";
pub const ENV_PACK_KIND: &str = "gt.env_pack_kind";
pub const GENERATION: &str = "gt.generation";
pub const MESSAGING_ENDPOINT_ID: &str = "gt.messaging_endpoint_id";
}
#[cfg(feature = "telemetry-autoinit")]
use greentic_telemetry::set_current_telemetry_ctx;
#[cfg(feature = "telemetry-autoinit")]
pub use greentic_telemetry::{TelemetryConfig, TelemetryCtx, init_telemetry_auto};
#[cfg(feature = "telemetry-autoinit")]
pub use greentic_types_macros::main;
#[cfg(feature = "telemetry-autoinit")]
#[doc(hidden)]
pub use tokio::main as __tokio_main;
#[cfg(feature = "telemetry-autoinit")]
pub fn install_telemetry(service_name: &str) -> anyhow::Result<()> {
init_telemetry_auto(TelemetryConfig {
service_name: service_name.to_string(),
})
}
#[cfg(feature = "telemetry-autoinit")]
pub fn tenant_ctx_to_telemetry(ctx: &crate::TenantCtx) -> TelemetryCtx {
let mut telemetry = TelemetryCtx::new(ctx.tenant_id.as_ref()).with_env(ctx.env.as_str());
if let Some(team) = ctx.team_id.as_ref().or(ctx.team.as_ref()) {
telemetry = telemetry.with_team(team.as_str());
}
if let Some(session) = ctx.session_id() {
telemetry = telemetry.with_session(session);
}
if let Some(flow) = ctx.flow_id() {
telemetry = telemetry.with_flow(flow);
}
if let Some(node) = ctx.node_id() {
telemetry = telemetry.with_node(node);
}
if let Some(provider) = ctx.provider_id() {
telemetry = telemetry.with_provider(provider);
}
if let Some(v) = ctx.attributes.get(attr_keys::CUSTOMER_ID) {
telemetry = telemetry.with_customer_id(v);
}
if let Some(v) = ctx.attributes.get(attr_keys::DEPLOYMENT_ID) {
telemetry = telemetry.with_deployment_id(v);
}
if let Some(v) = ctx.attributes.get(attr_keys::BUNDLE_ID) {
telemetry = telemetry.with_bundle_id(v);
}
if let Some(v) = ctx.attributes.get(attr_keys::REVISION_ID) {
telemetry = telemetry.with_revision_id(v);
}
if let Some(v) = ctx.attributes.get(attr_keys::PACK_ID) {
telemetry = telemetry.with_pack_id(v);
}
if let Some(v) = ctx.attributes.get(attr_keys::ENV_PACK_KIND) {
telemetry = telemetry.with_env_pack_kind(v);
}
if let Some(n) = ctx
.attributes
.get(attr_keys::GENERATION)
.and_then(|v| v.parse::<u64>().ok())
{
telemetry = telemetry.with_generation(n);
}
if let Some(v) = ctx.attributes.get(attr_keys::MESSAGING_ENDPOINT_ID) {
telemetry = telemetry.with_messaging_endpoint_id(v);
}
telemetry
}
#[cfg(feature = "telemetry-autoinit")]
pub fn set_current_tenant_ctx(ctx: &crate::TenantCtx) {
set_current_telemetry_ctx(tenant_ctx_to_telemetry(ctx));
}
#[cfg(all(test, feature = "telemetry-autoinit"))]
mod tests {
use crate::{EnvId, TeamId, TenantCtx, TenantId};
use std::str::FromStr;
fn ctx() -> TenantCtx {
TenantCtx::new(
EnvId::from_str("prod-eu").unwrap_or_else(|err| panic!("{err}")),
TenantId::from_str("acme").unwrap_or_else(|err| panic!("{err}")),
)
}
#[test]
fn bridge_copies_env_and_rollout_ids_from_attributes() {
let mut c = ctx();
c.attributes
.insert(super::attr_keys::CUSTOMER_ID.into(), "cust-acme".into());
c.attributes
.insert(super::attr_keys::DEPLOYMENT_ID.into(), "01JTKS".into());
c.attributes.insert(
super::attr_keys::BUNDLE_ID.into(),
"customer.support".into(),
);
c.attributes
.insert(super::attr_keys::REVISION_ID.into(), "01JTKR".into());
c.attributes.insert(
super::attr_keys::PACK_ID.into(),
"customer.support@1.2.0".into(),
);
c.attributes.insert(
super::attr_keys::ENV_PACK_KIND.into(),
"greentic.deployer.k8s".into(),
);
c.attributes
.insert(super::attr_keys::GENERATION.into(), "3".into());
c.attributes.insert(
super::attr_keys::MESSAGING_ENDPOINT_ID.into(),
"teams-legal".into(),
);
let t = super::tenant_ctx_to_telemetry(&c);
assert_eq!(t.tenant, "acme");
assert_eq!(t.env.as_deref(), Some("prod-eu"));
assert_eq!(t.customer_id.as_deref(), Some("cust-acme"));
assert_eq!(t.deployment_id.as_deref(), Some("01JTKS"));
assert_eq!(t.bundle_id.as_deref(), Some("customer.support"));
assert_eq!(t.revision_id.as_deref(), Some("01JTKR"));
assert_eq!(t.pack_id.as_deref(), Some("customer.support@1.2.0"));
assert_eq!(t.env_pack_kind.as_deref(), Some("greentic.deployer.k8s"));
assert_eq!(t.generation.as_deref(), Some("3"));
assert_eq!(t.messaging_endpoint_id.as_deref(), Some("teams-legal"));
}
#[test]
fn bridge_leaves_rollout_ids_unset_when_absent() {
let t = super::tenant_ctx_to_telemetry(&ctx());
assert_eq!(t.env.as_deref(), Some("prod-eu"));
assert!(t.team.is_none());
assert!(t.customer_id.is_none());
assert!(t.deployment_id.is_none());
assert!(t.bundle_id.is_none());
assert!(t.revision_id.is_none());
assert!(t.pack_id.is_none());
assert!(t.env_pack_kind.is_none());
assert!(t.generation.is_none());
assert!(t.messaging_endpoint_id.is_none());
}
#[test]
fn bridge_projects_team_from_typed_field() {
let team = TeamId::from_str("support").unwrap_or_else(|err| panic!("{err}"));
let mut c = ctx();
c.team_id = Some(team); c.team = None;
let t = super::tenant_ctx_to_telemetry(&c);
assert_eq!(t.team.as_deref(), Some("support"));
}
#[test]
fn bridge_falls_back_to_legacy_team_slot() {
let team = TeamId::from_str("support").unwrap_or_else(|err| panic!("{err}"));
let mut c = ctx();
c.team = Some(team); c.team_id = None;
let t = super::tenant_ctx_to_telemetry(&c);
assert_eq!(t.team.as_deref(), Some("support"));
}
#[test]
fn bridge_team_id_wins_over_legacy_team_slot() {
let typed = TeamId::from_str("typed-team").unwrap_or_else(|err| panic!("{err}"));
let legacy = TeamId::from_str("legacy-team").unwrap_or_else(|err| panic!("{err}"));
let mut c = ctx();
c.team_id = Some(typed);
c.team = Some(legacy);
let t = super::tenant_ctx_to_telemetry(&c);
assert_eq!(t.team.as_deref(), Some("typed-team"));
}
#[test]
fn bridge_drops_non_u64_generation_silently() {
let mut c = ctx();
c.attributes
.insert(super::attr_keys::GENERATION.into(), "not-a-number".into());
let t = super::tenant_ctx_to_telemetry(&c);
assert!(t.generation.is_none());
}
}