Skip to content

Commit dcdba0e

Browse files
committed
Collect Zipkin v2 json
Signed-off-by: Pavol Loffay <ploffay@redhat.com>
1 parent 2b73fe9 commit dcdba0e

20 files changed

+1697
-14
lines changed

.gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@
44
[submodule "jaeger-ui"]
55
path = jaeger-ui
66
url = https://github.com/uber/jaeger-ui
7+
[submodule "zipkin-api"]
8+
path = zipkin-api
9+
url = git@github.com:openzipkin/zipkin-api.git

Makefile

+11-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ PROJECT_ROOT=github.com/uber/jaeger
22
TOP_PKGS := $(shell glide novendor | grep -v -e ./thrift-gen/... -e ./examples/... -e ./scripts/...)
33

44
# all .go files that don't exist in hidden directories
5-
ALL_SRC := $(shell find . -name "*.go" | grep -v -e vendor -e thrift-gen \
5+
ALL_SRC := $(shell find . -name "*.go" | grep -v -e vendor -e thrift-gen -e swagger-gen \
66
-e ".*/\..*" \
77
-e ".*/_.*" \
88
-e ".*/mocks.*")
@@ -28,6 +28,11 @@ THRIFT_GO_ARGS=thrift_import="github.com/apache/thrift/lib/go/thrift"
2828
THRIFT_GEN=$(shell which thrift-gen)
2929
THRIFT_GEN_DIR=thrift-gen
3030

31+
SWAGGER_IMG_VER=0.12.0
32+
SWAGGER_IMAGE=quay.io/goswagger/swagger:$(SWAGGER_IMG_VER)
33+
SWAGGER=docker run --rm -it -u ${shell id -u} -v "${PWD}:/go/src/${PROJECT_ROOT}" -w /go/src/${PROJECT_ROOT} $(SWAGGER_IMAGE)
34+
SWAGGER_GEN_DIR=swagger-gen
35+
3136
PASS=$(shell printf "\033[32mPASS\033[0m")
3237
FAIL=$(shell printf "\033[31mFAIL\033[0m")
3338
COLORIZE=$(SED) ''/PASS/s//$(PASS)/'' | $(SED) ''/FAIL/s//$(FAIL)/''
@@ -209,6 +214,11 @@ idl-submodule:
209214
git submodule init
210215
git submodule update
211216

217+
.PHONY: generate-zipkin-swagger
218+
generate-zipkin-swagger:
219+
$(SWAGGER) generate server -f ./zipkin-api/zipkin2-api.yaml -t $(SWAGGER_GEN_DIR) -O PostSpans --exclude-main
220+
rm $(SWAGGER_GEN_DIR)/restapi/operations/post_spans_urlbuilder.go $(SWAGGER_GEN_DIR)/restapi/server.go $(SWAGGER_GEN_DIR)/restapi/configure_zipkin.go $(SWAGGER_GEN_DIR)/models/trace.go $(SWAGGER_GEN_DIR)/models/list_of_traces.go $(SWAGGER_GEN_DIR)/models/dependency_link.go
221+
212222
.PHONY: thrift-image
213223
thrift-image:
214224
$(THRIFT) -version

cmd/collector/app/zipkin/http_handler.go

+61-7
Original file line numberDiff line numberDiff line change
@@ -23,30 +23,43 @@ import (
2323
"time"
2424

2525
"github.com/apache/thrift/lib/go/thrift"
26+
"github.com/go-openapi/loads"
27+
"github.com/go-openapi/swag"
2628
"github.com/gorilla/mux"
29+
"github.com/pkg/errors"
2730
tchanThrift "github.com/uber/tchannel-go/thrift"
2831

2932
"github.com/uber/jaeger/cmd/collector/app"
33+
"github.com/uber/jaeger/swagger-gen/models"
34+
"github.com/uber/jaeger/swagger-gen/restapi"
35+
"github.com/uber/jaeger/swagger-gen/restapi/operations"
3036
"github.com/uber/jaeger/thrift-gen/zipkincore"
3137
)
3238

3339
// APIHandler handles all HTTP calls to the collector
3440
type APIHandler struct {
3541
zipkinSpansHandler app.ZipkinSpansHandler
42+
zipkinV2API *operations.ZipkinAPI
3643
}
3744

3845
// NewAPIHandler returns a new APIHandler
3946
func NewAPIHandler(
4047
zipkinSpansHandler app.ZipkinSpansHandler,
41-
) *APIHandler {
48+
) (*APIHandler, error) {
49+
swaggerSpec, err := loads.Analyzed(restapi.SwaggerJSON, "")
50+
if err != nil {
51+
return nil, errors.Wrapf(err, "Failed to create zipkin swagger")
52+
}
4253
return &APIHandler{
4354
zipkinSpansHandler: zipkinSpansHandler,
44-
}
55+
zipkinV2API: operations.NewZipkinAPI(swaggerSpec),
56+
}, nil
4557
}
4658

