From 2f1ae75896123e0aeaa1608fde15312adddd5614 Mon Sep 17 00:00:00 2001 From: Neek Sandhu Date: Wed, 18 Oct 2023 15:35:24 -0700 Subject: [PATCH] Capture action plugin metrics (#971) Just like how we capture metrics relating to performance of classic integrations, this patch now enables capturing of metrics related to action destinations as well. --- .changeset/metal-drinks-repeat.md | 5 ++ packages/browser/package.json | 2 +- .../__tests__/action-destination.test.ts | 72 +++++++++++++++++++ .../src/plugins/remote-loader/index.ts | 34 ++++++++- 4 files changed, 109 insertions(+), 4 deletions(-) create mode 100644 .changeset/metal-drinks-repeat.md create mode 100644 packages/browser/src/plugins/remote-loader/__tests__/action-destination.test.ts diff --git a/.changeset/metal-drinks-repeat.md b/.changeset/metal-drinks-repeat.md new file mode 100644 index 000000000..cd24a810d --- /dev/null +++ b/.changeset/metal-drinks-repeat.md @@ -0,0 +1,5 @@ +--- +'@segment/analytics-next': minor +--- + +Capture action plugin metrics diff --git a/packages/browser/package.json b/packages/browser/package.json index c843f9bcb..15fcfb8a7 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -44,7 +44,7 @@ "size-limit": [ { "path": "dist/umd/index.js", - "limit": "28.9 KB" + "limit": "29 KB" } ], "dependencies": { diff --git a/packages/browser/src/plugins/remote-loader/__tests__/action-destination.test.ts b/packages/browser/src/plugins/remote-loader/__tests__/action-destination.test.ts new file mode 100644 index 000000000..805933d2d --- /dev/null +++ b/packages/browser/src/plugins/remote-loader/__tests__/action-destination.test.ts @@ -0,0 +1,72 @@ +import unfetch from 'unfetch' +import { PluginFactory } from '..' + +import { AnalyticsBrowser } from '../../../browser' +import { createSuccess } from '../../../test-helpers/factories' + +jest.mock('unfetch') +jest.mocked(unfetch).mockImplementation(() => + createSuccess({ + integrations: {}, + remotePlugins: [ + { + name: 'testDestination', + libraryName: 'testDestination', + settings: { + subscriptions: [ + { + name: 'Track Calls', + enabled: true, + partnerAction: 'trackEvent', + subscribe: 'type = "track"', + }, + ], + }, + }, + ], + }) +) + +const testDestination: PluginFactory = () => { + return { + name: 'testDestination', + version: '1.0.0', + type: 'destination', + isLoaded: () => true, + load: () => Promise.resolve(), + track: (ctx) => Promise.resolve(ctx), + } +} + +testDestination.pluginName = 'testDestination' + +describe('ActionDestination', () => { + it('captures essential metrics when invoking methods on an action plugin', async () => { + const ajs = AnalyticsBrowser.load({ + writeKey: 'abc', + plugins: [testDestination], + }) + + await ajs.ready() + + expect(ajs.ctx?.stats.metrics[0]).toMatchObject( + expect.objectContaining({ + metric: 'analytics_js.action_plugin.invoke', + tags: ['method:load', 'action_plugin_name:testDestination'], + }) + ) + + const trackCtx = await ajs.track('test') + + const actionInvokeMetric = trackCtx.stats.metrics.find( + (m) => m.metric === 'analytics_js.action_plugin.invoke' + ) + + expect(actionInvokeMetric).toMatchObject( + expect.objectContaining({ + metric: 'analytics_js.action_plugin.invoke', + tags: ['method:track', 'action_plugin_name:testDestination'], + }) + ) + }) +}) diff --git a/packages/browser/src/plugins/remote-loader/index.ts b/packages/browser/src/plugins/remote-loader/index.ts index 73d797c02..55af1c2de 100644 --- a/packages/browser/src/plugins/remote-loader/index.ts +++ b/packages/browser/src/plugins/remote-loader/index.ts @@ -79,7 +79,21 @@ export class ActionDestination implements DestinationPlugin { transformedContext = await this.transform(ctx) } - await this.action[methodName]!(transformedContext) + try { + ctx.stats.increment('analytics_js.action_plugin.invoke', 1, [ + `method:${methodName}`, + `action_plugin_name:${this.action.name}`, + ]) + + await this.action[methodName]!(transformedContext) + } catch (error) { + ctx.stats.increment('analytics_js.action_plugin.invoke.error', 1, [ + `method:${methodName}`, + `action_plugin_name:${this.action.name}`, + ]) + + throw error + } return ctx } @@ -101,8 +115,22 @@ export class ActionDestination implements DestinationPlugin { return this.action.ready ? this.action.ready() : Promise.resolve() } - load(ctx: Context, analytics: Analytics): Promise { - return this.action.load(ctx, analytics) + async load(ctx: Context, analytics: Analytics): Promise { + try { + ctx.stats.increment('analytics_js.action_plugin.invoke', 1, [ + `method:load`, + `action_plugin_name:${this.action.name}`, + ]) + + return await this.action.load(ctx, analytics) + } catch (error) { + ctx.stats.increment('analytics_js.action_plugin.invoke.error', 1, [ + `method:load`, + `action_plugin_name:${this.action.name}`, + ]) + + throw error + } } unload(ctx: Context, analytics: Analytics): Promise | unknown {