Skip to content

Commit 8e2d8d5

Browse files
committed
chore: merge update and get session functions
1 parent 8d86f13 commit 8e2d8d5

6 files changed

+75
-50
lines changed

packages/web/src/SplunkSpanAttributesProcessor.ts

+15-8
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818

1919
import { Attributes } from '@opentelemetry/api'
2020
import { Span, SpanProcessor } from '@opentelemetry/sdk-trace-base'
21-
import { getRumSessionId } from './session'
21+
import { getOrCreateSessionIdAndUpdateExpirationIfNecessary } from './session'
22+
import { suppressTracing } from '@opentelemetry/core'
23+
import { context } from '@opentelemetry/api'
2224

2325
export class SplunkSpanAttributesProcessor implements SpanProcessor {
2426
private readonly _globalAttributes: Attributes
@@ -43,13 +45,18 @@ export class SplunkSpanAttributesProcessor implements SpanProcessor {
4345
}
4446

4547
onStart(span: Span): void {
46-
span.setAttribute('location.href', location.href)
47-
span.setAttributes(this._globalAttributes)
48-
span.setAttribute(
49-
'splunk.rumSessionId',
50-
getRumSessionId({ useLocalStorage: this.useLocalStorageForSessionMetadata }),
51-
)
52-
span.setAttribute('browser.instance.visibility_state', document.visibilityState)
48+
context.with(suppressTracing(context.active()), () => {
49+
span.setAttribute('location.href', location.href)
50+
span.setAttributes(this._globalAttributes)
51+
span.setAttribute(
52+
'splunk.rumSessionId',
53+
getOrCreateSessionIdAndUpdateExpirationIfNecessary({
54+
useLocalStorage: this.useLocalStorageForSessionMetadata,
55+
forceStore: true,
56+
}),
57+
)
58+
span.setAttribute('browser.instance.visibility_state', document.visibilityState)
59+
})
5360
}
5461

5562
setGlobalAttributes(attributes?: Attributes): void {

packages/web/src/index.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import { SplunkExporterConfig } from './exporters/common'
4343
import { SplunkZipkinExporter } from './exporters/zipkin'
4444
import { ERROR_INSTRUMENTATION_NAME, SplunkErrorInstrumentation } from './SplunkErrorInstrumentation'
4545
import { generateId, getPluginConfig } from './utils'
46-
import { getRumSessionId, initSessionTracking, updateSessionStatus } from './session'
46+
import { getOrCreateSessionIdAndUpdateExpirationIfNecessary, getRumSessionId, initSessionTracking } from './session'
4747
import { SplunkWebSocketInstrumentation } from './SplunkWebSocketInstrumentation'
4848
import { initWebVitals } from './webvitals'
4949
import { SplunkLongTaskInstrumentation } from './SplunkLongTaskInstrumentation'
@@ -387,7 +387,6 @@ export const SplunkRum: SplunkOtelWebType = {
387387
// TODO
388388
_deinitSessionTracking = initSessionTracking(
389389
provider,
390-
instanceId,
391390
eventTarget,
392391
processedOptions.cookieDomain,
393392
!!options._experimental_allSpansExtendSession,
@@ -560,7 +559,7 @@ export const SplunkRum: SplunkOtelWebType = {
560559
return
561560
}
562561

563-
updateSessionStatus({
562+
getOrCreateSessionIdAndUpdateExpirationIfNecessary({
564563
forceStore: false,
565564
useLocalStorage: this._processedOptions.persistence === 'localStorage',
566565
forceActivity: this._processedOptions._experimental_allSpansExtendSession,

packages/web/src/session/session.ts

+40-22
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ import { parseCookieToSessionState, renewCookieTimeout } from './cookie-session'
2323
import { SessionState, SessionId } from './types'
2424
import { getSessionStateFromLocalStorage, setSessionStateToLocalStorage } from './local-storage-session'
2525
import { SESSION_INACTIVITY_TIMEOUT_MS } from './constants'
26-
import { suppressTracing } from '@opentelemetry/core'
27-
import { context } from '@opentelemetry/api'
2826

2927
/*
3028
The basic idea is to let the browser expire cookies for us "naturally" once
@@ -71,15 +69,22 @@ export function getCurrentSessionState({ useLocalStorage = false, forceStoreRead
7169
// 1) Check if the cookie has been expired by the browser; if so, create a new one
7270
// 2) If activity has occurred since the last periodic invocation, renew the cookie timeout
7371
// (Only exported for testing purposes.)
74-
export function updateSessionStatus({
75-
forceStore,
76-
useLocalStorage = false,
77-
forceActivity,
78-
}: {
79-
forceActivity?: boolean
80-
forceStore: boolean
81-
useLocalStorage: boolean
82-
}): void {
72+
export function getOrCreateSessionIdAndUpdateExpirationIfNecessary(
73+
{
74+
forceStore,
75+
useLocalStorage,
76+
forceActivity,
77+
}: {
78+
forceActivity?: boolean
79+
forceStore: boolean
80+
useLocalStorage: boolean
81+
},
82+
level = 0,
83+
): string {
84+
if (hasNativeSessionId()) {
85+
return window['SplunkRumNative'].getNativeSessionId()
86+
}
87+
8388
let sessionState = getCurrentSessionState({ useLocalStorage, forceStoreRead: forceStore })
8489
let shouldForceWrite = false
8590
if (!sessionState) {
@@ -104,6 +109,29 @@ export function updateSessionStatus({
104109
}
105110

106111
recentActivity = false
112+
113+
// New session created, check if another tab has created a new session at the same time
114+
if (shouldForceWrite && level < 1) {
115+
return getOrCreateSessionIdAndUpdateExpirationIfNecessary(
116+
{
117+
forceStore: true,
118+
useLocalStorage,
119+
},
120+
level + 1,
121+
)
122+
}
123+
124+
return sessionState.id
125+
}
126+
127+
export function getCurrentSessionId({
128+
forceStore,
129+
useLocalStorage,
130+
}: {
131+
forceStore: boolean
132+
useLocalStorage: boolean
133+
}): string | undefined {
134+
return getCurrentSessionState({ useLocalStorage, forceStoreRead: forceStore })?.id
107135
}
108136

109137
function hasNativeSessionId(): boolean {
@@ -128,13 +156,6 @@ class SessionSpanProcessor implements SpanProcessor {
128156
if (this.options.allSpansAreActivity) {
129157
markActivity()
130158
}
131-
132-
context.with(suppressTracing(context.active()), () => {
133-
updateSessionStatus({
134-
forceStore: false,
135-
useLocalStorage: this.options.useLocalStorage,
136-
})
137-
})
138159
}
139160

140161
shutdown(): Promise<void> {
@@ -146,7 +167,6 @@ const ACTIVITY_EVENTS = ['click', 'scroll', 'mousedown', 'keydown', 'touchend',
146167

147168
export function initSessionTracking(
148169
provider: WebTracerProvider,
149-
instanceId: SessionId,
150170
newEventTarget: InternalEventTarget,
151171
domain?: string,
152172
allSpansAreActivity = false,
@@ -169,8 +189,6 @@ export function initSessionTracking(
169189
ACTIVITY_EVENTS.forEach((type) => document.addEventListener(type, markActivity, { capture: true, passive: true }))
170190
provider.addSpanProcessor(new SessionSpanProcessor({ allSpansAreActivity, useLocalStorage }))
171191

172-
updateSessionStatus({ useLocalStorage, forceStore: true })
173-
174192
return {
175193
deinit: () => {
176194
ACTIVITY_EVENTS.forEach((type) => document.removeEventListener(type, markActivity))
@@ -184,5 +202,5 @@ export function getRumSessionId({ useLocalStorage }: { useLocalStorage: boolean
184202
return window['SplunkRumNative'].getNativeSessionId()
185203
}
186204

187-
return getCurrentSessionState({ useLocalStorage, forceStoreRead: true })?.id
205+
return getCurrentSessionId({ useLocalStorage, forceStore: true })
188206
}

packages/web/test/SessionBasedSampler.test.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import * as assert from 'assert'
2020
import { InternalEventTarget } from '../src/EventTarget'
2121
import { SessionBasedSampler } from '../src/SessionBasedSampler'
22-
import { initSessionTracking, updateSessionStatus } from '../src/session/session'
22+
import { initSessionTracking, getOrCreateSessionIdAndUpdateExpirationIfNecessary } from '../src/session'
2323
import { context, SamplingDecision } from '@opentelemetry/api'
2424
import { SplunkWebTracerProvider } from '../src'
2525
import { SESSION_INACTIVITY_TIMEOUT_MS, SESSION_STORAGE_KEY } from '../src/session/constants'
@@ -37,7 +37,7 @@ describe('Session based sampler', () => {
3737
)
3838
document.cookie = SESSION_STORAGE_KEY + '=' + lowCookieValue + '; path=/; max-age=' + 10
3939
const provider = new SplunkWebTracerProvider()
40-
initSessionTracking(provider, lowSessionId, new InternalEventTarget())
40+
initSessionTracking(provider, new InternalEventTarget())
4141

4242
const sampler = new SessionBasedSampler({ ratio: 0.5 })
4343
assert.strictEqual(
@@ -56,7 +56,7 @@ describe('Session based sampler', () => {
5656
}),
5757
)
5858
document.cookie = SESSION_STORAGE_KEY + '=' + highCookieValue + '; path=/; max-age=' + 10
59-
updateSessionStatus({
59+
getOrCreateSessionIdAndUpdateExpirationIfNecessary({
6060
forceStore: true,
6161
useLocalStorage: false,
6262
})

packages/web/test/SplunkOtelWeb.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import { SpanAttributes } from '@opentelemetry/api'
2020
import { expect } from 'chai'
2121
import SplunkRum from '../src'
22-
import { updateSessionStatus } from '../src/session/session'
22+
import { getOrCreateSessionIdAndUpdateExpirationIfNecessary } from '../src/session'
2323

2424
describe('SplunkOtelWeb', () => {
2525
afterEach(() => {
@@ -124,7 +124,7 @@ describe('SplunkOtelWeb', () => {
124124
})
125125

126126
document.body.click()
127-
updateSessionStatus({ forceStore: false, useLocalStorage: false })
127+
getOrCreateSessionIdAndUpdateExpirationIfNecessary({ forceStore: false, useLocalStorage: false })
128128

129129
// Wait for promise chain to resolve
130130
await Promise.resolve()

packages/web/test/session.test.ts

+13-12
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818

1919
import * as assert from 'assert'
2020
import { InternalEventTarget } from '../src/EventTarget'
21-
import { initSessionTracking, getRumSessionId, updateSessionStatus } from '../src/session/session'
21+
import {
22+
initSessionTracking,
23+
getRumSessionId,
24+
getOrCreateSessionIdAndUpdateExpirationIfNecessary,
25+
} from '../src/session'
2226
import { SplunkWebTracerProvider } from '../src'
2327
import sinon from 'sinon'
2428
import { SESSION_STORAGE_KEY, SESSION_INACTIVITY_TIMEOUT_MS } from '../src/session/constants'
@@ -37,11 +41,11 @@ describe('Session tracking', () => {
3741
it('should correctly handle expiry, garbage values, (in)activity, etc.', (done) => {
3842
// the init tests have possibly already started the setInterval for updateSessionStatus. Try to accomodate this.
3943
const provider = new SplunkWebTracerProvider()
40-
const trackingHandle = initSessionTracking(provider, '1234', new InternalEventTarget())
44+
const trackingHandle = initSessionTracking(provider, new InternalEventTarget())
4145
const firstSessionId = getRumSessionId({ useLocalStorage: false })
4246
assert.strictEqual(firstSessionId.length, 32)
4347
// no marked activity, should keep same state
44-
updateSessionStatus({ forceStore: false, useLocalStorage: false })
48+
getOrCreateSessionIdAndUpdateExpirationIfNecessary({ forceStore: false, useLocalStorage: false })
4549
assert.strictEqual(firstSessionId, getRumSessionId({ useLocalStorage: false }))
4650
// set cookie to expire in 2 seconds, mark activity, and then updateSessionStatus.
4751
// Wait 4 seconds and cookie should still be there (having been renewed)
@@ -54,7 +58,7 @@ describe('Session tracking', () => {
5458
)
5559
document.cookie = SESSION_STORAGE_KEY + '=' + cookieValue + '; path=/; max-age=' + 2
5660
document.body.dispatchEvent(new Event('click'))
57-
updateSessionStatus({ forceStore: false, useLocalStorage: false })
61+
getOrCreateSessionIdAndUpdateExpirationIfNecessary({ forceStore: false, useLocalStorage: false })
5862
setTimeout(() => {
5963
// because of activity, same session should be there
6064
assert.ok(document.cookie.includes(SESSION_STORAGE_KEY))
@@ -72,7 +76,7 @@ describe('Session tracking', () => {
7276
)
7377
document.cookie = SESSION_STORAGE_KEY + '=' + tooOldCookieValue + '; path=/; max-age=' + 4
7478

75-
updateSessionStatus({ forceStore: true, useLocalStorage: false })
79+
getOrCreateSessionIdAndUpdateExpirationIfNecessary({ forceStore: true, useLocalStorage: false })
7680
assert.ok(document.cookie.includes(SESSION_STORAGE_KEY))
7781
const newSessionId = getRumSessionId({ useLocalStorage: false })
7882
assert.strictEqual(newSessionId.length, 32)
@@ -90,11 +94,10 @@ describe('Session tracking', () => {
9094

9195
function subject(allSpansAreActivity = false) {
9296
const provider = new SplunkWebTracerProvider()
93-
const firstSessionId = getRumSessionId({ useLocalStorage: false })
94-
initSessionTracking(provider, firstSessionId, new InternalEventTarget(), undefined, allSpansAreActivity)
97+
initSessionTracking(provider, new InternalEventTarget(), undefined, allSpansAreActivity)
9598

9699
provider.getTracer('tracer').startSpan('any-span').end()
97-
updateSessionStatus({ forceStore: false, useLocalStorage: false })
100+
getOrCreateSessionIdAndUpdateExpirationIfNecessary({ forceStore: false, useLocalStorage: false })
98101
}
99102

100103
it('non-activity spans do not trigger a new session', (done) => {
@@ -131,16 +134,14 @@ describe('Session tracking - localStorage', () => {
131134
const provider = new SplunkWebTracerProvider()
132135
const trackingHandle = initSessionTracking(
133136
provider,
134-
'1234',
135137
new InternalEventTarget(),
136138
undefined,
137139
undefined,
138140
useLocalStorage,
139141
)
140142

141-
const firstSessionId = getRumSessionId({ useLocalStorage })
142-
updateSessionStatus({ forceStore: true, useLocalStorage })
143-
assert.strictEqual(firstSessionId, getRumSessionId({ useLocalStorage }))
143+
const sessionId = getOrCreateSessionIdAndUpdateExpirationIfNecessary({ forceStore: true, useLocalStorage })
144+
assert.strictEqual(sessionId, getRumSessionId({ useLocalStorage }))
144145

145146
trackingHandle.deinit()
146147
})

0 commit comments

Comments
 (0)