@@ -20,8 +20,17 @@ import android.util.Log
20
20
import com.google.firebase.dataconnect.BuildConfig
21
21
import com.google.firebase.dataconnect.LogLevel
22
22
import com.google.firebase.dataconnect.core.LoggerGlobals.LOG_TAG
23
+ import com.google.firebase.dataconnect.core.LoggerGlobals.Logger
23
24
import com.google.firebase.util.nextAlphanumericString
24
25
import kotlin.random.Random
26
+ import kotlinx.coroutines.CoroutineScope
27
+ import kotlinx.coroutines.DelicateCoroutinesApi
28
+ import kotlinx.coroutines.GlobalScope
29
+ import kotlinx.coroutines.flow.Flow
30
+ import kotlinx.coroutines.flow.MutableStateFlow
31
+ import kotlinx.coroutines.flow.getAndUpdate
32
+ import kotlinx.coroutines.flow.launchIn
33
+ import kotlinx.coroutines.flow.onEach
25
34
26
35
internal interface Logger {
27
36
val name: String
@@ -58,31 +67,58 @@ private class LoggerImpl(override val name: String) : Logger {
58
67
internal object LoggerGlobals {
59
68
const val LOG_TAG = " FirebaseDataConnect"
60
69
61
- @Volatile var logLevel: LogLevel = LogLevel .WARN
70
+ val logLevel =
71
+ MutableStateFlow (LogLevel .WARN ).also { logLevelFlow ->
72
+ val logger = Logger (" LogLevelChange" )
73
+ @OptIn(DelicateCoroutinesApi ::class )
74
+ logger.logChanges(logLevelFlow.value, logLevelFlow, GlobalScope )
75
+ }
62
76
63
77
inline fun Logger.debug (message : () -> Any? ) {
64
- if (logLevel <= LogLevel .DEBUG ) debug(" ${message()} " )
78
+ if (logLevel.value <= LogLevel .DEBUG ) debug(" ${message()} " )
65
79
}
66
80
67
81
fun Logger.debug (message : String ) {
68
- if (logLevel <= LogLevel .DEBUG ) log(null , LogLevel .DEBUG , message)
82
+ if (logLevel.value <= LogLevel .DEBUG ) log(null , LogLevel .DEBUG , message)
69
83
}
70
84
71
85
inline fun Logger.warn (message : () -> Any? ) {
72
- if (logLevel <= LogLevel .WARN ) warn(" ${message()} " )
86
+ if (logLevel.value <= LogLevel .WARN ) warn(" ${message()} " )
73
87
}
74
88
75
89
inline fun Logger.warn (exception : Throwable ? , message : () -> Any? ) {
76
- if (logLevel <= LogLevel .WARN ) warn(exception, " ${message()} " )
90
+ if (logLevel.value <= LogLevel .WARN ) warn(exception, " ${message()} " )
77
91
}
78
92
79
93
fun Logger.warn (message : String ) {
80
94
warn(null , message)
81
95
}
82
96
83
97
fun Logger.warn (exception : Throwable ? , message : String ) {
84
- if (logLevel <= LogLevel .WARN ) log(exception, LogLevel .WARN , message)
98
+ if (logLevel.value <= LogLevel .WARN ) log(exception, LogLevel .WARN , message)
85
99
}
86
100
87
101
fun Logger (name : String ): Logger = LoggerImpl (name)
102
+
103
+ // Log a message each time the log level changes. This is intended to provide context when debug
104
+ // logging is enabled and no logs are produced, to at least confirm that debug logging has been
105
+ // enabled. Also, it will leave a "mark" in the logs when debug logging is _disabled_ to explain
106
+ // why the debug logs stop.
107
+ private fun Logger.logChanges (
108
+ initialLogLevel : LogLevel ,
109
+ flow : Flow <LogLevel >,
110
+ coroutineScope : CoroutineScope
111
+ ) {
112
+ val state = MutableStateFlow (initialLogLevel)
113
+ log(null , initialLogLevel, " Log level set to $initialLogLevel " )
114
+ flow
115
+ .onEach { newLogLevel: LogLevel ->
116
+ val oldLogLevel = state.getAndUpdate { newLogLevel }
117
+ if (newLogLevel != oldLogLevel) {
118
+ val emitLogLevel = LogLevel .noisiestOf(newLogLevel, oldLogLevel)
119
+ log(null , emitLogLevel, " Log level changed to $newLogLevel (was $oldLogLevel )" )
120
+ }
121
+ }
122
+ .launchIn(coroutineScope)
123
+ }
88
124
}
0 commit comments