1
1
import { randomBytes } from "crypto" ;
2
2
import { logDebug } from "../utils" ;
3
3
import { SampleMode , TraceContext , TraceSource } from "./trace-context-service" ;
4
- import BigNumber from "bignumber.js" ;
5
4
import { Socket , createSocket } from "dgram" ;
6
5
import { SpanContextWrapper } from "./span-context-wrapper" ;
7
6
import { StepFunctionContext } from "./step-function-service" ;
7
+ import {
8
+ DATADOG_TRACE_ID_HEADER ,
9
+ DATADOG_PARENT_ID_HEADER ,
10
+ DATADOG_SAMPLING_PRIORITY_HEADER ,
11
+ DatadogTraceHeaders ,
12
+ } from "./context/extractor" ;
8
13
9
14
const AMZN_TRACE_ID_ENV_VAR = "_X_AMZN_TRACE_ID" ;
10
15
const AWS_XRAY_DAEMON_ADDRESS_ENV_VAR = "AWS_XRAY_DAEMON_ADDRESS" ;
@@ -70,16 +75,9 @@ export class XrayService {
70
75
} ) ;
71
76
}
72
77
73
- private parseTraceContextHeader ( ) : XrayTraceHeader | undefined {
74
- const header = process . env [ AMZN_TRACE_ID_ENV_VAR ] ;
75
- if ( header === undefined ) {
76
- logDebug ( "Couldn't read Xray trace header from env" ) ;
77
- return ;
78
- }
79
-
80
- // Example: Root=1-5e272390-8c398be037738dc042009320;Parent=94ae789b969f1cc5;Sampled=1
81
- logDebug ( `Reading Xray trace context from env var ${ header } ` ) ;
82
- const [ root , parent , _sampled ] = header . split ( ";" ) ;
78
+ // Example: Root=1-5e272390-8c398be037738dc042009320;Parent=94ae789b969f1cc5;Sampled=1
79
+ public static parseAWSTraceHeader ( awsTraceHeader : string ) : XrayTraceHeader | undefined {
80
+ const [ root , parent , _sampled ] = awsTraceHeader . split ( ";" ) ;
83
81
if ( parent === undefined || _sampled === undefined ) return ;
84
82
85
83
const [ , traceId ] = root . split ( "=" ) ;
@@ -94,6 +92,18 @@ export class XrayService {
94
92
} ;
95
93
}
96
94
95
+ private parseTraceContextHeader ( ) : XrayTraceHeader | undefined {
96
+ const header = process . env [ AMZN_TRACE_ID_ENV_VAR ] ;
97
+ if ( header === undefined ) {
98
+ logDebug ( "Couldn't read Xray trace header from env" ) ;
99
+ return ;
100
+ }
101
+
102
+ // Example: Root=1-5e272390-8c398be037738dc042009320;Parent=94ae789b969f1cc5;Sampled=1
103
+ logDebug ( `Reading Xray trace context from env var ${ header } ` ) ;
104
+ return XrayService . parseAWSTraceHeader ( header ) ;
105
+ }
106
+
97
107
private convertToSampleMode ( xraySampled : number ) : SampleMode {
98
108
return xraySampled === 1 ? SampleMode . USER_KEEP : SampleMode . USER_REJECT ;
99
109
}
@@ -172,11 +182,12 @@ export class XrayService {
172
182
173
183
private convertToParentId ( xrayParentId : string ) : string | undefined {
174
184
if ( xrayParentId . length !== 16 ) return ;
175
-
176
- const hex = new BigNumber ( xrayParentId , 16 ) ;
177
- if ( hex . isNaN ( ) ) return ;
178
-
179
- return hex . toString ( 10 ) ;
185
+ try {
186
+ return BigInt ( "0x" + xrayParentId ) . toString ( 10 ) ;
187
+ } catch ( _ ) {
188
+ logDebug ( `Faied to convert xray parent id ${ xrayParentId } ` ) ;
189
+ return undefined ;
190
+ }
180
191
}
181
192
182
193
private convertToTraceId ( xrayTraceId : string ) : string | undefined {
@@ -187,13 +198,30 @@ export class XrayService {
187
198
if ( lastPart . length !== 24 ) return ;
188
199
189
200
// We want to turn the last 63 bits into a decimal number in a string representation
190
- // Unfortunately, all numbers in javascript are represented by float64 bit numbers, which
191
- // means we can't parse 64 bit integers accurately.
192
- const hex = new BigNumber ( lastPart , 16 ) ;
193
- if ( hex . isNaN ( ) ) return ;
194
-
195
- // Toggle off the 64th bit
196
- const last63Bits = hex . mod ( new BigNumber ( "8000000000000000" , 16 ) ) ;
197
- return last63Bits . toString ( 10 ) ;
201
+ try {
202
+ return ( BigInt ( "0x" + lastPart ) % BigInt ( "0x8000000000000000" ) ) . toString ( 10 ) ; // mod by 2^63 will leave us with the last 63 bits
203
+ } catch ( _ ) {
204
+ logDebug ( `Faied to convert trace id ${ lastPart } ` ) ;
205
+ return undefined ;
206
+ }
207
+ }
208
+
209
+ public static extraceDDContextFromAWSTraceHeader ( amznTraceId : string ) : DatadogTraceHeaders | null {
210
+ const awsContext = XrayService . parseAWSTraceHeader ( amznTraceId ) ;
211
+ if ( ! awsContext ) {
212
+ return null ;
213
+ }
214
+ const traceIdParts = awsContext . traceId . split ( "-" ) ;
215
+ if ( traceIdParts && traceIdParts . length > 2 && traceIdParts [ 2 ] . startsWith ( "00000000" ) ) {
216
+ // This AWSTraceHeader contains Datadog injected trace context
217
+ return {
218
+ [ DATADOG_TRACE_ID_HEADER ] : hexStrToDecimalStr ( traceIdParts [ 2 ] . substring ( 8 ) ) ,
219
+ [ DATADOG_PARENT_ID_HEADER ] : hexStrToDecimalStr ( awsContext . parentId ) ,
220
+ [ DATADOG_SAMPLING_PRIORITY_HEADER ] : awsContext . sampled ,
221
+ } ;
222
+ }
223
+ return null ;
198
224
}
199
225
}
226
+
227
+ const hexStrToDecimalStr = ( hexString : string ) : string => BigInt ( "0x" + hexString ) . toString ( 10 ) ;
0 commit comments