Skip to content

Commit 5d238e8

Browse files
committed
Add WithStatus option to set Span status at the same time (open-telemetry#1677)
Signed-off-by: lastchiliarch <lastchiliarch@163.com>
1 parent a2cecb6 commit 5d238e8

File tree

5 files changed

+86
-4
lines changed

5 files changed

+86
-4
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
141141

142142
### Added
143143

144+
- Added `WithStatus` event option to set Span status at the same time when call RecordError. (#1677)
144145
- Added `resource.Default()` for use with meter and tracer providers. (#1507)
145146
- `AttributePerEventCountLimit` and `AttributePerLinkCountLimit` for `SpanLimits`. (#1535)
146147
- Added `Keys()` method to `propagation.TextMapCarrier` and `propagation.HeaderCarrier` to adapt `http.Header` to this interface. (#1544)

sdk/trace/span.go

+8-4
Original file line numberDiff line numberDiff line change
@@ -244,14 +244,18 @@ func (s *span) End(options ...trace.SpanOption) {
244244
}
245245
}
246246

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

256260
opts = append(opts, trace.WithAttributes(
257261
semconv.ExceptionTypeKey.String(typeStr(err)),

sdk/trace/trace_test.go

+53
Original file line numberDiff line numberDiff line change
@@ -1164,6 +1164,59 @@ func TestRecordErrorNil(t *testing.T) {
11641164
}
11651165
}
11661166

1167+
func TestRecordErrorWithStatus(t *testing.T) {
1168+
scenarios := []struct {
1169+
err error
1170+
typ string
1171+
msg string
1172+
}{
1173+
{
1174+
err: ottest.NewTestError("test error"),
1175+
typ: "go.opentelemetry.io/otel/internal/internaltest.TestError",
1176+
msg: "test error",
1177+
},
1178+
}
1179+
1180+
for _, s := range scenarios {
1181+
te := NewTestExporter()
1182+
tp := NewTracerProvider(WithSyncer(te), WithResource(resource.Empty()))
1183+
span := startSpan(tp, "RecordError")
1184+
1185+
errTime := time.Now()
1186+
span.RecordError(s.err, trace.WithTimestamp(errTime), trace.WithStatus(true))
1187+
1188+
got, err := endSpan(te, span)
1189+
if err != nil {
1190+
t.Fatal(err)
1191+
}
1192+
1193+
want := &SpanSnapshot{
1194+
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
1195+
TraceID: tid,
1196+
TraceFlags: 0x1,
1197+
}),
1198+
Parent: sc.WithRemote(true),
1199+
Name: "span0",
1200+
StatusCode: codes.Error,
1201+
SpanKind: trace.SpanKindInternal,
1202+
MessageEvents: []trace.Event{
1203+
{
1204+
Name: semconv.ExceptionEventName,
1205+
Time: errTime,
1206+
Attributes: []attribute.KeyValue{
1207+
semconv.ExceptionTypeKey.String(s.typ),
1208+
semconv.ExceptionMessageKey.String(s.msg),
1209+
},
1210+
},
1211+
},
1212+
InstrumentationLibrary: instrumentation.Library{Name: "RecordError"},
1213+
}
1214+
if diff := cmpDiff(got, want); diff != "" {
1215+
t.Errorf("SpanErrorOptions: -got +want %s", diff)
1216+
}
1217+
}
1218+
}
1219+
11671220
func TestWithSpanKind(t *testing.T) {
11681221
te := NewTestExporter()
11691222
tp := NewTracerProvider(WithSyncer(te), WithSampler(AlwaysSample()), WithResource(resource.Empty()))

trace/config.go

+14
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ type SpanConfig struct {
6060
NewRoot bool
6161
// SpanKind is the role a Span has in a trace.
6262
SpanKind SpanKind
63+
// WithStatus is used to control whether or not set Span status when recordError
64+
WithStatus bool
6365
}
6466

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

205207
func (instrumentationVersionOption) private() {}
208+
209+
type withStatusSpanOption bool
210+
211+
func (o withStatusSpanOption) ApplySpan(c *SpanConfig) { o.apply(c) }
212+
func (o withStatusSpanOption) ApplyEvent(c *SpanConfig) { o.apply(c) }
213+
func (withStatusSpanOption) private() {}
214+
func (o withStatusSpanOption) apply(c *SpanConfig) { c.WithStatus = bool(o) }
215+
216+
// WithStatus sets the status at the same time when recordError
217+
func WithStatus(o bool) LifeCycleOption {
218+
return withStatusSpanOption(o)
219+
}

trace/config_test.go

+10
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,14 @@ func TestNewSpanConfig(t *testing.T) {
151151
SpanKind: SpanKindConsumer,
152152
},
153153
},
154+
{
155+
[]SpanOption{
156+
WithStatus(true),
157+
},
158+
&SpanConfig{
159+
WithStatus: true,
160+
},
161+
},
154162
{
155163
// Everything should work together.
156164
[]SpanOption{
@@ -159,13 +167,15 @@ func TestNewSpanConfig(t *testing.T) {
159167
WithLinks(link1, link2),
160168
WithNewRoot(),
161169
WithSpanKind(SpanKindConsumer),
170+
WithStatus(true),
162171
},
163172
&SpanConfig{
164173
Attributes: []attribute.KeyValue{k1v1},
165174
Timestamp: timestamp0,
166175
Links: []Link{link1, link2},
167176
NewRoot: true,
168177
SpanKind: SpanKindConsumer,
178+
WithStatus: true,
169179
},
170180
},
171181
}

0 commit comments

Comments
 (0)