/******************************************************************************* * Copyright 2012 Pradeep Nambiar, Pexus LLC * * Source File: src/org/perf/log/context/PerfLogContextHelper.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.context; import java.lang.management.GarbageCollectorMXBean; import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; import java.lang.management.ThreadMXBean; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import org.perf.log.logger.*; import org.perf.log.properties.PerfLogContextProperties; import org.perf.log.properties.LoggerProperties; import org.perf.log.properties.TxnThresholdProps; import org.perf.log.txn.types.PerfLogTxnType; import org.perf.log.utils.RuntimeEnvHelper; /** * This class enables creating and managing log context data that can be accessed * by any logger. Log context data is created and deleted from filters such as Portlet Filter, Servlet Filter * Struts Interceptors, Web Service handlers and SQL handlers etc. They are used to track requests with * a JVM and across JVMs. The contextual data can be used by tools such as Splunk to correlate log outputs * for diagnosis */ public class PerfLogContextHelper { private final static Logger logger = LoggerFactory.getLogger("PerfLogContextHelper"); private static final String LINE_SEPARATOR = System.getProperty("line.separator"); //private static final String LINE_SEPARATOR = "\n"; // GUID Hash map.. This hash contains a unique ID for each request thread // key consists of - ThreadID // value consists of a uuid // Portlet Filter, Servlet Filter, JAX-RPC Handlers, JAX-WS Handlers // is used to create (add) an entry on request entry into the J2EE container // and also to remove from this hash map private static ConcurrentHashMap<String, PerfLogContext> guidHashMap = new ConcurrentHashMap<String, PerfLogContext>(); // create with a given GUID, jvmDepth and filterDepth // and initialized the common context e.g. host, clone id, thread id. // this is called when request crosses JVM boundaries and we need to keep // GUID same to track log data using tools such as Splunk // // Note: Both the arguments to this method could be null private static void _startPerfLogTxnMonitor(PerfLogContextTrackingData perfLogContextTrackingData, TxnData txnData) { String currentThreadID = new Long(Thread.currentThread().getId()) .toString(); boolean logStartPerfLogTxn = false; PerfLogContext thisThreadPerfLogContext = new PerfLogContext(); // Create the first TxnFilter PerfLogContext.incrementTxnFilterDepth(thisThreadPerfLogContext, txnData); // Check if we have to create a new Perf Log Context or use data from a previous context if (perfLogContextTrackingData == null || (perfLogContextTrackingData != null && perfLogContextTrackingData.getGuid()==null)) { // create a guid for this new context thisThreadPerfLogContext.setGuid(RuntimeEnvHelper.getInstance().getCloneName() + "-" + UUID.randomUUID().toString()); thisThreadPerfLogContext.setJvmDepth(1); // When creating a new context, set the context creation time // and filter creation time for the first filter to be the same thisThreadPerfLogContext.setContextCreationTime(System.currentTimeMillis()); thisThreadPerfLogContext.setTxnFilterCreationTime(1, thisThreadPerfLogContext.getContextCreationTime()); // We only log the startPerfLogTxn when creating the guid context // If the guid is passed from another JVM then the startPerfLogTxn has already been created if(LoggerProperties.getInstance().isLogStartEndPerfLogTxnEnabled()) logStartPerfLogTxn=true; } else { // use supplied guid and jvmdepth and createTime for Perf Log context thisThreadPerfLogContext.setGuid(perfLogContextTrackingData.getGuid()); // increement the calling JVM depth by 1 thisThreadPerfLogContext.setJvmDepth(perfLogContextTrackingData.getCallingJvmDepth()+1); // Context creation time is the time of the original perf log context creation time thisThreadPerfLogContext.setContextCreationTime(perfLogContextTrackingData.getCreateTimeInMillis()); // filter creation time for the first filter in this JVM is set to the current time thisThreadPerfLogContext.setTxnFilterCreationTime(1, System.currentTimeMillis()); } //initialize filter depth push count for stacks thisThreadPerfLogContext.getInfoContextPushCountForTxnFilterDepth().add(0, new Integer(0)); thisThreadPerfLogContext.setThreadId(currentThreadID); thisThreadPerfLogContext.setJvmStatsAtContextCreation(getJVMStats()); thisThreadPerfLogContext.setHostId(RuntimeEnvHelper.getInstance().getHostName()); thisThreadPerfLogContext.setHostIp(RuntimeEnvHelper.getInstance().getIpAddress()); thisThreadPerfLogContext.setJvmCloneId(RuntimeEnvHelper.getInstance() .getCloneName()); thisThreadPerfLogContext.setThreadName("["+Thread.currentThread().getName()+"]"); // Before putting the new one, see if there is an existing one that // was not cleaned out.. due to some hung thread or if (guidHashMap.get(currentThreadID) != null) { logger.warn("_startPerfLogTxnMonitor: Found zombie PerfLog Context data that will be deleted for thread ID:" + currentThreadID + ":" + "context data is: " + getBaseAndInfoContextString()); _endPerfLogTxnMonitor(true); } // put the new one. guidHashMap.put(currentThreadID, thisThreadPerfLogContext); if (logStartPerfLogTxn) { // ----------------------------------------------- // Log start of transaction data.. in the first JVM if enabled // This transaction indicates the creation of the GUID context // and the start of the performance log sequence tied to a single // request GUID PerfLogData perfLogData = new PerfLogData(thisThreadPerfLogContext); // set transaction type, other fields will be defaulted based on // current thread context. perfLogData.setTransactionType(PerfLogTxnType.START_PERF_LOG_TRANSACTION); perfLogData.setTransactionName("startPerfLogTxnMonitor"); perfLogData.setSubTransactionName("perfLogTxnMarker"); perfLogData.setTransactionTime(0); //Set the Transaction date to the same time as the context creation date time perfLogData.setTransactionDate(new Date(thisThreadPerfLogContext.getContextCreationTime())); logPerfLogData(perfLogData); // ------------------------------------------------- } } public static boolean startPerfLogTxnMonitor(PerfLogContextTrackingData perfLogContextTrackingData) { if (PerfLogContextHelper.getCurrentThreadPerfLogContextObject()!= null) { _endPerfLogTxnMonitor(false); } _startPerfLogTxnMonitor(perfLogContextTrackingData, null); return true; } public static boolean startPerfLogTxnMonitor(PerfLogContextTrackingData perfLogContextTrackingData, TxnData txnData) { if (PerfLogContextHelper.getCurrentThreadPerfLogContextObject()!= null) { _endPerfLogTxnMonitor(false); } _startPerfLogTxnMonitor(perfLogContextTrackingData, txnData); return true; } public static boolean startPerfLogTxnMonitor() { boolean contextCreated = false; PerfLogContext perfLogContext = getCurrentThreadPerfLogContextObject(); if (perfLogContext == null) { contextCreated = true; _startPerfLogTxnMonitor(null, null); } else { // increment filter depth PerfLogContext.incrementTxnFilterDepth(perfLogContext,null); } return contextCreated; } public static boolean startPerfLogTxnMonitor(TxnData txnData) { boolean contextCreated = false; PerfLogContext perfLogContext = getCurrentThreadPerfLogContextObject(); if (perfLogContext == null) { contextCreated = true; _startPerfLogTxnMonitor(null, txnData); } else { // increment filter depth PerfLogContext.incrementTxnFilterDepth(perfLogContext,txnData); } return contextCreated; } public static void dumpPerfLogContext(java.util.logging.Logger inLogger) { // use provided logger to dump the PerfLog context data _dumpPerfLogContext(inLogger); } public static void dumpPerfLogContext() { // use provided default project logger to dump PerfLog context data _dumpPerfLogContext(null); } public static String getJVMStats() { ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean(); List <GarbageCollectorMXBean> garbageCollectorMXBeansList = ManagementFactory.getGarbageCollectorMXBeans(); StringBuffer buf = new StringBuffer(); buf.append(LINE_SEPARATOR + " threadCount = " + threadMXBean.getThreadCount()); buf.append(LINE_SEPARATOR + " heapMemUsage = " + memoryMXBean.getHeapMemoryUsage()); buf.append(LINE_SEPARATOR + " nonHeapMemUsage = " + memoryMXBean.getNonHeapMemoryUsage()); for (GarbageCollectorMXBean garbageCollectorMXBean : garbageCollectorMXBeansList) { buf.append(LINE_SEPARATOR + " GCName = " + garbageCollectorMXBean.getName() + " GCCount = " + garbageCollectorMXBean.getCollectionCount() + " GCTime (ms) = " + garbageCollectorMXBean.getCollectionTime()); } return buf.toString(); } private static void _dumpPerfLogContext(java.util.logging.Logger inLogger) { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext != null) { String debugContextString = getDebugContextString(); String requestDataContextString = getRequestDataContextString(); long currentTime = System.currentTimeMillis(); SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yy HH:mm:ss:SSS z"); Date contextCreationDateWithMilliSecondPrecision = new Date(thisThreadPerfLogContext.getContextCreationTime()); String formattedContextCreationDate = sdf.format(contextCreationDateWithMilliSecondPrecision); Date thisJVMEntryDateWithMilliSecondPrecision = new Date(thisThreadPerfLogContext.getTxnFilterCreationTime(1)); String formattedThisJVMEntryDateWithMilliSecondPrecision = sdf.format(thisJVMEntryDateWithMilliSecondPrecision); long elapsedTimeSinceContextCreation = currentTime - thisThreadPerfLogContext.getContextCreationTime(); long elapsedTimeSinceJMVEntry = currentTime - thisThreadPerfLogContext.getTxnFilterCreationTime(1); StringBuffer buf = new StringBuffer(); buf.append(": Full Request PerfLog Context Data" + LINE_SEPARATOR); buf.append("======= Request PerfLog Context Data Begin ==================="); buf.append(LINE_SEPARATOR + "context creation time = " + formattedContextCreationDate); buf.append(LINE_SEPARATOR + "elapsedtime since context creation (ms) = " + elapsedTimeSinceContextCreation); buf.append(LINE_SEPARATOR + "this JVM entry time = " + formattedThisJVMEntryDateWithMilliSecondPrecision); buf.append(LINE_SEPARATOR + "elapsedtime since this JVM entry = " + elapsedTimeSinceJMVEntry ); buf.append(LINE_SEPARATOR + "responseTimeThreshold (ms) = "); buf.append(TxnThresholdProps.getMaxResponseTimeThresholdForTxnList( thisThreadPerfLogContext.getTxnList())); buf.append(LINE_SEPARATOR + "txnList = "+thisThreadPerfLogContext.getTxnList().toString()); buf.append(LINE_SEPARATOR + "currentDebugContextDataSize / Max Size = "); buf.append(thisThreadPerfLogContext.getCurrentDebugDataContextSize()); buf.append(" / " + thisThreadPerfLogContext.getMaxDebugContexDataSize()); buf.append(LINE_SEPARATOR + "currentRequestDataSize / Max Size = "); buf.append(thisThreadPerfLogContext.getCurrentRequestDataContextSize()); buf.append(" / " + thisThreadPerfLogContext.getMaxRequestDataContextSize()); buf.append(LINE_SEPARATOR + "JVM Stats - At context creation:"); buf.append(thisThreadPerfLogContext.getJvmStatsAtContextCreation()); buf.append(LINE_SEPARATOR + "JVM Stats - Current:"); buf.append(getJVMStats()); if(requestDataContextString != null) { if(!requestDataContextString.equals("[null]") && !requestDataContextString.equals("[NullDataContext]")) { buf.append(LINE_SEPARATOR + "----- Request Data --------"); buf.append(LINE_SEPARATOR + requestDataContextString); } } if(debugContextString != null ) { if(!debugContextString.equals("[null]") && !debugContextString.equals("[NullDataContext]")) { buf.append(LINE_SEPARATOR + "----- Debug Context Data --------" ); buf.append(LINE_SEPARATOR + debugContextString ); } } buf.append(LINE_SEPARATOR + "======== Request PerfLog Context Data End ==================="+ LINE_SEPARATOR); if(inLogger != null) { inLogger.log(Level.SEVERE,buf.toString()); } else { // use built-in default logger logger.info(buf.toString()); } } } private static void _endPerfLogTxnMonitor(boolean forceDumpDebugContext) { String currentThreadID = new Long(Thread.currentThread().getId()).toString(); PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext == null) { logger.warn("_endPerfLogTxnMonitor(): Unexpected delete for PerfLogContext object requested for thread ID:" + currentThreadID); } else { // Log context details if the response time threshold exceeds for this context... long elapsedTime = System.currentTimeMillis() - thisThreadPerfLogContext.getContextCreationTime(); long responseTimeThreshold = TxnThresholdProps. getMaxResponseTimeThresholdForTxnList( thisThreadPerfLogContext.getTxnList()); if (elapsedTime > responseTimeThreshold) { logger.info("Elapsed time exceeded response time threshold: "+ responseTimeThreshold); dumpPerfLogContext(); } else if (forceDumpDebugContext ) { logger.info("forceDumpDebugContext = true"); dumpPerfLogContext(); } else if(PerfLogContextProperties.instance().isForceDumpOfDebugContextOnDelete()) { logger.info("forceDumpOfDebugContextOnDelete = true"); dumpPerfLogContext(); } if (thisThreadPerfLogContext.getJvmDepth() == 1 && LoggerProperties.getInstance() .isLogStartEndPerfLogTxnEnabled()) { // ---------------------------------------------------------- // Before deleting this context log the end perf log txn long t1 = System.currentTimeMillis(); PerfLogData perfLogData = new PerfLogData(thisThreadPerfLogContext); perfLogData.setTransactionDate(new Date(t1)); // set transaction type, other fields will be defaulted based on // current thread context. perfLogData.setTransactionType(PerfLogTxnType.END_PERF_LOG_TRANSACTION); perfLogData.setTransactionName("endPerfLogTxnMonitor"); perfLogData.setSubTransactionName("perfLogTxnMarker"); perfLogData.setTransactionTime(System.currentTimeMillis()-t1); logPerfLogData(perfLogData); // -------------------------------------------------------------- } // remove the TxnFilter PerfLogContext.decrementTxnFilterDepth(thisThreadPerfLogContext); if(thisThreadPerfLogContext.getInfoContextStack()!=null) thisThreadPerfLogContext.getInfoContextStack().clear(); if(thisThreadPerfLogContext.getDebugContextQueue()!=null) thisThreadPerfLogContext.getDebugContextQueue().clear(); if(thisThreadPerfLogContext.getRequestDataContext()!=null) thisThreadPerfLogContext.getRequestDataContext().clear(); if(thisThreadPerfLogContext.getTxnList()!=null) thisThreadPerfLogContext.getTxnList().clear(); thisThreadPerfLogContext.getInfoContextPushCountForTxnFilterDepth().clear(); guidHashMap.remove(currentThreadID); } } public static boolean endPerfLogTxnMonitor() { String currentThreadID = new Long(Thread.currentThread().getId()).toString(); PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if(thisThreadPerfLogContext == null) { logger.warn("endPerfLogTxnMonitor(): Unexpected delete PerfLogContext object requested for thread ID:" + currentThreadID); return true;// assume it is deleted } if (thisThreadPerfLogContext.getTxnFilterDepth() > 1) { PerfLogContext.decrementTxnFilterDepth(thisThreadPerfLogContext); return false; } else { _endPerfLogTxnMonitor(false); return true; } } // argument indicates if the performance data collected for current txn filter needs to be logged // Caller can always log outside this call if required. // If no logging is desired then either use the overloaded method without this argument // or set this argument to false public static boolean endPerfLogTxnMonitor(boolean logPerfLogData) { if(logPerfLogData) { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); // create a PerfLogData object from current context information and log to the default // perfLogger PerfLogData perfLogData = new PerfLogData(thisThreadPerfLogContext); // Get Current TxnFilter info TxnData txnData=null; int currentTxnFilterDepth = thisThreadPerfLogContext.getTxnFilterDepth(); TxnFilter txnFilter = thisThreadPerfLogContext.getTxnFilter(currentTxnFilterDepth); if(txnFilter != null && (txnData = txnFilter.getTxnData()) != null) { perfLogData.setTransactionDate(new Date(txnFilter.getCreationTime())); perfLogData.setTransactionName(txnData.getTxnName()); perfLogData.setTransactionType(txnData.getTxnType()); perfLogData.setSubTransactionName(txnData.getSubTxnName()); perfLogData.setTransactionClass(txnData.getTxnClass()); perfLogData.setTransactionTime(txnFilter.getTxnTime()); } // other contextual details including guid, IP, host etc // will be filled in by this method PerfLogContextHelper.logPerfLogData(perfLogData); } // now end this PerfLogTxnMonitor return endPerfLogTxnMonitor(); } // End the performance log monitor for the current txn filter // and log the provided perf log data public static boolean endPerfLogTxnMonitor(PerfLogData perfLogData) { if(perfLogData != null) { PerfLogContextHelper.logPerfLogData(perfLogData); } // now end this PerfLogTxnMonitor, this will remove the current // transaction filter and delete the perf log context if this is the // last txn filter return endPerfLogTxnMonitor(); } public static void pushInfoContext(String context) { pushInfoContext("", context); } public static void pushInfoContext(ContextElement logContextElement) { pushInfoContext(logContextElement.getName(), logContextElement .getValue()); } // context string any string that provides a unique business context for // logging // e.g. task id, user id, etc. // all context are logged as a list separated by | character // multiple contexts are allowed public static void pushInfoContext(String name, String value) { // first PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext != null) { thisThreadPerfLogContext.pushInfoContext(name, value); } } public static void pushInfoContext(String name, String value, int maxValueSize) { // first PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext != null) { thisThreadPerfLogContext.pushInfoContext(name, value, maxValueSize); } } public static void addToDebugContext(String context) { addToDebugContext("", context); } public static void addToDebugContext(ContextElement logContextElement) { addToDebugContext(logContextElement.getName(), logContextElement .getValue()); } public static void addToDebugContext(String name, String value) { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext!= null) { thisThreadPerfLogContext.addToDebugContext(name, value); } } public static void addToRequestDataContext(String context) { addToDebugContext("", context); } public static void addToRequestDataContext(ContextElement logContextElement) { addToRequestDataContext(logContextElement.getName(), logContextElement .getValue()); } public static void addToRequestDataContext(String name, String value) { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext !=null) { thisThreadPerfLogContext.addToRequestDataContext(name, value); } } public static void addToRequestDataContext(String name, String value, int maxValueSize) { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext !=null) { thisThreadPerfLogContext.addToRequestDataContext(name, value, maxValueSize); } } public static void removeLastInsertedFromRequestDataContext() { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext !=null) { thisThreadPerfLogContext.removeLastInsertedFromRequestDataContext(); } } public static void removeLastInsertedFromDebugDataContext() { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext !=null) { thisThreadPerfLogContext.removeLastInsertedFromDebugDataContext(); } } public static void popInfoContext() { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext != null) { thisThreadPerfLogContext.popInfoContext(); } } public static void setUserId(String userId) { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext != null) { thisThreadPerfLogContext.setUserId(userId); } } public static String getUserId() { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext != null) { return thisThreadPerfLogContext.getUserId(); } else return null; } public static void setRequestSessionId(String sid) { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext != null) { thisThreadPerfLogContext.setRequestSessionId(sid); } } public static String getRequestSessionId() { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext != null) { return thisThreadPerfLogContext.getRequestSessionId(); } else return null; } public static String getThreadId() { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext != null) { return thisThreadPerfLogContext.getThreadId(); } else return null; } public static String getHostId() { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext != null) { return thisThreadPerfLogContext.getHostId(); } else return null; } public static String getHostIp() { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext != null) { return thisThreadPerfLogContext.getHostIp(); } else return null; } public static String getJvmCloneId() { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext != null) { return thisThreadPerfLogContext.getJvmCloneId(); } else return null; } public static PerfLogContext getCurrentThreadPerfLogContextObject() { String currentThreadID = new Long(Thread.currentThread().getId()) .toString(); return guidHashMap.get(currentThreadID); } public static String getBaseContextString() { return PerfLogContext.getBaseContextString(getCurrentThreadPerfLogContextObject()); } public static String getBaseAndInfoContextString() { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); return PerfLogContext.getBaseContextString(thisThreadPerfLogContext) + PerfLogContext.getInfoContextString(thisThreadPerfLogContext); } public static String getDebugContextString() { return PerfLogContext.getDebugContextString(getCurrentThreadPerfLogContextObject()); } public static String getValueForInfoContextName(String name) { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext != null) { return PerfLogContext.getValueForContextName(name, thisThreadPerfLogContext.getInfoContextStack()); } return null; } public static String getGuid() { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext != null) return thisThreadPerfLogContext.getGuid(); else return null; } public static long getElapsedTime() { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext != null) { return thisThreadPerfLogContext.getElapsedTimeFromContextCreation(); } else { return 0; } } public static String getRequestDataContextString() { return PerfLogContext.getRequestDataContextString(getCurrentThreadPerfLogContextObject()); } public static long getElapsedTimeForCurrentFilter() { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext != null) { return thisThreadPerfLogContext.getElapsedTimeFromTxnFilterCreation(); } else { return 0; } } public static List<String> getTxnList() { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext !=null) { return thisThreadPerfLogContext.getTxnList(); } else return null; } public static void addToTxnList(String txnName) { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext !=null) { thisThreadPerfLogContext.addToTxnList(txnName); } } public static boolean isAwaitingReturnFromOutboundJvmCall() { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext !=null) { return thisThreadPerfLogContext.isAwaitingReturnFromOutboundJvmCall(); } else return false; } public static void setAwatingReturnFromOutboundJvmCall(boolean flag) { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if (thisThreadPerfLogContext !=null) { thisThreadPerfLogContext.setAwaitingReturnFromOutboundJvmCall(flag); } } // Out bound JVM calls e.g. web service client call can return malformed soap response // The JVM container can bypass the response handler in such cases. This puts the filter count out of sync // causing the context to hang around even after the request is complete // This method compensates for such scenarios public static void compensateForOutboundJvmCallExceptionIfAny() { PerfLogContext thisThreadGuidContext = getCurrentThreadPerfLogContextObject(); if(thisThreadGuidContext != null && PerfLogContextHelper.isAwaitingReturnFromOutboundJvmCall()) { logger.error("Compensating PerfLogContext state for uncaught Exception from outbound Jvm call for guid="+thisThreadGuidContext.getGuid()); // do an extra delete to adjust the filter count PerfLogContextHelper.setAwatingReturnFromOutboundJvmCall(false); PerfLogContextHelper.endPerfLogTxnMonitor(); } } // // Helper function to aid logging performance metrics from custom application code // using the PerfLogger implementation // Ideally the perfLogData is initialized by the calling application code // However if the common elements are not initialized this method will // extract information from the current perflog context // public static void logPerfLogData(PerfLogData perfLogData) { PerfLogContext thisThreadPerfLogContext = getCurrentThreadPerfLogContextObject(); if(perfLogData != null) { // fill in perfLogData with common elements from thread guid context // if not already initialized if(thisThreadPerfLogContext != null) { if(perfLogData.getUserId()==null) perfLogData.setUserId(thisThreadPerfLogContext.getUserId()); if(perfLogData.getCloneName() == null) perfLogData.setCloneName(thisThreadPerfLogContext.getJvmCloneId()); if(perfLogData.getGuid()==null) perfLogData.setGuid(thisThreadPerfLogContext.getGuid()); if(perfLogData.getSessionId()==null) perfLogData.setSessionId(thisThreadPerfLogContext.getRequestSessionId()); if(perfLogData.getThreadName()==null) perfLogData.setThreadName(thisThreadPerfLogContext.getThreadName()); if(perfLogData.getServerIp()==null) perfLogData.setServerIp(thisThreadPerfLogContext.getHostIp()); if(perfLogData.getServerName()==null) perfLogData.setServerName(thisThreadPerfLogContext.getHostId()); if(perfLogData.getTransactionDate()==null) perfLogData.setTransactionDate(new Date()); if(perfLogData.getTransactionName()==null) perfLogData.setTransactionName("UnknownTransactionName"); if(perfLogData.getSubTransactionName()==null) perfLogData.setSubTransactionName("UnknownSubTransactionName"); if(perfLogData.getTransactionType()==null) perfLogData.setTransactionType("UnknownTransactionType"); // Set the perflog context of this thread to this perfLogData // This will also set the InfoContext String perfLogData.setPerfLogContext(thisThreadPerfLogContext); } PerfLogger plogger = PerfLoggerFactory.getLogger(); plogger.log(perfLogData); } } }