/******************************************************************************* * Copyright 2012 Pradeep Nambiar, Pexus LLC * * Source File: src/org/perf/log/logger/PerfLoggerImplJMSQ.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; import java.util.Properties; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.DeliveryMode; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageProducer; import javax.jms.Queue; import javax.jms.Session; import javax.jms.TextMessage; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import org.perf.log.properties.LoggerProperties; import org.perf.log.properties.TunableProperties; import org.perf.log.utils.PropertyFileLoader; // This implementation will work with JMS including MQ environment public class PerfLoggerImplJMSQ implements PerfLogger { // Properties for this class private static final String STATIC_PERF_LOGGER_IMPL_JMSQ_QUEUE = "static.perfLoggerImplJMSQ.queue"; private static final String STATIC_PERF_LOGGER_IMPL_JMSQ_QUEUE_CONNECTION_FACTORY = "static.perfLoggerImplJMSQ.queueConnectionFactory"; private static final String DYNAMIC_PERF_LOGGER_IMPL_JMSQ_MESSAGE_EXPIRATION_TIME_IN_MILLIS = "dynamic.perfLoggerImplJMSQ.messageExpirationTimeInMillis"; // Dynamic private static TunableProperties tunableProperties = null; protected boolean logEnabled; // initialized from property file //Default the JMS Message expire time to 1 hours = 3600000 private static long msgExpiryTimeInMillis = 3600000L; //Defult perfLoggerImpl if JMS resource initialization fails protected static PerfLoggerImplStdOut defaultPerfLogger = new PerfLoggerImplStdOut(); private final static Logger logger = LoggerFactory.getLogger(PerfLoggerImplJMSQ.class.getName()); // cached variables protected static ConnectionFactory cachedConnectionFactory = null; protected static Destination cachedQDestination = null; protected static long messageDeliveryExpirationTime ; protected static String queueName; protected static String queueConnFactoryName; // cached variables protected static Context cachedContext = null; public long getMesageDeliveryExpirationInMillis() { if(tunableProperties == null) tunableProperties = LoggerProperties.getInstance().getTunableProperties(); // Check if this property is defined in Name Space binding and refresh the value // if defined. This enables dynamic control to enable or disable this property String propertyValue = tunableProperties.getDynamicProperty(DYNAMIC_PERF_LOGGER_IMPL_JMSQ_MESSAGE_EXPIRATION_TIME_IN_MILLIS); if(propertyValue != null) { return Long.valueOf(propertyValue); } else // return value initialized in this class return msgExpiryTimeInMillis; } @Override public boolean getLogEnabled(long txnTimeInMillis) { return (LoggerProperties.getInstance().isPerfLoggerImplLogEnabled() && (txnTimeInMillis >= LoggerProperties.getInstance().getPerfLoggerImplLogThreshold())); } @Override public void setLogEnabled(boolean inLogEnabled) { logEnabled = inLogEnabled; } protected void loadProps() { String propVal; ClassLoader ctxClassLoader = Thread.currentThread().getContextClassLoader(); Properties props = PropertyFileLoader.load( "perfLog.properties", "perfLogDefault.properties", ctxClassLoader, PerfLoggerImplJMSQ.class.getClass().getClassLoader(), PerfLoggerImplJMSQ.class.getName()); if (props != null) { queueConnFactoryName = props.getProperty(STATIC_PERF_LOGGER_IMPL_JMSQ_QUEUE_CONNECTION_FACTORY); if (queueConnFactoryName == null) queueConnFactoryName = "jms/perfQCF"; queueName = props.getProperty(STATIC_PERF_LOGGER_IMPL_JMSQ_QUEUE); if (queueName == null) queueName = "jms/qPerfLog"; propVal = props.getProperty(DYNAMIC_PERF_LOGGER_IMPL_JMSQ_MESSAGE_EXPIRATION_TIME_IN_MILLIS); if(propVal!=null) msgExpiryTimeInMillis = Long.valueOf(propVal); } else { System.out.println("PerfLoggerImplJMSQ.loadProps():"+"Error in loading perfLog.properties, using default properties"); } System.out.println("PerfLoggerImplJMSQ.loadProps():queueConnFactoryName=" + queueConnFactoryName); System.out.println("PerfLoggerImplJMSQ.loadProps():queueName=" + queueName); System.out.println("PerfLoggerImplJMSQ.loadProps():msgExpiryTimeInMillis=" + msgExpiryTimeInMillis); } private static ConnectionFactory getConnectionFactory(Context context) { ConnectionFactory connectionFactory = null; try { connectionFactory = (ConnectionFactory) context.lookup(queueConnFactoryName); } catch (NamingException e) { logger.error(e.getMessage(), e); return null; } return connectionFactory; } private static Destination getQueueDestination(Context context) { Destination queueDestination = null; try { queueDestination = (Queue) context.lookup(queueName); } catch (NamingException e) { logger.error(e.getMessage(), e); return null; } return queueDestination; } PerfLoggerImplJMSQ() { super(); loadProps(); // cache initial context try { cachedContext = new InitialContext(); } catch (NamingException e) { logger.error(e.getMessage(), e); } if (cachedContext != null) { cachedConnectionFactory = getConnectionFactory(cachedContext); cachedQDestination = getQueueDestination(cachedContext); } } @Override public void log(PerfLogData perfLogData) { if (getLogEnabled(perfLogData.getTransactionTime()) && cachedContext != null && cachedConnectionFactory != null && cachedQDestination != null) { Connection connection = null; Session session = null; long startTime; long endTime; long elapsedDuration; try { // Start Time startTime = System.currentTimeMillis(); logger.debug("Start Time: " + startTime + "(ms)"); connection = cachedConnectionFactory.createConnection(); session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE); MessageProducer producer = session.createProducer(cachedQDestination); producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); // messages sent by this producer will be retained for the value specified in the properties file. messageDeliveryExpirationTime = getMesageDeliveryExpirationInMillis(); logger.debug("messageDeliveryExpirationTime="+messageDeliveryExpirationTime); producer.setTimeToLive(messageDeliveryExpirationTime); TextMessage msg = session.createTextMessage(); String perfLogDataJSONStr = perfLogData.toJSON(); logger.debug(perfLogDataJSONStr); msg.setText(perfLogDataJSONStr); producer.send(msg); // End Time endTime = System.currentTimeMillis(); logger.debug("PerfLoggerImplJMSQ End Time: " + endTime + "(ms)"); // Elapsed Duration elapsedDuration = endTime-startTime; logger.debug("Elapsed time: " + elapsedDuration +"(ms)"); logger.debug("Succesfully sent JMS Message with ID : " + msg.getJMSMessageID() + " to the Queue : " + cachedQDestination + " : " + perfLogData.toString()); } catch (Exception jmsException) { // write a short version of the perf log data to log along with exception // this can happen when Q is full or other messaging error. logger.error("Error writing JMS Q:" + jmsException.getMessage() + ": " + perfLogData.toString()); } finally { try { if (session != null) { session.close(); } } catch (JMSException e) { logger.error(e.getMessage(), e); } try { if (connection != null) connection.close(); } catch (JMSException e) { logger.error(e.getMessage(), e); } } } else if (getLogEnabled(perfLogData.getTransactionTime())) { // log to stdout using default perf logger implementation // if there is an issue with getting JMS Resources defaultPerfLogger.log(perfLogData); } } }