@@ -17,49 +17,61 @@ package zipkin
17
17
import (
18
18
"compress/gzip"
19
19
"fmt"
20
+ "io"
20
21
"io/ioutil"
21
22
"net/http"
22
23
"strings"
23
24
"time"
24
25
25
26
"github.com/apache/thrift/lib/go/thrift"
27
+ "github.com/go-openapi/loads"
28
+ "github.com/go-openapi/swag"
26
29
"github.com/gorilla/mux"
30
+ "github.com/pkg/errors"
27
31
tchanThrift "github.com/uber/tchannel-go/thrift"
28
32
29
33
"github.com/uber/jaeger/cmd/collector/app"
34
+ "github.com/uber/jaeger/swagger-gen/models"
35
+ "github.com/uber/jaeger/swagger-gen/restapi"
36
+ "github.com/uber/jaeger/swagger-gen/restapi/operations"
30
37
"github.com/uber/jaeger/thrift-gen/zipkincore"
31
38
)
32
39
33
40
// APIHandler handles all HTTP calls to the collector
34
41
type APIHandler struct {
35
42
zipkinSpansHandler app.ZipkinSpansHandler
43
+ zipkinV2API * operations.ZipkinAPI
36
44
}
37
45
38
46
// NewAPIHandler returns a new APIHandler
39
47
func NewAPIHandler (
40
48
zipkinSpansHandler app.ZipkinSpansHandler ,
41
- ) * APIHandler {
49
+ ) (* APIHandler , error ) {
50
+ swaggerSpec , err := loads .Analyzed (restapi .SwaggerJSON , "" )
51
+ if err != nil {
52
+ return nil , errors .Wrapf (err , "Failed to create zipkin swagger" )
53
+ }
42
54
return & APIHandler {
43
55
zipkinSpansHandler : zipkinSpansHandler ,
44
- }
56
+ zipkinV2API : operations .NewZipkinAPI (swaggerSpec ),
57
+ }, nil
45
58
}
46
59
47
60
// RegisterRoutes registers Zipkin routes
48
61
func (aH * APIHandler ) RegisterRoutes (router * mux.Router ) {
49
62
router .HandleFunc ("/api/v1/spans" , aH .saveSpans ).Methods (http .MethodPost )
63
+ router .HandleFunc ("/api/v2/spans" , aH .saveSpansV2 ).Methods (http .MethodPost )
50
64
}
51
65
52
66
func (aH * APIHandler ) saveSpans (w http.ResponseWriter , r * http.Request ) {
53
67
bRead := r .Body
54
68
defer r .Body .Close ()
55
-
56
69
if strings .Contains (r .Header .Get ("Content-Encoding" ), "gzip" ) {
57
- gz , err := gzip . NewReader ( r . Body )
70
+ gz , err := gunzip ( bRead )
58
71
if err != nil {
59
72
http .Error (w , fmt .Sprintf (app .UnableToReadBodyErrFormat , err ), http .StatusBadRequest )
60
73
return
61
74
}
62
- defer gz .Close ()
63
75
bRead = gz
64
76
}
65
77
@@ -84,15 +96,73 @@ func (aH *APIHandler) saveSpans(w http.ResponseWriter, r *http.Request) {
84
96
return
85
97
}
86
98
87
- if len (tSpans ) > 0 {
88
- ctx , _ := tchanThrift .NewContext (time .Minute )
89
- if _ , err = aH .zipkinSpansHandler .SubmitZipkinBatch (ctx , tSpans ); err != nil {
90
- http .Error (w , fmt .Sprintf ("Cannot submit Zipkin batch: %v" , err ), http .StatusInternalServerError )
99
+ if err := aH .saveThriftSpans (tSpans ); err != nil {
100
+ http .Error (w , fmt .Sprintf ("Cannot submit Zipkin batch: %v" , err ), http .StatusInternalServerError )
101
+ return
102
+ }
103
+
104
+ w .WriteHeader (http .StatusAccepted )
105
+ }
106
+
107
+ func (aH * APIHandler ) saveSpansV2 (w http.ResponseWriter , r * http.Request ) {
108
+ bRead := r .Body
109
+ defer r .Body .Close ()
110
+ if strings .Contains (r .Header .Get ("Content-Encoding" ), "gzip" ) {
111
+ gz , err := gunzip (bRead )
112
+ if err != nil {
113
+ http .Error (w , fmt .Sprintf (app .UnableToReadBodyErrFormat , err ), http .StatusBadRequest )
91
114
return
92
115
}
116
+ bRead = gz
93
117
}
94
118
95
- w .WriteHeader (http .StatusAccepted )
119
+ bodyBytes , err := ioutil .ReadAll (bRead )
120
+ if err != nil {
121
+ http .Error (w , fmt .Sprintf (app .UnableToReadBodyErrFormat , err ), http .StatusInternalServerError )
122
+ return
123
+ }
124
+
125
+ var spans models.ListOfSpans
126
+ if err = swag .ReadJSON (bodyBytes , & spans ); err != nil {
127
+ http .Error (w , fmt .Sprintf (app .UnableToReadBodyErrFormat , err ), http .StatusBadRequest )
128
+ return
129
+ }
130
+ if err = spans .Validate (aH .zipkinV2API .Formats ()); err != nil {
131
+ http .Error (w , fmt .Sprintf (app .UnableToReadBodyErrFormat , err ), http .StatusBadRequest )
132
+ return
133
+ }
134
+
135
+ tSpans , err := spansV2ToThrift (& spans )
136
+ if err != nil {
137
+ http .Error (w , fmt .Sprintf (app .UnableToReadBodyErrFormat , err ), http .StatusBadRequest )
138
+ return
139
+ }
140
+
141
+ if err := aH .saveThriftSpans (tSpans ); err != nil {
142
+ http .Error (w , fmt .Sprintf ("Cannot submit Zipkin batch: %v" , err ), http .StatusInternalServerError )
143
+ return
144
+ }
145
+
146
+ w .WriteHeader (operations .PostSpansAcceptedCode )
147
+ }
148
+
149
+ func gunzip (r io.ReadCloser ) (* gzip.Reader , error ) {
150
+ gz , err := gzip .NewReader (r )
151
+ if err != nil {
152
+ return nil , err
153
+ }
154
+ defer gz .Close ()
155
+ return gz , nil
156
+ }
157
+
158
+ func (aH * APIHandler ) saveThriftSpans (tSpans []* zipkincore.Span ) error {
159
+ if len (tSpans ) > 0 {
160
+ ctx , _ := tchanThrift .NewContext (time .Minute )
161
+ if _ , err := aH .zipkinSpansHandler .SubmitZipkinBatch (ctx , tSpans ); err != nil {
162
+ return err
163
+ }
164
+ }
165
+ return nil
96
166
}
97
167
98
168
func deserializeThrift (b []byte ) ([]* zipkincore.Span , error ) {
0 commit comments