/*******************************************************************************
* Copyright 2012 Pradeep Nambiar, Pexus LLC
*
* Source File: src/org/perf/log/logger/FileWriter.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.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.Properties;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.perf.log.properties.LoggerProperties;
import org.perf.log.properties.TunableProperties;
import org.perf.log.utils.JvmCloneGetterFactory;
import org.perf.log.utils.PropertyFileLoader;
/**
* This class is used to write the perf log messages to a file
*/
public class FileWriter
{
private final static org.perf.log.logger.Logger logger = LoggerFactory.getLogger(FileWriter.class.getName());
private static Logger perfFileLogger ;
private static TunableProperties tunableProperties = LoggerProperties.getInstance().getTunableProperties();
private static FileWriter instance = null;
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
private static String logRootDir=null;
// Properties for this class
static boolean propertiesInited = false;
private static final String LOGGER_FILEWRITER_LOGFILE_ROOT_DIR = "static.logger.FileWriter.logFileRootDir";
private static final String LOGGER_FILEWRITER_LOGFILE_MAX_SIZE = "static.logger.FileWriter.logFileMaxSize";
private static final String LOGGER_FILEWRITER_LOGFILE_NUM_TO_KEEP = "static.logger.FileWriter.logFileNumToKeep";
private static final String LOGGER_FILEWRITER_FILE_WRITE_ENABLED = "dynamic.logger.FileWriter.fileWriteEnabled";// dynamic
static boolean fileWriterEnabled = true;
static String logFileRootDirFromProperty = null;
static int logFileMaxSize = 4194304; // 4MB
static int logFileNumToKeep = 10;
/**
* This method will construct a formatted perf log data string suitable for writing to perf log file
* @param PerfLogData
* @return str - formatted string
*/
private static String getFormatedPerfDataStr(PerfLogData perfLogData)
{
StringBuffer buf = new StringBuffer();
// This format is consistent with Splunk format
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yy HH:mm:ss:SSS z");
java.util.Date txnDate = null;
String formattedTransactionDate = null;
txnDate = new java.util.Date(perfLogData.getTransactionDate().getTime());
formattedTransactionDate = "["+sdf.format(txnDate)+"]";
buf.append(formattedTransactionDate);
buf.append(" PERFLOG");
if(perfLogData.getThrowable()!=null)
{
buf.append("(FAILURE=");
buf.append(perfLogData.getThrowableClassName() + ": " + perfLogData.getThrowableMessage());
buf.append(")");
}
else
buf.append("(SUCCESS)");
buf.append(" :txnType="+perfLogData.getTransactionType());
buf.append(" :txnDate="+txnDate);
buf.append(" :txnTime="+perfLogData.getTransactionTime());
buf.append(" :userId="+perfLogData.getUserId());
buf.append(" :guid="+perfLogData.getGuid());
buf.append(" :sessionId="+perfLogData.getSessionId());
buf.append(" :threadName="+perfLogData.getThreadName());
buf.append(" :threadId="+perfLogData.getThreadId());
buf.append(" :serverName="+ perfLogData.getServerName());
buf.append(" :serverIp="+ perfLogData.getServerIp());
buf.append(" :cloneName="+perfLogData.getCloneName());
buf.append(" :jvmDepth="+perfLogData.getJvmDepth());
buf.append(" :txnFilterDepth="+perfLogData.getTxnFilterDepth());
buf.append(" :txnName="+perfLogData.getTransactionName());
buf.append(" :subTxnName="+perfLogData.getSubTransactionName());
buf.append(" :txnClass="+perfLogData.getTransactionClass());
buf.append(LINE_SEPARATOR);
buf.append(" :infoCtxStr="+perfLogData.getInfoContextString());
buf.append(LINE_SEPARATOR);
buf.append(" :message="+perfLogData.getMessage());
return buf.toString();
}
/**
* This Private constructor creates a JDK Logger Instance using File Handler
* that rotates for every 4 MB to a new file up to a max of 100 files
*/
private FileWriter() throws Exception
{
//PerfLogDB Properties
FileHandler fileHandler = null;
String logFileName="perf-log";
if(perfFileLogger == null)
{
perfFileLogger = Logger.getLogger(FileWriter.class.getName());
File f = new File(getLogRootDir());
if(!f.exists())
{
f.mkdirs();
}
if(logFileName != null)
{
logFileName = logFileName.trim();
if(!logFileName.endsWith(".log"))
{
logFileName = logFileName.concat("%g%u.log");
}
else
{
logFileName = logFileName.substring(0,logFileName.indexOf(".log"));
logFileName = logFileName.concat("%g%u.log");
}
}
logFileName = getLogRootDir() + "/" + logFileName;
try
{
fileHandler = new FileHandler(logFileName,getLogFileMaxSize(),getLogFileNumToKeep(),true);
fileHandler.setFormatter(new PerfLogMessageFormatter(new MessageFormat("{0}\n")));
} catch (IOException ioException)
{
logger.error("IO Exception during initializing perf log file:"+ioException.getMessage());
throw ioException;
}
System.out.println(FileWriter.class.getName()+":PerfLog file opened for logging:"+logFileName);
perfFileLogger.addHandler(fileHandler);
perfFileLogger.setUseParentHandlers(false);
perfFileLogger.setLevel(Level.INFO);
}
}
/**
* Returns the singleton instance of PerfLogger class
* @return
*/
public synchronized static FileWriter getInstance() throws Exception
{
if(instance == null)
{
initProperties();
try {
instance = new FileWriter();
} catch (Exception e) {
throw e;
}
}
return instance;
}
/**
* This method internally calls the PerfLogger Instance to put a PERF LOG entry in to the PERFDB-LOG File.
* @param messageContent
*/
public static void write(PerfLogData perfLogData) throws Exception
{
if(perfFileLogger==null)
{
getInstance();
}
perfFileLogger.log(Level.INFO,getFormatedPerfDataStr(perfLogData));
}
public static String getLogFileRootDirFromProperty() {
String propertyValue = tunableProperties.getStaticProperty(LOGGER_FILEWRITER_LOGFILE_ROOT_DIR);
if(propertyValue != null) {
logFileRootDirFromProperty = propertyValue;
}
return logFileRootDirFromProperty;
}
public static String getLogRootDir() {
// Get the File Root Dir
String propValue = getLogFileRootDirFromProperty();
if(propValue != null) {
FileWriter.logRootDir = propValue + "/perfLogs";
}
else
FileWriter.logRootDir = "perfLogs";
// append the JVM Clone name to the directory to split individually
// create and log to each JVM clone's instance log file
String envInstanceName = JvmCloneGetterFactory.getJvmCloneGetterImpl().getName();
if(envInstanceName!=null)
{
FileWriter.logRootDir = FileWriter.logRootDir+"/"+envInstanceName;
}
return FileWriter.logRootDir;
}
public static void setFileWriterEnabled(boolean fileWriterEnabled) {
FileWriter.fileWriterEnabled = fileWriterEnabled;
}
public static void setLogFileRootDirFromProperty(String logFileRootDir) {
FileWriter.logFileRootDirFromProperty = logFileRootDir;
}
public static void setLogFileMaxSize(int logFileMaxSize) {
FileWriter.logFileMaxSize = logFileMaxSize;
}
public static void setLogFileNumToKeep(int logFileNumToKeep) {
FileWriter.logFileNumToKeep = logFileNumToKeep;
}
public static void setInstance(FileWriter instance) {
FileWriter.instance = instance;
}
/**
* @return the fileWriterEnabled
*/
public static boolean isFileWriterEnabled() {
String propertyValue = tunableProperties.getDynamicProperty(LOGGER_FILEWRITER_FILE_WRITE_ENABLED);
if(propertyValue != null) {
return new Boolean(propertyValue).booleanValue();
}
else
return fileWriterEnabled;
}
public static int getLogFileMaxSize() {
String propertyValue = tunableProperties.getStaticProperty(LOGGER_FILEWRITER_LOGFILE_MAX_SIZE);
if(propertyValue != null) {
logFileMaxSize = new Integer(propertyValue).intValue();
}
return logFileMaxSize;
}
public static int getLogFileNumToKeep() {
String propertyValue = tunableProperties.getStaticProperty(LOGGER_FILEWRITER_LOGFILE_NUM_TO_KEEP);
if(propertyValue != null) {
logFileNumToKeep = new Integer(propertyValue).intValue();
}
return logFileNumToKeep;
}
private static synchronized void initProperties() {
if (!propertiesInited) {
try {
String propVal;
ClassLoader ctxClassLoader = Thread.currentThread().getContextClassLoader();
Properties props = PropertyFileLoader.load(
"perfLog.properties",
"perfLogDefault.properties",
ctxClassLoader,
FileWriter.class.getClass().getClassLoader(),
FileWriter.class.getName());
if (props != null) {
propVal = props
.getProperty(LOGGER_FILEWRITER_FILE_WRITE_ENABLED);
if (propVal != null)
setFileWriterEnabled(new Boolean(propVal)
.booleanValue());
propVal = props
.getProperty(LOGGER_FILEWRITER_LOGFILE_ROOT_DIR);
if (propVal != null)
setLogFileRootDirFromProperty(propVal);
propVal = props
.getProperty(LOGGER_FILEWRITER_LOGFILE_NUM_TO_KEEP);
if (propVal != null)
setLogFileNumToKeep(new Integer(propVal).intValue());
propVal = props
.getProperty(LOGGER_FILEWRITER_LOGFILE_MAX_SIZE);
if (propVal != null)
setLogFileMaxSize(new Integer(propVal).intValue());
} else {
System.out.println(FileWriter.class.getName()+":Error in reading perfLog.properties or perfLogDefault.properties");
}
} catch (Exception exception) {
System.out.println(FileWriter.class.getName()+":Error Loading perfLog.properties or perfLogDefault.properties"
+ exception.getMessage());
}
propertiesInited = true;
}
}
}