1
1
import log from 'loglevel' ;
2
+ import { ThrottleBatch } from './helpers' ;
3
+ import { LOG_SERVER_ENDPOINT } from './defines' ;
2
4
3
5
// TODO: Disable debug logging in production
4
6
export const createLogger = ( level : log . LogLevelDesc = 'DEBUG' ) => {
@@ -16,7 +18,80 @@ export const createLogger = (level: log.LogLevelDesc = 'DEBUG') => {
16
18
} ;
17
19
log . rebuild ( ) ;
18
20
21
+ // Provide a LOG_SERVER=http://127.0.0.1:8000 env var to enable remote
22
+ // logging. The remote logging server is run via `tsx scripts/log-server.ts`
23
+ //
24
+ // Remote logging is excluded from bundle via treeshaking if the `LOG_SERVER`
25
+ // env var is not provided.
26
+ //
27
+ // DO NOT ENABLE THIS FOR PRODUCTION.
28
+ if ( LOG_SERVER_ENDPOINT ) {
29
+ remoteLogger ( log , LOG_SERVER_ENDPOINT ) ;
30
+ }
31
+
19
32
return log ;
20
33
} ;
21
34
22
35
export type Logger = log . RootLogger ;
36
+
37
+ export type RemoteLoggerMessage = {
38
+ msg : unknown [ ] ;
39
+ timestamp : string ;
40
+ methodName : string ;
41
+ logger : string ;
42
+ stackTrace : string [ ] ;
43
+ } ;
44
+
45
+ function remoteLogger ( log : log . RootLogger , endpoint : string ) {
46
+ const queue = new ThrottleBatch ( send , ( logItems ) => logItems . flat ( ) , 500 ) ;
47
+
48
+ const originalFactory = log . methodFactory ;
49
+ log . methodFactory = ( methodName , logLevel , loggerName ) => {
50
+ const raw = originalFactory ( methodName , logLevel , loggerName ) ;
51
+ const original = raw . bind ( log ) ;
52
+ // Note: this interception breaks the stack trace linenumber in devtools console
53
+ return ( ...msgArgs : unknown [ ] ) => {
54
+ const logItem : RemoteLoggerMessage = {
55
+ msg : msgArgs ,
56
+ methodName,
57
+ timestamp : new Date ( ) . toISOString ( ) ,
58
+ logger : loggerName ?. toString ( ) || '' ,
59
+ stackTrace : formatStackTrace ( getStacktrace ( ) ) ,
60
+ } ;
61
+ queue . enqueue ( logItem ) ;
62
+ original . apply ( log , msgArgs ) ;
63
+ } ;
64
+ } ;
65
+ log . rebuild ( ) ;
66
+
67
+ function send ( ...logItems : unknown [ ] ) {
68
+ void fetch ( endpoint , {
69
+ method : 'POST' ,
70
+ headers : { 'Content-Type' : 'application/json' } ,
71
+ body : JSON . stringify ( logItems ) ,
72
+ } ) . catch ( ( ) => { } ) ;
73
+ }
74
+
75
+ function getStacktrace ( ) {
76
+ try {
77
+ throw new Error ( ) ;
78
+ } catch ( trace ) {
79
+ return trace . stack ;
80
+ }
81
+ }
82
+
83
+ function formatStackTrace ( rawStacktrace : string ) : string [ ] {
84
+ let stacktrace = rawStacktrace . split ( '\n' ) ;
85
+ const lines = stacktrace ;
86
+ lines . splice ( 0 , 3 ) ;
87
+ const depth = 3 ;
88
+ if ( depth && lines . length !== depth + 1 ) {
89
+ const shrink = lines . splice ( 0 , depth ) ;
90
+ stacktrace = shrink ;
91
+ if ( lines . length ) stacktrace . push ( `and ${ lines . length } more` ) ;
92
+ } else {
93
+ stacktrace = lines ;
94
+ }
95
+ return stacktrace ;
96
+ }
97
+ }
0 commit comments