de.alexandria.cms.frontend.webapp.aop.AopMethodLogger.java Source code

Java tutorial

Introduction

Here is the source code for de.alexandria.cms.frontend.webapp.aop.AopMethodLogger.java

Source

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package de.alexandria.cms.frontend.webapp.aop;

import java.lang.reflect.Proxy;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.CodeSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

/**
 * Aspekt: Logging method calls. Log all public service calls and all public repository calls.
 *
 * @author ralf
 */
@Aspect
@Component
public class AopMethodLogger {

    private static Logger logger = LoggerFactory.getLogger(AopMethodLogger.class);

    @Pointcut("execution(public * de.alexandria.cms.frontend.webapp.controller..*Controller.*(..)) || "
            + "execution(public * de.alexandria.cms.business.impl.service..*Service.*(..)) || "
            + "execution(public * de.alexandria.cms.backend.impl.repository..*.*Repository.*(..))")
    public void methodsToBeLogged() {
    }

    /**
     * Protokolliert die Ausfhrung eines join points und dessen Parameter. Paremeter werden nur angezeigt, wenn der
     * Wert nicht null ist.
     *
     * In aspect-oriented programming a set of join points is called a pointcut. A join point is a specification of
     * when, in the corresponding main program, the aspect code should be executed. The join point is a point of
     * execution in the base code where the advice specified in a corresponding pointcut is applied.
     *
     * @param joinPoint Das Event des Advices
     */
    @Before("methodsToBeLogged()")
    public void logMethodCall(JoinPoint joinPoint) {
        final Object target = joinPoint.getTarget();
        Class<?> targetClass = target.getClass();
        if (target instanceof Proxy) {
            targetClass = AopUtils.getTargetClass(target);
        }
        String targetClassName = targetClass.getName();
        String logMsg = createMsgForLogMethodCall(joinPoint);
        Logger targetLog = LoggerFactory.getLogger(targetClassName);
        targetLog.info(logMsg);
    }

    String createMsgForLogMethodCall(JoinPoint joinPoint) {
        StringBuilder buffer = new StringBuilder();
        String targetMethodName = joinPoint.getSignature().getName();
        buffer.append(targetMethodName);
        buffer.append("(");
        final Object[] args = joinPoint.getArgs();
        CodeSignature codeSignature = (CodeSignature) joinPoint.getSignature();
        String[] argNames = codeSignature.getParameterNames();
        for (int i = 0; i < args.length; i++) {
            final Object arg = args[i];
            if (arg != null) {
                String argName = null;
                if (argNames != null) {
                    argName = argNames[i];
                    if (argName != null) {
                        buffer.append(argNames[i]);
                        buffer.append("=");
                    }
                }
                buffer.append(arg.getClass().getSimpleName());
                buffer.append((" "));

                String argValue = arg.toString();

                // mask security sensible data
                if (argName != null && (argName.contains("password") || argName.contains("pwd"))) {
                    argValue = "***";
                }
                if (argValue.length() > 50) {
                    argValue = argValue.substring(0, 49) + "...";
                }
                buffer.append(argValue);
                if (i < (args.length - 1)) {
                    buffer.append(", ");
                }
            }
        }
        buffer.append(")");
        return buffer.toString();
    }

    /**
     *
     * Protokolliert die Laufzeit des join points. Das logging ist nur aktiv, wenn {@link #logger} mindestens
     * debug-Level hat.
     *
     * @param call
     * @return
     * @throws Throwable
     */
    @Around("methodsToBeLogged()")
    public Object logMethodDuration(ProceedingJoinPoint call) throws Throwable { // NOSONAR
        // proceed bentigt das Weiterreichen der Exception (throws Throwable)...
        Object returnValue;
        if (logger.isDebugEnabled()) {
            String targetClassName = call.getTarget().getClass().getName();
            String targetMethodName = call.getSignature().getName();
            Logger targetLog = LoggerFactory.getLogger(targetClassName);
            if (targetLog.isDebugEnabled()) {
                StopWatch clock = new StopWatch(getClass().getName());
                try {
                    clock.start(call.toShortString());
                    returnValue = call.proceed();
                } finally {
                    clock.stop();
                    String msg = createMsgForLogMethodDuration(targetMethodName, clock.getTotalTimeMillis());
                    targetLog.debug(msg);
                }
            } else {
                returnValue = call.proceed();
            }
        } else {
            returnValue = call.proceed();
        }
        return returnValue;
    }

    String createMsgForLogMethodDuration(String targetMethodName, long duration) {
        final StringBuilder sb = new StringBuilder();
        sb.append(targetMethodName).append("(): ");
        sb.append("duration ").append(duration).append(" ms");
        return sb.toString();
    }

    /**
     * Existiert zum Testen, so kann ein Logger-Mock gesetzt werden.
     *
     * @param logger
     */
    static void setLogger(Logger logger) {
        AopMethodLogger.logger = logger;
    }
}