11import { randomBytes } from "crypto" ;
22import { logDebug } from "../utils" ;
33import { SampleMode , TraceContext , TraceSource } from "./trace-context-service" ;
4- import BigNumber from "bignumber.js" ;
54import { Socket , createSocket } from "dgram" ;
65import { SpanContextWrapper } from "./span-context-wrapper" ;
76import { 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" ;
813
914const AMZN_TRACE_ID_ENV_VAR = "_X_AMZN_TRACE_ID" ;
1015const AWS_XRAY_DAEMON_ADDRESS_ENV_VAR = "AWS_XRAY_DAEMON_ADDRESS" ;
@@ -70,16 +75,9 @@ export class XrayService {
7075 } ) ;
7176 }
7277
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 ( ";" ) ;
8381 if ( parent === undefined || _sampled === undefined ) return ;
8482
8583 const [ , traceId ] = root . split ( "=" ) ;
@@ -94,6 +92,18 @@ export class XrayService {
9492 } ;
9593 }
9694
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+
97107 private convertToSampleMode ( xraySampled : number ) : SampleMode {
98108 return xraySampled === 1 ? SampleMode . USER_KEEP : SampleMode . USER_REJECT ;
99109 }
@@ -172,11 +182,12 @@ export class XrayService {
172182
173183 private convertToParentId ( xrayParentId : string ) : string | undefined {
174184 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+ }
180191 }
181192
182193 private convertToTraceId ( xrayTraceId : string ) : string | undefined {
@@ -187,13 +198,30 @@ export class XrayService {
187198 if ( lastPart . length !== 24 ) return ;
188199
189200 // 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 ;
198224 }
199225}
226+
227+ const hexStrToDecimalStr = ( hexString : string ) : string => BigInt ( "0x" + hexString ) . toString ( 10 ) ;
0 commit comments