[APP-1782] Analytics migration (#9734)
* WIP * Clean up growthbook code, integrate into init and sessions * Move everything out of React * Add metrics client * Move to separate file * Shared metadata cache * Ensure we update metadata when session ID changes * Ensure userMetadata is cleared when logging out * WIP revamp * Integrate feature gates into analytics context * Clean up old code * Fix useMeta util * Some comments and cleanup * Add logger to base analytics context * Refactor current route handling * Rip out LogEvent from navigation * Update tracking endpoint * Migrate toClout * Clear out statsig client * Add todo, reset logger readme * Ope fix statsig noop * Refactor logging in feed-feedback, add debug logging to metrics client * Remove LogEvents alias for Metrics * Prefer root package export * Remove Metrics alias from logger * [APP-1782] Migrate to new analytics APIs (#9735) * Migrate logEvent to useAnalytics * Migrate logger.metric to useAnalytics * Migrate tricky spot, fix types * Migrate remaining tricky spot * Missed one * Remove metric() from logger * Migrate useGate to useAnalytics * Remove all other StatSig mentions * Update event payload * Update logger tests * Mock expo method * Fix session ID bug * Add session ID test * Add test for metrics client * Clarify intent * Clean up core analytics file * Clean up the call once utils * Fix TODO * Fix TODO * Fix TODO * Fix TODO * Fix TODO * Remove debug code * Fix navigation context * OK nav context is not working, todo * Checkpoint: works but feels hacky * Fix navigation context issue * Improve feature API * Improve metric logging * Update logger tests
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
import {nanoid} from 'nanoid/non-secure'
|
||||
|
||||
import {add} from '#/logger/logDump'
|
||||
import {consoleTransport} from '#/logger/transports/console'
|
||||
import {sentryTransport} from '#/logger/transports/sentry'
|
||||
import {
|
||||
LogContext,
|
||||
LogLevel,
|
||||
type Metadata,
|
||||
type Transport,
|
||||
} from '#/logger/types'
|
||||
import {enabledLogLevels} from '#/logger/util'
|
||||
import {ENV} from '#/env'
|
||||
|
||||
const TRANSPORTS: Transport[] = (function configureTransports() {
|
||||
switch (ENV) {
|
||||
case 'production': {
|
||||
return [sentryTransport].filter(Boolean)
|
||||
}
|
||||
case 'test': {
|
||||
return []
|
||||
}
|
||||
default: {
|
||||
return [consoleTransport]
|
||||
}
|
||||
}
|
||||
})()
|
||||
|
||||
export class Logger {
|
||||
static Level = LogLevel
|
||||
static Context = LogContext
|
||||
|
||||
level: LogLevel
|
||||
context: LogContext | undefined = undefined
|
||||
contextFilter: string = ''
|
||||
ambientMetadata: Record<string, unknown> = {}
|
||||
|
||||
protected debugContextRegexes: RegExp[] = []
|
||||
protected transports: Transport[] = []
|
||||
|
||||
static create(context?: LogContext, metadata: Record<string, unknown> = {}) {
|
||||
const logger = new Logger({
|
||||
level: process.env.EXPO_PUBLIC_LOG_LEVEL as LogLevel,
|
||||
context,
|
||||
contextFilter: process.env.EXPO_PUBLIC_LOG_DEBUG || '',
|
||||
metadata,
|
||||
})
|
||||
for (const transport of TRANSPORTS) {
|
||||
logger.addTransport(transport)
|
||||
}
|
||||
return logger
|
||||
}
|
||||
|
||||
constructor({
|
||||
level,
|
||||
context,
|
||||
contextFilter,
|
||||
metadata: ambientMetadata = {},
|
||||
}: {
|
||||
level?: LogLevel
|
||||
context?: LogContext
|
||||
contextFilter?: string
|
||||
metadata?: Record<string, unknown>
|
||||
} = {}) {
|
||||
this.context = context
|
||||
this.level = level || LogLevel.Info
|
||||
this.contextFilter = contextFilter || ''
|
||||
this.ambientMetadata = ambientMetadata
|
||||
if (this.contextFilter) {
|
||||
this.level = LogLevel.Debug
|
||||
}
|
||||
this.debugContextRegexes = (this.contextFilter || '')
|
||||
.split(',')
|
||||
.map(filter => {
|
||||
return new RegExp(filter.replace(/[^\w:*-]/, '').replace(/\*/g, '.*'))
|
||||
})
|
||||
}
|
||||
|
||||
debug(message: string, metadata: Metadata = {}) {
|
||||
this.transport({level: LogLevel.Debug, message, metadata})
|
||||
}
|
||||
|
||||
info(message: string, metadata: Metadata = {}) {
|
||||
this.transport({level: LogLevel.Info, message, metadata})
|
||||
}
|
||||
|
||||
log(message: string, metadata: Metadata = {}) {
|
||||
this.transport({level: LogLevel.Log, message, metadata})
|
||||
}
|
||||
|
||||
warn(message: string, metadata: Metadata = {}) {
|
||||
this.transport({level: LogLevel.Warn, message, metadata})
|
||||
}
|
||||
|
||||
error(error: Error | string, metadata: Metadata = {}) {
|
||||
this.transport({level: LogLevel.Error, message: error, metadata})
|
||||
}
|
||||
|
||||
addTransport(transport: Transport) {
|
||||
this.transports.push(transport)
|
||||
return () => {
|
||||
this.transports.splice(this.transports.indexOf(transport), 1)
|
||||
}
|
||||
}
|
||||
|
||||
protected transport({
|
||||
level,
|
||||
message,
|
||||
metadata = {},
|
||||
}: {
|
||||
level: LogLevel
|
||||
message: string | Error
|
||||
metadata: Metadata
|
||||
}) {
|
||||
if (
|
||||
level === LogLevel.Debug &&
|
||||
!!this.contextFilter &&
|
||||
!!this.context &&
|
||||
!this.debugContextRegexes.find(reg => reg.test(this.context!))
|
||||
)
|
||||
return
|
||||
|
||||
const timestamp = Date.now()
|
||||
const meta: Metadata = {
|
||||
__metadata__: this.ambientMetadata,
|
||||
...metadata,
|
||||
}
|
||||
|
||||
// send every log to syslog
|
||||
add({
|
||||
id: nanoid(),
|
||||
timestamp,
|
||||
level,
|
||||
context: this.context,
|
||||
message,
|
||||
metadata: meta,
|
||||
})
|
||||
|
||||
if (!enabledLogLevels[this.level].includes(level)) return
|
||||
|
||||
for (const transport of this.transports) {
|
||||
transport(level, this.context, message, meta, timestamp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default logger instance. See `@/logger/README` for docs.
|
||||
*
|
||||
* Basic usage:
|
||||
*
|
||||
* `logger.debug(message[, metadata])`
|
||||
* `logger.info(message[, metadata])`
|
||||
* `logger.log(message[, metadata])`
|
||||
* `logger.warn(message[, metadata])`
|
||||
* `logger.error(error[, metadata])`
|
||||
*/
|
||||
export const logger = Logger.create(Logger.Context.Default)
|
||||
Reference in New Issue
Block a user