/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2009-2013 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.enterprise.server.logging.logviewer.backend;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.inject.Inject;
import javax.management.Attribute;
import javax.management.AttributeList;
import org.glassfish.api.admin.CommandRunner;
import org.glassfish.api.admin.ServerEnvironment;
import org.glassfish.api.logging.LogLevel;
import org.glassfish.config.support.TranslatedConfigView;
import org.glassfish.hk2.api.ServiceLocator;
import org.jvnet.hk2.annotations.Service;
import com.sun.common.util.logging.LoggingConfigImpl;
import com.sun.enterprise.config.serverbeans.Cluster;
import com.sun.enterprise.config.serverbeans.Domain;
import com.sun.enterprise.config.serverbeans.Node;
import com.sun.enterprise.config.serverbeans.Server;
import com.sun.enterprise.server.logging.LogFacade;
import com.sun.enterprise.util.StringUtils;
import com.sun.enterprise.util.SystemPropertyConstants;
/**
* <p/>
* LogFilter will be used by Admin Too Log Viewer Front End to filter the
* records. LogMBean delegates the getLogRecordsUsingQuery method to this
* class static method.
*
* @AUTHOR: Hemanth Puttaswamy and Ken Paulsen
* @AUTHOR: Carla Mott, Naman Mehta
*/
@Service
public class LogFilter {
// This is the name of the Results Attribute that we send out to the
// Admin front end.
private static final String RESULTS_ATTRIBUTE = "Results";
// Load the custom level class for query purpose.
private static final Level[] GF_CUSTOM_LEVELS = new Level[] {
LogLevel.ALERT,
LogLevel.EMERGENCY
};
private static final String NV_SEPARATOR = ";";
@Inject
Domain domain;
@Inject
CommandRunner commandRunner;
@Inject
ServerEnvironment env;
@Inject
private ServiceLocator habitat;
@Inject
LoggingConfigImpl loggingConfig;
private static final Logger LOGGER = LogFacade.LOGGING_LOGGER;
private static final boolean DEBUG = false;
/**
* The public method that Log Viewer Front End will be calling on.
* The query will be run on records starting from the fromRecord.
* If any of the elements for the query is null, then that element will
* not be used for the query. If the user is interested in viewing only
* records whose Log Level is SEVERE and WARNING, then the query would
* look like:
* <p/>
* fromDate = null, toDate = null, logLevel = WARNING, onlyLevel = false,
* listOfModules = null, nameValueMap = null.
*
* @param logFileName The LogFile to use to run the query. If null
* the current server.log will be used. This is
* not the absolute file name, just the fileName
* needs to be passed. We will use the parent
* directory of the previous server.log to
* build the absolute file name.
* @param fromRecord The location within the LogFile
* @param next True to get the next set of results, false to
* get the previous set
* @param forward True to search forward through the log file
* @param requestedCount The # of desired return values
* @param fromDate The lower bound date
* @param toDate The upper bound date
* @param logLevel The minimum log level to display
* @param onlyLevel True to only display messsage for "logLevel"
* @param listOfModules List of modules to match
* @param nameValueMap NVP's to match
* @return
*/
public AttributeList getLogRecordsUsingQuery(
String logFileName, Long fromRecord, Boolean next, Boolean forward,
Integer requestedCount, Date fromDate, Date toDate,
String logLevel, Boolean onlyLevel, List listOfModules,
Properties nameValueMap, String anySearch) {
// Testing code for instance setup
//return getLogRecordsUsingQuery(logFileName, fromRecord, next, forward, requestedCount,
// fromDate, toDate, logLevel, onlyLevel, listOfModules, nameValueMap, anySearch, "in2", false);
LogFile logFile = null;
String logFileDetailsForServer = "";
try {
logFileDetailsForServer = loggingConfig.getLoggingFileDetails();
logFileDetailsForServer = TranslatedConfigView.getTranslatedValue(logFileDetailsForServer).toString();
logFileDetailsForServer = new File(logFileDetailsForServer).getAbsolutePath();
} catch (Exception ex) {
LOGGER.log(Level.SEVERE, LogFacade.ERROR_EXECUTING_LOG_QUERY, ex);
return new AttributeList();
}
if ((logFileName != null)
&& (logFileName.length() != 0)) {
logFileName = logFileDetailsForServer.substring(0, logFileDetailsForServer.lastIndexOf(File.separator)) + File.separator +
logFileName.trim();
if (new File(logFileName).exists()) {
logFile = getLogFile(logFileName);
} else {
logFileName = logFileDetailsForServer;
logFile = getLogFile(logFileName);
}
} else {
logFileName = logFileDetailsForServer;
logFile = getLogFile(logFileName);
}
boolean forwd = (forward == null) ? true : forward.booleanValue();
boolean nxt = (next == null) ? true : next.booleanValue();
long reqCount = (requestedCount == null) ?
logFile.getIndexSize() : requestedCount.intValue();
long startingRecord;
if (fromRecord == -1) {
// In this case next/previous (before/after) don't mean much since
// we don't have a reference record number. So set before/after
// according to the direction.
nxt = forwd;
// We +1 for reverse so that we see the very end of the file (the
// query will not go past the "startingRecord", so we have to put
// it after the end of the file)
startingRecord = forwd ?
(-1) : ((logFile.getLastIndexNumber() + 1) * logFile.getIndexSize());
} else {
startingRecord = fromRecord.longValue();
if (startingRecord < -1) {
throw new IllegalArgumentException(
"fromRecord must be greater than 0!");
}
}
// TO DO: If the fromRecord count is zero and the fromDate entry is
// non-null, then the system should take advantage of file Indexing.
// It should move the file position to the marker where the DateTime
// query matches.
try {
return fetchRecordsUsingQuery(logFile, startingRecord, nxt, forwd,
reqCount, fromDate, toDate, logLevel,
onlyLevel.booleanValue(), listOfModules, nameValueMap, anySearch);
} catch (Exception ex) {
LOGGER.log(Level.SEVERE, LogFacade.ERROR_EXECUTING_LOG_QUERY, ex);
return new AttributeList();
}
}
public Vector getInstanceLogFileNames(String instanceName) {
Server targetServer = domain.getServerNamed(instanceName);
Vector allInstanceFileNames = new Vector();
if (targetServer.isDas()) {
String logFileDetailsForServer = "";
try {
// getting log file attribute value from logging.properties file
logFileDetailsForServer = loggingConfig.getLoggingFileDetails();
logFileDetailsForServer = TranslatedConfigView.getTranslatedValue(logFileDetailsForServer).toString();
logFileDetailsForServer = new File(logFileDetailsForServer).getAbsolutePath();
} catch (Exception ex) {
LOGGER.log(Level.SEVERE, LogFacade.ERROR_EXECUTING_LOG_QUERY, ex);
return new Vector();
}
File logsDir = new File(logFileDetailsForServer.substring(0, logFileDetailsForServer.lastIndexOf(File.separator)));
File allLogFileNames[] = logsDir.listFiles();
for (File file : allLogFileNames) {
String fileName = file.getName();
if (file.isFile() && !fileName.equals(".") && !fileName.equals("..")
&& fileName.contains(".log") && !fileName.contains(".log.")) {
allInstanceFileNames.add(fileName);
}
}
} else {
try {
// getting log file attribute value from logging.properties file
String instanceLogFileDetails = getInstanceLogFileDetails(targetServer);
allInstanceFileNames = new LogFilterForInstance().getInstanceLogFileNames(habitat, targetServer, domain, LOGGER, instanceName, instanceLogFileDetails);
} catch (Exception ex) {
LOGGER.log(Level.SEVERE, LogFacade.ERROR_EXECUTING_LOG_QUERY, ex);
return new Vector();
}
}
return allInstanceFileNames;
}
/*
This function is used to get log file details from logging.properties file for given target.
*/
private String getInstanceLogFileDetails(Server targetServer) throws IOException {
String logFileDetailsForServer = "";
String targetConfigName = "";
Cluster clusterForInstance = targetServer.getCluster();
if (clusterForInstance != null) {
targetConfigName = clusterForInstance.getConfigRef();
} else {
targetConfigName = targetServer.getConfigRef();
}
logFileDetailsForServer = loggingConfig.getLoggingFileDetails(targetConfigName);
return logFileDetailsForServer;
}
/*
* This method is used by LogViewerResource which is used to display raw log data like 'tail -f server.log'.
*/
public String getLogFileForGivenTarget(String targetServerName) throws IOException {
Server targetServer = domain.getServerNamed(targetServerName);
String serverNode = targetServer.getNodeRef();
if (targetServer.isDas()) {
// getting log file for DAS from logging.properties and returning the same
String logFileDetailsForServer = loggingConfig.getLoggingFileDetails();
logFileDetailsForServer = TranslatedConfigView.getTranslatedValue(logFileDetailsForServer).toString();
logFileDetailsForServer = new File(logFileDetailsForServer).getAbsolutePath();
return logFileDetailsForServer;
} else {
// getting log file for instance from logging.properties
String logFileDetailsForInstance = getInstanceLogFileDetails(targetServer);
Node node = domain.getNodes().getNode(serverNode);
String loggingDir = "";
String loggingFile = "";
// replacing instanceRoot value if it's there
if (logFileDetailsForInstance.contains("${com.sun.aas.instanceRoot}/logs") && node.getNodeDir() != null) {
// this code is used if no changes made in logging.properties file
loggingDir = node.getNodeDir() + File.separator + serverNode
+ File.separator + targetServerName;
loggingFile = logFileDetailsForInstance.replace("${com.sun.aas.instanceRoot}", loggingDir);
} else if (logFileDetailsForInstance.contains("${com.sun.aas.instanceRoot}/logs") && node.getInstallDir() != null) {
loggingDir = node.getInstallDir() + File.separator + "glassfish" + File.separator + "nodes"
+ File.separator + serverNode + File.separator + targetServerName;
loggingFile = logFileDetailsForInstance.replace("${com.sun.aas.instanceRoot}", loggingDir);
} else {
loggingFile = logFileDetailsForInstance;
}
if (node.isLocal()) {
// if local just returning log file to view
return loggingFile;
} else {
// if remote then need to download log file on DAS and returning that log file for view
String logFileName = logFileDetailsForInstance.substring(logFileDetailsForInstance.lastIndexOf(File.separator) + 1, logFileDetailsForInstance.length());
File instanceFile = null;
instanceFile = new LogFilterForInstance().downloadGivenInstanceLogFile(habitat, targetServer, domain, LOGGER,
targetServerName, env.getDomainRoot().getAbsolutePath(), logFileName, logFileDetailsForInstance);
return instanceFile.getAbsolutePath();
}
}
}
public AttributeList getLogRecordsUsingQuery(
String logFileName, Long fromRecord, Boolean next, Boolean forward,
Integer requestedCount, Date fromDate, Date toDate,
String logLevel, Boolean onlyLevel, List listOfModules,
Properties nameValueMap, String anySearch, String instanceName) {
Server targetServer = domain.getServerNamed(instanceName);
File instanceLogFile = null;
if (targetServer.isDas()) {
return getLogRecordsUsingQuery(
logFileName, fromRecord, next, forward,
requestedCount, fromDate, toDate,
logLevel, onlyLevel, listOfModules,
nameValueMap, anySearch);
} else {
// for Instance it's going through this loop. This will use ssh utility to get file from instance machine(remote machine) and
// store under glassfish/domains/domain1/logs/<instance name>/ directory which is used to get LogFile object.
// Right now user needs to go through this URL to setup and configure ssh http://wikis.sun.com/display/GlassFish/3.1SSHSetup
String serverNode = targetServer.getNodeRef();
Node node = domain.getNodes().getNode(serverNode);
String loggingDir = "";
String instanceLogFileName = "";
try {
// getting lof file details for given target.
instanceLogFileName = getInstanceLogFileDetails(targetServer);
} catch (Exception e) {
LOGGER.log(Level.SEVERE, LogFacade.ERROR_EXECUTING_LOG_QUERY, e);
return new AttributeList();
}
if (node.isLocal()) {
loggingDir = new LogFilterForInstance().getLoggingDirectoryForNode(instanceLogFileName, node, serverNode, instanceName);
File logsDir = new File(loggingDir);
File allLogFileNames[] = logsDir.listFiles();
boolean noFileFound = true;
if (allLogFileNames != null) { // This check for, if directory doesn't present or missing on machine. It happens due to bug 16451
for (int i = 0; i < allLogFileNames.length; i++) {
File file = allLogFileNames[i];
String fileName = file.getName();
// code to remove . and .. file which is return
if (file.isFile() && !fileName.equals(".") && !fileName.equals("..") && fileName.contains(".log")
&& !fileName.contains(".log.")) {
noFileFound = false;
break;
}
}
}
if (noFileFound) {
// this loop is used when user has changed value for server.log but not restarted the server.
loggingDir = new LogFilterForInstance().getLoggingDirectoryForNodeWhenNoFilesFound(instanceLogFileName, node, serverNode, instanceName);
}
instanceLogFile = new File(loggingDir + File.separator + logFileName);
// verifying loggingFile presents or not if not then changing logFileName value to server.log. It means wrong name is coming
// from GUI to back end code.
if (!instanceLogFile.exists()) {
instanceLogFile = new File(loggingDir + File.separator + "server.log");
} else if (!instanceLogFile.exists()) {
// this code is used when user changes the attributes value(com.sun.enterprise.server.logging.GFFileHandler.file) in
// logging.properties file to something else.
loggingDir = instanceLogFileName.substring(0, instanceLogFileName.lastIndexOf(File.separator));
instanceLogFile = new File(loggingDir + File.separator + logFileName);
if (!instanceLogFile.exists()) {
instanceLogFile = new File(instanceLogFileName);
}
}
} else {
try {
// this code is used when the node is not local.
instanceLogFile = new LogFilterForInstance().downloadGivenInstanceLogFile(habitat, targetServer,
domain, LOGGER, instanceName, env.getDomainRoot().getAbsolutePath(), logFileName, instanceLogFileName);
} catch (Exception e) {
LOGGER.log(Level.SEVERE, LogFacade.ERROR_EXECUTING_LOG_QUERY, e);
return new AttributeList();
}
}
}
LogFile logFile = null;
File loggingFileExists = new File(instanceLogFile.getAbsolutePath());
if (!loggingFileExists.exists()) {
LOGGER.log(Level.WARNING, LogFacade.INSTANCE_LOG_FILE_NOT_FOUND, instanceLogFile.getAbsolutePath());
return new AttributeList();
}
logFile = getLogFile(instanceLogFile.getAbsolutePath());
boolean forwd = (forward == null) ? true : forward.booleanValue();
boolean nxt = (next == null) ? true : next.booleanValue();
long reqCount = (requestedCount == null) ?
logFile.getIndexSize() : requestedCount.intValue();
long startingRecord;
if (fromRecord == -1) {
// In this case next/previous (before/after) don't mean much since
// we don't have a reference record number. So set before/after
// according to the direction.
nxt = forwd;
// We +1 for reverse so that we see the very end of the file (the
// query will not go past the "startingRecord", so we have to put
// it after the end of the file)
startingRecord = forwd ?
(-1) : ((logFile.getLastIndexNumber() + 1) * logFile.getIndexSize());
} else {
startingRecord = fromRecord.longValue();
if (startingRecord < -1) {
throw new IllegalArgumentException(
"fromRecord must be greater than 0!");
}
}
// TO DO: If the fromRecord count is zero and the fromDate entry is
// non-null, then the system should take advantage of file Indexing.
// It should move the file position to the marker where the DateTime
// query matches.
try {
return fetchRecordsUsingQuery(logFile, startingRecord, nxt, forwd,
reqCount, fromDate, toDate, logLevel,
onlyLevel.booleanValue(), listOfModules, nameValueMap, anySearch);
} catch (Exception ex) {
LOGGER.log(Level.SEVERE, LogFacade.ERROR_EXECUTING_LOG_QUERY, ex);
return new AttributeList();
}
}
/**
* Internal method that will be called from getLogRecordsUsingQuery()
*/
protected AttributeList fetchRecordsUsingQuery(
LogFile logFile, long startingRecord, boolean next, boolean forward,
long requestedCount, Date fromDate, Date toDate, String logLevel,
boolean onlyLevel, List listOfModules, Properties nameValueMap, String anySearch) {
// If !next, then set to search in reverse
boolean origForward = forward;
if (next) {
startingRecord++;
forward = true;
} else {
forward = false;
}
// Setup forward/reverse stuff
int inc = 1;
int start = 0; // depends on length of results (for reverse)
int end = -1; // depends on length of results (for forward)
long searchChunkIncrement = requestedCount;
if (!forward) {
inc = -1;
// Move back to find records before the startingRecord
// -1 because we still want to see the starting record (only if in
// "next" mode)
startingRecord -=
((next) ? (searchChunkIncrement - 1) : (searchChunkIncrement));
if (startingRecord < 0) {
// Don't go past the original startingRecord
searchChunkIncrement += startingRecord;
startingRecord = 0;
}
}
// Make sure the module names are correct
//updateModuleList(listOfModules);
// Keep pulling records to search through until we get enough matches
List results = new ArrayList();
List records = null;
LogFile.LogEntry entry = null;
while (results.size() < requestedCount) {
// The following will always return unfiltered forward records
records = logFile.getLogEntries(
startingRecord, searchChunkIncrement);
if (records == null) {
break;
}
// Determine end/start
if (forward) {
end = records.size();
} else {
start = records.size() - 1;
}
// Loop through the records, filtering and storing the matches
for (int count = start;
(count != end) && (results.size() < requestedCount);
count += inc) {
entry = (LogFile.LogEntry) records.get(count);
if (allChecks(entry, fromDate, toDate, logLevel, onlyLevel,
listOfModules, nameValueMap, anySearch)) {
results.add(entry);
}
}
// Update startingRecord / searchChunkIncrement & check for finish
if (forward) {
// If the record size is smaller than requested, then there
// are no more records.
if (records.size() < searchChunkIncrement) {
break;
}
// Get starting record BEFORE updating searchChunkIncrement to
// skip all the records we already saw
startingRecord += searchChunkIncrement * inc;
searchChunkIncrement = requestedCount - results.size();
} else {
// If we already searched from 0, then there are no more
if (startingRecord == 0) {
break;
}
// Get starting record AFTER updating searchChunkIncrement
searchChunkIncrement = requestedCount - results.size();
startingRecord += searchChunkIncrement * inc;
if (startingRecord < 1) {
searchChunkIncrement += startingRecord;
startingRecord = 0;
}
}
}
// Deal with previous&forward or next&reverse
if (next ^ origForward) {
List reversedResults = new ArrayList();
// Reverse the results
for (int count = results.size() - 1; count > -1; count--) {
reversedResults.add(results.get(count));
}
results = reversedResults;
}
// Return the matches. If this is less than requested, then there are
// no more.
if (DEBUG) {
System.out.println("Log filter results size="+results.size() + ", requestedCount=" + requestedCount);
}
return convertResultsToTheStructure(results);
}
/**
* This method converts the results to the appropriate structure for
* LogMBean to return to the Admin Front End.
* <p/>
* AttributeList Results contain 2 attributes
* <p/>
* Attribute 1: Contains the Header Information, that lists out all the
* Field Names and Positions
* Attribute 2: Contains the actual Results, Each Log record is an entry
* of this result. The LogRecord itself is an ArrayList of
* all fields.
*/
private AttributeList convertResultsToTheStructure(List results) {
if (results == null) {
return null;
}
AttributeList resultsInTemplate = new AttributeList();
resultsInTemplate.add(LogRecordTemplate.getHeader());
Iterator iterator = results.iterator();
ArrayList listOfResults = new ArrayList();
Attribute resultsAttribute = new Attribute(RESULTS_ATTRIBUTE,
listOfResults);
resultsInTemplate.add(resultsAttribute);
while (iterator.hasNext()) {
LogFile.LogEntry entry = (LogFile.LogEntry) iterator.next();
ArrayList logRecord = new ArrayList();
logRecord.add(Long.valueOf(entry.getRecordNumber()));
logRecord.add(entry.getLoggedDateTime());
logRecord.add(entry.getLoggedLevel());
logRecord.add(entry.getLoggedProduct());
logRecord.add(entry.getLoggedLoggerName());
logRecord.add(entry.getLoggedNameValuePairs());
logRecord.add(entry.getMessageId());
logRecord.add(entry.getLoggedMessage());
listOfResults.add(logRecord);
}
return resultsInTemplate;
}
/**
* This provides access to the LogFile object.
*/
public LogFile getLogFile() {
return _logFile;
}
/**
* This fetches or updates logFileCache entries.
* <p/>
* _REVISIT_: We may want to limit the entries here as each logFile
* takes up so much of memory to maintain indexes
*/
public LogFile getLogFile(String fileName) {
// No need to check for null or zero length string as the
// test is already done before.
String logFileName = fileName.trim();
LogFile logFile = (LogFile) logFileCache.get(fileName);
String parent = null;
if (logFile == null) {
try {
// First check if the fileName provided is an absolute filename
// if yes, then we don't have to construct the parent element
// path with the parent.
if (new File(fileName).exists()) {
logFile = new LogFile(fileName);
logFileCache.put(fileName, logFile);
return logFile;
}
// If the absolute path is not provided, the burden of
// constructing the parent path falls on us. We try
// using the default parent path used for the current LogFile.
// assume the user specified the path from the instance root and that is the parent
parent = System.getProperty(
SystemPropertyConstants.INSTANCE_ROOT_PROPERTY);
} catch (Exception e) {
LOGGER.log(Level.SEVERE, LogFacade.ERROR_EXECUTING_LOG_QUERY, e);
}
if (parent != null) {
// Just use the parent directory from the other server.log
// file.
String[] logFileNameParts = {parent, logFileName};
logFileName = StringUtils.makeFilePath(
logFileNameParts, false);
}
logFile = new LogFile(logFileName);
logFileCache.put(fileName, logFile);
}
return logFile;
}
/**
* This method accepts the first line of the Log Record and checks
* to see if it matches the query.
*/
protected boolean allChecks(LogFile.LogEntry entry,
Date fromDate, Date toDate, String queryLevel, boolean onlyLevel,
List listOfModules, Properties nameValueMap, String anySearch) {
if (DEBUG) {
StringBuffer buf = new StringBuffer();
buf.append(dateTimeCheck(entry.getLoggedDateTime(), fromDate, toDate));
buf.append(",");
buf.append(levelCheck(entry.getLoggedLevel(), queryLevel, onlyLevel));
buf.append(",");
buf.append(moduleCheck(entry.getLoggedLoggerName(), listOfModules));
buf.append(",");
buf.append(nameValueCheck(entry.getLoggedNameValuePairs(), nameValueMap));
buf.append(",");
buf.append(messageDataCheck(entry.getLoggedMessage(), entry.getLoggedNameValuePairs(), anySearch));
System.out.println("allChecks="+buf.toString());
}
if ((dateTimeCheck(entry.getLoggedDateTime(), fromDate, toDate))
&& (levelCheck(entry.getLoggedLevel(), queryLevel, onlyLevel))
&& (moduleCheck(entry.getLoggedLoggerName(), listOfModules))
&& (nameValueCheck(entry.getLoggedNameValuePairs(), nameValueMap))
&& (messageDataCheck(entry.getLoggedMessage(), entry.getLoggedNameValuePairs(), anySearch))) {
return true;
}
return false;
}
protected boolean dateTimeCheck(Date loggedDateTime,
Date fromDateTime, Date toDateTime) {
if ((fromDateTime == null) || (toDateTime == null)) {
// If user doesn't specify fromDate and toDate, then S/He is
// not interested in DateTime filter
return true;
}
// Now do a range check
if (!(loggedDateTime.before(fromDateTime) ||
loggedDateTime.after(toDateTime))) {
return true;
}
return false;
}
protected boolean levelCheck(
final String loggedLevel,
final String queryLevelIn,
final boolean isOnlyLevelFlag) {
// If queryLevel is null, that means user is not interested in
// running the query on the Log Level field.
if (queryLevelIn == null) {
return true;
}
final String queryLevel = queryLevelIn.trim();
if (isOnlyLevelFlag) {
// This means the user is interested in seeing log messages whose
// log level is equal to what is specified
return loggedLevel.equals(queryLevel);
} else {
try {
int loggedLevelValue = Level.parse(loggedLevel).intValue();
int queryLevelValue = Level.parse(queryLevelIn).intValue();
return (loggedLevelValue >= queryLevelValue);
} catch(Exception e) {
return true;
}
}
}
protected boolean moduleCheck(String loggerName, List modules) {
if ((modules == null) || (modules.size() == 0)) {
return true;
}
loggerName = loggerName.trim();
Iterator iterator = modules.iterator();
while (iterator.hasNext()) {
String module = (String) iterator.next();
module = module.trim();
if (loggerName.equals(module)) {
return true;
}
}
return false;
}
protected boolean nameValueCheck(String loggedNameValuePairs,
Properties queriedNameValueMap) {
if ((queriedNameValueMap == null) || (queriedNameValueMap.size() == 0)) {
return true;
}
if (loggedNameValuePairs == null) {
// We didn't match the name values...
return false;
}
StringTokenizer nvListTokenizer =
new StringTokenizer(loggedNameValuePairs, NV_SEPARATOR);
while (nvListTokenizer.hasMoreTokens()) {
String nameandvalue = nvListTokenizer.nextToken();
StringTokenizer nvToken = new StringTokenizer(nameandvalue, "=");
if (nvToken.countTokens() < 2)
continue;
String loggedName = nvToken.nextToken();
String loggedValue = nvToken.nextToken();
// Reset the iterator to start from the first entry AGAIN
// FIXME: Is there any other cleaner way to reset the iterator
// position to zero than recreating a new iterator everytime
Iterator queriedNameValueMapIterator =
queriedNameValueMap.entrySet().iterator();
while (queriedNameValueMapIterator.hasNext()) {
Map.Entry entry =
(Map.Entry) queriedNameValueMapIterator.next();
if (entry.getKey().equals(loggedName)) {
Object value = entry.getValue();
// We have a key with multiple values to match.
// This will happen if the match condition is like
// _ThreadID=10 or _ThreadID=11
// _REVISIT_: There is an opportunity to improve performance
// for this search.
Iterator iterator = ((java.util.List) value).iterator();
while (iterator.hasNext()) {
if (((String) iterator.next()).equals(
loggedValue)) {
return true;
}
}
}
}
}
return false;
}
protected boolean messageDataCheck(String message, String nvp,
String anySearch) {
if (anySearch == null || ("").contains(anySearch) || anySearch.length() < 3) {
return true;
}
if ((message != null && message.contains(anySearch)) || (nvp != null && nvp.contains(anySearch))) {
return true;
}
return false;
}
static final String[] LOG_LEVELS = {"SEVERE", "WARNING",
"INFO", "CONFIG", "FINE", "FINER", "FINEST"};
private static String[] serverLogElements =
{System.getProperty("com.sun.aas.instanceRoot"), "logs", "server.log"};
private static String pL =
System.getProperty("com.sun.aas.processLauncher");
private static String verboseMode =
System.getProperty("com.sun.aas.verboseMode", "false");
private static String defaultLogFile =
System.getProperty("com.sun.aas.defaultLogFile");
private LogFile _logFile =
(pL != null && !verboseMode.equals("true") && defaultLogFile != null) ?
new LogFile(defaultLogFile) :
new LogFile(StringUtils.makeFilePath(serverLogElements, false));
private static Hashtable logFileCache = new Hashtable();
}