Skip to content

Commit ccca3b3

Browse files
authored
Change logLevel to not touch simple-logger defaultLogLevel (#368)
Fix #331 > `Config.logLevel` / `DEVELOCITY_API_LOG_LEVEL` internally changes `org.slf4j.simpleLogger.defaultLogLevel`, which changes level of all loggers, not only the library's as the javadoc says. In practice, this is an issue when the user is using `simple-logger` and using loggers (or using other dependencies that use loggers), as changing `Config.logLevel` / `DEVELOCITY_API_LOG_LEVEL` will unexpectedly affect those loggers.
1 parent e36aaff commit ccca3b3

File tree

5 files changed

+63
-8
lines changed

5 files changed

+63
-8
lines changed

library/src/main/kotlin/com/gabrielfeo/develocity/api/internal/LoggerFactory.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import kotlin.reflect.KClass
66

77
internal interface LoggerFactory {
88
fun newLogger(cls: KClass<*>): Logger
9+
fun newLogger(name: String): Logger
910
}
1011

1112
internal class RealLoggerFactory(
@@ -17,11 +18,16 @@ internal class RealLoggerFactory(
1718
return org.slf4j.LoggerFactory.getLogger(cls.java)
1819
}
1920

21+
override fun newLogger(name: String): Logger {
22+
setLogLevel()
23+
return org.slf4j.LoggerFactory.getLogger(name)
24+
}
25+
2026
private fun setLogLevel() {
2127
System.setProperty(LOG_LEVEL_SYSTEM_PROPERTY, config.logLevel)
2228
}
2329

2430
companion object {
25-
const val LOG_LEVEL_SYSTEM_PROPERTY = "org.slf4j.simpleLogger.defaultLogLevel"
31+
const val LOG_LEVEL_SYSTEM_PROPERTY = "org.slf4j.simpleLogger.log.com.gabrielfeo.develocity.api"
2632
}
2733
}

library/src/main/kotlin/com/gabrielfeo/develocity/api/internal/OkHttpClient.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import okhttp3.logging.HttpLoggingInterceptor.Level.BODY
1313
import java.time.Duration
1414
import org.slf4j.Logger
1515

16+
private const val HTTP_LOGGER_NAME = "com.gabrielfeo.develocity.api.OkHttpClient"
17+
1618
/**
1719
* Base instance just so that multiple created [Config]s will share resources by default.
1820
*/
@@ -58,7 +60,7 @@ private fun OkHttpClient.Builder.addNetworkInterceptors(
5860
if (config.cacheConfig.cacheEnabled) {
5961
addNetworkInterceptor(buildCacheEnforcingInterceptor(config))
6062
}
61-
val logger = loggerFactory.newLogger(HttpLoggingInterceptor::class)
63+
val logger = loggerFactory.newLogger(HTTP_LOGGER_NAME)
6264
addNetworkInterceptor(HttpLoggingInterceptor(logger = logger::debug).apply { level = BASIC })
6365
addNetworkInterceptor(HttpLoggingInterceptor(logger = logger::trace).apply { level = BODY })
6466
// Add authentication after logging to prevent clients from leaking their access key

library/src/test/kotlin/com/gabrielfeo/develocity/api/OkHttpClientTest.kt

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,25 @@ class OkHttpClientTest {
6565
assertTrue(client.readTimeoutMillis > defaultTimeout)
6666
}
6767

68+
@Test
69+
fun `Logs under library package`() {
70+
val loggerFactory = ProxyLoggerFactory(delegate = RealLoggerFactory(Config()))
71+
buildClient(loggerFactory = loggerFactory)
72+
loggerFactory.createdLoggers.let {
73+
assertTrue(it.isNotEmpty())
74+
it.forEach {
75+
assertTrue(
76+
it.name.startsWith("com.gabrielfeo.develocity.api"),
77+
"Logger name '${it.name}' should start with 'com.gabrielfeo.develocity.api'"
78+
)
79+
}
80+
}
81+
}
82+
6883
private fun buildClient(
6984
vararg envVars: Pair<String, String?>,
7085
clientBuilder: OkHttpClient.Builder? = null,
86+
loggerFactory: LoggerFactory? = null,
7187
): OkHttpClient {
7288
val fakeEnv = FakeEnv(*envVars)
7389
if ("DEVELOCITY_ACCESS_KEY" !in fakeEnv)
@@ -85,6 +101,6 @@ class OkHttpClientTest {
85101
null -> Config()
86102
else -> Config(clientBuilder = clientBuilder)
87103
}
88-
return buildOkHttpClient(config, RealLoggerFactory(config))
104+
return buildOkHttpClient(config, loggerFactory ?: RealLoggerFactory(config))
89105
}
90106
}

library/src/test/kotlin/com/gabrielfeo/develocity/api/internal/LoggerFactoryTest.kt

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,37 @@ import kotlin.test.Test
44
import com.gabrielfeo.develocity.api.Config
55
import kotlin.test.AfterTest
66
import kotlin.test.BeforeTest
7-
import kotlin.test.assertEquals
7+
import kotlin.test.assertTrue
8+
import kotlin.test.assertFalse
89

910
class LoggerFactoryTest {
1011

1112
private val logLevelProperty = RealLoggerFactory.LOG_LEVEL_SYSTEM_PROPERTY
13+
private val defaultLogLevelProperty = "org.slf4j.simpleLogger.defaultLogLevel"
1214

1315
@BeforeTest
1416
@AfterTest
1517
fun cleanup() {
1618
System.clearProperty(logLevelProperty)
19+
System.clearProperty(defaultLogLevelProperty)
1720
env = FakeEnv("DEVELOCITY_URL" to "https://example.com/")
1821
}
1922

2023
@Test
21-
fun `Level always copied from`() {
22-
val loggerFactory = RealLoggerFactory(Config(logLevel = "foo"))
23-
loggerFactory.newLogger(LoggerFactoryTest::class)
24-
assertEquals("foo", System.getProperty(logLevelProperty))
24+
fun `Given custom log level set, loggers created with log level`() {
25+
check(Config().logLevel != "trace") { "Precondition failed: default level is already trace" }
26+
val loggerFactory = RealLoggerFactory(Config(logLevel = "trace"))
27+
val logger = loggerFactory.newLogger(LoggerFactoryTest::class)
28+
assertTrue(logger.isTraceEnabled)
29+
}
30+
31+
@Test
32+
fun `Given custom log level set, unrelated loggers unaffected`() {
33+
val unrelatedLogger = org.slf4j.LoggerFactory.getLogger("foo.Bar")
34+
check(!unrelatedLogger.isTraceEnabled) { "Precondition failed: unrelated logger is already trace" }
35+
val loggerFactory = RealLoggerFactory(Config(logLevel = "trace"))
36+
val logger = loggerFactory.newLogger(LoggerFactoryTest::class)
37+
assertTrue(logger.isTraceEnabled)
38+
assertFalse(unrelatedLogger.isTraceEnabled)
2539
}
2640
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.gabrielfeo.develocity.api.internal
2+
3+
import com.gabrielfeo.develocity.api.Config
4+
import kotlin.reflect.KClass
5+
6+
internal class ProxyLoggerFactory(
7+
private val delegate: LoggerFactory,
8+
) : LoggerFactory {
9+
10+
val createdLoggers: MutableList<org.slf4j.Logger> = mutableListOf()
11+
12+
override fun newLogger(cls: KClass<*>) = delegate.newLogger(cls)
13+
.also { createdLoggers.add(it) }
14+
15+
override fun newLogger(name: String) = delegate.newLogger(name)
16+
.also { createdLoggers.add(it) }
17+
}

0 commit comments

Comments
 (0)