1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2025-06-16 23:47:36 +02:00

Add Status type to SDK (#1874)

Add Status type to SDK

Use this type to encapsulate the Span status similar to the Event type
encapsulating a Span event and the Link type a span link.

Co-authored-by: Anthony Mirabella <a9@aneurysm9.com>
This commit is contained in:
Tyler Yahn
2021-05-03 19:00:54 +00:00
committed by GitHub
parent f90d0d93f8
commit b7d02db147
14 changed files with 179 additions and 134 deletions

View File

@ -21,6 +21,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
| 10 | Out of Range |
| 14 | Unavailable |
| 15 | Data Loss |
- The `Status` type was added to the `go.opentelemetry.io/otel/sdk/trace` package to represent the status of a span. (#1874)
### Changed
@ -31,6 +32,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- BatchSpanProcessor now report export failures when calling `ForceFlush()` method. (#1860)
- `Set.Encoded(Encoder)` no longer caches the result of an encoding. (#1855)
- Renamed `CloudZoneKey` to `CloudAvailabilityZoneKey` in Resource semantic conventions according to spec. (#1871)
- The `StatusCode` and `StatusMessage` methods of the `ReadOnlySpan` interface and the `Span` produced by the `go.opentelemetry.io/otel/sdk/trace` package have been replaced with a single `Status` method.
This method returns the status of a span using the new `Status` type. (#1874)
### Deprecated

View File

@ -99,8 +99,7 @@ func SingleSpanSnapshot() []*tracesdk.SpanSnapshot {
Attributes: []attribute.KeyValue{},
MessageEvents: []tracesdk.Event{},
Links: []trace.Link{},
StatusCode: codes.Ok,
StatusMessage: "",
Status: tracesdk.Status{Code: codes.Ok},
DroppedAttributeCount: 0,
DroppedMessageEventCount: 0,
DroppedLinkCount: 0,

View File

@ -108,7 +108,7 @@ func span(sd *tracesdk.SpanSnapshot) *tracepb.Span {
TraceId: tid[:],
SpanId: sid[:],
TraceState: sd.SpanContext.TraceState().String(),
Status: status(sd.StatusCode, sd.StatusMessage),
Status: status(sd.Status.Code, sd.Status.Description),
StartTimeUnixNano: uint64(sd.StartTime.UnixNano()),
EndTimeUnixNano: uint64(sd.EndTime.UnixNano()),
Links: links(sd.Links),

View File

@ -249,8 +249,10 @@ func TestSpanData(t *testing.T) {
},
},
},
StatusCode: codes.Error,
StatusMessage: "utterly unrecognized",
Status: tracesdk.Status{
Code: codes.Error,
Description: "utterly unrecognized",
},
Attributes: []attribute.KeyValue{
attribute.Int64("timeout_ns", 12e9),
},
@ -276,7 +278,7 @@ func TestSpanData(t *testing.T) {
Kind: tracepb.Span_SPAN_KIND_SERVER,
StartTimeUnixNano: uint64(startTime.UnixNano()),
EndTimeUnixNano: uint64(endTime.UnixNano()),
Status: status(spanData.StatusCode, spanData.StatusMessage),
Status: status(spanData.Status.Code, spanData.Status.Description),
Events: spanEvents(spanData.MessageEvents),
Links: links(spanData.Links),
Attributes: Attributes(spanData.Attributes),

View File

@ -68,8 +68,10 @@ func TestExportSpans(t *testing.T) {
attribute.String("user", "alice"),
attribute.Bool("authenticated", true),
},
StatusCode: codes.Ok,
StatusMessage: "Ok",
Status: tracesdk.Status{
Code: codes.Ok,
Description: "Ok",
},
Resource: resource.NewWithAttributes(attribute.String("instance", "tester-a")),
InstrumentationLibrary: instrumentation.Library{
Name: "lib-a",
@ -90,8 +92,10 @@ func TestExportSpans(t *testing.T) {
attribute.String("user", "alice"),
attribute.Bool("authenticated", true),
},
StatusCode: codes.Ok,
StatusMessage: "Ok",
Status: tracesdk.Status{
Code: codes.Ok,
Description: "Ok",
},
Resource: resource.NewWithAttributes(attribute.String("instance", "tester-a")),
InstrumentationLibrary: instrumentation.Library{
Name: "lib-b",
@ -117,8 +121,10 @@ func TestExportSpans(t *testing.T) {
attribute.String("user", "alice"),
attribute.Bool("authenticated", true),
},
StatusCode: codes.Ok,
StatusMessage: "Ok",
Status: tracesdk.Status{
Code: codes.Ok,
Description: "Ok",
},
Resource: resource.NewWithAttributes(attribute.String("instance", "tester-a")),
InstrumentationLibrary: instrumentation.Library{
Name: "lib-a",
@ -139,8 +145,10 @@ func TestExportSpans(t *testing.T) {
attribute.String("user", "bob"),
attribute.Bool("authenticated", false),
},
StatusCode: codes.Error,
StatusMessage: "Unauthenticated",
Status: tracesdk.Status{
Code: codes.Error,
Description: "Unauthenticated",
},
Resource: resource.NewWithAttributes(attribute.String("instance", "tester-b")),
InstrumentationLibrary: instrumentation.Library{
Name: "lib-a",

View File

@ -65,8 +65,10 @@ func TestExporter_ExportSpan(t *testing.T) {
{Name: "bar", Attributes: []attribute.KeyValue{attribute.Float64("double", doubleValue)}, Time: now},
},
SpanKind: trace.SpanKindInternal,
StatusCode: codes.Error,
StatusMessage: "interesting",
Status: tracesdk.Status{
Code: codes.Error,
Description: "interesting",
},
Resource: resource,
}
if err := ex.ExportSpans(context.Background(), []*tracesdk.SpanSnapshot{testSpan}); err != nil {
@ -129,8 +131,7 @@ func TestExporter_ExportSpan(t *testing.T) {
`}` +
`],` +
`"Links":null,` +
`"StatusCode":"Error",` +
`"StatusMessage":"interesting",` +
`"Status":{"Code":"Error","Description":"interesting"},` +
`"DroppedAttributeCount":0,` +
`"DroppedMessageEventCount":0,` +
`"DroppedLinkCount":0,` +

View File

@ -170,13 +170,13 @@ func spanSnapshotToThrift(ss *sdktrace.SpanSnapshot) *gen.Span {
)
}
if ss.StatusCode != codes.Unset {
tags = append(tags, getInt64Tag(keyStatusCode, int64(ss.StatusCode)))
if ss.StatusMessage != "" {
tags = append(tags, getStringTag(keyStatusMessage, ss.StatusMessage))
if ss.Status.Code != codes.Unset {
tags = append(tags, getInt64Tag(keyStatusCode, int64(ss.Status.Code)))
if ss.Status.Description != "" {
tags = append(tags, getStringTag(keyStatusMessage, ss.Status.Description))
}
if ss.StatusCode == codes.Error {
if ss.Status.Code == codes.Error {
tags = append(tags, getBoolTag(keyError, true))
}
}

View File

@ -232,7 +232,7 @@ func Test_spanSnapshotToThrift(t *testing.T) {
Name: "/foo",
StartTime: now,
EndTime: now,
StatusCode: codes.Error,
Status: sdktrace.Status{Code: codes.Error},
SpanKind: trace.SpanKindClient,
InstrumentationLibrary: instrumentation.Library{
Name: instrLibName,
@ -287,8 +287,10 @@ func Test_spanSnapshotToThrift(t *testing.T) {
Time: now,
},
},
StatusCode: codes.Error,
StatusMessage: statusMessage,
Status: sdktrace.Status{
Code: codes.Error,
Description: statusMessage,
},
SpanKind: trace.SpanKindClient,
InstrumentationLibrary: instrumentation.Library{
Name: instrLibName,
@ -370,8 +372,10 @@ func Test_spanSnapshotToThrift(t *testing.T) {
Attributes: []attribute.KeyValue{
attribute.Array("arr", []int{0, 1, 2, 3}),
},
StatusCode: codes.Unset,
StatusMessage: statusMessage,
Status: sdktrace.Status{
Code: codes.Unset,
Description: statusMessage,
},
SpanKind: trace.SpanKindInternal,
InstrumentationLibrary: instrumentation.Library{
Name: instrLibName,
@ -421,8 +425,10 @@ func Test_spanSnapshotToThrift(t *testing.T) {
attribute.Int64("rk2", rv2),
semconv.ServiceNameKey.String("service name"),
),
StatusCode: codes.Unset,
StatusMessage: statusMessage,
Status: sdktrace.Status{
Code: codes.Unset,
Description: statusMessage,
},
SpanKind: trace.SpanKindInternal,
InstrumentationLibrary: instrumentation.Library{
Name: instrLibName,

View File

@ -187,12 +187,12 @@ func toZipkinTags(data *tracesdk.SpanSnapshot) map[string]string {
}
}
if data.StatusCode != codes.Unset {
m["otel.status_code"] = data.StatusCode.String()
if data.Status.Code != codes.Unset {
m["otel.status_code"] = data.Status.Code.String()
}
if data.StatusCode == codes.Error {
m["error"] = data.StatusMessage
if data.Status.Code == codes.Error {
m["error"] = data.Status.Description
} else {
delete(m, "error")
}

View File

@ -74,8 +74,10 @@ func TestModelConversion(t *testing.T) {
Attributes: nil,
},
},
StatusCode: codes.Error,
StatusMessage: "404, file not found",
Status: tracesdk.Status{
Code: codes.Error,
Description: "404, file not found",
},
Resource: resource,
},
// span data with no parent (same as typical, but has
@ -107,8 +109,10 @@ func TestModelConversion(t *testing.T) {
Attributes: nil,
},
},
StatusCode: codes.Error,
StatusMessage: "404, file not found",
Status: tracesdk.Status{
Code: codes.Error,
Description: "404, file not found",
},
Resource: resource,
},
// span data of unspecified kind
@ -143,8 +147,10 @@ func TestModelConversion(t *testing.T) {
Attributes: nil,
},
},
StatusCode: codes.Error,
StatusMessage: "404, file not found",
Status: tracesdk.Status{
Code: codes.Error,
Description: "404, file not found",
},
Resource: resource,
},
// span data of internal kind
@ -179,8 +185,10 @@ func TestModelConversion(t *testing.T) {
Attributes: nil,
},
},
StatusCode: codes.Error,
StatusMessage: "404, file not found",
Status: tracesdk.Status{
Code: codes.Error,
Description: "404, file not found",
},
Resource: resource,
},
// span data of client kind
@ -218,8 +226,10 @@ func TestModelConversion(t *testing.T) {
Attributes: nil,
},
},
StatusCode: codes.Error,
StatusMessage: "404, file not found",
Status: tracesdk.Status{
Code: codes.Error,
Description: "404, file not found",
},
Resource: resource,
},
// span data of producer kind
@ -254,8 +264,10 @@ func TestModelConversion(t *testing.T) {
Attributes: nil,
},
},
StatusCode: codes.Error,
StatusMessage: "404, file not found",
Status: tracesdk.Status{
Code: codes.Error,
Description: "404, file not found",
},
Resource: resource,
},
// span data of consumer kind
@ -290,8 +302,10 @@ func TestModelConversion(t *testing.T) {
Attributes: nil,
},
},
StatusCode: codes.Error,
StatusMessage: "404, file not found",
Status: tracesdk.Status{
Code: codes.Error,
Description: "404, file not found",
},
Resource: resource,
},
// span data with no events
@ -313,8 +327,10 @@ func TestModelConversion(t *testing.T) {
attribute.String("attr2", "bar"),
},
MessageEvents: nil,
StatusCode: codes.Error,
StatusMessage: "404, file not found",
Status: tracesdk.Status{
Code: codes.Error,
Description: "404, file not found",
},
Resource: resource,
},
// span data with an "error" attribute set to "false"
@ -348,7 +364,6 @@ func TestModelConversion(t *testing.T) {
Attributes: nil,
},
},
StatusCode: codes.Unset,
Resource: resource,
},
}
@ -759,8 +774,10 @@ func TestTagsTransformation(t *testing.T) {
attribute.String("key", keyValue),
attribute.Bool("error", true),
},
StatusCode: codes.Error,
StatusMessage: statusMessage,
Status: tracesdk.Status{
Code: codes.Error,
Description: statusMessage,
},
},
want: map[string]string{
"error": statusMessage,

View File

@ -246,8 +246,10 @@ func TestExportSpans(t *testing.T) {
EndTime: time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC),
Attributes: nil,
MessageEvents: nil,
StatusCode: codes.Error,
StatusMessage: "404, file not found",
Status: sdktrace.Status{
Code: codes.Error,
Description: "404, file not found",
},
Resource: resource,
},
// child
@ -266,8 +268,10 @@ func TestExportSpans(t *testing.T) {
EndTime: time.Date(2020, time.March, 11, 19, 24, 45, 0, time.UTC),
Attributes: nil,
MessageEvents: nil,
StatusCode: codes.Error,
StatusMessage: "403, forbidden",
Status: sdktrace.Status{
Code: codes.Error,
Description: "403, forbidden",
},
Resource: resource,
},
}

