@@ -35,6 +35,29 @@ type LogListener = (entry: LogEntry) => void;
3535
3636const BREADCRUMB_DISABLED_KEY = 'sable_sentry_breadcrumb_disabled' ;
3737
38+ type ConsoleMethod = 'error' | 'warn' | 'info' | 'log' | 'debug' ;
39+
40+ const CONSOLE_METHODS : ConsoleMethod [ ] = [ 'error' , 'warn' , 'info' , 'log' , 'debug' ] ;
41+
42+ const MAX_CONSOLE_MESSAGE_LENGTH = 1000 ;
43+
44+ const formatConsoleArgs = ( args : unknown [ ] ) : string => {
45+ const text = args
46+ . map ( ( arg ) => {
47+ if ( typeof arg === 'string' ) return arg ;
48+ if ( arg instanceof Error ) return arg . stack ?? arg . message ;
49+ try {
50+ return JSON . stringify ( arg ) ;
51+ } catch {
52+ return String ( arg ) ;
53+ }
54+ } )
55+ . join ( ' ' ) ;
56+ return text . length > MAX_CONSOLE_MESSAGE_LENGTH
57+ ? `${ text . slice ( 0 , MAX_CONSOLE_MESSAGE_LENGTH ) } …`
58+ : text ;
59+ } ;
60+
3861class DebugLoggerService {
3962 private logs : LogEntry [ ] = [ ] ;
4063
@@ -52,6 +75,12 @@ class DebugLoggerService {
5275
5376 private sentryStats = { errors : 0 , warnings : 0 } ;
5477
78+ private originalConsole : Partial < Record < ConsoleMethod , ( ...args : unknown [ ] ) => void > > = { } ;
79+
80+ private consoleIntercepted = false ;
81+
82+ private writingToConsole = false ;
83+
5584 constructor ( ) {
5685 // Check if debug logging is enabled from localStorage
5786 this . enabled = localStorage . getItem ( 'sable_internal_debug' ) === '1' ;
@@ -91,6 +120,7 @@ class DebugLoggerService {
91120 this . clear ( ) ;
92121 this . captureActive = true ;
93122 this . captureSince = Date . now ( ) ;
123+ this . interceptConsole ( ) ;
94124 this . log ( 'info' , 'general' , 'diagnostics' , 'Diagnostic capture started' ) ;
95125 return this . captureSince ;
96126 }
@@ -99,9 +129,44 @@ class DebugLoggerService {
99129 if ( ! this . captureActive ) return this . captureSince ;
100130 this . log ( 'info' , 'general' , 'diagnostics' , 'Diagnostic capture stopped' ) ;
101131 this . captureActive = false ;
132+ this . restoreConsole ( ) ;
102133 return this . captureSince ;
103134 }
104135
136+ /**
137+ * Funnels console output (including matrix-js-sdk's logger, which writes to the
138+ * console) into the capture buffer for the duration of a diagnostics session.
139+ */
140+ private interceptConsole ( ) : void {
141+ if ( this . consoleIntercepted ) return ;
142+ this . consoleIntercepted = true ;
143+ CONSOLE_METHODS . forEach ( ( method ) => {
144+ const original = console [ method ] as ( ...args : unknown [ ] ) => void ;
145+ this . originalConsole [ method ] = original ;
146+ console [ method ] = ( ...args : unknown [ ] ) => {
147+ original . apply ( console , args ) ;
148+ if ( this . writingToConsole ) return ;
149+ const level : LogLevel = method === 'log' ? 'debug' : method ;
150+ this . log (
151+ level ,
152+ level === 'error' ? 'error' : 'general' ,
153+ 'console' ,
154+ formatConsoleArgs ( args )
155+ ) ;
156+ } ;
157+ } ) ;
158+ }
159+
160+ private restoreConsole ( ) : void {
161+ if ( ! this . consoleIntercepted ) return ;
162+ this . consoleIntercepted = false ;
163+ CONSOLE_METHODS . forEach ( ( method ) => {
164+ const original = this . originalConsole [ method ] ;
165+ if ( original ) console [ method ] = original ;
166+ } ) ;
167+ this . originalConsole = { } ;
168+ }
169+
105170 public addListener ( listener : LogListener ) : ( ) => void {
106171 this . listeners . add ( listener ) ;
107172 return ( ) => this . listeners . delete ( listener ) ;
@@ -175,7 +240,12 @@ class DebugLoggerService {
175240 // Also log to console for developer convenience
176241 const prefix = `[sable:${ category } :${ namespace } ]` ;
177242 const consoleLevel = level === 'debug' ? 'log' : level ;
178- console [ consoleLevel ] ( prefix , message , data !== undefined ? data : '' ) ;
243+ this . writingToConsole = true ;
244+ try {
245+ console [ consoleLevel ] ( prefix , message , data !== undefined ? data : '' ) ;
246+ } finally {
247+ this . writingToConsole = false ;
248+ }
179249 }
180250
181251 public getBreadcrumbCategoryEnabled ( category : LogCategory ) : boolean {
0 commit comments