[console/logging] Introduce LoggerControlState for optimize performance

This commit is contained in:
Karlatemp 2022-11-08 22:50:48 +08:00 committed by Him188
parent 4962f1907e
commit 8a07308a56
6 changed files with 145 additions and 11 deletions

View File

@ -270,6 +270,9 @@ ___ ____ _ _____ _
consoleDataScope.addAndReloadConfig(loggerController.loggerConfig)
}
consoleDataScope.reloadAll()
if (loggerController is LoggerControllerImpl) {
loggerController.onReload()
}
}
phase("initialize all plugins") {

View File

@ -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) {

View File

@ -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)
}
}

View File

@ -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] 对应

View File

@ -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
}
}

View File

@ -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)
}
}
}