[core+console] Improve logging hierarchy: (#2196)

- always use factory API from mirai-core
- Terminal is still overriding standard outputs
- plugins are forbidden to override logging framework (this was allowed but not working before)
This commit is contained in:
Him188 2022-08-27 18:46:16 +08:00 committed by GitHub
parent 2d393ee0b0
commit f0651c81c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 314 additions and 127 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
* 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.
@ -7,6 +7,8 @@
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
package net.mamoe.mirai.utils.logging
import io.ktor.client.*
@ -20,18 +22,6 @@ import kotlin.test.assertFalse
import kotlin.test.assertIs
internal class MiraiLog4JAdapterTest {
@Suppress("DEPRECATION_ERROR")
@Test
fun `services prevail than legacy overrides`() {
MiraiLogger.setDefaultLoggerCreator {
net.mamoe.mirai.utils.SimpleLogger("my logger") { _: String?, _: Throwable? -> }
}
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
assertIs<net.mamoe.mirai.internal.utils.Log4jLoggerAdapter>(MiraiLogger.Factory.create(this::class))
}
@Test
fun `using log4j`() {
assertIs<MiraiLog4JFactory>(loadService(MiraiLogger.Factory::class))

View File

@ -128,8 +128,17 @@ public interface MiraiConsole : CoroutineScope {
get() = throw UnsupportedOperationException("PluginCenter is not supported yet")
/**
* 创建一个 logger
* 创建一个 logger. 已弃用. 请使用 [MiraiLogger.Factory.create].
*/
@Deprecated(
"Please use the standard way in mirai-core to create loggers, i.e. MiraiLogger.Factory.INSTANCE.create()",
level = DeprecationLevel.WARNING,
replaceWith = ReplaceWith(
"MiraiLogger.Factory.create(yourClass::class, identity)",
"net.mamoe.mirai.utils.MiraiLogger"
),
)
@DeprecatedSinceMirai(warningSince = "2.13")
@ConsoleExperimentalApi
public fun createLogger(identity: String?): MiraiLogger
@ -204,6 +213,7 @@ public interface MiraiConsole : CoroutineScope {
mainLogger.verbose { "Renaming $deviceInfoInWorkingDir to $deviceInWorkingDir" }
deviceInfoInWorkingDir.renameTo(deviceInWorkingDir)
}
deviceInRoot.exists() -> {
// copy root/device.json to bots/id/device.json
mainLogger.verbose { "Coping $deviceInRoot to $deviceInWorkingDir" }

View File

@ -37,10 +37,7 @@ import net.mamoe.mirai.console.plugin.loader.PluginLoader
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import net.mamoe.mirai.console.util.ConsoleInput
import net.mamoe.mirai.message.data.Message
import net.mamoe.mirai.utils.BotConfiguration
import net.mamoe.mirai.utils.LoginSolver
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.NotStableForInheritance
import net.mamoe.mirai.utils.*
import java.nio.file.Path
import java.util.*
import java.util.concurrent.locks.ReentrantLock
@ -216,9 +213,14 @@ public interface MiraiConsoleImplementation : CoroutineScope {
/**
* 创建一个 [MiraiLogger].
*
* **注意**: [MiraiConsole] 会将 [net.mamoe.mirai.utils.MiraiLogger.setDefaultLoggerCreator] 设置为 `MiraiConsole::createLogger`.
* **注意**: [MiraiConsole] 会将 [net.mamoe.mirai.utils.MiraiLogger.Factory] 设置为 `MiraiConsole::createLogger`.
* 因此不要在 [createLogger] 中调用 [net.mamoe.mirai.utils.MiraiLogger.create]
*/
@Deprecated(
"Deprecated for removal. Implement the other overload, or use MiraiConsole.createLogger instead.",
level = DeprecationLevel.ERROR
)
@DeprecatedSinceMirai(errorSince = "2.13")
public fun createLogger(identity: String?): MiraiLogger
/** @see [MiraiConsole.newProcessProgress] */
@ -226,6 +228,16 @@ public interface MiraiConsoleImplementation : CoroutineScope {
return DefaultLoggingProcessProgress()
}
/**
* 创建一个 [MiraiLogger.Factory]. 在返回的实例中必须调用 [platformImplementation] 来适配平台日志实现.
*
* @param platformImplementation 平台的日志实现, 这可能是使用 SLF4J 等日志框架转接的实例.
*
* @since 2.13
*/
public fun createLoggerFactory(platformImplementation: MiraiLogger.Factory): MiraiLogger.Factory
/**
* 该前端是否支持使用 Ansi 输出彩色信息
*

View File

@ -59,9 +59,9 @@ import net.mamoe.mirai.utils.*
import java.time.Instant
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.reflect.KClass
import kotlin.reflect.KProperty
import kotlin.reflect.KProperty0
@ -100,22 +100,49 @@ internal class MiraiConsoleImplementationBridge(
externalImplementation.loggerController
}
override val mainLogger: MiraiLogger by lazy { createLogger("main") }
override val mainLogger: MiraiLogger by lazy { MiraiLogger.Factory.create(MiraiConsole::class, "main") }
init {
// TODO: Replace to standard api
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
DefaultFactoryOverrides.override { requester, identity ->
return@override createLogger(
identity ?: requester.kotlin.simpleName ?: requester.simpleName
)
/**
* Delegates the [platformImplementation] with [loggerController].
*/
private inner class ControlledLoggerFactory(
private val platformImplementation: MiraiLogger.Factory,
) : MiraiLogger.Factory {
override fun create(requester: KClass<*>, identity: String?): MiraiLogger {
return MiraiConsoleLogger(loggerController, platformImplementation.create(requester, identity))
}
override fun create(requester: Class<*>, identity: String?): MiraiLogger {
return MiraiConsoleLogger(loggerController, platformImplementation.create(requester, identity))
}
}
init {
// When writing a log:
// 1. ControlledLoggerFactory checks if that log level is enabled
// 2. ... if enabled, goto 3
// ... if not, return
// 3. [externalImplementation] decides how to log the message
// 4. [externalImplementation] outputs by using [platform]
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
MiraiLoggerFactoryImplementationBridge.wrapCurrent { platform ->
ControlledLoggerFactory(externalImplementation.createLoggerFactory(platform))
}
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
MiraiLoggerFactoryImplementationBridge.freeze() // forbid any further overrides
}
@Deprecated(
"Please use the standard way in mirai-core to create loggers, i.e. MiraiLogger.Factory.INSTANCE.create()",
replaceWith = ReplaceWith(
"MiraiLogger.Factory.create(yourClass::class, identity)",
"net.mamoe.mirai.utils.MiraiLogger"
),
level = DeprecationLevel.WARNING
)
override fun createLogger(identity: String?): MiraiLogger {
val controller = loggerController
return MiraiConsoleLogger(controller, externalImplementation.createLogger(identity))
return MiraiLogger.Factory.create(MiraiConsole::class, identity)
}
@Suppress("RemoveRedundantBackticks")
@ -286,6 +313,7 @@ internal class MiraiConsoleImplementationBridge(
PLAIN -> {
MiraiConsole.addBot(id, account.password.value, BotConfiguration::configBot)
}
MD5 -> {
val md5 = kotlin.runCatching {
account.password.value.hexToBytes()
@ -339,4 +367,5 @@ internal class MiraiConsoleImplementationBridge(
override fun postPhase(phase: String) {
externalImplementation.postPhase(phase)
}
}
}

View File

@ -11,7 +11,6 @@ package net.mamoe.mirai.console.internal.command
import kotlinx.atomicfu.locks.withLock
import kotlinx.coroutines.CoroutineScope
import net.mamoe.mirai.console.MiraiConsole
import net.mamoe.mirai.console.MiraiConsoleImplementation.ConsoleDataScope.Companion.get
import net.mamoe.mirai.console.command.*
import net.mamoe.mirai.console.command.Command.Companion.allNames
@ -37,7 +36,7 @@ internal class CommandManagerImpl(
parentCoroutineContext: CoroutineContext
) : CommandManager, CoroutineScope by parentCoroutineContext.childScope("CommandManagerImpl") {
private val logger: MiraiLogger by lazy {
MiraiConsole.createLogger("command")
MiraiLogger.Factory.create(CommandManager::class, "command")
}
@Suppress("ObjectPropertyName")

View File

@ -41,7 +41,8 @@ internal class BuiltInJvmPluginLoaderImpl(
JvmPluginLoader {
companion object {
internal val logger: MiraiLogger = MiraiConsole.createLogger(JvmPluginLoader::class.simpleName!!)
internal val logger: MiraiLogger =
MiraiLogger.Factory.create(JvmPluginLoader::class)
}
fun pluginsFilesSequence(

View File

@ -10,7 +10,6 @@
package net.mamoe.mirai.console.internal.plugin
import net.mamoe.mirai.console.MiraiConsole
import net.mamoe.mirai.console.plugin.jvm.ExportManager
import net.mamoe.mirai.console.plugin.jvm.JvmPluginClasspath
import net.mamoe.mirai.utils.*
@ -197,7 +196,12 @@ internal class JvmPluginClassLoaderN : URLClassLoader {
private val file_: File
get() = file
var linkedLogger by lateinitMutableProperty { MiraiConsole.createLogger("JvmPlugin[" + file_.name + "]") }
var linkedLogger by lateinitMutableProperty {
MiraiLogger.Factory.create(
JvmPluginClassLoaderN::class,
"JvmPlugin[" + file_.name + "]"
)
}
val undefinedDependencies = mutableSetOf<String>()
@Suppress("UNUSED_PARAMETER")

View File

@ -65,7 +65,7 @@ internal abstract class JvmPluginInternal(
// region JvmPlugin
final override val logger: MiraiLogger by lazy {
BuiltInJvmPluginLoaderImpl.logger.runCatchingLog {
MiraiConsole.createLogger(this.description.name)
MiraiLogger.Factory.create(this@JvmPluginInternal::class, this.description.name)
}.getOrThrow()
}

View File

@ -26,10 +26,7 @@ import net.mamoe.mirai.console.plugin.loader.PluginLoadException
import net.mamoe.mirai.console.plugin.loader.PluginLoader
import net.mamoe.mirai.console.plugin.name
import net.mamoe.mirai.console.util.SemVersion
import net.mamoe.mirai.utils.TestOnly
import net.mamoe.mirai.utils.cast
import net.mamoe.mirai.utils.childScope
import net.mamoe.mirai.utils.info
import net.mamoe.mirai.utils.*
import java.io.File
import java.nio.file.Path
import java.util.concurrent.CopyOnWriteArrayList
@ -60,7 +57,7 @@ internal class PluginManagerImpl(
builtInLoaders.toMutableList()
}
private val logger = MiraiConsole.createLogger("plugin")
private val logger = MiraiLogger.Factory.create(PluginManager::class, "plugin")
@JvmField
internal val resolvedPlugins: MutableList<Plugin> =

View File

@ -22,6 +22,11 @@ import org.junit.jupiter.api.AfterEach
import kotlin.test.BeforeTest
abstract class AbstractConsoleInstanceTest {
init {
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
net.mamoe.mirai.utils.MiraiLoggerFactoryImplementationBridge.reinit()
}
val mockPlugin by lazy { mockKotlinPlugin() }
private lateinit var implementation: MiraiConsoleImplementation
val consoleImplementation: MiraiConsoleImplementation by ::implementation

View File

@ -76,10 +76,23 @@ open class MockConsoleImplementation : MiraiConsoleImplementation {
override fun createLoginSolver(requesterBot: Long, configuration: BotConfiguration): LoginSolver =
LoginSolver.Default!!
@Suppress("DeprecatedCallableAddReplaceWith")
@Deprecated(
"Deprecated for removal. Implement the other overload, or use MiraiConsole.createLogger instead.",
level = DeprecationLevel.ERROR
)
override fun createLogger(identity: String?): MiraiLogger {
return PlatformLogger(identity)
}
override fun createLoggerFactory(platformImplementation: MiraiLogger.Factory): MiraiLogger.Factory {
return object : MiraiLogger.Factory {
override fun create(requester: Class<*>, identity: String?): MiraiLogger {
return PlatformLogger(identity)
}
}
}
override val consoleDataScope: MiraiConsoleImplementation.ConsoleDataScope by lazy {
MiraiConsoleImplementation.ConsoleDataScope.createDefault(
coroutineContext,

View File

@ -1,10 +1,10 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
* 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.
* 此源代码的使用受 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/master/LICENSE
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
@file:Suppress(
@ -55,6 +55,7 @@ import java.nio.file.Path
import java.nio.file.Paths
import kotlin.concurrent.withLock
import kotlin.coroutines.Continuation
import kotlin.reflect.KClass
import kotlin.reflect.KProperty
/**
@ -102,14 +103,45 @@ open class MiraiConsoleImplementationTerminal
return StandardCharImageLoginSolver(input = { requestInput("LOGIN> ") })
}
@Suppress("DeprecatedCallableAddReplaceWith")
@Deprecated(
"Deprecated for removal. Implement the other overload, or use MiraiConsole.createLogger instead.",
level = DeprecationLevel.ERROR
)
override fun createLogger(identity: String?): MiraiLogger {
return PlatformLogger(identity = identity, output = { line ->
val text = line + ANSI_RESET
prePrintNewLog()
lineReader.printAbove(text)
postPrintNewLog()
logService.pushLine(text)
})
return MiraiLogger.Factory.create(MiraiConsoleImplementationTerminal::class, identity)
// return PlatformLogger(identity = identity, output = { line ->
// val text = line + ANSI_RESET
// lineReader.printAbove(text)
// logService.pushLine(text)
// })
}
override fun createLoggerFactory(platformImplementation: MiraiLogger.Factory): MiraiLogger.Factory {
// platformImplementation is not used by Terminal
return object : MiraiLogger.Factory {
override fun create(requester: Class<*>, identity: String?): MiraiLogger {
return PlatformLogger(identity = identity ?: requester.simpleName, output = { line ->
val text = line + ANSI_RESET
prePrintNewLog()
lineReader.printAbove(text)
postPrintNewLog()
logService.pushLine(text)
})
}
override fun create(requester: KClass<*>, identity: String?): MiraiLogger {
return PlatformLogger(identity = identity ?: requester.simpleName, output = { line ->
val text = line + ANSI_RESET
prePrintNewLog()
lineReader.printAbove(text)
postPrintNewLog()
logService.pushLine(text)
})
}
}
}
init {

View File

@ -1,10 +1,10 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
* 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.
* 此源代码的使用受 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/master/LICENSE
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
@file:Suppress(
@ -28,10 +28,7 @@ import net.mamoe.mirai.console.terminal.noconsole.SystemOutputPrintStream
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import net.mamoe.mirai.console.util.ConsoleInternalApi
import net.mamoe.mirai.message.data.Message
import net.mamoe.mirai.utils.childScope
import net.mamoe.mirai.utils.debug
import net.mamoe.mirai.utils.info
import net.mamoe.mirai.utils.verbose
import net.mamoe.mirai.utils.*
import org.jline.utils.Signals
import java.io.FileDescriptor
import java.io.FileOutputStream
@ -48,6 +45,9 @@ import kotlin.system.exitProcess
* mirai-console-terminal CLI 入口点
*/
object MiraiConsoleTerminalLoader {
// Note: Do not run this in IDEA, as you will get invalid classpath and `java.lang.NoClassDefFoundError`.
// Run `RunTerminal.kt` under `test` source set instead.
@JvmStatic
fun main(args: Array<String>) {
parse(args, exitProcess = true)
@ -123,19 +123,24 @@ object MiraiConsoleTerminalLoader {
if (exitProcess) exitProcess(0)
return
}
"--no-console" -> {
ConsoleTerminalSettings.noConsole = true
}
"--dont-setup-terminal-ansi" -> {
ConsoleTerminalSettings.setupAnsi = false
}
"--no-logging" -> {
ConsoleTerminalSettings.noLogging = true
}
"--no-ansi" -> {
ConsoleTerminalSettings.noAnsi = true
ConsoleTerminalSettings.setupAnsi = false
}
"--reading-replacement" -> {
ConsoleTerminalSettings.noConsoleSafeReading = true
if (iterator.hasNext()) {
@ -148,9 +153,11 @@ object MiraiConsoleTerminalLoader {
return
}
}
"--safe-reading" -> {
ConsoleTerminalSettings.noConsoleSafeReading = true
}
else -> {
println("Unknown option `$option`")
printHelpMessage()
@ -287,7 +294,7 @@ internal fun overrideSTD(terminal: MiraiConsoleImplementation) {
System.setOut(
PrintStream(
BufferedOutputStream(
logger = terminal.createLogger("stdout")::info
logger = MiraiLogger.Factory.create(terminal::class, "stdout")::info
),
false,
"UTF-8"
@ -296,7 +303,7 @@ internal fun overrideSTD(terminal: MiraiConsoleImplementation) {
System.setErr(
PrintStream(
BufferedOutputStream(
logger = terminal.createLogger("stderr")::warning
logger = MiraiLogger.Factory.create(terminal::class, "stderr")::warning
),
false,
"UTF-8"

View File

@ -6162,7 +6162,7 @@ public abstract interface class net/mamoe/mirai/utils/MiraiLogger {
public fun isVerboseEnabled ()Z
public fun isWarningEnabled ()Z
public synthetic fun plus (Lnet/mamoe/mirai/utils/MiraiLogger;)Lnet/mamoe/mirai/utils/MiraiLogger;
public static fun setDefaultLoggerCreator (Lkotlin/jvm/functions/Function1;)V
public static synthetic fun setDefaultLoggerCreator (Lkotlin/jvm/functions/Function1;)V
public synthetic fun setFollower (Lnet/mamoe/mirai/utils/MiraiLogger;)V
public abstract fun verbose (Ljava/lang/String;)V
public abstract fun verbose (Ljava/lang/String;Ljava/lang/Throwable;)V
@ -6175,7 +6175,7 @@ public abstract interface class net/mamoe/mirai/utils/MiraiLogger {
public final class net/mamoe/mirai/utils/MiraiLogger$Companion {
public final synthetic fun create (Ljava/lang/String;)Lnet/mamoe/mirai/utils/MiraiLogger;
public final synthetic fun getTopLevel ()Lnet/mamoe/mirai/utils/MiraiLogger;
public final fun setDefaultLoggerCreator (Lkotlin/jvm/functions/Function1;)V
public final synthetic fun setDefaultLoggerCreator (Lkotlin/jvm/functions/Function1;)V
}
public abstract interface class net/mamoe/mirai/utils/MiraiLogger$Factory {

View File

@ -6162,7 +6162,7 @@ public abstract interface class net/mamoe/mirai/utils/MiraiLogger {
public fun isVerboseEnabled ()Z
public fun isWarningEnabled ()Z
public synthetic fun plus (Lnet/mamoe/mirai/utils/MiraiLogger;)Lnet/mamoe/mirai/utils/MiraiLogger;
public static fun setDefaultLoggerCreator (Lkotlin/jvm/functions/Function1;)V
public static synthetic fun setDefaultLoggerCreator (Lkotlin/jvm/functions/Function1;)V
public synthetic fun setFollower (Lnet/mamoe/mirai/utils/MiraiLogger;)V
public abstract fun verbose (Ljava/lang/String;)V
public abstract fun verbose (Ljava/lang/String;Ljava/lang/Throwable;)V
@ -6175,7 +6175,7 @@ public abstract interface class net/mamoe/mirai/utils/MiraiLogger {
public final class net/mamoe/mirai/utils/MiraiLogger$Companion {
public final synthetic fun create (Ljava/lang/String;)Lnet/mamoe/mirai/utils/MiraiLogger;
public final synthetic fun getTopLevel ()Lnet/mamoe/mirai/utils/MiraiLogger;
public final fun setDefaultLoggerCreator (Lkotlin/jvm/functions/Function1;)V
public final synthetic fun setDefaultLoggerCreator (Lkotlin/jvm/functions/Function1;)V
}
public abstract interface class net/mamoe/mirai/utils/MiraiLogger$Factory {

View File

@ -32,9 +32,16 @@ public object LoggerAdapters {
*/
@JvmStatic
public fun useLog4j2() {
DefaultFactoryOverrides.override { requester, identity ->
val logger = LogManager.getLogger(requester)
Log4jLoggerAdapter(logger, MarkerManager.getMarker(identity ?: logger.name).addParents(MARKER_MIRAI))
MiraiLoggerFactoryImplementationBridge.wrapCurrent {
object : MiraiLogger.Factory {
override fun create(requester: Class<*>, identity: String?): MiraiLogger {
val logger = LogManager.getLogger(requester)
return Log4jLoggerAdapter(
logger,
MarkerManager.getMarker(identity ?: logger.name).addParents(MARKER_MIRAI)
)
}
}
}
}

View File

@ -12,8 +12,13 @@
package net.mamoe.mirai.utils
import kotlinx.atomicfu.atomic
import kotlinx.atomicfu.loop
import me.him188.kotlin.dynamic.delegation.dynamicDelegation
import net.mamoe.mirai.utils.*
import java.util.*
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.reflect.KClass
/**
@ -27,7 +32,7 @@ import kotlin.reflect.KClass
*
* ## 使用第三方日志库接管 Mirai 日志系统
*
* 使用 [LoggerAdapters], 将第三方日志 `Logger` 转为 [MiraiLogger]. 然后通过 [MiraiLogger.setDefaultLoggerCreator] 全局覆盖日志.
* 使用 [LoggerAdapters], 将第三方日志 `Logger` 转为 [MiraiLogger]. 然后通过 [MiraiLogger.Factory] 提供实现.
*
* ## 实现或使用 [MiraiLogger]
*
@ -79,7 +84,8 @@ public actual interface MiraiLogger {
*/
public fun create(requester: Class<*>): MiraiLogger = create(requester, null)
public actual companion object INSTANCE : Factory by loadService(Factory::class, { DefaultFactory() })
public actual companion object INSTANCE :
Factory by dynamicDelegation({ MiraiLoggerFactoryImplementationBridge })
}
public actual companion object {
@ -95,21 +101,21 @@ public actual interface MiraiLogger {
/**
* 已弃用, 请实现 service [net.mamoe.mirai.utils.MiraiLogger.Factory] 并以 [ServiceLoader] 支持的方式提供.
*/
@Suppress("DeprecatedCallableAddReplaceWith")
@Deprecated(
"Please set factory by providing an service of type net.mamoe.mirai.utils.MiraiLogger.Factory",
level = DeprecationLevel.ERROR
level = DeprecationLevel.HIDDEN
) // deprecated since 2.7
@JvmStatic
@DeprecatedSinceMirai(warningSince = "2.7", errorSince = "2.10") // left ERROR intentionally, for internal uses.
public fun setDefaultLoggerCreator(creator: (identity: String?) -> MiraiLogger) {
DefaultFactoryOverrides.override { _, identity -> creator(identity) }
@DeprecatedSinceMirai(warningSince = "2.7", errorSince = "2.10", hiddenSince = "2.13")
public fun setDefaultLoggerCreator(@Suppress("UNUSED_PARAMETER") creator: (identity: String?) -> MiraiLogger) {
// nop
// DefaultFactoryOverrides.override { _, identity -> creator(identity) }
}
/**
* 旧版本用于创建 [MiraiLogger]. 已弃用. 请使用 [MiraiLogger.Factory.INSTANCE.create].
*
* @see setDefaultLoggerCreator
*/
@Deprecated(
"Please use MiraiLogger.Factory.create", ReplaceWith(
@ -249,33 +255,75 @@ public actual interface MiraiLogger {
public actual fun call(priority: SimpleLogger.LogPriority, message: String?, e: Throwable?): Unit =
priority.correspondingFunction(this, message, e)
@Suppress("DeprecatedCallableAddReplaceWith")
@Deprecated("plus 设计不佳, 请避免使用.", level = DeprecationLevel.HIDDEN) // deprecated since 2.7
@DeprecatedSinceMirai(warningSince = "2.7", errorSince = "2.10", hiddenSince = "2.11")
public operator fun <T : MiraiLogger> plus(follower: T): T = follower
}
// used by Mirai Console
/**
* @since 2.13
*/
internal object MiraiLoggerFactoryImplementationBridge : MiraiLogger.Factory {
@Volatile
var instance: MiraiLogger.Factory = createPlatformInstance()
private set
internal object DefaultFactoryOverrides {
var override: ((requester: Class<*>, identity: String?) -> MiraiLogger)? =
null // 支持 LoggerAdapters 以及兼容旧版本
fun createPlatformInstance() = loadService(MiraiLogger.Factory::class) { DefaultFactory() }
@JvmStatic
fun override(lambda: (requester: Class<*>, identity: String?) -> MiraiLogger) {
override = lambda
private val frozen = atomic(false)
fun freeze(): Boolean {
return frozen.compareAndSet(expect = false, update = true)
}
@JvmStatic
fun clearOverride() {
override = null
@TestOnly
fun reinit() {
frozen.loop { value ->
instance = createPlatformInstance()
if (frozen.compareAndSet(value, false)) return
}
}
fun setInstance(instance: MiraiLogger.Factory) {
if (frozen.value) {
error(
"LoggerFactory instance had been frozen, so it's impossible to override it." +
"If you are using Mirai Console and you want to override platform logging implementation, " +
"please do so before initialization of MiraiConsole, that is, before `MiraiConsoleImplementation.start()`. " +
"Plugins are not allowed to override logging implementation, and this is done in the very fundamental implementation of Mirai Console so there is no way to escape that." +
"Normally it is only sensible for Mirai Console frontend implementor to do that." +
"If you are just using mirai-core, this error should not happen. There should be no limitation in overriding logging implementation with mirai-core. " +
"Check if you actually did use mirai-console somewhere, or please file an issue on https://github.com/mamoe/mirai/issues/new/choose"
)
}
this.instance = instance
}
inline fun wrapCurrent(mapper: (current: MiraiLogger.Factory) -> MiraiLogger.Factory) {
contract { callsInPlace(mapper, InvocationKind.EXACTLY_ONCE) }
setInstance(this.instance.let(mapper))
}
override fun create(requester: KClass<*>, identity: String?): MiraiLogger {
return instance.create(requester, identity)
}
}
internal class DefaultFactory : MiraiLogger.Factory {
override fun create(requester: Class<*>, identity: String?): MiraiLogger {
val override = DefaultFactoryOverrides.override
return if (override != null) override(requester, identity) else PlatformLogger(
identity ?: requester.kotlin.simpleName ?: requester.simpleName
)
return instance.create(requester, identity)
}
override fun create(requester: KClass<*>): MiraiLogger {
return instance.create(requester)
}
override fun create(requester: Class<*>): MiraiLogger {
return instance.create(requester)
}
}
private class DefaultFactory : MiraiLogger.Factory {
override fun create(requester: Class<*>, identity: String?): MiraiLogger {
return PlatformLogger(identity ?: requester.kotlin.simpleName ?: requester.simpleName)
}
}

View File

@ -0,0 +1,20 @@
/*
* 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.logging
import net.mamoe.mirai.utils.MiraiLoggerFactoryImplementationBridge
import org.junit.jupiter.api.AfterEach
internal abstract class AbstractLoggingTest {
@AfterEach
fun cleanup() {
MiraiLoggerFactoryImplementationBridge.run { setInstance(createPlatformInstance()) }
}
}

View File

@ -11,26 +11,25 @@ package net.mamoe.mirai.logging
import net.mamoe.mirai.Bot
import net.mamoe.mirai.internal.utils.*
import net.mamoe.mirai.utils.DefaultFactoryOverrides
import net.mamoe.mirai.utils.LoggerAdapters.asMiraiLogger
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.MiraiLoggerFactoryImplementationBridge
import org.apache.logging.log4j.LogManager
import org.junit.jupiter.api.AfterEach
import kotlin.test.*
internal class Log4j2LoggingTest {
internal class Log4j2LoggingTest : AbstractLoggingTest() {
@BeforeTest
fun init() {
DefaultFactoryOverrides.override { requester, identity ->
LogManager.getLogger(requester).asMiraiLogger(Marker(identity ?: requester.simpleName, MARKER_MIRAI))
MiraiLoggerFactoryImplementationBridge.wrapCurrent {
object : MiraiLogger.Factory {
override fun create(requester: Class<*>, identity: String?): MiraiLogger {
return LogManager.getLogger(requester)
.asMiraiLogger(Marker(identity ?: requester.simpleName, MARKER_MIRAI))
}
}
}
}
@AfterEach
fun cleanup() {
DefaultFactoryOverrides.clearOverride()
}
private fun MiraiLogger.cast(): Log4jLoggerAdapter = this as Log4jLoggerAdapter
@Test

View File

@ -10,20 +10,26 @@
package net.mamoe.mirai.logging
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.MiraiLoggerFactoryImplementationBridge
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertIs
internal class LoggingCompatibilityTest {
internal class LoggingCompatibilityTest : AbstractLoggingTest() {
@Suppress("DEPRECATION_ERROR")
@Test
fun `legacy overrides are still working if no services are found`() {
val messages = StringBuilder()
MiraiLogger.setDefaultLoggerCreator {
net.mamoe.mirai.utils.SimpleLogger("my logger") { message: String?, _: Throwable? ->
messages.append(message)
MiraiLoggerFactoryImplementationBridge.wrapCurrent {
object : MiraiLogger.Factory {
override fun create(requester: Class<*>, identity: String?): MiraiLogger {
return net.mamoe.mirai.utils.SimpleLogger("my logger") { message: String?, _: Throwable? ->
messages.append(message)
}
}
}
}

View File

@ -13,7 +13,7 @@ import net.mamoe.mirai.utils.MiraiLogger
import org.bouncycastle.jce.provider.BouncyCastleProvider
import java.security.Security
import kotlin.test.Test
import kotlin.test.assertTrue
import kotlin.test.assertIs
internal actual fun initPlatform() {
init
@ -32,9 +32,7 @@ internal actual class PlatformInitializationTest : AbstractTest() {
@Test
actual fun test() {
assertTrue {
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
MiraiLogger.Factory.create(this::class, "1") is net.mamoe.mirai.internal.utils.StdoutLogger
}
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
assertIs<net.mamoe.mirai.internal.utils.StdoutLogger>(MiraiLogger.Factory.create(this::class, "1"))
}
}

View File

@ -51,9 +51,17 @@ internal actual abstract class AbstractTest actual constructor() : CommonAbstrac
DebugProbes.install()
@Suppress("DEPRECATION_ERROR")
MiraiLogger.setDefaultLoggerCreator {
SynchronizedStdoutLogger(it)
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
net.mamoe.mirai.utils.MiraiLoggerFactoryImplementationBridge.wrapCurrent {
object : MiraiLogger.Factory {
override fun create(requester: Class<*>, identity: String?): MiraiLogger {
return SynchronizedStdoutLogger(identity ?: requester.simpleName)
}
override fun create(requester: KClass<*>, identity: String?): MiraiLogger {
return SynchronizedStdoutLogger(identity ?: requester.simpleName)
}
}
}
setSystemProp("mirai.network.packet.logger", "true")

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
* 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.
@ -12,10 +12,7 @@
package net.mamoe.mirai.internal.netinternalkit
import kotlinx.atomicfu.locks.withLock
import net.mamoe.mirai.utils.DefaultFactoryOverrides
import net.mamoe.mirai.utils.PlatformLogger
import net.mamoe.mirai.utils.SizedCache
import net.mamoe.mirai.utils.currentTimeMillis
import net.mamoe.mirai.utils.*
import java.io.File
internal object LogCapture {
@ -28,12 +25,17 @@ internal object LogCapture {
fun setupCapture(maxLine: Int = 200) {
logCache = SizedCache(maxLine)
@Suppress("INVISIBLE_MEMBER")
DefaultFactoryOverrides.override { requester, identity ->
PlatformLogger(
identity ?: requester.kotlin.simpleName ?: requester.simpleName,
output
)
MiraiLoggerFactoryImplementationBridge.wrapCurrent {
object : MiraiLogger.Factory {
override fun create(requester: Class<*>, identity: String?): MiraiLogger {
return PlatformLogger(
identity ?: requester.kotlin.simpleName ?: requester.simpleName,
output
)
}
}
}
NetReplayHelperSettings.logger_console = PlatformLogger(