From cf34be22efb2cb0f364c4681f779c7501777cd76 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Thu, 22 Jan 2026 11:16:20 +0000 Subject: [PATCH 1/4] feat: save app and ldk logs to same file #655 - Both APP and LDK loggers now write to same file (bitkit_.log) - Logs are automatically in chronological order due to shared file - File writes serialized via single-threaded coroutine queue - APP/LDK tag prefixes distinguish log sources --- app/src/main/java/to/bitkit/utils/Logger.kt | 24 +++++++++++++-------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/to/bitkit/utils/Logger.kt b/app/src/main/java/to/bitkit/utils/Logger.kt index 1b0ddbdad..226a790b9 100644 --- a/app/src/main/java/to/bitkit/utils/Logger.kt +++ b/app/src/main/java/to/bitkit/utils/Logger.kt @@ -37,6 +37,15 @@ val Logger = AppLogger() class AppLogger(private val source: LogSource = LogSource.Bitkit) { companion object { private const val TAG = "Logger" + private var saver: LogSaver? = null + + fun getOrCreateSaver(): LogSaver { + if (saver == null) { + val sessionPath = runCatching { buildSessionLogFilePath() }.getOrElse { "" } + saver = LogSaverImpl(sessionPath) + } + return requireNotNull(saver) { "saver should be initialized" } + } } private var delegate: LoggerImpl? = null @@ -46,13 +55,13 @@ class AppLogger(private val source: LogSource = LogSource.Bitkit) { } private fun createDelegate(): LoggerImpl { - val sessionPath = runCatching { buildSessionLogFilePath(source) }.getOrElse { "" } - return LoggerImpl(APP, LogSaverImpl(source, sessionPath)) + return LoggerImpl(APP, getOrCreateSaver()) } fun reset() { warn("Wiping entire logs directory…", context = TAG) runCatching { Env.logDir.deleteRecursively() } + saver = null delegate = runCatching { createDelegate() }.getOrNull() } @@ -198,7 +207,6 @@ interface LogSaver { } class LogSaverImpl( - source: LogSource, private val sessionFilePath: String, ) : LogSaver { private val queue: CoroutineScope by lazy { @@ -207,7 +215,7 @@ class LogSaverImpl( init { if (sessionFilePath.isNotEmpty()) { - log("Log session for '${source.name}' initialized with file path: '$sessionFilePath'") + log("Log session initialized with file path: '$sessionFilePath'") // Clean all old log files in background CoroutineScope(Dispatchers.IO).launch { @@ -273,8 +281,7 @@ class LogSaverImpl( class LdkLogWriter( private val maxLogLevel: LdkLogLevel = Env.ldkLogLevel, - private val source: LogSource = LogSource.Ldk, - saver: LogSaver = LogSaverImpl(source, buildSessionLogFilePath(source)), + saver: LogSaver = AppLogger.getOrCreateSaver(), ) : LogWriter { private val delegate: LoggerImpl = LoggerImpl(LDK, saver) @@ -296,11 +303,10 @@ class LdkLogWriter( } } -private fun buildSessionLogFilePath(source: LogSource): String { +private fun buildSessionLogFilePath(): String { val logDir = Env.logDir - val sourceName = source.name.lowercase() val timestamp = utcDateFormatterOf(DatePattern.LOG_FILE).format(Date()) - val path = logDir.resolve("${sourceName}_$timestamp.log").path + val path = logDir.resolve("bitkit_$timestamp.log").path return path } From 13b3376e8a69840a6db941a1e5a71fe4787351c3 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 22 Jan 2026 21:31:12 +0100 Subject: [PATCH 2/4] fix: allow claude bot to trigger code review workflow Co-Authored-By: Claude Opus 4.5 --- .github/workflows/claude-code-review.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index 1110b6680..15238d635 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -56,7 +56,11 @@ jobs: uses: anthropics/claude-code-action@v1 with: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} - # use_sticky_comment: "true" # doesn't work + # use_sticky_comment: "true" # doesn't work plugin_marketplaces: 'https://github.com/anthropics/claude-code.git' plugins: 'code-review@claude-code-plugins' prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}' + # Allow Claude bot to trigger this workflow + allowed_bots: 'claude[bot]' + # Allow Claude to use GH CLI for reading external PR details and fetch web content + claude_args: '--allowed-tools Bash(gh:*) WebFetch' From 778ca10cc3801034fd05479f56d758c79a5efe66 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 22 Jan 2026 22:34:02 +0100 Subject: [PATCH 3/4] fix: sanitize newlines in saved log messages Co-Authored-By: Claude Opus 4.5 --- app/src/main/java/to/bitkit/utils/Logger.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/to/bitkit/utils/Logger.kt b/app/src/main/java/to/bitkit/utils/Logger.kt index 226a790b9..cca51ca7f 100644 --- a/app/src/main/java/to/bitkit/utils/Logger.kt +++ b/app/src/main/java/to/bitkit/utils/Logger.kt @@ -229,8 +229,9 @@ class LogSaverImpl( queue.launch { runCatching { + val sanitized = message.replace("\n", " ") FileOutputStream(File(sessionFilePath), true).use { stream -> - stream.write("$message\n".toByteArray()) + stream.write("$sanitized\n".toByteArray()) } }.onFailure { Log.e(APP, "Error writing to log file: '$sessionFilePath'", it) From 05314d4f329afccf7f19f6ebe439cc5ed0277a68 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Fri, 23 Jan 2026 10:24:10 +0000 Subject: [PATCH 4/4] refactor: remove unused source param, make LoggerImpl private Co-authored-by: Ovi Trif --- app/src/main/java/to/bitkit/utils/Logger.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/to/bitkit/utils/Logger.kt b/app/src/main/java/to/bitkit/utils/Logger.kt index cca51ca7f..89d1ca08e 100644 --- a/app/src/main/java/to/bitkit/utils/Logger.kt +++ b/app/src/main/java/to/bitkit/utils/Logger.kt @@ -34,7 +34,7 @@ enum class LogLevel { PERF, VERBOSE, GOSSIP, TRACE, DEBUG, INFO, WARN, ERROR; } val Logger = AppLogger() -class AppLogger(private val source: LogSource = LogSource.Bitkit) { +class AppLogger { companion object { private const val TAG = "Logger" private var saver: LogSaver? = null @@ -123,7 +123,7 @@ class AppLogger(private val source: LogSource = LogSource.Bitkit) { } } -class LoggerImpl( +private class LoggerImpl( private val tag: String = APP, private val saver: LogSaver, private val compact: Boolean = COMPACT,