Skip to content

Commit ebebb73

Browse files
authored
Merge branch 'main' into fix-net-http-host
2 parents 25e767b + ef154ab commit ebebb73

18 files changed

+192
-2
lines changed

Diff for: CHANGES.md

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Release Notes.
99
* support attaching events to span in the toolkit.
1010
* support record log in the toolkit.
1111
* support manually report metrics in the toolkit.
12+
* support manually set span error in the toolkit.
1213

1314
#### Plugins
1415
* Support [goframev2](https://github.com/gogf/gf) goframev2.
@@ -22,6 +23,7 @@ Release Notes.
2223
* Fix wrong docker image name and `-version` command.
2324
* Fix redis plugin cannot work in cluster mode.
2425
* Fix cannot find file when exec build in test/plugins.
26+
* Fix not set span error when http status code >= 400
2527
* Fix http plugin cannot provide peer name when optional Host is empty.
2628

2729
#### Issues and PR

Diff for: plugins/core/span_default.go

+8
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,14 @@ func (ds *DefaultSpan) Error(ll ...string) {
148148
ds.Log(ll...)
149149
}
150150

151+
func (ds *DefaultSpan) ErrorOccured() {
152+
if ds.InAsyncMode {
153+
ds.AsyncOpLocker.Lock()
154+
defer ds.AsyncOpLocker.Unlock()
155+
}
156+
ds.IsError = true
157+
}
158+
151159
func (ds *DefaultSpan) End(changeParent bool) {
152160
ds.EndTime = time.Now()
153161
if changeParent {

Diff for: plugins/core/span_noop.go

+3
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ func (*NoopSpan) Log(...string) {
8989
func (*NoopSpan) Error(...string) {
9090
}
9191

92+
func (*NoopSpan) ErrorOccured() {
93+
}
94+
9295
func (n *NoopSpan) enterNoSpan() {
9396
n.stackCount++
9497
}

Diff for: plugins/core/span_tracing.go

+4
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,10 @@ func (s *SnapshotSpan) Error(_ ...string) {
312312
panic(fmt.Errorf("cannot add error of span in other goroutine"))
313313
}
314314

315+
func (s *SnapshotSpan) ErrorOccured() {
316+
panic(fmt.Errorf("cannot add error of span in other goroutine"))
317+
}
318+
315319
func (s *SnapshotSpan) GetSegmentContext() SegmentContext {
316320
return s.SegmentContext
317321
}

Diff for: plugins/core/tracing/api.go

+2
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,8 @@ func (n *NoopSpan) Log(...string) {
232232
}
233233
func (n *NoopSpan) Error(...string) {
234234
}
235+
func (n *NoopSpan) ErrorOccured() {
236+
}
235237
func (n *NoopSpan) End() {
236238
}
237239
func (n *NoopSpan) PrepareAsync() {

Diff for: plugins/core/tracing/bridge.go

+5
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ type AdaptSpan interface {
3838
Tag(string, string)
3939
Log(...string)
4040
Error(...string)
41+
ErrorOccured()
4142
End()
4243
}
4344

@@ -89,6 +90,10 @@ func (s *SpanWrapper) Error(v ...string) {
8990
s.Span.Error(v...)
9091
}
9192

93+
func (s *SpanWrapper) ErrorOccured() {
94+
s.Span.ErrorOccured()
95+
}
96+
9297
func (s *SpanWrapper) End() {
9398
s.Span.End()
9499
}

Diff for: plugins/core/tracing/span.go

+2
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ type Span interface {
137137
Log(...string)
138138
// Error add error log to the Span
139139
Error(...string)
140+
// Error and no log to the Span
141+
ErrorOccured()
140142
// End end the Span
141143
End()
142144
}

Diff for: plugins/gin/intercepter.go

+3
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ func (h *ContextInterceptor) AfterInvoke(invocation operator.Invocation, result
6767
context := invocation.CallerInstance().(*gin.Context)
6868
span := invocation.GetContext().(tracing.Span)
6969
span.Tag(tracing.TagStatusCode, fmt.Sprintf("%d", context.Writer.Status()))
70+
if context.Writer.Status() >= 400 {
71+
span.ErrorOccured()
72+
}
7073
if len(context.Errors) > 0 {
7174
span.Error(context.Errors.String())
7275
}

Diff for: plugins/http/client_intercepter.go

+3
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ func (h *ClientInterceptor) AfterInvoke(invocation operator.Invocation, result .
5555
span := invocation.GetContext().(tracing.Span)
5656
if resp, ok := result[0].(*http.Response); ok && resp != nil {
5757
span.Tag(tracing.TagStatusCode, fmt.Sprintf("%d", resp.StatusCode))
58+
if resp.StatusCode >= 400 {
59+
span.ErrorOccured()
60+
}
5861
}
5962
if err, ok := result[1].(error); ok && err != nil {
6063
span.Error(err.Error())

Diff for: plugins/http/client_intercepter_test.go

+24
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,27 @@ func TestClientInvoke(t *testing.T) {
6969
assert.Nil(t, spans[0].Refs(), "refs should be nil")
7070
assert.Greater(t, spans[0].EndTime(), spans[0].StartTime(), "end time should be greater than start time")
7171
}
72+
73+
func TestClientInvokeError(t *testing.T) {
74+
defer core.ResetTracingContext()
75+
interceptor := &ClientInterceptor{}
76+
request, err := http.NewRequest("GET", "http://localhost/", http.NoBody)
77+
assert.Nil(t, err, "new request error should be nil")
78+
invocation := operator.NewInvocation(nil, request)
79+
err = interceptor.BeforeInvoke(invocation)
80+
assert.Nil(t, err, "before invoke error should be nil")
81+
assert.NotNil(t, invocation.GetContext(), "context should not be nil")
82+
83+
time.Sleep(100 * time.Millisecond)
84+
85+
err = interceptor.AfterInvoke(invocation, &http.Response{
86+
StatusCode: 500,
87+
}, nil)
88+
assert.Nil(t, err, "after invoke error should be nil")
89+
90+
time.Sleep(100 * time.Millisecond)
91+
spans := core.GetReportedSpans()
92+
assert.NotNil(t, spans, "spans should not be nil")
93+
assert.Equal(t, 1, len(spans), "spans length should be 1")
94+
assert.True(t, spans[0].IsError(), "span should be error")
95+
}

Diff for: plugins/http/server_intercepter.go

+3
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ func (h *ServerInterceptor) AfterInvoke(invocation operator.Invocation, result .
5959
span := invocation.GetContext().(tracing.Span)
6060
if wrapped, ok := invocation.Args()[0].(*writerWrapper); ok {
6161
span.Tag(tracing.TagStatusCode, fmt.Sprintf("%d", wrapped.statusCode))
62+
if wrapped.statusCode >= 400 {
63+
span.ErrorOccured()
64+
}
6265
}
6366
span.End()
6467
return nil

Diff for: plugins/http/server_intercepter_test.go

+27
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,26 @@ func TestServerInvoke(t *testing.T) {
5555
assert.Greater(t, spans[0].EndTime(), spans[0].StartTime(), "end time should be greater than start time")
5656
}
5757

58+
func TestServerInvokeError(t *testing.T) {
59+
defer core.ResetTracingContext()
60+
interceptor := &ServerInterceptor{}
61+
request, _ := http.NewRequest("GET", "http://localhost/", http.NoBody)
62+
responseWriter := &testResponseWriter{}
63+
invocation := operator.NewInvocation(nil, responseWriter, request)
64+
_ = interceptor.BeforeInvoke(invocation)
65+
66+
wrapped, _ := invocation.Args()[0].(*writerWrapper)
67+
68+
wrapped.WriteHeader(http.StatusInternalServerError)
69+
70+
time.Sleep(100 * time.Millisecond)
71+
_ = interceptor.AfterInvoke(invocation)
72+
time.Sleep(100 * time.Millisecond)
73+
74+
spans := core.GetReportedSpans()
75+
assert.True(t, spans[0].IsError(), "span should be error")
76+
}
77+
5878
type testResponseWriter struct {
5979
http.ResponseWriter
6080
}
@@ -71,3 +91,10 @@ func (t *testResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
7191
}
7292
return dial, nil, nil
7393
}
94+
95+
func (t *testResponseWriter) WriteHeader(code int) {
96+
}
97+
98+
func (t *testResponseWriter) Write(b []byte) (int, error) {
99+
return len(b), nil
100+
}

Diff for: plugins/toolkit-activation/instrument.go

+4
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,10 @@ func tracePoint() []*instrument.Point {
203203
PackagePath: "trace", At: instrument.NewStaticMethodEnhance("SetComponent"),
204204
Interceptor: "SetComponentInterceptor",
205205
},
206+
{
207+
PackagePath: "trace", At: instrument.NewStaticMethodEnhance("Error"),
208+
Interceptor: "ErrorIntercepter",
209+
},
206210
}
207211
}
208212

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Licensed to Apache Software Foundation (ASF) under one or more contributor
2+
// license agreements. See the NOTICE file distributed with
3+
// this work for additional information regarding copyright
4+
// ownership. Apache Software Foundation (ASF) licenses this file to you under
5+
// the Apache License, Version 2.0 (the "License"); you may
6+
// not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package traceactivation
19+
20+
import (
21+
"github.com/apache/skywalking-go/plugins/core/operator"
22+
"github.com/apache/skywalking-go/plugins/core/tracing"
23+
)
24+
25+
type ErrorIntercepter struct {
26+
}
27+
28+
func (h *ErrorIntercepter) BeforeInvoke(invocation operator.Invocation) error {
29+
span := tracing.ActiveSpan()
30+
if span != nil {
31+
args := invocation.Args()[0].([]string)
32+
span.Error(args...)
33+
}
34+
return nil
35+
}
36+
37+
func (h *ErrorIntercepter) AfterInvoke(_ operator.Invocation, _ ...interface{}) error {
38+
return nil
39+
}

Diff for: test/plugins/scenarios/gin/config/excepted.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ segmentItems:
4949
startTime: nq 0
5050
endTime: nq 0
5151
componentId: 5006
52-
isError: false
52+
isError: true
5353
spanType: Entry
5454
peer: ''
5555
skipAnalysis: false
@@ -85,7 +85,7 @@ segmentItems:
8585
startTime: gt 0
8686
endTime: gt 0
8787
componentId: 5005
88-
isError: false
88+
isError: true
8989
spanType: Exit
9090
peer: localhost:8080
9191
skipAnalysis: false

Diff for: test/plugins/scenarios/http/config/excepted.yml

+37
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,21 @@ segmentItems:
5757
- {key: http.method, value: GET}
5858
- {key: url, value: 'localhost:8080/provider'}
5959
- {key: status_code, value: '200'}
60+
- operationName: GET:/errortest
61+
parentSpanId: 0
62+
spanId: 2
63+
spanLayer: Http
64+
startTime: gt 0
65+
endTime: gt 0
66+
componentId: 5005
67+
isError: true
68+
spanType: Exit
69+
peer: localhost:8080
70+
skipAnalysis: false
71+
tags:
72+
- {key: http.method, value: GET}
73+
- {key: url, value: 'localhost:8080/errortest'}
74+
- {key: status_code, value: '500'}
6075
- operationName: GET:/consumer
6176
parentSpanId: -1
6277
spanId: 0
@@ -73,5 +88,27 @@ segmentItems:
7388
- {key: url, value: 'service:8080/consumer'}
7489
- {key: http.params, value: ''}
7590
- {key: status_code, value: '200'}
91+
- segmentId: not null
92+
spans:
93+
- operationName: GET:/errortest
94+
parentSpanId: -1
95+
spanId: 0
96+
spanLayer: Http
97+
startTime: nq 0
98+
endTime: nq 0
99+
componentId: 5004
100+
isError: true
101+
spanType: Entry
102+
peer: ''
103+
skipAnalysis: false
104+
tags:
105+
- {key: http.method, value: GET}
106+
- {key: url, value: 'localhost:8080/errortest'}
107+
- {key: http.params, value: ''}
108+
- {key: status_code, value: '500'}
109+
refs:
110+
- {parentEndpoint: 'GET:/consumer', networkAddress: 'localhost:8080', refType: CrossProcess,
111+
parentSpanId: 2, parentTraceSegmentId: not null, parentServiceInstance: not null,
112+
parentService: http, traceId: not null}
76113
meterItems: []
77114
logItems: []

Diff for: test/plugins/scenarios/http/main.go

+21
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,32 @@ func consumerHandler(w http.ResponseWriter, r *http.Request) {
4444
return
4545
}
4646
_, _ = w.Write(body)
47+
48+
resp, err = http.Get("http://localhost:8080/errortest")
49+
if err != nil {
50+
log.Printf("request errortest error: %v", err)
51+
w.WriteHeader(http.StatusInternalServerError)
52+
return
53+
}
54+
defer resp.Body.Close()
55+
body, err = io.ReadAll(resp.Body)
56+
if err != nil {
57+
log.Print(err)
58+
w.WriteHeader(http.StatusInternalServerError)
59+
return
60+
}
61+
_, _ = w.Write(body)
62+
}
63+
64+
func errorHandler(w http.ResponseWriter, r *http.Request) {
65+
w.WriteHeader(http.StatusInternalServerError)
66+
w.Write([]byte("internal server error"))
4767
}
4868

4969
func main() {
5070
http.HandleFunc("/provider", providerHandler)
5171
http.HandleFunc("/consumer", consumerHandler)
72+
http.HandleFunc("/errortest", errorHandler)
5273

5374
http.HandleFunc("/health", func(writer http.ResponseWriter, request *http.Request) {
5475
writer.WriteHeader(http.StatusOK)

Diff for: toolkit/trace/api.go

+3
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,6 @@ func SetCorrelation(key string, value string) {
8686

8787
func SetComponent(componentID int32) {
8888
}
89+
90+
func Error(...string) {
91+
}

0 commit comments

Comments
 (0)