From 400dd25f492d4d1001267d4bb55402007e45bc8d Mon Sep 17 00:00:00 2001 From: sgoudham Date: Sun, 15 Jan 2023 03:41:17 +0000 Subject: [PATCH] feat: refactor and add time annotation --- pom.xml | 5 -- src/main/java/me/goudham/trace/Trace.java | 16 ---- .../me/goudham/trace/annotation/Time.java | 26 +++++++ .../me/goudham/trace/annotation/Trace.java | 26 +++++++ .../java/me/goudham/trace/domain/LogType.java | 19 +++++ .../trace/interceptor/TraceInterpreter.java | 45 ----------- .../goudham/trace/service/LoggingService.java | 30 ++++++++ .../me/goudham/trace/shared/Intercepter.java | 40 ++++++++++ .../goudham/trace/shared/TimeIntercepter.java | 45 +++++++++++ .../goudham/trace/shared/TimeInterpreter.java | 31 ++++++++ .../trace/shared/TraceIntercepter.java | 49 ++++++++++++ .../trace/shared/TraceInterpreter.java | 31 ++++++++ src/main/resources/logback.xml | 3 +- .../trace/shared/TimeIntercepterTest.java | 76 +++++++++++++++++++ .../TraceIntercepterTest.java} | 46 ++++++----- 15 files changed, 401 insertions(+), 87 deletions(-) delete mode 100644 src/main/java/me/goudham/trace/Trace.java create mode 100644 src/main/java/me/goudham/trace/annotation/Time.java create mode 100644 src/main/java/me/goudham/trace/annotation/Trace.java create mode 100644 src/main/java/me/goudham/trace/domain/LogType.java delete mode 100644 src/main/java/me/goudham/trace/interceptor/TraceInterpreter.java create mode 100644 src/main/java/me/goudham/trace/service/LoggingService.java create mode 100644 src/main/java/me/goudham/trace/shared/Intercepter.java create mode 100644 src/main/java/me/goudham/trace/shared/TimeIntercepter.java create mode 100644 src/main/java/me/goudham/trace/shared/TimeInterpreter.java create mode 100644 src/main/java/me/goudham/trace/shared/TraceIntercepter.java create mode 100644 src/main/java/me/goudham/trace/shared/TraceInterpreter.java create mode 100644 src/test/java/me/goudham/trace/shared/TimeIntercepterTest.java rename src/test/java/me/goudham/trace/{interceptor/TraceInterpreterTest.java => shared/TraceIntercepterTest.java} (57%) diff --git a/pom.xml b/pom.xml index 11a4aa7..a132ceb 100644 --- a/pom.xml +++ b/pom.xml @@ -75,11 +75,6 @@ micronaut-inject compile - - io.micronaut - micronaut-jackson-databind - compile - ch.qos.logback logback-classic diff --git a/src/main/java/me/goudham/trace/Trace.java b/src/main/java/me/goudham/trace/Trace.java deleted file mode 100644 index c5d91d0..0000000 --- a/src/main/java/me/goudham/trace/Trace.java +++ /dev/null @@ -1,16 +0,0 @@ -package me.goudham.trace; - -import io.micronaut.aop.Around; -import jakarta.inject.Qualifier; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Qualifier -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -@Around -public @interface Trace { -} \ No newline at end of file diff --git a/src/main/java/me/goudham/trace/annotation/Time.java b/src/main/java/me/goudham/trace/annotation/Time.java new file mode 100644 index 0000000..87c795e --- /dev/null +++ b/src/main/java/me/goudham/trace/annotation/Time.java @@ -0,0 +1,26 @@ +package me.goudham.trace.annotation; + +import io.micronaut.aop.Around; +import jakarta.inject.Qualifier; +import me.goudham.trace.shared.TimeInterpreter; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * {@code @Time} calculates the execution time of the + * annotated method and logs it. + *

+ *

