diff --git a/sdk-core/src/main/kotlin/org/dexpace/sdk/core/instrumentation/ClientLogger.kt b/sdk-core/src/main/kotlin/org/dexpace/sdk/core/instrumentation/ClientLogger.kt index 57987a59..785743d3 100644 --- a/sdk-core/src/main/kotlin/org/dexpace/sdk/core/instrumentation/ClientLogger.kt +++ b/sdk-core/src/main/kotlin/org/dexpace/sdk/core/instrumentation/ClientLogger.kt @@ -141,9 +141,16 @@ public class ClientLogger private constructor( * Equivalent to SLF4J `Logger.isEnabledForLevel(Level)`; named `canLog` to read naturally * at call sites such as `if (logger.canLog(LogLevel.VERBOSE)) { … }`. */ - public fun canLog(level: LogLevel): Boolean = slf4j.isEnabledForLevel(toSlf4j(level)) + public fun canLog(level: LogLevel): Boolean = slf4j.isEnabledForLevel(slf4jLevel(level)) - internal fun slf4jLevel(level: LogLevel): Level = toSlf4j(level) + internal fun slf4jLevel(level: LogLevel): Level = + when (level) { + LogLevel.ERROR -> Level.ERROR + LogLevel.WARNING -> Level.WARN + LogLevel.INFO -> Level.INFO + // SLF4J has no VERBOSE; map to DEBUG (the closest convention). + LogLevel.VERBOSE -> Level.DEBUG + } /** * One-shot guard for the [warnDroppedEventFieldOnce] diagnostic. The misuse it flags — a @@ -175,15 +182,6 @@ public class ClientLogger private constructor( eventNameTag, ) } - - private fun toSlf4j(level: LogLevel): Level = - when (level) { - LogLevel.ERROR -> Level.ERROR - LogLevel.WARNING -> Level.WARN - LogLevel.INFO -> Level.INFO - // SLF4J has no VERBOSE; map to DEBUG (the closest convention). - LogLevel.VERBOSE -> Level.DEBUG - } } /** diff --git a/sdk-core/src/main/kotlin/org/dexpace/sdk/core/instrumentation/UrlRedactor.kt b/sdk-core/src/main/kotlin/org/dexpace/sdk/core/instrumentation/UrlRedactor.kt index bf20619c..04957f2a 100644 --- a/sdk-core/src/main/kotlin/org/dexpace/sdk/core/instrumentation/UrlRedactor.kt +++ b/sdk-core/src/main/kotlin/org/dexpace/sdk/core/instrumentation/UrlRedactor.kt @@ -169,29 +169,19 @@ public object UrlRedactor { ) { if (pair.isEmpty()) return val eq = pair.indexOf('=') - val encodedName: String - val hasValue: Boolean - val encodedValue: String if (eq < 0) { - encodedName = pair - hasValue = false - encodedValue = "" - } else { - encodedName = pair.substring(0, eq) - hasValue = true - encodedValue = pair.substring(eq + 1) + // Bare name with no '=' — emit verbatim; there is no value to redact. + out.append(pair) + return } - val allowed = allowedLower.contains(safeDecode(encodedName).lowercase()) - + val encodedName = pair.substring(0, eq) out.append(encodedName) - if (hasValue) { - out.append('=') - if (allowed) { - out.append(encodedValue) - } else { - out.append(REDACTED_ENCODED) - } + out.append('=') + if (allowedLower.contains(safeDecode(encodedName).lowercase())) { + out.append(pair.substring(eq + 1)) + } else { + out.append(REDACTED_ENCODED) } } diff --git a/sdk-core/src/main/kotlin/org/dexpace/sdk/core/io/TeeSink.kt b/sdk-core/src/main/kotlin/org/dexpace/sdk/core/io/TeeSink.kt index 0af6238c..fb8bac44 100644 --- a/sdk-core/src/main/kotlin/org/dexpace/sdk/core/io/TeeSink.kt +++ b/sdk-core/src/main/kotlin/org/dexpace/sdk/core/io/TeeSink.kt @@ -104,10 +104,7 @@ internal class TeeSink( * [requested] and the remaining [tapLimit] budget, clamped to never go negative. The actual * copy and [mirrored] advancement stay at each call site. */ - private fun tapAllowance(requested: Long): Long { - val remaining = (tapLimit - mirrored).coerceAtLeast(0L) - return if (requested < remaining) requested else remaining - } + private fun tapAllowance(requested: Long): Long = minOf(requested, (tapLimit - mirrored).coerceAtLeast(0L)) @Throws(IOException::class) override fun flush() { @@ -119,23 +116,28 @@ internal class TeeSink( primary.close() } - @Throws(IOException::class) - override fun write(source: ByteArray): BufferedSink { - scratch.write(source) + /** + * Stages one typed write into [scratch] then tees it into the tap and drains it into the + * primary in a single pass, returning `this` for chaining. [encode] receives [scratch] + * explicitly as its `it` argument so the staged write always targets the staging [Buffer] — + * never one of this `TeeSink`'s own `write*` overrides, which a `Buffer.()` receiver lambda + * could silently rebind to (and self-recurse) if a `Buffer` overload were ever added. + */ + private inline fun staged(encode: (Buffer) -> Unit): BufferedSink { + encode(scratch) drainScratch() return this } + @Throws(IOException::class) + override fun write(source: ByteArray): BufferedSink = staged { it.write(source) } + @Throws(IOException::class) override fun write( source: ByteArray, offset: Int, byteCount: Int, - ): BufferedSink { - scratch.write(source, offset, byteCount) - drainScratch() - return this - } + ): BufferedSink = staged { it.write(source, offset, byteCount) } @Throws(IOException::class) override fun writeAll(source: Source): Long { @@ -157,32 +159,20 @@ internal class TeeSink( } @Throws(IOException::class) - override fun writeUtf8(string: String): BufferedSink { - scratch.writeUtf8(string) - drainScratch() - return this - } + override fun writeUtf8(string: String): BufferedSink = staged { it.writeUtf8(string) } @Throws(IOException::class) override fun writeUtf8( string: String, beginIndex: Int, endIndex: Int, - ): BufferedSink { - scratch.writeUtf8(string, beginIndex, endIndex) - drainScratch() - return this - } + ): BufferedSink = staged { it.writeUtf8(string, beginIndex, endIndex) } @Throws(IOException::class) override fun writeString( string: String, charset: Charset, - ): BufferedSink { - scratch.writeString(string, charset) - drainScratch() - return this - } + ): BufferedSink = staged { it.writeString(string, charset) } @Throws(IOException::class) override fun outputStream(): OutputStream {