View File

@ -46,8 +46,7 @@ type ReadOnlySpan interface {
Attributes() []attribute.KeyValue
Links() []trace.Link
Events() []Event
StatusCode() codes.Code
StatusMessage() string
Status() Status
Tracer() trace.Tracer
IsRecording() bool
InstrumentationLibrary() instrumentation.Library
@ -92,11 +91,8 @@ type span struct {
// value of time.Time until the span is ended.
endTime time.Time
// statusCode represents the status of this span as a codes.Code value.
statusCode codes.Code
// statusMessage represents the status of this span as a string.
statusMessage string
// status is the status of this span.
status Status
// childSpanCount holds the number of child spans created for this span.
childSpanCount int
@ -154,19 +150,22 @@ func (s *span) IsRecording() bool {
return !s.startTime.IsZero() && s.endTime.IsZero()
}
// SetStatus sets the status of this span in the form of a code and a
// message. This overrides the existing value of this span's status if one
// exists. Message will be set only if status is error. If this span is not being
// recorded than this method does nothing.
func (s *span) SetStatus(code codes.Code, msg string) {
// SetStatus sets the status of the Span in the form of a code and a
// description, overriding previous values set. The description is only
// included in the set status when the code is for an error. If this span is
// not being recorded than this method does nothing.
func (s *span) SetStatus(code codes.Code, description string) {
if !s.IsRecording() {
return
}
s.mu.Lock()
s.statusCode = code
status := Status{Code: code}
if code == codes.Error {
s.statusMessage = msg
status.Description = description
}
s.mu.Lock()
s.status = status
s.mu.Unlock()
}
@ -381,18 +380,11 @@ func (s *span) Events() []Event {
return s.interfaceArrayToMessageEventArray()
}
// StatusCode returns the status code of this span.
func (s *span) StatusCode() codes.Code {
// Status returns the status of this span.
func (s *span) Status() Status {
s.mu.Lock()
defer s.mu.Unlock()
return s.statusCode
}
// StatusMessage returns the status message of this span.
func (s *span) StatusMessage() string {
s.mu.Lock()
defer s.mu.Unlock()
return s.statusMessage
return s.status
}
// InstrumentationLibrary returns the instrumentation.Library associated with
@ -443,8 +435,7 @@ func (s *span) Snapshot() *SpanSnapshot {
sd.SpanContext = s.spanContext
sd.SpanKind = s.spanKind
sd.StartTime = s.startTime
sd.StatusCode = s.statusCode
sd.StatusMessage = s.statusMessage
sd.Status = s.status
if s.attributes.evictList.Len() > 0 {
sd.Attributes = s.attributes.toKeyValue()
@ -580,6 +571,15 @@ func isSampled(s SamplingResult) bool {
return s.Decision == RecordAndSample
}
// Status is the classified state of a Span.
type Status struct {
// Code is an identifier of a Span's state classification.
Code codes.Code
// Message is a user hint about why the status was set. It is only
// applicable when Code is Error.
Description string
}
// SpanSnapshot is a snapshot of a span which contains all the information
// collected by the span. Its main purpose is exporting completed spans.
// Although SpanSnapshot fields can be accessed and potentially modified,
@ -597,8 +597,7 @@ type SpanSnapshot struct {
Attributes []attribute.KeyValue
MessageEvents []Event
Links []trace.Link
StatusCode codes.Code
StatusMessage string
Status Status
// DroppedAttributeCount contains dropped attributes for the span itself.
DroppedAttributeCount int

View File

@ -741,8 +741,10 @@ func TestSetSpanStatus(t *testing.T) {
Parent: sc.WithRemote(true),
Name: "span0",
SpanKind: trace.SpanKindInternal,
StatusCode: codes.Error,
StatusMessage: "Error",
Status: Status{
Code: codes.Error,
Description: "Error",
},
InstrumentationLibrary: instrumentation.Library{Name: "SpanStatus"},
}
if diff := cmpDiff(got, want); diff != "" {
@ -769,8 +771,10 @@ func TestSetSpanStatusWithoutMessageWhenStatusIsNotError(t *testing.T) {
Parent: sc.WithRemote(true),
Name: "span0",
SpanKind: trace.SpanKindInternal,
StatusCode: codes.Ok,
StatusMessage: "",
Status: Status{
Code: codes.Ok,
Description: "",
},
InstrumentationLibrary: instrumentation.Library{Name: "SpanStatus"},
}
if diff := cmpDiff(got, want); diff != "" {
@ -1117,7 +1121,7 @@ func TestRecordError(t *testing.T) {
}),
Parent: sc.WithRemote(true),
Name: "span0",
StatusCode: codes.Unset,
Status: Status{Code: codes.Unset},
SpanKind: trace.SpanKindInternal,
MessageEvents: []Event{
{
@ -1157,8 +1161,10 @@ func TestRecordErrorNil(t *testing.T) {
Parent: sc.WithRemote(true),
Name: "span0",
SpanKind: trace.SpanKindInternal,
StatusCode: codes.Unset,
StatusMessage: "",
Status: Status{
Code: codes.Unset,
Description: "",
},
InstrumentationLibrary: instrumentation.Library{Name: "RecordErrorNil"},
}
if diff := cmpDiff(got, want); diff != "" {
@ -1380,8 +1386,8 @@ func TestReadOnlySpan(t *testing.T) {
assert.Equal(t, linked, ro.Links()[0].SpanContext)
assert.Equal(t, kv.Key, ro.Events()[0].Attributes[0].Key)
assert.Equal(t, kv.Value, ro.Events()[0].Attributes[0].Value)
assert.Equal(t, codes.Ok, ro.StatusCode())
assert.Equal(t, "", ro.StatusMessage())
assert.Equal(t, codes.Ok, ro.Status().Code)
assert.Equal(t, "", ro.Status().Description)
assert.Equal(t, "ReadOnlySpan", ro.InstrumentationLibrary().Name)
assert.Equal(t, "3", ro.InstrumentationLibrary().Version)
assert.Equal(t, kv.Key, ro.Resource().Attributes()[0].Key)

View File

@ -525,9 +525,9 @@ type Span interface {
SpanContext() SpanContext
// SetStatus sets the status of the Span in the form of a code and a
// message. SetStatus overrides the value of previous calls to SetStatus
// on the Span.
SetStatus(code codes.Code, msg string)
// description, overriding previous values set. The description is only
// included in a status when the code is for an error.
SetStatus(code codes.Code, description string)
// SetName sets the Span name.
SetName(name string)