Improve logging

This commit is contained in:
Him188 2021-04-25 18:37:21 +08:00
parent 5fa54114c1
commit a7a4879d05
16 changed files with 210 additions and 124 deletions

View File

@ -15,7 +15,8 @@ import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import net.mamoe.mirai.event.events.BotEvent
import net.mamoe.mirai.internal.event.broadcastInternal
import net.mamoe.mirai.event.events.MessageEvent
import net.mamoe.mirai.internal.event.callAndRemoveIfRequired
import net.mamoe.mirai.internal.network.Packet
import net.mamoe.mirai.utils.JavaFriendlyAPI
import net.mamoe.mirai.utils.MiraiExperimentalApi
@ -143,26 +144,32 @@ public interface CancellableEvent : Event {
* @see __broadcastJava Java 使用
*/
@JvmSynthetic
public suspend fun <E : Event> E.broadcast(): E = apply {
public suspend fun <E : Event> E.broadcast(): E {
check(this is AbstractEvent) {
"Events must extend AbstractEvent"
}
if (this is BroadcastControllable && !this.shouldBroadcast) {
return@apply
return this
}
this.broadCastLock.withLock {
this._intercepted = false
if (EventDisabled) return@withLock
if (this is Packet.NoEventLog) return@withLock
if (this is Packet) return@withLock // all [Packet]s are logged in [LoggingPacketHandler]
if (this is Packet.NoLog) return@withLock
if (this is MessageEvent) return@withLock // specially handled in [LoggingPacketHandlerAdapter]
// if (this is Packet) return@withLock // all [Packet]s are logged in [LoggingPacketHandlerAdapter]
if (this is BotEvent) {
this.bot.logger.verbose { "Event: $this" }
} else {
MiraiLogger.TopLevel.verbose { "Event: $this" }
}
this.broadcastInternal() // inline, no extra cost
callAndRemoveIfRequired(this)
}
return this
}
/**

View File

@ -97,65 +97,52 @@ internal object GlobalEventListeners {
}
// inline: NO extra Continuation
@Suppress("UNCHECKED_CAST")
internal suspend inline fun AbstractEvent.broadcastInternal() {
callAndRemoveIfRequired(this@broadcastInternal)
}
internal inline fun <E, T : Iterable<E>> T.forEach0(block: T.(E) -> Unit) {
forEach { block(it) }
}
@Suppress("DuplicatedCode")
internal suspend inline fun <E : AbstractEvent> callAndRemoveIfRequired(
event: E
) {
internal suspend fun <E : AbstractEvent> callAndRemoveIfRequired(event: E) {
for (p in EventPriority.prioritiesExcludedMonitor) {
GlobalEventListeners[p].forEach0 { registeredRegistry ->
if (event.isIntercepted) {
return
}
if (!registeredRegistry.type.isInstance(event)) return@forEach0
val listener = registeredRegistry.listener
when (listener.concurrencyKind) {
ConcurrencyKind.LOCKED -> {
(listener as Handler).lock!!.withLock {
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
remove(registeredRegistry)
}
}
}
ConcurrencyKind.CONCURRENT -> {
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
remove(registeredRegistry)
}
}
}
val container = GlobalEventListeners[p]
for (registry in container) {
if (event.isIntercepted) return
if (!registry.type.isInstance(event)) continue
val listener = registry.listener
process(container, registry, listener, event)
}
}
coroutineScope {
GlobalEventListeners[EventPriority.MONITOR].forEach0 { registeredRegistry ->
if (event.isIntercepted) {
return@coroutineScope
}
if (!registeredRegistry.type.isInstance(event)) return@forEach0
val listener = registeredRegistry.listener
launch {
when (listener.concurrencyKind) {
ConcurrencyKind.LOCKED -> {
(listener as Handler).lock!!.withLock {
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
remove(registeredRegistry)
}
}
}
ConcurrencyKind.CONCURRENT -> {
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
remove(registeredRegistry)
}
}
}
if (event.isIntercepted) return
val container = GlobalEventListeners[EventPriority.MONITOR]
when (container.size) {
0 -> return
1 -> {
val registry = container.firstOrNull() ?: return
if (!registry.type.isInstance(event)) return
process(container, registry, registry.listener, event)
}
else -> supervisorScope {
for (registry in GlobalEventListeners[EventPriority.MONITOR]) {
if (!registry.type.isInstance(event)) continue
launch { process(container, registry, registry.listener, event) }
}
}
}
}
private suspend fun <E : AbstractEvent> process(
container: ConcurrentLinkedQueue<ListenerRegistry>,
registry: ListenerRegistry,
listener: Listener<Event>,
event: E,
) {
when (listener.concurrencyKind) {
ConcurrencyKind.LOCKED -> {
(listener as Handler).lock!!.withLock {
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
container.remove(registry)
}
}
}
ConcurrencyKind.CONCURRENT -> {
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
container.remove(registry)
}
}
}

View File

@ -27,7 +27,7 @@ import java.util.*
*
* 示例:
* ```log
* 2020-05-21 19:51:09 V/Bot 1994701021: Send: OidbSvc.0x88d_7
* 2020-05-21 19:51:09 V/Bot 123456789: Send: OidbSvc.0x88d_7
* ```
*
* 日期时间格式为 `yyyy-MM-dd HH:mm:ss`,

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
* Copyright 2019-2021 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.
@ -234,7 +234,7 @@ public inline fun MiraiLogger.error(message: () -> String?, e: Throwable?) {
*
* 示例:
* ```log
* 2020-05-21 19:51:09 V/Bot 1994701021: Send: OidbSvc.0x88d_7
* 2020-05-21 19:51:09 V/Bot 123456789: Send: OidbSvc.0x88d_7
* ```
*
* 日期时间格式为 `yyyy-MM-dd HH:mm:ss`,

View File

@ -27,7 +27,7 @@ import java.util.*
*
* 示例:
* ```log
* 2020-05-21 19:51:09 V/Bot 1994701021: Send: OidbSvc.0x88d_7
* 2020-05-21 19:51:09 V/Bot 123456789: Send: OidbSvc.0x88d_7
* ```
*
* 日期时间格式为 `yyyy-MM-dd HH:mm:ss`,

View File

@ -163,9 +163,10 @@ internal open class QQAndroidBot constructor(
set(ContactUpdater, ContactUpdaterImpl(bot, components, networkLogger))
set(BdhSessionSyncer, BdhSessionSyncerImpl(configuration, networkLogger, components))
set(ServerList, ServerListImpl())
set(PacketLoggingStrategy, PacketLoggingStrategyImpl(bot))
set(
PacketHandler, PacketHandlerChain(
LoggingPacketHandler(bot, networkLogger),
LoggingPacketHandlerAdapter(networkLogger, get(PacketLoggingStrategy)),
EventBroadcasterPacketHandler(networkLogger),
CallPacketFactoryPacketHandler(bot)
)

View File

@ -9,7 +9,7 @@
package net.mamoe.mirai.internal.network
import net.mamoe.mirai.internal.QQAndroidBot
import net.mamoe.mirai.internal.AbstractBot
import net.mamoe.mirai.internal.network.handler.logger
import net.mamoe.mirai.utils.MiraiLogger
@ -52,12 +52,12 @@ internal class ParseErrorPacket(
) : Packet, Packet.NoLog {
enum class Direction {
TO_BOT_LOGGER {
override fun getLogger(bot: QQAndroidBot): MiraiLogger = bot.logger
override fun getLogger(bot: AbstractBot): MiraiLogger = bot.logger
},
TO_NETWORK_LOGGER {
override fun getLogger(bot: QQAndroidBot): MiraiLogger = bot.network.logger
override fun getLogger(bot: AbstractBot): MiraiLogger = bot.network.logger
};
abstract fun getLogger(bot: QQAndroidBot): MiraiLogger
abstract fun getLogger(bot: AbstractBot): MiraiLogger
}
}

View File

@ -13,17 +13,13 @@ import net.mamoe.mirai.event.BroadcastControllable
import net.mamoe.mirai.event.CancellableEvent
import net.mamoe.mirai.event.Event
import net.mamoe.mirai.event.broadcast
import net.mamoe.mirai.event.events.MessageEvent
import net.mamoe.mirai.internal.QQAndroidBot
import net.mamoe.mirai.internal.contact.logMessageReceived
import net.mamoe.mirai.internal.contact.replaceMagicCodes
import net.mamoe.mirai.internal.network.MultiPacket
import net.mamoe.mirai.internal.network.Packet
import net.mamoe.mirai.internal.network.ParseErrorPacket
import net.mamoe.mirai.internal.network.component.ComponentKey
import net.mamoe.mirai.internal.network.protocol.packet.*
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.cast
import net.mamoe.mirai.utils.verbose
internal interface PacketHandler {
suspend fun handlePacket(incomingPacket: IncomingPacket)
@ -53,29 +49,15 @@ internal data class ExceptionInPacketHandlerException(
override val cause: Throwable,
) : IllegalStateException("Exception in PacketHandler '$packetHandler'.")
internal class LoggingPacketHandler(
private val bot: QQAndroidBot,
internal class LoggingPacketHandlerAdapter(
private val logger: MiraiLogger,
private val strategy: PacketLoggingStrategy,
) : PacketHandler {
override suspend fun handlePacket(incomingPacket: IncomingPacket) {
val packet = incomingPacket.data ?: return
if (!bot.logger.isEnabled && !logger.isEnabled) return
when {
packet is ParseErrorPacket -> {
packet.direction.getLogger(bot).error(packet.error)
}
packet is MessageEvent -> packet.logMessageReceived()
packet is Packet.NoLog -> {
// nothing to do
}
packet is Event && packet !is Packet.NoEventLog -> bot.logger.verbose {
"Event: $packet".replaceMagicCodes()
}
else -> logger.verbose { "Recv: ${incomingPacket.commandName} ${incomingPacket.data}".replaceMagicCodes() }
}
strategy.logReceived(logger, incomingPacket)
}
override fun toString(): String = "LoggingPacketHandler"
override fun toString(): String = "LoggingPacketHandlerAdapter"
}
internal class EventBroadcasterPacketHandler(
@ -83,7 +65,16 @@ internal class EventBroadcasterPacketHandler(
) : PacketHandler {
override suspend fun handlePacket(incomingPacket: IncomingPacket) {
val packet = incomingPacket.data ?: return
val data = incomingPacket.data ?: return
impl(data)
}
private suspend fun impl(packet: Packet) {
if (packet is MultiPacket<*>) {
for (p in packet) {
impl(p)
}
}
when {
packet is CancellableEvent && packet.isCancelled -> return
packet is BroadcastControllable && !packet.shouldBroadcast -> return
@ -105,7 +96,7 @@ internal class EventBroadcasterPacketHandler(
return qualified.substringAfter("net.mamoe.mirai.event.events.")
}
override fun toString(): String = "LoggingPacketHandler"
override fun toString(): String = "EventBroadcasterPacketHandler"
}
internal class CallPacketFactoryPacketHandler(

View File

@ -0,0 +1,80 @@
/*
* Copyright 2019-2021 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/master/LICENSE
*/
package net.mamoe.mirai.internal.network.components
import net.mamoe.mirai.event.Event
import net.mamoe.mirai.event.events.MessageEvent
import net.mamoe.mirai.internal.AbstractBot
import net.mamoe.mirai.internal.contact.logMessageReceived
import net.mamoe.mirai.internal.contact.replaceMagicCodes
import net.mamoe.mirai.internal.network.Packet
import net.mamoe.mirai.internal.network.ParseErrorPacket
import net.mamoe.mirai.internal.network.component.ComponentKey
import net.mamoe.mirai.internal.network.protocol.packet.IncomingPacket
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.systemProp
import net.mamoe.mirai.utils.verbose
/**
* Implementation must be fast and non-blocking, throwing no exception.
*/
internal interface PacketLoggingStrategy {
fun logSent(logger: MiraiLogger, outgoingPacket: OutgoingPacket)
fun logReceived(logger: MiraiLogger, incomingPacket: IncomingPacket)
companion object : ComponentKey<PacketLoggingStrategy>
}
internal class PacketLoggingStrategyImpl(
private val bot: AbstractBot,
private val blacklist: Set<String> = DEFAULT_BLACKLIST,
) : PacketLoggingStrategy {
override fun logSent(logger: MiraiLogger, outgoingPacket: OutgoingPacket) {
if (outgoingPacket.commandName in blacklist) return
logger.verbose { "Send: ${outgoingPacket.commandName}" }
}
override fun logReceived(logger: MiraiLogger, incomingPacket: IncomingPacket) {
val packet = incomingPacket.data ?: return
if (!bot.logger.isEnabled && !logger.isEnabled) return
when {
packet is ParseErrorPacket -> {
packet.direction.getLogger(bot).error(packet.error)
}
packet is MessageEvent -> packet.logMessageReceived()
packet is Packet.NoLog -> {
// nothing to do
}
packet is Event && packet !is Packet.NoEventLog -> bot.logger.verbose {
"Event: $packet".replaceMagicCodes()
}
else -> {
if (SHOW_PACKET_DETAILS) {
logger.verbose { "Recv: ${incomingPacket.commandName} ${incomingPacket.data}".replaceMagicCodes() }
} else {
logger.verbose { "Recv: ${incomingPacket.commandName}".replaceMagicCodes() }
}
}
}
}
companion object {
@JvmField
val DEFAULT_BLACKLIST = setOf(
"MessageSvc.PbDeleteMsg",
"MessageSvc.PbGetMsg", // they are too verbose.
"OnlinePush.RespPush"
)
@JvmField
var SHOW_PACKET_DETAILS = systemProp("mirai.debug.network.show.packet.details", false)
}
}

View File

@ -9,6 +9,7 @@
package net.mamoe.mirai.internal.network.handler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.selects.SelectClause1
import net.mamoe.mirai.Bot
import net.mamoe.mirai.internal.network.Packet
@ -30,7 +31,7 @@ import net.mamoe.mirai.utils.MiraiLogger
* @see NetworkHandlerSupport
* @see NetworkHandlerFactory
*/
internal interface NetworkHandler {
internal interface NetworkHandler : CoroutineScope {
val context: NetworkHandlerContext
fun isOk() = state == State.OK

View File

@ -14,6 +14,7 @@ import kotlinx.coroutines.selects.SelectClause1
import net.mamoe.mirai.internal.network.Packet
import net.mamoe.mirai.internal.network.components.PacketCodec
import net.mamoe.mirai.internal.network.components.PacketHandler
import net.mamoe.mirai.internal.network.components.PacketLoggingStrategy
import net.mamoe.mirai.internal.network.components.RawIncomingPacket
import net.mamoe.mirai.internal.network.handler.state.StateObserver
import net.mamoe.mirai.internal.network.protocol.packet.IncomingPacket
@ -69,7 +70,7 @@ internal abstract class NetworkHandlerSupport(
val listener = PacketListener(packet.commandName, packet.sequenceId)
var exception: Throwable? = null
repeat(attempts.coerceAtLeast(1)) {
logger.verbose { "Send: ${packet.commandName}" }
context[PacketLoggingStrategy].logSent(logger, packet)
try {
packetListeners.add(listener)
sendPacketImpl(packet)
@ -92,7 +93,7 @@ internal abstract class NetworkHandlerSupport(
}
final override suspend fun sendWithoutExpect(packet: OutgoingPacket) {
logger.verbose { "Send: ${packet.commandName}" }
context[PacketLoggingStrategy].logSent(logger, packet)
sendPacketImpl(packet)
}
@ -102,7 +103,7 @@ internal abstract class NetworkHandlerSupport(
// } else {
// logger.info { "NetworkHandler '$this' closed: $cause" }
// }
coroutineContext.job.cancel("NetworkHandler closed.", cause)
coroutineContext.job.cancel("NetworkHandler closed", cause)
}
protected val packetLogger: MiraiLogger by lazy {

View File

@ -18,6 +18,7 @@ import net.mamoe.mirai.internal.network.handler.NetworkHandler
import net.mamoe.mirai.internal.network.handler.NetworkHandler.State
import net.mamoe.mirai.internal.network.handler.NetworkHandlerContext
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
import kotlin.coroutines.CoroutineContext
/**
* A proxy to [NetworkHandler] that delegates calls to instance returned by [NetworkHandlerSelector.awaitResumeInstance].
@ -52,6 +53,9 @@ internal class SelectorNetworkHandler(
selector.getResumedInstance()?.close(cause)
}
override val coroutineContext: CoroutineContext
get() = selector.getResumedInstance()?.coroutineContext ?: scope.coroutineContext // merely use fallback
override fun toString(): String = "SelectorNetworkHandler(currentInstance=${selector.getResumedInstance()})"
}

View File

@ -81,7 +81,7 @@ internal open class NettyNetworkHandler(
private inner class OutgoingPacketEncoder : MessageToByteEncoder<OutgoingPacket>(OutgoingPacket::class.java) {
override fun encode(ctx: ChannelHandlerContext, msg: OutgoingPacket, out: ByteBuf) {
PacketCodec.PacketLogger.debug { "encode: $msg" }
packetLogger.debug { "encode: $msg" }
out.writeBytes(msg.delegate)
}
}
@ -261,19 +261,29 @@ internal open class NettyNetworkHandler(
connection.writeAndFlush(packet)
}
private val configPush = this@NettyNetworkHandler.launch(CoroutineName("ConfigPush sync")) {
try {
context[ConfigPushProcessor].syncConfigPush(this@NettyNetworkHandler)
} catch (e: ConfigPushProcessor.RequireReconnectException) {
setState { StateConnecting(ExceptionCollector(e), false) }
}
}
override suspend fun resumeConnection0() {
(coroutineContext.job as CompletableJob).run {
complete()
join()
}
setState { StateOK(connection) }
joinCompleted(configPush) // throw exception
setState { StateOK(connection, configPush) }
} // noop
override fun toString(): String = "StateLoading"
}
protected inner class StateOK(
private val connection: NettyChannel
private val connection: NettyChannel,
private val configPush: Job,
) : NettyState(State.OK) {
init {
coroutineContext.job.invokeOnCompletion {
@ -307,14 +317,6 @@ internal open class NettyNetworkHandler(
}
}
private val configPush = launch(CoroutineName("ConfigPush sync")) {
try {
context[ConfigPushProcessor].syncConfigPush(this@NettyNetworkHandler)
} catch (e: ConfigPushProcessor.RequireReconnectException) {
setState { StateClosed(e) }
}
}
// we can also move them as observers if needed.
private val keyRefresh = launch(CoroutineName("Key refresh")) {
@ -332,10 +334,6 @@ internal open class NettyNetworkHandler(
joinCompleted(keyRefresh)
} // noop
private suspend inline fun joinCompleted(job: Job) {
if (job.isCompleted) job.join()
}
override fun toString(): String = "StateOK"
}

View File

@ -14,6 +14,7 @@ import io.netty.buffer.ByteBufInputStream
import io.netty.channel.ChannelFuture
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.Job
import kotlinx.io.core.ByteReadPacket
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.SimpleLogger
@ -55,3 +56,8 @@ internal fun MiraiLogger.asCoroutineExceptionHandler(
)
}
}
internal suspend inline fun joinCompleted(job: Job) {
if (job.isCompleted) job.join()
}

View File

@ -18,6 +18,7 @@ import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.withLock
import kotlinx.io.core.*
import net.mamoe.mirai.Bot
import net.mamoe.mirai.Mirai
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.MemberPermission
@ -55,7 +56,10 @@ import net.mamoe.mirai.message.data.MessageSourceKind.STRANGER
import net.mamoe.mirai.message.data.MessageSourceKind.TEMP
import net.mamoe.mirai.message.data.PlainText
import net.mamoe.mirai.message.data.buildMessageChain
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.cast
import net.mamoe.mirai.utils.debug
import net.mamoe.mirai.utils.read
import net.mamoe.mirai.utils.toUHexString
import kotlin.random.Random
@ -93,12 +97,13 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
)
}
open class GetMsgSuccess(delegate: List<Packet>, syncCookie: ByteArray?, val bot: QQAndroidBot) : Response(
open class GetMsgSuccess(delegate: List<Packet>, syncCookie: ByteArray?, bot: QQAndroidBot) : Response(
MsgSvc.SyncFlag.STOP, delegate,
syncCookie
syncCookie,
bot
), Event,
Packet.NoLog {
override fun toString(): String = "MessageSvcPbGetMsg.GetMsgSuccess(messages=<Iterable>))"
override fun toString(): String = "MessageSvcPbGetMsg.GetMsgSuccess"
}
/**
@ -107,15 +112,16 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
open class Response(
internal val syncFlagFromServer: MsgSvc.SyncFlag,
delegate: List<Packet>,
val syncCookie: ByteArray?
val syncCookie: ByteArray?, override val bot: Bot
) :
AbstractEvent(),
MultiPacket<Packet>,
Iterable<Packet> by (delegate),
Packet.NoLog {
Packet.NoLog,
BotEvent {
override fun toString(): String =
"MessageSvcPbGetMsg.Response(syncFlagFromServer=$syncFlagFromServer, messages=<Iterable>))"
"MessageSvcPbGetMsg.Response(flag=$syncFlagFromServer)"
}
class EmptyResponse(
@ -128,9 +134,12 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
val resp = readProtoBuf(MsgSvc.PbGetMsgResp.serializer())
if (resp.result != 0) {
bot.network.logger
.warning { "MessageSvcPushNotify: result != 0, result = ${resp.result}, errorMsg=${resp.errmsg}" }
bot.launch(CoroutineName("MessageSvcPushNotify.retry")) {
// this is normally recoverable, no need to log
// bot.network.logger
// .warning { "MessageSvcPushNotify: result != 0, result = ${resp.result}, errorMsg=${resp.errmsg}" }
bot.network.launch(CoroutineName("MessageSvcPushNotify.retry")) {
delay(500 + Random.nextLong(0, 1000))
bot.network.run {
MessageSvcPbGetMsg(bot.client, syncCookie = null).sendWithoutExpect()
@ -188,7 +197,7 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
if (resp.syncFlag == MsgSvc.SyncFlag.STOP) {
return GetMsgSuccess(list, resp.syncCookie, bot)
}
return Response(resp.syncFlag, list, resp.syncCookie)
return Response(resp.syncFlag, list, resp.syncCookie, bot)
}
override suspend fun QQAndroidBot.handle(packet: Response) {

View File

@ -110,7 +110,8 @@ internal abstract class AbstractRealNetworkHandlerTest<H : NetworkHandler> : Abs
set(ContactUpdater, ContactUpdaterImpl(bot, components, networkLogger))
set(BdhSessionSyncer, BdhSessionSyncerImpl(configuration, networkLogger, components))
set(ServerList, ServerListImpl())
set(PacketHandler, LoggingPacketHandler(bot, networkLogger))
set(PacketLoggingStrategy, PacketLoggingStrategyImpl(bot))
set(PacketHandler, LoggingPacketHandlerAdapter(networkLogger, get(PacketLoggingStrategy)))
set(PacketCodec, PacketCodecImpl())
set(OtherClientUpdater, OtherClientUpdaterImpl(bot, components, bot.logger))
set(ConfigPushSyncer, ConfigPushSyncerImpl())