Skip to content

Commit

Permalink
Merge pull request #2848 from MeroRai/PAYARA-2828
Browse files Browse the repository at this point in the history
PAYARA-2828 Add rotation on file fize options on Access logging
  • Loading branch information
Pandrex247 committed Jun 18, 2018
2 parents 387db18 + a466fae commit 3a51eae
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 31 deletions.
Expand Up @@ -38,7 +38,7 @@
only if the new code is made subject to such option by the copyright
holder.
-->
<!-- Portions Copyright [2016] [Payara Foundation] -->
<!-- Portions Copyright [2016-2018] [Payara Foundation] -->

<!-- configuration/accessLog.jsf -->

Expand Down Expand Up @@ -122,6 +122,10 @@
<sun:property id="MaxHistoryFiles" labelAlign="left" noWrap="#{true}" overlapLabel="#{false}" label="$resource{i18n_web.access.MaxHistoryFiles}" helpText="$resource{i18n_web.access.MaxHistoryFilesHelp}">
<sun:textField id="MaxHistoryFiles" columns="$int{30}" maxLength="#{sessionScope.fieldLengths['maxLength.access.MaxHistoryFiles']}" text="#{pageSession.valueMap2['maxHistoryFiles']}" />
</sun:property>

<sun:property id="MaximumFileSize" labelAlign="left" noWrap="#{true}" overlapLabel="#{false}" label="$resource{i18n_web.access.MaxFileSize}" helpText="$resource{i18n_web.access.MaxFileSizeHelp}">
<sun:textField id="MaximumFileSize" columns="$int{30}" maxLength="#{sessionScope.fieldLengths['maxLength.access.MaximumFileSize']}" text="#{pageSession.valueMap2['maximumFileSize']}" />
</sun:property>

<sun:property id="accessLogBufferSize" labelAlign="left" noWrap="#{true}" overlapLabel="#{false}" label="$resource{i18n_web.access.accessLogBufferSize}" helpText="$resource{i18n_web.access.accessLogBufferSizeHelp}">
<sun:textField id="accessLogBufferSize" styleClass="intAllowMinus" columns="$int{30}" maxLength="#{sessionScope.fieldLengths['maxLength.access.accessLogBufferSize']}" text="#{pageSession.valueMap2['bufferSizeBytes']}" />
Expand Down Expand Up @@ -149,4 +153,3 @@
</define>
</composition>


Expand Up @@ -110,6 +110,8 @@ access.Format=Format:
access.FormatHelp=Global format for the access log file
access.MaxHistoryFilesHelp=The maximum number of rotated access log files that are to be kept. Negative value indicates no limit.
access.MaxHistoryFiles=Max File Count:
access.MaxFileSize=Max File Size
access.MaxFileSizeHelp=File size limit for log file at which it will rotate. If set to 0 rotation is disabled


#deployment
Expand Down Expand Up @@ -495,4 +497,4 @@ httpListenerNewPageTitle=New HTTP Listener
httpListenerNewPageTitleHelp=Use the <a href="#{request.contextPath}/web/grizzly/networkListenerNew.jsf?configName=#{pageSession.encodedConfigName}">New Network Listener </a> page for more <a href="#{request.contextPath}/web/grizzly/networkListenerNew.jsf?configName=#{pageSession.encodedConfigName}">Advanced</a> configuration, including specifying Protocol and Transport for creating a new listener.
httpListener.protocol.alreadyExist=Protocol named {0} already exists. Cannot add duplicate protocol.
configuration.httpListenerEditPageTitle=Edit HTTP Listener
configuration.httpListenerEditPageTitleHelp=Use the <a href="#{request.contextPath}/web/grizzly/networkListenerEdit.jsf?configName=#{pageSession.encodedConfigName}&name=#{pageSession.encodedName}">Edit Network Listener </a> page for more <a href="#{request.contextPath}/web/grizzly/networkListenerEdit.jsf?configName=#{pageSession.encodedConfigName}&name=#{pageSession.encodedName}">Advanced</a> configuration changes.
configuration.httpListenerEditPageTitleHelp=Use the <a href="#{request.contextPath}/web/grizzly/networkListenerEdit.jsf?configName=#{pageSession.encodedConfigName}&name=#{pageSession.encodedName}">Edit Network Listener </a> page for more <a href="#{request.contextPath}/web/grizzly/networkListenerEdit.jsf?configName=#{pageSession.encodedConfigName}&name=#{pageSession.encodedName}">Advanced</a> configuration changes.
Expand Up @@ -62,6 +62,7 @@
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.text.FieldPosition;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.*;
Expand Down Expand Up @@ -114,6 +115,17 @@ public final class PEAccessLogValve
*/
private final static int MIN_BUFFER_SIZE = 5120;

/**
* The minimum size a log file rotation limit can have.
*/
private final static int DEFAULT_FILE_SIZE_ROTATION_LIMIT = 0;

private static final String LOG_ROTATION_TIME_FORMAT
= "'T'HH-mm-ss";

private static final SimpleDateFormat logRotationTimeFormatter
= new SimpleDateFormat(LOG_ROTATION_TIME_FORMAT);

// ----------------------------------------------------- Instance Variables
/**
* The directory in which log files are created.
Expand Down Expand Up @@ -198,6 +210,11 @@ public final class PEAccessLogValve
* The interval between rotating the logs
*/
private int rotationInterval;

/**
* Maximum size a log file can be before rotating
*/
private int maximumLogFileSize;

