Pipe statsig events to logger (#7141)
* Pipe statsig events to logger * Log rich objects to bitdrift * Fix tests * Consolidate mocks, fix tests * Reduce log trash on native
This commit is contained in:
@@ -105,3 +105,19 @@ jest.mock('expo-modules-core', () => ({
|
|||||||
return () => null
|
return () => null
|
||||||
}),
|
}),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
jest.mock('expo-localization', () => ({
|
||||||
|
getLocales: () => [],
|
||||||
|
}))
|
||||||
|
|
||||||
|
jest.mock('statsig-react-native-expo', () => ({
|
||||||
|
Statsig: {
|
||||||
|
initialize() {},
|
||||||
|
initializeCalled() {
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
jest.mock('../src/lib/bitdrift', () => ({}))
|
||||||
|
jest.mock('../src/lib/statsig/statsig', () => ({}))
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import {init} from '@bitdrift/react-native'
|
import {init} from '@bitdrift/react-native'
|
||||||
import {Statsig} from 'statsig-react-native-expo'
|
import {Statsig} from 'statsig-react-native-expo'
|
||||||
|
export {debug, error, info, warn} from '@bitdrift/react-native'
|
||||||
|
|
||||||
import {initPromise} from './statsig/statsig'
|
import {initPromise} from './statsig/statsig'
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export function debug() {}
|
||||||
|
export function error() {}
|
||||||
|
export function info() {}
|
||||||
|
export function warn() {}
|
||||||
@@ -5,6 +5,7 @@ import {sha256} from 'js-sha256'
|
|||||||
import {Statsig, StatsigProvider} from 'statsig-react-native-expo'
|
import {Statsig, StatsigProvider} from 'statsig-react-native-expo'
|
||||||
|
|
||||||
import {BUNDLE_DATE, BUNDLE_IDENTIFIER, IS_TESTFLIGHT} from '#/lib/app-info'
|
import {BUNDLE_DATE, BUNDLE_IDENTIFIER, IS_TESTFLIGHT} from '#/lib/app-info'
|
||||||
|
import * as bitdrift from '#/lib/bitdrift'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {isWeb} from '#/platform/detection'
|
import {isWeb} from '#/platform/detection'
|
||||||
import * as persisted from '#/state/persisted'
|
import * as persisted from '#/state/persisted'
|
||||||
@@ -97,19 +98,38 @@ export function logEvent<E extends keyof LogEvents>(
|
|||||||
rawMetadata: LogEvents[E] & FlatJSONRecord,
|
rawMetadata: LogEvents[E] & FlatJSONRecord,
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const fullMetadata = {
|
const fullMetadata = toStringRecord(rawMetadata)
|
||||||
...rawMetadata,
|
|
||||||
} as Record<string, string> // Statsig typings are unnecessarily strict here.
|
|
||||||
fullMetadata.routeName = getCurrentRouteName() ?? '(Uninitialized)'
|
fullMetadata.routeName = getCurrentRouteName() ?? '(Uninitialized)'
|
||||||
if (Statsig.initializeCalled()) {
|
if (Statsig.initializeCalled()) {
|
||||||
Statsig.logEvent(eventName, null, fullMetadata)
|
Statsig.logEvent(eventName, null, fullMetadata)
|
||||||
}
|
}
|
||||||
|
// Intentionally bypass the logger abstraction to log rich objects.
|
||||||
|
console.groupCollapsed(eventName)
|
||||||
|
console.log(fullMetadata)
|
||||||
|
console.groupEnd()
|
||||||
|
bitdrift.info(eventName, fullMetadata)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// A log should never interrupt the calling code, whatever happens.
|
// A log should never interrupt the calling code, whatever happens.
|
||||||
logger.error('Failed to log an event', {message: e})
|
logger.error('Failed to log an event', {message: e})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toStringRecord<E extends keyof LogEvents>(
|
||||||
|
metadata: LogEvents[E] & FlatJSONRecord,
|
||||||
|
): Record<string, string> {
|
||||||
|
const record: Record<string, string> = {}
|
||||||
|
for (let key in metadata) {
|
||||||
|
if (metadata.hasOwnProperty(key)) {
|
||||||
|
if (typeof metadata[key] === 'string') {
|
||||||
|
record[key] = metadata[key]
|
||||||
|
} else {
|
||||||
|
record[key] = JSON.stringify(metadata[key])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return record
|
||||||
|
}
|
||||||
|
|
||||||
// We roll our own cache in front of Statsig because it is a singleton
|
// We roll our own cache in front of Statsig because it is a singleton
|
||||||
// and it's been difficult to get it to behave in a predictable way.
|
// and it's been difficult to get it to behave in a predictable way.
|
||||||
// Our own cache ensures consistent evaluation within a single session.
|
// Our own cache ensures consistent evaluation within a single session.
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ import {
|
|||||||
error as bdError,
|
error as bdError,
|
||||||
info as bdInfo,
|
info as bdInfo,
|
||||||
warn as bdWarn,
|
warn as bdWarn,
|
||||||
} from '@bitdrift/react-native'
|
} from '../lib/bitdrift'
|
||||||
|
|
||||||
import {LogLevel, Transport} from './types'
|
import {LogLevel, Transport} from './types'
|
||||||
|
|
||||||
export function createBitdriftTransport(): Transport {
|
export function createBitdriftTransport(): Transport {
|
||||||
@@ -18,6 +17,6 @@ export function createBitdriftTransport(): Transport {
|
|||||||
|
|
||||||
return (level, message) => {
|
return (level, message) => {
|
||||||
const log = logFunctions[level]
|
const log = logFunctions[level]
|
||||||
log(message.toString())
|
log('' + message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
import {Transport} from './index'
|
|
||||||
|
|
||||||
export function createBitdriftTransport(): Transport {
|
|
||||||
return (_level, _message) => {
|
|
||||||
// noop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,25 +4,12 @@ import {describe, expect, it, jest} from '@jest/globals'
|
|||||||
import {agentToSessionAccountOrThrow} from '../agent'
|
import {agentToSessionAccountOrThrow} from '../agent'
|
||||||
import {Action, getInitialState, reducer, State} from '../reducer'
|
import {Action, getInitialState, reducer, State} from '../reducer'
|
||||||
|
|
||||||
jest.mock('statsig-react-native-expo', () => ({
|
|
||||||
Statsig: {
|
|
||||||
initialize() {},
|
|
||||||
initializeCalled() {
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}))
|
|
||||||
|
|
||||||
jest.mock('jwt-decode', () => ({
|
jest.mock('jwt-decode', () => ({
|
||||||
jwtDecode(_token: string) {
|
jwtDecode(_token: string) {
|
||||||
return {}
|
return {}
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
jest.mock('expo-localization', () => ({
|
|
||||||
getLocales: () => [],
|
|
||||||
}))
|
|
||||||
|
|
||||||
describe('session', () => {
|
describe('session', () => {
|
||||||
it('can log in and out', () => {
|
it('can log in and out', () => {
|
||||||
let state = getInitialState([])
|
let state = getInitialState([])
|
||||||
|
|||||||
Reference in New Issue
Block a user