From 88b2c85e8da78b0f770dbc526774d86cf8d7c447 Mon Sep 17 00:00:00 2001 From: cjr125 Date: Sun, 22 Sep 2024 10:48:25 -0400 Subject: [PATCH 1/2] feat: Add callback option to config to capture context when starting transactions and spans --- docs/configuration.asciidoc | 30 +++++++++++++++++++ .../rum-core/src/common/config-service.js | 3 +- .../transaction-service.js | 17 ++++++++++- .../src/performance-monitoring/transaction.js | 7 +++++ packages/rum/src/index.d.ts | 3 +- 5 files changed, 57 insertions(+), 3 deletions(-) diff --git a/docs/configuration.asciidoc b/docs/configuration.asciidoc index d8e1d3546..2632053ca 100644 --- a/docs/configuration.asciidoc +++ b/docs/configuration.asciidoc @@ -410,3 +410,33 @@ This is useful on scenarios where the APM server is behind a reverse proxy that NOTE: If APM Server is deployed in an origin different than the page’s origin, you will need to <>. + + +[function] +[[transaction-context-callback]] +==== `transactionContextCallback` + +* *Type:* Function +* *Default:* `null` + +`transactionContextCallback` allows the agent to specify a function to be called when starting automatically instrumented transactions and spans and return +context to be set as tags. This enables the agent to capture the context when instrumented events are fired from files which do not import the RUM agent library. + +The following example illustrates an example which captures the stack trace: + +[source,js] +---- +var options = { + transactionContextCallback: () => { + let stack + try { + throw new Error('') + } + catch (error) { + stack = (error as Error).stack || '' + } + stack = stack.split('\n').map(function (line) { return line.trim(); }) + return { stack }; + } +} +---- \ No newline at end of file diff --git a/packages/rum-core/src/common/config-service.js b/packages/rum-core/src/common/config-service.js index 819967174..03f6f86a6 100644 --- a/packages/rum-core/src/common/config-service.js +++ b/packages/rum-core/src/common/config-service.js @@ -94,7 +94,8 @@ class Config { context: {}, session: false, apmRequest: null, - sendCredentials: false + sendCredentials: false, + transactionContextCallback: null } this.events = new EventHandler() diff --git a/packages/rum-core/src/performance-monitoring/transaction-service.js b/packages/rum-core/src/performance-monitoring/transaction-service.js index a69e8ca66..94675bb08 100644 --- a/packages/rum-core/src/performance-monitoring/transaction-service.js +++ b/packages/rum-core/src/performance-monitoring/transaction-service.js @@ -101,7 +101,15 @@ class TransactionService { createOptions(options) { const config = this._config.config - let presetOptions = { transactionSampleRate: config.transactionSampleRate } + let presetOptions = { + transactionSampleRate: config.transactionSampleRate + } + if (config.transactionContextCallback) { + presetOptions = { + ...presetOptions, + transactionContextCallback: config.transactionContextCallback + } + } let perfOptions = extend(presetOptions, options) if (perfOptions.managed) { perfOptions = extend( @@ -483,6 +491,13 @@ class TransactionService { ) } + if (this._config.config.transactionContextCallback) { + options = { + ...options, + tags: this._config.config.transactionContextCallback() + } + } + const span = tr.startSpan(name, type, options) if (__DEV__) { this._logger.debug( diff --git a/packages/rum-core/src/performance-monitoring/transaction.js b/packages/rum-core/src/performance-monitoring/transaction.js index c4d56e780..18b37b444 100644 --- a/packages/rum-core/src/performance-monitoring/transaction.js +++ b/packages/rum-core/src/performance-monitoring/transaction.js @@ -54,6 +54,13 @@ class Transaction extends SpanBase { this.sampleRate = this.options.transactionSampleRate this.sampled = Math.random() <= this.sampleRate + + if (this.options.transactionContextCallback) { + this.options = { + ...this.options, + tags: this.options.transactionContextCallback() + } + } } addMarks(obj) { diff --git a/packages/rum/src/index.d.ts b/packages/rum/src/index.d.ts index acdd045a6..2f3f62d2b 100644 --- a/packages/rum/src/index.d.ts +++ b/packages/rum/src/index.d.ts @@ -107,7 +107,8 @@ declare module '@elastic/apm-rum' { method: string payload?: string headers?: Record - }) => boolean + }) => boolean, + transactionContextCallback?: (...args: any[]) => any } type Init = (options?: AgentConfigOptions) => ApmBase From e13e4286eb8cc4da57312ecc1b0892276df6e6b9 Mon Sep 17 00:00:00 2001 From: cjr125 Date: Wed, 4 Dec 2024 15:13:58 -0500 Subject: [PATCH 2/2] added unit test --- .../transaction-service.spec.js | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/packages/rum-core/test/performance-monitoring/transaction-service.spec.js b/packages/rum-core/test/performance-monitoring/transaction-service.spec.js index ce511c99f..e5dc7fec1 100644 --- a/packages/rum-core/test/performance-monitoring/transaction-service.spec.js +++ b/packages/rum-core/test/performance-monitoring/transaction-service.spec.js @@ -619,6 +619,34 @@ describe('TransactionService', function () { transaction.end(pageLoadTime + 1000) }) + + it('should capture tags from dispatch context', done => { + config.setConfig({ + transactionContextCallback: () => { + let stack + try { + throw new Error('') + } + catch (error) { + stack = error.stack || '' + } + stack = stack.split('\n').map(function (line) { return line.trim(); }) + return { stack }; + } + }) + const transactionService = new TransactionService(logger, config) + + const tr1 = transactionService.startTransaction( + 'transaction1', + 'transaction' + ) + + tr1.onEnd = () => { + expect(tr1.options.tags.stack).toBeTruthy() + done() + } + tr1.end() + }) }) it('should truncate active spans after transaction ends', () => {