/** * The contents of this file are subject to the OpenMRS Public License * Version 1.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://license.openmrs.org * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * Copyright (C) OpenMRS, LLC. All Rights Reserved. */ package org.openmrs.aop; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.openmrs.annotation.Logging; /** * This class provides the log4j aop around advice for our service layer. This advice is placed on * all services and daos via the spring application context. See * /metadata/api/spring/applicationContext.xml */ public class LoggingAdvice implements MethodInterceptor { /** * Logger for this class. Uses the name "org.openmrs.api" so that it seems to fit into the * log4j.xml configuration */ protected static final Log log = LogFactory.getLog("org.openmrs.api"); /** * This method prints out debug statements for getters and info statements for everything else * ("setters"). If debugging is turned on, execution time for each method is printed as well. * This method is called for every method in the Class/Service that it is wrapped around. This * method should be fairly quick and light. * * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) */ public Object invoke(MethodInvocation invocation) throws Throwable { Method method = invocation.getMethod(); String name = method.getName(); // decide what type of logging we're doing with the current method and loglevel boolean isGetterTypeOfMethod = name.startsWith("get") || name.startsWith("find"); boolean logGetter = isGetterTypeOfMethod && log.isDebugEnabled(); boolean logSetter = !isGetterTypeOfMethod && log.isInfoEnabled(); // used for the execution time calculations long startTime = new Date().getTime(); if (logGetter || logSetter) { StringBuilder output = new StringBuilder(); output.append("In method ").append(method.getDeclaringClass().getSimpleName()).append(".").append(name); // check if this method has the logging annotation on it Logging loggingAnnotation = method.getAnnotation(Logging.class); // print the argument values unless we're ignoring all if (loggingAnnotation == null || loggingAnnotation.ignoreAllArgumentValues() == false) { int x; Class<?>[] types = method.getParameterTypes(); Object[] values = invocation.getArguments(); // change the annotation array of indexes to a list of indexes to ignore List<Integer> argsToIgnore = new ArrayList<Integer>(); if (loggingAnnotation != null && loggingAnnotation.ignoredArgumentIndexes().length > 0) { for (int argIndexToIgnore : loggingAnnotation.ignoredArgumentIndexes()) argsToIgnore.add(argIndexToIgnore); } // loop over and print out each argument value output.append(". Arguments: "); for (x = 0; x < types.length; x++) { output.append(types[x].getSimpleName()).append("="); // if there is an annotation to skip this, print out a bogus string. if (argsToIgnore.contains(x)) output.append("<Arg value ignored>"); else output.append(values[x]); output.append(", "); } } // print the string as either debug or info if (logGetter) log.debug(output.toString()); else if (logSetter) log.info(output.toString()); } try { // do the actual method we're wrapped around return invocation.proceed(); } catch (Throwable t) { if (logGetter || logSetter) log.error("An error occurred while executing this method. Error message: " + t.getMessage(), t); throw t; } finally { if (logGetter || logSetter) { StringBuilder output = new StringBuilder(); output.append("Exiting method ").append(name); // only append execution time info if we're in debug mode if (log.isDebugEnabled()) output.append(". execution time: " + (new Date().getTime() - startTime)).append(" ms"); // print the string as either debug or info if (logGetter) log.debug(output.toString()); else if (logSetter) log.info(output.toString()); } } } }