Skip to content

Commit f36a9b5

Browse files
authored
feat: Add trace id to http events (#447)
1 parent 33892c5 commit f36a9b5

File tree

5 files changed

+188
-13
lines changed

5 files changed

+188
-13
lines changed

src/event-schemas/http-event.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@
99
"type": "string",
1010
"description": "Schema version."
1111
},
12+
"trace_id": {
13+
"type": "string",
14+
"minLength": 35,
15+
"maxLength": 35
16+
},
17+
"segment_id": {
18+
"type": "string",
19+
"minLength": 16,
20+
"maxLength": 16
21+
},
1222
"request": {
1323
"type": "object",
1424
"properties": {

src/plugins/event-plugins/FetchPlugin.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,8 @@ export class FetchPlugin extends MonkeyPatched<Window, 'fetch'> {
274274

275275
if (this.isTracingEnabled() && this.isSessionRecorded()) {
276276
trace = this.beginTrace(input, init, argsArray);
277+
httpEvent.trace_id = trace.trace_id;
278+
httpEvent.segment_id = trace.subsegments![0].id;
277279
}
278280

279281
return original

src/plugins/event-plugins/XhrPlugin.ts

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -243,12 +243,17 @@ export class XhrPlugin extends MonkeyPatched<XMLHttpRequest, 'send' | 'open'> {
243243
xhrDetails: XhrDetails,
244244
xhr: XMLHttpRequest
245245
) {
246+
const httpEvent: HttpEvent = {
247+
version: '1.0.0',
248+
request: { method: xhrDetails.method, url: xhrDetails.url },
249+
response: { status: xhr.status, statusText: xhr.statusText }
250+
};
251+
if (this.isTracingEnabled()) {
252+
httpEvent.trace_id = xhrDetails.trace!.trace_id;
253+
httpEvent.segment_id = xhrDetails.trace!.subsegments![0].id;
254+
}
246255
if (this.config.recordAllRequests || !this.statusOk(xhr.status)) {
247-
this.context.record(HTTP_EVENT_TYPE, {
248-
version: '1.0.0',
249-
request: { method: xhrDetails.method, url: xhrDetails.url },
250-
response: { status: xhr.status, statusText: xhr.statusText }
251-
});
256+
this.context.record(HTTP_EVENT_TYPE, httpEvent);
252257
}
253258
}
254259

@@ -258,15 +263,19 @@ export class XhrPlugin extends MonkeyPatched<XMLHttpRequest, 'send' | 'open'> {
258263
) {
259264
const httpEvent: HttpEvent = {
260265
version: '1.0.0',
261-
request: { method: xhrDetails.method, url: xhrDetails.url }
266+
request: { method: xhrDetails.method, url: xhrDetails.url },
267+
error: errorEventToJsErrorEvent(
268+
{
269+
type: 'error',
270+
error
271+
} as ErrorEvent,
272+
this.config.stackTraceLength
273+
)
262274
};
263-
httpEvent.error = errorEventToJsErrorEvent(
264-
{
265-
type: 'error',
266-
error
267-
} as ErrorEvent,
268-
this.config.stackTraceLength
269-
);
275+
if (this.isTracingEnabled()) {
276+
httpEvent.trace_id = xhrDetails.trace!.trace_id;
277+
httpEvent.segment_id = xhrDetails.trace!.subsegments![0].id;
278+
}
270279
this.context.record(HTTP_EVENT_TYPE, httpEvent);
271280
}
272281

src/plugins/event-plugins/__tests__/FetchPlugin.test.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,4 +884,54 @@ describe('FetchPlugin tests', () => {
884884
}
885885
});
886886
});
887+
888+
test('when tracing is enabled then the trace id is added to the http event', async () => {
889+
// Init
890+
const config: PartialHttpPluginConfig = {
891+
logicalServiceName: 'sample.rum.aws.amazon.com',
892+
urlsToInclude: [/aws\.amazon\.com/],
893+
recordAllRequests: true
894+
};
895+
896+
const plugin: FetchPlugin = new FetchPlugin(config);
897+
plugin.load(xRayOnContext);
898+
899+
// Run
900+
await fetch(URL);
901+
plugin.disable();
902+
903+
// Assert
904+
expect(record).toHaveBeenCalledTimes(2);
905+
expect(record.mock.calls[1][0]).toEqual(HTTP_EVENT_TYPE);
906+
expect(record.mock.calls[1][1]).toMatchObject({
907+
trace_id: '1-0-000000000000000000000000',
908+
segment_id: '0000000000000000'
909+
});
910+
});
911+
912+
test('when tracing is not enabled then the trace id is not added to the http event', async () => {
913+
// Init
914+
const config: PartialHttpPluginConfig = {
915+
logicalServiceName: 'sample.rum.aws.amazon.com',
916+
urlsToInclude: [/aws\.amazon\.com/],
917+
recordAllRequests: true
918+
};
919+
920+
const plugin: FetchPlugin = new FetchPlugin(config);
921+
plugin.load(xRayOffContext);
922+
923+
// Run
924+
await fetch(URL);
925+
plugin.disable();
926+
927+
// Assert
928+
expect(record).toHaveBeenCalledTimes(1);
929+
expect(record.mock.calls[0][0]).toEqual(HTTP_EVENT_TYPE);
930+
expect(record.mock.calls[0][1]).not.toMatchObject({
931+
trace_id: expect.anything()
932+
});
933+
expect(record.mock.calls[0][1]).not.toMatchObject({
934+
segment_id: expect.anything()
935+
});
936+
});
887937
});

