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