Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow sampling based on decide response #839

Merged
merged 43 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
ecc0f54
feat: allow sampling based on decide response
pauldambra Oct 18, 2023
d38e1ea
extract type
pauldambra Oct 18, 2023
461233b
move the comment
pauldambra Oct 18, 2023
3090cd0
quick version
pauldambra Oct 18, 2023
c362083
maybe nicer
pauldambra Oct 18, 2023
963a7a3
fix
pauldambra Oct 19, 2023
2b27ff1
fix
pauldambra Oct 19, 2023
1cd017e
fix
pauldambra Oct 19, 2023
565b8fb
fix
pauldambra Oct 19, 2023
d22ae8d
fix
pauldambra Oct 19, 2023
09796fd
fix
pauldambra Oct 19, 2023
6fe04a7
fix
pauldambra Oct 19, 2023
baff1e0
fix
pauldambra Oct 19, 2023
7f7ad36
fix
pauldambra Oct 19, 2023
0d1bcbf
convert test file to TS
pauldambra Oct 20, 2023
ea1cc41
use real persistence code
pauldambra Oct 20, 2023
5cd18b4
can store session minimum duration if received
pauldambra Oct 20, 2023
e3432ba
type safety for decide response in tests
pauldambra Oct 20, 2023
5394059
don't flush until minimum duration
pauldambra Oct 20, 2023
d16292a
move our files into an extension directory
pauldambra Oct 20, 2023
be760ba
no need to put sampling metadata on
pauldambra Oct 20, 2023
6a83fd1
fix
pauldambra Oct 20, 2023
96be310
fix first pass minimum duration fitler
pauldambra Oct 20, 2023
c089be7
log when delaying
pauldambra Oct 20, 2023
ec863a1
log when delaying
pauldambra Oct 20, 2023
50ec6be
remove noisy log
pauldambra Oct 20, 2023
026c5a3
can calculate rather than store status so its all in one place
pauldambra Oct 21, 2023
d072662
linked flags control recordings
pauldambra Oct 21, 2023
cd851a5
fix
pauldambra Oct 21, 2023
076738b
fix
pauldambra Oct 22, 2023
4e22bf5
Merge branch 'master' into feat/allow-sampling-based-on-decide-response
pauldambra Oct 23, 2023
5a5a616
fix
pauldambra Oct 23, 2023
168177c
fix
pauldambra Oct 23, 2023
074184b
Merge branch 'master' into feat/allow-sampling-based-on-decide-response
pauldambra Oct 24, 2023
8784d62
Merge branch 'master' into feat/allow-sampling-based-on-decide-response
pauldambra Oct 24, 2023
b2dbdd1
Fix
pauldambra Oct 24, 2023
64e9640
Update src/extensions/replay/sessionrecording.ts
pauldambra Oct 24, 2023
f7ddc45
Update src/extensions/replay/sessionrecording.ts
pauldambra Oct 24, 2023
34dda74
with a comment for the future traveller
pauldambra Oct 24, 2023
4c8a088
rename refactor
pauldambra Oct 24, 2023
649757d
more hidden
pauldambra Oct 24, 2023
051347b
fewer getters
pauldambra Oct 24, 2023
d28803d
fix
pauldambra Oct 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,55 +1,66 @@
/// <reference lib="dom" />
import { PostHogPersistence } from '../posthog-persistence'
import { SESSION_ID, USER_STATE } from '../constants'

given('lib', () => new PostHogPersistence({ name: 'bla', persistence: 'cookie' }))
import { PostHogConfig } from '../types'
import Mock = jest.Mock

let referrer = '' // No referrer by default
Object.defineProperty(document, 'referrer', { get: () => referrer })

function makePostHogConfig(name: string, persistenceMode: string): PostHogConfig {
return <PostHogConfig>{
name,
persistence: persistenceMode as 'cookie' | 'localStorage' | 'localStorage+cookie' | 'memory' | 'sessionStorage',
}
}

