/******************************************************************************* * Copyright 2012 Pradeep Nambiar, Pexus LLC * * Source File: src/org/perf/log/logger/AbsAsyncLoggerTask.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; /** * Abstract Asynchronous Worker Thread run() implementation * The thread is created in PerfLoggerImplXXXX class * Multiple threads can be created that listens to independent queues * The PerfLoggerImplXXX class uses a simple round robin * to queue to multiple queues * This abstract class implements methods that can be used * in either WebSphere Work Manager or CommonJ Work Manager APIs * * @author Pradeep Nambiar 2/10/2012 */ import java.util.Properties; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import org.perf.log.properties.LoggerProperties; import org.perf.log.properties.TunableProperties; import org.perf.log.utils.PropertyFileLoader; public abstract class AsyncLoggerWorkerThreadAbstract { private final static Logger logger = LoggerFactory.getLogger(AsyncLoggerWorkerThreadAbstract.class.getName()); String asyncLogTaskName; LinkedBlockingQueue<PerfLogData> logQueue; LogQueueMetricTracker logQueueMetricTracker; // Property Names // following can be set dynamically public static final String LOGGER_ASYNC_THREAD_LOGGER_MIN_FLUSH_THRESHOLD = "dynamic.logger.asyncThreadLogger.minFlushThreshold"; // dynamic public static final String LOGGER_ASYNC_THREAD_LOGGER_THREAD_SLEEP_TIME_IN_MILLIS = "dynamic.logger.asyncThreadLogger.threadSleepTimeInMillis"; // dynamic public static final String LOGGER_ASYNC_THREAD_LOGGER_PRINT_STAT_TIME_INTERVAL_IN_MILLIS = "dynamic.logger.asyncThreadLogger.printStatTimeInMillis";// dynamic static int minFlushThreshold = 500; static long threadSleepTimeInMillis = 10000; static long printStatTimeIntervalInMillis = 600000; static boolean terminateThread = false; private static TunableProperties tunableProperties = LoggerProperties.getInstance().getTunableProperties(); private 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(), AsyncLoggerWorkerThreadAbstract.class.getName()); if (props != null) { propVal = props .getProperty(LOGGER_ASYNC_THREAD_LOGGER_MIN_FLUSH_THRESHOLD); if (propVal != null) setMinFlushThreshold(new Integer(propVal).intValue()); propVal = props .getProperty(LOGGER_ASYNC_THREAD_LOGGER_PRINT_STAT_TIME_INTERVAL_IN_MILLIS); if (propVal != null) setPrintStatTimeIntervalInMillis(new Long(propVal) .longValue()); propVal = props .getProperty(LOGGER_ASYNC_THREAD_LOGGER_THREAD_SLEEP_TIME_IN_MILLIS); if (propVal != null) setThreadSleepTimeInMillis(new Long(propVal) .longValue()); } else { System.out.println(AsyncLoggerWorkerThreadAbstract.class.getName()+ ":Error in reading perfLog.properties or perfLogDefault.properties"); } } catch (Exception exception) { System.out.println(AsyncLoggerWorkerThreadAbstract.class.getName()+ ":Error Loading perfLog.properties or perfLogDefault.properties" + exception.getMessage()); } propertiesInited = true; } } public AsyncLoggerWorkerThreadAbstract(String asyncLogTaskName, LinkedBlockingQueue<PerfLogData> logQueue, LogQueueMetricTracker logQueueMetricTracker) { super(); this.asyncLogTaskName = asyncLogTaskName; this.logQueue = logQueue; this.logQueueMetricTracker = logQueueMetricTracker; initProperties(); } public void release() { // stop the thread terminateThread = true; } public void run() { Thread.currentThread().setPriority(Thread.MIN_PRIORITY); // add thread name to the task name this.asyncLogTaskName = Thread.currentThread().getName() + ":" + this.asyncLogTaskName; logQueueMetricTracker.setThreadManagingThisQueue(Thread.currentThread()); // Configuration params System.out.println(asyncLogTaskName + ": Worker thread started."); long lastPrintStatTimeInMillis = System.currentTimeMillis(); System.out.println(asyncLogTaskName + ": " + logQueueMetricTracker.getStats()); // iterate over the queue and write to file and DB while (!terminateThread) { try { PerfLogData logData = logQueue.poll(getThreadSleepTimeInMillis(), TimeUnit.MILLISECONDS);; if(logData != null) { // Write to performance log file if enabled if(FileWriter.isFileWriterEnabled()) try { FileWriter.write(logData); } catch (Exception e) { // An exception occurred, increment error count and continue logQueueMetricTracker.incrementNumErrored(); } // Write to performance database if enabled if(DBWriter.isDbWriterEnabled()) try { DBWriter.write(logData); } catch (Exception e) { // An Exception occurred while writing to DB, increment error count and continue logQueueMetricTracker.incrementNumErrored(); } logQueueMetricTracker.decrementSize(); } if ((System.currentTimeMillis() - lastPrintStatTimeInMillis) > printStatTimeIntervalInMillis) { System.out.println(asyncLogTaskName + ": PerfLog Stats : " + logQueueMetricTracker.getStats()); lastPrintStatTimeInMillis = System.currentTimeMillis(); } } catch(InterruptedException e) { // ignore.. } } System.out.println(asyncLogTaskName + ": " + logQueueMetricTracker.getStats()); System.out.println(asyncLogTaskName + ": Worker thread terminated."); } /** * @return the minFlushThreshold */ public static int getMinFlushThreshold() { String propertyValue = tunableProperties.getDynamicProperty(LOGGER_ASYNC_THREAD_LOGGER_MIN_FLUSH_THRESHOLD); if(propertyValue != null) { return new Integer(propertyValue).intValue(); } else // return value initialized in this class return minFlushThreshold; } /** * @return the threadSleepTimeInMillis */ public static long getThreadSleepTimeInMillis() { String propertyValue = tunableProperties.getDynamicProperty(LOGGER_ASYNC_THREAD_LOGGER_THREAD_SLEEP_TIME_IN_MILLIS); if(propertyValue != null) { return new Long(propertyValue).longValue(); } else return threadSleepTimeInMillis; } /** * @return the printStatTimeIntervalInMillis */ public static long getPrintStatTimeIntervalInMillis() { String propertyValue = tunableProperties.getDynamicProperty(LOGGER_ASYNC_THREAD_LOGGER_PRINT_STAT_TIME_INTERVAL_IN_MILLIS); if(propertyValue != null) { return new Integer(propertyValue).intValue(); } else return printStatTimeIntervalInMillis; } /** * @param minFlushThreshold the minFlushThreshold to set */ public static void setMinFlushThreshold(int minFlushThreshold) { AsyncLoggerWorkerThreadAbstract.minFlushThreshold = minFlushThreshold; } /** * @param threadSleepTimeInMillis the threadSleepTimeInMillis to set */ public static void setThreadSleepTimeInMillis(long threadSleepTimeInMillis) { AsyncLoggerWorkerThreadAbstract.threadSleepTimeInMillis = threadSleepTimeInMillis; } /** * @param printStatTimeIntervalInMillis the printStatTimeIntervalInMillis to set */ public static void setPrintStatTimeIntervalInMillis( long printStatTimeIntervalInMillis) { AsyncLoggerWorkerThreadAbstract.printStatTimeIntervalInMillis = printStatTimeIntervalInMillis; } public boolean isDaemon() { return true; } }