/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.juli;
/** * 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>org.apache.juli.OneLineFormatter</code></li> * <li><code>maxDays</code> - The maximum number of days to keep the log files. If the specified value is * <code><=0</code> then the log files will be kept on the file system forever, otherwise they will be kept the * specified maximum days. Default value: <code>-1</code>.</li> * </ul>
*/ publicclass FileHandler extends Handler {
/** * Represents a file name pattern of type {prefix}{date}{suffix}. The date is YYYY-MM-DD
*/ private Pattern pattern;
// --------------------------------------------------------- Public Methods
/** * Format and publish a <code>LogRecord</code>. * * @param record description of the log event
*/
@Override publicvoid publish(LogRecord record) {
if (!isLoggable(record)) { return;
}
final String tsDate; if (rotatable.booleanValue()) { // Construct the timestamp we will use
Timestamp ts = new Timestamp(System.currentTimeMillis());
tsDate = ts.toString().substring(0, 10);
} else {
tsDate = "";
}
writerLock.readLock().lock(); try { // If the date has changed, switch log files if (!tsDate.equals(date)) { // Upgrade to writeLock before we switch
writerLock.readLock().unlock();
writerLock.writeLock().lock(); try { // Make sure another thread hasn't already done this if (!tsDate.equals(date)) {
closeWriter();
date = tsDate;
openWriter();
clean();
}
} finally { // Downgrade to read-lock. This ensures the writer remains valid // until the log message is written
writerLock.readLock().lock();
writerLock.writeLock().unlock();
}
}
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.intValue() < 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);
}
} finally {
writerLock.readLock().unlock();
}
}
// Retrieve configuration of logging file name if (rotatable == null) {
rotatable = Boolean.valueOf(getProperty(className + ".rotatable", "true"));
} if (directory == null) {
directory = getProperty(className + ".directory", "logs");
} if (prefix == null) {
prefix = getProperty(className + ".prefix", "juli.");
} if (suffix == null) {
suffix = getProperty(className + ".suffix", ".log");
}
// https://bz.apache.org/bugzilla/show_bug.cgi?id=61232 boolean shouldCheckForRedundantSeparator = !rotatable.booleanValue() && !prefix.isEmpty() && !suffix.isEmpty(); // assuming separator is just one char, if there are use cases with // more, the notion of separator might be introduced if (shouldCheckForRedundantSeparator && (prefix.charAt(prefix.length() - 1) == suffix.charAt(0))) {
suffix = suffix.substring(1);
}
// Set formatter
String formatterName = getProperty(className + ".formatter", null); if (formatterName != null) { try {
setFormatter((Formatter) cl.loadClass(formatterName).getConstructor().newInstance());
} catch (Exception e) { // Ignore and fallback to defaults
setFormatter(new OneLineFormatter());
}
} else {
setFormatter(new OneLineFormatter());
}
// 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>.
*/ publicvoid open() {
openWriter();
}
protectedvoid 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.booleanValue() ? 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.intValue() > 0 ? new BufferedOutputStream(fos, bufferSize.intValue()) : 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();
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.