Fields Summary |
---|
private static final Logger | _logger |
private static final String | COMMON_PATTERN |
private static final String | COMBINED_PATTERN |
private static final String | LOGGING_MAX_HISTORY_FILESName of the system property whose value specifies the max number of
access log history files to keep.
If this property has been specified without any value, a default value
of 10 is used.
Else, if it has been specified with a value of 0, no access log
history files will be maintained, and the current access log file will
be reset after each rotation.
If undefined, all access log history files will be preserved. |
private static final int | MIN_BUFFER_SIZEThe minimum size a buffer can have. |
private String | directoryThe directory in which log files are created. |
protected static final String | infoThe descriptive information about this implementation. |
private String | prefixThe prefix that is added to log file filenames. |
private boolean | rotatableShould we rotate our log file? |
private org.apache.catalina.util.StringManager | smThe string manager for this package. |
private boolean | startedHas this component been started yet? |
private String | suffixThe suffix that is added to log file filenames. |
private boolean | removeLeadingDotFromSuffixIf prefix ends in '.', and suffix starts with '.', we must remove the
leading '.' from suffix when prefix and suffix are concatenated. |
private String | dotLessSuffixSuffix from which leading '.' has been removed if
removeLeadingDotFromSuffix is true |
private SimpleDateFormat | dateFormatterA date formatter to format a Date into a date in the format
"yyyy-MM-dd". |
private boolean | resolveHostsResolve hosts. |
private long | lastAccessLogCreationTimeInstant when the log daily rotation was last checked. |
private String | conditionAre we doing conditional logging. default false. |
private String | fileDateFormatDate format to place in log file name. Use at your own risk! |
protected FileChannel | fileChannelThe FileChannel used to write the access log. |
FileOutputStream | fosThe stream used to store the logs. |
private int | writeIntervalThe interval (in seconds) between writing the logs |
private int | rotationIntervalThe interval between rotating the logs |
private Thread | writerThreadThe background writerThread. |
private boolean | threadDoneThe background writerThread completion semaphore. |
private CharBuffer | charBufferThe CharBuffer used to store the logs. |
protected int | bufferSizeThe byteBuffer used to store the log. |
protected boolean | flushRealTimeIf the writer interval is equals to zero, then always flush the
direct byte buffer after every request. |
private boolean | addDateStampToFirstAccessLogFileAre we supposed to add datestamp to first access log file we create,
or only after first rotation?
If set to false, the current access log file will never have any
date stamp: It will be moved to a date-stamped file upon rotation |
private File | logFileThe current access log file. |
private int | maxHistoryFilesThe maximum number of access log history files to keep |
private boolean | deleteAllHistoryFilesTrue if no access log history files are to be kept, false otherwise |
private LinkedList | historyFilesList of most recent access log history files (the size of this list
is not to exceed maxHistoryFiles ) |
private com.sun.enterprise.web.accesslog.AccessLogFormatter | formatterThe access log formatter |
private Object | lockSimple lock |
Methods Summary |
---|
public void | addLifecycleListener(org.apache.catalina.LifecycleListener listener)Add a lifecycle event listener to this component.
lifecycle.addLifecycleListener(listener);
|
private synchronized void | close()Close the currently open log file (if any)
try{
// Make sure the byteBuffer is clean
log();
fileChannel.close();
fos.close();
} catch (IOException ex){
;
}
|
boolean | configure(java.lang.String vsId, com.sun.enterprise.config.serverbeans.VirtualServer vsBean, com.sun.enterprise.config.serverbeans.HttpService httpService, com.sun.enterprise.config.serverbeans.Domain domain, com.sun.enterprise.instance.InstanceEnvironment instance, com.sun.enterprise.server.pluggable.WebContainerFeatureFactory fac, java.lang.String globalAccessLogBufferSize, java.lang.String globalAccessLogWriteInterval)
setPrefix(vsId + fac.getDefaultAccessLogPrefix());
boolean start = updateVirtualServerProperties(
vsId, vsBean, domain, instance, globalAccessLogBufferSize,
globalAccessLogWriteInterval);
updateAccessLogAttributes(httpService, fac);
return start;
|
public org.apache.catalina.LifecycleListener[] | findLifecycleListeners()Get the lifecycle listeners associated with this lifecycle. If this
Lifecycle has no listeners registered, a zero-length array is returned.
return lifecycle.findLifecycleListeners();
|
public int | geRotationInterval()Return rotation interval
return rotationInterval;
|
public int | getBufferSize()Return the direct ByteBuffer size
return bufferSize;
|
public java.lang.String | getCondition()Return whether the attribute name to look for when
performing conditional loggging. If null, every
request is logged.
return condition;
|
public java.lang.String | getDirectory()Return the directory in which we create log files.
return (directory);
|
public java.lang.String | getFileDateFormat()Return the date format date based log rotation.
return fileDateFormat;
|
public java.lang.String | getInfo()Return descriptive information about this implementation.
return (this.info);
|
public java.lang.String | getPrefix()Return the log file prefix.
return (prefix);
|
public java.lang.String | getSuffix()Return the log file suffix.
return (suffix);
|
public int | getWriterInterval()Return writerThread interval (seconds)
return writeInterval;
|
public int | invoke(org.apache.catalina.Request request, org.apache.catalina.Response response)Log a message summarizing the specified request and response, according
to the format specified by the pattern property.
if (formatter.needTimeTaken()) {
request.setNote(Constants.REQUEST_START_TIME_NOTE,
Long.valueOf(System.currentTimeMillis()));
}
return INVOKE_NEXT;
|
public boolean | isResolveHosts()Get the value of the resolve hosts flag.
return resolveHosts;
|
public boolean | isRotatable()Should we rotate the logs
return rotatable;
|
boolean | isStarted()
return started;
|
public void | log()Log the specified message to the log file, switching files if the date
has changed since the previous log call.
if (rotatable){
long systime = System.currentTimeMillis();
if ((systime-lastAccessLogCreationTime) > (rotationInterval*1000)) {
synchronized (this) {
systime = System.currentTimeMillis();
if ((systime-lastAccessLogCreationTime) >
(rotationInterval*1000)) {
// Rotate only if the formatted datestamps are
// different
String lastDateStamp = dateFormatter.format(
new Date(lastAccessLogCreationTime));
String newDateStamp = dateFormatter.format(
new Date(systime));
lastAccessLogCreationTime = systime;
if (!lastDateStamp.equals(newDateStamp)) {
close();
open(newDateStamp, false);
}
}
}
}
}
synchronized(lock){
try{
charBuffer.flip();
ByteBuffer byteBuffer =
ByteBuffer.wrap(charBuffer.toString().getBytes());
while (byteBuffer.hasRemaining()){
fileChannel.write(byteBuffer);
}
charBuffer.clear();
} catch (IOException ex){
;
}
}
|
private synchronized void | open(java.lang.String dateStamp, boolean firstAccessLogFile)Open new access log file.
// Create the directory if necessary
File dir = new File(directory);
if (!dir.isAbsolute())
dir = new File(System.getProperty("catalina.base"), directory);
dir.mkdirs();
// Open the current log file
try {
String pathname;
// If no rotate - no need for dateStamp in fileName
if (rotatable && addDateStampToFirstAccessLogFile) {
pathname = dir.getAbsolutePath() + File.separator +
prefix + dateStamp + suffix;
} else {
if (removeLeadingDotFromSuffix) {
pathname = dir.getAbsolutePath() + File.separator +
prefix + dotLessSuffix;
} else {
pathname = dir.getAbsolutePath() + File.separator +
prefix + suffix;
}
}
if (rotatable
&& !addDateStampToFirstAccessLogFile
&& !firstAccessLogFile) {
// Move current access log file, which has no date stamp,
// to date-stamped file
String dateStampedPathname = dir.getAbsolutePath()
+ File.separator
+ prefix + dateStamp + suffix;
File renameToFile = new File(dateStampedPathname);
if (!logFile.renameTo(renameToFile)) {
_logger.log(
Level.WARNING,
"peaccesslogvalve.unableToRenameLogFile",
new Object[] {
logFile.toString(), dateStampedPathname });
}
File removeFile = null;
if (deleteAllHistoryFiles) {
removeFile = renameToFile;
} else {
if (historyFiles != null) {
historyFiles.addLast(renameToFile);
if (historyFiles.size() > maxHistoryFiles) {
removeFile = historyFiles.removeFirst();
}
}
}
if (removeFile != null && !removeFile.delete()) {
_logger.log(Level.WARNING,
"peaccesslogvalve.unableToRemoveLogFile",
removeFile.toString());
}
}
// Open the file and then get a channel from the stream
logFile = new File(pathname);
fos = new FileOutputStream(logFile, true);
fileChannel = fos.getChannel();
} catch (IOException e) {
try{
if ( fileChannel != null )
fileChannel.close();
} catch (IOException ex){
;
}
}
|
public void | postInvoke(org.apache.catalina.Request request, org.apache.catalina.Response response)
if (!started || (condition!=null &&
null!=request.getRequest().getAttribute(condition))) {
return;
}
synchronized (lock){
// Reset properly the buffer in case of an unexpected
// exception.
if (charBuffer.position() == charBuffer.limit()){
charBuffer.limit(charBuffer.capacity());
}
int pos = charBuffer.position();
// We've flushed our buffer to make room for the current request.
// Now process the current request
for (int i=0; i < 2; i++){
try {
formatter.appendLogEntry(request, response, charBuffer);
charBuffer.put("\n");
if (flushRealTime){
log();
}
break;
} catch (BufferOverflowException ex) {
charBuffer.position(pos);
log();
if (i+1 == 2){
_logger.log(
Level.SEVERE,
"peaccesslogvalve.unableToWrite",
new Object[] {ex});
return;
}
charBuffer = CharBuffer.allocate(MIN_BUFFER_SIZE);
}
}
}
|
public void | removeLifecycleListener(org.apache.catalina.LifecycleListener listener)Remove a lifecycle event listener from this component.
lifecycle.removeLifecycleListener(listener);
|
public void | run()The background writerThread that checks for write the log.
// Loop until the termination semaphore is set
while (!threadDone) {
threadSleep();
log();
}
|
public void | setAddDateStampToFirstAccessLogFile(boolean add)Are we supposed to add datestamp to first access log file we create,
or only starting with first rotation?
this.addDateStampToFirstAccessLogFile = add;
|
public void | setBufferSize(int size)Set the direct ByteBuffer size
if ( size > 0 ){
flushRealTime = false;
}
bufferSize = size;
|
public void | setCondition(java.lang.String condition)Set the ServletRequest.attribute to look for to perform
conditional logging. Set to null to log everything.
this.condition = condition;
|
public void | setDirectory(java.lang.String directory)Set the directory in which we create log files.
this.directory = directory;
|
public void | setFileDateFormat(java.lang.String fileDateFormat)Set the date format date based log rotation.
this.fileDateFormat = fileDateFormat;
|
public void | setPattern(java.lang.String p)Set the format pattern, first translating any recognized alias.
if (COMMON_PATTERN.equalsIgnoreCase(p)) {
formatter = new CommonAccessLogFormatterImpl();
} else if (COMBINED_PATTERN.equalsIgnoreCase(p)) {
formatter = new CombinedAccessLogFormatterImpl();
} else {
formatter = new DefaultAccessLogFormatterImpl(p, getContainer());
}
|
public void | setPrefix(java.lang.String p)Set the log file prefix.
prefix = p;
if (prefix != null && suffix != null && prefix.endsWith(".")
&& suffix.startsWith(".")) {
removeLeadingDotFromSuffix = true;
dotLessSuffix = suffix.substring(1);
} else {
removeLeadingDotFromSuffix = false;
}
|
public void | setResolveHosts(boolean resolveHosts)Set the resolve hosts flag.
this.resolveHosts = resolveHosts;
|
public void | setRotatable(boolean rotatable)Set the value is we should we rotate the logs
this.rotatable = rotatable;
|
public void | setRotationInterval(int t)Set rotation interval
rotationInterval = t;
|
public void | setSuffix(java.lang.String s)Set the log file suffix.
suffix = s;
if (prefix != null && suffix != null && prefix.endsWith(".")
&& suffix.startsWith(".")) {
removeLeadingDotFromSuffix = true;
dotLessSuffix = suffix.substring(1);
} else {
removeLeadingDotFromSuffix = false;
}
|
public void | setWriterInterval(int t)Set writerthread interval (seconds)
if ( t > 0 ){
flushRealTime = false;
}
writeInterval = t;
|
public void | start()Prepare for the beginning of active use of the public methods of this
component. This method should be called after configure() ,
and before any of the public methods of the component are utilized.
// Validate and update our current component state
if (started) {
throw new LifecycleException
(sm.getString("accessLogValve.alreadyStarted"));
}
lifecycle.fireLifecycleEvent(START_EVENT, null);
deleteAllHistoryFiles = false;
historyFiles = null;
String prop = System.getProperty(LOGGING_MAX_HISTORY_FILES);
if (prop != null) {
maxHistoryFiles = 10;
if (!"".equals(prop)) {
try {
maxHistoryFiles = Integer.parseInt(prop);
} catch (NumberFormatException e) {};
}
if (maxHistoryFiles == 0) {
deleteAllHistoryFiles = true;
} else if (maxHistoryFiles > 0) {
historyFiles = new LinkedList<File>();
}
}
if (bufferSize <= 0) {
bufferSize = MIN_BUFFER_SIZE;
}
charBuffer = CharBuffer.allocate(bufferSize);
// Initialize the timeZone, Date formatters, and currentDate
TimeZone tz = TimeZone.getDefault();
if (fileDateFormat==null || fileDateFormat.length()==0)
fileDateFormat = "yyyy-MM-dd";
dateFormatter = new SimpleDateFormat(fileDateFormat);
dateFormatter.setTimeZone(tz);
long systime = System.currentTimeMillis();
open(dateFormatter.format(new Date(systime)), true);
lastAccessLogCreationTime = systime;
if (!flushRealTime){
// Start the background writer writerThread
threadStart();
}
started = true;
|
public void | stop()Gracefully terminate the active use of the public methods of this
component. This method should be the last one called on a given
instance of this component.
// Validate and update our current component state
if (!started)
throw new LifecycleException
(sm.getString("accessLogValve.notStarted"));
lifecycle.fireLifecycleEvent(STOP_EVENT, null);
started = false;
if (!flushRealTime){
// Stop the background writer thread
threadStop();
}
close();
|
private void | threadSleep()Sleep for the duration specified by the writeInterval
property.
if (writerThread != null || writeInterval == 0)
return;
try {
writerThread.sleep(writeInterval * 1000L);
} catch (InterruptedException e) {
;
}
|
private void | threadStart()Start the background writerThread that will periodically write access log
if (writerThread != null || writeInterval == 0)
return;
threadDone = false;
String threadName = "AccessLogWriter";
writerThread = new Thread(this, threadName);
writerThread.setDaemon(true);
writerThread.start();
|
private void | threadStop()Stop the background writerThread that is periodically write logs
if (writerThread == null || writeInterval == 0)
return;
threadDone = true;
writerThread.interrupt();
try {
writerThread.join();
} catch (InterruptedException e) {
;
}
writerThread = null;
|
void | updateAccessLogAttributes(com.sun.enterprise.config.serverbeans.HttpService httpService, com.sun.enterprise.server.pluggable.WebContainerFeatureFactory fac)Configures this accesslog valve with the accesslog related
attributes of the domain.xml's and
elements.
HttpProtocol httpProtocol = httpService.getHttpProtocol();
if (httpProtocol != null) {
setResolveHosts(httpProtocol.isDnsLookupEnabled());
} else {
setResolveHosts(false);
}
AccessLog accessLogConfig = httpService.getAccessLog();
// access-log format
String format = null;
if (accessLogConfig != null) {
format = accessLogConfig.getFormat();
} else {
format = AccessLog.getDefaultFormat();
}
setPattern(format);
// rotation-enabled
if (accessLogConfig != null) {
setRotatable(accessLogConfig.isRotationEnabled());
} else {
setRotatable(Boolean.valueOf(
AccessLog.getDefaultRotationEnabled()).booleanValue());
}
// rotation-interval
int rotationInterval = 0;
if (accessLogConfig != null) {
String s = accessLogConfig.getRotationIntervalInMinutes();
rotationInterval = Integer.parseInt(s) * 60;
} else {
rotationInterval = fac.getDefaultRotationIntervalInMinutes() * 60;
}
setRotationInterval(rotationInterval);
// rotation-datestamp
String rotationDateStamp = null;
if (accessLogConfig != null) {
rotationDateStamp = accessLogConfig.getRotationSuffix();
} else {
rotationDateStamp = fac.getDefaultAccessLogDateStampPattern();
}
if ("%YYYY;%MM;%DD;-%hh;h%mm;m%ss;s".equals(rotationDateStamp)) {
/*
* Modify the default rotation suffix pattern specified in the
* sun-domain DTD in such a way that it is accepted by
* java.text.SimpleDateFormat. We support only those patterns
* accepted by java.text.SimpleDateFormat.
*/
rotationDateStamp = "yyyyMMdd-HH'h'mm'm'ss's'";
}
setFileDateFormat(rotationDateStamp);
// rotation-suffix
setSuffix(fac.getDefaultAccessLogSuffix());
setAddDateStampToFirstAccessLogFile(
fac.getAddDateStampToFirstAccessLogFile());
|
boolean | updateVirtualServerProperties(java.lang.String vsId, com.sun.enterprise.config.serverbeans.VirtualServer vsBean, com.sun.enterprise.config.serverbeans.Domain domain, com.sun.enterprise.instance.InstanceEnvironment instance, java.lang.String globalAccessLogBufferSize, java.lang.String globalAccessLogWriteInterval)Configures this accesslog valve with the accesslog related properties
of the given bean.
/*
* Determine the virtual server's access log directory, which may be
* specified in two places:
*
* 1. <virtual-server>
* <http-access-log log-directory="..."/>
* </virtual-server>
*
* 2. <virtual-server>
* <property name="accesslog" value="..."/>
* </virtual-server>
*
* If both have been specified, the latter takes precedence.
*/
String accessLog = "access";
if (vsBean.getElementPropertyByName(
Constants.ACCESS_LOG_PROPERTY) != null) {
accessLog = vsBean.getElementPropertyByName(
Constants.ACCESS_LOG_PROPERTY).getValue();
} else if (vsBean.getHttpAccessLog() != null) {
accessLog = vsBean.getHttpAccessLog().getLogDirectory();
}
if (accessLog == null) {
return false;
}
File dir = new File(accessLog);
if (!dir.isAbsolute()) {
/*
* If accesslog is relative, turn it into an absolute path by
* prepending log-root of domain element
*/
String logRoot = domain.getLogRoot();
if (logRoot != null) {
dir = new File(logRoot, accessLog);
} else {
dir = new File(instance.getInstancesRoot(), accessLog);
}
}
if (_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE,
"Setting accesslog directory for virtual "
+ "server '" + vsId + "' to "
+ dir.getAbsolutePath());
}
setDirectory(dir.getAbsolutePath());
// If the property is defined under virtual-server, override the one
// defined under http-service.
String acWriteInterval = globalAccessLogWriteInterval;
if (vsBean.getElementPropertyByName(
Constants.ACCESS_LOG_WRITE_INTERVAL_PROPERTY) != null){
acWriteInterval = vsBean.getElementPropertyByName(
Constants.ACCESS_LOG_WRITE_INTERVAL_PROPERTY).getValue();
}
if (acWriteInterval != null){
try{
setWriterInterval(Integer.parseInt(acWriteInterval));
} catch (NumberFormatException ex){
_logger.log(Level.WARNING,
"pewebcontainer.invalid_accessLog_writerInterval",
acWriteInterval);
}
}
// If the property is defined under virtual-server, override the one
// defined under http-service.
String acBufferSize = globalAccessLogBufferSize;
if (vsBean.getElementPropertyByName(
Constants.ACCESS_LOG_BUFFER_SIZE_PROPERTY) != null){
acBufferSize = vsBean.getElementPropertyByName(
Constants.ACCESS_LOG_BUFFER_SIZE_PROPERTY).getValue();
}
if (acBufferSize != null){
try{
setBufferSize(Integer.parseInt(acBufferSize));
} catch (NumberFormatException ex){
_logger.log(Level.WARNING,
"pewebcontainer.invalid_accessLog_bufferSize",
acBufferSize);
}
}
return true;
|