It is important to note that these logs will only be seen if {@link System.Logger} + * is configured to log at {@link System.Logger.Level#TRACE}

+ * + * @see TimeInterpreter + */ +@Qualifier +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Around +public @interface Time { +} \ No newline at end of file diff --git a/src/main/java/me/goudham/trace/annotation/Trace.java b/src/main/java/me/goudham/trace/annotation/Trace.java new file mode 100644 index 0000000..38e4e4a --- /dev/null +++ b/src/main/java/me/goudham/trace/annotation/Trace.java @@ -0,0 +1,26 @@ +package me.goudham.trace.annotation; + +import io.micronaut.aop.Around; +import jakarta.inject.Qualifier; +import me.goudham.trace.shared.TraceInterpreter; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * {@code @Trace} indicates that the current method will be monitored to allow + * logging when the method was entered and exited. + *

+ *

It is important to note that these logs will only be seen if {@link System.Logger} + * is configured to log at {@link System.Logger.Level#TRACE}

+ * + * @see TraceInterpreter + */ +@Qualifier +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Around +public @interface Trace { +} \ No newline at end of file diff --git a/src/main/java/me/goudham/trace/domain/LogType.java b/src/main/java/me/goudham/trace/domain/LogType.java new file mode 100644 index 0000000..d11f0c8 --- /dev/null +++ b/src/main/java/me/goudham/trace/domain/LogType.java @@ -0,0 +1,19 @@ +package me.goudham.trace.domain; + +import me.goudham.trace.shared.TimeInterpreter; +import me.goudham.trace.shared.TraceInterpreter; +import me.goudham.trace.service.LoggingService; + +/** + * Represents each type that's used for logging + * + * @see LoggingService + * @see TraceInterpreter + * @see TimeInterpreter + */ +public enum LogType { + ENTERING, + EXITING, + ERROR, + EXECUTION_TIME +} \ No newline at end of file diff --git a/src/main/java/me/goudham/trace/interceptor/TraceInterpreter.java b/src/main/java/me/goudham/trace/interceptor/TraceInterpreter.java deleted file mode 100644 index dde0114..0000000 --- a/src/main/java/me/goudham/trace/interceptor/TraceInterpreter.java +++ /dev/null @@ -1,45 +0,0 @@ -package me.goudham.trace.interceptor; - -import io.micronaut.aop.InterceptorBean; -import io.micronaut.aop.MethodInterceptor; -import io.micronaut.aop.MethodInvocationContext; -import jakarta.inject.Singleton; -import me.goudham.trace.Trace; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Arrays; -import java.util.stream.Collectors; - -@Singleton -@InterceptorBean(Trace.class) -public class TraceInterpreter implements MethodInterceptor { - - @Override - public Object intercept(MethodInvocationContext context) { - Logger logger = LoggerFactory.getLogger(context.getDeclaringType()); - if (logger.isTraceEnabled()) { - return executeMethod(context, logger); - } - return context.proceed(); - } - - protected Object executeMethod(MethodInvocationContext context, Logger logger) { - Object result; - String methodName = context.getMethodName(); - String signature = Arrays.stream(context.getArguments()) - .map(argument -> argument.getTypeName() + " " + argument.getName()) - .collect(Collectors.joining(", ")); - - logger.trace("[ENTERING]: {}({})", methodName, signature); - try { - result = context.proceed(); - } catch (Throwable throwable) { - logger.trace("[ERROR]: {}({})", methodName, signature); - throw throwable; - } - logger.trace("[EXITING]: {}({})", methodName, signature); - - return result; - } -} \ No newline at end of file diff --git a/src/main/java/me/goudham/trace/service/LoggingService.java b/src/main/java/me/goudham/trace/service/LoggingService.java new file mode 100644 index 0000000..1981e60 --- /dev/null +++ b/src/main/java/me/goudham/trace/service/LoggingService.java @@ -0,0 +1,30 @@ +package me.goudham.trace.service; + +import jakarta.inject.Singleton; +import me.goudham.trace.domain.LogType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Encapsulates the built-in {@link Logger} + */ +@Singleton +public class LoggingService { + private Logger logger; + + public void trace(LogType logType, String method, String signature) { + logger.trace("[{}]: {}({})", logType.name(), method, signature); + } + + public void trace(LogType logType, String method, String signature, long timeElapsed) { + logger.trace("[{}]: Elapsed execution time for {}({}) is {} milliseconds", logType.name(), method, signature, timeElapsed); + } + + public void setLogger(Class clazz) { + logger = LoggerFactory.getLogger(clazz); + } + + public boolean isTraceEnabled() { + return logger.isTraceEnabled(); + } +} \ No newline at end of file diff --git a/src/main/java/me/goudham/trace/shared/Intercepter.java b/src/main/java/me/goudham/trace/shared/Intercepter.java new file mode 100644 index 0000000..0a175e7 --- /dev/null +++ b/src/main/java/me/goudham/trace/shared/Intercepter.java @@ -0,0 +1,40 @@ +package me.goudham.trace.shared; + +import io.micronaut.aop.MethodInterceptor; +import io.micronaut.aop.MethodInvocationContext; +import me.goudham.trace.service.LoggingService; + +import java.util.Arrays; +import java.util.stream.Collectors; + +abstract class Intercepter implements MethodInterceptor { + final LoggingService loggingService; + + Intercepter(LoggingService loggingService) { + this.loggingService = loggingService; + } + + abstract Object logAndExecuteMethod(MethodInvocationContext context); + + @Override + public Object intercept(MethodInvocationContext context) { + loggingService.setLogger(context.getDeclaringType()); + if (loggingService.isTraceEnabled()) { + return logAndExecuteMethod(context); + } + return context.proceed(); + } + + /** + * {@link java.util.stream.Stream}'s over all method arguments, + * joining the type and name together into one string. + * + * @param context Object representing information about the annotated method + * @return {@code String} containing all method arguments separated by commas + */ + String getArguments(MethodInvocationContext context) { + return Arrays.stream(context.getArguments()) + .map(argument -> argument.getTypeName() + " " + argument.getName()) + .collect(Collectors.joining(", ")); + } +} \ No newline at end of file diff --git a/src/main/java/me/goudham/trace/shared/TimeIntercepter.java b/src/main/java/me/goudham/trace/shared/TimeIntercepter.java new file mode 100644 index 0000000..836d99f --- /dev/null +++ b/src/main/java/me/goudham/trace/shared/TimeIntercepter.java @@ -0,0 +1,45 @@ +package me.goudham.trace.shared; + +import io.micronaut.aop.MethodInvocationContext; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import me.goudham.trace.annotation.Time; +import me.goudham.trace.domain.LogType; +import me.goudham.trace.service.LoggingService; + +import java.util.concurrent.TimeUnit; + +/** + * Intercepts the annotated method and logs out the + * execution time of the entire method. + * + * @see Time + */ +@Singleton +class TimeIntercepter extends Intercepter { + + @Inject + TimeIntercepter(LoggingService loggingService) { + super(loggingService); + } + + /** + * Logs the execution time of the annotated method. + * The method name and signature are included within + * the log itself. + * + * @param context Object representing information about the annotated method + * @return Result of annotated method after execution + */ + @Override + Object logAndExecuteMethod(MethodInvocationContext context) { + long start = System.nanoTime(); + Object result = context.proceed(); + long finish = System.nanoTime(); + long timeElapsed = TimeUnit.NANOSECONDS.toMillis(finish - start); + + loggingService.trace(LogType.EXECUTION_TIME, context.getMethodName(), getArguments(context), timeElapsed); + + return result; + } +} \ No newline at end of file diff --git a/src/main/java/me/goudham/trace/shared/TimeInterpreter.java b/src/main/java/me/goudham/trace/shared/TimeInterpreter.java new file mode 100644 index 0000000..7702d2e --- /dev/null +++ b/src/main/java/me/goudham/trace/shared/TimeInterpreter.java @@ -0,0 +1,31 @@ +package me.goudham.trace.shared; + +import io.micronaut.aop.InterceptorBean; +import io.micronaut.aop.MethodInterceptor; +import io.micronaut.aop.MethodInvocationContext; +import jakarta.inject.Inject; +import jakarta.inject.Named; +import jakarta.inject.Singleton; +import me.goudham.trace.annotation.Time; + +/** + * Intercepts the annotated method and logs out the + * execution time of the entire method. + * + * @see Time + */ +@Singleton +@InterceptorBean(Time.class) +public class TimeInterpreter implements MethodInterceptor { + private final Intercepter intercepter; + + @Inject + public TimeInterpreter(@Named("Time") Intercepter intercepter) { + this.intercepter = intercepter; + } + + @Override + public Object intercept(MethodInvocationContext context) { + return intercepter.intercept(context); + } +} \ No newline at end of file diff --git a/src/main/java/me/goudham/trace/shared/TraceIntercepter.java b/src/main/java/me/goudham/trace/shared/TraceIntercepter.java new file mode 100644 index 0000000..599a0c0 --- /dev/null +++ b/src/main/java/me/goudham/trace/shared/TraceIntercepter.java @@ -0,0 +1,49 @@ +package me.goudham.trace.shared; + +import io.micronaut.aop.MethodInvocationContext; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import me.goudham.trace.annotation.Trace; +import me.goudham.trace.domain.LogType; +import me.goudham.trace.service.LoggingService; + +/** + * Intercepts the annotated method and logs out when it + * was entered and exited. + * + * @see Trace + */ +@Singleton +class TraceIntercepter extends Intercepter { + + @Inject + TraceIntercepter(LoggingService loggingService) { + super(loggingService); + } + + /** + * Logs before and after the method is called. + * The method name and signature are included + * within the log itself. + * + * @param context Object representing information about the annotated method + * @return Result of annotated method after execution + */ + @Override + Object logAndExecuteMethod(MethodInvocationContext context) { + Object result; + String name = context.getMethodName(); + String signature = getArguments(context); + + loggingService.trace(LogType.ENTERING, name, signature); + try { + result = context.proceed(); + } catch (Throwable throwable) { + loggingService.trace(LogType.ERROR, name, signature); + throw throwable; + } + loggingService.trace(LogType.EXITING, name, signature); + + return result; + } +} \ No newline at end of file diff --git a/src/main/java/me/goudham/trace/shared/TraceInterpreter.java b/src/main/java/me/goudham/trace/shared/TraceInterpreter.java new file mode 100644 index 0000000..ae922d9 --- /dev/null +++ b/src/main/java/me/goudham/trace/shared/TraceInterpreter.java @@ -0,0 +1,31 @@ +package me.goudham.trace.shared; + +import io.micronaut.aop.InterceptorBean; +import io.micronaut.aop.MethodInterceptor; +import io.micronaut.aop.MethodInvocationContext; +import jakarta.inject.Inject; +import jakarta.inject.Named; +import jakarta.inject.Singleton; +import me.goudham.trace.annotation.Trace; + +/** + * Intercepts the annotated method and logs out when it + * was entered and exited. + * + * @see Trace + */ +@Singleton +@InterceptorBean(Trace.class) +public class TraceInterpreter implements MethodInterceptor { + private final Intercepter traceIntercepter; + + @Inject + public TraceInterpreter(@Named("Trace") Intercepter traceIntercepter) { + this.traceIntercepter = traceIntercepter; + } + + @Override + public Object intercept(MethodInvocationContext context) { + return traceIntercepter.intercept(context); + } +} \ No newline at end of file diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 3145c36..5aace44 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -1,5 +1,4 @@ - true