apollo-opentelemetry 0.8.0

OpenTelemetry configuration types for Apollo platform
Documentation
/// Adds an event to the current span.
///
/// This macro provides a concise way to add events to the currently active span.
/// Events are timestamped annotations that can include attributes.
///
/// # Syntax
///
/// ```text
/// span_event!("event-name")
/// span_event!("event-name", "key" = "value")
/// span_event!("event-name", "key1" = value1, "key2" = value2)
/// ```
///
/// # Examples
///
/// ```
/// use apollo_opentelemetry::{span, span_event};
/// use opentelemetry::trace::{FutureExt as _, TraceContextExt};
/// use opentelemetry::Context;
///
/// # async fn parent_task() {
/// let span = span!("process-request");
/// let cx = Context::current_with_span(span);
///
/// async {
///     // Add a simple event
///     span_event!("starting-validation");
///
///     // Add an event with attributes
///     span_event!("validation-complete",
///         "items_validated" = 42i64,
///         "status" = "success"
///     );
/// }
/// .with_context(cx)
/// .await;
/// # }
/// ```
///
/// # Optional Attributes
///
/// Attributes can be optional - if the value is `None`, the attribute is skipped:
///
/// ```
/// use apollo_opentelemetry::span_event;
/// let error_code: Option<i64> = None;
/// span_event!("completed", "error.code" = error_code);
/// ```
#[macro_export]
macro_rules! span_event {
    // Simple event with just a name
    ($name:literal) => {{
        use $crate::__private::opentelemetry::trace::TraceContextExt;
        use $crate::__private::opentelemetry::Context;
        Context::current().span().add_event($name, vec![]);
    }};

    // Event with attributes
    ($name:literal, $($key:literal = $value:tt),+ $(,)?) => {{
        use $crate::__private::opentelemetry::trace::TraceContextExt;
        use $crate::__private::opentelemetry::KeyValue;
        use $crate::__private::opentelemetry::Context;
        let __attrs = [$((
            $key,
            $crate::__attr_to_option!($value)
        )),+];
        Context::current().span().add_event(
            $name,
            __attrs
                .into_iter()
                .filter_map(|(k, v)| v.map(|v| KeyValue::new(k, v)))
                .collect::<Vec<_>>()
        );
    }};
}

#[cfg(test)]
mod tests {
    use crate::span;

    use apollo_opentelemetry_test::{TelemetryContext, assert_spans_snapshot};
    use opentelemetry::Context;
    use opentelemetry::trace::{FutureExt as _, TraceContextExt};

    #[test]
    fn test_span_event_simple() {
        let ctx = TelemetryContext::new();

        let span = span!("parent");
        let cx = Context::current_with_span(span);
        let _guard = cx.attach();

        span_event!("my-event");

        drop(_guard);

        assert_spans_snapshot!(ctx, @r#"
        - name: parent
          span_kind: Internal
          is_sampled: true
          events:
            - name: my-event
        "#);
    }

    #[test]
    fn test_span_event_with_attributes() {
        let ctx = TelemetryContext::new();

        let span = span!("parent");
        let cx = Context::current_with_span(span);
        let _guard = cx.attach();

        span_event!("my-event", "key" = "value", "count" = 42i64);

        drop(_guard);

        assert_spans_snapshot!(ctx, @r#"
        - name: parent
          span_kind: Internal
          is_sampled: true
          events:
            - name: my-event
              attributes:
                count: "42"
                key: value
        "#);
    }

    #[tokio::test]
    async fn test_span_event_in_async() {
        let ctx = TelemetryContext::new();

        let span = span!("async-parent");
        let cx = Context::current_with_span(span);

        async {
            span_event!("async-event", "stage" = "processing");
        }
        .with_context(cx)
        .await;

        assert_spans_snapshot!(ctx, @r#"
        - name: async-parent
          span_kind: Internal
          is_sampled: true
          events:
            - name: async-event
              attributes:
                stage: processing
        "#);
    }
}