Bluesky app fork with some witchin' additions 馃挮
at main 4.3 kB view raw
1import {nanoid} from 'nanoid/non-secure' 2 3import {logEvent} from '#/lib/statsig/statsig' 4import {add} from '#/logger/logDump' 5import {type MetricEvents} from '#/logger/metrics' 6import {consoleTransport} from '#/logger/transports/console' 7import { 8 LogContext, 9 LogLevel, 10 type Metadata, 11 type Transport, 12} from '#/logger/types' 13import {enabledLogLevels} from '#/logger/util' 14import {isNative} from '#/platform/detection' 15import {ENV} from '#/env' 16import {bitdriftTransport} from './transports/bitdrift' 17import {sentryTransport} from './transports/sentry' 18 19const TRANSPORTS: Transport[] = (function configureTransports() { 20 switch (ENV) { 21 case 'production': { 22 return [sentryTransport, isNative && bitdriftTransport].filter( 23 Boolean, 24 ) as Transport[] 25 } 26 case 'test': { 27 return [] 28 } 29 default: { 30 return [consoleTransport] 31 } 32 } 33})() 34 35export class Logger { 36 static Level = LogLevel 37 static Context = LogContext 38 39 level: LogLevel 40 context: LogContext | undefined = undefined 41 contextFilter: string = '' 42 43 protected debugContextRegexes: RegExp[] = [] 44 protected transports: Transport[] = [] 45 46 static create(context?: LogContext) { 47 const logger = new Logger({ 48 level: process.env.EXPO_PUBLIC_LOG_LEVEL as LogLevel, 49 context, 50 contextFilter: process.env.EXPO_PUBLIC_LOG_DEBUG || '', 51 }) 52 for (const transport of TRANSPORTS) { 53 logger.addTransport(transport) 54 } 55 return logger 56 } 57 58 constructor({ 59 level, 60 context, 61 contextFilter, 62 }: { 63 level?: LogLevel 64 context?: LogContext 65 contextFilter?: string 66 } = {}) { 67 this.context = context 68 this.level = level || LogLevel.Info 69 this.contextFilter = contextFilter || '' 70 if (this.contextFilter) { 71 this.level = LogLevel.Debug 72 } 73 this.debugContextRegexes = (this.contextFilter || '') 74 .split(',') 75 .map(filter => { 76 return new RegExp(filter.replace(/[^\w:*-]/, '').replace(/\*/g, '.*')) 77 }) 78 } 79 80 debug(message: string, metadata: Metadata = {}) { 81 this.transport({level: LogLevel.Debug, message, metadata}) 82 } 83 84 info(message: string, metadata: Metadata = {}) { 85 this.transport({level: LogLevel.Info, message, metadata}) 86 } 87 88 log(message: string, metadata: Metadata = {}) { 89 this.transport({level: LogLevel.Log, message, metadata}) 90 } 91 92 warn(message: string, metadata: Metadata = {}) { 93 this.transport({level: LogLevel.Warn, message, metadata}) 94 } 95 96 error(error: Error | string, metadata: Metadata = {}) { 97 this.transport({level: LogLevel.Error, message: error, metadata}) 98 } 99 100 metric<E extends keyof MetricEvents>( 101 event: E & string, 102 metadata: MetricEvents[E], 103 options: { 104 /** 105 * Optionally also send to StatSig 106 */ 107 statsig?: boolean 108 } = {statsig: true}, 109 ) { 110 logEvent(event, metadata, { 111 lake: !options.statsig, 112 }) 113 114 for (const transport of this.transports) { 115 transport(LogLevel.Info, LogContext.Metric, event, metadata, Date.now()) 116 } 117 } 118 119 addTransport(transport: Transport) { 120 this.transports.push(transport) 121 return () => { 122 this.transports.splice(this.transports.indexOf(transport), 1) 123 } 124 } 125 126 protected transport({ 127 level, 128 message, 129 metadata = {}, 130 }: { 131 level: LogLevel 132 message: string | Error 133 metadata: Metadata 134 }) { 135 if ( 136 level === LogLevel.Debug && 137 !!this.contextFilter && 138 !!this.context && 139 !this.debugContextRegexes.find(reg => reg.test(this.context!)) 140 ) 141 return 142 143 const timestamp = Date.now() 144 const meta = metadata || {} 145 146 // send every log to syslog 147 add({ 148 id: nanoid(), 149 timestamp, 150 level, 151 context: this.context, 152 message, 153 metadata: meta, 154 }) 155 156 if (!enabledLogLevels[this.level].includes(level)) return 157 158 for (const transport of this.transports) { 159 transport(level, this.context, message, meta, timestamp) 160 } 161 } 162} 163 164/** 165 * Default logger instance. See `@/logger/README` for docs. 166 * 167 * Basic usage: 168 * 169 * `logger.debug(message[, metadata])` 170 * `logger.info(message[, metadata])` 171 * `logger.log(message[, metadata])` 172 * `logger.warn(message[, metadata])` 173 * `logger.error(error[, metadata])` 174 */ 175export const logger = Logger.create(Logger.Context.Default)