@@ -48,6 +48,7 @@ type Logger interface {
4848 SetLevel (level LogLevel )
4949 SetConsoleLevel (level LogLevel )
5050 SetConsole (c Console )
51+ UnsetConsole (c Console )
5152 Usr (msg string )
5253 Printf (msg string , args ... any )
5354 VeryVerbosef (at int , msg string , args ... any )
@@ -94,10 +95,21 @@ func (a *atom[T]) get() (zz T) {
9495}
9596
9697func (a * atom [T ]) set (t T ) {
98+ if a == nil {
99+ return
100+ }
97101 aa := (* atomic .Value )(a )
98102 aa .Store (t )
99103}
100104
105+ func (a * atom [T ]) cas (old T , new T ) bool {
106+ if a == nil {
107+ return false
108+ }
109+ aa := (* atomic .Value )(a )
110+ return aa .CompareAndSwap (old , new )
111+ }
112+
101113const pcbuckets = 512
102114
103115// a clock-like spam rate limiter
@@ -172,6 +184,15 @@ const defaultLevel = INFO
172184const defaultClevel = STACKTRACE
173185
174186var _ Logger = (* simpleLogger )(nil )
187+ var _ Console = (* noopclog )(nil )
188+
189+ // noopclog is a no-op Console logger that does nothing.
190+ type noopclog struct {}
191+
192+ func (z * noopclog ) Log (level LogLevel , msg string ) {}
193+
194+ // default console is a no-op
195+ var zzclog = & noopclog {}
175196
176197// runtime crashes "E Go ..." are sent to logd / /dev/log from here:
177198// github.com/golang/go/blob/3fd729b2a1/src/runtime/write_err_android.go#L13
@@ -226,6 +247,7 @@ func defaultLogger() *simpleLogger {
226247 clevel : defaultClevel ,
227248 cmsgC : make (chan * conMsg , consoleChSize ),
228249 stcount : make (map [string ]uint32 ),
250+ c : * newclog (), // zero console
229251 // gomobile pipes stderr & stdout to logcat
230252 // github.com/golang/mobile/blob/fa72addaaa/internal/mobileinit/mobileinit_android.go#L74-L92
231253 e : golog .New (os .Stderr , "" , defaultFlags ),
@@ -236,6 +258,12 @@ func defaultLogger() *simpleLogger {
236258 return l
237259}
238260
261+ func newclog () * atom [Console ] {
262+ a := new (atom [Console ])
263+ a .set (zzclog ) // default console is a no-op
264+ return a // escape stack
265+ }
266+
239267// NewLogger creates a new Glogger with the given tag.
240268func NewLogger (tag string ) * simpleLogger {
241269 l := defaultLogger ()
@@ -266,9 +294,18 @@ func (l *simpleLogger) SetConsoleLevel(n LogLevel) {
266294func (l * simpleLogger ) SetConsole (c Console ) {
267295 l .clearStCounts ()
268296
297+ if c == nil || IsNil (c ) {
298+ c = zzclog // no-op console
299+ }
269300 l .c .set (c ) // c may point to nil impl
270301}
271302
303+ func (l * simpleLogger ) UnsetConsole (c Console ) {
304+ l .clearStCounts ()
305+
306+ l .c .cas (c , zzclog ) // reset console to no-op
307+ }
308+
272309func (l * simpleLogger ) clearStCounts () {
273310 l .stmu .Lock ()
274311 defer l .stmu .Unlock ()
@@ -293,7 +330,7 @@ func (l *simpleLogger) consoleDispatcher() {
293330 continue
294331 }
295332 load := (len (l .cmsgC ) / cap (l .cmsgC ) * 100 ) // load percentage
296- if c := l .c .get (); c != nil && ! IsNil ( c ) { // look for l.c on every msg
333+ if c := l .c .get (); c != nil { // look for l.c on every msg
297334 switch m .t {
298335 case NONE :
299336 // drop
@@ -394,7 +431,7 @@ func (l *simpleLogger) emitStack(at int, msgs ...string) {
394431 }
395432 if ! sendtoconsole {
396433 l .err (at + nextframe , msg )
397- } else if c != nil && ! IsNil ( c ) {
434+ } else if c != nil {
398435 // c.Stack() on the same go routine, since
399436 // the caller (ex: core.Recover) may exit
400437 // immediately once simpleLogger.Stack() returns
0 commit comments