func makeCause()

in exporter/awsxrayexporter/internal/translator/cause.go [32:189]


func makeCause(span ptrace.Span, attributes map[string]pcommon.Value, resource pcommon.Resource) (isError, isFault, isThrottle bool,
	filtered map[string]pcommon.Value, cause *awsxray.CauseData,
) {
	status := span.Status()

	filtered = attributes

	var (
		message   string
		errorKind string
	)

	isAwsSdkSpan := isAwsSdkSpan(span)
	hasExceptionEvents := false
	hasAwsIndividualHTTPError := false
	for i := 0; i < span.Events().Len(); i++ {
		event := span.Events().At(i)
		if event.Name() == ExceptionEventName {
			hasExceptionEvents = true
			break
		}
		if isAwsSdkSpan && event.Name() == AwsIndividualHTTPEventName {
			hasAwsIndividualHTTPError = true
			break
		}
	}
	hasExceptions := hasExceptionEvents || hasAwsIndividualHTTPError

	switch {
	case hasExceptions:
		language := ""
		if val, ok := resource.Attributes().Get(conventionsv112.AttributeTelemetrySDKLanguage); ok {
			language = val.Str()
		}
		isRemote := false
		if span.Kind() == ptrace.SpanKindClient || span.Kind() == ptrace.SpanKindProducer {
			isRemote = true
		}

		var exceptions []awsxray.Exception
		for i := 0; i < span.Events().Len(); i++ {
			event := span.Events().At(i)
			if event.Name() == ExceptionEventName {
				exceptionType := ""
				message = ""
				stacktrace := ""

				if val, ok := event.Attributes().Get(conventionsv112.AttributeExceptionType); ok {
					exceptionType = val.Str()
				}

				if val, ok := event.Attributes().Get(conventionsv112.AttributeExceptionMessage); ok {
					message = val.Str()
				}

				if val, ok := event.Attributes().Get(conventionsv112.AttributeExceptionStacktrace); ok {
					stacktrace = val.Str()
				}

				parsed := parseException(exceptionType, message, stacktrace, isRemote, language)
				exceptions = append(exceptions, parsed...)
			} else if isAwsSdkSpan && event.Name() == AwsIndividualHTTPEventName {
				errorCode, ok1 := event.Attributes().Get(conventions.AttributeHTTPResponseStatusCode)
				errorMessage, ok2 := event.Attributes().Get(AwsIndividualHTTPErrorMsgAttr)
				if ok1 && ok2 {
					eventEpochTime := event.Timestamp().AsTime().UnixMicro()
					strs := []string{
						errorCode.AsString(),
						strconv.FormatFloat(float64(eventEpochTime)/1_000_000, 'f', 6, 64),
						errorMessage.Str(),
					}
					message = strings.Join(strs, "@")
					segmentID := newSegmentID()
					exception := awsxray.Exception{
						ID:      aws.String(hex.EncodeToString(segmentID[:])),
						Type:    aws.String(AwsIndividualHTTPErrorEventType),
						Remote:  aws.Bool(true),
						Message: aws.String(message),
					}
					exceptions = append(exceptions, exception)
				}
			}
		}
		cause = &awsxray.CauseData{
			Type: awsxray.CauseTypeObject,
			CauseObject: awsxray.CauseObject{
				Exceptions: exceptions,
			},
		}

	case status.Code() != ptrace.StatusCodeError:
		cause = nil

	default:
		// Use OpenCensus behavior if we didn't find any exception events to ease migration.
		message = status.Message()
		filtered = make(map[string]pcommon.Value)
		for key, value := range attributes {
			switch key {
			case "http.status_text":
				if message == "" {
					message = value.Str()
				}
			default:
				filtered[key] = value
			}
		}

		if message != "" {
			segmentID := newSegmentID()
			cause = &awsxray.CauseData{
				Type: awsxray.CauseTypeObject,
				CauseObject: awsxray.CauseObject{
					Exceptions: []awsxray.Exception{
						{
							ID:      aws.String(hex.EncodeToString(segmentID[:])),
							Type:    aws.String(errorKind),
							Message: aws.String(message),
						},
					},
				},
			}
		}
	}

	val, ok := span.Attributes().Get(conventionsv112.AttributeHTTPStatusCode)
	if !ok {
		val, ok = span.Attributes().Get(conventions.AttributeHTTPResponseStatusCode)
	}

	// The segment status for http spans will be based on their http.statuscode as we found some http
	// spans does not fill with status.Code() but always filled with http.statuscode
	var code int64
	if ok {
		code = val.Int()
	}

	// Default values
	isThrottle = false
	isError = false
	isFault = false

	switch {
	case !ok || code < 400 || code > 599:
		if status.Code() == ptrace.StatusCodeError {
			isFault = true
		}
	case code >= 400 && code <= 499:
		isError = true
		if code == 429 {
			isThrottle = true
		}
	case code >= 500 && code <= 599:
		isFault = true
	}

	return isError, isFault, isThrottle, filtered, cause
}