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