Skip to content

Commit

Permalink
Add WithStatus option to set Span status at the same time (open-telem…
Browse files Browse the repository at this point in the history
…etry#1677)

Signed-off-by: lastchiliarch <[email protected]>
  • Loading branch information
lastchiliarch committed Apr 17, 2021
1 parent a2cecb6 commit 5ae2893
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

### Added

- Added `WithStatus` event option to set Span status at the same time when call RecordError. (#1677)
- Added `resource.Default()` for use with meter and tracer providers. (#1507)
- `AttributePerEventCountLimit` and `AttributePerLinkCountLimit` for `SpanLimits`. (#1535)
- Added `Keys()` method to `propagation.TextMapCarrier` and `propagation.HeaderCarrier` to adapt `http.Header` to this interface. (#1544)
Expand Down
12 changes: 8 additions & 4 deletions sdk/trace/span.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,14 +244,18 @@ func (s *span) End(options ...trace.SpanOption) {
}
}

// RecordError will record err as a span event for this span. An additional call to
// SetStatus is required if the Status of the Span should be set to Error, this method
// does not change the Span status. If this span is not being recorded or err is nil
// than this method does nothing.
// RecordError will record err as a span event for this span.
// this method does not change the Span status in default.
// If you want to change Span status, pass WithStatus as opts.
// this metod does nothing If this span is not being recorded or err is nil.
func (s *span) RecordError(err error, opts ...trace.EventOption) {
if s == nil || err == nil || !s.IsRecording() {
return
}
c := trace.NewEventConfig(opts...)
if c.WithStatus {
s.SetStatus(codes.Error, "")
}

opts = append(opts, trace.WithAttributes(
semconv.ExceptionTypeKey.String(typeStr(err)),
Expand Down
53 changes: 53 additions & 0 deletions sdk/trace/trace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1164,6 +1164,59 @@ func TestRecordErrorNil(t *testing.T) {
}
}

func TestRecordErrorWithStatus(t *testing.T) {
scenarios := []struct {
err error
typ string
msg string
}{
{
err: ottest.NewTestError("test error"),
typ: "go.opentelemetry.io/otel/internal/internaltest.TestError",
msg: "test error",
},
}

for _, s := range scenarios {
te := NewTestExporter()
tp := NewTracerProvider(WithSyncer(te), WithResource(resource.Empty()))
span := startSpan(tp, "RecordError")

errTime := time.Now()
span.RecordError(s.err, trace.WithTimestamp(errTime), trace.WithStatus(true))

got, err := endSpan(te, span)
if err != nil {
t.Fatal(err)
}

want := &SpanSnapshot{
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: tid,
TraceFlags: 0x1,
}),
Parent: sc.WithRemote(true),
Name: "span0",
StatusCode: codes.Error,
SpanKind: trace.SpanKindInternal,
MessageEvents: []trace.Event{
{
Name: semconv.ExceptionEventName,
Time: errTime,
Attributes: []attribute.KeyValue{
semconv.ExceptionTypeKey.String(s.typ),
semconv.ExceptionMessageKey.String(s.msg),
},
},
},
InstrumentationLibrary: instrumentation.Library{Name: "RecordError"},
}
if diff := cmpDiff(got, want); diff != "" {
t.Errorf("SpanErrorOptions: -got +want %s", diff)
}
}
}

func TestWithSpanKind(t *testing.T) {
te := NewTestExporter()
tp := NewTracerProvider(WithSyncer(te), WithSampler(AlwaysSample()), WithResource(resource.Empty()))
Expand Down
14 changes: 14 additions & 0 deletions trace/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ type SpanConfig struct {
NewRoot bool
// SpanKind is the role a Span has in a trace.
SpanKind SpanKind
// WithStatus is used to control whether or not set Span status when recordError
WithStatus bool
}

// NewSpanConfig applies all the options to a returned SpanConfig.
Expand Down Expand Up @@ -203,3 +205,15 @@ func (i instrumentationVersionOption) ApplyTracer(config *TracerConfig) {
}

func (instrumentationVersionOption) private() {}

type withStatusSpanOption bool

func (o withStatusSpanOption) ApplySpan(c *SpanConfig) { o.apply(c) }
func (o withStatusSpanOption) ApplyEvent(c *SpanConfig) { o.apply(c) }
func (withStatusSpanOption) private() {}
func (o withStatusSpanOption) apply(c *SpanConfig) { c.WithStatus = bool(o) }

// WithStatus sets the status at the same time when recordError
func WithStatus(o bool) LifeCycleOption {
return withStatusSpanOption(o)
}
14 changes: 14 additions & 0 deletions trace/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ func TestNewSpanConfig(t *testing.T) {
Attributes: []attribute.KeyValue{k1v2, k2v2},
}

withStatusOpt := WithStatus(true)
//just for coverage
withStatusOpt.private()

tests := []struct {
options []SpanOption
expected *SpanConfig
Expand Down Expand Up @@ -151,6 +155,14 @@ func TestNewSpanConfig(t *testing.T) {
SpanKind: SpanKindConsumer,
},
},
{
[]SpanOption{
withStatusOpt,
},
&SpanConfig{
WithStatus: true,
},
},
{
// Everything should work together.
[]SpanOption{
Expand All @@ -159,13 +171,15 @@ func TestNewSpanConfig(t *testing.T) {
WithLinks(link1, link2),
WithNewRoot(),
WithSpanKind(SpanKindConsumer),
WithStatus(true),
},
&SpanConfig{
Attributes: []attribute.KeyValue{k1v1},
Timestamp: timestamp0,
Links: []Link{link1, link2},
NewRoot: true,
SpanKind: SpanKindConsumer,
WithStatus: true,
},
},
}
Expand Down

0 comments on commit 5ae2893

Please sign in to comment.