Add a custom file logger and a custom log manager to be able to use system.env in the log configuration
parent
2091d51141
commit
e9e5f2cb4f
|
@ -0,0 +1,400 @@
|
|||
package net.openesb.standalone.logger;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.logging.ErrorManager;
|
||||
import java.util.logging.Filter;
|
||||
import java.util.logging.Formatter;
|
||||
import java.util.logging.Handler;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogManager;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.SimpleFormatter;
|
||||
|
||||
/**
|
||||
* Implementation of <b>Handler</b> that appends log messages to a file
|
||||
* named {prefix}{date}{suffix} in a configured directory.
|
||||
*
|
||||
* <p>The following configuration properties are available:</p>
|
||||
*
|
||||
* <ul>
|
||||
* <li><code>directory</code> - The directory where to create the log file.
|
||||
* If the path is not absolute, it is relative to the current working
|
||||
* directory of the application. The Apache Tomcat configuration files usually
|
||||
* specify an absolute path for this property,
|
||||
* <code>${catalina.base}/logs</code>
|
||||
* Default value: <code>logs</code></li>
|
||||
* <li><code>rotatable</code> - If <code>true</code>, the log file will be
|
||||
* rotated on the first write past midnight and the filename will be
|
||||
* <code>{prefix}{date}{suffix}</code>, where date is yyyy-MM-dd. If <code>false</code>,
|
||||
* the file will not be rotated and the filename will be <code>{prefix}{suffix}</code>.
|
||||
* Default value: <code>true</code></li>
|
||||
* <li><code>prefix</code> - The leading part of the log file name.
|
||||
* Default value: <code>juli.</code></li>
|
||||
* <li><code>suffix</code> - The trailing part of the log file name. Default value: <code>.log</code></li>
|
||||
* <li><code>bufferSize</code> - Configures buffering. The value of <code>0</code>
|
||||
* uses system default buffering (typically an 8K buffer will be used). A
|
||||
* value of <code><0</code> forces a writer flush upon each log write. A
|
||||
* value <code>>0</code> uses a BufferedOutputStream with the defined
|
||||
* value but note that the system default buffering will also be
|
||||
* applied. Default value: <code>-1</code></li>
|
||||
* <li><code>encoding</code> - Character set used by the log file. Default value:
|
||||
* empty string, which means to use the system default character set.</li>
|
||||
* <li><code>level</code> - The level threshold for this Handler. See the
|
||||
* <code>java.util.logging.Level</code> class for the possible levels.
|
||||
* Default value: <code>ALL</code></li>
|
||||
* <li><code>filter</code> - The <code>java.util.logging.Filter</code>
|
||||
* implementation class name for this Handler. Default value: unset</li>
|
||||
* <li><code>formatter</code> - The <code>java.util.logging.Formatter</code>
|
||||
* implementation class name for this Handler. Default value:
|
||||
* <code>java.util.logging.SimpleFormatter</code></li>
|
||||
* </ul>
|
||||
*
|
||||
*/
|
||||
|
||||
public class FileHandler
|
||||
extends Handler {
|
||||
|
||||
|
||||
// ------------------------------------------------------------ Constructor
|
||||
|
||||
|
||||
public FileHandler() {
|
||||
this(null, null, null);
|
||||
}
|
||||
|
||||
|
||||
public FileHandler(String directory, String prefix, String suffix) {
|
||||
this.directory = directory;
|
||||
this.prefix = prefix;
|
||||
this.suffix = suffix;
|
||||
configure();
|
||||
openWriter();
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
|
||||
/**
|
||||
* The as-of date for the currently open log file, or a zero-length
|
||||
* string if there is no open log file.
|
||||
*/
|
||||
private volatile String date = "";
|
||||
|
||||
|
||||
/**
|
||||
* The directory in which log files are created.
|
||||
*/
|
||||
private String directory = null;
|
||||
|
||||
|
||||
/**
|
||||
* The prefix that is added to log file filenames.
|
||||
*/
|
||||
private String prefix = null;
|
||||
|
||||
|
||||
/**
|
||||
* The suffix that is added to log file filenames.
|
||||
*/
|
||||
private String suffix = null;
|
||||
|
||||
|
||||
/**
|
||||
* Determines whether the logfile is rotatable
|
||||
*/
|
||||
private boolean rotatable = true;
|
||||
|
||||
|
||||
/**
|
||||
* The PrintWriter to which we are currently logging, if any.
|
||||
*/
|
||||
private volatile PrintWriter writer = null;
|
||||
|
||||
|
||||
/**
|
||||
* Lock used to control access to the writer.
|
||||
*/
|
||||
protected ReadWriteLock writerLock = new ReentrantReadWriteLock();
|
||||
|
||||
|
||||
/**
|
||||
* Log buffer size.
|
||||
*/
|
||||
private int bufferSize = -1;
|
||||
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
|
||||
/**
|
||||
* Format and publish a <tt>LogRecord</tt>.
|
||||
*
|
||||
* @param record description of the log event
|
||||
*/
|
||||
@Override
|
||||
public void publish(LogRecord record) {
|
||||
|
||||
if (!isLoggable(record)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Construct the timestamp we will use, if requested
|
||||
Timestamp ts = new Timestamp(System.currentTimeMillis());
|
||||
String tsString = ts.toString().substring(0, 19);
|
||||
String tsDate = tsString.substring(0, 10);
|
||||
|
||||
try {
|
||||
writerLock.readLock().lock();
|
||||
// If the date has changed, switch log files
|
||||
if (rotatable && !date.equals(tsDate)) {
|
||||
try {
|
||||
// Update to writeLock before we switch
|
||||
writerLock.readLock().unlock();
|
||||
writerLock.writeLock().lock();
|
||||
|
||||
// Make sure another thread hasn't already done this
|
||||
if (!date.equals(tsDate)) {
|
||||
closeWriter();
|
||||
date = tsDate;
|
||||
openWriter();
|
||||
}
|
||||
} finally {
|
||||
writerLock.writeLock().unlock();
|
||||
// Down grade to read-lock. This ensures the writer remains valid
|
||||
// until the log message is written
|
||||
writerLock.readLock().lock();
|
||||
}
|
||||
}
|
||||
|
||||
String result = null;
|
||||
try {
|
||||
result = getFormatter().format(record);
|
||||
} catch (Exception e) {
|
||||
reportError(null, e, ErrorManager.FORMAT_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (writer!=null) {
|
||||
writer.write(result);
|
||||
if (bufferSize < 0) {
|
||||
writer.flush();
|
||||
}
|
||||
} else {
|
||||
reportError("FileHandler is closed or not yet initialized, unable to log ["+result+"]", null, ErrorManager.WRITE_FAILURE);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
reportError(null, e, ErrorManager.WRITE_FAILURE);
|
||||
return;
|
||||
}
|
||||
} finally {
|
||||
writerLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------- Private Methods
|
||||
|
||||
|
||||
/**
|
||||
* Close the currently open log file (if any).
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
closeWriter();
|
||||
}
|
||||
|
||||
protected void closeWriter() {
|
||||
|
||||
writerLock.writeLock().lock();
|
||||
try {
|
||||
if (writer == null)
|
||||
return;
|
||||
writer.write(getFormatter().getTail(this));
|
||||
writer.flush();
|
||||
writer.close();
|
||||
writer = null;
|
||||
date = "";
|
||||
} catch (Exception e) {
|
||||
reportError(null, e, ErrorManager.CLOSE_FAILURE);
|
||||
} finally {
|
||||
writerLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Flush the writer.
|
||||
*/
|
||||
@Override
|
||||
public void flush() {
|
||||
|
||||
writerLock.readLock().lock();
|
||||
try {
|
||||
if (writer == null)
|
||||
return;
|
||||
writer.flush();
|
||||
} catch (Exception e) {
|
||||
reportError(null, e, ErrorManager.FLUSH_FAILURE);
|
||||
} finally {
|
||||
writerLock.readLock().unlock();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Configure from <code>LogManager</code> properties.
|
||||
*/
|
||||
private void configure() {
|
||||
|
||||
Timestamp ts = new Timestamp(System.currentTimeMillis());
|
||||
String tsString = ts.toString().substring(0, 19);
|
||||
date = tsString.substring(0, 10);
|
||||
|
||||
String className = this.getClass().getName(); //allow classes to override
|
||||
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
|
||||
// Retrieve configuration of logging file name
|
||||
rotatable = Boolean.parseBoolean(getProperty(className + ".rotatable", "true"));
|
||||
if (directory == null)
|
||||
directory = getProperty(className + ".directory", "logs");
|
||||
if (prefix == null)
|
||||
prefix = getProperty(className + ".prefix", "openesb.");
|
||||
if (suffix == null)
|
||||
suffix = getProperty(className + ".suffix", ".log");
|
||||
String sBufferSize = getProperty(className + ".bufferSize", String.valueOf(bufferSize));
|
||||
try {
|
||||
bufferSize = Integer.parseInt(sBufferSize);
|
||||
} catch (NumberFormatException ignore) {
|
||||
//no op
|
||||
}
|
||||
// Get encoding for the logging file
|
||||
String encoding = getProperty(className + ".encoding", null);
|
||||
if (encoding != null && encoding.length() > 0) {
|
||||
try {
|
||||
setEncoding(encoding);
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
// Get logging level for the handler
|
||||
setLevel(Level.parse(getProperty(className + ".level", "" + Level.ALL)));
|
||||
|
||||
// Get filter configuration
|
||||
String filterName = getProperty(className + ".filter", null);
|
||||
if (filterName != null) {
|
||||
try {
|
||||
setFilter((Filter) cl.loadClass(filterName).newInstance());
|
||||
} catch (Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
// Set formatter
|
||||
String formatterName = getProperty(className + ".formatter", null);
|
||||
if (formatterName != null) {
|
||||
try {
|
||||
setFormatter((Formatter) cl.loadClass(formatterName).newInstance());
|
||||
} catch (Exception e) {
|
||||
// Ignore and fallback to defaults
|
||||
setFormatter(new SimpleFormatter());
|
||||
}
|
||||
} else {
|
||||
setFormatter(new SimpleFormatter());
|
||||
}
|
||||
|
||||
// Set error manager
|
||||
setErrorManager(new ErrorManager());
|
||||
|
||||
}
|
||||
|
||||
|
||||
private String getProperty(String name, String defaultValue) {
|
||||
String value = LogManager.getLogManager().getProperty(name);
|
||||
if (value == null) {
|
||||
value = defaultValue;
|
||||
} else {
|
||||
value = value.trim();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Open the new log file for the date specified by <code>date</code>.
|
||||
*/
|
||||
protected void open() {
|
||||
openWriter();
|
||||
}
|
||||
|
||||
protected void openWriter() {
|
||||
|
||||
// Create the directory if necessary
|
||||
File dir = new File(directory);
|
||||
if (!dir.mkdirs() && !dir.isDirectory()) {
|
||||
reportError("Unable to create [" + dir + "]", null,
|
||||
ErrorManager.OPEN_FAILURE);
|
||||
writer = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// Open the current log file
|
||||
writerLock.writeLock().lock();
|
||||
FileOutputStream fos = null;
|
||||
OutputStream os = null;
|
||||
try {
|
||||
File pathname = new File(dir.getAbsoluteFile(), prefix
|
||||
+ (rotatable ? date : "") + suffix);
|
||||
File parent = pathname.getParentFile();
|
||||
if (!parent.mkdirs() && !parent.isDirectory()) {
|
||||
reportError("Unable to create [" + parent + "]", null,
|
||||
ErrorManager.OPEN_FAILURE);
|
||||
writer = null;
|
||||
return;
|
||||
}
|
||||
String encoding = getEncoding();
|
||||
fos = new FileOutputStream(pathname, true);
|
||||
os = bufferSize>0?new BufferedOutputStream(fos,bufferSize):fos;
|
||||
writer = new PrintWriter(
|
||||
(encoding != null) ? new OutputStreamWriter(os, encoding)
|
||||
: new OutputStreamWriter(os), false);
|
||||
writer.write(getFormatter().getHead(this));
|
||||
} catch (Exception e) {
|
||||
reportError(null, e, ErrorManager.OPEN_FAILURE);
|
||||
writer = null;
|
||||
if (fos != null) {
|
||||
try {
|
||||
fos.close();
|
||||
} catch (IOException e1) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
if (os != null) {
|
||||
try {
|
||||
os.close();
|
||||
} catch (IOException e1) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
writerLock.writeLock().unlock();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package net.openesb.standalone.logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author David BRASSELY (brasseld at gmail.com)
|
||||
* @author OpenESB Community
|
||||
*/
|
||||
public class OpenESBLogManager extends java.util.logging.LogManager {
|
||||
|
||||
@Override
|
||||
public String getProperty(String name) {
|
||||
String result = super.getProperty(name);
|
||||
|
||||
if (result != null) {
|
||||
result = replace(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* System property replacement in the given string.
|
||||
*
|
||||
* @param str The original string
|
||||
* @return the modified string
|
||||
*/
|
||||
protected String replace(String str) {
|
||||
String result = str;
|
||||
int pos_start = str.indexOf("${");
|
||||
if (pos_start >= 0) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
int pos_end = -1;
|
||||
while (pos_start >= 0) {
|
||||
builder.append(str, pos_end + 1, pos_start);
|
||||
pos_end = str.indexOf('}', pos_start + 2);
|
||||
if (pos_end < 0) {
|
||||
pos_end = pos_start - 1;
|
||||
break;
|
||||
}
|
||||
String propName = str.substring(pos_start + 2, pos_end);
|
||||
String replacement = propName.length() > 0 ? System
|
||||
.getProperty(propName) : null;
|
||||
if (replacement != null) {
|
||||
builder.append(replacement);
|
||||
} else {
|
||||
builder.append(str, pos_start, pos_end + 1);
|
||||
}
|
||||
pos_start = str.indexOf("${", pos_end + 1);
|
||||
}
|
||||
builder.append(str, pos_end + 1, str.length());
|
||||
result = builder.toString();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -63,7 +63,7 @@ echo OPENESB_HOME is set with the value: %OPENESB_HOME%
|
|||
cd %OPENESB_HOME%
|
||||
|
||||
:: Start OpenESB in a new Dos window
|
||||
START /MIN "OpenESB SE" %JAVA_HOME%\bin\java -Djava.util.logging.config.file=%OPENESB_HOME%/config/logger.properties -Djavax.net.ssl.keyStore=%OPENESB_HOME%/keystore.jks -Djavax.net.ssl.trustStore=%OPENESB_HOME%/cacerts.jks -Djavax.net.ssl.keyStorePassword=changeit -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=9009,suspend=n -Djmx.invoke.getters=true -Dinstall.root=%OPENESB_HOME% -jar %OPENESB_HOME%\lib\openesb-standalone-bootstrap.jar
|
||||
START /MIN "OpenESB SE" %JAVA_HOME%\bin\java -Djava.util.logging.config.file=%OPENESB_HOME%/config/logger.properties -Djava.util.logging.manager=net.openesb.standalone.logger.OpenESBLogManager -Djavax.net.ssl.keyStore=%OPENESB_HOME%/keystore.jks -Djavax.net.ssl.trustStore=%OPENESB_HOME%/cacerts.jks -Djavax.net.ssl.keyStorePassword=changeit -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=9009,suspend=n -Djmx.invoke.getters=true -Dinstall.root=%OPENESB_HOME% -jar %OPENESB_HOME%\lib\openesb-standalone-bootstrap.jar
|
||||
|
||||
echo.
|
||||
echo.
|
||||
|
|
|
@ -77,6 +77,7 @@ echo ""
|
|||
# Execute the JVM in the foreground
|
||||
"$JAVA" $JAVA_OPTS \
|
||||
-Djava.util.logging.config.file=$OPENESB_HOME/config/logger.properties \
|
||||
-Djava.util.logging.manager=net.openesb.standalone.logger.OpenESBLogManager \
|
||||
-Djmx.invoke.getters=true \
|
||||
-Dinstall.root=$OPENESB_HOME \
|
||||
-jar "$OPENESB_BOOT_CLASSPATH" \
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
# The set of handlers to be loaded upon startup.
|
||||
# Comma-separated list of class names.
|
||||
# (? LogManager docs say no comma here, but JDK example has comma.)
|
||||
handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler
|
||||
handlers=net.openesb.standalone.logger.FileHandler, java.util.logging.ConsoleHandler
|
||||
|
||||
# Default global logging level.
|
||||
# Loggers and Handlers may override this level
|
||||
|
@ -27,25 +27,28 @@ handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler
|
|||
|
||||
# --- ConsoleHandler ---
|
||||
# Override of global logging level
|
||||
java.util.logging.ConsoleHandler.level=INFO
|
||||
java.util.logging.ConsoleHandler.level=FINEST
|
||||
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
|
||||
|
||||
# --- FileHandler ---
|
||||
# Override of global logging level
|
||||
java.util.logging.FileHandler.level=INFO
|
||||
net.openesb.standalone.logger.FileHandler.level=INFO
|
||||
|
||||
# Naming style for the output file:
|
||||
java.util.logging.FileHandler.pattern=logs/openesb%u.log
|
||||
net.openesb.standalone.logger.FileHandler.directory=${install.root}/logs
|
||||
|
||||
# Encoding
|
||||
net.openesb.standalone.logger.FileHandler.encoding=UTF-8
|
||||
|
||||
# Limiting size of output file in bytes:
|
||||
java.util.logging.FileHandler.limit=50000
|
||||
net.openesb.standalone.logger.FileHandler.limit=50000
|
||||
|
||||
# Number of output files to cycle through, by appending an
|
||||
# integer to the base file name:
|
||||
java.util.logging.FileHandler.count=1
|
||||
net.openesb.standalone.logger.FileHandler.count=5
|
||||
|
||||
# Style of output (Simple or XML):
|
||||
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
|
||||
net.openesb.standalone.logger.FileHandler.formatter=java.util.logging.SimpleFormatter
|
||||
|
||||
# Loggers
|
||||
# ------------------------------------------
|
||||
|
|
Loading…
Reference in New Issue