Merge pull request #2005 from davotoula/Introduce-log-level-filtering

Introduce log level filtering
This commit is contained in:
Vitor Pamplona
2026-03-29 09:56:21 -04:00
committed by GitHub
124 changed files with 569 additions and 367 deletions
@@ -20,7 +20,7 @@
*/
package com.vitorpamplona.quartz.utils
actual object Log {
actual object PlatformLog {
actual fun w(
tag: String,
message: String,
@@ -48,14 +48,24 @@ actual object Log {
actual fun d(
tag: String,
message: String,
throwable: Throwable?,
) {
android.util.Log.d(tag, message)
if (throwable != null) {
android.util.Log.d(tag, message, throwable)
} else {
android.util.Log.d(tag, message)
}
}
actual fun i(
tag: String,
message: String,
throwable: Throwable?,
) {
android.util.Log.i(tag, message)
if (throwable != null) {
android.util.Log.i(tag, message, throwable)
} else {
android.util.Log.i(tag, message)
}
}
}
@@ -22,42 +22,41 @@ package com.vitorpamplona.quartz.utils
import platform.Foundation.NSLog
actual object Log {
actual fun w(
actual object PlatformLog {
private fun log(
level: String,
tag: String,
message: String,
throwable: Throwable?,
) {
if (throwable != null) {
NSLog("WARN: [$tag] $message. Throwable: $throwable CAUSE ${throwable.cause}")
NSLog("$level: [$tag] $message. Throwable: $throwable CAUSE ${throwable.cause}")
} else {
NSLog("WARN: [$tag] $message")
NSLog("$level: [$tag] $message")
}
}
actual fun w(
tag: String,
message: String,
throwable: Throwable?,
) = log("WARN", tag, message, throwable)
actual fun e(
tag: String,
message: String,
throwable: Throwable?,
) {
if (throwable != null) {
NSLog("ERROR: [$tag] $message. Throwable: $throwable CAUSE ${throwable.cause}")
} else {
NSLog("ERROR: [$tag] $message")
}
}
) = log("ERROR", tag, message, throwable)
actual fun d(
tag: String,
message: String,
) {
NSLog("DEBUG: [$tag] $message")
}
throwable: Throwable?,
) = log("DEBUG", tag, message, throwable)
actual fun i(
tag: String,
message: String,
) {
NSLog("INFO: [$tag] $message")
}
throwable: Throwable?,
) = log("INFO", tag, message, throwable)
}
@@ -46,7 +46,7 @@ class AddressSerializer {
if (parts.size > 2 && parts[1].length == 64 && Hex.isHex(parts[1])) {
if (parts[0].length > 5) {
// invalid kind
Log.w("AddressableId", "Error parsing. invalid kind $addressId")
Log.w("AddressableId") { "Error parsing. invalid kind $addressId" }
null
} else {
Address(parts[0].toInt(), parts[1], parts.getOrNull(2) ?: "")
@@ -57,11 +57,11 @@ class AddressSerializer {
if (addr is NAddress) {
addr.address()
} else {
Log.w("AddressableId", "Error parsing. naddr1 seems invalid: $addressId")
Log.w("AddressableId") { "Error parsing. naddr1 seems invalid: $addressId" }
null
}
} else {
Log.w("AddressableId", "Error parsing. Not a valid address: $addressId")
Log.w("AddressableId") { "Error parsing. Not a valid address: $addressId" }
null
}
}
@@ -71,7 +71,7 @@ class MetadataEvent(
Json.parseToJsonElement(content) as JsonObject
} catch (e: Exception) {
if (e is CancellationException) throw e
Log.w("MetadataEvent", "Content Parse Error: ${toNostrUri()} ${e.message}")
Log.w("MetadataEvent") { "Content Parse Error: ${toNostrUri()} ${e.message}" }
null
}
@@ -80,7 +80,7 @@ class MetadataEvent(
JsonMapper.fromJson<UserMetadata>(content)
} catch (e: Exception) {
if (e is CancellationException) throw e
Log.w("MetadataEvent", "Content Parse Error: ${toNostrUri()} ${e.message}")
Log.w("MetadataEvent") { "Content Parse Error: ${toNostrUri()} ${e.message}" }
null
}
@@ -59,7 +59,7 @@ suspend fun INostrClient.publishAndConfirmDetailed(
): Map<NormalizedRelayUrl, Boolean> {
val resultChannel = Channel<Result>(UNLIMITED)
Log.d("publishAndConfirm", "Waiting for ${relayList.size} responses")
Log.d("publishAndConfirm") { "Waiting for ${relayList.size} responses" }
val subscription =
object : RelayConnectionListener {
@@ -69,14 +69,14 @@ suspend fun INostrClient.publishAndConfirmDetailed(
) {
if (relay.url in relayList) {
resultChannel.trySend(Result(relay.url, false))
Log.d("publishAndConfirm", "Error from relay ${relay.url}: $errorMessage")
Log.d("publishAndConfirm") { "Error from relay ${relay.url}: $errorMessage" }
}
}
override fun onDisconnected(relay: IRelayClient) {
if (relay.url in relayList) {
resultChannel.trySend(Result(relay.url, false))
Log.d("publishAndConfirm", "Disconnected from relay ${relay.url}")
Log.d("publishAndConfirm") { "Disconnected from relay ${relay.url}" }
}
}
@@ -91,7 +91,7 @@ suspend fun INostrClient.publishAndConfirmDetailed(
is OkMessage -> {
if (msg.eventId == event.id) {
resultChannel.trySend(Result(relay.url, msg.success))
Log.d("publishAndConfirm", "onSendResponse Received response for ${msg.eventId} from relay ${relay.url} message ${msg.message} success ${msg.success}")
Log.d("publishAndConfirm") { "onSendResponse Received response for ${msg.eventId} from relay ${relay.url} message ${msg.message} success ${msg.success}" }
}
}
}
@@ -136,7 +136,7 @@ suspend fun INostrClient.publishAndConfirmDetailed(
// Clean up the channel
resultChannel.close()
Log.d("publishAndConfirm", "Finished with ${receivedResults.size} results")
Log.d("publishAndConfirm") { "Finished with ${receivedResults.size} results" }
return receivedResults
}
@@ -57,14 +57,14 @@ class RelayLogger(
val logTag = logTag(relay.url)
when (msg) {
is EventMessage -> if (debugReceiving) Log.d(logTag, "Received: $msgStr")
is EoseMessage -> if (debugReceiving) Log.d(logTag, "EOSE: ${msg.subId}")
is NoticeMessage -> Log.w(logTag, "Notice: ${msg.message}")
is OkMessage -> if (debugReceiving) Log.d(logTag, "OK: ${msg.eventId} ${msg.success} ${msg.message}")
is AuthMessage -> if (debugReceiving) Log.d(logTag, "Auth: ${msg.challenge}")
is NotifyMessage -> if (debugReceiving) Log.d(logTag, "Notify: ${msg.message}")
is CountMessage -> if (debugReceiving) Log.d(logTag, "Count: ${msg.result.count} approx: ${msg.result.approximate} hll: ${msg.result.hll != null}")
is ClosedMessage -> Log.w(logTag, "Closed: ${msg.subId} ${msg.message}")
is EventMessage -> if (debugReceiving) Log.d(logTag) { "Received: $msgStr" }
is EoseMessage -> if (debugReceiving) Log.d(logTag) { "EOSE: ${msg.subId}" }
is NoticeMessage -> Log.w(logTag) { "Notice: ${msg.message}" }
is OkMessage -> if (debugReceiving) Log.d(logTag) { "OK: ${msg.eventId} ${msg.success} ${msg.message}" }
is AuthMessage -> if (debugReceiving) Log.d(logTag) { "Auth: ${msg.challenge}" }
is NotifyMessage -> if (debugReceiving) Log.d(logTag) { "Notify: ${msg.message}" }
is CountMessage -> if (debugReceiving) Log.d(logTag) { "Count: ${msg.result.count} approx: ${msg.result.approximate} hll: ${msg.result.hll != null}" }
is ClosedMessage -> Log.w(logTag) { "Closed: ${msg.subId} ${msg.message}" }
}
}
@@ -76,7 +76,7 @@ class RelayLogger(
) {
if (success) {
if (debugSending) {
Log.d(logTag(relay.url), "Sent (${cmdStr.length} chars): $cmdStr")
Log.d(logTag(relay.url)) { "Sent (${cmdStr.length} chars): $cmdStr" }
}
} else {
Log.e(logTag(relay.url), "Failure sending (${cmdStr.length} chars): $cmdStr")
@@ -92,7 +92,7 @@ class RelayLogger(
pingMillis: Int,
compressed: Boolean,
) {
Log.d(logTag(relay.url), "OnOpen (ping: ${pingMillis}ms${if (compressed) ", using compression" else ""})")
Log.d(logTag(relay.url)) { "OnOpen (ping: ${pingMillis}ms${if (compressed) ", using compression" else ""})" }
}
override fun onDisconnected(relay: IRelayClient) {
@@ -36,7 +36,7 @@ fun List<RelayBasedFilter>.groupByRelay(): Map<NormalizedRelayUrl, List<Filter>>
val result = mutableMapOf<NormalizedRelayUrl, MutableList<Filter>>()
for (relayBasedFilter in this) {
if (relayBasedFilter.filter.isEmpty()) {
Log.e("FilterError", "Ignoring empty filter for ${relayBasedFilter.relay}")
Log.e("FilterError") { "Ignoring empty filter for ${relayBasedFilter.relay}" }
} else {
result.getOrPut(relayBasedFilter.relay) { mutableListOf() }.add(relayBasedFilter.filter)
}
@@ -51,7 +51,7 @@ class RelayReqStats(
fun printStats() =
stats.printCounter { subId, kind, counter ->
Log.d("RelaySubStats", "$subId, kind $kind: $counter")
Log.d("RelaySubStats") { "$subId, kind $kind: $counter" }
}
init {
@@ -91,32 +91,32 @@ class Filter(
init {
ids?.forEach {
if (it.length != 64) Log.e("FilterError", "Invalid id length $it on ${toJson()}")
if (it.length != 64) Log.e("FilterError") { "Invalid id length $it on ${toJson()}" }
}
authors?.forEach {
if (it.length != 64) Log.e("FilterError", "Invalid author length $it on ${toJson()}")
if (it.length != 64) Log.e("FilterError") { "Invalid author length $it on ${toJson()}" }
}
// tests common tags.
if (tags != null) {
tags["p"]?.forEach {
if (it.length != 64) Log.e("FilterError", "Invalid p-tag length $it on ${toJson()}")
if (it.length != 64) Log.e("FilterError") { "Invalid p-tag length $it on ${toJson()}" }
}
tags["e"]?.forEach {
if (it.length != 64) Log.e("FilterError", "Invalid e-tag length $it on ${toJson()}")
if (it.length != 64) Log.e("FilterError") { "Invalid e-tag length $it on ${toJson()}" }
}
tags["a"]?.forEach {
if (Address.parse(it) == null) Log.e("FilterError", "Invalid a-tag $it on ${toJson()}")
if (Address.parse(it) == null) Log.e("FilterError") { "Invalid a-tag $it on ${toJson()}" }
}
}
if (tagsAll != null) {
tagsAll["p"]?.forEach {
if (it.length != 64) Log.e("FilterError", "Invalid p-tag length $it on ${toJson()}")
if (it.length != 64) Log.e("FilterError") { "Invalid p-tag length $it on ${toJson()}" }
}
tagsAll["e"]?.forEach {
if (it.length != 64) Log.e("FilterError", "Invalid e-tag length $it on ${toJson()}")
if (it.length != 64) Log.e("FilterError") { "Invalid e-tag length $it on ${toJson()}" }
}
tagsAll["a"]?.forEach {
if (Address.parse(it) == null) Log.e("FilterError", "Invalid a-tag $it on ${toJson()}")
if (Address.parse(it) == null) Log.e("FilterError") { "Invalid a-tag $it on ${toJson()}" }
}
}
}
@@ -145,7 +145,7 @@ class RelayUrlNormalizer {
if (trimmed.contains("://")) {
// some other scheme we cannot connect to.
Log.w("RelayUrlNormalizer", "Rejected $url")
Log.w("RelayUrlNormalizer") { "Rejected $url" }
return null
}
@@ -178,14 +178,14 @@ class RelayUrlNormalizer {
normalizedUrls.put(url, NormalizationResult.Success(normalized))
normalized
} else {
Log.w("NormalizedRelayUrl", "Rejected $url")
Log.w("NormalizedRelayUrl") { "Rejected $url" }
normalizedUrls.put(url, NormalizationResult.Error)
null
}
} catch (e: Exception) {
if (e is CancellationException) throw e
normalizedUrls.put(url, NormalizationResult.Error)
Log.w("NormalizedRelayUrl", "Rejected $url")
Log.w("NormalizedRelayUrl") { "Rejected $url" }
null
}
}
@@ -73,7 +73,7 @@ class RelaySession(
try {
onSend(OptimizedJsonMapper.toJson(message))
} catch (e: Exception) {
Log.w("ClientSession", "Failed to send to ${e.message}")
Log.w("ClientSession") { "Failed to send to ${e.message}" }
}
}
@@ -156,7 +156,7 @@ class OpenTimestamps(
): Timestamp {
val responses =
mapNotNullAsync(calendarUrls) { calendarUrl ->
Log.i("OpenTimestamps", "Submitting to remote calendar $calendarUrl")
Log.i("OpenTimestamps") { "Submitting to remote calendar $calendarUrl" }
calendar.submit(calendarUrl, timestamp.digest)
}
@@ -361,7 +361,7 @@ class OpenTimestamps(
val attsFromRemote: MutableSet<TimeAttestation> = upgradedStamp.getAttestations()
if (attsFromRemote.isNotEmpty()) {
Log.i("OpenTimestamps", "Got 1 attestation(s) from $calendarUrl")
Log.i("OpenTimestamps") { "Got 1 attestation(s) from $calendarUrl" }
}
// Set difference from remote attestations & existing attestations
@@ -56,7 +56,7 @@ abstract class OpUnary : Op() {
}
else -> {
Log.e("OpenTimestamp", "Unknown operation tag: $tag")
Log.e("OpenTimestamp") { "Unknown operation tag: $tag" }
null // TODO: Is this OK? Won't it blow up later? Better to throw?
}
@@ -62,7 +62,7 @@ class EncryptedInfo(
nonce = Base64.decode(parts[1]),
)
} catch (e: Exception) {
Log.w("NIP04", "Unable to Parse encrypted payload: $payload")
Log.w("NIP04") { "Unable to Parse encrypted payload: $payload" }
null
}
}
@@ -51,7 +51,7 @@ fun ATag.Companion.parseAtag(
ATag(parts[0].toInt(), parts[1], parts[2], relayHint)
} catch (t: Throwable) {
Log.w("ATag", "Error parsing A Tag: $atag: ${t.message}")
Log.w("ATag") { "Error parsing A Tag: $atag: ${t.message}" }
null
}
@@ -78,7 +78,7 @@ object Nip19Parser {
return type!! + key
} catch (e: Throwable) {
Log.e("NIP19 Parser", "Issue trying to Decode NIP19 $uri: ${e.message}")
Log.e("NIP19 Parser") { "Issue trying to Decode NIP19 $uri: ${e.message}" }
}
return null
@@ -98,7 +98,7 @@ object Nip19Parser {
return parseComponents(type, key, additionalChars?.ifEmpty { null })
} catch (e: Throwable) {
Log.e("NIP19 Parser", "Issue trying to Decode NIP19 $uri: ${e.message}")
Log.e("NIP19 Parser") { "Issue trying to Decode NIP19 $uri: ${e.message}" }
}
return null
@@ -127,7 +127,7 @@ object Nip19Parser {
ParseReturn(it, nip19, additionalChars)
}
} catch (e: Throwable) {
Log.w("NIP19 Parser", "Issue trying to Decode NIP19 $key: ${e.message}")
Log.w("NIP19 Parser") { "Issue trying to Decode NIP19 $key: ${e.message}" }
null
}
@@ -55,7 +55,7 @@ data class NAddress(
return parse(key.bechToBytes())
}
} catch (e: Throwable) {
Log.w("NAddress", "Issue trying to Decode NIP19 $this: ${e.message}")
Log.w("NAddress") { "Issue trying to Decode NIP19 $this: ${e.message}" }
}
return null
@@ -68,7 +68,7 @@ class ChannelCreateEvent(
}
} catch (e: Exception) {
if (e is CancellationException) throw e
Log.w("ChannelCreateEvent", "Failure to parse ${this.toJson()}")
Log.w("ChannelCreateEvent") { "Failure to parse ${this.toJson()}" }
ChannelDataNorm()
}
@@ -74,7 +74,7 @@ class ChannelMetadataEvent(
}
} catch (e: Exception) {
if (e is CancellationException) throw e
Log.w("ChannelCreateEvent", "Failure to parse ${this.toJson()}")
Log.w("ChannelCreateEvent") { "Failure to parse ${this.toJson()}" }
ChannelDataNorm()
}
@@ -60,7 +60,7 @@ class DraftWrapEvent(
fromJson(json)
} catch (e: Exception) {
if (e is CancellationException) throw e
Log.w("DraftEvent", "Unable to parse inner event of a draft: $json")
Log.w("DraftEvent") { "Unable to parse inner event of a draft: $json" }
throw e
}
}
@@ -43,7 +43,7 @@ class PrivateTagsInContent {
decode(json)
} catch (e: Exception) {
if (e is CancellationException) throw e
Log.w("DraftEvent", "Unable to parse inner event of a draft: $json")
Log.w("DraftEvent") { "Unable to parse inner event of a draft: $json" }
throw e
}
}
@@ -90,7 +90,7 @@ enum class ReportType(
"スパム \uD83D\uDCE3" -> SPAM
"Pourriel \uD83D\uDCE3" -> SPAM
"violence" -> VIOLENCE
else -> Log.w("ReportedEventTag", "Report type not supported: `$code` ${tag.joinToString(", ")}").let { OTHER }
else -> Log.w("ReportedEventTag") { "Report type not supported: `$code` ${tag.joinToString(", ")}" }.let { OTHER }
}
}
}
@@ -61,7 +61,7 @@ class NIP90ContentDiscoveryResponseEvent(
}
}
} catch (e: Throwable) {
Log.w("NIP90ContentDiscoveryResponseEvent", "Error parsing the JSON ${e.message}")
Log.w("NIP90ContentDiscoveryResponseEvent") { "Error parsing the JSON ${e.message}" }
}
return events ?: listOf()
@@ -20,26 +20,66 @@
*/
package com.vitorpamplona.quartz.utils
expect object Log {
object Log {
@Volatile var minLevel: LogLevel = LogLevel.DEBUG
fun d(
tag: String,
message: String,
throwable: Throwable? = null,
) {
if (minLevel <= LogLevel.DEBUG) PlatformLog.d(tag, message, throwable)
}
inline fun d(
tag: String,
message: () -> String,
) {
if (minLevel <= LogLevel.DEBUG) PlatformLog.d(tag, message())
}
fun i(
tag: String,
message: String,
throwable: Throwable? = null,
) {
if (minLevel <= LogLevel.INFO) PlatformLog.i(tag, message, throwable)
}
inline fun i(
tag: String,
message: () -> String,
) {
if (minLevel <= LogLevel.INFO) PlatformLog.i(tag, message())
}
fun w(
tag: String,
message: String,
throwable: Throwable? = null,
)
) {
if (minLevel <= LogLevel.WARN) PlatformLog.w(tag, message, throwable)
}
inline fun w(
tag: String,
message: () -> String,
) {
if (minLevel <= LogLevel.WARN) PlatformLog.w(tag, message())
}
fun e(
tag: String,
message: String,
throwable: Throwable? = null,
)
) {
if (minLevel <= LogLevel.ERROR) PlatformLog.e(tag, message, throwable)
}
fun d(
inline fun e(
tag: String,
message: String,
)
fun i(
tag: String,
message: String,
)
message: () -> String,
) {
if (minLevel <= LogLevel.ERROR) PlatformLog.e(tag, message())
}
}
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2025 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.quartz.utils
/** Ordered by severity -- do not reorder. Filtering uses ordinal comparison. */
enum class LogLevel { DEBUG, INFO, WARN, ERROR }
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2025 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.quartz.utils
expect object PlatformLog {
fun w(
tag: String,
message: String,
throwable: Throwable? = null,
)
fun e(
tag: String,
message: String,
throwable: Throwable? = null,
)
fun d(
tag: String,
message: String,
throwable: Throwable? = null,
)
fun i(
tag: String,
message: String,
throwable: Throwable? = null,
)
}
@@ -61,7 +61,7 @@ class LargeDBTests {
try {
db.insert(event)
} catch (e: SQLiteException) {
Log.w("LargeDBTests", "Error inserting event: ${e.message} for event: ${event.toJson()}")
Log.w("LargeDBTests") { "Error inserting event: ${e.message} for event: ${event.toJson()}" }
}
}
}
@@ -72,7 +72,7 @@ class LargeDBTests {
try {
db.insert(event)
} catch (e: SQLiteException) {
Log.w("LargeDBTests", "Error inserting event: ${e.message} for event: ${event.toJson()}")
Log.w("LargeDBTests") { "Error inserting event: ${e.message} for event: ${event.toJson()}" }
}
}
}
@@ -60,7 +60,7 @@ class OkHttpBitcoinExplorer(
return client.newCall(request).execute().use {
if (it.isSuccessful) {
Log.d("OkHttpBlockstreamExplorer", "$baseAPI/block/$hash")
Log.d("OkHttpBlockstreamExplorer") { "$baseAPI/block/$hash" }
val jsonObject = JacksonMapper.mapper.readTree(it.body.string())
@@ -104,7 +104,7 @@ class OkHttpBitcoinExplorer(
if (it.isSuccessful) {
val blockHash = it.body.string()
Log.d("OkHttpBlockstreamExplorer", "$url $blockHash")
Log.d("OkHttpBlockstreamExplorer") { "$url $blockHash" }
cache.putHeight(height, blockHash)
blockHash
@@ -61,7 +61,7 @@ class NostrClientRepeatSubTest : BaseNostrClientTest() {
msgStr: String,
msg: Message,
) {
Log.d("Test", "Receiving message: $msgStr")
Log.d("Test") { "Receiving message: $msgStr" }
when (msg) {
is EventMessage -> {
if (mySubId == msg.subId) {
@@ -117,7 +117,7 @@ class NostrClientRepeatSubTest : BaseNostrClientTest() {
launch {
withTimeoutOrNull(30000) {
while (events.size < 112) {
Log.d("Test", "Processing message ${events.size}")
Log.d("Test") { "Processing message ${events.size}" }
// simulates an update in the middle of the sub
if (events.size == 1) {
client.subscribe(mySubId, filtersShouldIgnore)
@@ -65,7 +65,7 @@ class NostrClientSubscriptionAsFlowTest : BaseNostrClientTest() {
val job =
launch {
flow.collect {
Log.d("ZZ", "List timestamp deltas ${it.printDates()}")
Log.d("ZZ") { "List timestamp deltas ${it.printDates()}" }
feedStates = it
}
}
@@ -104,7 +104,7 @@ class NostrClientSubscriptionAsFlowTest : BaseNostrClientTest() {
val job =
launch {
flow.debounce(100).collect {
Log.d("ZZ", "List timestamp deltas ${it.printDates()}")
Log.d("ZZ") { "List timestamp deltas ${it.printDates()}" }
feedStates = it
}
}
@@ -65,7 +65,7 @@ class NostrClientSubscriptionUntilEoseAsFlowTest : BaseNostrClientTest() {
val job =
launch {
flow.collect {
Log.d("ZZ", "List timestamp deltas ${it.printDates()}")
Log.d("ZZ") { "List timestamp deltas ${it.printDates()}" }
feedStates = it
}
}
@@ -104,7 +104,7 @@ class NostrClientSubscriptionUntilEoseAsFlowTest : BaseNostrClientTest() {
val job =
launch {
flow.debounce(100).collect {
Log.d("ZZ", "List timestamp deltas ${it.printDates()}")
Log.d("ZZ") { "List timestamp deltas ${it.printDates()}" }
feedStates = it
}
}
@@ -23,47 +23,45 @@ package com.vitorpamplona.quartz.utils
import java.time.LocalTime
import java.time.format.DateTimeFormatter
actual object Log {
// Define a formatter for the desired output format (e.g., HH:mm:ss)
val formatter: DateTimeFormatter? = DateTimeFormatter.ofPattern("HH:mm:ss.SSS")
actual object PlatformLog {
private val formatter = DateTimeFormatter.ofPattern("HH:mm:ss.SSS")
fun time() = LocalTime.now().format(formatter)
private fun time() = LocalTime.now().format(formatter)
private fun log(
level: String,
tag: String,
message: String,
throwable: Throwable?,
) {
if (throwable != null) {
println("${time()} $level: [$tag] $message. Throwable: ${throwable.message}")
} else {
println("${time()} $level: [$tag] $message")
}
}
actual fun w(
tag: String,
message: String,
throwable: Throwable?,
) {
if (throwable != null) {
println("${time()} WARN : [$tag] $message. Throwable: ${throwable.message}")
} else {
println("${time()} WARN : [$tag] $message")
}
}
) = log("WARN ", tag, message, throwable)
actual fun e(
tag: String,
message: String,
throwable: Throwable?,
) {
if (throwable != null) {
println("${time()} ERROR: [$tag] $message. Throwable: ${throwable.message}")
} else {
println("${time()} ERROR: [$tag] $message")
}
}
) = log("ERROR", tag, message, throwable)
actual fun d(
tag: String,
message: String,
) {
println("${time()} DEBUG: [$tag] $message")
}
throwable: Throwable?,
) = log("DEBUG", tag, message, throwable)
actual fun i(
tag: String,
message: String,
) {
println("${time()} INFO : [$tag] $message")
}
throwable: Throwable?,
) = log("INFO ", tag, message, throwable)
}