/******************************************************************************* * Copyright 2012 Pradeep Nambiar, Pexus LLC * * Source File: src/org/perf/log/logger/PerfLoggerImplAsyncThreadAbstract.java * * 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 org.perf.log.logger; /** * This is an abstract Perf Logger implementation that uses * work manager to implement an asynchronous logger * to log performance data to a file and database * @author Pradeep Nambiar 2/10/2012 */ import java.util.ArrayList; import java.util.Properties; import java.util.concurrent.LinkedBlockingQueue; import org.perf.log.properties.LoggerProperties; import org.perf.log.properties.TunableProperties; import org.perf.log.utils.PropertyFileLoader; public abstract class PerfLoggerImplAsyncThreadAbstract implements PerfLogger { private final static Logger logger = LoggerFactory.getLogger(PerfLoggerImplAsyncThreadAbstract.class.getName()); // Async Logger Thread Implementation properties public static final String LOGGER_ASYNC_THREAD_LOGGER_NUM_ASYNC_LOGGER_TASK_THREADS = "static.logger.asyncThreadLogger.numAsyncLoggerTaskThreads"; // static property public static final String LOGGER_ASYNC_THREAD_LOGGER_MAX_Q_SIZE = "dynamic.logger.asyncThreadLogger.maxQSize"; // dynamic property public static final String LOGGER_ASYNC_THREAD_LOGGER_WORK_MANAGER_RESOURCE_NAME = "static.logger.asyncThreadLogger.workManagerResourceName"; // static property // Max records in a single Q static long maxQSize = 2000; // num instances of worker thread static int numAsyncLoggerTaskThreads = 2; // JNDI Resource for default work manager static String workManagerResourceName = "wm/default"; static ArrayList<LinkedBlockingQueue<PerfLogData>> perfLogQueueArrayList = new ArrayList<LinkedBlockingQueue<PerfLogData>>(); LogQueueMetricTracker logQueueMetricTrackerArray[]; int roundRobinCount = 0; static TunableProperties tunableProperties = LoggerProperties.getInstance().getTunableProperties(); static boolean propertiesInited = false; private synchronized void initProperties() { if(!propertiesInited) { try { String propVal; ClassLoader ctxClassLoader = Thread.currentThread().getContextClassLoader(); Properties props = PropertyFileLoader.load( "perfLog.properties", "perfLogDefault.properties", ctxClassLoader, this.getClass().getClassLoader(), PerfLoggerImplAsyncThreadAbstract.class.getName()); if (props != null) { propVal = props.getProperty(LOGGER_ASYNC_THREAD_LOGGER_MAX_Q_SIZE); if(propVal!=null) setMaxQSize(new Long(propVal).longValue()); propVal = props.getProperty(LOGGER_ASYNC_THREAD_LOGGER_NUM_ASYNC_LOGGER_TASK_THREADS); if(propVal!=null) setNumAsyncLoggerTaskThreads(new Integer(propVal).intValue()); propVal = props.getProperty(LOGGER_ASYNC_THREAD_LOGGER_WORK_MANAGER_RESOURCE_NAME); if(propVal!=null) setWorkManagerResourceName(propVal); } else { System.out.println(PerfLoggerImplAsyncThreadAbstract.class.getName() +":Error in reading perfLog.properties or perfLogDefault.properties"); } } catch (Exception exception) { System.out.println(PerfLoggerImplAsyncThreadAbstract.class.getName()+ ":Error Loading perfLog.properties or perfLogDefault.proeprties" + exception.getMessage()); } propertiesInited = true; } } public PerfLoggerImplAsyncThreadAbstract() { super(); // implementing class must look up work manager, initialize // start the asynchronous work on thread to dequeue PerfLogData from the queues // See sample implementations for WebSphere and CommonJ work managers initProperties(); } private synchronized int getQueueIndexToLog() { // do a round robin between the number of Queues available.. int index = roundRobinCount; roundRobinCount++; if (roundRobinCount == getNumAsyncLoggerTaskThreads()) roundRobinCount = 0; return index; } @Override public void log(PerfLogData perfLogData) { if (perfLogData != null && getLogEnabled(perfLogData.getTransactionTime())) { //--- Begin Log - if log enabled and exceeds log threshold int index = getQueueIndexToLog(); if (logQueueMetricTrackerArray[index].getQSize() <= getMaxQSize()) { perfLogQueueArrayList.get(index).add(perfLogData); logQueueMetricTrackerArray[index].incrementSize(); } else { // remove the oldest in the Q and add this one to the end.. // This will ensure the memory will not grow unbounded. // and at the same time keep the most recent perf log records // and increment the num dropped count.. perfLogQueueArrayList.get(index).remove(); perfLogQueueArrayList.get(index).add(perfLogData); logQueueMetricTrackerArray[index].incrementNumDropped(); } //--- End log } } @Override public void setLogEnabled(boolean logEnabled) { // TODO Auto-generated method stub } /** * @return the maxQSize */ public static long getMaxQSize() { String propertyValue = tunableProperties .getStaticProperty(LOGGER_ASYNC_THREAD_LOGGER_MAX_Q_SIZE); if (propertyValue != null) { maxQSize = new Long(propertyValue).longValue(); } return maxQSize; } /** * @return the numAsyncLoggerTaskThreads */ public static int getNumAsyncLoggerTaskThreads() { String propertyValue = tunableProperties .getStaticProperty(LOGGER_ASYNC_THREAD_LOGGER_NUM_ASYNC_LOGGER_TASK_THREADS); if (propertyValue != null) { numAsyncLoggerTaskThreads = new Integer(propertyValue).intValue(); } return numAsyncLoggerTaskThreads; } /** * @param maxQSize * the maxQSize to set */ public static void setMaxQSize(long maxQSize) { PerfLoggerImplAsyncThreadAbstract.maxQSize = maxQSize; } /** * @param numAsyncLoggerTaskThreads * the numAsyncLoggerTaskThreads to set */ public static void setNumAsyncLoggerTaskThreads(int numAsyncLoggerTasks) { PerfLoggerImplAsyncThreadAbstract.numAsyncLoggerTaskThreads = numAsyncLoggerTasks; } @Override public boolean getLogEnabled(long txnTimeInMillis) { return (LoggerProperties.getInstance().isPerfLoggerImplLogEnabled() && (txnTimeInMillis >= LoggerProperties .getInstance().getPerfLoggerImplLogThreshold())); } public static String getWorkManagerResourceName() { return workManagerResourceName; } public static void setWorkManagerResourceName(String workManagerResourceName) { PerfLoggerImplAsyncThreadAbstract.workManagerResourceName = workManagerResourceName; } }