From 8a07308a56f7e49c647a65adea23996a20179ee8 Mon Sep 17 00:00:00 2001 From: Karlatemp Date: Tue, 8 Nov 2022 22:50:48 +0800 Subject: [PATCH] [console/logging] Introduce `LoggerControlState` for optimize performance --- .../MiraiConsoleImplementationBridge.kt | 3 + .../internal/logging/LoggerControllerImpl.kt | 5 ++ .../internal/logging/MiraiConsoleLogger.kt | 24 +++---- .../src/logging/AbstractLoggerController.kt | 38 +++++++++++ .../src/logging/LoggerController.kt | 20 ++++++ .../mirai-console/test/logging/TestALC.kt | 66 +++++++++++++++++++ 6 files changed, 145 insertions(+), 11 deletions(-) create mode 100644 mirai-console/backend/mirai-console/test/logging/TestALC.kt diff --git a/mirai-console/backend/mirai-console/src/internal/MiraiConsoleImplementationBridge.kt b/mirai-console/backend/mirai-console/src/internal/MiraiConsoleImplementationBridge.kt index ce6769a92..53662d4ac 100644 --- a/mirai-console/backend/mirai-console/src/internal/MiraiConsoleImplementationBridge.kt +++ b/mirai-console/backend/mirai-console/src/internal/MiraiConsoleImplementationBridge.kt @@ -270,6 +270,9 @@ ___ ____ _ _____ _ consoleDataScope.addAndReloadConfig(loggerController.loggerConfig) } consoleDataScope.reloadAll() + if (loggerController is LoggerControllerImpl) { + loggerController.onReload() + } } phase("initialize all plugins") { diff --git a/mirai-console/backend/mirai-console/src/internal/logging/LoggerControllerImpl.kt b/mirai-console/backend/mirai-console/src/internal/logging/LoggerControllerImpl.kt index 4c6e1f745..f9935e7f6 100644 --- a/mirai-console/backend/mirai-console/src/internal/logging/LoggerControllerImpl.kt +++ b/mirai-console/backend/mirai-console/src/internal/logging/LoggerControllerImpl.kt @@ -18,6 +18,11 @@ internal class LoggerControllerImpl : AbstractLoggerController.PathBased() { internal val loggerConfig: LoggerConfig by lazy { LoggerConfig() } + override val isLoggerControlStateSupported: Boolean get() = true + + internal fun onReload() { + this.loggerConfigUpdateTime++ + } override fun findPriority(identity: String?): LogPriority? { return if (identity == null) { diff --git a/mirai-console/backend/mirai-console/src/internal/logging/MiraiConsoleLogger.kt b/mirai-console/backend/mirai-console/src/internal/logging/MiraiConsoleLogger.kt index 9d7e8cb6a..f8967bc4c 100644 --- a/mirai-console/backend/mirai-console/src/internal/logging/MiraiConsoleLogger.kt +++ b/mirai-console/backend/mirai-console/src/internal/logging/MiraiConsoleLogger.kt @@ -15,45 +15,47 @@ import net.mamoe.mirai.utils.MiraiLoggerPlatformBase import net.mamoe.mirai.utils.SimpleLogger internal class MiraiConsoleLogger( - private val controller: LoggerController, + controller: LoggerController, val logger: MiraiLogger ) : MiraiLoggerPlatformBase() { override val identity: String? get() = logger.identity override val isEnabled: Boolean get() = logger.isEnabled + private val logState = controller.getLoggerControlState(identity) + override val isInfoEnabled: Boolean - get() = controller.shouldLog(identity, SimpleLogger.LogPriority.INFO) + get() = logState.shouldLog(SimpleLogger.LogPriority.INFO) override val isWarningEnabled: Boolean - get() = controller.shouldLog(identity, SimpleLogger.LogPriority.WARNING) + get() = logState.shouldLog(SimpleLogger.LogPriority.WARNING) override val isDebugEnabled: Boolean - get() = controller.shouldLog(identity, SimpleLogger.LogPriority.DEBUG) + get() = logState.shouldLog(SimpleLogger.LogPriority.DEBUG) override val isErrorEnabled: Boolean - get() = controller.shouldLog(identity, SimpleLogger.LogPriority.ERROR) + get() = logState.shouldLog(SimpleLogger.LogPriority.ERROR) override val isVerboseEnabled: Boolean - get() = controller.shouldLog(identity, SimpleLogger.LogPriority.VERBOSE) + get() = logState.shouldLog(SimpleLogger.LogPriority.VERBOSE) override fun info0(message: String?, e: Throwable?) { - if (controller.shouldLog(identity, SimpleLogger.LogPriority.INFO)) + if (logState.shouldLog(SimpleLogger.LogPriority.INFO)) logger.info(message, e) } override fun warning0(message: String?, e: Throwable?) { - if (controller.shouldLog(identity, SimpleLogger.LogPriority.WARNING)) + if (logState.shouldLog(SimpleLogger.LogPriority.WARNING)) logger.warning(message, e) } override fun debug0(message: String?, e: Throwable?) { - if (controller.shouldLog(identity, SimpleLogger.LogPriority.DEBUG)) + if (logState.shouldLog(SimpleLogger.LogPriority.DEBUG)) logger.debug(message, e) } override fun error0(message: String?, e: Throwable?) { - if (controller.shouldLog(identity, SimpleLogger.LogPriority.ERROR)) + if (logState.shouldLog(SimpleLogger.LogPriority.ERROR)) logger.error(message, e) } override fun verbose0(message: String?, e: Throwable?) { - if (controller.shouldLog(identity, SimpleLogger.LogPriority.VERBOSE)) + if (logState.shouldLog(SimpleLogger.LogPriority.VERBOSE)) logger.verbose(message, e) } } diff --git a/mirai-console/backend/mirai-console/src/logging/AbstractLoggerController.kt b/mirai-console/backend/mirai-console/src/logging/AbstractLoggerController.kt index 451b60375..6bae18946 100644 --- a/mirai-console/backend/mirai-console/src/logging/AbstractLoggerController.kt +++ b/mirai-console/backend/mirai-console/src/logging/AbstractLoggerController.kt @@ -36,6 +36,44 @@ public abstract class AbstractLoggerController : LoggerController { override fun shouldLog(identity: String?, priority: SimpleLogger.LogPriority): Boolean = shouldLog(LogPriority.by(priority), getPriority(identity)) + // region LoggerControlState support + protected open val isLoggerControlStateSupported: Boolean get() = false + + @Volatile + @Transient + @JvmField + protected var loggerConfigUpdateTime: Long = 0L + + override fun getLoggerControlState(identity: String?): LoggerController.LoggerControlState { + if (isLoggerControlStateSupported) { + return object : LoggerController.LoggerControlState { + private val status = BitSet(SimpleLogger.LogPriority.values().size) + + @Volatile + @Transient + private var lastUpdateTime = -1L + + override fun shouldLog(priority: SimpleLogger.LogPriority): Boolean { + if (lastUpdateTime != loggerConfigUpdateTime) { + updateProperties() + } + return status[priority.ordinal] + } + + @Synchronized + private fun updateProperties() { + lastUpdateTime = loggerConfigUpdateTime + SimpleLogger.LogPriority.values().forEach { prio -> + status.set(prio.ordinal, shouldLog(identity, prio)) + } + } + + } + } + return super.getLoggerControlState(identity) + } + // endregion + /** * 便于进行配置存储的 [LogPriority], * 等级优先级与 [SimpleLogger.LogPriority] 对应 diff --git a/mirai-console/backend/mirai-console/src/logging/LoggerController.kt b/mirai-console/backend/mirai-console/src/logging/LoggerController.kt index d8b634b11..bb937d3b1 100644 --- a/mirai-console/backend/mirai-console/src/logging/LoggerController.kt +++ b/mirai-console/backend/mirai-console/src/logging/LoggerController.kt @@ -12,6 +12,7 @@ package net.mamoe.mirai.console.logging import net.mamoe.mirai.console.MiraiConsoleImplementation import net.mamoe.mirai.console.internal.logging.MiraiConsoleLogger import net.mamoe.mirai.console.util.ConsoleExperimentalApi +import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.SimpleLogger /** @@ -26,4 +27,23 @@ public interface LoggerController { /** 是否应该记录该等级的日志 */ public fun shouldLog(identity: String?, priority: SimpleLogger.LogPriority): Boolean + public fun getLoggerControlState(identity: String?): LoggerControlState { + return object : LoggerControlState { + override fun shouldLog(priority: SimpleLogger.LogPriority): Boolean { + return shouldLog(identity, priority) + } + } + } + + /** + * 一个 [MiraiLogger] 的日志开关状态 + * + * 这个类可以缓存 [LoggerController.shouldLog] 的结果, 避免多次查询 + * + * 在需要的时候会自动更新, 所以不需要手动更换 [LoggerControlState] + */ + @ConsoleExperimentalApi + public interface LoggerControlState { + public fun shouldLog(priority: SimpleLogger.LogPriority): Boolean + } } diff --git a/mirai-console/backend/mirai-console/test/logging/TestALC.kt b/mirai-console/backend/mirai-console/test/logging/TestALC.kt new file mode 100644 index 000000000..65ab28b44 --- /dev/null +++ b/mirai-console/backend/mirai-console/test/logging/TestALC.kt @@ -0,0 +1,66 @@ +/* + * Copyright 2019-2022 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/dev/LICENSE + */ + +package net.mamoe.mirai.console.logging + +import net.mamoe.mirai.utils.SimpleLogger +import org.junit.jupiter.api.Test +import kotlin.test.assertEquals + +internal class TestALC { + private class TestController( + override val isLoggerControlStateSupported: Boolean, + ) : AbstractLoggerController() { + var callcount = 0 + + + override fun getPriority(identity: String?): LogPriority { + return LogPriority.ALL + } + + override fun shouldLog(identity: String?, priority: SimpleLogger.LogPriority): Boolean { + if (priority == SimpleLogger.LogPriority.INFO) { + callcount++ + } + return super.shouldLog(identity, priority) + } + } + + @Test + fun `test logger control state caching`() { + val controller = TestController(true) + assertEquals(0, controller.callcount) + val state = controller.getLoggerControlState("Test") + assertEquals(0, controller.callcount) // lazy load + + state.shouldLog(SimpleLogger.LogPriority.DEBUG) + assertEquals(1, controller.callcount) + + state.shouldLog(SimpleLogger.LogPriority.INFO) + assertEquals(1, controller.callcount) + + state.shouldLog(SimpleLogger.LogPriority.DEBUG) + state.shouldLog(SimpleLogger.LogPriority.INFO) + state.shouldLog(SimpleLogger.LogPriority.INFO) + assertEquals(1, controller.callcount) + } + + @Test + fun `test keep binary compatibility`() { + val controller = TestController(false) + assertEquals(0, controller.callcount) + val state = controller.getLoggerControlState("Test") + assertEquals(0, controller.callcount) + + repeat(50) { count -> + state.shouldLog(SimpleLogger.LogPriority.INFO) + assertEquals(count + 1, controller.callcount) + } + } +} \ No newline at end of file