Skip to content

Commit

Permalink
add log messages when the log level changes
Browse files Browse the repository at this point in the history
  • Loading branch information
dconeybe committed Dec 11, 2024
1 parent a5bc6e4 commit dc3dd91
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,26 @@ public enum class LogLevel {
WARN,

/** Do not log anything. */
NONE,
NONE;

internal companion object {

/**
* Returns one of the two given log levels, the one that is "noisier" (i.e. that logs more).
*
* It can be useful to figure out which of two log levels are noisier on log level change, to
* emit a message about the log level change at the noisiest level.
*/
fun noisiestOf(logLevel1: LogLevel, logLevel2: LogLevel): LogLevel =
when (logLevel1) {
DEBUG -> DEBUG
NONE -> logLevel2
WARN ->
when (logLevel2) {
DEBUG -> DEBUG
WARN -> WARN
NONE -> WARN
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,14 @@ import android.util.Log
import com.google.firebase.dataconnect.BuildConfig
import com.google.firebase.dataconnect.LogLevel
import com.google.firebase.dataconnect.core.LoggerGlobals.LOG_TAG
import com.google.firebase.dataconnect.core.LoggerGlobals.Logger
import com.google.firebase.util.nextAlphanumericString
import kotlin.random.Random
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch

internal interface Logger {
val name: String
Expand Down Expand Up @@ -59,7 +64,11 @@ private class LoggerImpl(override val name: String) : Logger {
internal object LoggerGlobals {
const val LOG_TAG = "FirebaseDataConnect"

val logLevel = MutableStateFlow(LogLevel.WARN)
val logLevel =
MutableStateFlow(LogLevel.WARN).also { logLevelFlow ->
val logger = Logger("LogLevelChange")
@OptIn(DelicateCoroutinesApi::class) logger.logChanges(logLevelFlow, GlobalScope)
}

inline fun Logger.debug(message: () -> Any?) {
if (logLevel.value <= LogLevel.DEBUG) debug("${message()}")
Expand All @@ -86,4 +95,21 @@ internal object LoggerGlobals {
}

fun Logger(name: String): Logger = LoggerImpl(name)

// Log a message each time the log level changes. This is intended to provide context when debug
// logging is enabled and no logs are produced, to at least confirm that debug logging has been
// enabled. Also, it will leave a "mark" in the logs when debug logging is _disabled_ to explain
// why the debug logs stop.
private fun Logger.logChanges(flow: MutableStateFlow<LogLevel>, coroutineScope: CoroutineScope) {
var previousLogLevel = flow.value
coroutineScope.launch {
flow.collect { newLogLevel: LogLevel ->
if (newLogLevel != previousLogLevel) {
val emitLogLevel = LogLevel.noisiestOf(newLogLevel, previousLogLevel)
log(null, emitLogLevel, "Log level changed to $newLogLevel (was $previousLogLevel)")
previousLogLevel = newLogLevel
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.firebase.dataconnect

import io.kotest.assertions.assertSoftly
import io.kotest.assertions.withClue
import io.kotest.matchers.shouldBe
import kotlinx.coroutines.test.runTest
import org.junit.Test

class LoggerUnitTest {

@Test
fun `noisiestOf()`() = runTest {
assertSoftly {
verifyNoisiestOf(LogLevel.NONE, LogLevel.NONE, LogLevel.NONE)
verifyNoisiestOf(LogLevel.NONE, LogLevel.WARN, LogLevel.WARN)
verifyNoisiestOf(LogLevel.NONE, LogLevel.DEBUG, LogLevel.DEBUG)
verifyNoisiestOf(LogLevel.WARN, LogLevel.NONE, LogLevel.WARN)
verifyNoisiestOf(LogLevel.WARN, LogLevel.WARN, LogLevel.WARN)
verifyNoisiestOf(LogLevel.WARN, LogLevel.DEBUG, LogLevel.DEBUG)
verifyNoisiestOf(LogLevel.DEBUG, LogLevel.NONE, LogLevel.DEBUG)
verifyNoisiestOf(LogLevel.DEBUG, LogLevel.WARN, LogLevel.DEBUG)
verifyNoisiestOf(LogLevel.DEBUG, LogLevel.DEBUG, LogLevel.DEBUG)
}
}

private companion object {

fun verifyNoisiestOf(logLevel1: LogLevel, logLevel2: LogLevel, expected: LogLevel) {
withClue("noisiestOf($logLevel1, $logLevel2)") {
LogLevel.noisiestOf(logLevel1, logLevel2) shouldBe expected
}
}
}
}

0 comments on commit dc3dd91

Please sign in to comment.