describe('persistence', () => {
let library: PostHogPersistence

afterEach(() => {
given.lib.clear()
library.clear()
document.cookie = ''
referrer = ''
})

describe.each([`cookie`, `localStorage`, `localStorage+cookie`])('persistence modes: %p', (persistenceMode) => {
// Common tests for all storage modes
beforeEach(() => {
given('lib', () => new PostHogPersistence({ name: 'test', persistence: persistenceMode }))
given.lib.clear()
library = new PostHogPersistence(makePostHogConfig('test', persistenceMode))
library.clear()
})

it('should register_once', () => {
given.lib.register_once({ distinct_id: 'hi', test_prop: 'test_val' })
library.register_once({ distinct_id: 'hi', test_prop: 'test_val' }, undefined, undefined)

let lib2 = new PostHogPersistence({ name: 'test', persistence: persistenceMode })
const lib2 = new PostHogPersistence(makePostHogConfig('test', persistenceMode))
expect(lib2.props).toEqual({ distinct_id: 'hi', test_prop: 'test_val' })
})

it('should save user state', () => {
let lib = new PostHogPersistence({ name: 'bla', persistence: 'cookie' })
const lib = new PostHogPersistence(makePostHogConfig('bla', persistenceMode))
lib.set_user_state('identified')
expect(lib.props[USER_STATE]).toEqual('identified')
})

it('can load user state', () => {
let lib = new PostHogPersistence({ name: 'bla', persistence: 'cookie' })
const lib = new PostHogPersistence(makePostHogConfig('bla', persistenceMode))
lib.set_user_state('identified')
expect(lib.get_user_state()).toEqual('identified')
})

it('has user state as a reserved property key', () => {
let lib = new PostHogPersistence({ name: 'bla', persistence: 'cookie' })
const lib = new PostHogPersistence(makePostHogConfig('bla', persistenceMode))
lib.register({ distinct_id: 'testy', test_prop: 'test_value' })
lib.set_user_state('identified')
expect(lib.properties()).toEqual({ distinct_id: 'testy', test_prop: 'test_value' })
})

it(`should only call save if props changes`, () => {
let lib = new PostHogPersistence({ name: 'test', persistence: 'localStorage+cookie' })
const lib = new PostHogPersistence(makePostHogConfig('test', 'localStorage+cookie'))
lib.register({ distinct_id: 'hi', test_prop: 'test_val' })
lib.save = jest.fn()
const saveMock: Mock = jest.fn()
lib.save = saveMock

lib.register({ distinct_id: 'hi', test_prop: 'test_val' })
lib.register({})
Expand All @@ -58,41 +69,41 @@ describe('persistence', () => {

lib.register({ distinct_id: 'hi2' })
expect(lib.save).toHaveBeenCalledTimes(1)
lib.save.mockClear()
saveMock.mockClear()

lib.register({ new_key: '1234' })
expect(lib.save).toHaveBeenCalledTimes(1)
lib.save.mockClear()
saveMock.mockClear()
})

it('should set direct referrer', () => {
referrer = ''
given.lib.update_referrer_info()
library.update_referrer_info()

expect(given.lib.props['$referring_domain']).toBe('$direct')
expect(given.lib.props['$referrer']).toBe('$direct')
expect(library.props['$referring_domain']).toBe('$direct')
expect(library.props['$referrer']).toBe('$direct')
})

it('should set external referrer', () => {
referrer = 'https://www.google.com'
given.lib.update_referrer_info()
library.update_referrer_info()

expect(given.lib.props['$referring_domain']).toBe('www.google.com')
expect(given.lib.props['$referrer']).toBe('https://www.google.com')
expect(library.props['$referring_domain']).toBe('www.google.com')
expect(library.props['$referrer']).toBe('https://www.google.com')
})

it('should set internal referrer', () => {
referrer = 'https://hedgebox.net/files/abc.png'
given.lib.update_referrer_info()
library.update_referrer_info()

expect(given.lib.props['$referring_domain']).toBe('hedgebox.net')
expect(given.lib.props['$referrer']).toBe('https://hedgebox.net/files/abc.png')
expect(library.props['$referring_domain']).toBe('hedgebox.net')
expect(library.props['$referrer']).toBe('https://hedgebox.net/files/abc.png')
})

it('extracts enabled feature flags', () => {
given.lib.register({ $enabled_feature_flags: { flag: 'variant', other: true } })
expect(given.lib.props['$enabled_feature_flags']).toEqual({ flag: 'variant', other: true })
expect(given.lib.properties()).toEqual({
library.register({ $enabled_feature_flags: { flag: 'variant', other: true } })
expect(library.props['$enabled_feature_flags']).toEqual({ flag: 'variant', other: true })
expect(library.properties()).toEqual({
'$feature/flag': 'variant',
'$feature/other': true,
})
Expand All @@ -101,27 +112,27 @@ describe('persistence', () => {

describe('localStorage+cookie', () => {
it('should migrate data from cookies to localStorage', () => {
let lib = new PostHogPersistence({ name: 'bla', persistence: 'cookie' })
lib.register_once({ distinct_id: 'testy', test_prop: 'test_value' })
const lib = new PostHogPersistence(makePostHogConfig('bla', 'cookie'))
lib.register_once({ distinct_id: 'testy', test_prop: 'test_value' }, undefined, undefined)
expect(document.cookie).toContain(
'ph__posthog=%7B%22distinct_id%22%3A%22testy%22%2C%22test_prop%22%3A%22test_value%22%7D'
)
let lib2 = new PostHogPersistence({ name: 'bla', persistence: 'localStorage+cookie' })
const lib2 = new PostHogPersistence(makePostHogConfig('bla', 'localStorage+cookie'))
expect(document.cookie).toContain('ph__posthog=%7B%22distinct_id%22%3A%22testy%22%7D')
lib2.register({ test_prop2: 'test_val', distinct_id: 'test2' })
expect(document.cookie).toContain('ph__posthog=%7B%22distinct_id%22%3A%22test2%22%7D')
expect(lib2.props).toEqual({ distinct_id: 'test2', test_prop: 'test_value', test_prop2: 'test_val' })
lib2.remove('ph__posthog')
lib2.remove()
expect(localStorage.getItem('ph__posthog')).toEqual(null)
expect(document.cookie).toEqual('')
})

it(`should additionally store certain values in cookies if localStorage+cookie`, () => {
expect(document.cookie).toEqual('')

const encode = (props) => encodeURIComponent(JSON.stringify(props))
const encode = (props: any) => encodeURIComponent(JSON.stringify(props))

let lib = new PostHogPersistence({ name: 'test', persistence: 'localStorage+cookie' })
const lib = new PostHogPersistence(makePostHogConfig('test', 'localStorage+cookie'))
lib.register({ distinct_id: 'test', test_prop: 'test_val' })
expect(document.cookie).toContain(
`ph__posthog=${encode({
Expand All @@ -147,7 +158,7 @@ describe('persistence', () => {
// Clear localstorage to simulate being on a different domain
localStorage.clear()

const newLib = new PostHogPersistence({ name: 'test', persistence: 'localStorage+cookie' })
const newLib = new PostHogPersistence(makePostHogConfig('test', 'localStorage+cookie'))

expect(newLib.props).toEqual({
distinct_id: 'test',
Expand Down
2 changes: 2 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ export const AUTOCAPTURE_DISABLED_SERVER_SIDE = '$autocapture_disabled_server_si
export const SESSION_RECORDING_ENABLED_SERVER_SIDE = '$session_recording_enabled_server_side'
export const CONSOLE_LOG_RECORDING_ENABLED_SERVER_SIDE = '$console_log_recording_enabled_server_side'
export const SESSION_RECORDING_RECORDER_VERSION_SERVER_SIDE = '$session_recording_recorder_version_server_side' // follows rrweb versioning
export const SESSION_RECORDING_SAMPLE_RATE = '$session_recording_sample_rate'
export const SESSION_ID = '$sesid'
export const SESSION_RECORDING_IS_SAMPLED = '$session_is_sampled'
export const ENABLED_FEATURE_FLAGS = '$enabled_feature_flags'
export const PERSISTENCE_EARLY_ACCESS_FEATURES = '$early_access_features'
export const STORED_PERSON_PROPERTIES_KEY = '$stored_person_properties'
Expand Down
5 changes: 0 additions & 5 deletions src/extensions/exceptions/exception-autocapture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,6 @@ export class ExceptionObserver {
if (this.isEnabled()) {
this.startCapturing()
this.debugLog('Remote config for exception autocapture is enabled, starting', autocaptureExceptionsResponse)
} else {
this.debugLog(
'Remote config for exception autocapture is disabled, not starting',
autocaptureExceptionsResponse
)
}
}

Expand Down
Loading
Loading