/**
* The background writerThread.
Expand Down Expand Up @@ -584,31 +601,9 @@ public void postInvoke(Request request, Response response)
*/
public void log() throws IOException {

if (rotatable){

long systime = System.currentTimeMillis();
long rotationIntervalLong = rotationInterval*1000L;
if (systime-lastAccessLogCreationTime > rotationIntervalLong) {
synchronized (this) {
systime = System.currentTimeMillis();
if (systime-lastAccessLogCreationTime >
rotationIntervalLong) {

// Rotate only if the formatted datestamps are
// different
String lastDateStamp = dateFormatter.get().format(
new Date(lastAccessLogCreationTime));
String newDateStamp = dateFormatter.get().format(
new Date(systime));

lastAccessLogCreationTime = systime;

if (!lastDateStamp.equals(newDateStamp)) {
close();
open(newDateStamp, false);
}
}
}
if (rotatable) {
synchronized (lock) {
rotateOnDateChange();
}
}

Expand All @@ -632,6 +627,12 @@ public void log() throws IOException {
}
}

if (rotatable && maximumLogFileSize > 0
&& logFile.length() >= maximumLogFileSize) {
synchronized (lock) {
rotate();
}
}
}

/*
Expand Down Expand Up @@ -863,6 +864,12 @@ void updateAccessLogAttributes(HttpService httpService,

// log to console
accessLogToConsole = Boolean.parseBoolean(accessLogConfig.getLogToConsoleEnabled());

if (accessLogConfig != null) {
maximumLogFileSize = Integer.parseInt(accessLogConfig.getMaximumFileSize());
} else {
maximumLogFileSize = DEFAULT_FILE_SIZE_ROTATION_LIMIT;
}
}

// -------------------------------------------------------- Private Methods
Expand Down Expand Up @@ -1032,6 +1039,97 @@ private void cleanUpHistoryLogFiles() {
}
}

/**
* Rotates the old log file and creates a new log file on date change.
*/
private void rotateOnDateChange(){
long systime = System.currentTimeMillis();
long rotationIntervalLong = rotationInterval * 1000L;
if (systime - lastAccessLogCreationTime > rotationIntervalLong) {
synchronized (this) {
systime = System.currentTimeMillis();
if (systime - lastAccessLogCreationTime
> rotationIntervalLong) {

// Rotate only if the formatted datestamps are
// different
String lastDateStamp = dateFormatter.get().format(
new Date(lastAccessLogCreationTime));
String newDateStamp = dateFormatter.get().format(
new Date(systime));

lastAccessLogCreationTime = systime;

if (!lastDateStamp.equals(newDateStamp)) {
try {
close();
open(newDateStamp, false);
} catch (IOException ex) {
_logger.log(Level.SEVERE, "Could not rotate the Access log file on date chnage", ex);
}
}
}
}
}
}

/**
* Rotates the old log file and creates a new log file.
*/
private void rotate() {
if (rotatable) {
synchronized (lock) {
try {
if (!logFile.exists()) {
File creatingDeletedLogFile = new File(logFile.getAbsolutePath());
if (creatingDeletedLogFile.createNewFile()) {
logFile = creatingDeletedLogFile;
}
} else {
File oldLogFile = logFile;
StringBuffer renamedLogFile = new StringBuffer(
logFile.getAbsolutePath().replace(".txt", ""));
logRotationTimeFormatter.format(new Date(), renamedLogFile, new FieldPosition(0));
File rotatedFile = new File(renamedLogFile
.toString() + ".txt");

boolean isRenameSuccessful = oldLogFile.renameTo(rotatedFile);

if (!isRenameSuccessful) {
/**
* If we don't succeed with file rename which most
* likely can happen on Windows because of multiple
* file handles opened. We go through Plan B to copy
* bytes explicitly to a renamed file.
*/
FileUtils.copy(logFile, rotatedFile);
File newServerLogFile = logFile;
/**
* We do this to make sure that log file contents
* are flushed out to start from a clean file again
* after the rename.
*/
FileOutputStream fileOutputStream = new FileOutputStream(newServerLogFile);
fileOutputStream.close();
}

FileOutputStream oldFileOutputStream = new FileOutputStream(oldLogFile);
oldFileOutputStream.close();

logFileOutputStream = new FileOutputStream(logFile, true);
fileChannel = logFileOutputStream.getChannel();

if (maxHistoryFiles > 0) {
cleanUpHistoryLogFiles();
}
}
} catch (IOException ex) {
_logger.log(Level.SEVERE, "Could not rotate the Access log file", ex);
}
}
}
}

// ------------------------------------------------------ Lifecycle Methods
/**
* Add a lifecycle event listener to this component.
Expand Down Expand Up @@ -1215,4 +1313,4 @@ private void threadStop() {
writerThread = null;

}
}
}
Expand Up @@ -37,7 +37,7 @@
* only if the new code is made subject to such option by the copyright
* holder.
*/
// Portions Copyright [2016-2017] [Payara Foundation]
// Portions Copyright [2016-2018] [Payara Foundation]

package com.sun.enterprise.config.serverbeans;

Expand Down Expand Up @@ -196,7 +196,25 @@ public interface AccessLog extends ConfigBeanProxy, PropertyBag {
* @throws PropertyVetoException if a listener vetoes the change
*/
void setMaxHistoryFiles(String value) throws PropertyVetoException;


/**
* Gets the file size limit at which log will rotate.
*
* <p>A value of 0 will disable log rotation based on file size
* @return log file size rotation limit
*/
@NotNull
@Attribute(defaultValue = "0", dataType=Integer.class)
String getMaximumFileSize();

/**
* Set size limit for log file at which it will rotate.
*
* @param value the limit for log file size
* @throws PropertyVetoException if a listener vetoes the change
*/
void setMaximumFileSize(String value) throws PropertyVetoException;

/**
* Specifies whether to display access logs on the console
*
Expand Down

0 comments on commit 3a51eae

Please sign in to comment.