/******************************************************************************* * Copyright 2012 Pradeep Nambiar, Pexus LLC * * Source File: src/org/perf/log/app/logger/CommonJAsyncThreadLogger.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.app.logger; /** *Implement asynchronous thread based logging using J2EE CommonJ * @author Pradeep Nambiar 9/27/2012 */ import java.util.ArrayList; import java.util.Properties; import java.util.concurrent.LinkedBlockingQueue; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import org.perf.log.app.logger.CommonJAsyncWorkerThread; import org.perf.log.logger.LogQueueMetricTracker; import org.perf.log.utils.PropertyFileLoader; import commonj.work.WorkException; import commonj.work.WorkManager; public class CommonJAsyncThreadLogger { // Async Logger Thread Implementation properties public static final String ASYNC_THREAD_LOGGER_NUM_ASYNC_LOGGER_TASK_THREADS = "commonJAsyncThreadLogger.numAsyncLoggerTaskThreads"; public static final String ASYNC_THREAD_LOGGER_MAX_Q_SIZE = "commonJAsyncThreadLogger.maxQSize"; public static final String ASYNC_THREAD_LOGGER_WORK_MANAGER_RESOURCE_NAME = "commonJAsyncThreadLogger.workManagerThreadPoolResourceName"; // Max records in a single Q static long maxQSize = 1000; // num instances of worker thread static int numAsyncLoggerTaskThreads = 2; // JNDI Resource for default work manager static String workManagerResourceName = "wm/default"; private Object syncObject = new Object(); static ArrayList<LinkedBlockingQueue<AppLogData>> appLogQueueArrayList = new ArrayList<LinkedBlockingQueue<AppLogData>>(); LogQueueMetricTracker logQueueMetricTrackerArray[]; private static Context ctx = null; int roundRobinCount = 0; static boolean inited = false; private void initProperties() { try { String propVal; ClassLoader ctxClassLoader = Thread.currentThread().getContextClassLoader(); Properties props = PropertyFileLoader.load( "perfLogAppLogger.properties", "perfLogAppLogerDefault.properties", ctxClassLoader, CommonJAsyncThreadLogger.class.getClass().getClassLoader(), CommonJAsyncThreadLogger.class.getName()); if (props != null) { propVal = props.getProperty(ASYNC_THREAD_LOGGER_MAX_Q_SIZE); if (propVal != null) setMaxQSize(new Long(propVal).longValue()); propVal = props .getProperty(ASYNC_THREAD_LOGGER_NUM_ASYNC_LOGGER_TASK_THREADS); if (propVal != null) setNumAsyncLoggerTaskThreads(new Integer(propVal) .intValue()); propVal = props .getProperty(ASYNC_THREAD_LOGGER_WORK_MANAGER_RESOURCE_NAME); if (propVal != null) setWorkManagerResourceName(propVal); } else { System.out.println(CommonJAsyncThreadLogger.class.getName() + ":Error in reading perfLogAppLogger properties"); } } catch (Exception exception) { System.out.println(CommonJAsyncThreadLogger.class.getName() + ":Error Loading perfLogAppLogger properties" + exception.getMessage()); } } public CommonJAsyncThreadLogger() { super(); // Initialize and start the worker threads if (inited == false) { synchronized (syncObject) { if (inited == false) { initProperties(); int numThreads = getNumAsyncLoggerTaskThreads(); logQueueMetricTrackerArray = new LogQueueMetricTracker[numThreads]; CommonJAsyncWorkerThread asyncLogTaskArray[] = new CommonJAsyncWorkerThread[numThreads]; // create the work objects for (int i = 0; i < numThreads; i++) { logQueueMetricTrackerArray[i] = new LogQueueMetricTracker(); appLogQueueArrayList.add(i, new LinkedBlockingQueue<AppLogData>()); asyncLogTaskArray[i] = new CommonJAsyncWorkerThread( "PerfLogAppLoggerAsyncWorkerThread_" + i, appLogQueueArrayList.get(i), logQueueMetricTrackerArray[i]); } try { ctx = new InitialContext(); WorkManager wm = (WorkManager) ctx .lookup("wm/default"); for (int i = 0; i < numThreads; i++) wm.schedule(asyncLogTaskArray[i]); } catch (NamingException e) { System.out.println(CommonJAsyncThreadLogger.class.getName()+"Exception:"+e.getMessage()); } catch (WorkException e) { System.out.println(CommonJAsyncThreadLogger.class.getName()+"Exception:"+e.getMessage()); } catch (IllegalArgumentException e) { System.out.println(CommonJAsyncThreadLogger.class.getName()+"Exception:"+e.getMessage()); } } // if } // sync } // if } 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; } public void log(AppLogData appLogData) { { //--- Begin Log - if log enabled and exceeds log threshold int index = getQueueIndexToLog(); if (logQueueMetricTrackerArray[index].getQSize() <= getMaxQSize()) { appLogQueueArrayList.get(index).add(appLogData); 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.. appLogQueueArrayList.get(index).remove(); appLogQueueArrayList.get(index).add(appLogData); logQueueMetricTrackerArray[index].incrementNumDropped(); } //--- End log } } /** * @return the maxQSize */ public static long getMaxQSize() { return maxQSize; } /** * @return the numAsyncLoggerTaskThreads */ public static int getNumAsyncLoggerTaskThreads() { return numAsyncLoggerTaskThreads; } /** * @param maxQSize * the maxQSize to set */ public static void setMaxQSize(long maxQSize) { CommonJAsyncThreadLogger.maxQSize = maxQSize; } /** * @param numAsyncLoggerTaskThreads * the numAsyncLoggerTaskThreads to set */ public static void setNumAsyncLoggerTaskThreads(int numAsyncLoggerTasks) { CommonJAsyncThreadLogger.numAsyncLoggerTaskThreads = numAsyncLoggerTasks; } public static String getWorkManagerResourceName() { return workManagerResourceName; } public static void setWorkManagerResourceName(String workManagerResourceName) { CommonJAsyncThreadLogger.workManagerResourceName = workManagerResourceName; } }