Span Interface

The Span Interface specifies a series of timed application events that have a start and end time.

A Transaction may contain zero or more Spans in an array attribute named spans. Spans in the list don't have to be ordered, they will be ordered by start / end time on the Server.

While Span attributes will be normalized on the server, a Span is most useful when it includes at least an op and description.

Attributes

Below describe the transformations between an OpenTelemetry span and a Sentry Span. Related: the interface for a Sentry Span, the Relay spec for a Sentry Span and the spec for an OpenTelemetry span.

This is based on a mapping done as part of work on the OpenTelemetry Sentry Exporter.

OpenTelemetry SpanSentry SpanNotes
Span.trace_idSpan.trace_id
Span.span_idSpan.span_id
Span.parent_span_idSpan.parent_span_idIf a span does not have a parent span ID, it is a root span. For a root span:
  • If there is an active Sentry transaction, add it to the transaction
  • If there is no active Sentry transaction, construct a new transaction from that span
  • Span.nameSpan.attributesSpan.kindSpan.descriptionThe span description is decided using OpenTelemetry Semantic Conventions. Generally, the OpenTelemetrySpan.namemaps to a SentrySpan.description
    Span.nameSpan.attributesSpan.kindSpan.op
    Span.attributesSpan.kindSpan.StatusSpan.tagsThe OpenTelemetry Span Status message and span kind are set as tags on the Sentry span.
    Span.attributesSpan.StatusSpan.statusSee Span Status for more details
    Span.start_time_unix_nanoSpan.start_timestamp
    Span.end_time_unix_nanoSpan.timestamp

    Span Status

    In OpenTelemetry, Span Status is an enum of 3 values, while Sentry's Span Status is an enum of 17 values that map to the GRPC status codes. Each of the Sentry Span Status codes also map to HTTP codes. Sentry adopted it's Span Status spec from OpenTelemetry, who used the GRPC status code spec, but later on changed to the current spec it uses today.

    To map from OpenTelemetry Span Status to, you need to rely on both OpenTelemetry Span Status and Span attributes. This approach was adapted from a PR by GH user @anguisa to the OpenTelemetry Sentry Exporter.

    Copied
    // OpenTelemetry span status can be Unset, Ok, Error. HTTP and Grpc codes contained in tags can make it more detailed.
    
    // canonicalCodesHTTPMap maps some HTTP codes to Sentry's span statuses. See possible mapping in https://develop.sentry.dev/sdk/event-payloads/span/
    var canonicalCodesHTTPMap = map[string]sentry.SpanStatus{
    	"400": sentry.SpanStatusFailedPrecondition, // SpanStatusInvalidArgument, SpanStatusOutOfRange
    	"401": sentry.SpanStatusUnauthenticated,
    	"403": sentry.SpanStatusPermissionDenied,
    	"404": sentry.SpanStatusNotFound,
    	"409": sentry.SpanStatusAborted, // SpanStatusAlreadyExists
    	"429": sentry.SpanStatusResourceExhausted,
    	"499": sentry.SpanStatusCanceled,
    	"500": sentry.SpanStatusInternalError, // SpanStatusDataLoss, SpanStatusUnknown
    	"501": sentry.SpanStatusUnimplemented,
    	"503": sentry.SpanStatusUnavailable,
    	"504": sentry.SpanStatusDeadlineExceeded,
    }
    
    // canonicalCodesGrpcMap maps some GRPC codes to Sentry's span statuses. See description in grpc documentation.
    var canonicalCodesGrpcMap = map[string]sentry.SpanStatus{
    	"1":  sentry.SpanStatusCanceled,
    	"2":  sentry.SpanStatusUnknown,
    	"3":  sentry.SpanStatusInvalidArgument,
    	"4":  sentry.SpanStatusDeadlineExceeded,
    	"5":  sentry.SpanStatusNotFound,
    	"6":  sentry.SpanStatusAlreadyExists,
    	"7":  sentry.SpanStatusPermissionDenied,
    	"8":  sentry.SpanStatusResourceExhausted,
    	"9":  sentry.SpanStatusFailedPrecondition,
    	"10": sentry.SpanStatusAborted,
    	"11": sentry.SpanStatusOutOfRange,
    	"12": sentry.SpanStatusUnimplemented,
    	"13": sentry.SpanStatusInternalError,
    	"14": sentry.SpanStatusUnavailable,
    	"15": sentry.SpanStatusDataLoss,
    	"16": sentry.SpanStatusUnauthenticated,
    }
    
    code := spanStatus.Code()
    if code < 0 || int(code) > 2 {
        return sentry.SpanStatusUnknown, fmt.Sprintf("error code %d", code)
    }
    httpCode, foundHTTPCode := tags["http.status_code"]
    grpcCode, foundGrpcCode := tags["rpc.grpc.status_code"]
    var sentryStatus sentry.SpanStatus
    switch {
    case code == 1 || code == 0:
        sentryStatus = sentry.SpanStatusOK
    case foundHTTPCode:
        httpStatus, foundHTTPStatus := canonicalCodesHTTPMap[httpCode]
        switch {
        case foundHTTPStatus:
            sentryStatus = httpStatus
        default:
            sentryStatus = sentry.SpanStatusUnknown
        }
    case foundGrpcCode:
        grpcStatus, foundGrpcStatus := canonicalCodesGrpcMap[grpcCode]
        switch {
        case foundGrpcStatus:
            sentryStatus = grpcStatus
        default:
            sentryStatus = sentry.SpanStatusUnknown
        }
    default:
        sentryStatus = sentry.SpanStatusUnknown
    }
    return sentryStatus

    tags
    Optional. A map or list of tags for this event. Each tag must be less than 200 characters.

    Copied
    {
      "tags": {
        "ios_version": "4.0",
        "context": "production"
      }
    }

    trace_id:
    Required. Determines which trace the Span belongs to. The value should be 16 random bytes encoded as a hex string (32 characters long).

    Copied
    {
      "trace_id": "1e57b752bc6e4544bbaa246cd1d05dee"
    }

    op
    Recommended. Short code identifying the type of operation the span is measuring.

    For more details, see Sentry's conventions around span operations.

    Copied
    {
      "op": "db.query"
    }

    description
    Optional. Longer description of the span's operation, which uniquely identifies the span but is consistent across instances of the span.

    Copied
    {
      "description": "SELECT * FROM users WHERE last_active < DATE_SUB(CURRENT_DATE, INTERVAL 1 YEAR)`"
    }

    start_timestamp
    Required. A timestamp representing when the measuring started. The format is either a string as defined in RFC 3339 or a numeric (integer or float) value representing the number of seconds that have elapsed since the Unix epoch. The start_timestamp value must be less than or equal to the timestamp value, otherwise the Span is discarded as invalid.

    Copied
    {
      "start_timestamp": "2011-05-02T17:41:36.242Z"
    }

    or:

    Copied
    {
      "start_timestamp": 1304358096.242
    }

    timestamp
    Required. A timestamp representing when the measuring finished. The format is either a string as defined in RFC 3339 or a numeric (integer or float) value representing the number of seconds that have elapsed since the Unix epoch.

    Copied
    {
      "timestamp": "2011-05-02T17:41:36.955Z"
    }

    or:

    Copied
    {
      "timestamp": 1304358096.955
    }

    status
    Optional. Describes the status of the Span/Transaction.

    StateDescriptionHTTP status code equivalent
    okNot an error, returned on success200 and 2XX HTTP statuses
    cancelledThe operation was cancelled, typically by the caller499
    unknown or unknown_errorAn unknown error raised by APIs that don't return enough error information500
    invalid_argumentThe client specified an invalid argument400
    deadline_exceededThe deadline expired before the operation could succeed504
    not_foundContent was not found or request was denied for an entire class of users404
    already_existsThe entity attempted to be created already exists409
    permission_deniedThe caller doesn't have permission to execute the specified operation403
    resource_exhaustedThe resource has been exhausted e.g. per-user quota exhausted, file system out of space429
    failed_preconditionThe client shouldn't retry until the system state has been explicitly handled400
    abortedThe operation was aborted409
    out_of_rangeThe operation was attempted past the valid range e.g. seeking past the end of a file400
    unimplementedThe operation is not implemented or is not supported/enabled for this operation501
    internal_errorSome invariants expected by the underlying system have been broken. This code is reserved for serious errors500
    unavailableThe service is currently available e.g. as a transient condition503
    data_lossUnrecoverable data loss or corruption500
    unauthenticatedThe requester doesn't have valid authentication credentials for the operation401
    Copied
    {
      "status": "ok"
    }

    tags
    Optional. A map or list of tags for this event. Each tag must be less than 200 characters.

    Copied
    {
      "tags": {
        "ios_version": "4.0",
        "context": "production"
      }
    }

    data
    Optional. Arbitrary data associated with this Span.

    Copied
    {
      "data": {
        "url": "http://localhost:8080/sockjs-node/info?t=1588601703755",
        "status_code": 200,
        "type": "xhr",
        "method": "GET"
      }
    }

    Examples

    The following example illustrates the Span as part of the Transaction and omits other attributes for simplicity.

    Copied
    {
      "spans": [
        {
          "trace_id": "1e57b752bc6e4544bbaa246cd1d05dee",
          "span_id": "b01b9f6349558cd1",
          "parent_span_id": "b0e6f15b45c36b12",
          "op": "http",
          "description": "GET /sockjs-node/info",
          "status": "ok",
          "start_timestamp": 1588601261.481961,
          "timestamp": 1588601261.488901,
          "tags": {
            "http.status_code": "200"
          },
          "data": {
            "url": "http://localhost:8080/sockjs-node/info?t=1588601703755",
            "status_code": 200,
            "type": "xhr",
            "method": "GET"
          }
        },
        {
          "trace_id": "1e57b752bc6e4544bbaa246cd1d05dee",
          "span_id": "b980d4dec78d7344",
          "parent_span_id": "9312d0d18bf51736",
          "op": "update",
          "description": "Vue <App>",
          "start_timestamp": 1588601261.535386,
          "timestamp": 1588601261.544196
        }
      ]
    }
    You can edit this page on GitHub.