generateAtatusAttributes function

Map<String, Object?> generateAtatusAttributes(
  1. TracingContext? context,
  2. double samplingRate, {
  3. String spanKind = 'client',
})

Builds the _atatus.* attributes that make a RUM resource a span.

spanKind defaults to client, the kind of every outgoing request. The root span of a manual trace wraps those requests rather than being one, so it passes internal.

Implementation

Map<String, Object?> generateAtatusAttributes(
  TracingContext? context,
  double samplingRate, {
  String spanKind = 'client',
}) {
  var attributes = <String, Object?>{};

  if (context != null) {
    // ATCHG - Change package name from DDRumPlatformAttributeKey to AtatusRumPlatformAttributeKey
    attributes[AtatusRumPlatformAttributeKey.rulePsr] = samplingRate / 100.0;
    if (context.sampled) {
      // Ids are reported in the same representation the `traceparent` header
      // carries: 32 hex chars for the trace, 16 for the span.
      //
      // This deliberately differs from the Atatus Android agent, which reports
      // `_atatus.span_id` as unsigned decimal (`DDSpanId.toString()`). Android
      // can afford that because it *also* uploads a separate span payload whose
      // ids are hex, so the backend has both forms to reconcile. The Flutter
      // agent uploads no span payload - this RUM resource IS the client span -
      // so its id has to string-match the id the receiving service records as
      // its parent, which comes from `traceparent` and is hex. Reporting
      // decimal here leaves the server span with a parent it cannot find, and
      // the client span goes missing from the waterfall.
      final traceIdStr =
          context.traceId.asString(TracingIdRepresentation.hex32Chars);
      final spanIdStr =
          context.spanId.asString(TracingIdRepresentation.hex16Chars);

      // ATCHG - Change package name from DDRumPlatformAttributeKey to AtatusRumPlatformAttributeKey
      attributes[AtatusRumPlatformAttributeKey.traceID] = traceIdStr;
      // ATCHG - Change package name from DDRumPlatformAttributeKey to AtatusRumPlatformAttributeKey
      attributes[AtatusRumPlatformAttributeKey.spanID] = spanIdStr;

      if (kDebugMode) {
        // print('⚡ [Atatus Agent] Generated Trace ID: $traceIdStr, Span ID: $spanIdStr');
      }

      // Every request the agent reports is an outgoing call, so it is a
      // `client` span - including a request that has no parent. The matching
      // `server` span for the same request is produced by the backend's own
      // APM agent. The Atatus Android agent tags this unconditionally too; see
      // TracingInterceptor.kt
      // (`span.setTag(Tags.KEY_SPAN_KIND, Tags.VALUE_SPAN_KIND_CLIENT)`).
      attributes[AtatusRumPlatformAttributeKey.spanKind] = spanKind;

      // A zero parent means "no parent" - it is what `TracingId.fromString`
      // yields for an empty or unparseable id, e.g. from a caller-supplied
      // `AtatusDioParentSpanResolver`. Reporting it would make a root span look
      // like the child of a span that does not exist, so the key is omitted
      // instead, which is how a root is identified.
      if (context.parentSpanId != null &&
          context.parentSpanId!.value != BigInt.zero) {
        final parentSpanIdStr =
            context.parentSpanId!.asString(TracingIdRepresentation.hex16Chars);
        attributes[AtatusRumPlatformAttributeKey.parentSpanID] =
            parentSpanIdStr;

        if (kDebugMode) {
          // print('⚡ [Atatus Agent] Parent Span ID: $parentSpanIdStr');
        }
      }
    }
  }

  return attributes;
}