|
31 | 31 | (let [tx-details (es-find-first-document (str "(processor.event:transaction%20AND%20transaction.id:" @transaction-id ")"))]
|
32 | 32 | (is (= "TestTransaction" (get-in tx-details [:transaction :name])))
|
33 | 33 | (is (= "1" (get-in tx-details [:labels :t1])))
|
34 |
| - (is (= 2 (get-in tx-details [:labels :t2]))) |
35 |
| - (is (true? (get-in tx-details [:labels :t3]))) |
| 34 | + (is (= "2" (get-in tx-details [:labels :t2]))) |
| 35 | + (is (= "true" (get-in tx-details [:labels :t3]))) |
36 | 36 | (is (= "Label 4" (get-in tx-details [:labels :t4])))
|
37 | 37 | (is (= "test-result" (get-in tx-details [:transaction :result])))
|
38 | 38 | (is (= "success" (get-in tx-details [:event :outcome]))))))
|
|
159 | 159 | (-> doc
|
160 | 160 | (select-keys [:span])
|
161 | 161 | (update :span (fn [span] (select-keys span [:name :type])))))))))
|
| 162 | + |
| 163 | +(defn trace-context |
| 164 | + "Given an APM span, return the trace context[1] HTTP headers of the span. |
| 165 | +
|
| 166 | + [1]: https://www.w3.org/TR/trace-context/" |
| 167 | + [span] |
| 168 | + (let [headers (transient {})] |
| 169 | + (.injectTraceHeaders span |
| 170 | + (reify co.elastic.apm.api.HeaderInjector |
| 171 | + (addHeader [_ name value] |
| 172 | + (assoc! headers name value)))) |
| 173 | + (persistent! headers))) |
| 174 | + |
| 175 | +(def ^:private traceparent-regex |
| 176 | + "https://www.w3.org/TR/trace-context/#traceparent-header" |
| 177 | + #"^([0-9a-fA-F]{2})-([0-9a-fA-F]{32})-([0-9a-fA-F]{16})-([0-9a-fA-F]{2})$") |
| 178 | + |
| 179 | +(def ^:private tracestate-regex |
| 180 | + "https://www.w3.org/TR/trace-context/#tracestate-header" |
| 181 | + #"^[!-~]+(,[!-~]+=[!-~]+)*$") |
| 182 | + |
| 183 | +(defn parse-traceparent-header |
| 184 | + "Given a traceparent header, parse the header value into its constituents." |
| 185 | + [traceparent] |
| 186 | + (zipmap [:version :trace-id :parent-id :trace-flags] |
| 187 | + (rest (re-matches traceparent-regex traceparent)))) |
| 188 | + |
| 189 | +(defn fields-except |
| 190 | + "Given a traceparent header, return a map of its constituents, except fields." |
| 191 | + [traceparent & fields] |
| 192 | + (-> (parse-traceparent-header traceparent) |
| 193 | + (apply dissoc fields))) |
| 194 | + |
| 195 | +(deftest trace-context-test |
| 196 | + (testing "no opts" |
| 197 | + (let [tx (apm/start-transaction) |
| 198 | + {:strs [traceparent tracestate]} (trace-context tx)] |
| 199 | + ;; APM adds new trace context headers. |
| 200 | + (is (re-matches traceparent-regex traceparent)) |
| 201 | + (is (re-matches tracestate-regex tracestate)))) |
| 202 | + |
| 203 | + (testing ":headers -- empty & nil" |
| 204 | + (let [tx (apm/start-transaction {:headers {}}) |
| 205 | + {:strs [traceparent tracestate]} (trace-context tx)] |
| 206 | + (is (re-matches traceparent-regex traceparent)) |
| 207 | + (is (re-matches tracestate-regex tracestate))) |
| 208 | + |
| 209 | + (let [tx (apm/start-transaction {:headers nil}) |
| 210 | + {:strs [traceparent tracestate]} (trace-context tx)] |
| 211 | + (is (re-matches traceparent-regex traceparent)) |
| 212 | + (is (re-matches tracestate-regex tracestate)))) |
| 213 | + |
| 214 | + (testing ":headers -- traceparent only" |
| 215 | + (let [inbound-traceparent "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01" |
| 216 | + tx (apm/start-transaction {:headers {"traceparent" inbound-traceparent}}) |
| 217 | + {:strs [traceparent]} (trace-context tx)] |
| 218 | + (is (= (fields-except inbound-traceparent :parent-id) |
| 219 | + (fields-except traceparent :parent-id))))) |
| 220 | + |
| 221 | + (testing ":headers -- traceparent & tracestate" |
| 222 | + (let [inbound-traceparent "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01" |
| 223 | + inbound-tracestate "es=s:0.25" |
| 224 | + tx (apm/start-transaction {:headers {"traceparent" inbound-traceparent |
| 225 | + "tracestate" inbound-tracestate}}) |
| 226 | + {:strs [traceparent tracestate]} (trace-context tx)] |
| 227 | + (is (= (fields-except inbound-traceparent :parent-id) |
| 228 | + (fields-except traceparent :parent-id))) |
| 229 | + (is (= inbound-tracestate tracestate)))) |
| 230 | + |
| 231 | + (testing ":headers -- multi-value tracestate" |
| 232 | + (let [inbound-traceparent "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01" |
| 233 | + inbound-tracestate "es=s:0.5,rojo=00f067aa0ba902b7" |
| 234 | + tx (apm/start-transaction {:headers {"traceparent" inbound-traceparent |
| 235 | + "tracestate" inbound-tracestate}}) |
| 236 | + {:strs [tracestate]} (trace-context tx)] |
| 237 | + (is (= inbound-tracestate tracestate)))) |
| 238 | + |
| 239 | + (testing ":traceparent (backwards compatibility only, do not use)" |
| 240 | + (let [inbound-traceparent "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01" |
| 241 | + tx (apm/start-transaction {:traceparent inbound-traceparent}) |
| 242 | + {:strs [traceparent tracestate]} (trace-context tx)] |
| 243 | + (is (= (fields-except inbound-traceparent :parent-id) |
| 244 | + (fields-except traceparent :parent-id))) |
| 245 | + |
| 246 | + ;; Using the :traceparent option incorrectly sets the value of every |
| 247 | + ;; trace context header -- including tracestate -- to the value of the |
| 248 | + ;; traceparent header. Do not use it. |
| 249 | + (is (= inbound-traceparent tracestate))))) |
0 commit comments