4759
// RegisterRoutes registers Zipkin routes
4860
func (aH *APIHandler) RegisterRoutes(router *mux.Router) {
4961
router.HandleFunc("/api/v1/spans", aH.saveSpans).Methods(http.MethodPost)
62+
router.HandleFunc("/api/v2/spans", aH.saveSpansV2).Methods(http.MethodPost)
5063
}
5164

5265
func (aH *APIHandler) saveSpans(w http.ResponseWriter, r *http.Request) {
@@ -84,15 +97,56 @@ func (aH *APIHandler) saveSpans(w http.ResponseWriter, r *http.Request) {
8497
return
8598
}
8699

100+
if err := aH.saveThriftSpans(tSpans); err != nil {
101+
http.Error(w, fmt.Sprintf("Cannot submit Zipkin batch: %v", err), http.StatusInternalServerError)
102+
return
103+
}
104+
105+
w.WriteHeader(http.StatusAccepted)
106+
}
107+
108+
func (aH *APIHandler) saveSpansV2(w http.ResponseWriter, r *http.Request) {
109+
bRead := r.Body
110+
defer r.Body.Close()
111+
112+
bodyBytes, err := ioutil.ReadAll(bRead)
113+
if err != nil {
114+
http.Error(w, fmt.Sprintf(app.UnableToReadBodyErrFormat, err), http.StatusInternalServerError)
115+
return
116+
}
117+
118+
var spans *models.ListOfSpans = &models.ListOfSpans{}
119+
if err = swag.ReadJSON(bodyBytes, spans); err != nil {
120+
http.Error(w, fmt.Sprintf(app.UnableToReadBodyErrFormat, err), http.StatusBadRequest)
121+
return
122+
}
123+
if err = spans.Validate(aH.zipkinV2API.Formats()); err != nil {
124+
http.Error(w, fmt.Sprintf(app.UnableToReadBodyErrFormat, err), http.StatusBadRequest)
125+
return
126+
}
127+
128+
tSpans, err := spansV2ToThrift(spans)
129+
if err != nil {
130+
http.Error(w, fmt.Sprintf(app.UnableToReadBodyErrFormat, err), http.StatusBadRequest)
131+
return
132+
}
133+
134+
if err := aH.saveThriftSpans(tSpans); err != nil {
135+
http.Error(w, fmt.Sprintf("Cannot submit Zipkin batch: %v", err), http.StatusInternalServerError)
136+
return
137+
}
138+
139+
w.WriteHeader(operations.PostSpansAcceptedCode)
140+
}
141+
142+
func (aH *APIHandler) saveThriftSpans(tSpans []*zipkincore.Span) error {
87143
if len(tSpans) > 0 {
88144
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)
91-
return
145+
if _, err := aH.zipkinSpansHandler.SubmitZipkinBatch(ctx, tSpans); err != nil {
146+
return err
92147
}
93148
}
94-
95-
w.WriteHeader(http.StatusAccepted)
149+
return nil
96150
}
97151

