mirror of
https://github.com/slhaf/Partner.git
synced 2026-05-12 08:43:02 +08:00
refactor(log): support advice invoke or invoke with no result via different methods to avoid unnecessary nullable check
This commit is contained in:
@@ -24,16 +24,12 @@ sealed class AbstractAgentModule {
|
|||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
LogAdviceProvider.createAdvice(
|
LogAdviceProvider.createAdvice(
|
||||||
moduleName,
|
moduleName,
|
||||||
resolveGenericType(0) as Class<T>,
|
resolveGenericType(0) as Class<T>
|
||||||
Void::class.java
|
) { context -> doExecute(context) }
|
||||||
) { context ->
|
|
||||||
doExecute(context)
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun execute(context: T) {
|
fun execute(context: T) {
|
||||||
advice.invoke(context)
|
advice.invokeWithoutResult(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract fun doExecute(context: T)
|
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()
|
return advice.invoke(input).getOrThrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract fun doExecute(input: I): O?
|
protected abstract fun doExecute(input: I): O
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class Standalone : AbstractAgentModule()
|
abstract class Standalone : AbstractAgentModule()
|
||||||
|
|||||||
@@ -30,15 +30,29 @@ object LogAdviceProvider : Configurable, ConfigRegistration<AdviceLoggingConfig>
|
|||||||
inputType: Class<I>,
|
inputType: Class<I>,
|
||||||
outputType: Class<O>,
|
outputType: Class<O>,
|
||||||
meta: Map<String, Any> = emptyMap(),
|
meta: Map<String, Any> = emptyMap(),
|
||||||
invoker: (I) -> O?
|
invoker: (I) -> O
|
||||||
): LogAdvice<I, O> {
|
): LogAdvice<I, O> {
|
||||||
return LogAdvice(
|
return LogAdvice(
|
||||||
adviceTarget = adviceTarget,
|
adviceTarget,
|
||||||
invoker = invoker,
|
AdviceInvoker.WithResult(invoker),
|
||||||
AdviceMeta(adviceTarget, inputType, outputType, meta)
|
AdviceMeta(adviceTarget, inputType, outputType, meta)
|
||||||
).apply { _adviceRegistry.add(this) }
|
).apply { _adviceRegistry.add(this) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmOverloads
|
||||||
|
fun <I> createAdvice(
|
||||||
|
adviceTarget: String,
|
||||||
|
inputType: Class<I>,
|
||||||
|
meta: Map<String, Any> = emptyMap(),
|
||||||
|
invoker: (I) -> Unit
|
||||||
|
): LogAdvice<I, Void> {
|
||||||
|
return LogAdvice(
|
||||||
|
adviceTarget,
|
||||||
|
AdviceInvoker.WithoutResult(invoker),
|
||||||
|
AdviceMeta(adviceTarget, inputType, Void::class.java, meta)
|
||||||
|
).apply { _adviceRegistry.add(this) }
|
||||||
|
}
|
||||||
|
|
||||||
internal fun record(result: AdviceResult) {
|
internal fun record(result: AdviceResult) {
|
||||||
val path = logPath.resolve(result.adviceTarget).normalize().toAbsolutePath()
|
val path = logPath.resolve(result.adviceTarget).normalize().toAbsolutePath()
|
||||||
val traceEvent = TraceEvent(path, result.toJSON(), result.finishTime.toInstant().toEpochMilli())
|
val traceEvent = TraceEvent(path, result.toJSON(), result.finishTime.toInstant().toEpochMilli())
|
||||||
@@ -61,7 +75,7 @@ object LogAdviceProvider : Configurable, ConfigRegistration<AdviceLoggingConfig>
|
|||||||
|
|
||||||
class LogAdvice<I, O> internal constructor(
|
class LogAdvice<I, O> internal constructor(
|
||||||
val adviceTarget: String,
|
val adviceTarget: String,
|
||||||
private val invoker: (I) -> O?,
|
private val invoker: AdviceInvoker<I, O>,
|
||||||
private val adviceMeta: AdviceMeta
|
private val adviceMeta: AdviceMeta
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@@ -69,11 +83,13 @@ class LogAdvice<I, O> internal constructor(
|
|||||||
private val log = LoggerFactory.getLogger(LogAdvice::class.java)
|
private val log = LoggerFactory.getLogger(LogAdvice::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun invoke(input: I): Result<O?> {
|
fun invoke(input: I): Result<O> {
|
||||||
|
val currentInvoker = invoker as? AdviceInvoker.WithResult<I, O>
|
||||||
|
?: error("LogAdvice[$adviceTarget] does not provide a return value")
|
||||||
val startAt = ZonedDateTime.now()
|
val startAt = ZonedDateTime.now()
|
||||||
return try {
|
return try {
|
||||||
logEnter(input)
|
logEnter(input)
|
||||||
val output = invoker(input)
|
val output = currentInvoker.invoker(input)
|
||||||
logOutput(output)
|
logOutput(output)
|
||||||
createResult(input, output, startAt)
|
createResult(input, output, startAt)
|
||||||
Result.success(output)
|
Result.success(output)
|
||||||
@@ -84,6 +100,22 @@ class LogAdvice<I, O> internal constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun invokeWithoutResult(input: I) {
|
||||||
|
val currentInvoker = invoker as? AdviceInvoker.WithoutResult<I>
|
||||||
|
?: 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) {
|
private fun logException(e: Exception) {
|
||||||
when (LogAdviceProvider.logLevel) {
|
when (LogAdviceProvider.logLevel) {
|
||||||
AdviceLoggingConfig.LogLevel.NONE -> return
|
AdviceLoggingConfig.LogLevel.NONE -> return
|
||||||
@@ -92,7 +124,7 @@ class LogAdvice<I, O> internal constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun logOutput(output: O?) {
|
private fun logOutput(output: O) {
|
||||||
when (LogAdviceProvider.logLevel) {
|
when (LogAdviceProvider.logLevel) {
|
||||||
AdviceLoggingConfig.LogLevel.NONE -> return
|
AdviceLoggingConfig.LogLevel.NONE -> return
|
||||||
AdviceLoggingConfig.LogLevel.ABSTRACT -> log.info("${adviceMeta.adviceTarget} ended.")
|
AdviceLoggingConfig.LogLevel.ABSTRACT -> log.info("${adviceMeta.adviceTarget} ended.")
|
||||||
@@ -100,12 +132,20 @@ class LogAdvice<I, O> internal constructor(
|
|||||||
try {
|
try {
|
||||||
log.info("${adviceMeta.adviceTarget} ended with output: ${JSONObject.toJSONString(output)}")
|
log.info("${adviceMeta.adviceTarget} ended with output: ${JSONObject.toJSONString(output)}")
|
||||||
} catch (_: Exception) {
|
} 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) {
|
private fun logEnter(input: I) {
|
||||||
when (LogAdviceProvider.logLevel) {
|
when (LogAdviceProvider.logLevel) {
|
||||||
AdviceLoggingConfig.LogLevel.NONE -> return
|
AdviceLoggingConfig.LogLevel.NONE -> return
|
||||||
@@ -120,16 +160,28 @@ class LogAdvice<I, O> 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 inputSerialized = serializeRequired(input)
|
||||||
val outputSerialized = serializeNullable(output)
|
|
||||||
LogAdviceProvider.record(
|
LogAdviceProvider.record(
|
||||||
AdviceResult.Normal(
|
AdviceResult.Normal(
|
||||||
adviceTarget,
|
adviceTarget,
|
||||||
inputSerialized,
|
inputSerialized,
|
||||||
startAt,
|
startAt,
|
||||||
adviceMeta,
|
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<I, O> internal constructor(
|
|||||||
value?.toString() ?: "null"
|
value?.toString() ?: "null"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun serializeNullable(value: Any?): String? {
|
internal sealed interface AdviceInvoker<I, O> {
|
||||||
return if (value == null) {
|
data class WithResult<I, O>(val invoker: (I) -> O) : AdviceInvoker<I, O>
|
||||||
null
|
data class WithoutResult<I>(val invoker: (I) -> Unit) : AdviceInvoker<I, Void>
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
JSONObject.toJSONString(value)
|
|
||||||
} catch (_: JSONException) {
|
|
||||||
value.toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data class AdviceMeta(
|
data class AdviceMeta(
|
||||||
|
|||||||
Reference in New Issue
Block a user