Skip to content

Commit

Permalink
Add support for segment inspector (#413)
Browse files Browse the repository at this point in the history
This patch adds event reporting to Segment Inspector. The reporting happens through the interface injected by the extension itself.
  • Loading branch information
zikaari authored Jul 12, 2022
1 parent 9b032ee commit 44cc464
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/khaki-frogs-look.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@segment/analytics-next': minor
---

Add support for Segment Inspector Chrome extension
3 changes: 2 additions & 1 deletion packages/browser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"size-limit": [
{
"path": "dist/umd/index.js",
"limit": "25.6 KB"
"limit": "25.8 KB"
}
],
"dependencies": {
Expand All @@ -59,6 +59,7 @@
"unfetch": "^4.1.0"
},
"devDependencies": {
"@segment/inspector-core": "^1.0.0",
"@size-limit/preset-big-lib": "^7.0.8",
"@types/flat": "^5.0.1",
"@types/fs-extra": "^9.0.2",
Expand Down
15 changes: 15 additions & 0 deletions packages/browser/src/core/analytics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import type {
import { version } from '../../generated/version'
import { PriorityQueue } from '../../lib/priority-queue'
import { getGlobal } from '../../lib/get-global'
import { inspectorHost } from '../inspector'

const deprecationWarning =
'This is being deprecated and will be not be available in future releases of Analytics JS'
Expand Down Expand Up @@ -114,6 +115,13 @@ export class Analytics extends Emitter {
this.integrations = options?.integrations ?? {}
this.options = options ?? {}

inspectorHost.start({
user: {
id: this.user().id() || null,
traits: this.user().traits(),
},
})

autoBind(this)
}

Expand Down Expand Up @@ -321,6 +329,13 @@ export class Analytics extends Emitter {
): Promise<DispatchedEvent> {
const ctx = new Context(event)

inspectorHost.trace({
stage: 'triggered',
id: ctx.id,
event: event as any,
timestamp: new Date().toISOString(),
})

if (isOffline() && !this.options.retryQueue) {
return ctx
}
Expand Down
59 changes: 59 additions & 0 deletions packages/browser/src/core/inspector/__tests__/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { Analytics } from '../../analytics'

let analytics: Analytics

describe('Inspector interface', () => {
beforeEach(() => {
window.__SEGMENT_INSPECTOR__ = {
start: jest.fn(),
trace: jest.fn(),
}

analytics = new Analytics({
writeKey: 'abc',
})
})

it('accepts and starts up an inspector client trying to connect', () => {
expect(window.__SEGMENT_INSPECTOR__?.start).toHaveBeenCalledTimes(1)
})

it('notifies the connected inspector client about each event API call and delivery', async () => {
expect(window.__SEGMENT_INSPECTOR__?.trace).not.toHaveBeenCalled()

const timestampMatcher = expect.stringMatching(
/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/
)
const deliveryPromise = analytics.track('Test event').catch(() => {})

// expect 2 calls, triggered report, followed enriched report
expect(window.__SEGMENT_INSPECTOR__?.trace).toHaveBeenCalledTimes(2)

expect(window.__SEGMENT_INSPECTOR__?.trace).toHaveBeenCalledWith(
expect.objectContaining({
stage: 'triggered',
timestamp: timestampMatcher,
event: expect.objectContaining({
event: 'Test event',
type: 'track',
}),
})
)

await deliveryPromise

// triggered -> enriched -> delivered
expect(window.__SEGMENT_INSPECTOR__?.trace).toHaveBeenCalledTimes(3)

expect(window.__SEGMENT_INSPECTOR__?.trace).toHaveBeenCalledWith(
expect.objectContaining({
stage: 'delivered',
timestamp: timestampMatcher,
event: expect.objectContaining({
event: 'Test event',
type: 'track',
}),
})
)
})
})
15 changes: 15 additions & 0 deletions packages/browser/src/core/inspector/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { Inspector } from '@segment/inspector-core'
import { getGlobal } from '../../lib/get-global'

declare global {
interface Window {
__SEGMENT_INSPECTOR__?: Inspector
}
}

const env = getGlobal()

export const inspectorHost: Inspector = {
start: (...args) => (env as any)?.['__SEGMENT_INSPECTOR__']?.start(...args),
trace: (...args) => (env as any)?.['__SEGMENT_INSPECTOR__']?.trace(...args),
}
17 changes: 17 additions & 0 deletions packages/browser/src/core/queue/event-queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Emitter } from '../emitter'
import { Integrations } from '../events'
import { Plugin } from '../plugin'
import { attempt, ensure } from './delivery'
import { inspectorHost } from '../inspector'

type PluginsByType = {
before: Plugin[]
Expand Down Expand Up @@ -265,6 +266,13 @@ export class EventQueue extends Emitter {
}
}

inspectorHost.trace({
stage: 'enriched',
id: ctx.id,
event: ctx.event as any,
timestamp: new Date().toISOString(),
})

// Enrichment and before plugins can re-arrange the deny list dynamically
// so we need to pluck them at the end
const { destinations, after } = this.availableExtensions(
Expand All @@ -282,6 +290,15 @@ export class EventQueue extends Emitter {

ctx.stats.increment('message_delivered')

inspectorHost.trace({
stage: 'delivered',
id: ctx.id,
event: ctx.event as any,
timestamp: new Date().toISOString(),
// FIXME: Resolve browsers destinations that the event was sent to
destinations: ['segment.io'],
})

const afterCalls = after.map((after) => attempt(ctx, after))
await Promise.all(afterCalls)

Expand Down
8 changes: 8 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1491,6 +1491,7 @@ __metadata:
"@lukeed/uuid": ^2.0.0
"@segment/analytics.js-video-plugins": ^0.2.1
"@segment/facade": ^3.4.9
"@segment/inspector-core": ^1.0.0
"@segment/tsub": ^0.1.12
"@size-limit/preset-big-lib": ^7.0.8
"@types/flat": ^5.0.1
Expand Down Expand Up @@ -1570,6 +1571,13 @@ __metadata:
languageName: node
linkType: hard

"@segment/inspector-core@npm:^1.0.0":
version: 1.0.0
resolution: "@segment/inspector-core@npm:1.0.0"
checksum: 4c04303301f54cab9fe8d0502fe0a755ad21206b8917ebbfb5edb8be5888cd7ed4dc948cf34e52b957863de44f9152551d78571ba12c00106f573fdb2136f4ef
languageName: node
linkType: hard

"@segment/isodate-traverse@npm:^1.1.1":
version: 1.1.1
resolution: "@segment/isodate-traverse@npm:1.1.1"
Expand Down

0 comments on commit 44cc464

Please sign in to comment.