98152
func deserializeThrift(b []byte) ([]*zipkincore.Span, error) {

cmd/collector/app/zipkin/http_handler_test.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func (p *mockZipkinHandler) getSpans() []*zipkincore.Span {
5959

6060
func initializeTestServer(err error) (*httptest.Server, *APIHandler) {
6161
r := mux.NewRouter()
62-
handler := NewAPIHandler(&mockZipkinHandler{err: err})
62+
handler, _ := NewAPIHandler(&mockZipkinHandler{err: err})
6363
handler.RegisterRoutes(r)
6464
return httptest.NewServer(r), handler
6565
}
@@ -224,7 +224,8 @@ func TestDeserializeWithBadListStart(t *testing.T) {
224224
}
225225

226226
func TestCannotReadBodyFromRequest(t *testing.T) {
227-
handler := NewAPIHandler(&mockZipkinHandler{})
227+
handler, err := NewAPIHandler(&mockZipkinHandler{})
228+
require.NoError(t, err)
228229
req, err := http.NewRequest(http.MethodPost, "whatever", &errReader{})
229230
assert.NoError(t, err)
230231
rw := dummyResponseWriter{}

cmd/collector/app/zipkin/jsonv2.go

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// Copyright (c) 2017 The Jaeger Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package zipkin
16+
17+
import (
18+
"github.com/uber/jaeger/model"
19+
"github.com/uber/jaeger/swagger-gen/models"
20+
"github.com/uber/jaeger/thrift-gen/zipkincore"
21+
)
22+
23+
func spansV2ToThrift(spans *models.ListOfSpans) ([]*zipkincore.Span, error) {
24+
var tSpans []*zipkincore.Span
25+
for _, span := range *spans {
26+
tSpan, err := spanV2ToThrift(*span)
27+
if err != nil {
28+
return nil, err
29+
}
30+
tSpans = append(tSpans, tSpan)
31+
}
32+
return tSpans, nil
33+
34+
return nil, nil
35+
}
36+
37+
func spanV2ToThrift(s models.Span) (*zipkincore.Span, error) {
38+
id, err := model.SpanIDFromString(cutLongID(*s.ID))
39+
if err != nil {
40+
return nil, err
41+
}
42+
traceID, err := model.TraceIDFromString(*s.TraceID)
43+
if err != nil {
44+
return nil, err
45+
}
46+
47+
tSpan := &zipkincore.Span{
48+
ID: int64(id),
49+
TraceID: int64(traceID.Low),
50+
Name: s.Name,
51+
Debug: s.Debug,
52+
Timestamp: &s.Timestamp,
53+
Duration: &s.Duration,
54+
}
55+
56+
if len(s.ParentID) > 0 {
57+
parentID, err := model.SpanIDFromString(cutLongID(s.ParentID))
58+
if err != nil {
59+
return nil, err
60+
}
61+
signed := int64(parentID)
62+
tSpan.ParentID = &signed
63+
}
64+
65+
for _, a := range s.Annotations {
66+
tA, err := annToThrift(a)
67+
if err != nil {
68+
return nil, err
69+
}
70+
tSpan.Annotations = append(tSpan.Annotations, tA)
71+
}
72+
73+
for k, v := range s.Tags {
74+
ba := &zipkincore.BinaryAnnotation{
75+
Key: k,
76+
Value: []byte(v),
77+
AnnotationType: zipkincore.AnnotationType_STRING,
78+
// TODO endpoint
79+
}
80+
tSpan.BinaryAnnotations = append(tSpan.BinaryAnnotations, ba)
81+
}
82+
83+
// TODO
84+
//s.Kind
85+
//s.LocalEndpoint
86+
//s.RemoteEndpoint
87+
88+
return tSpan, nil
89+
}
90+
91+
func annToThrift(a *models.Annotation) (*zipkincore.Annotation, error) {
92+
ta := &zipkincore.Annotation{
93+
Value: a.Value,
94+
Timestamp: a.Timestamp,
95+
// TODO host - endpoint
96+
}
97+
98+
return ta, nil
99+
}

cmd/collector/main.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,13 @@ func startZipkinHTTPAPI(
151151
recoveryHandler func(http.Handler) http.Handler,
152152
) {
153153
if zipkinPort != 0 {
154+
zHandler, err := zipkin.NewAPIHandler(zipkinSpansHandler)
155+
if err != nil {
156+
logger.Fatal("Failed to initialize Zipkin handler", zap.Error(err))
157+
}
154158
r := mux.NewRouter()
155-
zipkin.NewAPIHandler(zipkinSpansHandler).RegisterRoutes(r)
159+
zHandler.RegisterRoutes(r)
160+
156161
httpPortStr := ":" + strconv.Itoa(zipkinPort)
157162
logger.Info("Listening for Zipkin HTTP traffic", zap.Int("zipkin.http-port", zipkinPort))
158163

crossdock/docker-compose.yml

+13-2
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,17 @@ services:
1010
- java
1111
- python
1212
- zipkin-brave-json
13+
- zipkin-brave-json-v2
1314
- zipkin-brave-thrift
1415

1516
environment:
16-
- WAIT_FOR=test_driver,go,node,java,python,zipkin-brave-thrift,zipkin-brave-json
17+
- WAIT_FOR=test_driver,go,node,java,python,zipkin-brave-thrift,zipkin-brave-json,zipkin-brave-json-v2
1718
- WAIT_FOR_TIMEOUT=60s
1819

1920
- CALL_TIMEOUT=60s
2021

2122
- AXIS_CLIENT=test_driver
22-
- AXIS_SERVICES=go,node,java,python,zipkin-brave-json,zipkin-brave-thrift
23+
- AXIS_SERVICES=go,node,java,python,zipkin-brave-json,zipkin-brave-json-v2,zipkin-brave-thrift
2324

2425
- BEHAVIOR_ENDTOEND=client,services
2526

@@ -37,6 +38,8 @@ services:
3738
image: jaegertracing/xdock-java
3839
ports:
3940
- "8080-8082"
41+
depends_on:
42+
- jaeger-agent
4043

4144
python:
4245
image: jaegertracing/xdock-py
@@ -50,6 +53,14 @@ services:
5053
environment:
5154
- ENCODING=JSON
5255

56+
zipkin-brave-json-v2:
57+
image: jaegertracing/xdock-zipkin-brave
58+
ports:
59+
- "8080-8081"
60+
environment:
61+
- ENCODING=JSON
62+
- JSON_ENCODER=JSON_V2
63+
5364
zipkin-brave-thrift:
5465
image: jaegertracing/xdock-zipkin-brave
5566
ports:

scripts/updateLicenses.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22

33
set -e
44

5-
python scripts/updateLicense.py $(git ls-files "*\.go" | grep -v -e thrift-gen)
5+
python scripts/updateLicense.py $(git ls-files "*\.go" | grep -v -e thrift-gen -e swagger-gen)

0 commit comments

Comments
 (0)