src/plugins/event-plugins/__tests__/XhrPlugin.test.ts

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,4 +803,108 @@ describe('XhrPlugin tests', () => {
803803
]
804804
});
805805
});
806+
807+
test('when the plugin records a trace then the trace id is added to the http event', async () => {
808+
// Init
809+
const config: PartialHttpPluginConfig = {
810+
logicalServiceName: 'sample.rum.aws.amazon.com',
811+
urlsToInclude: [/response\.json/],
812+
recordAllRequests: true
813+
};
814+
815+
mock.get(/.*/, {
816+
body: JSON.stringify({ message: 'Hello World!' }),
817+
headers: { 'Content-Length': '125' } as MockHeaders
818+
});
819+
820+
const plugin: XhrPlugin = new XhrPlugin(config);
821+
plugin.load(xRayOnContext);
822+
823+
// Run
824+
const xhr = new XMLHttpRequest();
825+
xhr.open('GET', './response.json', true);
826+
xhr.send();
827+
828+
// Yield to the event queue so the event listeners can run
829+
await new Promise((resolve) => setTimeout(resolve, 0));
830+
831+
plugin.disable();
832+
833+
// Assert
834+
expect(record).toHaveBeenCalledTimes(2);
835+
expect(record.mock.calls[1][0]).toEqual(HTTP_EVENT_TYPE);
836+
expect(record.mock.calls[1][1]).toMatchObject({
837+
trace_id: '1-0-000000000000000000000000',
838+
segment_id: '0000000000000000'
839+
});
840+
});
841+
842+
test('when XHR aborts with tracing then the trace id is added to the http event', async () => {
843+
// Init
844+
const config: PartialHttpPluginConfig = {
845+
logicalServiceName: 'sample.rum.aws.amazon.com',
846+
urlsToInclude: [/response\.json/]
847+
};
848+
849+
mock.get(/.*/, {
850+
body: JSON.stringify({ message: 'Hello World!' })
851+
});
852+
853+
const plugin: XhrPlugin = new XhrPlugin(config);
854+
plugin.load(xRayOnContext);
855+
856+
// Run
857+
const xhr = new XMLHttpRequest();
858+
xhr.open('GET', './response.json', true);
859+
xhr.send();
860+
xhr.abort();
861+
862+
// Yield to the event queue so the event listeners can run
863+
await new Promise((resolve) => setTimeout(resolve, 0));
864+
865+
plugin.disable();
866+
867+
// Assert
868+
expect(record).toHaveBeenCalledTimes(2);
869+
expect(record.mock.calls[1][0]).toEqual(HTTP_EVENT_TYPE);
870+
expect(record.mock.calls[1][1]).toMatchObject({
871+
trace_id: '1-0-000000000000000000000000',
872+
segment_id: '0000000000000000'
873+
});
874+
});
875+
876+
test('when the plugin does not record a trace then the trace id is not added to the http event', async () => {
877+
// Init
878+
const config: PartialHttpPluginConfig = {
879+
logicalServiceName: 'sample.rum.aws.amazon.com',
880+
urlsToInclude: [/response\.json/],
881+
recordAllRequests: true
882+
};
883+
884+
mock.get(/.*/, {
885+
body: JSON.stringify({ message: 'Hello World!' }),
886+
headers: { 'Content-Length': '125' } as MockHeaders
887+
});
888+
889+
const plugin: XhrPlugin = new XhrPlugin(config);
890+
plugin.load(xRayOffContext);
891+
892+
// Run
893+
const xhr = new XMLHttpRequest();
894+
xhr.open('GET', './response.json', true);
895+
xhr.send();
896+
897+
// Yield to the event queue so the event listeners can run
898+
await new Promise((resolve) => setTimeout(resolve, 0));
899+
900+
plugin.disable();
901+
902+
// Assert
903+
expect(record).toHaveBeenCalledTimes(1);
904+
expect(record.mock.calls[0][0]).toEqual(HTTP_EVENT_TYPE);
905+
expect(record.mock.calls[0][1]).not.toMatchObject({
906+
trace_id: '1-0-000000000000000000000000',
907+
segment_id: '0000000000000000'
908+
});
909+
});
806910
});

0 commit comments

Comments
 (0)