@@ -18,16 +18,17 @@ function toV1Endpoint(endpoint) {
18
18
}
19
19
20
20
function toV1Annotation ( ann , endpoint ) {
21
- return {
21
+ const res = {
22
22
value : ann . value ,
23
23
timestamp : ann . timestamp ,
24
- endpoint
25
24
} ;
25
+ if ( endpoint ) {
26
+ res . endpoint = endpoint ;
27
+ }
28
+ return res ;
26
29
}
27
30
28
- // Copied from https://github.com/openzipkin/zipkin-js/blob/8018e441d01804b02d0d217f10cd82759e71e02a/packages/zipkin/src/jsonEncoder.js#L25
29
- // Modified to correct assumption that 'annotations' always exist and ensure
30
- // that 'beginAnnotation' comes first timestamp/duration should always be copied over
31
+ // ported from zipkin2.v1.V1SpanConverter
31
32
function convertV1 ( span ) {
32
33
const res = {
33
34
traceId : span . traceId ,
@@ -37,65 +38,137 @@ function convertV1(span) {
37
38
}
38
39
res . id = span . id ;
39
40
res . name = span . name || '' ; // undefined is not allowed in v1
41
+ if ( span . debug ) {
42
+ res . debug = true ;
43
+ }
44
+
45
+ // Don't report timestamp and duration on shared spans (should be server, but not necessarily)
40
46
if ( ! span . shared ) {
41
47
if ( span . timestamp ) res . timestamp = span . timestamp ;
42
48
if ( span . duration ) res . duration = span . duration ;
43
49
}
44
50
45
- const jsonEndpoint = toV1Endpoint ( span . localEndpoint ) ;
51
+ let startTs = span . timestamp || 0 ;
52
+ let endTs = startTs && span . duration ? startTs + span . duration : 0 ;
53
+ let msTs = 0 ;
54
+ let wsTs = 0 ;
55
+ let wrTs = 0 ;
56
+ let mrTs = 0 ;
57
+
58
+ let begin ;
59
+ let end ;
60
+
61
+ let kind = span . kind ;
46
62
47
- let beginAnnotation ;
48
- let endAnnotation ;
49
- let addressKey ;
50
- let local ;
51
- switch ( span . kind ) {
63
+ // scan annotations in case there are better timestamps, or inferred kind
64
+ ( span . annotations || [ ] ) . forEach ( ( a ) => {
65
+ switch ( a . value ) {
66
+ case 'cs' :
67
+ kind = 'CLIENT' ;
68
+ if ( a . timestamp < startTs ) startTs = a . timestamp ;
69
+ break ;
70
+ case 'sr' :
71
+ kind = 'SERVER' ;
72
+ if ( a . timestamp < startTs ) startTs = a . timestamp ;
73
+ break ;
74
+ case 'ss' :
75
+ kind = 'SERVER' ;
76
+ if ( a . timestamp > endTs ) endTs = a . timestamp ;
77
+ break ;
78
+ case 'cr' :
79
+ kind = 'CLIENT' ;
80
+ if ( a . timestamp > endTs ) endTs = a . timestamp ;
81
+ break ;
82
+ case 'ms' :
83
+ kind = 'PRODUCER' ;
84
+ msTs = a . timestamp ;
85
+ break ;
86
+ case 'mr' :
87
+ kind = 'CONSUMER' ;
88
+ mrTs = a . timestamp ;
89
+ break ;
90
+ case 'ws' :
91
+ wsTs = a . timestamp ;
92
+ break ;
93
+ case 'wr' :
94
+ wrTs = a . timestamp ;
95
+ break ;
96
+ default :
97
+ }
98
+ } ) ;
99
+
100
+ let addr = 'sa' ; // default which will be unset later if needed
101
+
102
+ switch ( kind ) {
52
103
case 'CLIENT' :
53
- beginAnnotation = span . timestamp ? 'cs' : undefined ;
54
- endAnnotation = 'cr ' ;
55
- addressKey = 'sa ' ;
104
+ addr = 'sa' ;
105
+ begin = 'cs ' ;
106
+ end = 'cr ' ;
56
107
break ;
57
108
case 'SERVER' :
58
- beginAnnotation = span . timestamp ? 'sr' : undefined ;
59
- endAnnotation = 'ss ' ;
60
- addressKey = 'ca ' ;
109
+ addr = 'ca' ;
110
+ begin = 'sr ' ;
111
+ end = 'ss ' ;
61
112
break ;
62
113
case 'PRODUCER' :
63
- beginAnnotation = span . timestamp ? 'ms' : undefined ;
64
- endAnnotation = 'ws' ;
65
- addressKey = 'ma' ;
114
+ addr = 'ma' ;
115
+ begin = 'ms' ;
116
+ end = 'ws' ;
117
+ if ( startTs === 0 || ( msTs !== 0 && msTs < startTs ) ) {
118
+ startTs = msTs ;
119
+ }
120
+ if ( endTs === 0 || ( wsTs !== 0 && wsTs > endTs ) ) {
121
+ endTs = wsTs ;
122
+ }
66
123
break ;
67
124
case 'CONSUMER' :
68
- if ( span . timestamp && span . duration ) {
69
- beginAnnotation = 'wr' ;
70
- endAnnotation = 'mr' ;
71
- } else if ( span . timestamp ) {
72
- beginAnnotation = 'mr' ;
125
+ addr = 'ma' ;
126
+ if ( startTs === 0 || ( wrTs !== 0 && wrTs < startTs ) ) {
127
+ startTs = wrTs ;
128
+ }
129
+ if ( endTs === 0 || ( mrTs !== 0 && mrTs > endTs ) ) {
130
+ endTs = mrTs ;
131
+ }
132
+ if ( endTs !== 0 || wrTs !== 0 ) {
133
+ begin = 'wr' ;
134
+ end = 'mr' ;
135
+ } else {
136
+ begin = 'mr' ;
73
137
}
74
- addressKey = 'ma' ;
75
138
break ;
76
139
default :
77
- local = true ;
78
140
}
79
141
142
+ // If we didn't find a span kind, directly or indirectly, unset the addr
143
+ if ( ! span . remoteEndpoint ) addr = undefined ;
144
+
145
+ const beginAnnotation = startTs && begin ;
146
+ const endAnnotation = endTs && end ;
147
+ const ep = toV1Endpoint ( span . localEndpoint ) ;
148
+
80
149
res . annotations = [ ] ; // prefer empty to undefined for arrays
150
+
151
+ let annotationCount = ( span . annotations || [ ] ) . length ;
81
152
if ( beginAnnotation ) {
82
- res . annotations . push ( {
83
- value : beginAnnotation ,
84
- timestamp : span . timestamp ,
85
- endpoint : jsonEndpoint
86
- } ) ;
153
+ annotationCount ++ ;
154
+ res . annotations . push ( toV1Annotation ( {
155
+ value : begin ,
156
+ timestamp : startTs
157
+ } , ep ) ) ;
87
158
}
88
159
89
- ( span . annotations || [ ] ) . forEach ( ( ann ) =>
90
- res . annotations . push ( toV1Annotation ( ann , jsonEndpoint ) )
91
- ) ;
160
+ ( span . annotations || [ ] ) . forEach ( ( a ) => {
161
+ if ( beginAnnotation && a . value === begin ) return ;
162
+ if ( endAnnotation && a . value === end ) return ;
163
+ res . annotations . push ( toV1Annotation ( a , ep ) ) ;
164
+ } ) ;
92
165
93
- if ( beginAnnotation && span . duration ) {
94
- res . annotations . push ( {
95
- value : endAnnotation ,
96
- timestamp : span . timestamp + span . duration ,
97
- endpoint : jsonEndpoint
98
- } ) ;
166
+ if ( endAnnotation ) {
167
+ annotationCount ++ ;
168
+ res . annotations . push ( toV1Annotation ( {
169
+ value : end ,
170
+ timestamp : endTs
171
+ } , ep ) ) ;
99
172
}
100
173
101
174
res . binaryAnnotations = [ ] ; // prefer empty to undefined for arrays
@@ -104,27 +177,26 @@ function convertV1(span) {
104
177
res . binaryAnnotations = keys . map ( key => ( {
105
178
key,
106
179
value : span . tags [ key ] ,
107
- endpoint : jsonEndpoint
180
+ endpoint : ep
108
181
} ) ) ;
109
182
}
110
183
111
- // worst case, make a dummy local component annotation, so the span can be looked up
112
- if ( res . annotations . length === 0 && res . binaryAnnotations . length === 0 && local ) {
113
- res . binaryAnnotations . push ( { key : 'lc' , value : '' , endpoint : jsonEndpoint } ) ;
114
- }
184
+ const writeLocalComponent = annotationCount === 0 && ep && keys . length === 0 ;
185
+ const hasRemoteEndpoint = addr && span . remoteEndpoint ;
115
186
116
- if ( span . remoteEndpoint ) {
187
+ // write an empty "lc" annotation to avoid missing the localEndpoint in an in-process span
188
+ if ( writeLocalComponent ) {
189
+ res . binaryAnnotations . push ( { key : 'lc' , value : '' , endpoint : ep } ) ;
190
+ }
191
+ if ( hasRemoteEndpoint ) {
117
192
const address = {
118
- key : addressKey ,
193
+ key : addr ,
119
194
value : true ,
120
195
endpoint : toV1Endpoint ( span . remoteEndpoint )
121
196
} ;
122
197
res . binaryAnnotations . push ( address ) ;
123
198
}
124
199
125
- if ( span . debug ) {
126
- res . debug = true ;
127
- }
128
200
return res ;
129
201
}
130
202
0 commit comments