de.huxhorn.lilith.tracing.TracingAspect.java Source code

Java tutorial

Introduction

Here is the source code for de.huxhorn.lilith.tracing.TracingAspect.java

Source

/*
 * Lilith - a log event viewer.
 * Copyright (C) 2007-2017 Joern Huxhorn
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * Copyright 2007-2017 Joern Huxhorn
 *
 * 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.huxhorn.lilith.tracing;

import de.huxhorn.sulky.formatting.SafeString;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;

public class TracingAspect {
    public static final String TRACED_CLASS_MDC_KEY = "tracedClass";
    public static final String TRACED_METHOD_MDC_KEY = "tracedMethod";

    public static final String ENTERING_MARKER_NAME = "ENTERING";
    public static final String EXITING_MARKER_NAME = "EXITING";
    public static final String THROWING_MARKER_NAME = "THROWING";
    public static final String TRACE_MARKER_NAME = "TRACE";

    private static final Marker ENTERING_MARKER = MarkerFactory.getDetachedMarker(ENTERING_MARKER_NAME);
    private static final Marker EXITING_MARKER = MarkerFactory.getDetachedMarker(EXITING_MARKER_NAME);
    private static final Marker THROWING_MARKER = MarkerFactory.getDetachedMarker(THROWING_MARKER_NAME);
    private static final Marker TRACE_MARKER = MarkerFactory.getDetachedMarker(TRACE_MARKER_NAME);

    static {
        ENTERING_MARKER.add(TRACE_MARKER);
        EXITING_MARKER.add(TRACE_MARKER);
        THROWING_MARKER.add(TRACE_MARKER);
    }

    private String loggerName;
    private Logger logger;
    private boolean showingParameterValues;
    private boolean usingShortClassName;
    private boolean showingModifiers;
    private ProfilingHandler profilingHandler;

    public TracingAspect() {
        showingParameterValues = true;
        usingShortClassName = false;
        showingModifiers = false;
        profilingHandler = new BasicProfilingHandler();
    }

    public boolean isShowingParameterValues() {
        return showingParameterValues;
    }

    public void setShowingParameterValues(boolean showingParameterValues) {
        this.showingParameterValues = showingParameterValues;
    }

    public boolean isUsingShortClassName() {
        return usingShortClassName;
    }

    public void setUsingShortClassName(boolean usingShortClassName) {
        this.usingShortClassName = usingShortClassName;
    }

    public boolean isShowingModifiers() {
        return showingModifiers;
    }

    public void setShowingModifiers(boolean showingModifiers) {
        this.showingModifiers = showingModifiers;
    }

    public ProfilingHandler getProfilingHandler() {
        return profilingHandler;
    }

    public void setProfilingHandler(ProfilingHandler profilingHandler) {
        this.profilingHandler = profilingHandler;
    }

    public String getLoggerName() {
        return loggerName;
    }

    public void setLoggerName(String loggerName) {
        this.loggerName = loggerName;
        if (loggerName != null) {
            logger = LoggerFactory.getLogger(loggerName);
        } else {
            logger = LoggerFactory.getLogger(TracingAspect.class);
        }
    }

    @Override
    public String toString() {
        return "TracingAspect{loggerName=" + loggerName + ", showingParameterValues=" + showingParameterValues
                + ", usingShortClassName=" + usingShortClassName + ", showingModifiers=" + showingModifiers
                + ", profilingHandler=" + profilingHandler + "}";
    }

    public Object trace(ProceedingJoinPoint call) throws Throwable {
        if (logger == null) {
            setLoggerName(null);
            // this initializes the logger
        }
        Signature signature = call.getSignature();
        Class<?> clazz = signature.getDeclaringType();
        Object theTarget = call.getTarget();
        if (theTarget != null) {
            clazz = theTarget.getClass();
        }
        String fullClassName = clazz.getName();
        String methodName = signature.getName();
        StringBuilder msg = new StringBuilder();
        if (showingModifiers) {
            msg.append(Modifier.toString(signature.getModifiers())).append(' ');
        }
        if (usingShortClassName) {
            msg.append(clazz.getSimpleName());
        } else {
            msg.append(fullClassName);
        }
        msg.append('.').append(methodName);
        String methodBaseName = msg.toString();
        if (signature instanceof MethodSignature) {
            MethodSignature methodSignature = (MethodSignature) signature;
            msg.append('(');
            if (showingParameterValues) {
                Object[] args = call.getArgs();
                boolean first = true;
                for (Object arg : args) {
                    if (first) {
                        first = false;
                    } else {
                        msg.append(", ");
                    }
                    msg.append(SafeString.toString(arg, SafeString.StringWrapping.ALL,
                            SafeString.StringStyle.GROOVY, SafeString.MapStyle.GROOVY));
                }
            } else {
                Method method = methodSignature.getMethod();
                Class<?>[] parameterTypes = method.getParameterTypes();
                boolean first = true;
                for (Class<?> param : parameterTypes) {
                    if (first) {
                        first = false;
                    } else {
                        msg.append(", ");
                    }
                    msg.append(param.getSimpleName());
                }
                if (method.isVarArgs()) {
                    int length = msg.length();
                    msg.delete(length - 2, length); // cut of existing []
                    msg.append("...");
                }
            }
            msg.append(')');
        }
        String methodSignatureString = msg.toString();

        String previousClass = MDC.get(TRACED_CLASS_MDC_KEY);
        String previousMethod = MDC.get(TRACED_METHOD_MDC_KEY);
        long nanoSeconds = 0;
        try {
            MDC.put(TRACED_CLASS_MDC_KEY, fullClassName);
            MDC.put(TRACED_METHOD_MDC_KEY, methodName);
            if (logger.isInfoEnabled(ENTERING_MARKER))
                logger.info(ENTERING_MARKER, "{} entered.", methodSignatureString);
            Object result;
            nanoSeconds = System.nanoTime();
            result = call.proceed();
            nanoSeconds = System.nanoTime() - nanoSeconds;
            profile(methodBaseName, methodSignatureString, nanoSeconds);
            if (result == null || !showingParameterValues) {
                if (logger.isInfoEnabled(EXITING_MARKER))
                    logger.info(EXITING_MARKER, "{} returned.", methodSignatureString);
            } else {
                if (logger.isInfoEnabled(EXITING_MARKER))
                    logger.info(EXITING_MARKER, "{} returned {}.", methodSignatureString, result);
            }
            return result;
        } catch (Throwable t) {
            nanoSeconds = System.nanoTime() - nanoSeconds;
            profile(methodBaseName, methodSignatureString, nanoSeconds);
            if (logger.isInfoEnabled(THROWING_MARKER))
                logger.info(THROWING_MARKER, "{} failed.", methodSignatureString, t);
            throw t; // rethrow
        } finally {
            if (previousClass == null) {
                MDC.remove(TRACED_CLASS_MDC_KEY);
            } else {
                MDC.put(TRACED_CLASS_MDC_KEY, previousClass);
            }
            if (previousMethod == null) {
                MDC.remove(TRACED_METHOD_MDC_KEY);
            } else {
                MDC.put(TRACED_METHOD_MDC_KEY, previousMethod);
            }
        }
    }

    private void profile(String methodBaseName, String fullMethodSignature, long nanoSeconds) {
        if (profilingHandler != null) {
            logger.info("{}", profilingHandler);
            profilingHandler.profile(logger, methodBaseName, fullMethodSignature, nanoSeconds);
        }
    }
}