From 28d0a43ef3357dcbdbc2c2a5d48819ebd317eec1 Mon Sep 17 00:00:00 2001 From: slhafzjw Date: Tue, 14 Apr 2026 10:08:31 +0800 Subject: [PATCH] refactor(log): support advice invoke or invoke with no result via different methods to avoid unnecessary nullable check --- .../component/abstracts/AgentModule.kt | 14 ++- .../framework/agent/log/LogAdviceProvider.kt | 89 ++++++++++++++----- 2 files changed, 72 insertions(+), 31 deletions(-) diff --git a/Partner-Framework/src/main/java/work/slhaf/partner/framework/agent/factory/component/abstracts/AgentModule.kt b/Partner-Framework/src/main/java/work/slhaf/partner/framework/agent/factory/component/abstracts/AgentModule.kt index 5b728e6b..68cac6ba 100644 --- a/Partner-Framework/src/main/java/work/slhaf/partner/framework/agent/factory/component/abstracts/AgentModule.kt +++ b/Partner-Framework/src/main/java/work/slhaf/partner/framework/agent/factory/component/abstracts/AgentModule.kt @@ -24,16 +24,12 @@ sealed class AbstractAgentModule { @Suppress("UNCHECKED_CAST") LogAdviceProvider.createAdvice( moduleName, - resolveGenericType(0) as Class, - Void::class.java - ) { context -> - doExecute(context) - null - } + resolveGenericType(0) as Class + ) { context -> doExecute(context) } } fun execute(context: T) { - advice.invoke(context) + advice.invokeWithoutResult(context) } protected abstract fun doExecute(context: T) @@ -53,11 +49,11 @@ sealed class AbstractAgentModule { } } - fun execute(input: I): O? { + fun execute(input: I): O { return advice.invoke(input).getOrThrow() } - protected abstract fun doExecute(input: I): O? + protected abstract fun doExecute(input: I): O } abstract class Standalone : AbstractAgentModule() diff --git a/Partner-Framework/src/main/java/work/slhaf/partner/framework/agent/log/LogAdviceProvider.kt b/Partner-Framework/src/main/java/work/slhaf/partner/framework/agent/log/LogAdviceProvider.kt index 86c1caf4..e396c0d4 100644 --- a/Partner-Framework/src/main/java/work/slhaf/partner/framework/agent/log/LogAdviceProvider.kt +++ b/Partner-Framework/src/main/java/work/slhaf/partner/framework/agent/log/LogAdviceProvider.kt @@ -30,15 +30,29 @@ object LogAdviceProvider : Configurable, ConfigRegistration inputType: Class, outputType: Class, meta: Map = emptyMap(), - invoker: (I) -> O? + invoker: (I) -> O ): LogAdvice { return LogAdvice( - adviceTarget = adviceTarget, - invoker = invoker, + adviceTarget, + AdviceInvoker.WithResult(invoker), AdviceMeta(adviceTarget, inputType, outputType, meta) ).apply { _adviceRegistry.add(this) } } + @JvmOverloads + fun createAdvice( + adviceTarget: String, + inputType: Class, + meta: Map = emptyMap(), + invoker: (I) -> Unit + ): LogAdvice { + return LogAdvice( + adviceTarget, + AdviceInvoker.WithoutResult(invoker), + AdviceMeta(adviceTarget, inputType, Void::class.java, meta) + ).apply { _adviceRegistry.add(this) } + } + internal fun record(result: AdviceResult) { val path = logPath.resolve(result.adviceTarget).normalize().toAbsolutePath() val traceEvent = TraceEvent(path, result.toJSON(), result.finishTime.toInstant().toEpochMilli()) @@ -61,7 +75,7 @@ object LogAdviceProvider : Configurable, ConfigRegistration class LogAdvice internal constructor( val adviceTarget: String, - private val invoker: (I) -> O?, + private val invoker: AdviceInvoker, private val adviceMeta: AdviceMeta ) { @@ -69,11 +83,13 @@ class LogAdvice internal constructor( private val log = LoggerFactory.getLogger(LogAdvice::class.java) } - fun invoke(input: I): Result { + fun invoke(input: I): Result { + val currentInvoker = invoker as? AdviceInvoker.WithResult + ?: error("LogAdvice[$adviceTarget] does not provide a return value") val startAt = ZonedDateTime.now() return try { logEnter(input) - val output = invoker(input) + val output = currentInvoker.invoker(input) logOutput(output) createResult(input, output, startAt) Result.success(output) @@ -84,6 +100,22 @@ class LogAdvice internal constructor( } } + fun invokeWithoutResult(input: I) { + val currentInvoker = invoker as? AdviceInvoker.WithoutResult + ?: error("LogAdvice[$adviceTarget] expects a return value") + val startAt = ZonedDateTime.now() + try { + logEnter(input) + currentInvoker.invoker(input) + logNoOutput() + createResultWithoutOutput(input, startAt) + } catch (e: Exception) { + logException(e) + createUnexpectedResult(input, e, startAt) + throw e + } + } + private fun logException(e: Exception) { when (LogAdviceProvider.logLevel) { AdviceLoggingConfig.LogLevel.NONE -> return @@ -92,7 +124,7 @@ class LogAdvice internal constructor( } } - private fun logOutput(output: O?) { + private fun logOutput(output: O) { when (LogAdviceProvider.logLevel) { AdviceLoggingConfig.LogLevel.NONE -> return AdviceLoggingConfig.LogLevel.ABSTRACT -> log.info("${adviceMeta.adviceTarget} ended.") @@ -100,12 +132,20 @@ class LogAdvice internal constructor( try { log.info("${adviceMeta.adviceTarget} ended with output: ${JSONObject.toJSONString(output)}") } catch (_: Exception) { - log.info("${adviceMeta.adviceTarget} ended with output: ${output ?: "null"}, which cannot be printed as json string.") + log.info("${adviceMeta.adviceTarget} ended with output: ${output.toString()}, which cannot be printed as json string.") } } } } + private fun logNoOutput() { + when (LogAdviceProvider.logLevel) { + AdviceLoggingConfig.LogLevel.NONE -> return + AdviceLoggingConfig.LogLevel.ABSTRACT -> log.info("${adviceMeta.adviceTarget} ended.") + AdviceLoggingConfig.LogLevel.DETAIL -> log.info("${adviceMeta.adviceTarget} ended without output.") + } + } + private fun logEnter(input: I) { when (LogAdviceProvider.logLevel) { AdviceLoggingConfig.LogLevel.NONE -> return @@ -120,16 +160,28 @@ class LogAdvice internal constructor( } } - private fun createResult(input: I, output: O?, startAt: ZonedDateTime) { + private fun createResult(input: I, output: O, startAt: ZonedDateTime) { val inputSerialized = serializeRequired(input) - val outputSerialized = serializeNullable(output) LogAdviceProvider.record( AdviceResult.Normal( adviceTarget, inputSerialized, startAt, adviceMeta, - outputSerialized + serializeRequired(output) + ) + ) + } + + private fun createResultWithoutOutput(input: I, startAt: ZonedDateTime) { + val inputSerialized = serializeRequired(input) + LogAdviceProvider.record( + AdviceResult.Normal( + adviceTarget, + inputSerialized, + startAt, + adviceMeta, + null ) ) } @@ -155,18 +207,11 @@ class LogAdvice internal constructor( value?.toString() ?: "null" } } +} - private fun serializeNullable(value: Any?): String? { - return if (value == null) { - null - } else { - try { - JSONObject.toJSONString(value) - } catch (_: JSONException) { - value.toString() - } - } - } +internal sealed interface AdviceInvoker { + data class WithResult(val invoker: (I) -> O) : AdviceInvoker + data class WithoutResult(val invoker: (I) -> Unit) : AdviceInvoker } data class AdviceMeta(