Log4J source files uit trunk gehaald en vervangen door jar.
This commit is contained in:
BIN
java/lib/log4j-1.2.16.jar
Normal file
BIN
java/lib/log4j-1.2.16.jar
Normal file
Binary file not shown.
@@ -1,142 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j;
|
|
||||||
|
|
||||||
import org.apache.log4j.spi.Filter;
|
|
||||||
import org.apache.log4j.spi.ErrorHandler;
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Implement this interface for your own strategies for outputting log
|
|
||||||
statements.
|
|
||||||
|
|
||||||
@author Ceki Gülcü
|
|
||||||
*/
|
|
||||||
public interface Appender {
|
|
||||||
|
|
||||||
/**
|
|
||||||
Add a filter to the end of the filter list.
|
|
||||||
|
|
||||||
@since 0.9.0
|
|
||||||
*/
|
|
||||||
void addFilter(Filter newFilter);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the head Filter. The Filters are organized in a linked list
|
|
||||||
and so all Filters on this Appender are available through the result.
|
|
||||||
|
|
||||||
@return the head Filter or null, if no Filters are present
|
|
||||||
@since 1.1
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
Filter getFilter();
|
|
||||||
|
|
||||||
/**
|
|
||||||
Clear the list of filters by removing all the filters in it.
|
|
||||||
|
|
||||||
@since 0.9.0
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void clearFilters();
|
|
||||||
|
|
||||||
/**
|
|
||||||
Release any resources allocated within the appender such as file
|
|
||||||
handles, network connections, etc.
|
|
||||||
|
|
||||||
<p>It is a programming error to append to a closed appender.
|
|
||||||
|
|
||||||
@since 0.8.4
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void close();
|
|
||||||
|
|
||||||
/**
|
|
||||||
Log in <code>Appender</code> specific way. When appropriate,
|
|
||||||
Loggers will call the <code>doAppend</code> method of appender
|
|
||||||
implementations in order to log. */
|
|
||||||
public
|
|
||||||
void doAppend(LoggingEvent event);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get the name of this appender.
|
|
||||||
@return name, may be null.*/
|
|
||||||
public
|
|
||||||
String getName();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set the {@link ErrorHandler} for this appender.
|
|
||||||
|
|
||||||
@since 0.9.0
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setErrorHandler(ErrorHandler errorHandler);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the {@link ErrorHandler} for this appender.
|
|
||||||
|
|
||||||
@since 1.1
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
ErrorHandler getErrorHandler();
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set the {@link Layout} for this appender.
|
|
||||||
|
|
||||||
@since 0.8.1
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setLayout(Layout layout);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns this appenders layout.
|
|
||||||
|
|
||||||
@since 1.1
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
Layout getLayout();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set the name of this appender. The name is used by other
|
|
||||||
components to identify this appender.
|
|
||||||
|
|
||||||
@since 0.8.1
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setName(String name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Configurators call this method to determine if the appender
|
|
||||||
requires a layout. If this method returns <code>true</code>,
|
|
||||||
meaning that layout is required, then the configurator will
|
|
||||||
configure an layout using the configuration information at its
|
|
||||||
disposal. If this method returns <code>false</code>, meaning that
|
|
||||||
a layout is not required, then layout configuration will be
|
|
||||||
skipped even if there is available layout configuration
|
|
||||||
information at the disposal of the configurator..
|
|
||||||
|
|
||||||
<p>In the rather exceptional case, where the appender
|
|
||||||
implementation admits a layout but can also work without it, then
|
|
||||||
the appender should return <code>true</code>.
|
|
||||||
|
|
||||||
@since 0.8.4 */
|
|
||||||
public
|
|
||||||
boolean requiresLayout();
|
|
||||||
}
|
|
||||||
@@ -1,304 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j;
|
|
||||||
|
|
||||||
import org.apache.log4j.spi.Filter;
|
|
||||||
import org.apache.log4j.spi.ErrorHandler;
|
|
||||||
import org.apache.log4j.spi.OptionHandler;
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
import org.apache.log4j.helpers.OnlyOnceErrorHandler;
|
|
||||||
import org.apache.log4j.helpers.LogLog;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract superclass of the other appenders in the package.
|
|
||||||
*
|
|
||||||
* This class provides the code for common functionality, such as
|
|
||||||
* support for threshold filtering and support for general filters.
|
|
||||||
*
|
|
||||||
* @since 0.8.1
|
|
||||||
* @author Ceki Gülcü
|
|
||||||
* */
|
|
||||||
public abstract class AppenderSkeleton implements Appender, OptionHandler {
|
|
||||||
|
|
||||||
/** The layout variable does not need to be set if the appender
|
|
||||||
implementation has its own layout. */
|
|
||||||
protected Layout layout;
|
|
||||||
|
|
||||||
/** Appenders are named. */
|
|
||||||
protected String name;
|
|
||||||
|
|
||||||
/**
|
|
||||||
There is no level threshold filtering by default. */
|
|
||||||
protected Priority threshold;
|
|
||||||
|
|
||||||
/**
|
|
||||||
It is assumed and enforced that errorHandler is never null.
|
|
||||||
*/
|
|
||||||
protected ErrorHandler errorHandler = new OnlyOnceErrorHandler();
|
|
||||||
|
|
||||||
/** The first filter in the filter chain. Set to <code>null</code>
|
|
||||||
initially. */
|
|
||||||
protected Filter headFilter;
|
|
||||||
/** The last filter in the filter chain. */
|
|
||||||
protected Filter tailFilter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Is this appender closed?
|
|
||||||
*/
|
|
||||||
protected boolean closed = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create new instance.
|
|
||||||
*/
|
|
||||||
public AppenderSkeleton() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create new instance.
|
|
||||||
* Provided for compatibility with log4j 1.3.
|
|
||||||
*
|
|
||||||
* @param isActive true if appender is ready for use upon construction.
|
|
||||||
* Not used in log4j 1.2.x.
|
|
||||||
* @since 1.2.15
|
|
||||||
*/
|
|
||||||
protected AppenderSkeleton(final boolean isActive) {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Derived appenders should override this method if option structure
|
|
||||||
requires it. */
|
|
||||||
public
|
|
||||||
void activateOptions() {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Add a filter to end of the filter list.
|
|
||||||
|
|
||||||
@since 0.9.0
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void addFilter(Filter newFilter) {
|
|
||||||
if(headFilter == null) {
|
|
||||||
headFilter = tailFilter = newFilter;
|
|
||||||
} else {
|
|
||||||
tailFilter.setNext(newFilter);
|
|
||||||
tailFilter = newFilter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Subclasses of <code>AppenderSkeleton</code> should implement this
|
|
||||||
method to perform actual logging. See also {@link #doAppend
|
|
||||||
AppenderSkeleton.doAppend} method.
|
|
||||||
|
|
||||||
@since 0.9.0
|
|
||||||
*/
|
|
||||||
abstract
|
|
||||||
protected
|
|
||||||
void append(LoggingEvent event);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Clear the filters chain.
|
|
||||||
|
|
||||||
@since 0.9.0 */
|
|
||||||
public
|
|
||||||
void clearFilters() {
|
|
||||||
headFilter = tailFilter = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Finalize this appender by calling the derived class'
|
|
||||||
<code>close</code> method.
|
|
||||||
|
|
||||||
@since 0.8.4 */
|
|
||||||
public
|
|
||||||
void finalize() {
|
|
||||||
// An appender might be closed then garbage collected. There is no
|
|
||||||
// point in closing twice.
|
|
||||||
if(this.closed)
|
|
||||||
return;
|
|
||||||
|
|
||||||
LogLog.debug("Finalizing appender named ["+name+"].");
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Return the currently set {@link ErrorHandler} for this
|
|
||||||
Appender.
|
|
||||||
|
|
||||||
@since 0.9.0 */
|
|
||||||
public
|
|
||||||
ErrorHandler getErrorHandler() {
|
|
||||||
return this.errorHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the head Filter.
|
|
||||||
|
|
||||||
@since 1.1
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
Filter getFilter() {
|
|
||||||
return headFilter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Return the first filter in the filter chain for this
|
|
||||||
Appender. The return value may be <code>null</code> if no is
|
|
||||||
filter is set.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
final
|
|
||||||
Filter getFirstFilter() {
|
|
||||||
return headFilter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the layout of this appender. The value may be null.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
Layout getLayout() {
|
|
||||||
return layout;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the name of this appender.
|
|
||||||
@return name, may be null.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
final
|
|
||||||
String getName() {
|
|
||||||
return this.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns this appenders threshold level. See the {@link
|
|
||||||
#setThreshold} method for the meaning of this option.
|
|
||||||
|
|
||||||
@since 1.1 */
|
|
||||||
public
|
|
||||||
Priority getThreshold() {
|
|
||||||
return threshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Check whether the message level is below the appender's
|
|
||||||
threshold. If there is no threshold set, then the return value is
|
|
||||||
always <code>true</code>.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
boolean isAsSevereAsThreshold(Priority priority) {
|
|
||||||
return ((threshold == null) || priority.isGreaterOrEqual(threshold));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method performs threshold checks and invokes filters before
|
|
||||||
* delegating actual logging to the subclasses specific {@link
|
|
||||||
* AppenderSkeleton#append} method.
|
|
||||||
* */
|
|
||||||
public
|
|
||||||
synchronized
|
|
||||||
void doAppend(LoggingEvent event) {
|
|
||||||
if(closed) {
|
|
||||||
LogLog.error("Attempted to append to closed appender named ["+name+"].");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!isAsSevereAsThreshold(event.getLevel())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Filter f = this.headFilter;
|
|
||||||
|
|
||||||
FILTER_LOOP:
|
|
||||||
while(f != null) {
|
|
||||||
switch(f.decide(event)) {
|
|
||||||
case Filter.DENY: return;
|
|
||||||
case Filter.ACCEPT: break FILTER_LOOP;
|
|
||||||
case Filter.NEUTRAL: f = f.getNext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.append(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set the {@link ErrorHandler} for this Appender.
|
|
||||||
@since 0.9.0
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
synchronized
|
|
||||||
void setErrorHandler(ErrorHandler eh) {
|
|
||||||
if(eh == null) {
|
|
||||||
// We do not throw exception here since the cause is probably a
|
|
||||||
// bad config file.
|
|
||||||
LogLog.warn("You have tried to set a null error-handler.");
|
|
||||||
} else {
|
|
||||||
this.errorHandler = eh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set the layout for this appender. Note that some appenders have
|
|
||||||
their own (fixed) layouts or do not use one. For example, the
|
|
||||||
{@link org.apache.log4j.net.SocketAppender} ignores the layout set
|
|
||||||
here.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setLayout(Layout layout) {
|
|
||||||
this.layout = layout;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set the name of this Appender.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set the threshold level. All log events with lower level
|
|
||||||
than the threshold level are ignored by the appender.
|
|
||||||
|
|
||||||
<p>In configuration files this option is specified by setting the
|
|
||||||
value of the <b>Threshold</b> option to a level
|
|
||||||
string, such as "DEBUG", "INFO" and so on.
|
|
||||||
|
|
||||||
@since 0.8.3 */
|
|
||||||
public
|
|
||||||
void setThreshold(Priority threshold) {
|
|
||||||
this.threshold = threshold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,596 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Contibutors: Aaron Greenhouse <aarong@cs.cmu.edu>
|
|
||||||
// Thomas Tuft Muller <ttm@online.no>
|
|
||||||
package org.apache.log4j;
|
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.apache.log4j.helpers.AppenderAttachableImpl;
|
|
||||||
import org.apache.log4j.spi.AppenderAttachable;
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The AsyncAppender lets users log events asynchronously.
|
|
||||||
* <p/>
|
|
||||||
* <p/>
|
|
||||||
* The AsyncAppender will collect the events sent to it and then dispatch them
|
|
||||||
* to all the appenders that are attached to it. You can attach multiple
|
|
||||||
* appenders to an AsyncAppender.
|
|
||||||
* </p>
|
|
||||||
* <p/>
|
|
||||||
* <p/>
|
|
||||||
* The AsyncAppender uses a separate thread to serve the events in its buffer.
|
|
||||||
* </p>
|
|
||||||
* <p/>
|
|
||||||
* <b>Important note:</b> The <code>AsyncAppender</code> can only be script
|
|
||||||
* configured using the {@link org.apache.log4j.xml.DOMConfigurator}.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @author Ceki Gülcü
|
|
||||||
* @author Curt Arnold
|
|
||||||
* @since 0.9.1
|
|
||||||
*/
|
|
||||||
public class AsyncAppender extends AppenderSkeleton
|
|
||||||
implements AppenderAttachable {
|
|
||||||
/**
|
|
||||||
* The default buffer size is set to 128 events.
|
|
||||||
*/
|
|
||||||
public static final int DEFAULT_BUFFER_SIZE = 128;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event buffer, also used as monitor to protect itself and
|
|
||||||
* discardMap from simulatenous modifications.
|
|
||||||
*/
|
|
||||||
private final List buffer = new ArrayList();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Map of DiscardSummary objects keyed by logger name.
|
|
||||||
*/
|
|
||||||
private final Map discardMap = new HashMap();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Buffer size.
|
|
||||||
*/
|
|
||||||
private int bufferSize = DEFAULT_BUFFER_SIZE;
|
|
||||||
|
|
||||||
/** Nested appenders. */
|
|
||||||
AppenderAttachableImpl aai;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Nested appenders.
|
|
||||||
*/
|
|
||||||
private final AppenderAttachableImpl appenders;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dispatcher.
|
|
||||||
*/
|
|
||||||
private final Thread dispatcher;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Should location info be included in dispatched messages.
|
|
||||||
*/
|
|
||||||
private boolean locationInfo = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does appender block when buffer is full.
|
|
||||||
*/
|
|
||||||
private boolean blocking = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create new instance.
|
|
||||||
*/
|
|
||||||
public AsyncAppender() {
|
|
||||||
appenders = new AppenderAttachableImpl();
|
|
||||||
|
|
||||||
//
|
|
||||||
// only set for compatibility
|
|
||||||
aai = appenders;
|
|
||||||
|
|
||||||
dispatcher =
|
|
||||||
new Thread(new Dispatcher(this, buffer, discardMap, appenders));
|
|
||||||
|
|
||||||
// It is the user's responsibility to close appenders before
|
|
||||||
// exiting.
|
|
||||||
dispatcher.setDaemon(true);
|
|
||||||
|
|
||||||
// set the dispatcher priority to lowest possible value
|
|
||||||
// dispatcher.setPriority(Thread.MIN_PRIORITY);
|
|
||||||
dispatcher.setName("AsyncAppender-Dispatcher-" + dispatcher.getName());
|
|
||||||
dispatcher.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add appender.
|
|
||||||
*
|
|
||||||
* @param newAppender appender to add, may not be null.
|
|
||||||
*/
|
|
||||||
public void addAppender(final Appender newAppender) {
|
|
||||||
synchronized (appenders) {
|
|
||||||
appenders.addAppender(newAppender);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public void append(final LoggingEvent event) {
|
|
||||||
//
|
|
||||||
// if dispatcher thread has died then
|
|
||||||
// append subsequent events synchronously
|
|
||||||
// See bug 23021
|
|
||||||
if ((dispatcher == null) || !dispatcher.isAlive() || (bufferSize <= 0)) {
|
|
||||||
synchronized (appenders) {
|
|
||||||
appenders.appendLoopOnAppenders(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the NDC and thread name for the calling thread as these
|
|
||||||
// LoggingEvent fields were not set at event creation time.
|
|
||||||
event.getNDC();
|
|
||||||
event.getThreadName();
|
|
||||||
// Get a copy of this thread's MDC.
|
|
||||||
event.getMDCCopy();
|
|
||||||
if (locationInfo) {
|
|
||||||
event.getLocationInformation();
|
|
||||||
}
|
|
||||||
event.getRenderedMessage();
|
|
||||||
event.getThrowableStrRep();
|
|
||||||
|
|
||||||
synchronized (buffer) {
|
|
||||||
while (true) {
|
|
||||||
int previousSize = buffer.size();
|
|
||||||
|
|
||||||
if (previousSize < bufferSize) {
|
|
||||||
buffer.add(event);
|
|
||||||
|
|
||||||
//
|
|
||||||
// if buffer had been empty
|
|
||||||
// signal all threads waiting on buffer
|
|
||||||
// to check their conditions.
|
|
||||||
//
|
|
||||||
if (previousSize == 0) {
|
|
||||||
buffer.notifyAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Following code is only reachable if buffer is full
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// if blocking and thread is not already interrupted
|
|
||||||
// and not the dispatcher then
|
|
||||||
// wait for a buffer notification
|
|
||||||
boolean discard = true;
|
|
||||||
if (blocking
|
|
||||||
&& !Thread.interrupted()
|
|
||||||
&& Thread.currentThread() != dispatcher) {
|
|
||||||
try {
|
|
||||||
buffer.wait();
|
|
||||||
discard = false;
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
//
|
|
||||||
// reset interrupt status so
|
|
||||||
// calling code can see interrupt on
|
|
||||||
// their next wait or sleep.
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// if blocking is false or thread has been interrupted
|
|
||||||
// add event to discard map.
|
|
||||||
//
|
|
||||||
if (discard) {
|
|
||||||
String loggerName = event.getLoggerName();
|
|
||||||
DiscardSummary summary = (DiscardSummary) discardMap.get(loggerName);
|
|
||||||
|
|
||||||
if (summary == null) {
|
|
||||||
summary = new DiscardSummary(event);
|
|
||||||
discardMap.put(loggerName, summary);
|
|
||||||
} else {
|
|
||||||
summary.add(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close this <code>AsyncAppender</code> by interrupting the dispatcher
|
|
||||||
* thread which will process all pending events before exiting.
|
|
||||||
*/
|
|
||||||
public void close() {
|
|
||||||
/**
|
|
||||||
* Set closed flag and notify all threads to check their conditions.
|
|
||||||
* Should result in dispatcher terminating.
|
|
||||||
*/
|
|
||||||
synchronized (buffer) {
|
|
||||||
closed = true;
|
|
||||||
buffer.notifyAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
dispatcher.join();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
org.apache.log4j.helpers.LogLog.error(
|
|
||||||
"Got an InterruptedException while waiting for the "
|
|
||||||
+ "dispatcher to finish.", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// close all attached appenders.
|
|
||||||
//
|
|
||||||
synchronized (appenders) {
|
|
||||||
Enumeration iter = appenders.getAllAppenders();
|
|
||||||
|
|
||||||
if (iter != null) {
|
|
||||||
while (iter.hasMoreElements()) {
|
|
||||||
Object next = iter.nextElement();
|
|
||||||
|
|
||||||
if (next instanceof Appender) {
|
|
||||||
((Appender) next).close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get iterator over attached appenders.
|
|
||||||
* @return iterator or null if no attached appenders.
|
|
||||||
*/
|
|
||||||
public Enumeration getAllAppenders() {
|
|
||||||
synchronized (appenders) {
|
|
||||||
return appenders.getAllAppenders();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get appender by name.
|
|
||||||
*
|
|
||||||
* @param name name, may not be null.
|
|
||||||
* @return matching appender or null.
|
|
||||||
*/
|
|
||||||
public Appender getAppender(final String name) {
|
|
||||||
synchronized (appenders) {
|
|
||||||
return appenders.getAppender(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets whether the location of the logging request call
|
|
||||||
* should be captured.
|
|
||||||
*
|
|
||||||
* @return the current value of the <b>LocationInfo</b> option.
|
|
||||||
*/
|
|
||||||
public boolean getLocationInfo() {
|
|
||||||
return locationInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines if specified appender is attached.
|
|
||||||
* @param appender appender.
|
|
||||||
* @return true if attached.
|
|
||||||
*/
|
|
||||||
public boolean isAttached(final Appender appender) {
|
|
||||||
synchronized (appenders) {
|
|
||||||
return appenders.isAttached(appender);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public boolean requiresLayout() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes and closes all attached appenders.
|
|
||||||
*/
|
|
||||||
public void removeAllAppenders() {
|
|
||||||
synchronized (appenders) {
|
|
||||||
appenders.removeAllAppenders();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes an appender.
|
|
||||||
* @param appender appender to remove.
|
|
||||||
*/
|
|
||||||
public void removeAppender(final Appender appender) {
|
|
||||||
synchronized (appenders) {
|
|
||||||
appenders.removeAppender(appender);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove appender by name.
|
|
||||||
* @param name name.
|
|
||||||
*/
|
|
||||||
public void removeAppender(final String name) {
|
|
||||||
synchronized (appenders) {
|
|
||||||
appenders.removeAppender(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The <b>LocationInfo</b> option takes a boolean value. By default, it is
|
|
||||||
* set to false which means there will be no effort to extract the location
|
|
||||||
* information related to the event. As a result, the event that will be
|
|
||||||
* ultimately logged will likely to contain the wrong location information
|
|
||||||
* (if present in the log format).
|
|
||||||
* <p/>
|
|
||||||
* <p/>
|
|
||||||
* Location information extraction is comparatively very slow and should be
|
|
||||||
* avoided unless performance is not a concern.
|
|
||||||
* </p>
|
|
||||||
* @param flag true if location information should be extracted.
|
|
||||||
*/
|
|
||||||
public void setLocationInfo(final boolean flag) {
|
|
||||||
locationInfo = flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the number of messages allowed in the event buffer
|
|
||||||
* before the calling thread is blocked (if blocking is true)
|
|
||||||
* or until messages are summarized and discarded. Changing
|
|
||||||
* the size will not affect messages already in the buffer.
|
|
||||||
*
|
|
||||||
* @param size buffer size, must be positive.
|
|
||||||
*/
|
|
||||||
public void setBufferSize(final int size) {
|
|
||||||
//
|
|
||||||
// log4j 1.2 would throw exception if size was negative
|
|
||||||
// and deadlock if size was zero.
|
|
||||||
//
|
|
||||||
if (size < 0) {
|
|
||||||
throw new java.lang.NegativeArraySizeException("size");
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized (buffer) {
|
|
||||||
//
|
|
||||||
// don't let size be zero.
|
|
||||||
//
|
|
||||||
bufferSize = (size < 1) ? 1 : size;
|
|
||||||
buffer.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the current buffer size.
|
|
||||||
* @return the current value of the <b>BufferSize</b> option.
|
|
||||||
*/
|
|
||||||
public int getBufferSize() {
|
|
||||||
return bufferSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets whether appender should wait if there is no
|
|
||||||
* space available in the event buffer or immediately return.
|
|
||||||
*
|
|
||||||
* @since 1.2.14
|
|
||||||
* @param value true if appender should wait until available space in buffer.
|
|
||||||
*/
|
|
||||||
public void setBlocking(final boolean value) {
|
|
||||||
synchronized (buffer) {
|
|
||||||
blocking = value;
|
|
||||||
buffer.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets whether appender should block calling thread when buffer is full.
|
|
||||||
* If false, messages will be counted by logger and a summary
|
|
||||||
* message appended after the contents of the buffer have been appended.
|
|
||||||
*
|
|
||||||
* @since 1.2.14
|
|
||||||
* @return true if calling thread will be blocked when buffer is full.
|
|
||||||
*/
|
|
||||||
public boolean getBlocking() {
|
|
||||||
return blocking;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Summary of discarded logging events for a logger.
|
|
||||||
*/
|
|
||||||
private static final class DiscardSummary {
|
|
||||||
/**
|
|
||||||
* First event of the highest severity.
|
|
||||||
*/
|
|
||||||
private LoggingEvent maxEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Total count of messages discarded.
|
|
||||||
*/
|
|
||||||
private int count;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create new instance.
|
|
||||||
*
|
|
||||||
* @param event event, may not be null.
|
|
||||||
*/
|
|
||||||
public DiscardSummary(final LoggingEvent event) {
|
|
||||||
maxEvent = event;
|
|
||||||
count = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add discarded event to summary.
|
|
||||||
*
|
|
||||||
* @param event event, may not be null.
|
|
||||||
*/
|
|
||||||
public void add(final LoggingEvent event) {
|
|
||||||
if (event.getLevel().toInt() > maxEvent.getLevel().toInt()) {
|
|
||||||
maxEvent = event;
|
|
||||||
}
|
|
||||||
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create event with summary information.
|
|
||||||
*
|
|
||||||
* @return new event.
|
|
||||||
*/
|
|
||||||
public LoggingEvent createEvent() {
|
|
||||||
String msg =
|
|
||||||
MessageFormat.format(
|
|
||||||
"Discarded {0} messages due to full event buffer including: {1}",
|
|
||||||
new Object[] { new Integer(count), maxEvent.getMessage() });
|
|
||||||
|
|
||||||
return new LoggingEvent(
|
|
||||||
"org.apache.log4j.AsyncAppender.DONT_REPORT_LOCATION",
|
|
||||||
Logger.getLogger(maxEvent.getLoggerName()),
|
|
||||||
maxEvent.getLevel(),
|
|
||||||
msg,
|
|
||||||
null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event dispatcher.
|
|
||||||
*/
|
|
||||||
private static class Dispatcher implements Runnable {
|
|
||||||
/**
|
|
||||||
* Parent AsyncAppender.
|
|
||||||
*/
|
|
||||||
private final AsyncAppender parent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event buffer.
|
|
||||||
*/
|
|
||||||
private final List buffer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Map of DiscardSummary keyed by logger name.
|
|
||||||
*/
|
|
||||||
private final Map discardMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapped appenders.
|
|
||||||
*/
|
|
||||||
private final AppenderAttachableImpl appenders;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create new instance of dispatcher.
|
|
||||||
*
|
|
||||||
* @param parent parent AsyncAppender, may not be null.
|
|
||||||
* @param buffer event buffer, may not be null.
|
|
||||||
* @param discardMap discard map, may not be null.
|
|
||||||
* @param appenders appenders, may not be null.
|
|
||||||
*/
|
|
||||||
public Dispatcher(
|
|
||||||
final AsyncAppender parent, final List buffer, final Map discardMap,
|
|
||||||
final AppenderAttachableImpl appenders) {
|
|
||||||
|
|
||||||
this.parent = parent;
|
|
||||||
this.buffer = buffer;
|
|
||||||
this.appenders = appenders;
|
|
||||||
this.discardMap = discardMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public void run() {
|
|
||||||
boolean isActive = true;
|
|
||||||
|
|
||||||
//
|
|
||||||
// if interrupted (unlikely), end thread
|
|
||||||
//
|
|
||||||
try {
|
|
||||||
//
|
|
||||||
// loop until the AsyncAppender is closed.
|
|
||||||
//
|
|
||||||
while (isActive) {
|
|
||||||
LoggingEvent[] events = null;
|
|
||||||
|
|
||||||
//
|
|
||||||
// extract pending events while synchronized
|
|
||||||
// on buffer
|
|
||||||
//
|
|
||||||
synchronized (buffer) {
|
|
||||||
int bufferSize = buffer.size();
|
|
||||||
isActive = !parent.closed;
|
|
||||||
|
|
||||||
while ((bufferSize == 0) && isActive) {
|
|
||||||
buffer.wait();
|
|
||||||
bufferSize = buffer.size();
|
|
||||||
isActive = !parent.closed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bufferSize > 0) {
|
|
||||||
events = new LoggingEvent[bufferSize + discardMap.size()];
|
|
||||||
buffer.toArray(events);
|
|
||||||
|
|
||||||
//
|
|
||||||
// add events due to buffer overflow
|
|
||||||
//
|
|
||||||
int index = bufferSize;
|
|
||||||
|
|
||||||
for (
|
|
||||||
Iterator iter = discardMap.values().iterator();
|
|
||||||
iter.hasNext();) {
|
|
||||||
events[index++] = ((DiscardSummary) iter.next()).createEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// clear buffer and discard map
|
|
||||||
//
|
|
||||||
buffer.clear();
|
|
||||||
discardMap.clear();
|
|
||||||
|
|
||||||
//
|
|
||||||
// allow blocked appends to continue
|
|
||||||
buffer.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// process events after lock on buffer is released.
|
|
||||||
//
|
|
||||||
if (events != null) {
|
|
||||||
for (int i = 0; i < events.length; i++) {
|
|
||||||
synchronized (appenders) {
|
|
||||||
appenders.appendLoopOnAppenders(events[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (InterruptedException ex) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Contibutors: "Luke Blanshard" <Luke@quiq.com>
|
|
||||||
// "Mark DONSZELMANN" <Mark.Donszelmann@cern.ch>
|
|
||||||
// "Muly Oved" <mulyoved@hotmail.com>
|
|
||||||
|
|
||||||
package org.apache.log4j;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Use this class to quickly configure the package.
|
|
||||||
|
|
||||||
<p>For file based configuration see {@link
|
|
||||||
PropertyConfigurator}. For XML based configuration see {@link
|
|
||||||
org.apache.log4j.xml.DOMConfigurator DOMConfigurator}.
|
|
||||||
|
|
||||||
@since 0.8.1
|
|
||||||
@author Ceki Gülcü */
|
|
||||||
public class BasicConfigurator {
|
|
||||||
|
|
||||||
protected BasicConfigurator() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Add a {@link ConsoleAppender} that uses {@link PatternLayout}
|
|
||||||
using the {@link PatternLayout#TTCC_CONVERSION_PATTERN} and
|
|
||||||
prints to <code>System.out</code> to the root category. */
|
|
||||||
static
|
|
||||||
public
|
|
||||||
void configure() {
|
|
||||||
Logger root = Logger.getRootLogger();
|
|
||||||
root.addAppender(new ConsoleAppender(
|
|
||||||
new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Add <code>appender</code> to the root category.
|
|
||||||
@param appender The appender to add to the root category.
|
|
||||||
*/
|
|
||||||
static
|
|
||||||
public
|
|
||||||
void configure(Appender appender) {
|
|
||||||
Logger root = Logger.getRootLogger();
|
|
||||||
root.addAppender(appender);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Reset the default hierarchy to its defaut. It is equivalent to
|
|
||||||
calling
|
|
||||||
<code>Category.getDefaultHierarchy().resetConfiguration()</code>.
|
|
||||||
|
|
||||||
See {@link Hierarchy#resetConfiguration()} for more details. */
|
|
||||||
public
|
|
||||||
static
|
|
||||||
void resetConfiguration() {
|
|
||||||
LogManager.resetConfiguration();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,52 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j;
|
|
||||||
|
|
||||||
/**
|
|
||||||
CategoryKey is a wrapper for String that apparently accellerated
|
|
||||||
hash table lookup in early JVM's.
|
|
||||||
@author Ceki Gülcü
|
|
||||||
*/
|
|
||||||
class CategoryKey {
|
|
||||||
|
|
||||||
String name;
|
|
||||||
int hashCache;
|
|
||||||
|
|
||||||
CategoryKey(String name) {
|
|
||||||
this.name = name;
|
|
||||||
hashCache = name.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
final
|
|
||||||
public
|
|
||||||
int hashCode() {
|
|
||||||
return hashCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
final
|
|
||||||
public
|
|
||||||
boolean equals(Object rArg) {
|
|
||||||
if(this == rArg)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if(rArg != null && CategoryKey.class == rArg.getClass())
|
|
||||||
return name.equals(((CategoryKey)rArg ).name);
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,220 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import org.apache.log4j.helpers.LogLog;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ConsoleAppender appends log events to <code>System.out</code> or
|
|
||||||
* <code>System.err</code> using a layout specified by the user. The
|
|
||||||
* default target is <code>System.out</code>.
|
|
||||||
*
|
|
||||||
* @author Ceki Gülcü
|
|
||||||
* @author Curt Arnold
|
|
||||||
* @since 1.1 */
|
|
||||||
public class ConsoleAppender extends WriterAppender {
|
|
||||||
|
|
||||||
public static final String SYSTEM_OUT = "System.out";
|
|
||||||
public static final String SYSTEM_ERR = "System.err";
|
|
||||||
|
|
||||||
protected String target = SYSTEM_OUT;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines if the appender honors reassignments of System.out
|
|
||||||
* or System.err made after configuration.
|
|
||||||
*/
|
|
||||||
private boolean follow = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs an unconfigured appender.
|
|
||||||
*/
|
|
||||||
public ConsoleAppender() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a configured appender.
|
|
||||||
*
|
|
||||||
* @param layout layout, may not be null.
|
|
||||||
*/
|
|
||||||
public ConsoleAppender(Layout layout) {
|
|
||||||
this(layout, SYSTEM_OUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a configured appender.
|
|
||||||
* @param layout layout, may not be null.
|
|
||||||
* @param target target, either "System.err" or "System.out".
|
|
||||||
*/
|
|
||||||
public ConsoleAppender(Layout layout, String target) {
|
|
||||||
setLayout(layout);
|
|
||||||
setTarget(target);
|
|
||||||
activateOptions();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the value of the <b>Target</b> option. Recognized values
|
|
||||||
* are "System.out" and "System.err". Any other value will be
|
|
||||||
* ignored.
|
|
||||||
* */
|
|
||||||
public
|
|
||||||
void setTarget(String value) {
|
|
||||||
String v = value.trim();
|
|
||||||
|
|
||||||
if (SYSTEM_OUT.equalsIgnoreCase(v)) {
|
|
||||||
target = SYSTEM_OUT;
|
|
||||||
} else if (SYSTEM_ERR.equalsIgnoreCase(v)) {
|
|
||||||
target = SYSTEM_ERR;
|
|
||||||
} else {
|
|
||||||
targetWarn(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current value of the <b>Target</b> property. The
|
|
||||||
* default value of the option is "System.out".
|
|
||||||
*
|
|
||||||
* See also {@link #setTarget}.
|
|
||||||
* */
|
|
||||||
public
|
|
||||||
String getTarget() {
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets whether the appender honors reassignments of System.out
|
|
||||||
* or System.err made after configuration.
|
|
||||||
* @param newValue if true, appender will use value of System.out or
|
|
||||||
* System.err in force at the time when logging events are appended.
|
|
||||||
* @since 1.2.13
|
|
||||||
*/
|
|
||||||
public final void setFollow(final boolean newValue) {
|
|
||||||
follow = newValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets whether the appender honors reassignments of System.out
|
|
||||||
* or System.err made after configuration.
|
|
||||||
* @return true if appender will use value of System.out or
|
|
||||||
* System.err in force at the time when logging events are appended.
|
|
||||||
* @since 1.2.13
|
|
||||||
*/
|
|
||||||
public final boolean getFollow() {
|
|
||||||
return follow;
|
|
||||||
}
|
|
||||||
|
|
||||||
void targetWarn(String val) {
|
|
||||||
LogLog.warn("["+val+"] should be System.out or System.err.");
|
|
||||||
LogLog.warn("Using previously set target, System.out by default.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepares the appender for use.
|
|
||||||
*/
|
|
||||||
public void activateOptions() {
|
|
||||||
if (follow) {
|
|
||||||
if (target.equals(SYSTEM_ERR)) {
|
|
||||||
setWriter(createWriter(new SystemErrStream()));
|
|
||||||
} else {
|
|
||||||
setWriter(createWriter(new SystemOutStream()));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (target.equals(SYSTEM_ERR)) {
|
|
||||||
setWriter(createWriter(System.err));
|
|
||||||
} else {
|
|
||||||
setWriter(createWriter(System.out));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.activateOptions();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
protected
|
|
||||||
final
|
|
||||||
void closeWriter() {
|
|
||||||
if (follow) {
|
|
||||||
super.closeWriter();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An implementation of OutputStream that redirects to the
|
|
||||||
* current System.err.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private static class SystemErrStream extends OutputStream {
|
|
||||||
public SystemErrStream() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void flush() {
|
|
||||||
System.err.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(final byte[] b) throws IOException {
|
|
||||||
System.err.write(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(final byte[] b, final int off, final int len)
|
|
||||||
throws IOException {
|
|
||||||
System.err.write(b, off, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(final int b) throws IOException {
|
|
||||||
System.err.write(b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An implementation of OutputStream that redirects to the
|
|
||||||
* current System.out.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private static class SystemOutStream extends OutputStream {
|
|
||||||
public SystemOutStream() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void flush() {
|
|
||||||
System.out.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(final byte[] b) throws IOException {
|
|
||||||
System.out.write(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(final byte[] b, final int off, final int len)
|
|
||||||
throws IOException {
|
|
||||||
System.out.write(b, off, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(final int b) throws IOException {
|
|
||||||
System.out.write(b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,454 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.InterruptedIOException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.GregorianCalendar;
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.TimeZone;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import org.apache.log4j.helpers.LogLog;
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
DailyRollingFileAppender extends {@link FileAppender} so that the
|
|
||||||
underlying file is rolled over at a user chosen frequency.
|
|
||||||
|
|
||||||
DailyRollingFileAppender has been observed to exhibit
|
|
||||||
synchronization issues and data loss. The log4j extras
|
|
||||||
companion includes alternatives which should be considered
|
|
||||||
for new deployments and which are discussed in the documentation
|
|
||||||
for org.apache.log4j.rolling.RollingFileAppender.
|
|
||||||
|
|
||||||
<p>The rolling schedule is specified by the <b>DatePattern</b>
|
|
||||||
option. This pattern should follow the {@link SimpleDateFormat}
|
|
||||||
conventions. In particular, you <em>must</em> escape literal text
|
|
||||||
within a pair of single quotes. A formatted version of the date
|
|
||||||
pattern is used as the suffix for the rolled file name.
|
|
||||||
|
|
||||||
<p>For example, if the <b>File</b> option is set to
|
|
||||||
<code>/foo/bar.log</code> and the <b>DatePattern</b> set to
|
|
||||||
<code>'.'yyyy-MM-dd</code>, on 2001-02-16 at midnight, the logging
|
|
||||||
file <code>/foo/bar.log</code> will be copied to
|
|
||||||
<code>/foo/bar.log.2001-02-16</code> and logging for 2001-02-17
|
|
||||||
will continue in <code>/foo/bar.log</code> until it rolls over
|
|
||||||
the next day.
|
|
||||||
|
|
||||||
<p>Is is possible to specify monthly, weekly, half-daily, daily,
|
|
||||||
hourly, or minutely rollover schedules.
|
|
||||||
|
|
||||||
<p><table border="1" cellpadding="2">
|
|
||||||
<tr>
|
|
||||||
<th>DatePattern</th>
|
|
||||||
<th>Rollover schedule</th>
|
|
||||||
<th>Example</th>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><code>'.'yyyy-MM</code>
|
|
||||||
<td>Rollover at the beginning of each month</td>
|
|
||||||
|
|
||||||
<td>At midnight of May 31st, 2002 <code>/foo/bar.log</code> will be
|
|
||||||
copied to <code>/foo/bar.log.2002-05</code>. Logging for the month
|
|
||||||
of June will be output to <code>/foo/bar.log</code> until it is
|
|
||||||
also rolled over the next month.
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><code>'.'yyyy-ww</code>
|
|
||||||
|
|
||||||
<td>Rollover at the first day of each week. The first day of the
|
|
||||||
week depends on the locale.</td>
|
|
||||||
|
|
||||||
<td>Assuming the first day of the week is Sunday, on Saturday
|
|
||||||
midnight, June 9th 2002, the file <i>/foo/bar.log</i> will be
|
|
||||||
copied to <i>/foo/bar.log.2002-23</i>. Logging for the 24th week
|
|
||||||
of 2002 will be output to <code>/foo/bar.log</code> until it is
|
|
||||||
rolled over the next week.
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><code>'.'yyyy-MM-dd</code>
|
|
||||||
|
|
||||||
<td>Rollover at midnight each day.</td>
|
|
||||||
|
|
||||||
<td>At midnight, on March 8th, 2002, <code>/foo/bar.log</code> will
|
|
||||||
be copied to <code>/foo/bar.log.2002-03-08</code>. Logging for the
|
|
||||||
9th day of March will be output to <code>/foo/bar.log</code> until
|
|
||||||
it is rolled over the next day.
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><code>'.'yyyy-MM-dd-a</code>
|
|
||||||
|
|
||||||
<td>Rollover at midnight and midday of each day.</td>
|
|
||||||
|
|
||||||
<td>At noon, on March 9th, 2002, <code>/foo/bar.log</code> will be
|
|
||||||
copied to <code>/foo/bar.log.2002-03-09-AM</code>. Logging for the
|
|
||||||
afternoon of the 9th will be output to <code>/foo/bar.log</code>
|
|
||||||
until it is rolled over at midnight.
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><code>'.'yyyy-MM-dd-HH</code>
|
|
||||||
|
|
||||||
<td>Rollover at the top of every hour.</td>
|
|
||||||
|
|
||||||
<td>At approximately 11:00.000 o'clock on March 9th, 2002,
|
|
||||||
<code>/foo/bar.log</code> will be copied to
|
|
||||||
<code>/foo/bar.log.2002-03-09-10</code>. Logging for the 11th hour
|
|
||||||
of the 9th of March will be output to <code>/foo/bar.log</code>
|
|
||||||
until it is rolled over at the beginning of the next hour.
|
|
||||||
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><code>'.'yyyy-MM-dd-HH-mm</code>
|
|
||||||
|
|
||||||
<td>Rollover at the beginning of every minute.</td>
|
|
||||||
|
|
||||||
<td>At approximately 11:23,000, on March 9th, 2001,
|
|
||||||
<code>/foo/bar.log</code> will be copied to
|
|
||||||
<code>/foo/bar.log.2001-03-09-10-22</code>. Logging for the minute
|
|
||||||
of 11:23 (9th of March) will be output to
|
|
||||||
<code>/foo/bar.log</code> until it is rolled over the next minute.
|
|
||||||
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p>Do not use the colon ":" character in anywhere in the
|
|
||||||
<b>DatePattern</b> option. The text before the colon is interpeted
|
|
||||||
as the protocol specificaion of a URL which is probably not what
|
|
||||||
you want.
|
|
||||||
|
|
||||||
|
|
||||||
@author Eirik Lygre
|
|
||||||
@author Ceki Gülcü*/
|
|
||||||
public class DailyRollingFileAppender extends FileAppender {
|
|
||||||
|
|
||||||
|
|
||||||
// The code assumes that the following constants are in a increasing
|
|
||||||
// sequence.
|
|
||||||
static final int TOP_OF_TROUBLE=-1;
|
|
||||||
static final int TOP_OF_MINUTE = 0;
|
|
||||||
static final int TOP_OF_HOUR = 1;
|
|
||||||
static final int HALF_DAY = 2;
|
|
||||||
static final int TOP_OF_DAY = 3;
|
|
||||||
static final int TOP_OF_WEEK = 4;
|
|
||||||
static final int TOP_OF_MONTH = 5;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
The date pattern. By default, the pattern is set to
|
|
||||||
"'.'yyyy-MM-dd" meaning daily rollover.
|
|
||||||
*/
|
|
||||||
private String datePattern = "'.'yyyy-MM-dd";
|
|
||||||
|
|
||||||
/**
|
|
||||||
The log file will be renamed to the value of the
|
|
||||||
scheduledFilename variable when the next interval is entered. For
|
|
||||||
example, if the rollover period is one hour, the log file will be
|
|
||||||
renamed to the value of "scheduledFilename" at the beginning of
|
|
||||||
the next hour.
|
|
||||||
|
|
||||||
The precise time when a rollover occurs depends on logging
|
|
||||||
activity.
|
|
||||||
*/
|
|
||||||
private String scheduledFilename;
|
|
||||||
|
|
||||||
/**
|
|
||||||
The next time we estimate a rollover should occur. */
|
|
||||||
private long nextCheck = System.currentTimeMillis () - 1;
|
|
||||||
|
|
||||||
Date now = new Date();
|
|
||||||
|
|
||||||
SimpleDateFormat sdf;
|
|
||||||
|
|
||||||
RollingCalendar rc = new RollingCalendar();
|
|
||||||
|
|
||||||
int checkPeriod = TOP_OF_TROUBLE;
|
|
||||||
|
|
||||||
// The gmtTimeZone is used only in computeCheckPeriod() method.
|
|
||||||
static final TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT");
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
The default constructor does nothing. */
|
|
||||||
public DailyRollingFileAppender() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Instantiate a <code>DailyRollingFileAppender</code> and open the
|
|
||||||
file designated by <code>filename</code>. The opened filename will
|
|
||||||
become the ouput destination for this appender.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public DailyRollingFileAppender (Layout layout, String filename,
|
|
||||||
String datePattern) throws IOException {
|
|
||||||
super(layout, filename, true);
|
|
||||||
this.datePattern = datePattern;
|
|
||||||
activateOptions();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
The <b>DatePattern</b> takes a string in the same format as
|
|
||||||
expected by {@link SimpleDateFormat}. This options determines the
|
|
||||||
rollover schedule.
|
|
||||||
*/
|
|
||||||
public void setDatePattern(String pattern) {
|
|
||||||
datePattern = pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the value of the <b>DatePattern</b> option. */
|
|
||||||
public String getDatePattern() {
|
|
||||||
return datePattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void activateOptions() {
|
|
||||||
super.activateOptions();
|
|
||||||
if(datePattern != null && fileName != null) {
|
|
||||||
now.setTime(System.currentTimeMillis());
|
|
||||||
sdf = new SimpleDateFormat(datePattern);
|
|
||||||
int type = computeCheckPeriod();
|
|
||||||
printPeriodicity(type);
|
|
||||||
rc.setType(type);
|
|
||||||
File file = new File(fileName);
|
|
||||||
scheduledFilename = fileName+sdf.format(new Date(file.lastModified()));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
LogLog.error("Either File or DatePattern options are not set for appender ["
|
|
||||||
+name+"].");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void printPeriodicity(int type) {
|
|
||||||
switch(type) {
|
|
||||||
case TOP_OF_MINUTE:
|
|
||||||
LogLog.debug("Appender ["+name+"] to be rolled every minute.");
|
|
||||||
break;
|
|
||||||
case TOP_OF_HOUR:
|
|
||||||
LogLog.debug("Appender ["+name
|
|
||||||
+"] to be rolled on top of every hour.");
|
|
||||||
break;
|
|
||||||
case HALF_DAY:
|
|
||||||
LogLog.debug("Appender ["+name
|
|
||||||
+"] to be rolled at midday and midnight.");
|
|
||||||
break;
|
|
||||||
case TOP_OF_DAY:
|
|
||||||
LogLog.debug("Appender ["+name
|
|
||||||
+"] to be rolled at midnight.");
|
|
||||||
break;
|
|
||||||
case TOP_OF_WEEK:
|
|
||||||
LogLog.debug("Appender ["+name
|
|
||||||
+"] to be rolled at start of week.");
|
|
||||||
break;
|
|
||||||
case TOP_OF_MONTH:
|
|
||||||
LogLog.debug("Appender ["+name
|
|
||||||
+"] to be rolled at start of every month.");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LogLog.warn("Unknown periodicity for appender ["+name+"].");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// This method computes the roll over period by looping over the
|
|
||||||
// periods, starting with the shortest, and stopping when the r0 is
|
|
||||||
// different from from r1, where r0 is the epoch formatted according
|
|
||||||
// the datePattern (supplied by the user) and r1 is the
|
|
||||||
// epoch+nextMillis(i) formatted according to datePattern. All date
|
|
||||||
// formatting is done in GMT and not local format because the test
|
|
||||||
// logic is based on comparisons relative to 1970-01-01 00:00:00
|
|
||||||
// GMT (the epoch).
|
|
||||||
|
|
||||||
int computeCheckPeriod() {
|
|
||||||
RollingCalendar rollingCalendar = new RollingCalendar(gmtTimeZone, Locale.getDefault());
|
|
||||||
// set sate to 1970-01-01 00:00:00 GMT
|
|
||||||
Date epoch = new Date(0);
|
|
||||||
if(datePattern != null) {
|
|
||||||
for(int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) {
|
|
||||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(datePattern);
|
|
||||||
simpleDateFormat.setTimeZone(gmtTimeZone); // do all date formatting in GMT
|
|
||||||
String r0 = simpleDateFormat.format(epoch);
|
|
||||||
rollingCalendar.setType(i);
|
|
||||||
Date next = new Date(rollingCalendar.getNextCheckMillis(epoch));
|
|
||||||
String r1 = simpleDateFormat.format(next);
|
|
||||||
//System.out.println("Type = "+i+", r0 = "+r0+", r1 = "+r1);
|
|
||||||
if(r0 != null && r1 != null && !r0.equals(r1)) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return TOP_OF_TROUBLE; // Deliberately head for trouble...
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Rollover the current file to a new file.
|
|
||||||
*/
|
|
||||||
void rollOver() throws IOException {
|
|
||||||
|
|
||||||
/* Compute filename, but only if datePattern is specified */
|
|
||||||
if (datePattern == null) {
|
|
||||||
errorHandler.error("Missing DatePattern option in rollOver().");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String datedFilename = fileName+sdf.format(now);
|
|
||||||
// It is too early to roll over because we are still within the
|
|
||||||
// bounds of the current interval. Rollover will occur once the
|
|
||||||
// next interval is reached.
|
|
||||||
if (scheduledFilename.equals(datedFilename)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// close current file, and rename it to datedFilename
|
|
||||||
this.closeFile();
|
|
||||||
|
|
||||||
File target = new File(scheduledFilename);
|
|
||||||
if (target.exists()) {
|
|
||||||
target.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
File file = new File(fileName);
|
|
||||||
boolean result = file.renameTo(target);
|
|
||||||
if(result) {
|
|
||||||
LogLog.debug(fileName +" -> "+ scheduledFilename);
|
|
||||||
} else {
|
|
||||||
LogLog.error("Failed to rename ["+fileName+"] to ["+scheduledFilename+"].");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// This will also close the file. This is OK since multiple
|
|
||||||
// close operations are safe.
|
|
||||||
this.setFile(fileName, true, this.bufferedIO, this.bufferSize);
|
|
||||||
}
|
|
||||||
catch(IOException e) {
|
|
||||||
errorHandler.error("setFile("+fileName+", true) call failed.");
|
|
||||||
}
|
|
||||||
scheduledFilename = datedFilename;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method differentiates DailyRollingFileAppender from its
|
|
||||||
* super class.
|
|
||||||
*
|
|
||||||
* <p>Before actually logging, this method will check whether it is
|
|
||||||
* time to do a rollover. If it is, it will schedule the next
|
|
||||||
* rollover time and then rollover.
|
|
||||||
* */
|
|
||||||
protected void subAppend(LoggingEvent event) {
|
|
||||||
long n = System.currentTimeMillis();
|
|
||||||
if (n >= nextCheck) {
|
|
||||||
now.setTime(n);
|
|
||||||
nextCheck = rc.getNextCheckMillis(now);
|
|
||||||
try {
|
|
||||||
rollOver();
|
|
||||||
}
|
|
||||||
catch(IOException ioe) {
|
|
||||||
if (ioe instanceof InterruptedIOException) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
LogLog.error("rollOver() failed.", ioe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.subAppend(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RollingCalendar is a helper class to DailyRollingFileAppender.
|
|
||||||
* Given a periodicity type and the current time, it computes the
|
|
||||||
* start of the next interval.
|
|
||||||
* */
|
|
||||||
class RollingCalendar extends GregorianCalendar {
|
|
||||||
private static final long serialVersionUID = -3560331770601814177L;
|
|
||||||
|
|
||||||
int type = DailyRollingFileAppender.TOP_OF_TROUBLE;
|
|
||||||
|
|
||||||
RollingCalendar() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
RollingCalendar(TimeZone tz, Locale locale) {
|
|
||||||
super(tz, locale);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setType(int type) {
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getNextCheckMillis(Date now) {
|
|
||||||
return getNextCheckDate(now).getTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Date getNextCheckDate(Date now) {
|
|
||||||
this.setTime(now);
|
|
||||||
|
|
||||||
switch(type) {
|
|
||||||
case DailyRollingFileAppender.TOP_OF_MINUTE:
|
|
||||||
this.set(Calendar.SECOND, 0);
|
|
||||||
this.set(Calendar.MILLISECOND, 0);
|
|
||||||
this.add(Calendar.MINUTE, 1);
|
|
||||||
break;
|
|
||||||
case DailyRollingFileAppender.TOP_OF_HOUR:
|
|
||||||
this.set(Calendar.MINUTE, 0);
|
|
||||||
this.set(Calendar.SECOND, 0);
|
|
||||||
this.set(Calendar.MILLISECOND, 0);
|
|
||||||
this.add(Calendar.HOUR_OF_DAY, 1);
|
|
||||||
break;
|
|
||||||
case DailyRollingFileAppender.HALF_DAY:
|
|
||||||
this.set(Calendar.MINUTE, 0);
|
|
||||||
this.set(Calendar.SECOND, 0);
|
|
||||||
this.set(Calendar.MILLISECOND, 0);
|
|
||||||
int hour = get(Calendar.HOUR_OF_DAY);
|
|
||||||
if(hour < 12) {
|
|
||||||
this.set(Calendar.HOUR_OF_DAY, 12);
|
|
||||||
} else {
|
|
||||||
this.set(Calendar.HOUR_OF_DAY, 0);
|
|
||||||
this.add(Calendar.DAY_OF_MONTH, 1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DailyRollingFileAppender.TOP_OF_DAY:
|
|
||||||
this.set(Calendar.HOUR_OF_DAY, 0);
|
|
||||||
this.set(Calendar.MINUTE, 0);
|
|
||||||
this.set(Calendar.SECOND, 0);
|
|
||||||
this.set(Calendar.MILLISECOND, 0);
|
|
||||||
this.add(Calendar.DATE, 1);
|
|
||||||
break;
|
|
||||||
case DailyRollingFileAppender.TOP_OF_WEEK:
|
|
||||||
this.set(Calendar.DAY_OF_WEEK, getFirstDayOfWeek());
|
|
||||||
this.set(Calendar.HOUR_OF_DAY, 0);
|
|
||||||
this.set(Calendar.MINUTE, 0);
|
|
||||||
this.set(Calendar.SECOND, 0);
|
|
||||||
this.set(Calendar.MILLISECOND, 0);
|
|
||||||
this.add(Calendar.WEEK_OF_YEAR, 1);
|
|
||||||
break;
|
|
||||||
case DailyRollingFileAppender.TOP_OF_MONTH:
|
|
||||||
this.set(Calendar.DATE, 1);
|
|
||||||
this.set(Calendar.HOUR_OF_DAY, 0);
|
|
||||||
this.set(Calendar.MINUTE, 0);
|
|
||||||
this.set(Calendar.SECOND, 0);
|
|
||||||
this.set(Calendar.MILLISECOND, 0);
|
|
||||||
this.add(Calendar.MONTH, 1);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException("Unknown periodicity type.");
|
|
||||||
}
|
|
||||||
return getTime();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j;
|
|
||||||
|
|
||||||
import org.apache.log4j.spi.LoggerFactory;
|
|
||||||
|
|
||||||
class DefaultCategoryFactory implements LoggerFactory {
|
|
||||||
|
|
||||||
DefaultCategoryFactory() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
Logger makeNewLoggerInstance(String name) {
|
|
||||||
return new Logger(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j;
|
|
||||||
|
|
||||||
import org.apache.log4j.spi.ThrowableRenderer;
|
|
||||||
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.io.LineNumberReader;
|
|
||||||
import java.io.StringReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InterruptedIOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default implementation of ThrowableRenderer using
|
|
||||||
* Throwable.printStackTrace.
|
|
||||||
*
|
|
||||||
* @since 1.2.16
|
|
||||||
*/
|
|
||||||
public final class DefaultThrowableRenderer implements ThrowableRenderer {
|
|
||||||
/**
|
|
||||||
* Construct new instance.
|
|
||||||
*/
|
|
||||||
public DefaultThrowableRenderer() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public String[] doRender(final Throwable throwable) {
|
|
||||||
return render(throwable);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render throwable using Throwable.printStackTrace.
|
|
||||||
* @param throwable throwable, may not be null.
|
|
||||||
* @return string representation.
|
|
||||||
*/
|
|
||||||
public static String[] render(final Throwable throwable) {
|
|
||||||
StringWriter sw = new StringWriter();
|
|
||||||
PrintWriter pw = new PrintWriter(sw);
|
|
||||||
try {
|
|
||||||
throwable.printStackTrace(pw);
|
|
||||||
} catch(RuntimeException ex) {
|
|
||||||
}
|
|
||||||
pw.flush();
|
|
||||||
LineNumberReader reader = new LineNumberReader(
|
|
||||||
new StringReader(sw.toString()));
|
|
||||||
ArrayList lines = new ArrayList();
|
|
||||||
try {
|
|
||||||
String line = reader.readLine();
|
|
||||||
while(line != null) {
|
|
||||||
lines.add(line);
|
|
||||||
line = reader.readLine();
|
|
||||||
}
|
|
||||||
} catch(IOException ex) {
|
|
||||||
if (ex instanceof InterruptedIOException) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
lines.add(ex.toString());
|
|
||||||
}
|
|
||||||
String[] tempRep = new String[lines.size()];
|
|
||||||
lines.toArray(tempRep);
|
|
||||||
return tempRep;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j;
|
|
||||||
|
|
||||||
import org.apache.log4j.helpers.AppenderAttachableImpl;
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obsolete AsyncAppender dispatcher provided for compatibility only.
|
|
||||||
*
|
|
||||||
* @deprecated Since 1.3.
|
|
||||||
*/
|
|
||||||
class Dispatcher extends Thread {
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
private org.apache.log4j.helpers.BoundedFIFO bf;
|
|
||||||
private AppenderAttachableImpl aai;
|
|
||||||
private boolean interrupted = false;
|
|
||||||
AsyncAppender container;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param bf
|
|
||||||
* @param container
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
Dispatcher(org.apache.log4j.helpers.BoundedFIFO bf, AsyncAppender container) {
|
|
||||||
this.bf = bf;
|
|
||||||
this.container = container;
|
|
||||||
this.aai = container.aai;
|
|
||||||
|
|
||||||
// It is the user's responsibility to close appenders before
|
|
||||||
// exiting.
|
|
||||||
this.setDaemon(true);
|
|
||||||
|
|
||||||
// set the dispatcher priority to lowest possible value
|
|
||||||
this.setPriority(Thread.MIN_PRIORITY);
|
|
||||||
this.setName("Dispatcher-" + getName());
|
|
||||||
|
|
||||||
// set the dispatcher priority to MIN_PRIORITY plus or minus 2
|
|
||||||
// depending on the direction of MIN to MAX_PRIORITY.
|
|
||||||
//+ (Thread.MAX_PRIORITY > Thread.MIN_PRIORITY ? 1 : -1)*2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void close() {
|
|
||||||
synchronized (bf) {
|
|
||||||
interrupted = true;
|
|
||||||
|
|
||||||
// We have a waiting dispacther if and only if bf.length is
|
|
||||||
// zero. In that case, we need to give it a death kiss.
|
|
||||||
if (bf.length() == 0) {
|
|
||||||
bf.notify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The dispatching strategy is to wait until there are events in the buffer
|
|
||||||
* to process. After having processed an event, we release the monitor
|
|
||||||
* (variable bf) so that new events can be placed in the buffer, instead of
|
|
||||||
* keeping the monitor and processing the remaining events in the buffer.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* Other approaches might yield better results.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public void run() {
|
|
||||||
//Category cat = Category.getInstance(Dispatcher.class.getName());
|
|
||||||
LoggingEvent event;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
synchronized (bf) {
|
|
||||||
if (bf.length() == 0) {
|
|
||||||
// Exit loop if interrupted but only if the the buffer is empty.
|
|
||||||
if (interrupted) {
|
|
||||||
//cat.info("Exiting.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
//LogLog.debug("Waiting for new event to dispatch.");
|
|
||||||
bf.wait();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
event = bf.get();
|
|
||||||
|
|
||||||
if (bf.wasFull()) {
|
|
||||||
//LogLog.debug("Notifying AsyncAppender about freed space.");
|
|
||||||
bf.notify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// synchronized
|
|
||||||
synchronized (container.aai) {
|
|
||||||
if ((aai != null) && (event != null)) {
|
|
||||||
aai.appendLoopOnAppenders(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// while
|
|
||||||
// close and remove all appenders
|
|
||||||
aai.removeAllAppenders();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,559 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j;
|
|
||||||
|
|
||||||
import org.apache.log4j.helpers.OptionConverter;
|
|
||||||
import org.apache.log4j.helpers.PatternConverter;
|
|
||||||
import org.apache.log4j.pattern.BridgePatternConverter;
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
|
|
||||||
|
|
||||||
// Contributors: Nelson Minar <nelson@monkey.org>
|
|
||||||
// Anders Kristensen <akristensen@dynamicsoft.com>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is an enhanced version of org.apache.log4j.PatternLayout
|
|
||||||
* which was originally developed as part of the abandoned log4j 1.3
|
|
||||||
* effort and has been available in the extras companion.
|
|
||||||
* This pattern layout should be used in preference to
|
|
||||||
* org.apache.log4j.PatternLayout except when compatibility
|
|
||||||
* where PatternLayout has been extended either through subclassing
|
|
||||||
* or alternative pattern parsers.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* <p>A flexible layout configurable with pattern string. The goal of this class
|
|
||||||
* is to {@link #format format} a {@link LoggingEvent} and return the results
|
|
||||||
* in a {@link StringBuffer}. The format of the result depends on the
|
|
||||||
* <em>conversion pattern</em>.
|
|
||||||
* <p>
|
|
||||||
*
|
|
||||||
* <p>The conversion pattern is closely related to the conversion
|
|
||||||
* pattern of the printf function in C. A conversion pattern is
|
|
||||||
* composed of literal text and format control expressions called
|
|
||||||
* <em>conversion specifiers</em>.
|
|
||||||
*
|
|
||||||
* <p><i>Note that you are free to insert any literal text within the
|
|
||||||
* conversion pattern.</i>
|
|
||||||
* </p>
|
|
||||||
|
|
||||||
<p>Each conversion specifier starts with a percent sign (%) and is
|
|
||||||
followed by optional <em>format modifiers</em> and a <em>conversion
|
|
||||||
character</em>. The conversion character specifies the type of
|
|
||||||
data, e.g. category, priority, date, thread name. The format
|
|
||||||
modifiers control such things as field width, padding, left and
|
|
||||||
right justification. The following is a simple example.
|
|
||||||
|
|
||||||
<p>Let the conversion pattern be <b>"%-5p [%t]: %m%n"</b> and assume
|
|
||||||
that the log4j environment was set to use a EnhancedPatternLayout. Then the
|
|
||||||
statements
|
|
||||||
<pre>
|
|
||||||
Category root = Category.getRoot();
|
|
||||||
root.debug("Message 1");
|
|
||||||
root.warn("Message 2");
|
|
||||||
</pre>
|
|
||||||
would yield the output
|
|
||||||
<pre>
|
|
||||||
DEBUG [main]: Message 1
|
|
||||||
WARN [main]: Message 2
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>Note that there is no explicit separator between text and
|
|
||||||
conversion specifiers. The pattern parser knows when it has reached
|
|
||||||
the end of a conversion specifier when it reads a conversion
|
|
||||||
character. In the example above the conversion specifier
|
|
||||||
<b>%-5p</b> means the priority of the logging event should be left
|
|
||||||
justified to a width of five characters.
|
|
||||||
|
|
||||||
The recognized conversion characters are
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<table border="1" CELLPADDING="8">
|
|
||||||
<th>Conversion Character</th>
|
|
||||||
<th>Effect</th>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center><b>c</b></td>
|
|
||||||
|
|
||||||
<td>Used to output the category of the logging event. The
|
|
||||||
category conversion specifier can be optionally followed by
|
|
||||||
NameAbbreviator pattern.
|
|
||||||
|
|
||||||
<p>For example, for the category name "alpha.beta.gamma" the pattern
|
|
||||||
<b>%c{2}</b> will output the last two elements ("beta.gamma"),
|
|
||||||
<b>%c{-2}</b> will remove two elements leaving "gamma",
|
|
||||||
<b>%c{1.}</b> will output "a.b.gamma".
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center><b>C</b></td>
|
|
||||||
|
|
||||||
<td>Used to output the fully qualified class name of the caller
|
|
||||||
issuing the logging request. This conversion specifier
|
|
||||||
can be optionally followed by <em>precision specifier</em>, that
|
|
||||||
is a decimal constant in brackets.
|
|
||||||
|
|
||||||
<td>Used to output the category of the logging event. The
|
|
||||||
category conversion specifier can be optionally followed by
|
|
||||||
NameAbbreviator pattern.
|
|
||||||
|
|
||||||
<p>For example, for the category name "alpha.beta.gamma" the pattern
|
|
||||||
<b>%c{2}</b> will output the last two elements ("beta.gamma"),
|
|
||||||
<b>%c{-2}</b> will remove two elements leaving "gamma",
|
|
||||||
<b>%c{1.}</b> will output "a.b.gamma".
|
|
||||||
|
|
||||||
<p><b>WARNING</b> Generating the caller class information is
|
|
||||||
slow. Thus, its use should be avoided unless execution speed is
|
|
||||||
not an issue.
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr> <td align=center><b>d</b></td> <td>Used to output the date of
|
|
||||||
the logging event. The date conversion specifier may be
|
|
||||||
followed by a set of braces containing a
|
|
||||||
date and time pattern strings {@link java.text.SimpleDateFormat},
|
|
||||||
<em>ABSOLUTE</em>, <em>DATE</em> or <em>ISO8601</em>
|
|
||||||
and a set of braces containing a time zone id per
|
|
||||||
{@link java.util.TimeZone#getTimeZone(String)}.
|
|
||||||
For example, <b>%d{HH:mm:ss,SSS}</b>,
|
|
||||||
<b>%d{dd MMM yyyy HH:mm:ss,SSS}</b>,
|
|
||||||
<b>%d{DATE}</b> or <b>%d{HH:mm:ss}{GMT+0}</b>. If no date format specifier is given then
|
|
||||||
ISO8601 format is assumed.
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center><b>F</b></td>
|
|
||||||
|
|
||||||
<td>Used to output the file name where the logging request was
|
|
||||||
issued.
|
|
||||||
|
|
||||||
<p><b>WARNING</b> Generating caller location information is
|
|
||||||
extremely slow and should be avoided unless execution speed
|
|
||||||
is not an issue.
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center><b>l</b></td>
|
|
||||||
|
|
||||||
<td>Used to output location information of the caller which generated
|
|
||||||
the logging event.
|
|
||||||
|
|
||||||
<p>The location information depends on the JVM implementation but
|
|
||||||
usually consists of the fully qualified name of the calling
|
|
||||||
method followed by the callers source the file name and line
|
|
||||||
number between parentheses.
|
|
||||||
|
|
||||||
<p>The location information can be very useful. However, its
|
|
||||||
generation is <em>extremely</em> slow and should be avoided
|
|
||||||
unless execution speed is not an issue.
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center><b>L</b></td>
|
|
||||||
|
|
||||||
<td>Used to output the line number from where the logging request
|
|
||||||
was issued.
|
|
||||||
|
|
||||||
<p><b>WARNING</b> Generating caller location information is
|
|
||||||
extremely slow and should be avoided unless execution speed
|
|
||||||
is not an issue.
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center><b>m</b></td>
|
|
||||||
<td>Used to output the application supplied message associated with
|
|
||||||
the logging event.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center><b>M</b></td>
|
|
||||||
|
|
||||||
<td>Used to output the method name where the logging request was
|
|
||||||
issued.
|
|
||||||
|
|
||||||
<p><b>WARNING</b> Generating caller location information is
|
|
||||||
extremely slow and should be avoided unless execution speed
|
|
||||||
is not an issue.
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center><b>n</b></td>
|
|
||||||
|
|
||||||
<td>Outputs the platform dependent line separator character or
|
|
||||||
characters.
|
|
||||||
|
|
||||||
<p>This conversion character offers practically the same
|
|
||||||
performance as using non-portable line separator strings such as
|
|
||||||
"\n", or "\r\n". Thus, it is the preferred way of specifying a
|
|
||||||
line separator.
|
|
||||||
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center><b>p</b></td>
|
|
||||||
<td>Used to output the priority of the logging event.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
|
|
||||||
<td align=center><b>r</b></td>
|
|
||||||
|
|
||||||
<td>Used to output the number of milliseconds elapsed since the construction
|
|
||||||
of the layout until the creation of the logging event.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center><b>t</b></td>
|
|
||||||
|
|
||||||
<td>Used to output the name of the thread that generated the
|
|
||||||
logging event.</td>
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
|
|
||||||
<td align=center><b>x</b></td>
|
|
||||||
|
|
||||||
<td>Used to output the NDC (nested diagnostic context) associated
|
|
||||||
with the thread that generated the logging event.
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center><b>X</b></td>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
|
|
||||||
<p>Used to output the MDC (mapped diagnostic context) associated
|
|
||||||
with the thread that generated the logging event. The <b>X</b>
|
|
||||||
conversion character can be followed by the key for the
|
|
||||||
map placed between braces, as in <b>%X{clientNumber}</b> where
|
|
||||||
<code>clientNumber</code> is the key. The value in the MDC
|
|
||||||
corresponding to the key will be output. If no additional sub-option
|
|
||||||
is specified, then the entire contents of the MDC key value pair set
|
|
||||||
is output using a format {{key1,val1},{key2,val2}}</p>
|
|
||||||
|
|
||||||
<p>See {@link MDC} class for more details.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center><b>properties</b></td>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
<p>Used to output the Properties associated
|
|
||||||
with the logging event. The <b>properties</b>
|
|
||||||
conversion word can be followed by the key for the
|
|
||||||
map placed between braces, as in <b>%properties{application}</b> where
|
|
||||||
<code>application</code> is the key. The value in the Properties bundle
|
|
||||||
corresponding to the key will be output. If no additional sub-option
|
|
||||||
is specified, then the entire contents of the Properties key value pair set
|
|
||||||
is output using a format {{key1,val1},{key2,val2}}</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center><b>throwable</b></td>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
<p>Used to output the Throwable trace that has been bound to the LoggingEvent, by
|
|
||||||
default this will output the full trace as one would normally
|
|
||||||
find by a call to Throwable.printStackTrace().
|
|
||||||
<b>%throwable{short}</b> or <b>%throwable{1}</b> will output the first line of
|
|
||||||
stack trace. <b>throwable{none}</b> or <b>throwable{0}</b> will suppress
|
|
||||||
the stack trace. <b>%throwable{n}</b> will output n lines of stack trace
|
|
||||||
if a positive integer or omit the last -n lines if a negative integer.
|
|
||||||
If no %throwable pattern is specified, the appender will take
|
|
||||||
responsibility to output the stack trace as it sees fit.</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
|
|
||||||
<td align=center><b>%</b></td>
|
|
||||||
|
|
||||||
<td>The sequence %% outputs a single percent sign.
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p>By default the relevant information is output as is. However,
|
|
||||||
with the aid of format modifiers it is possible to change the
|
|
||||||
minimum field width, the maximum field width and justification.
|
|
||||||
|
|
||||||
<p>The optional format modifier is placed between the percent sign
|
|
||||||
and the conversion character.
|
|
||||||
|
|
||||||
<p>The first optional format modifier is the <em>left justification
|
|
||||||
flag</em> which is just the minus (-) character. Then comes the
|
|
||||||
optional <em>minimum field width</em> modifier. This is a decimal
|
|
||||||
constant that represents the minimum number of characters to
|
|
||||||
output. If the data item requires fewer characters, it is padded on
|
|
||||||
either the left or the right until the minimum width is
|
|
||||||
reached. The default is to pad on the left (right justify) but you
|
|
||||||
can specify right padding with the left justification flag. The
|
|
||||||
padding character is space. If the data item is larger than the
|
|
||||||
minimum field width, the field is expanded to accommodate the
|
|
||||||
data. The value is never truncated.
|
|
||||||
|
|
||||||
<p>This behavior can be changed using the <em>maximum field
|
|
||||||
width</em> modifier which is designated by a period followed by a
|
|
||||||
decimal constant. If the data item is longer than the maximum
|
|
||||||
field, then the extra characters are removed from the
|
|
||||||
<em>beginning</em> of the data item and not from the end. For
|
|
||||||
example, it the maximum field width is eight and the data item is
|
|
||||||
ten characters long, then the first two characters of the data item
|
|
||||||
are dropped. This behavior deviates from the printf function in C
|
|
||||||
where truncation is done from the end.
|
|
||||||
|
|
||||||
<p>Below are various format modifier examples for the category
|
|
||||||
conversion specifier.
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<TABLE BORDER=1 CELLPADDING=8>
|
|
||||||
<th>Format modifier
|
|
||||||
<th>left justify
|
|
||||||
<th>minimum width
|
|
||||||
<th>maximum width
|
|
||||||
<th>comment
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center>%20c</td>
|
|
||||||
<td align=center>false</td>
|
|
||||||
<td align=center>20</td>
|
|
||||||
<td align=center>none</td>
|
|
||||||
|
|
||||||
<td>Left pad with spaces if the category name is less than 20
|
|
||||||
characters long.
|
|
||||||
|
|
||||||
<tr> <td align=center>%-20c</td> <td align=center>true</td> <td
|
|
||||||
align=center>20</td> <td align=center>none</td> <td>Right pad with
|
|
||||||
spaces if the category name is less than 20 characters long.
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center>%.30c</td>
|
|
||||||
<td align=center>NA</td>
|
|
||||||
<td align=center>none</td>
|
|
||||||
<td align=center>30</td>
|
|
||||||
|
|
||||||
<td>Truncate from the beginning if the category name is longer than 30
|
|
||||||
characters.
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center>%20.30c</td>
|
|
||||||
<td align=center>false</td>
|
|
||||||
<td align=center>20</td>
|
|
||||||
<td align=center>30</td>
|
|
||||||
|
|
||||||
<td>Left pad with spaces if the category name is shorter than 20
|
|
||||||
characters. However, if category name is longer than 30 characters,
|
|
||||||
then truncate from the beginning.
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center>%-20.30c</td>
|
|
||||||
<td align=center>true</td>
|
|
||||||
<td align=center>20</td>
|
|
||||||
<td align=center>30</td>
|
|
||||||
|
|
||||||
<td>Right pad with spaces if the category name is shorter than 20
|
|
||||||
characters. However, if category name is longer than 30 characters,
|
|
||||||
then truncate from the beginning.
|
|
||||||
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p>Below are some examples of conversion patterns.
|
|
||||||
|
|
||||||
<dl>
|
|
||||||
|
|
||||||
<p><dt><b>%r [%t] %-5p %c %x - %m%n</b>
|
|
||||||
<p><dd>This is essentially the TTCC layout.
|
|
||||||
|
|
||||||
<p><dt><b>%-6r [%15.15t] %-5p %30.30c %x - %m%n</b>
|
|
||||||
|
|
||||||
<p><dd>Similar to the TTCC layout except that the relative time is
|
|
||||||
right padded if less than 6 digits, thread name is right padded if
|
|
||||||
less than 15 characters and truncated if longer and the category
|
|
||||||
name is left padded if shorter than 30 characters and truncated if
|
|
||||||
longer.
|
|
||||||
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<p>The above text is largely inspired from Peter A. Darnell and
|
|
||||||
Philip E. Margolis' highly recommended book "C -- a Software
|
|
||||||
Engineering Approach", ISBN 0-387-97389-3.
|
|
||||||
|
|
||||||
@author <a href="mailto:cakalijp@Maritz.com">James P. Cakalic</a>
|
|
||||||
@author Ceki Gülcü
|
|
||||||
|
|
||||||
|
|
||||||
@since 1.2.16 */
|
|
||||||
public class EnhancedPatternLayout extends Layout {
|
|
||||||
/** Default pattern string for log output. Currently set to the
|
|
||||||
string <b>"%m%n"</b> which just prints the application supplied
|
|
||||||
message. */
|
|
||||||
public static final String DEFAULT_CONVERSION_PATTERN = "%m%n";
|
|
||||||
|
|
||||||
/** A conversion pattern equivalent to the TTCCCLayout.
|
|
||||||
Current value is <b>%r [%t] %p %c %x - %m%n</b>. */
|
|
||||||
public static final String TTCC_CONVERSION_PATTERN =
|
|
||||||
"%r [%t] %p %c %x - %m%n";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initial size of internal buffer, no longer used.
|
|
||||||
* @deprecated since 1.3
|
|
||||||
*/
|
|
||||||
protected final int BUF_SIZE = 256;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum capacity of internal buffer, no longer used.
|
|
||||||
* @deprecated since 1.3
|
|
||||||
*/
|
|
||||||
protected final int MAX_CAPACITY = 1024;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Customized pattern conversion rules are stored under this key in the
|
|
||||||
* {@link org.apache.log4j.spi.LoggerRepository LoggerRepository} object store.
|
|
||||||
*/
|
|
||||||
public static final String PATTERN_RULE_REGISTRY = "PATTERN_RULE_REGISTRY";
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initial converter for pattern.
|
|
||||||
*/
|
|
||||||
private PatternConverter head;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Conversion pattern.
|
|
||||||
*/
|
|
||||||
private String conversionPattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* True if any element in pattern formats information from exceptions.
|
|
||||||
*/
|
|
||||||
private boolean handlesExceptions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Constructs a EnhancedPatternLayout using the DEFAULT_LAYOUT_PATTERN.
|
|
||||||
|
|
||||||
The default pattern just produces the application supplied message.
|
|
||||||
*/
|
|
||||||
public EnhancedPatternLayout() {
|
|
||||||
this(DEFAULT_CONVERSION_PATTERN);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a EnhancedPatternLayout using the supplied conversion pattern.
|
|
||||||
* @param pattern conversion pattern.
|
|
||||||
*/
|
|
||||||
public EnhancedPatternLayout(final String pattern) {
|
|
||||||
this.conversionPattern = pattern;
|
|
||||||
head = createPatternParser(
|
|
||||||
(pattern == null) ? DEFAULT_CONVERSION_PATTERN : pattern).parse();
|
|
||||||
if (head instanceof BridgePatternConverter) {
|
|
||||||
handlesExceptions = !((BridgePatternConverter) head).ignoresThrowable();
|
|
||||||
} else {
|
|
||||||
handlesExceptions = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the <b>ConversionPattern</b> option. This is the string which
|
|
||||||
* controls formatting and consists of a mix of literal content and
|
|
||||||
* conversion specifiers.
|
|
||||||
*
|
|
||||||
* @param conversionPattern conversion pattern.
|
|
||||||
*/
|
|
||||||
public void setConversionPattern(final String conversionPattern) {
|
|
||||||
this.conversionPattern =
|
|
||||||
OptionConverter.convertSpecialChars(conversionPattern);
|
|
||||||
head = createPatternParser(this.conversionPattern).parse();
|
|
||||||
if (head instanceof BridgePatternConverter) {
|
|
||||||
handlesExceptions = !((BridgePatternConverter) head).ignoresThrowable();
|
|
||||||
} else {
|
|
||||||
handlesExceptions = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the value of the <b>ConversionPattern</b> option.
|
|
||||||
* @return conversion pattern.
|
|
||||||
*/
|
|
||||||
public String getConversionPattern() {
|
|
||||||
return conversionPattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns PatternParser used to parse the conversion string. Subclasses
|
|
||||||
may override this to return a subclass of PatternParser which recognize
|
|
||||||
custom conversion characters.
|
|
||||||
|
|
||||||
@since 0.9.0
|
|
||||||
*/
|
|
||||||
protected org.apache.log4j.helpers.PatternParser createPatternParser(String pattern) {
|
|
||||||
return new org.apache.log4j.pattern.BridgePatternParser(pattern);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Activates the conversion pattern. Do not forget to call this method after
|
|
||||||
you change the parameters of the EnhancedPatternLayout instance.
|
|
||||||
*/
|
|
||||||
public void activateOptions() {
|
|
||||||
// nothing to do.
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Formats a logging event to a writer.
|
|
||||||
* @param event logging event to be formatted.
|
|
||||||
*/
|
|
||||||
public String format(final LoggingEvent event) {
|
|
||||||
StringBuffer buf = new StringBuffer();
|
|
||||||
for(PatternConverter c = head;
|
|
||||||
c != null;
|
|
||||||
c = c.next) {
|
|
||||||
c.format(buf, event);
|
|
||||||
}
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Will return false if any of the conversion specifiers in the pattern
|
|
||||||
* handles {@link Exception Exceptions}.
|
|
||||||
* @return true if the pattern formats any information from exceptions.
|
|
||||||
*/
|
|
||||||
public boolean ignoresThrowable() {
|
|
||||||
return !handlesExceptions;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,168 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j;
|
|
||||||
|
|
||||||
import org.apache.log4j.spi.ThrowableRenderer;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.security.CodeSource;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enhanced implementation of ThrowableRenderer. Uses Throwable.getStackTrace
|
|
||||||
* if running on JDK 1.4 or later and delegates to DefaultThrowableRenderer.render
|
|
||||||
* on earlier virtual machines.
|
|
||||||
*
|
|
||||||
* @since 1.2.16
|
|
||||||
*/
|
|
||||||
public final class EnhancedThrowableRenderer implements ThrowableRenderer {
|
|
||||||
/**
|
|
||||||
* Throwable.getStackTrace() method.
|
|
||||||
*/
|
|
||||||
private Method getStackTraceMethod;
|
|
||||||
/**
|
|
||||||
* StackTraceElement.getClassName() method.
|
|
||||||
*/
|
|
||||||
private Method getClassNameMethod;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct new instance.
|
|
||||||
*/
|
|
||||||
public EnhancedThrowableRenderer() {
|
|
||||||
try {
|
|
||||||
Class[] noArgs = null;
|
|
||||||
getStackTraceMethod = Throwable.class.getMethod("getStackTrace", noArgs);
|
|
||||||
Class ste = Class.forName("java.lang.StackTraceElement");
|
|
||||||
getClassNameMethod = ste.getMethod("getClassName", noArgs);
|
|
||||||
} catch(Exception ex) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public String[] doRender(final Throwable throwable) {
|
|
||||||
if (getStackTraceMethod != null) {
|
|
||||||
try {
|
|
||||||
Object[] noArgs = null;
|
|
||||||
Object[] elements = (Object[]) getStackTraceMethod.invoke(throwable, noArgs);
|
|
||||||
String[] lines = new String[elements.length + 1];
|
|
||||||
lines[0] = throwable.toString();
|
|
||||||
Map classMap = new HashMap();
|
|
||||||
for(int i = 0; i < elements.length; i++) {
|
|
||||||
lines[i+1] = formatElement(elements[i], classMap);
|
|
||||||
}
|
|
||||||
return lines;
|
|
||||||
} catch(Exception ex) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return DefaultThrowableRenderer.render(throwable);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format one element from stack trace.
|
|
||||||
* @param element element, may not be null.
|
|
||||||
* @param classMap map of class name to location.
|
|
||||||
* @return string representation of element.
|
|
||||||
*/
|
|
||||||
private String formatElement(final Object element, final Map classMap) {
|
|
||||||
StringBuffer buf = new StringBuffer("\tat ");
|
|
||||||
buf.append(element);
|
|
||||||
try {
|
|
||||||
String className = getClassNameMethod.invoke(element, (Object[]) null).toString();
|
|
||||||
Object classDetails = classMap.get(className);
|
|
||||||
if (classDetails != null) {
|
|
||||||
buf.append(classDetails);
|
|
||||||
} else {
|
|
||||||
Class cls = findClass(className);
|
|
||||||
int detailStart = buf.length();
|
|
||||||
buf.append('[');
|
|
||||||
try {
|
|
||||||
CodeSource source = cls.getProtectionDomain().getCodeSource();
|
|
||||||
if (source != null) {
|
|
||||||
URL locationURL = source.getLocation();
|
|
||||||
if (locationURL != null) {
|
|
||||||
//
|
|
||||||
// if a file: URL
|
|
||||||
//
|
|
||||||
if ("file".equals(locationURL.getProtocol())) {
|
|
||||||
String path = locationURL.getPath();
|
|
||||||
if (path != null) {
|
|
||||||
//
|
|
||||||
// find the last file separator character
|
|
||||||
//
|
|
||||||
int lastSlash = path.lastIndexOf('/');
|
|
||||||
int lastBack = path.lastIndexOf(File.separatorChar);
|
|
||||||
if (lastBack > lastSlash) {
|
|
||||||
lastSlash = lastBack;
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// if no separator or ends with separator (a directory)
|
|
||||||
// then output the URL, otherwise just the file name.
|
|
||||||
//
|
|
||||||
if (lastSlash <= 0 || lastSlash == path.length() - 1) {
|
|
||||||
buf.append(locationURL);
|
|
||||||
} else {
|
|
||||||
buf.append(path.substring(lastSlash + 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
buf.append(locationURL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch(SecurityException ex) {
|
|
||||||
}
|
|
||||||
buf.append(':');
|
|
||||||
Package pkg = cls.getPackage();
|
|
||||||
if (pkg != null) {
|
|
||||||
String implVersion = pkg.getImplementationVersion();
|
|
||||||
if (implVersion != null) {
|
|
||||||
buf.append(implVersion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buf.append(']');
|
|
||||||
classMap.put(className, buf.substring(detailStart));
|
|
||||||
}
|
|
||||||
} catch(Exception ex) {
|
|
||||||
}
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find class given class name.
|
|
||||||
* @param className class name, may not be null.
|
|
||||||
* @return class, will not be null.
|
|
||||||
* @throws ClassNotFoundException thrown if class can not be found.
|
|
||||||
*/
|
|
||||||
private Class findClass(final String className) throws ClassNotFoundException {
|
|
||||||
try {
|
|
||||||
return Thread.currentThread().getContextClassLoader().loadClass(className);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
try {
|
|
||||||
return Class.forName(className);
|
|
||||||
} catch (ClassNotFoundException e1) {
|
|
||||||
return getClass().getClassLoader().loadClass(className);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,348 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j;
|
|
||||||
|
|
||||||
import java.io.BufferedWriter;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InterruptedIOException;
|
|
||||||
import java.io.Writer;
|
|
||||||
|
|
||||||
import org.apache.log4j.helpers.LogLog;
|
|
||||||
import org.apache.log4j.helpers.QuietWriter;
|
|
||||||
import org.apache.log4j.spi.ErrorCode;
|
|
||||||
|
|
||||||
// Contibutors: Jens Uwe Pipka <jens.pipka@gmx.de>
|
|
||||||
// Ben Sandee
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FileAppender appends log events to a file.
|
|
||||||
*
|
|
||||||
* <p>Support for <code>java.io.Writer</code> and console appending
|
|
||||||
* has been deprecated and then removed. See the replacement
|
|
||||||
* solutions: {@link WriterAppender} and {@link ConsoleAppender}.
|
|
||||||
*
|
|
||||||
* @author Ceki Gülcü
|
|
||||||
* */
|
|
||||||
public class FileAppender extends WriterAppender {
|
|
||||||
|
|
||||||
/** Controls file truncatation. The default value for this variable
|
|
||||||
* is <code>true</code>, meaning that by default a
|
|
||||||
* <code>FileAppender</code> will append to an existing file and not
|
|
||||||
* truncate it.
|
|
||||||
*
|
|
||||||
* <p>This option is meaningful only if the FileAppender opens the
|
|
||||||
* file.
|
|
||||||
*/
|
|
||||||
protected boolean fileAppend = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
The name of the log file. */
|
|
||||||
protected String fileName = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Do we do bufferedIO? */
|
|
||||||
protected boolean bufferedIO = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines the size of IO buffer be. Default is 8K.
|
|
||||||
*/
|
|
||||||
protected int bufferSize = 8*1024;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
The default constructor does not do anything.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
FileAppender() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Instantiate a <code>FileAppender</code> and open the file
|
|
||||||
designated by <code>filename</code>. The opened filename will
|
|
||||||
become the output destination for this appender.
|
|
||||||
|
|
||||||
<p>If the <code>append</code> parameter is true, the file will be
|
|
||||||
appended to. Otherwise, the file designated by
|
|
||||||
<code>filename</code> will be truncated before being opened.
|
|
||||||
|
|
||||||
<p>If the <code>bufferedIO</code> parameter is <code>true</code>,
|
|
||||||
then buffered IO will be used to write to the output file.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
FileAppender(Layout layout, String filename, boolean append, boolean bufferedIO,
|
|
||||||
int bufferSize) throws IOException {
|
|
||||||
this.layout = layout;
|
|
||||||
this.setFile(filename, append, bufferedIO, bufferSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Instantiate a FileAppender and open the file designated by
|
|
||||||
<code>filename</code>. The opened filename will become the output
|
|
||||||
destination for this appender.
|
|
||||||
|
|
||||||
<p>If the <code>append</code> parameter is true, the file will be
|
|
||||||
appended to. Otherwise, the file designated by
|
|
||||||
<code>filename</code> will be truncated before being opened.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
FileAppender(Layout layout, String filename, boolean append)
|
|
||||||
throws IOException {
|
|
||||||
this.layout = layout;
|
|
||||||
this.setFile(filename, append, false, bufferSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Instantiate a FileAppender and open the file designated by
|
|
||||||
<code>filename</code>. The opened filename will become the output
|
|
||||||
destination for this appender.
|
|
||||||
|
|
||||||
<p>The file will be appended to. */
|
|
||||||
public
|
|
||||||
FileAppender(Layout layout, String filename) throws IOException {
|
|
||||||
this(layout, filename, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
The <b>File</b> property takes a string value which should be the
|
|
||||||
name of the file to append to.
|
|
||||||
|
|
||||||
<p><font color="#DD0044"><b>Note that the special values
|
|
||||||
"System.out" or "System.err" are no longer honored.</b></font>
|
|
||||||
|
|
||||||
<p>Note: Actual opening of the file is made when {@link
|
|
||||||
#activateOptions} is called, not when the options are set. */
|
|
||||||
public void setFile(String file) {
|
|
||||||
// Trim spaces from both ends. The users probably does not want
|
|
||||||
// trailing spaces in file names.
|
|
||||||
String val = file.trim();
|
|
||||||
fileName = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the value of the <b>Append</b> option.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
boolean getAppend() {
|
|
||||||
return fileAppend;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Returns the value of the <b>File</b> option. */
|
|
||||||
public
|
|
||||||
String getFile() {
|
|
||||||
return fileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
If the value of <b>File</b> is not <code>null</code>, then {@link
|
|
||||||
#setFile} is called with the values of <b>File</b> and
|
|
||||||
<b>Append</b> properties.
|
|
||||||
|
|
||||||
@since 0.8.1 */
|
|
||||||
public
|
|
||||||
void activateOptions() {
|
|
||||||
if(fileName != null) {
|
|
||||||
try {
|
|
||||||
setFile(fileName, fileAppend, bufferedIO, bufferSize);
|
|
||||||
}
|
|
||||||
catch(java.io.IOException e) {
|
|
||||||
errorHandler.error("setFile("+fileName+","+fileAppend+") call failed.",
|
|
||||||
e, ErrorCode.FILE_OPEN_FAILURE);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//LogLog.error("File option not set for appender ["+name+"].");
|
|
||||||
LogLog.warn("File option not set for appender ["+name+"].");
|
|
||||||
LogLog.warn("Are you using FileAppender instead of ConsoleAppender?");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Closes the previously opened file.
|
|
||||||
*/
|
|
||||||
protected
|
|
||||||
void closeFile() {
|
|
||||||
if(this.qw != null) {
|
|
||||||
try {
|
|
||||||
this.qw.close();
|
|
||||||
}
|
|
||||||
catch(java.io.IOException e) {
|
|
||||||
if (e instanceof InterruptedIOException) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
// Exceptionally, it does not make sense to delegate to an
|
|
||||||
// ErrorHandler. Since a closed appender is basically dead.
|
|
||||||
LogLog.error("Could not close " + qw, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get the value of the <b>BufferedIO</b> option.
|
|
||||||
|
|
||||||
<p>BufferedIO will significatnly increase performance on heavily
|
|
||||||
loaded systems.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
boolean getBufferedIO() {
|
|
||||||
return this.bufferedIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get the size of the IO buffer.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
int getBufferSize() {
|
|
||||||
return this.bufferSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
The <b>Append</b> option takes a boolean value. It is set to
|
|
||||||
<code>true</code> by default. If true, then <code>File</code>
|
|
||||||
will be opened in append mode by {@link #setFile setFile} (see
|
|
||||||
above). Otherwise, {@link #setFile setFile} will open
|
|
||||||
<code>File</code> in truncate mode.
|
|
||||||
|
|
||||||
<p>Note: Actual opening of the file is made when {@link
|
|
||||||
#activateOptions} is called, not when the options are set.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setAppend(boolean flag) {
|
|
||||||
fileAppend = flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
The <b>BufferedIO</b> option takes a boolean value. It is set to
|
|
||||||
<code>false</code> by default. If true, then <code>File</code>
|
|
||||||
will be opened and the resulting {@link java.io.Writer} wrapped
|
|
||||||
around a {@link BufferedWriter}.
|
|
||||||
|
|
||||||
BufferedIO will significatnly increase performance on heavily
|
|
||||||
loaded systems.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setBufferedIO(boolean bufferedIO) {
|
|
||||||
this.bufferedIO = bufferedIO;
|
|
||||||
if(bufferedIO) {
|
|
||||||
immediateFlush = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set the size of the IO buffer.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setBufferSize(int bufferSize) {
|
|
||||||
this.bufferSize = bufferSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
<p>Sets and <i>opens</i> the file where the log output will
|
|
||||||
go. The specified file must be writable.
|
|
||||||
|
|
||||||
<p>If there was already an opened file, then the previous file
|
|
||||||
is closed first.
|
|
||||||
|
|
||||||
<p><b>Do not use this method directly. To configure a FileAppender
|
|
||||||
or one of its subclasses, set its properties one by one and then
|
|
||||||
call activateOptions.</b>
|
|
||||||
|
|
||||||
@param fileName The path to the log file.
|
|
||||||
@param append If true will append to fileName. Otherwise will
|
|
||||||
truncate fileName. */
|
|
||||||
public
|
|
||||||
synchronized
|
|
||||||
void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize)
|
|
||||||
throws IOException {
|
|
||||||
LogLog.debug("setFile called: "+fileName+", "+append);
|
|
||||||
|
|
||||||
// It does not make sense to have immediate flush and bufferedIO.
|
|
||||||
if(bufferedIO) {
|
|
||||||
setImmediateFlush(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
reset();
|
|
||||||
FileOutputStream ostream = null;
|
|
||||||
try {
|
|
||||||
//
|
|
||||||
// attempt to create file
|
|
||||||
//
|
|
||||||
ostream = new FileOutputStream(fileName, append);
|
|
||||||
} catch(FileNotFoundException ex) {
|
|
||||||
//
|
|
||||||
// if parent directory does not exist then
|
|
||||||
// attempt to create it and try to create file
|
|
||||||
// see bug 9150
|
|
||||||
//
|
|
||||||
String parentName = new File(fileName).getParent();
|
|
||||||
if (parentName != null) {
|
|
||||||
File parentDir = new File(parentName);
|
|
||||||
if(!parentDir.exists() && parentDir.mkdirs()) {
|
|
||||||
ostream = new FileOutputStream(fileName, append);
|
|
||||||
} else {
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Writer fw = createWriter(ostream);
|
|
||||||
if(bufferedIO) {
|
|
||||||
fw = new BufferedWriter(fw, bufferSize);
|
|
||||||
}
|
|
||||||
this.setQWForFiles(fw);
|
|
||||||
this.fileName = fileName;
|
|
||||||
this.fileAppend = append;
|
|
||||||
this.bufferedIO = bufferedIO;
|
|
||||||
this.bufferSize = bufferSize;
|
|
||||||
writeHeader();
|
|
||||||
LogLog.debug("setFile ended");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Sets the quiet writer being used.
|
|
||||||
|
|
||||||
This method is overriden by {@link RollingFileAppender}.
|
|
||||||
*/
|
|
||||||
protected
|
|
||||||
void setQWForFiles(Writer writer) {
|
|
||||||
this.qw = new QuietWriter(writer, errorHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Close any previously opened file and call the parent's
|
|
||||||
<code>reset</code>. */
|
|
||||||
protected
|
|
||||||
void reset() {
|
|
||||||
closeFile();
|
|
||||||
this.fileName = null;
|
|
||||||
super.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,267 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j;
|
|
||||||
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
import org.apache.log4j.spi.LocationInfo;
|
|
||||||
import org.apache.log4j.helpers.Transform;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This layout outputs events in a HTML table.
|
|
||||||
*
|
|
||||||
* Appenders using this layout should have their encoding
|
|
||||||
* set to UTF-8 or UTF-16, otherwise events containing
|
|
||||||
* non ASCII characters could result in corrupted
|
|
||||||
* log files.
|
|
||||||
*
|
|
||||||
* @author Ceki Gülcü
|
|
||||||
*/
|
|
||||||
public class HTMLLayout extends Layout {
|
|
||||||
|
|
||||||
protected final int BUF_SIZE = 256;
|
|
||||||
protected final int MAX_CAPACITY = 1024;
|
|
||||||
|
|
||||||
static String TRACE_PREFIX = "<br> ";
|
|
||||||
|
|
||||||
// output buffer appended to when format() is invoked
|
|
||||||
private StringBuffer sbuf = new StringBuffer(BUF_SIZE);
|
|
||||||
|
|
||||||
/**
|
|
||||||
A string constant used in naming the option for setting the the
|
|
||||||
location information flag. Current value of this string
|
|
||||||
constant is <b>LocationInfo</b>.
|
|
||||||
|
|
||||||
<p>Note that all option keys are case sensitive.
|
|
||||||
|
|
||||||
@deprecated Options are now handled using the JavaBeans paradigm.
|
|
||||||
This constant is not longer needed and will be removed in the
|
|
||||||
<em>near</em> term.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public static final String LOCATION_INFO_OPTION = "LocationInfo";
|
|
||||||
|
|
||||||
/**
|
|
||||||
A string constant used in naming the option for setting the the
|
|
||||||
HTML document title. Current value of this string
|
|
||||||
constant is <b>Title</b>.
|
|
||||||
*/
|
|
||||||
public static final String TITLE_OPTION = "Title";
|
|
||||||
|
|
||||||
// Print no location info by default
|
|
||||||
boolean locationInfo = false;
|
|
||||||
|
|
||||||
String title = "Log4J Log Messages";
|
|
||||||
|
|
||||||
/**
|
|
||||||
The <b>LocationInfo</b> option takes a boolean value. By
|
|
||||||
default, it is set to false which means there will be no location
|
|
||||||
information output by this layout. If the the option is set to
|
|
||||||
true, then the file name and line number of the statement
|
|
||||||
at the origin of the log statement will be output.
|
|
||||||
|
|
||||||
<p>If you are embedding this layout within an {@link
|
|
||||||
org.apache.log4j.net.SMTPAppender} then make sure to set the
|
|
||||||
<b>LocationInfo</b> option of that appender as well.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setLocationInfo(boolean flag) {
|
|
||||||
locationInfo = flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the current value of the <b>LocationInfo</b> option.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
boolean getLocationInfo() {
|
|
||||||
return locationInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
The <b>Title</b> option takes a String value. This option sets the
|
|
||||||
document title of the generated HTML document.
|
|
||||||
|
|
||||||
<p>Defaults to 'Log4J Log Messages'.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setTitle(String title) {
|
|
||||||
this.title = title;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the current value of the <b>Title</b> option.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
String getTitle() {
|
|
||||||
return title;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the content type output by this layout, i.e "text/html".
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
String getContentType() {
|
|
||||||
return "text/html";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
No options to activate.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void activateOptions() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
String format(LoggingEvent event) {
|
|
||||||
|
|
||||||
if(sbuf.capacity() > MAX_CAPACITY) {
|
|
||||||
sbuf = new StringBuffer(BUF_SIZE);
|
|
||||||
} else {
|
|
||||||
sbuf.setLength(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
sbuf.append(Layout.LINE_SEP + "<tr>" + Layout.LINE_SEP);
|
|
||||||
|
|
||||||
sbuf.append("<td>");
|
|
||||||
sbuf.append(event.timeStamp - LoggingEvent.getStartTime());
|
|
||||||
sbuf.append("</td>" + Layout.LINE_SEP);
|
|
||||||
|
|
||||||
String escapedThread = Transform.escapeTags(event.getThreadName());
|
|
||||||
sbuf.append("<td title=\"" + escapedThread + " thread\">");
|
|
||||||
sbuf.append(escapedThread);
|
|
||||||
sbuf.append("</td>" + Layout.LINE_SEP);
|
|
||||||
|
|
||||||
sbuf.append("<td title=\"Level\">");
|
|
||||||
if (event.getLevel().equals(Level.DEBUG)) {
|
|
||||||
sbuf.append("<font color=\"#339933\">");
|
|
||||||
sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
|
|
||||||
sbuf.append("</font>");
|
|
||||||
}
|
|
||||||
else if(event.getLevel().isGreaterOrEqual(Level.WARN)) {
|
|
||||||
sbuf.append("<font color=\"#993300\"><strong>");
|
|
||||||
sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
|
|
||||||
sbuf.append("</strong></font>");
|
|
||||||
} else {
|
|
||||||
sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
|
|
||||||
}
|
|
||||||
sbuf.append("</td>" + Layout.LINE_SEP);
|
|
||||||
|
|
||||||
String escapedLogger = Transform.escapeTags(event.getLoggerName());
|
|
||||||
sbuf.append("<td title=\"" + escapedLogger + " category\">");
|
|
||||||
sbuf.append(escapedLogger);
|
|
||||||
sbuf.append("</td>" + Layout.LINE_SEP);
|
|
||||||
|
|
||||||
if(locationInfo) {
|
|
||||||
LocationInfo locInfo = event.getLocationInformation();
|
|
||||||
sbuf.append("<td>");
|
|
||||||
sbuf.append(Transform.escapeTags(locInfo.getFileName()));
|
|
||||||
sbuf.append(':');
|
|
||||||
sbuf.append(locInfo.getLineNumber());
|
|
||||||
sbuf.append("</td>" + Layout.LINE_SEP);
|
|
||||||
}
|
|
||||||
|
|
||||||
sbuf.append("<td title=\"Message\">");
|
|
||||||
sbuf.append(Transform.escapeTags(event.getRenderedMessage()));
|
|
||||||
sbuf.append("</td>" + Layout.LINE_SEP);
|
|
||||||
sbuf.append("</tr>" + Layout.LINE_SEP);
|
|
||||||
|
|
||||||
if (event.getNDC() != null) {
|
|
||||||
sbuf.append("<tr><td bgcolor=\"#EEEEEE\" style=\"font-size : xx-small;\" colspan=\"6\" title=\"Nested Diagnostic Context\">");
|
|
||||||
sbuf.append("NDC: " + Transform.escapeTags(event.getNDC()));
|
|
||||||
sbuf.append("</td></tr>" + Layout.LINE_SEP);
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] s = event.getThrowableStrRep();
|
|
||||||
if(s != null) {
|
|
||||||
sbuf.append("<tr><td bgcolor=\"#993300\" style=\"color:White; font-size : xx-small;\" colspan=\"6\">");
|
|
||||||
appendThrowableAsHTML(s, sbuf);
|
|
||||||
sbuf.append("</td></tr>" + Layout.LINE_SEP);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sbuf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
void appendThrowableAsHTML(String[] s, StringBuffer sbuf) {
|
|
||||||
if(s != null) {
|
|
||||||
int len = s.length;
|
|
||||||
if(len == 0)
|
|
||||||
return;
|
|
||||||
sbuf.append(Transform.escapeTags(s[0]));
|
|
||||||
sbuf.append(Layout.LINE_SEP);
|
|
||||||
for(int i = 1; i < len; i++) {
|
|
||||||
sbuf.append(TRACE_PREFIX);
|
|
||||||
sbuf.append(Transform.escapeTags(s[i]));
|
|
||||||
sbuf.append(Layout.LINE_SEP);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns appropriate HTML headers.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
String getHeader() {
|
|
||||||
StringBuffer sbuf = new StringBuffer();
|
|
||||||
sbuf.append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">" + Layout.LINE_SEP);
|
|
||||||
sbuf.append("<html>" + Layout.LINE_SEP);
|
|
||||||
sbuf.append("<head>" + Layout.LINE_SEP);
|
|
||||||
sbuf.append("<title>" + title + "</title>" + Layout.LINE_SEP);
|
|
||||||
sbuf.append("<style type=\"text/css\">" + Layout.LINE_SEP);
|
|
||||||
sbuf.append("<!--" + Layout.LINE_SEP);
|
|
||||||
sbuf.append("body, table {font-family: arial,sans-serif; font-size: x-small;}" + Layout.LINE_SEP);
|
|
||||||
sbuf.append("th {background: #336699; color: #FFFFFF; text-align: left;}" + Layout.LINE_SEP);
|
|
||||||
sbuf.append("-->" + Layout.LINE_SEP);
|
|
||||||
sbuf.append("</style>" + Layout.LINE_SEP);
|
|
||||||
sbuf.append("</head>" + Layout.LINE_SEP);
|
|
||||||
sbuf.append("<body bgcolor=\"#FFFFFF\" topmargin=\"6\" leftmargin=\"6\">" + Layout.LINE_SEP);
|
|
||||||
sbuf.append("<hr size=\"1\" noshade>" + Layout.LINE_SEP);
|
|
||||||
sbuf.append("Log session start time " + new java.util.Date() + "<br>" + Layout.LINE_SEP);
|
|
||||||
sbuf.append("<br>" + Layout.LINE_SEP);
|
|
||||||
sbuf.append("<table cellspacing=\"0\" cellpadding=\"4\" border=\"1\" bordercolor=\"#224466\" width=\"100%\">" + Layout.LINE_SEP);
|
|
||||||
sbuf.append("<tr>" + Layout.LINE_SEP);
|
|
||||||
sbuf.append("<th>Time</th>" + Layout.LINE_SEP);
|
|
||||||
sbuf.append("<th>Thread</th>" + Layout.LINE_SEP);
|
|
||||||
sbuf.append("<th>Level</th>" + Layout.LINE_SEP);
|
|
||||||
sbuf.append("<th>Category</th>" + Layout.LINE_SEP);
|
|
||||||
if(locationInfo) {
|
|
||||||
sbuf.append("<th>File:Line</th>" + Layout.LINE_SEP);
|
|
||||||
}
|
|
||||||
sbuf.append("<th>Message</th>" + Layout.LINE_SEP);
|
|
||||||
sbuf.append("</tr>" + Layout.LINE_SEP);
|
|
||||||
return sbuf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the appropriate HTML footers.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
String getFooter() {
|
|
||||||
StringBuffer sbuf = new StringBuffer();
|
|
||||||
sbuf.append("</table>" + Layout.LINE_SEP);
|
|
||||||
sbuf.append("<br>" + Layout.LINE_SEP);
|
|
||||||
sbuf.append("</body></html>");
|
|
||||||
return sbuf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
The HTML layout handles the throwable contained in logging
|
|
||||||
events. Hence, this method return <code>false</code>. */
|
|
||||||
public
|
|
||||||
boolean ignoresThrowable() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,577 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// WARNING This class MUST not have references to the Category or
|
|
||||||
// WARNING RootCategory classes in its static initiliazation neither
|
|
||||||
// WARNING directly nor indirectly.
|
|
||||||
|
|
||||||
// Contributors:
|
|
||||||
// Luke Blanshard <luke@quiq.com>
|
|
||||||
// Mario Schomburg - IBM Global Services/Germany
|
|
||||||
// Anders Kristensen
|
|
||||||
// Igor Poteryaev
|
|
||||||
|
|
||||||
package org.apache.log4j;
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.Hashtable;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
import org.apache.log4j.spi.LoggerFactory;
|
|
||||||
import org.apache.log4j.spi.HierarchyEventListener;
|
|
||||||
import org.apache.log4j.spi.LoggerRepository;
|
|
||||||
import org.apache.log4j.spi.RendererSupport;
|
|
||||||
import org.apache.log4j.or.RendererMap;
|
|
||||||
import org.apache.log4j.or.ObjectRenderer;
|
|
||||||
import org.apache.log4j.helpers.LogLog;
|
|
||||||
import org.apache.log4j.spi.ThrowableRendererSupport;
|
|
||||||
import org.apache.log4j.spi.ThrowableRenderer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
This class is specialized in retrieving loggers by name and also
|
|
||||||
maintaining the logger hierarchy.
|
|
||||||
|
|
||||||
<p><em>The casual user does not have to deal with this class
|
|
||||||
directly.</em>
|
|
||||||
|
|
||||||
<p>The structure of the logger hierarchy is maintained by the
|
|
||||||
{@link #getLogger} method. The hierarchy is such that children link
|
|
||||||
to their parent but parents do not have any pointers to their
|
|
||||||
children. Moreover, loggers can be instantiated in any order, in
|
|
||||||
particular descendant before ancestor.
|
|
||||||
|
|
||||||
<p>In case a descendant is created before a particular ancestor,
|
|
||||||
then it creates a provision node for the ancestor and adds itself
|
|
||||||
to the provision node. Other descendants of the same ancestor add
|
|
||||||
themselves to the previously created provision node.
|
|
||||||
|
|
||||||
@author Ceki Gülcü
|
|
||||||
|
|
||||||
*/
|
|
||||||
public class Hierarchy implements LoggerRepository, RendererSupport, ThrowableRendererSupport {
|
|
||||||
|
|
||||||
private LoggerFactory defaultFactory;
|
|
||||||
private Vector listeners;
|
|
||||||
|
|
||||||
Hashtable ht;
|
|
||||||
Logger root;
|
|
||||||
RendererMap rendererMap;
|
|
||||||
|
|
||||||
int thresholdInt;
|
|
||||||
Level threshold;
|
|
||||||
|
|
||||||
boolean emittedNoAppenderWarning = false;
|
|
||||||
boolean emittedNoResourceBundleWarning = false;
|
|
||||||
|
|
||||||
private ThrowableRenderer throwableRenderer = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Create a new logger hierarchy.
|
|
||||||
|
|
||||||
@param root The root of the new hierarchy.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
Hierarchy(Logger root) {
|
|
||||||
ht = new Hashtable();
|
|
||||||
listeners = new Vector(1);
|
|
||||||
this.root = root;
|
|
||||||
// Enable all level levels by default.
|
|
||||||
setThreshold(Level.ALL);
|
|
||||||
this.root.setHierarchy(this);
|
|
||||||
rendererMap = new RendererMap();
|
|
||||||
defaultFactory = new DefaultCategoryFactory();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Add an object renderer for a specific class.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void addRenderer(Class classToRender, ObjectRenderer or) {
|
|
||||||
rendererMap.put(classToRender, or);
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void addHierarchyEventListener(HierarchyEventListener listener) {
|
|
||||||
if(listeners.contains(listener)) {
|
|
||||||
LogLog.warn("Ignoring attempt to add an existent listener.");
|
|
||||||
} else {
|
|
||||||
listeners.addElement(listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
This call will clear all logger definitions from the internal
|
|
||||||
hashtable. Invoking this method will irrevocably mess up the
|
|
||||||
logger hierarchy.
|
|
||||||
|
|
||||||
<p>You should <em>really</em> know what you are doing before
|
|
||||||
invoking this method.
|
|
||||||
|
|
||||||
@since 0.9.0 */
|
|
||||||
public
|
|
||||||
void clear() {
|
|
||||||
//System.out.println("\n\nAbout to clear internal hash table.");
|
|
||||||
ht.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void emitNoAppenderWarning(Category cat) {
|
|
||||||
// No appenders in hierarchy, warn user only once.
|
|
||||||
if(!this.emittedNoAppenderWarning) {
|
|
||||||
LogLog.warn("No appenders could be found for logger (" +
|
|
||||||
cat.getName() + ").");
|
|
||||||
LogLog.warn("Please initialize the log4j system properly.");
|
|
||||||
LogLog.warn("See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.");
|
|
||||||
this.emittedNoAppenderWarning = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Check if the named logger exists in the hierarchy. If so return
|
|
||||||
its reference, otherwise returns <code>null</code>.
|
|
||||||
|
|
||||||
@param name The name of the logger to search for.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
Logger exists(String name) {
|
|
||||||
Object o = ht.get(new CategoryKey(name));
|
|
||||||
if(o instanceof Logger) {
|
|
||||||
return (Logger) o;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
The string form of {@link #setThreshold(Level)}.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setThreshold(String levelStr) {
|
|
||||||
Level l = (Level) Level.toLevel(levelStr, null);
|
|
||||||
if(l != null) {
|
|
||||||
setThreshold(l);
|
|
||||||
} else {
|
|
||||||
LogLog.warn("Could not convert ["+levelStr+"] to Level.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Enable logging for logging requests with level <code>l</code> or
|
|
||||||
higher. By default all levels are enabled.
|
|
||||||
|
|
||||||
@param l The minimum level for which logging requests are sent to
|
|
||||||
their appenders. */
|
|
||||||
public
|
|
||||||
void setThreshold(Level l) {
|
|
||||||
if(l != null) {
|
|
||||||
thresholdInt = l.level;
|
|
||||||
threshold = l;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void fireAddAppenderEvent(Category logger, Appender appender) {
|
|
||||||
if(listeners != null) {
|
|
||||||
int size = listeners.size();
|
|
||||||
HierarchyEventListener listener;
|
|
||||||
for(int i = 0; i < size; i++) {
|
|
||||||
listener = (HierarchyEventListener) listeners.elementAt(i);
|
|
||||||
listener.addAppenderEvent(logger, appender);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void fireRemoveAppenderEvent(Category logger, Appender appender) {
|
|
||||||
if(listeners != null) {
|
|
||||||
int size = listeners.size();
|
|
||||||
HierarchyEventListener listener;
|
|
||||||
for(int i = 0; i < size; i++) {
|
|
||||||
listener = (HierarchyEventListener) listeners.elementAt(i);
|
|
||||||
listener.removeAppenderEvent(logger, appender);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns a {@link Level} representation of the <code>enable</code>
|
|
||||||
state.
|
|
||||||
|
|
||||||
@since 1.2 */
|
|
||||||
public
|
|
||||||
Level getThreshold() {
|
|
||||||
return threshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns an integer representation of the this repository's
|
|
||||||
threshold.
|
|
||||||
|
|
||||||
@since 1.2 */
|
|
||||||
//public
|
|
||||||
//int getThresholdInt() {
|
|
||||||
// return thresholdInt;
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Return a new logger instance named as the first parameter using
|
|
||||||
the default factory.
|
|
||||||
|
|
||||||
<p>If a logger of that name already exists, then it will be
|
|
||||||
returned. Otherwise, a new logger will be instantiated and
|
|
||||||
then linked with its existing ancestors as well as children.
|
|
||||||
|
|
||||||
@param name The name of the logger to retrieve.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
Logger getLogger(String name) {
|
|
||||||
return getLogger(name, defaultFactory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Return a new logger instance named as the first parameter using
|
|
||||||
<code>factory</code>.
|
|
||||||
|
|
||||||
<p>If a logger of that name already exists, then it will be
|
|
||||||
returned. Otherwise, a new logger will be instantiated by the
|
|
||||||
<code>factory</code> parameter and linked with its existing
|
|
||||||
ancestors as well as children.
|
|
||||||
|
|
||||||
@param name The name of the logger to retrieve.
|
|
||||||
@param factory The factory that will make the new logger instance.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
Logger getLogger(String name, LoggerFactory factory) {
|
|
||||||
//System.out.println("getInstance("+name+") called.");
|
|
||||||
CategoryKey key = new CategoryKey(name);
|
|
||||||
// Synchronize to prevent write conflicts. Read conflicts (in
|
|
||||||
// getChainedLevel method) are possible only if variable
|
|
||||||
// assignments are non-atomic.
|
|
||||||
Logger logger;
|
|
||||||
|
|
||||||
synchronized(ht) {
|
|
||||||
Object o = ht.get(key);
|
|
||||||
if(o == null) {
|
|
||||||
logger = factory.makeNewLoggerInstance(name);
|
|
||||||
logger.setHierarchy(this);
|
|
||||||
ht.put(key, logger);
|
|
||||||
updateParents(logger);
|
|
||||||
return logger;
|
|
||||||
} else if(o instanceof Logger) {
|
|
||||||
return (Logger) o;
|
|
||||||
} else if (o instanceof ProvisionNode) {
|
|
||||||
//System.out.println("("+name+") ht.get(this) returned ProvisionNode");
|
|
||||||
logger = factory.makeNewLoggerInstance(name);
|
|
||||||
logger.setHierarchy(this);
|
|
||||||
ht.put(key, logger);
|
|
||||||
updateChildren((ProvisionNode) o, logger);
|
|
||||||
updateParents(logger);
|
|
||||||
return logger;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// It should be impossible to arrive here
|
|
||||||
return null; // but let's keep the compiler happy.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns all the currently defined categories in this hierarchy as
|
|
||||||
an {@link java.util.Enumeration Enumeration}.
|
|
||||||
|
|
||||||
<p>The root logger is <em>not</em> included in the returned
|
|
||||||
{@link Enumeration}. */
|
|
||||||
public
|
|
||||||
Enumeration getCurrentLoggers() {
|
|
||||||
// The accumlation in v is necessary because not all elements in
|
|
||||||
// ht are Logger objects as there might be some ProvisionNodes
|
|
||||||
// as well.
|
|
||||||
Vector v = new Vector(ht.size());
|
|
||||||
|
|
||||||
Enumeration elems = ht.elements();
|
|
||||||
while(elems.hasMoreElements()) {
|
|
||||||
Object o = elems.nextElement();
|
|
||||||
if(o instanceof Logger) {
|
|
||||||
v.addElement(o);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return v.elements();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@deprecated Please use {@link #getCurrentLoggers} instead.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
Enumeration getCurrentCategories() {
|
|
||||||
return getCurrentLoggers();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get the renderer map for this hierarchy.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
RendererMap getRendererMap() {
|
|
||||||
return rendererMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get the root of this hierarchy.
|
|
||||||
|
|
||||||
@since 0.9.0
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
Logger getRootLogger() {
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
This method will return <code>true</code> if this repository is
|
|
||||||
disabled for <code>level</code> object passed as parameter and
|
|
||||||
<code>false</code> otherwise. See also the {@link
|
|
||||||
#setThreshold(Level) threshold} emthod. */
|
|
||||||
public
|
|
||||||
boolean isDisabled(int level) {
|
|
||||||
return thresholdInt > level;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@deprecated Deprecated with no replacement.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void overrideAsNeeded(String override) {
|
|
||||||
LogLog.warn("The Hiearchy.overrideAsNeeded method has been deprecated.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Reset all values contained in this hierarchy instance to their
|
|
||||||
default. This removes all appenders from all categories, sets
|
|
||||||
the level of all non-root categories to <code>null</code>,
|
|
||||||
sets their additivity flag to <code>true</code> and sets the level
|
|
||||||
of the root logger to {@link Level#DEBUG DEBUG}. Moreover,
|
|
||||||
message disabling is set its default "off" value.
|
|
||||||
|
|
||||||
<p>Existing categories are not removed. They are just reset.
|
|
||||||
|
|
||||||
<p>This method should be used sparingly and with care as it will
|
|
||||||
block all logging until it is completed.</p>
|
|
||||||
|
|
||||||
@since 0.8.5 */
|
|
||||||
public
|
|
||||||
void resetConfiguration() {
|
|
||||||
|
|
||||||
getRootLogger().setLevel((Level) Level.DEBUG);
|
|
||||||
root.setResourceBundle(null);
|
|
||||||
setThreshold(Level.ALL);
|
|
||||||
|
|
||||||
// the synchronization is needed to prevent JDK 1.2.x hashtable
|
|
||||||
// surprises
|
|
||||||
synchronized(ht) {
|
|
||||||
shutdown(); // nested locks are OK
|
|
||||||
|
|
||||||
Enumeration cats = getCurrentLoggers();
|
|
||||||
while(cats.hasMoreElements()) {
|
|
||||||
Logger c = (Logger) cats.nextElement();
|
|
||||||
c.setLevel(null);
|
|
||||||
c.setAdditivity(true);
|
|
||||||
c.setResourceBundle(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rendererMap.clear();
|
|
||||||
throwableRenderer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Does nothing.
|
|
||||||
|
|
||||||
@deprecated Deprecated with no replacement.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setDisableOverride(String override) {
|
|
||||||
LogLog.warn("The Hiearchy.setDisableOverride method has been deprecated.");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Used by subclasses to add a renderer to the hierarchy passed as parameter.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setRenderer(Class renderedClass, ObjectRenderer renderer) {
|
|
||||||
rendererMap.put(renderedClass, renderer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public void setThrowableRenderer(final ThrowableRenderer renderer) {
|
|
||||||
throwableRenderer = renderer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public ThrowableRenderer getThrowableRenderer() {
|
|
||||||
return throwableRenderer;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Shutting down a hierarchy will <em>safely</em> close and remove
|
|
||||||
all appenders in all categories including the root logger.
|
|
||||||
|
|
||||||
<p>Some appenders such as {@link org.apache.log4j.net.SocketAppender}
|
|
||||||
and {@link AsyncAppender} need to be closed before the
|
|
||||||
application exists. Otherwise, pending logging events might be
|
|
||||||
lost.
|
|
||||||
|
|
||||||
<p>The <code>shutdown</code> method is careful to close nested
|
|
||||||
appenders before closing regular appenders. This is allows
|
|
||||||
configurations where a regular appender is attached to a logger
|
|
||||||
and again to a nested appender.
|
|
||||||
|
|
||||||
|
|
||||||
@since 1.0 */
|
|
||||||
public
|
|
||||||
void shutdown() {
|
|
||||||
Logger root = getRootLogger();
|
|
||||||
|
|
||||||
// begin by closing nested appenders
|
|
||||||
root.closeNestedAppenders();
|
|
||||||
|
|
||||||
synchronized(ht) {
|
|
||||||
Enumeration cats = this.getCurrentLoggers();
|
|
||||||
while(cats.hasMoreElements()) {
|
|
||||||
Logger c = (Logger) cats.nextElement();
|
|
||||||
c.closeNestedAppenders();
|
|
||||||
}
|
|
||||||
|
|
||||||
// then, remove all appenders
|
|
||||||
root.removeAllAppenders();
|
|
||||||
cats = this.getCurrentLoggers();
|
|
||||||
while(cats.hasMoreElements()) {
|
|
||||||
Logger c = (Logger) cats.nextElement();
|
|
||||||
c.removeAllAppenders();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
This method loops through all the *potential* parents of
|
|
||||||
'cat'. There 3 possible cases:
|
|
||||||
|
|
||||||
1) No entry for the potential parent of 'cat' exists
|
|
||||||
|
|
||||||
We create a ProvisionNode for this potential parent and insert
|
|
||||||
'cat' in that provision node.
|
|
||||||
|
|
||||||
2) There entry is of type Logger for the potential parent.
|
|
||||||
|
|
||||||
The entry is 'cat's nearest existing parent. We update cat's
|
|
||||||
parent field with this entry. We also break from the loop
|
|
||||||
because updating our parent's parent is our parent's
|
|
||||||
responsibility.
|
|
||||||
|
|
||||||
3) There entry is of type ProvisionNode for this potential parent.
|
|
||||||
|
|
||||||
We add 'cat' to the list of children for this potential parent.
|
|
||||||
*/
|
|
||||||
final
|
|
||||||
private
|
|
||||||
void updateParents(Logger cat) {
|
|
||||||
String name = cat.name;
|
|
||||||
int length = name.length();
|
|
||||||
boolean parentFound = false;
|
|
||||||
|
|
||||||
//System.out.println("UpdateParents called for " + name);
|
|
||||||
|
|
||||||
// if name = "w.x.y.z", loop thourgh "w.x.y", "w.x" and "w", but not "w.x.y.z"
|
|
||||||
for(int i = name.lastIndexOf('.', length-1); i >= 0;
|
|
||||||
i = name.lastIndexOf('.', i-1)) {
|
|
||||||
String substr = name.substring(0, i);
|
|
||||||
|
|
||||||
//System.out.println("Updating parent : " + substr);
|
|
||||||
CategoryKey key = new CategoryKey(substr); // simple constructor
|
|
||||||
Object o = ht.get(key);
|
|
||||||
// Create a provision node for a future parent.
|
|
||||||
if(o == null) {
|
|
||||||
//System.out.println("No parent "+substr+" found. Creating ProvisionNode.");
|
|
||||||
ProvisionNode pn = new ProvisionNode(cat);
|
|
||||||
ht.put(key, pn);
|
|
||||||
} else if(o instanceof Category) {
|
|
||||||
parentFound = true;
|
|
||||||
cat.parent = (Category) o;
|
|
||||||
//System.out.println("Linking " + cat.name + " -> " + ((Category) o).name);
|
|
||||||
break; // no need to update the ancestors of the closest ancestor
|
|
||||||
} else if(o instanceof ProvisionNode) {
|
|
||||||
((ProvisionNode) o).addElement(cat);
|
|
||||||
} else {
|
|
||||||
Exception e = new IllegalStateException("unexpected object type " +
|
|
||||||
o.getClass() + " in ht.");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If we could not find any existing parents, then link with root.
|
|
||||||
if(!parentFound)
|
|
||||||
cat.parent = root;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
We update the links for all the children that placed themselves
|
|
||||||
in the provision node 'pn'. The second argument 'cat' is a
|
|
||||||
reference for the newly created Logger, parent of all the
|
|
||||||
children in 'pn'
|
|
||||||
|
|
||||||
We loop on all the children 'c' in 'pn':
|
|
||||||
|
|
||||||
If the child 'c' has been already linked to a child of
|
|
||||||
'cat' then there is no need to update 'c'.
|
|
||||||
|
|
||||||
Otherwise, we set cat's parent field to c's parent and set
|
|
||||||
c's parent field to cat.
|
|
||||||
|
|
||||||
*/
|
|
||||||
final
|
|
||||||
private
|
|
||||||
void updateChildren(ProvisionNode pn, Logger logger) {
|
|
||||||
//System.out.println("updateChildren called for " + logger.name);
|
|
||||||
final int last = pn.size();
|
|
||||||
|
|
||||||
for(int i = 0; i < last; i++) {
|
|
||||||
Logger l = (Logger) pn.elementAt(i);
|
|
||||||
//System.out.println("Updating child " +p.name);
|
|
||||||
|
|
||||||
// Unless this child already points to a correct (lower) parent,
|
|
||||||
// make cat.parent point to l.parent and l.parent to cat.
|
|
||||||
if(!l.parent.name.startsWith(logger.name)) {
|
|
||||||
logger.parent = l.parent;
|
|
||||||
l.parent = logger;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j;
|
|
||||||
|
|
||||||
import org.apache.log4j.spi.OptionHandler;
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Extend this abstract class to create your own log layout format.
|
|
||||||
|
|
||||||
@author Ceki Gülcü
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
public abstract class Layout implements OptionHandler {
|
|
||||||
|
|
||||||
// Note that the line.separator property can be looked up even by
|
|
||||||
// applets.
|
|
||||||
public final static String LINE_SEP = System.getProperty("line.separator");
|
|
||||||
public final static int LINE_SEP_LEN = LINE_SEP.length();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Implement this method to create your own layout format.
|
|
||||||
*/
|
|
||||||
abstract
|
|
||||||
public
|
|
||||||
String format(LoggingEvent event);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the content type output by this layout. The base class
|
|
||||||
returns "text/plain".
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
String getContentType() {
|
|
||||||
return "text/plain";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the header for the layout format. The base class returns
|
|
||||||
<code>null</code>. */
|
|
||||||
public
|
|
||||||
String getHeader() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the footer for the layout format. The base class returns
|
|
||||||
<code>null</code>. */
|
|
||||||
public
|
|
||||||
String getFooter() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
If the layout handles the throwable object contained within
|
|
||||||
{@link LoggingEvent}, then the layout should return
|
|
||||||
<code>false</code>. Otherwise, if the layout ignores throwable
|
|
||||||
object, then the layout should return <code>true</code>.
|
|
||||||
If ignoresThrowable is true, the appender is responsible for
|
|
||||||
rendering the throwable.
|
|
||||||
|
|
||||||
<p>The {@link SimpleLayout}, {@link TTCCLayout}, {@link
|
|
||||||
PatternLayout} all return <code>true</code>. The {@link
|
|
||||||
org.apache.log4j.xml.XMLLayout} returns <code>false</code>.
|
|
||||||
|
|
||||||
@since 0.8.4 */
|
|
||||||
abstract
|
|
||||||
public
|
|
||||||
boolean ignoresThrowable();
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,224 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Contributors: Kitching Simon <Simon.Kitching@orange.ch>
|
|
||||||
// Nicholas Wolff
|
|
||||||
|
|
||||||
package org.apache.log4j;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.io.ObjectStreamException;
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Defines the minimum set of levels recognized by the system, that is
|
|
||||||
<code>OFF</code>, <code>FATAL</code>, <code>ERROR</code>,
|
|
||||||
<code>WARN</code>, <code>INFO</code, <code>DEBUG</code> and
|
|
||||||
<code>ALL</code>.
|
|
||||||
|
|
||||||
<p>The <code>Level</code> class may be subclassed to define a larger
|
|
||||||
level set.
|
|
||||||
|
|
||||||
@author Ceki Gülcü
|
|
||||||
|
|
||||||
*/
|
|
||||||
public class Level extends Priority implements Serializable {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TRACE level integer value.
|
|
||||||
* @since 1.2.12
|
|
||||||
*/
|
|
||||||
public static final int TRACE_INT = 5000;
|
|
||||||
|
|
||||||
/**
|
|
||||||
The <code>OFF</code> has the highest possible rank and is
|
|
||||||
intended to turn off logging. */
|
|
||||||
final static public Level OFF = new Level(OFF_INT, "OFF", 0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
The <code>FATAL</code> level designates very severe error
|
|
||||||
events that will presumably lead the application to abort.
|
|
||||||
*/
|
|
||||||
final static public Level FATAL = new Level(FATAL_INT, "FATAL", 0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
The <code>ERROR</code> level designates error events that
|
|
||||||
might still allow the application to continue running. */
|
|
||||||
final static public Level ERROR = new Level(ERROR_INT, "ERROR", 3);
|
|
||||||
|
|
||||||
/**
|
|
||||||
The <code>WARN</code> level designates potentially harmful situations.
|
|
||||||
*/
|
|
||||||
final static public Level WARN = new Level(WARN_INT, "WARN", 4);
|
|
||||||
|
|
||||||
/**
|
|
||||||
The <code>INFO</code> level designates informational messages
|
|
||||||
that highlight the progress of the application at coarse-grained
|
|
||||||
level. */
|
|
||||||
final static public Level INFO = new Level(INFO_INT, "INFO", 6);
|
|
||||||
|
|
||||||
/**
|
|
||||||
The <code>DEBUG</code> Level designates fine-grained
|
|
||||||
informational events that are most useful to debug an
|
|
||||||
application. */
|
|
||||||
final static public Level DEBUG = new Level(DEBUG_INT, "DEBUG", 7);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The <code>TRACE</code> Level designates finer-grained
|
|
||||||
* informational events than the <code>DEBUG</code level.
|
|
||||||
* @since 1.2.12
|
|
||||||
*/
|
|
||||||
public static final Level TRACE = new Level(TRACE_INT, "TRACE", 7);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
The <code>ALL</code> has the lowest possible rank and is intended to
|
|
||||||
turn on all logging. */
|
|
||||||
final static public Level ALL = new Level(ALL_INT, "ALL", 7);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serialization version id.
|
|
||||||
*/
|
|
||||||
static final long serialVersionUID = 3491141966387921974L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Instantiate a Level object.
|
|
||||||
*/
|
|
||||||
protected
|
|
||||||
Level(int level, String levelStr, int syslogEquivalent) {
|
|
||||||
super(level, levelStr, syslogEquivalent);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Convert the string passed as argument to a level. If the
|
|
||||||
conversion fails, then this method returns {@link #DEBUG}.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
Level toLevel(String sArg) {
|
|
||||||
return (Level) toLevel(sArg, Level.DEBUG);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Convert an integer passed as argument to a level. If the
|
|
||||||
conversion fails, then this method returns {@link #DEBUG}.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
Level toLevel(int val) {
|
|
||||||
return (Level) toLevel(val, Level.DEBUG);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Convert an integer passed as argument to a level. If the
|
|
||||||
conversion fails, then this method returns the specified default.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
Level toLevel(int val, Level defaultLevel) {
|
|
||||||
switch(val) {
|
|
||||||
case ALL_INT: return ALL;
|
|
||||||
case DEBUG_INT: return Level.DEBUG;
|
|
||||||
case INFO_INT: return Level.INFO;
|
|
||||||
case WARN_INT: return Level.WARN;
|
|
||||||
case ERROR_INT: return Level.ERROR;
|
|
||||||
case FATAL_INT: return Level.FATAL;
|
|
||||||
case OFF_INT: return OFF;
|
|
||||||
case TRACE_INT: return Level.TRACE;
|
|
||||||
default: return defaultLevel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Convert the string passed as argument to a level. If the
|
|
||||||
conversion fails, then this method returns the value of
|
|
||||||
<code>defaultLevel</code>.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
Level toLevel(String sArg, Level defaultLevel) {
|
|
||||||
if(sArg == null)
|
|
||||||
return defaultLevel;
|
|
||||||
|
|
||||||
String s = sArg.toUpperCase();
|
|
||||||
|
|
||||||
if(s.equals("ALL")) return Level.ALL;
|
|
||||||
if(s.equals("DEBUG")) return Level.DEBUG;
|
|
||||||
if(s.equals("INFO")) return Level.INFO;
|
|
||||||
if(s.equals("WARN")) return Level.WARN;
|
|
||||||
if(s.equals("ERROR")) return Level.ERROR;
|
|
||||||
if(s.equals("FATAL")) return Level.FATAL;
|
|
||||||
if(s.equals("OFF")) return Level.OFF;
|
|
||||||
if(s.equals("TRACE")) return Level.TRACE;
|
|
||||||
//
|
|
||||||
// For Turkish i problem, see bug 40937
|
|
||||||
//
|
|
||||||
if(s.equals("\u0130NFO")) return Level.INFO;
|
|
||||||
return defaultLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom deserialization of Level.
|
|
||||||
* @param s serialization stream.
|
|
||||||
* @throws IOException if IO exception.
|
|
||||||
* @throws ClassNotFoundException if class not found.
|
|
||||||
*/
|
|
||||||
private void readObject(final ObjectInputStream s) throws IOException, ClassNotFoundException {
|
|
||||||
s.defaultReadObject();
|
|
||||||
level = s.readInt();
|
|
||||||
syslogEquivalent = s.readInt();
|
|
||||||
levelStr = s.readUTF();
|
|
||||||
if (levelStr == null) {
|
|
||||||
levelStr = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serialize level.
|
|
||||||
* @param s serialization stream.
|
|
||||||
* @throws IOException if exception during serialization.
|
|
||||||
*/
|
|
||||||
private void writeObject(final ObjectOutputStream s) throws IOException {
|
|
||||||
s.defaultWriteObject();
|
|
||||||
s.writeInt(level);
|
|
||||||
s.writeInt(syslogEquivalent);
|
|
||||||
s.writeUTF(levelStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolved deserialized level to one of the stock instances.
|
|
||||||
* May be overriden in classes derived from Level.
|
|
||||||
* @return resolved object.
|
|
||||||
* @throws ObjectStreamException if exception during resolution.
|
|
||||||
*/
|
|
||||||
private Object readResolve() throws ObjectStreamException {
|
|
||||||
//
|
|
||||||
// if the deserizalized object is exactly an instance of Level
|
|
||||||
//
|
|
||||||
if (getClass() == Level.class) {
|
|
||||||
return toLevel(level);
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// extension of Level can't substitute stock item
|
|
||||||
//
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,276 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j;
|
|
||||||
|
|
||||||
import org.apache.log4j.spi.LoggerRepository;
|
|
||||||
import org.apache.log4j.spi.LoggerFactory;
|
|
||||||
import org.apache.log4j.spi.RepositorySelector;
|
|
||||||
import org.apache.log4j.spi.DefaultRepositorySelector;
|
|
||||||
import org.apache.log4j.spi.RootLogger;
|
|
||||||
import org.apache.log4j.spi.NOPLoggerRepository;
|
|
||||||
import org.apache.log4j.helpers.Loader;
|
|
||||||
import org.apache.log4j.helpers.OptionConverter;
|
|
||||||
import org.apache.log4j.helpers.LogLog;
|
|
||||||
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use the <code>LogManager</code> class to retreive {@link Logger}
|
|
||||||
* instances or to operate on the current {@link
|
|
||||||
* LoggerRepository}. When the <code>LogManager</code> class is loaded
|
|
||||||
* into memory the default initalzation procedure is inititated. The
|
|
||||||
* default intialization procedure</a> is described in the <a
|
|
||||||
* href="../../../../manual.html#defaultInit">short log4j manual</a>.
|
|
||||||
*
|
|
||||||
* @author Ceki Gülcü */
|
|
||||||
public class LogManager {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This variable is for internal use only. It will
|
|
||||||
* become package protected in future versions.
|
|
||||||
* */
|
|
||||||
static public final String DEFAULT_CONFIGURATION_FILE = "log4j.properties";
|
|
||||||
|
|
||||||
static final String DEFAULT_XML_CONFIGURATION_FILE = "log4j.xml";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This variable is for internal use only. It will
|
|
||||||
* become private in future versions.
|
|
||||||
* */
|
|
||||||
static final public String DEFAULT_CONFIGURATION_KEY="log4j.configuration";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This variable is for internal use only. It will
|
|
||||||
* become private in future versions.
|
|
||||||
* */
|
|
||||||
static final public String CONFIGURATOR_CLASS_KEY="log4j.configuratorClass";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This variable is for internal use only. It will
|
|
||||||
* become private in future versions.
|
|
||||||
*/
|
|
||||||
public static final String DEFAULT_INIT_OVERRIDE_KEY =
|
|
||||||
"log4j.defaultInitOverride";
|
|
||||||
|
|
||||||
|
|
||||||
static private Object guard = null;
|
|
||||||
static private RepositorySelector repositorySelector;
|
|
||||||
|
|
||||||
static {
|
|
||||||
// By default we use a DefaultRepositorySelector which always returns 'h'.
|
|
||||||
Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));
|
|
||||||
repositorySelector = new DefaultRepositorySelector(h);
|
|
||||||
|
|
||||||
/** Search for the properties file log4j.properties in the CLASSPATH. */
|
|
||||||
String override =OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY,
|
|
||||||
null);
|
|
||||||
|
|
||||||
// if there is no default init override, then get the resource
|
|
||||||
// specified by the user or the default config file.
|
|
||||||
if(override == null || "false".equalsIgnoreCase(override)) {
|
|
||||||
|
|
||||||
String configurationOptionStr = OptionConverter.getSystemProperty(
|
|
||||||
DEFAULT_CONFIGURATION_KEY,
|
|
||||||
null);
|
|
||||||
|
|
||||||
String configuratorClassName = OptionConverter.getSystemProperty(
|
|
||||||
CONFIGURATOR_CLASS_KEY,
|
|
||||||
null);
|
|
||||||
|
|
||||||
URL url = null;
|
|
||||||
|
|
||||||
// if the user has not specified the log4j.configuration
|
|
||||||
// property, we search first for the file "log4j.xml" and then
|
|
||||||
// "log4j.properties"
|
|
||||||
if(configurationOptionStr == null) {
|
|
||||||
url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
|
|
||||||
if(url == null) {
|
|
||||||
url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
url = new URL(configurationOptionStr);
|
|
||||||
} catch (MalformedURLException ex) {
|
|
||||||
// so, resource is not a URL:
|
|
||||||
// attempt to get the resource from the class path
|
|
||||||
url = Loader.getResource(configurationOptionStr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have a non-null url, then delegate the rest of the
|
|
||||||
// configuration to the OptionConverter.selectAndConfigure
|
|
||||||
// method.
|
|
||||||
if(url != null) {
|
|
||||||
LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");
|
|
||||||
try {
|
|
||||||
OptionConverter.selectAndConfigure(url, configuratorClassName,
|
|
||||||
LogManager.getLoggerRepository());
|
|
||||||
} catch (NoClassDefFoundError e) {
|
|
||||||
LogLog.warn("Error during default initialization", e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LogLog.debug("Could not find resource: ["+configurationOptionStr+"].");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LogLog.debug("Default initialization of overridden by " +
|
|
||||||
DEFAULT_INIT_OVERRIDE_KEY + "property.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Sets <code>LoggerFactory</code> but only if the correct
|
|
||||||
<em>guard</em> is passed as parameter.
|
|
||||||
|
|
||||||
<p>Initally the guard is null. If the guard is
|
|
||||||
<code>null</code>, then invoking this method sets the logger
|
|
||||||
factory and the guard. Following invocations will throw a {@link
|
|
||||||
IllegalArgumentException}, unless the previously set
|
|
||||||
<code>guard</code> is passed as the second parameter.
|
|
||||||
|
|
||||||
<p>This allows a high-level component to set the {@link
|
|
||||||
RepositorySelector} used by the <code>LogManager</code>.
|
|
||||||
|
|
||||||
<p>For example, when tomcat starts it will be able to install its
|
|
||||||
own repository selector. However, if and when Tomcat is embedded
|
|
||||||
within JBoss, then JBoss will install its own repository selector
|
|
||||||
and Tomcat will use the repository selector set by its container,
|
|
||||||
JBoss. */
|
|
||||||
static
|
|
||||||
public
|
|
||||||
void setRepositorySelector(RepositorySelector selector, Object guard)
|
|
||||||
throws IllegalArgumentException {
|
|
||||||
if((LogManager.guard != null) && (LogManager.guard != guard)) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Attempted to reset the LoggerFactory without possessing the guard.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(selector == null) {
|
|
||||||
throw new IllegalArgumentException("RepositorySelector must be non-null.");
|
|
||||||
}
|
|
||||||
|
|
||||||
LogManager.guard = guard;
|
|
||||||
LogManager.repositorySelector = selector;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method tests if called from a method that
|
|
||||||
* is known to result in class members being abnormally
|
|
||||||
* set to null but is assumed to be harmless since the
|
|
||||||
* all classes are in the process of being unloaded.
|
|
||||||
*
|
|
||||||
* @param ex exception used to determine calling stack.
|
|
||||||
* @return true if calling stack is recognized as likely safe.
|
|
||||||
*/
|
|
||||||
private static boolean isLikelySafeScenario(final Exception ex) {
|
|
||||||
StringWriter stringWriter = new StringWriter();
|
|
||||||
ex.printStackTrace(new PrintWriter(stringWriter));
|
|
||||||
String msg = stringWriter.toString();
|
|
||||||
return msg.indexOf("org.apache.catalina.loader.WebappClassLoader.stop") != -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
public
|
|
||||||
LoggerRepository getLoggerRepository() {
|
|
||||||
if (repositorySelector == null) {
|
|
||||||
repositorySelector = new DefaultRepositorySelector(new NOPLoggerRepository());
|
|
||||||
guard = null;
|
|
||||||
Exception ex = new IllegalStateException("Class invariant violation");
|
|
||||||
String msg =
|
|
||||||
"log4j called after unloading, see http://logging.apache.org/log4j/1.2/faq.html#unload.";
|
|
||||||
if (isLikelySafeScenario(ex)) {
|
|
||||||
LogLog.debug(msg, ex);
|
|
||||||
} else {
|
|
||||||
LogLog.error(msg, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return repositorySelector.getLoggerRepository();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Retrieve the appropriate root logger.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
Logger getRootLogger() {
|
|
||||||
// Delegate the actual manufacturing of the logger to the logger repository.
|
|
||||||
return getLoggerRepository().getRootLogger();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Retrieve the appropriate {@link Logger} instance.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
Logger getLogger(final String name) {
|
|
||||||
// Delegate the actual manufacturing of the logger to the logger repository.
|
|
||||||
return getLoggerRepository().getLogger(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Retrieve the appropriate {@link Logger} instance.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
Logger getLogger(final Class clazz) {
|
|
||||||
// Delegate the actual manufacturing of the logger to the logger repository.
|
|
||||||
return getLoggerRepository().getLogger(clazz.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Retrieve the appropriate {@link Logger} instance.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
Logger getLogger(final String name, final LoggerFactory factory) {
|
|
||||||
// Delegate the actual manufacturing of the logger to the logger repository.
|
|
||||||
return getLoggerRepository().getLogger(name, factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
static
|
|
||||||
Logger exists(final String name) {
|
|
||||||
return getLoggerRepository().exists(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
static
|
|
||||||
Enumeration getCurrentLoggers() {
|
|
||||||
return getLoggerRepository().getCurrentLoggers();
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
static
|
|
||||||
void shutdown() {
|
|
||||||
getLoggerRepository().shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
static
|
|
||||||
void resetConfiguration() {
|
|
||||||
getLoggerRepository().resetConfiguration();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,371 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j;
|
|
||||||
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a base class for LogMF and LogSF parameterized logging classes.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @see org.apache.log4j.LogMF
|
|
||||||
* @see org.apache.log4j.LogSF
|
|
||||||
* @since 1.2.16
|
|
||||||
*/
|
|
||||||
public abstract class LogXF {
|
|
||||||
/**
|
|
||||||
* Trace level.
|
|
||||||
*/
|
|
||||||
protected static final Level TRACE = new Level(5000, "TRACE", 7);
|
|
||||||
/**
|
|
||||||
* Fully Qualified Class Name of this class.
|
|
||||||
*/
|
|
||||||
private static final String FQCN = LogXF.class.getName();
|
|
||||||
|
|
||||||
protected LogXF() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a Boolean instance representing the specified boolean.
|
|
||||||
* Boolean.valueOf was added in JDK 1.4.
|
|
||||||
*
|
|
||||||
* @param b a boolean value.
|
|
||||||
* @return a Boolean instance representing b.
|
|
||||||
*/
|
|
||||||
protected static Boolean valueOf(final boolean b) {
|
|
||||||
if (b) {
|
|
||||||
return Boolean.TRUE;
|
|
||||||
}
|
|
||||||
return Boolean.FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a Character instance representing the specified char.
|
|
||||||
* Character.valueOf was added in JDK 1.5.
|
|
||||||
*
|
|
||||||
* @param c a character value.
|
|
||||||
* @return a Character instance representing c.
|
|
||||||
*/
|
|
||||||
protected static Character valueOf(final char c) {
|
|
||||||
return new Character(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a Byte instance representing the specified byte.
|
|
||||||
* Byte.valueOf was added in JDK 1.5.
|
|
||||||
*
|
|
||||||
* @param b a byte value.
|
|
||||||
* @return a Byte instance representing b.
|
|
||||||
*/
|
|
||||||
protected static Byte valueOf(final byte b) {
|
|
||||||
return new Byte(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a Short instance representing the specified short.
|
|
||||||
* Short.valueOf was added in JDK 1.5.
|
|
||||||
*
|
|
||||||
* @param b a short value.
|
|
||||||
* @return a Byte instance representing b.
|
|
||||||
*/
|
|
||||||
protected static Short valueOf(final short b) {
|
|
||||||
return new Short(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an Integer instance representing the specified int.
|
|
||||||
* Integer.valueOf was added in JDK 1.5.
|
|
||||||
*
|
|
||||||
* @param b an int value.
|
|
||||||
* @return an Integer instance representing b.
|
|
||||||
*/
|
|
||||||
protected static Integer valueOf(final int b) {
|
|
||||||
return new Integer(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a Long instance representing the specified long.
|
|
||||||
* Long.valueOf was added in JDK 1.5.
|
|
||||||
*
|
|
||||||
* @param b a long value.
|
|
||||||
* @return a Long instance representing b.
|
|
||||||
*/
|
|
||||||
protected static Long valueOf(final long b) {
|
|
||||||
return new Long(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a Float instance representing the specified float.
|
|
||||||
* Float.valueOf was added in JDK 1.5.
|
|
||||||
*
|
|
||||||
* @param b a float value.
|
|
||||||
* @return a Float instance representing b.
|
|
||||||
*/
|
|
||||||
protected static Float valueOf(final float b) {
|
|
||||||
return new Float(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a Double instance representing the specified double.
|
|
||||||
* Double.valueOf was added in JDK 1.5.
|
|
||||||
*
|
|
||||||
* @param b a double value.
|
|
||||||
* @return a Byte instance representing b.
|
|
||||||
*/
|
|
||||||
protected static Double valueOf(final double b) {
|
|
||||||
return new Double(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create new array.
|
|
||||||
*
|
|
||||||
* @param param1 parameter 1.
|
|
||||||
* @return new array.
|
|
||||||
*/
|
|
||||||
protected static Object[] toArray(final Object param1) {
|
|
||||||
return new Object[]{
|
|
||||||
param1
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create new array.
|
|
||||||
*
|
|
||||||
* @param param1 parameter 1.
|
|
||||||
* @param param2 parameter 2.
|
|
||||||
* @return new array.
|
|
||||||
*/
|
|
||||||
protected static Object[] toArray(final Object param1,
|
|
||||||
final Object param2) {
|
|
||||||
return new Object[]{
|
|
||||||
param1, param2
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create new array.
|
|
||||||
*
|
|
||||||
* @param param1 parameter 1.
|
|
||||||
* @param param2 parameter 2.
|
|
||||||
* @param param3 parameter 3.
|
|
||||||
* @return new array.
|
|
||||||
*/
|
|
||||||
protected static Object[] toArray(final Object param1,
|
|
||||||
final Object param2,
|
|
||||||
final Object param3) {
|
|
||||||
return new Object[]{
|
|
||||||
param1, param2, param3
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create new array.
|
|
||||||
*
|
|
||||||
* @param param1 parameter 1.
|
|
||||||
* @param param2 parameter 2.
|
|
||||||
* @param param3 parameter 3.
|
|
||||||
* @param param4 parameter 4.
|
|
||||||
* @return new array.
|
|
||||||
*/
|
|
||||||
protected static Object[] toArray(final Object param1,
|
|
||||||
final Object param2,
|
|
||||||
final Object param3,
|
|
||||||
final Object param4) {
|
|
||||||
return new Object[]{
|
|
||||||
param1, param2, param3, param4
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log an entering message at DEBUG level.
|
|
||||||
*
|
|
||||||
* @param logger logger, may not be null.
|
|
||||||
* @param sourceClass source class, may be null.
|
|
||||||
* @param sourceMethod method, may be null.
|
|
||||||
*/
|
|
||||||
public static void entering(final Logger logger,
|
|
||||||
final String sourceClass,
|
|
||||||
final String sourceMethod) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.callAppenders(new LoggingEvent(FQCN, logger, Level.DEBUG,
|
|
||||||
sourceClass + "." + sourceMethod + " ENTRY", null));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log an entering message with a parameter at DEBUG level.
|
|
||||||
*
|
|
||||||
* @param logger logger, may not be null.
|
|
||||||
* @param sourceClass source class, may be null.
|
|
||||||
* @param sourceMethod method, may be null.
|
|
||||||
* @param param parameter, may be null.
|
|
||||||
*/
|
|
||||||
public static void entering(final Logger logger,
|
|
||||||
final String sourceClass,
|
|
||||||
final String sourceMethod,
|
|
||||||
final String param) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
String msg = sourceClass + "." + sourceMethod + " ENTRY " + param;
|
|
||||||
logger.callAppenders(new LoggingEvent(FQCN, logger, Level.DEBUG,
|
|
||||||
msg, null));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log an entering message with a parameter at DEBUG level.
|
|
||||||
*
|
|
||||||
* @param logger logger, may not be null.
|
|
||||||
* @param sourceClass source class, may be null.
|
|
||||||
* @param sourceMethod method, may be null.
|
|
||||||
* @param param parameter, may be null.
|
|
||||||
*/
|
|
||||||
public static void entering(final Logger logger,
|
|
||||||
final String sourceClass,
|
|
||||||
final String sourceMethod,
|
|
||||||
final Object param) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
String msg = sourceClass + "." + sourceMethod + " ENTRY ";
|
|
||||||
if (param == null) {
|
|
||||||
msg += "null";
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
msg += param;
|
|
||||||
} catch(Throwable ex) {
|
|
||||||
msg += "?";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.callAppenders(new LoggingEvent(FQCN, logger, Level.DEBUG,
|
|
||||||
msg, null));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log an entering message with an array of parameters at DEBUG level.
|
|
||||||
*
|
|
||||||
* @param logger logger, may not be null.
|
|
||||||
* @param sourceClass source class, may be null.
|
|
||||||
* @param sourceMethod method, may be null.
|
|
||||||
* @param params parameters, may be null.
|
|
||||||
*/
|
|
||||||
public static void entering(final Logger logger,
|
|
||||||
final String sourceClass,
|
|
||||||
final String sourceMethod,
|
|
||||||
final Object[] params) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
String msg = sourceClass + "." + sourceMethod + " ENTRY ";
|
|
||||||
if (params != null && params.length > 0) {
|
|
||||||
String delim = "{";
|
|
||||||
for (int i = 0; i < params.length; i++) {
|
|
||||||
try {
|
|
||||||
msg += delim + params[i];
|
|
||||||
} catch(Throwable ex) {
|
|
||||||
msg += delim + "?";
|
|
||||||
}
|
|
||||||
delim = ",";
|
|
||||||
}
|
|
||||||
msg += "}";
|
|
||||||
} else {
|
|
||||||
msg += "{}";
|
|
||||||
}
|
|
||||||
logger.callAppenders(new LoggingEvent(FQCN, logger, Level.DEBUG,
|
|
||||||
msg, null));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log an exiting message at DEBUG level.
|
|
||||||
*
|
|
||||||
* @param logger logger, may not be null.
|
|
||||||
* @param sourceClass source class, may be null.
|
|
||||||
* @param sourceMethod method, may be null.
|
|
||||||
*/
|
|
||||||
public static void exiting(final Logger logger,
|
|
||||||
final String sourceClass,
|
|
||||||
final String sourceMethod) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.callAppenders(new LoggingEvent(FQCN, logger, Level.DEBUG,
|
|
||||||
sourceClass + "." + sourceMethod + " RETURN", null));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log an exiting message with result at DEBUG level.
|
|
||||||
*
|
|
||||||
* @param logger logger, may not be null.
|
|
||||||
* @param sourceClass source class, may be null.
|
|
||||||
* @param sourceMethod method, may be null.
|
|
||||||
* @param result result, may be null.
|
|
||||||
*/
|
|
||||||
public static void exiting(
|
|
||||||
final Logger logger,
|
|
||||||
final String sourceClass,
|
|
||||||
final String sourceMethod,
|
|
||||||
final String result) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.callAppenders(new LoggingEvent(FQCN, logger, Level.DEBUG,
|
|
||||||
sourceClass + "." + sourceMethod + " RETURN " + result, null));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log an exiting message with result at DEBUG level.
|
|
||||||
*
|
|
||||||
* @param logger logger, may not be null.
|
|
||||||
* @param sourceClass source class, may be null.
|
|
||||||
* @param sourceMethod method, may be null.
|
|
||||||
* @param result result, may be null.
|
|
||||||
*/
|
|
||||||
public static void exiting(
|
|
||||||
final Logger logger,
|
|
||||||
final String sourceClass,
|
|
||||||
final String sourceMethod,
|
|
||||||
final Object result) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
String msg = sourceClass + "." + sourceMethod + " RETURN ";
|
|
||||||
if (result == null) {
|
|
||||||
msg += "null";
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
msg += result;
|
|
||||||
} catch(Throwable ex) {
|
|
||||||
msg += "?";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.callAppenders(new LoggingEvent(FQCN, logger, Level.DEBUG,
|
|
||||||
msg, null));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs a throwing message at DEBUG level.
|
|
||||||
*
|
|
||||||
* @param logger logger, may not be null.
|
|
||||||
* @param sourceClass source class, may be null.
|
|
||||||
* @param sourceMethod method, may be null.
|
|
||||||
* @param thrown throwable, may be null.
|
|
||||||
*/
|
|
||||||
public static void throwing(
|
|
||||||
final Logger logger,
|
|
||||||
final String sourceClass,
|
|
||||||
final String sourceMethod,
|
|
||||||
final Throwable thrown) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.callAppenders(new LoggingEvent(FQCN, logger, Level.DEBUG,
|
|
||||||
sourceClass + "." + sourceMethod + " THROW", thrown));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,212 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j;
|
|
||||||
|
|
||||||
import org.apache.log4j.spi.LoggerFactory;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
This is the central class in the log4j package. Most logging
|
|
||||||
operations, except configuration, are done through this class.
|
|
||||||
|
|
||||||
@since log4j 1.2
|
|
||||||
|
|
||||||
@author Ceki Gülcü */
|
|
||||||
public class Logger extends Category {
|
|
||||||
|
|
||||||
/**
|
|
||||||
The fully qualified name of the Logger class. See also the
|
|
||||||
getFQCN method. */
|
|
||||||
private static final String FQCN = Logger.class.getName();
|
|
||||||
|
|
||||||
|
|
||||||
protected
|
|
||||||
Logger(String name) {
|
|
||||||
super(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Log a message object with the {@link Level#FINE FINE} level which
|
|
||||||
is just an alias for the {@link Level#DEBUG DEBUG} level.
|
|
||||||
|
|
||||||
<p>This method first checks if this category is <code>DEBUG</code>
|
|
||||||
enabled by comparing the level of this category with the {@link
|
|
||||||
Level#DEBUG DEBUG} level. If this category is
|
|
||||||
<code>DEBUG</code> enabled, then it converts the message object
|
|
||||||
(passed as parameter) to a string by invoking the appropriate
|
|
||||||
{@link org.apache.log4j.or.ObjectRenderer}. It then proceeds to call all the
|
|
||||||
registered appenders in this category and also higher in the
|
|
||||||
hierarchy depending on the value of the additivity flag.
|
|
||||||
|
|
||||||
<p><b>WARNING</b> Note that passing a {@link Throwable} to this
|
|
||||||
method will print the name of the <code>Throwable</code> but no
|
|
||||||
stack trace. To print a stack trace use the {@link #debug(Object,
|
|
||||||
Throwable)} form instead.
|
|
||||||
|
|
||||||
@param message the message object to log. */
|
|
||||||
//public
|
|
||||||
//void fine(Object message) {
|
|
||||||
// if(repository.isDisabled(Level.DEBUG_INT))
|
|
||||||
// return;
|
|
||||||
// if(Level.DEBUG.isGreaterOrEqual(this.getChainedLevel())) {
|
|
||||||
// forcedLog(FQCN, Level.DEBUG, message, null);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Log a message object with the <code>FINE</code> level including
|
|
||||||
the stack trace of the {@link Throwable} <code>t</code> passed as
|
|
||||||
parameter.
|
|
||||||
|
|
||||||
<p>See {@link #fine(Object)} form for more detailed information.
|
|
||||||
|
|
||||||
@param message the message object to log.
|
|
||||||
@param t the exception to log, including its stack trace. */
|
|
||||||
//public
|
|
||||||
//void fine(Object message, Throwable t) {
|
|
||||||
// if(repository.isDisabled(Level.DEBUG_INT))
|
|
||||||
// return;
|
|
||||||
// if(Level.DEBUG.isGreaterOrEqual(this.getChainedLevel()))
|
|
||||||
// forcedLog(FQCN, Level.FINE, message, t);
|
|
||||||
//}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve a logger named according to the value of the
|
|
||||||
* <code>name</code> parameter. If the named logger already exists,
|
|
||||||
* then the existing instance will be returned. Otherwise, a new
|
|
||||||
* instance is created.
|
|
||||||
*
|
|
||||||
* <p>By default, loggers do not have a set level but inherit it
|
|
||||||
* from their neareast ancestor with a set level. This is one of the
|
|
||||||
* central features of log4j.
|
|
||||||
*
|
|
||||||
* @param name The name of the logger to retrieve.
|
|
||||||
*/
|
|
||||||
static
|
|
||||||
public
|
|
||||||
Logger getLogger(String name) {
|
|
||||||
return LogManager.getLogger(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shorthand for <code>getLogger(clazz.getName())</code>.
|
|
||||||
*
|
|
||||||
* @param clazz The name of <code>clazz</code> will be used as the
|
|
||||||
* name of the logger to retrieve. See {@link #getLogger(String)}
|
|
||||||
* for more detailed information.
|
|
||||||
*/
|
|
||||||
static
|
|
||||||
public
|
|
||||||
Logger getLogger(Class clazz) {
|
|
||||||
return LogManager.getLogger(clazz.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the root logger for the current logger repository.
|
|
||||||
* <p>
|
|
||||||
* The {@link #getName Logger.getName()} method for the root logger always returns
|
|
||||||
* stirng value: "root". However, calling
|
|
||||||
* <code>Logger.getLogger("root")</code> does not retrieve the root
|
|
||||||
* logger but a logger just under root named "root".
|
|
||||||
* <p>
|
|
||||||
* In other words, calling this method is the only way to retrieve the
|
|
||||||
* root logger.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
Logger getRootLogger() {
|
|
||||||
return LogManager.getRootLogger();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Like {@link #getLogger(String)} except that the type of logger
|
|
||||||
instantiated depends on the type returned by the {@link
|
|
||||||
LoggerFactory#makeNewLoggerInstance} method of the
|
|
||||||
<code>factory</code> parameter.
|
|
||||||
|
|
||||||
<p>This method is intended to be used by sub-classes.
|
|
||||||
|
|
||||||
@param name The name of the logger to retrieve.
|
|
||||||
|
|
||||||
@param factory A {@link LoggerFactory} implementation that will
|
|
||||||
actually create a new Instance.
|
|
||||||
|
|
||||||
@since 0.8.5 */
|
|
||||||
public
|
|
||||||
static
|
|
||||||
Logger getLogger(String name, LoggerFactory factory) {
|
|
||||||
return LogManager.getLogger(name, factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log a message object with the {@link org.apache.log4j.Level#TRACE TRACE} level.
|
|
||||||
*
|
|
||||||
* @param message the message object to log.
|
|
||||||
* @see #debug(Object) for an explanation of the logic applied.
|
|
||||||
* @since 1.2.12
|
|
||||||
*/
|
|
||||||
public void trace(Object message) {
|
|
||||||
if (repository.isDisabled(Level.TRACE_INT)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Level.TRACE.isGreaterOrEqual(this.getEffectiveLevel())) {
|
|
||||||
forcedLog(FQCN, Level.TRACE, message, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log a message object with the <code>TRACE</code> level including the
|
|
||||||
* stack trace of the {@link Throwable}<code>t</code> passed as parameter.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* See {@link #debug(Object)} form for more detailed information.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param message the message object to log.
|
|
||||||
* @param t the exception to log, including its stack trace.
|
|
||||||
* @since 1.2.12
|
|
||||||
*/
|
|
||||||
public void trace(Object message, Throwable t) {
|
|
||||||
if (repository.isDisabled(Level.TRACE_INT)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Level.TRACE.isGreaterOrEqual(this.getEffectiveLevel())) {
|
|
||||||
forcedLog(FQCN, Level.TRACE, message, t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether this category is enabled for the TRACE Level.
|
|
||||||
* @since 1.2.12
|
|
||||||
*
|
|
||||||
* @return boolean - <code>true</code> if this category is enabled for level
|
|
||||||
* TRACE, <code>false</code> otherwise.
|
|
||||||
*/
|
|
||||||
public boolean isTraceEnabled() {
|
|
||||||
if (repository.isDisabled(Level.TRACE_INT)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Level.TRACE.isGreaterOrEqual(this.getEffectiveLevel());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,187 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j;
|
|
||||||
|
|
||||||
import java.util.Hashtable;
|
|
||||||
import org.apache.log4j.helpers.Loader;
|
|
||||||
import org.apache.log4j.helpers.ThreadLocalMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
The MDC class is similar to the {@link NDC} class except that it is
|
|
||||||
based on a map instead of a stack. It provides <em>mapped
|
|
||||||
diagnostic contexts</em>. A <em>Mapped Diagnostic Context</em>, or
|
|
||||||
MDC in short, is an instrument for distinguishing interleaved log
|
|
||||||
output from different sources. Log output is typically interleaved
|
|
||||||
when a server handles multiple clients near-simultaneously.
|
|
||||||
|
|
||||||
<p><b><em>The MDC is managed on a per thread basis</em></b>. A
|
|
||||||
child thread automatically inherits a <em>copy</em> of the mapped
|
|
||||||
diagnostic context of its parent.
|
|
||||||
|
|
||||||
<p>The MDC class requires JDK 1.2 or above. Under JDK 1.1 the MDC
|
|
||||||
will always return empty values but otherwise will not affect or
|
|
||||||
harm your application.
|
|
||||||
|
|
||||||
@since 1.2
|
|
||||||
|
|
||||||
@author Ceki Gülcü */
|
|
||||||
public class MDC {
|
|
||||||
|
|
||||||
final static MDC mdc = new MDC();
|
|
||||||
|
|
||||||
static final int HT_SIZE = 7;
|
|
||||||
|
|
||||||
boolean java1;
|
|
||||||
|
|
||||||
Object tlm;
|
|
||||||
|
|
||||||
private
|
|
||||||
MDC() {
|
|
||||||
java1 = Loader.isJava1();
|
|
||||||
if(!java1) {
|
|
||||||
tlm = new ThreadLocalMap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Put a context value (the <code>o</code> parameter) as identified
|
|
||||||
with the <code>key</code> parameter into the current thread's
|
|
||||||
context map.
|
|
||||||
|
|
||||||
<p>If the current thread does not have a context map it is
|
|
||||||
created as a side effect.
|
|
||||||
|
|
||||||
*/
|
|
||||||
static
|
|
||||||
public
|
|
||||||
void put(String key, Object o) {
|
|
||||||
if (mdc != null) {
|
|
||||||
mdc.put0(key, o);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get the context identified by the <code>key</code> parameter.
|
|
||||||
|
|
||||||
<p>This method has no side effects.
|
|
||||||
*/
|
|
||||||
static
|
|
||||||
public
|
|
||||||
Object get(String key) {
|
|
||||||
if (mdc != null) {
|
|
||||||
return mdc.get0(key);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Remove the the context identified by the <code>key</code>
|
|
||||||
parameter.
|
|
||||||
|
|
||||||
*/
|
|
||||||
static
|
|
||||||
public
|
|
||||||
void remove(String key) {
|
|
||||||
if (mdc != null) {
|
|
||||||
mdc.remove0(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current thread's MDC as a hashtable. This method is
|
|
||||||
* intended to be used internally.
|
|
||||||
* */
|
|
||||||
public static Hashtable getContext() {
|
|
||||||
if (mdc != null) {
|
|
||||||
return mdc.getContext0();
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove all values from the MDC.
|
|
||||||
* @since 1.2.16
|
|
||||||
*/
|
|
||||||
public static void clear() {
|
|
||||||
if (mdc != null) {
|
|
||||||
mdc.clear0();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private
|
|
||||||
void put0(String key, Object o) {
|
|
||||||
if(java1 || tlm == null) {
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
|
|
||||||
if(ht == null) {
|
|
||||||
ht = new Hashtable(HT_SIZE);
|
|
||||||
((ThreadLocalMap)tlm).set(ht);
|
|
||||||
}
|
|
||||||
ht.put(key, o);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private
|
|
||||||
Object get0(String key) {
|
|
||||||
if(java1 || tlm == null) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
|
|
||||||
if(ht != null && key != null) {
|
|
||||||
return ht.get(key);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private
|
|
||||||
void remove0(String key) {
|
|
||||||
if(!java1 && tlm != null) {
|
|
||||||
Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
|
|
||||||
if(ht != null) {
|
|
||||||
ht.remove(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private
|
|
||||||
Hashtable getContext0() {
|
|
||||||
if(java1 || tlm == null) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return (Hashtable) ((ThreadLocalMap)tlm).get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private
|
|
||||||
void clear0() {
|
|
||||||
if(!java1 && tlm != null) {
|
|
||||||
Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
|
|
||||||
if(ht != null) {
|
|
||||||
ht.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,436 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Contributors: Dan Milstein
|
|
||||||
// Ray Millard
|
|
||||||
|
|
||||||
package org.apache.log4j;
|
|
||||||
|
|
||||||
import java.util.Hashtable;
|
|
||||||
import java.util.Stack;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
import org.apache.log4j.helpers.LogLog;
|
|
||||||
|
|
||||||
/**
|
|
||||||
The NDC class implements <i>nested diagnostic contexts</i> as
|
|
||||||
defined by Neil Harrison in the article "Patterns for Logging
|
|
||||||
Diagnostic Messages" part of the book "<i>Pattern Languages of
|
|
||||||
Program Design 3</i>" edited by Martin et al.
|
|
||||||
|
|
||||||
<p>A Nested Diagnostic Context, or NDC in short, is an instrument
|
|
||||||
to distinguish interleaved log output from different sources. Log
|
|
||||||
output is typically interleaved when a server handles multiple
|
|
||||||
clients near-simultaneously.
|
|
||||||
|
|
||||||
<p>Interleaved log output can still be meaningful if each log entry
|
|
||||||
from different contexts had a distinctive stamp. This is where NDCs
|
|
||||||
come into play.
|
|
||||||
|
|
||||||
<p><em><b>Note that NDCs are managed on a per thread
|
|
||||||
basis</b></em>. NDC operations such as {@link #push push}, {@link
|
|
||||||
#pop}, {@link #clear}, {@link #getDepth} and {@link #setMaxDepth}
|
|
||||||
affect the NDC of the <em>current</em> thread only. NDCs of other
|
|
||||||
threads remain unaffected.
|
|
||||||
|
|
||||||
<p>For example, a servlet can build a per client request NDC
|
|
||||||
consisting the clients host name and other information contained in
|
|
||||||
the the request. <em>Cookies</em> are another source of distinctive
|
|
||||||
information. To build an NDC one uses the {@link #push push}
|
|
||||||
operation. Simply put,
|
|
||||||
|
|
||||||
<p><ul>
|
|
||||||
<li>Contexts can be nested.
|
|
||||||
|
|
||||||
<p><li>When entering a context, call <code>NDC.push</code>. As a
|
|
||||||
side effect, if there is no nested diagnostic context for the
|
|
||||||
current thread, this method will create it.
|
|
||||||
|
|
||||||
<p><li>When leaving a context, call <code>NDC.pop</code>.
|
|
||||||
|
|
||||||
<p><li><b>When exiting a thread make sure to call {@link #remove
|
|
||||||
NDC.remove()}</b>.
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>There is no penalty for forgetting to match each
|
|
||||||
<code>push</code> operation with a corresponding <code>pop</code>,
|
|
||||||
except the obvious mismatch between the real application context
|
|
||||||
and the context set in the NDC.
|
|
||||||
|
|
||||||
<p>If configured to do so, {@link PatternLayout} and {@link
|
|
||||||
TTCCLayout} instances automatically retrieve the nested diagnostic
|
|
||||||
context for the current thread without any user intervention.
|
|
||||||
Hence, even if a servlet is serving multiple clients
|
|
||||||
simultaneously, the logs emanating from the same code (belonging to
|
|
||||||
the same category) can still be distinguished because each client
|
|
||||||
request will have a different NDC tag.
|
|
||||||
|
|
||||||
<p>Heavy duty systems should call the {@link #remove} method when
|
|
||||||
leaving the running method of a thread. This ensures that the memory
|
|
||||||
used by the thread can be freed by the Java garbage
|
|
||||||
collector. There is a mechanism to lazily remove references to dead
|
|
||||||
threads. In practice, this means that you can be a little sloppy
|
|
||||||
and sometimes forget to call {@link #remove} before exiting a
|
|
||||||
thread.
|
|
||||||
|
|
||||||
<p>A thread may inherit the nested diagnostic context of another
|
|
||||||
(possibly parent) thread using the {@link #inherit inherit}
|
|
||||||
method. A thread may obtain a copy of its NDC with the {@link
|
|
||||||
#cloneStack cloneStack} method and pass the reference to any other
|
|
||||||
thread, in particular to a child.
|
|
||||||
|
|
||||||
@author Ceki Gülcü
|
|
||||||
@since 0.7.0
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class NDC {
|
|
||||||
|
|
||||||
// The synchronized keyword is not used in this class. This may seem
|
|
||||||
// dangerous, especially since the class will be used by
|
|
||||||
// multiple-threads. In particular, all threads share the same
|
|
||||||
// hashtable (the "ht" variable). This is OK since java hashtables
|
|
||||||
// are thread safe. Same goes for Stacks.
|
|
||||||
|
|
||||||
// More importantly, when inheriting diagnostic contexts the child
|
|
||||||
// thread is handed a clone of the parent's NDC. It follows that
|
|
||||||
// each thread has its own NDC (i.e. stack).
|
|
||||||
|
|
||||||
static Hashtable ht = new Hashtable();
|
|
||||||
|
|
||||||
static int pushCounter = 0; // the number of times push has been called
|
|
||||||
// after the latest call to lazyRemove
|
|
||||||
|
|
||||||
// The number of times we allow push to be called before we call lazyRemove
|
|
||||||
// 5 is a relatively small number. As such, lazyRemove is not called too
|
|
||||||
// frequently. We thus avoid the cost of creating an Enumeration too often.
|
|
||||||
// The higher this number, the longer is the avarage period for which all
|
|
||||||
// logging calls in all threads are blocked.
|
|
||||||
static final int REAP_THRESHOLD = 5;
|
|
||||||
|
|
||||||
// No instances allowed.
|
|
||||||
private NDC() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get NDC stack for current thread.
|
|
||||||
* @return NDC stack for current thread.
|
|
||||||
*/
|
|
||||||
private static Stack getCurrentStack() {
|
|
||||||
if (ht != null) {
|
|
||||||
return (Stack) ht.get(Thread.currentThread());
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Clear any nested diagnostic information if any. This method is
|
|
||||||
useful in cases where the same thread can be potentially used
|
|
||||||
over and over in different unrelated contexts.
|
|
||||||
|
|
||||||
<p>This method is equivalent to calling the {@link #setMaxDepth}
|
|
||||||
method with a zero <code>maxDepth</code> argument.
|
|
||||||
|
|
||||||
@since 0.8.4c */
|
|
||||||
public
|
|
||||||
static
|
|
||||||
void clear() {
|
|
||||||
Stack stack = getCurrentStack();
|
|
||||||
if(stack != null)
|
|
||||||
stack.setSize(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Clone the diagnostic context for the current thread.
|
|
||||||
|
|
||||||
<p>Internally a diagnostic context is represented as a stack. A
|
|
||||||
given thread can supply the stack (i.e. diagnostic context) to a
|
|
||||||
child thread so that the child can inherit the parent thread's
|
|
||||||
diagnostic context.
|
|
||||||
|
|
||||||
<p>The child thread uses the {@link #inherit inherit} method to
|
|
||||||
inherit the parent's diagnostic context.
|
|
||||||
|
|
||||||
@return Stack A clone of the current thread's diagnostic context.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
Stack cloneStack() {
|
|
||||||
Stack stack = getCurrentStack();
|
|
||||||
if(stack == null)
|
|
||||||
return null;
|
|
||||||
else {
|
|
||||||
return (Stack) stack.clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Inherit the diagnostic context of another thread.
|
|
||||||
|
|
||||||
<p>The parent thread can obtain a reference to its diagnostic
|
|
||||||
context using the {@link #cloneStack} method. It should
|
|
||||||
communicate this information to its child so that it may inherit
|
|
||||||
the parent's diagnostic context.
|
|
||||||
|
|
||||||
<p>The parent's diagnostic context is cloned before being
|
|
||||||
inherited. In other words, once inherited, the two diagnostic
|
|
||||||
contexts can be managed independently.
|
|
||||||
|
|
||||||
<p>In java, a child thread cannot obtain a reference to its
|
|
||||||
parent, unless it is directly handed the reference. Consequently,
|
|
||||||
there is no client-transparent way of inheriting diagnostic
|
|
||||||
contexts. Do you know any solution to this problem?
|
|
||||||
|
|
||||||
@param stack The diagnostic context of the parent thread.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
void inherit(Stack stack) {
|
|
||||||
if(stack != null)
|
|
||||||
ht.put(Thread.currentThread(), stack);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
<font color="#FF4040"><b>Never use this method directly, use the {@link
|
|
||||||
org.apache.log4j.spi.LoggingEvent#getNDC} method instead</b></font>.
|
|
||||||
*/
|
|
||||||
static
|
|
||||||
public
|
|
||||||
String get() {
|
|
||||||
Stack s = getCurrentStack();
|
|
||||||
if(s != null && !s.isEmpty())
|
|
||||||
return ((DiagnosticContext) s.peek()).fullMessage;
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current nesting depth of this diagnostic context.
|
|
||||||
*
|
|
||||||
* @see #setMaxDepth
|
|
||||||
* @since 0.7.5
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
int getDepth() {
|
|
||||||
Stack stack = getCurrentStack();
|
|
||||||
if(stack == null)
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return stack.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
private
|
|
||||||
static
|
|
||||||
void lazyRemove() {
|
|
||||||
if (ht == null) return;
|
|
||||||
|
|
||||||
// The synchronization on ht is necessary to prevent JDK 1.2.x from
|
|
||||||
// throwing ConcurrentModificationExceptions at us. This sucks BIG-TIME.
|
|
||||||
// One solution is to write our own hashtable implementation.
|
|
||||||
Vector v;
|
|
||||||
|
|
||||||
synchronized(ht) {
|
|
||||||
// Avoid calling clean-up too often.
|
|
||||||
if(++pushCounter <= REAP_THRESHOLD) {
|
|
||||||
return; // We release the lock ASAP.
|
|
||||||
} else {
|
|
||||||
pushCounter = 0; // OK let's do some work.
|
|
||||||
}
|
|
||||||
|
|
||||||
int misses = 0;
|
|
||||||
v = new Vector();
|
|
||||||
Enumeration enumeration = ht.keys();
|
|
||||||
// We give up after 4 straigt missses. That is 4 consecutive
|
|
||||||
// inspected threads in 'ht' that turn out to be alive.
|
|
||||||
// The higher the proportion on dead threads in ht, the higher the
|
|
||||||
// chances of removal.
|
|
||||||
while(enumeration.hasMoreElements() && (misses <= 4)) {
|
|
||||||
Thread t = (Thread) enumeration.nextElement();
|
|
||||||
if(t.isAlive()) {
|
|
||||||
misses++;
|
|
||||||
} else {
|
|
||||||
misses = 0;
|
|
||||||
v.addElement(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // synchronized
|
|
||||||
|
|
||||||
int size = v.size();
|
|
||||||
for(int i = 0; i < size; i++) {
|
|
||||||
Thread t = (Thread) v.elementAt(i);
|
|
||||||
LogLog.debug("Lazy NDC removal for thread [" + t.getName() + "] ("+
|
|
||||||
ht.size() + ").");
|
|
||||||
ht.remove(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Clients should call this method before leaving a diagnostic
|
|
||||||
context.
|
|
||||||
|
|
||||||
<p>The returned value is the value that was pushed last. If no
|
|
||||||
context is available, then the empty string "" is returned.
|
|
||||||
|
|
||||||
@return String The innermost diagnostic context.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
String pop() {
|
|
||||||
Stack stack = getCurrentStack();
|
|
||||||
if(stack != null && !stack.isEmpty())
|
|
||||||
return ((DiagnosticContext) stack.pop()).message;
|
|
||||||
else
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Looks at the last diagnostic context at the top of this NDC
|
|
||||||
without removing it.
|
|
||||||
|
|
||||||
<p>The returned value is the value that was pushed last. If no
|
|
||||||
context is available, then the empty string "" is returned.
|
|
||||||
|
|
||||||
@return String The innermost diagnostic context.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
String peek() {
|
|
||||||
Stack stack = getCurrentStack();
|
|
||||||
if(stack != null && !stack.isEmpty())
|
|
||||||
return ((DiagnosticContext) stack.peek()).message;
|
|
||||||
else
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Push new diagnostic context information for the current thread.
|
|
||||||
|
|
||||||
<p>The contents of the <code>message</code> parameter is
|
|
||||||
determined solely by the client.
|
|
||||||
|
|
||||||
@param message The new diagnostic context information. */
|
|
||||||
public
|
|
||||||
static
|
|
||||||
void push(String message) {
|
|
||||||
Stack stack = getCurrentStack();
|
|
||||||
|
|
||||||
if(stack == null) {
|
|
||||||
DiagnosticContext dc = new DiagnosticContext(message, null);
|
|
||||||
stack = new Stack();
|
|
||||||
Thread key = Thread.currentThread();
|
|
||||||
ht.put(key, stack);
|
|
||||||
stack.push(dc);
|
|
||||||
} else if (stack.isEmpty()) {
|
|
||||||
DiagnosticContext dc = new DiagnosticContext(message, null);
|
|
||||||
stack.push(dc);
|
|
||||||
} else {
|
|
||||||
DiagnosticContext parent = (DiagnosticContext) stack.peek();
|
|
||||||
stack.push(new DiagnosticContext(message, parent));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Remove the diagnostic context for this thread.
|
|
||||||
|
|
||||||
<p>Each thread that created a diagnostic context by calling
|
|
||||||
{@link #push} should call this method before exiting. Otherwise,
|
|
||||||
the memory used by the <b>thread</b> cannot be reclaimed by the
|
|
||||||
VM.
|
|
||||||
|
|
||||||
<p>As this is such an important problem in heavy duty systems and
|
|
||||||
because it is difficult to always guarantee that the remove
|
|
||||||
method is called before exiting a thread, this method has been
|
|
||||||
augmented to lazily remove references to dead threads. In
|
|
||||||
practice, this means that you can be a little sloppy and
|
|
||||||
occasionally forget to call {@link #remove} before exiting a
|
|
||||||
thread. However, you must call <code>remove</code> sometime. If
|
|
||||||
you never call it, then your application is sure to running out of
|
|
||||||
memory.
|
|
||||||
|
|
||||||
*/
|
|
||||||
static
|
|
||||||
public
|
|
||||||
void remove() {
|
|
||||||
if (ht != null) {
|
|
||||||
ht.remove(Thread.currentThread());
|
|
||||||
|
|
||||||
// Lazily remove dead-thread references in ht.
|
|
||||||
lazyRemove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set maximum depth of this diagnostic context. If the current
|
|
||||||
depth is smaller or equal to <code>maxDepth</code>, then no
|
|
||||||
action is taken.
|
|
||||||
|
|
||||||
<p>This method is a convenient alternative to multiple {@link
|
|
||||||
#pop} calls. Moreover, it is often the case that at the end of
|
|
||||||
complex call sequences, the depth of the NDC is
|
|
||||||
unpredictable. The <code>setMaxDepth</code> method circumvents
|
|
||||||
this problem.
|
|
||||||
|
|
||||||
<p>For example, the combination
|
|
||||||
<pre>
|
|
||||||
void foo() {
|
|
||||||
int depth = NDC.getDepth();
|
|
||||||
|
|
||||||
... complex sequence of calls
|
|
||||||
|
|
||||||
NDC.setMaxDepth(depth);
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
ensures that between the entry and exit of foo the depth of the
|
|
||||||
diagnostic stack is conserved.
|
|
||||||
|
|
||||||
@see #getDepth
|
|
||||||
@since 0.7.5 */
|
|
||||||
static
|
|
||||||
public
|
|
||||||
void setMaxDepth(int maxDepth) {
|
|
||||||
Stack stack = getCurrentStack();
|
|
||||||
if(stack != null && maxDepth < stack.size())
|
|
||||||
stack.setSize(maxDepth);
|
|
||||||
}
|
|
||||||
|
|
||||||
// =====================================================================
|
|
||||||
private static class DiagnosticContext {
|
|
||||||
|
|
||||||
String fullMessage;
|
|
||||||
String message;
|
|
||||||
|
|
||||||
DiagnosticContext(String message, DiagnosticContext parent) {
|
|
||||||
this.message = message;
|
|
||||||
if(parent != null) {
|
|
||||||
fullMessage = parent.fullMessage + ' ' + message;
|
|
||||||
} else {
|
|
||||||
fullMessage = message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,511 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j;
|
|
||||||
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
import org.apache.log4j.helpers.PatternParser;
|
|
||||||
import org.apache.log4j.helpers.PatternConverter;
|
|
||||||
|
|
||||||
|
|
||||||
// Contributors: Nelson Minar <nelson@monkey.org>
|
|
||||||
// Anders Kristensen <akristensen@dynamicsoft.com>
|
|
||||||
|
|
||||||
/**
|
|
||||||
|
|
||||||
A flexible layout configurable with pattern string.
|
|
||||||
|
|
||||||
This code is known to have synchronization and other issues
|
|
||||||
which are not present in org.apache.log4j.EnhancedPatternLayout.
|
|
||||||
EnhancedPatternLayout should be used in preference to PatternLayout.
|
|
||||||
EnhancedPatternLayout is distributed in the log4j extras companion.
|
|
||||||
|
|
||||||
<p>The goal of this class is to {@link #format format} a {@link
|
|
||||||
LoggingEvent} and return the results as a String. The results
|
|
||||||
depend on the <em>conversion pattern</em>.
|
|
||||||
|
|
||||||
<p>The conversion pattern is closely related to the conversion
|
|
||||||
pattern of the printf function in C. A conversion pattern is
|
|
||||||
composed of literal text and format control expressions called
|
|
||||||
<em>conversion specifiers</em>.
|
|
||||||
|
|
||||||
<p><i>You are free to insert any literal text within the conversion
|
|
||||||
pattern.</i>
|
|
||||||
|
|
||||||
<p>Each conversion specifier starts with a percent sign (%) and is
|
|
||||||
followed by optional <em>format modifiers</em> and a <em>conversion
|
|
||||||
character</em>. The conversion character specifies the type of
|
|
||||||
data, e.g. category, priority, date, thread name. The format
|
|
||||||
modifiers control such things as field width, padding, left and
|
|
||||||
right justification. The following is a simple example.
|
|
||||||
|
|
||||||
<p>Let the conversion pattern be <b>"%-5p [%t]: %m%n"</b> and assume
|
|
||||||
that the log4j environment was set to use a PatternLayout. Then the
|
|
||||||
statements
|
|
||||||
<pre>
|
|
||||||
Category root = Category.getRoot();
|
|
||||||
root.debug("Message 1");
|
|
||||||
root.warn("Message 2");
|
|
||||||
</pre>
|
|
||||||
would yield the output
|
|
||||||
<pre>
|
|
||||||
DEBUG [main]: Message 1
|
|
||||||
WARN [main]: Message 2
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>Note that there is no explicit separator between text and
|
|
||||||
conversion specifiers. The pattern parser knows when it has reached
|
|
||||||
the end of a conversion specifier when it reads a conversion
|
|
||||||
character. In the example above the conversion specifier
|
|
||||||
<b>%-5p</b> means the priority of the logging event should be left
|
|
||||||
justified to a width of five characters.
|
|
||||||
|
|
||||||
The recognized conversion characters are
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<table border="1" CELLPADDING="8">
|
|
||||||
<th>Conversion Character</th>
|
|
||||||
<th>Effect</th>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center><b>c</b></td>
|
|
||||||
|
|
||||||
<td>Used to output the category of the logging event. The
|
|
||||||
category conversion specifier can be optionally followed by
|
|
||||||
<em>precision specifier</em>, that is a decimal constant in
|
|
||||||
brackets.
|
|
||||||
|
|
||||||
<p>If a precision specifier is given, then only the corresponding
|
|
||||||
number of right most components of the category name will be
|
|
||||||
printed. By default the category name is printed in full.
|
|
||||||
|
|
||||||
<p>For example, for the category name "a.b.c" the pattern
|
|
||||||
<b>%c{2}</b> will output "b.c".
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center><b>C</b></td>
|
|
||||||
|
|
||||||
<td>Used to output the fully qualified class name of the caller
|
|
||||||
issuing the logging request. This conversion specifier
|
|
||||||
can be optionally followed by <em>precision specifier</em>, that
|
|
||||||
is a decimal constant in brackets.
|
|
||||||
|
|
||||||
<p>If a precision specifier is given, then only the corresponding
|
|
||||||
number of right most components of the class name will be
|
|
||||||
printed. By default the class name is output in fully qualified form.
|
|
||||||
|
|
||||||
<p>For example, for the class name "org.apache.xyz.SomeClass", the
|
|
||||||
pattern <b>%C{1}</b> will output "SomeClass".
|
|
||||||
|
|
||||||
<p><b>WARNING</b> Generating the caller class information is
|
|
||||||
slow. Thus, use should be avoided unless execution speed is
|
|
||||||
not an issue.
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr> <td align=center><b>d</b></td> <td>Used to output the date of
|
|
||||||
the logging event. The date conversion specifier may be
|
|
||||||
followed by a <em>date format specifier</em> enclosed between
|
|
||||||
braces. For example, <b>%d{HH:mm:ss,SSS}</b> or
|
|
||||||
<b>%d{dd MMM yyyy HH:mm:ss,SSS}</b>. If no
|
|
||||||
date format specifier is given then ISO8601 format is
|
|
||||||
assumed.
|
|
||||||
|
|
||||||
<p>The date format specifier admits the same syntax as the
|
|
||||||
time pattern string of the {@link
|
|
||||||
java.text.SimpleDateFormat}. Although part of the standard
|
|
||||||
JDK, the performance of <code>SimpleDateFormat</code> is
|
|
||||||
quite poor.
|
|
||||||
|
|
||||||
<p>For better results it is recommended to use the log4j date
|
|
||||||
formatters. These can be specified using one of the strings
|
|
||||||
"ABSOLUTE", "DATE" and "ISO8601" for specifying {@link
|
|
||||||
org.apache.log4j.helpers.AbsoluteTimeDateFormat
|
|
||||||
AbsoluteTimeDateFormat}, {@link
|
|
||||||
org.apache.log4j.helpers.DateTimeDateFormat DateTimeDateFormat}
|
|
||||||
and respectively {@link
|
|
||||||
org.apache.log4j.helpers.ISO8601DateFormat
|
|
||||||
ISO8601DateFormat}. For example, <b>%d{ISO8601}</b> or
|
|
||||||
<b>%d{ABSOLUTE}</b>.
|
|
||||||
|
|
||||||
<p>These dedicated date formatters perform significantly
|
|
||||||
better than {@link java.text.SimpleDateFormat}.
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center><b>F</b></td>
|
|
||||||
|
|
||||||
<td>Used to output the file name where the logging request was
|
|
||||||
issued.
|
|
||||||
|
|
||||||
<p><b>WARNING</b> Generating caller location information is
|
|
||||||
extremely slow and should be avoided unless execution speed
|
|
||||||
is not an issue.
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center><b>l</b></td>
|
|
||||||
|
|
||||||
<td>Used to output location information of the caller which generated
|
|
||||||
the logging event.
|
|
||||||
|
|
||||||
<p>The location information depends on the JVM implementation but
|
|
||||||
usually consists of the fully qualified name of the calling
|
|
||||||
method followed by the callers source the file name and line
|
|
||||||
number between parentheses.
|
|
||||||
|
|
||||||
<p>The location information can be very useful. However, its
|
|
||||||
generation is <em>extremely</em> slow and should be avoided
|
|
||||||
unless execution speed is not an issue.
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center><b>L</b></td>
|
|
||||||
|
|
||||||
<td>Used to output the line number from where the logging request
|
|
||||||
was issued.
|
|
||||||
|
|
||||||
<p><b>WARNING</b> Generating caller location information is
|
|
||||||
extremely slow and should be avoided unless execution speed
|
|
||||||
is not an issue.
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center><b>m</b></td>
|
|
||||||
<td>Used to output the application supplied message associated with
|
|
||||||
the logging event.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center><b>M</b></td>
|
|
||||||
|
|
||||||
<td>Used to output the method name where the logging request was
|
|
||||||
issued.
|
|
||||||
|
|
||||||
<p><b>WARNING</b> Generating caller location information is
|
|
||||||
extremely slow and should be avoided unless execution speed
|
|
||||||
is not an issue.
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center><b>n</b></td>
|
|
||||||
|
|
||||||
<td>Outputs the platform dependent line separator character or
|
|
||||||
characters.
|
|
||||||
|
|
||||||
<p>This conversion character offers practically the same
|
|
||||||
performance as using non-portable line separator strings such as
|
|
||||||
"\n", or "\r\n". Thus, it is the preferred way of specifying a
|
|
||||||
line separator.
|
|
||||||
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center><b>p</b></td>
|
|
||||||
<td>Used to output the priority of the logging event.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
|
|
||||||
<td align=center><b>r</b></td>
|
|
||||||
|
|
||||||
<td>Used to output the number of milliseconds elapsed from the construction
|
|
||||||
of the layout until the creation of the logging event.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center><b>t</b></td>
|
|
||||||
|
|
||||||
<td>Used to output the name of the thread that generated the
|
|
||||||
logging event.</td>
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
|
|
||||||
<td align=center><b>x</b></td>
|
|
||||||
|
|
||||||
<td>Used to output the NDC (nested diagnostic context) associated
|
|
||||||
with the thread that generated the logging event.
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center><b>X</b></td>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
|
|
||||||
<p>Used to output the MDC (mapped diagnostic context) associated
|
|
||||||
with the thread that generated the logging event. The <b>X</b>
|
|
||||||
conversion character <em>must</em> be followed by the key for the
|
|
||||||
map placed between braces, as in <b>%X{clientNumber}</b> where
|
|
||||||
<code>clientNumber</code> is the key. The value in the MDC
|
|
||||||
corresponding to the key will be output.</p>
|
|
||||||
|
|
||||||
<p>See {@link MDC} class for more details.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
|
|
||||||
<td align=center><b>%</b></td>
|
|
||||||
|
|
||||||
<td>The sequence %% outputs a single percent sign.
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p>By default the relevant information is output as is. However,
|
|
||||||
with the aid of format modifiers it is possible to change the
|
|
||||||
minimum field width, the maximum field width and justification.
|
|
||||||
|
|
||||||
<p>The optional format modifier is placed between the percent sign
|
|
||||||
and the conversion character.
|
|
||||||
|
|
||||||
<p>The first optional format modifier is the <em>left justification
|
|
||||||
flag</em> which is just the minus (-) character. Then comes the
|
|
||||||
optional <em>minimum field width</em> modifier. This is a decimal
|
|
||||||
constant that represents the minimum number of characters to
|
|
||||||
output. If the data item requires fewer characters, it is padded on
|
|
||||||
either the left or the right until the minimum width is
|
|
||||||
reached. The default is to pad on the left (right justify) but you
|
|
||||||
can specify right padding with the left justification flag. The
|
|
||||||
padding character is space. If the data item is larger than the
|
|
||||||
minimum field width, the field is expanded to accommodate the
|
|
||||||
data. The value is never truncated.
|
|
||||||
|
|
||||||
<p>This behavior can be changed using the <em>maximum field
|
|
||||||
width</em> modifier which is designated by a period followed by a
|
|
||||||
decimal constant. If the data item is longer than the maximum
|
|
||||||
field, then the extra characters are removed from the
|
|
||||||
<em>beginning</em> of the data item and not from the end. For
|
|
||||||
example, it the maximum field width is eight and the data item is
|
|
||||||
ten characters long, then the first two characters of the data item
|
|
||||||
are dropped. This behavior deviates from the printf function in C
|
|
||||||
where truncation is done from the end.
|
|
||||||
|
|
||||||
<p>Below are various format modifier examples for the category
|
|
||||||
conversion specifier.
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<TABLE BORDER=1 CELLPADDING=8>
|
|
||||||
<th>Format modifier
|
|
||||||
<th>left justify
|
|
||||||
<th>minimum width
|
|
||||||
<th>maximum width
|
|
||||||
<th>comment
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center>%20c</td>
|
|
||||||
<td align=center>false</td>
|
|
||||||
<td align=center>20</td>
|
|
||||||
<td align=center>none</td>
|
|
||||||
|
|
||||||
<td>Left pad with spaces if the category name is less than 20
|
|
||||||
characters long.
|
|
||||||
|
|
||||||
<tr> <td align=center>%-20c</td> <td align=center>true</td> <td
|
|
||||||
align=center>20</td> <td align=center>none</td> <td>Right pad with
|
|
||||||
spaces if the category name is less than 20 characters long.
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center>%.30c</td>
|
|
||||||
<td align=center>NA</td>
|
|
||||||
<td align=center>none</td>
|
|
||||||
<td align=center>30</td>
|
|
||||||
|
|
||||||
<td>Truncate from the beginning if the category name is longer than 30
|
|
||||||
characters.
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center>%20.30c</td>
|
|
||||||
<td align=center>false</td>
|
|
||||||
<td align=center>20</td>
|
|
||||||
<td align=center>30</td>
|
|
||||||
|
|
||||||
<td>Left pad with spaces if the category name is shorter than 20
|
|
||||||
characters. However, if category name is longer than 30 characters,
|
|
||||||
then truncate from the beginning.
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td align=center>%-20.30c</td>
|
|
||||||
<td align=center>true</td>
|
|
||||||
<td align=center>20</td>
|
|
||||||
<td align=center>30</td>
|
|
||||||
|
|
||||||
<td>Right pad with spaces if the category name is shorter than 20
|
|
||||||
characters. However, if category name is longer than 30 characters,
|
|
||||||
then truncate from the beginning.
|
|
||||||
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p>Below are some examples of conversion patterns.
|
|
||||||
|
|
||||||
<dl>
|
|
||||||
|
|
||||||
<p><dt><b>%r [%t] %-5p %c %x - %m%n</b>
|
|
||||||
<p><dd>This is essentially the TTCC layout.
|
|
||||||
|
|
||||||
<p><dt><b>%-6r [%15.15t] %-5p %30.30c %x - %m%n</b>
|
|
||||||
|
|
||||||
<p><dd>Similar to the TTCC layout except that the relative time is
|
|
||||||
right padded if less than 6 digits, thread name is right padded if
|
|
||||||
less than 15 characters and truncated if longer and the category
|
|
||||||
name is left padded if shorter than 30 characters and truncated if
|
|
||||||
longer.
|
|
||||||
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<p>The above text is largely inspired from Peter A. Darnell and
|
|
||||||
Philip E. Margolis' highly recommended book "C -- a Software
|
|
||||||
Engineering Approach", ISBN 0-387-97389-3.
|
|
||||||
|
|
||||||
@author <a href="mailto:cakalijp@Maritz.com">James P. Cakalic</a>
|
|
||||||
@author Ceki Gülcü
|
|
||||||
|
|
||||||
|
|
||||||
@since 0.8.2 */
|
|
||||||
public class PatternLayout extends Layout {
|
|
||||||
|
|
||||||
|
|
||||||
/** Default pattern string for log output. Currently set to the
|
|
||||||
string <b>"%m%n"</b> which just prints the application supplied
|
|
||||||
message. */
|
|
||||||
public final static String DEFAULT_CONVERSION_PATTERN ="%m%n";
|
|
||||||
|
|
||||||
/** A conversion pattern equivalent to the TTCCCLayout.
|
|
||||||
Current value is <b>%r [%t] %p %c %x - %m%n</b>. */
|
|
||||||
public final static String TTCC_CONVERSION_PATTERN
|
|
||||||
= "%r [%t] %p %c %x - %m%n";
|
|
||||||
|
|
||||||
|
|
||||||
protected final int BUF_SIZE = 256;
|
|
||||||
protected final int MAX_CAPACITY = 1024;
|
|
||||||
|
|
||||||
|
|
||||||
// output buffer appended to when format() is invoked
|
|
||||||
private StringBuffer sbuf = new StringBuffer(BUF_SIZE);
|
|
||||||
|
|
||||||
private String pattern;
|
|
||||||
|
|
||||||
private PatternConverter head;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Constructs a PatternLayout using the DEFAULT_LAYOUT_PATTERN.
|
|
||||||
|
|
||||||
The default pattern just produces the application supplied message.
|
|
||||||
*/
|
|
||||||
public PatternLayout() {
|
|
||||||
this(DEFAULT_CONVERSION_PATTERN);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Constructs a PatternLayout using the supplied conversion pattern.
|
|
||||||
*/
|
|
||||||
public PatternLayout(String pattern) {
|
|
||||||
this.pattern = pattern;
|
|
||||||
head = createPatternParser((pattern == null) ? DEFAULT_CONVERSION_PATTERN :
|
|
||||||
pattern).parse();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set the <b>ConversionPattern</b> option. This is the string which
|
|
||||||
controls formatting and consists of a mix of literal content and
|
|
||||||
conversion specifiers.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setConversionPattern(String conversionPattern) {
|
|
||||||
pattern = conversionPattern;
|
|
||||||
head = createPatternParser(conversionPattern).parse();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the value of the <b>ConversionPattern</b> option.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
String getConversionPattern() {
|
|
||||||
return pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Does not do anything as options become effective
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void activateOptions() {
|
|
||||||
// nothing to do.
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
The PatternLayout does not handle the throwable contained within
|
|
||||||
{@link LoggingEvent LoggingEvents}. Thus, it returns
|
|
||||||
<code>true</code>.
|
|
||||||
|
|
||||||
@since 0.8.4 */
|
|
||||||
public
|
|
||||||
boolean ignoresThrowable() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns PatternParser used to parse the conversion string. Subclasses
|
|
||||||
may override this to return a subclass of PatternParser which recognize
|
|
||||||
custom conversion characters.
|
|
||||||
|
|
||||||
@since 0.9.0
|
|
||||||
*/
|
|
||||||
protected PatternParser createPatternParser(String pattern) {
|
|
||||||
return new PatternParser(pattern);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Produces a formatted string as specified by the conversion pattern.
|
|
||||||
*/
|
|
||||||
public String format(LoggingEvent event) {
|
|
||||||
// Reset working stringbuffer
|
|
||||||
if(sbuf.capacity() > MAX_CAPACITY) {
|
|
||||||
sbuf = new StringBuffer(BUF_SIZE);
|
|
||||||
} else {
|
|
||||||
sbuf.setLength(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
PatternConverter c = head;
|
|
||||||
|
|
||||||
while(c != null) {
|
|
||||||
c.format(sbuf, event);
|
|
||||||
c = c.next;
|
|
||||||
}
|
|
||||||
return sbuf.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,193 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Contributors: Kitching Simon <Simon.Kitching@orange.ch>
|
|
||||||
|
|
||||||
package org.apache.log4j;
|
|
||||||
|
|
||||||
/**
|
|
||||||
<font color="#AA4444">Refrain from using this class directly, use
|
|
||||||
the {@link Level} class instead</font>.
|
|
||||||
|
|
||||||
@author Ceki Gülcü */
|
|
||||||
public class Priority {
|
|
||||||
|
|
||||||
transient int level;
|
|
||||||
transient String levelStr;
|
|
||||||
transient int syslogEquivalent;
|
|
||||||
|
|
||||||
public final static int OFF_INT = Integer.MAX_VALUE;
|
|
||||||
public final static int FATAL_INT = 50000;
|
|
||||||
public final static int ERROR_INT = 40000;
|
|
||||||
public final static int WARN_INT = 30000;
|
|
||||||
public final static int INFO_INT = 20000;
|
|
||||||
public final static int DEBUG_INT = 10000;
|
|
||||||
//public final static int FINE_INT = DEBUG_INT;
|
|
||||||
public final static int ALL_INT = Integer.MIN_VALUE;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use {@link Level#FATAL} instead.
|
|
||||||
*/
|
|
||||||
final static public Priority FATAL = new Level(FATAL_INT, "FATAL", 0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use {@link Level#ERROR} instead.
|
|
||||||
*/
|
|
||||||
final static public Priority ERROR = new Level(ERROR_INT, "ERROR", 3);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use {@link Level#WARN} instead.
|
|
||||||
*/
|
|
||||||
final static public Priority WARN = new Level(WARN_INT, "WARN", 4);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use {@link Level#INFO} instead.
|
|
||||||
*/
|
|
||||||
final static public Priority INFO = new Level(INFO_INT, "INFO", 6);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use {@link Level#DEBUG} instead.
|
|
||||||
*/
|
|
||||||
final static public Priority DEBUG = new Level(DEBUG_INT, "DEBUG", 7);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor for deserialization.
|
|
||||||
*/
|
|
||||||
protected Priority() {
|
|
||||||
level = DEBUG_INT;
|
|
||||||
levelStr = "DEBUG";
|
|
||||||
syslogEquivalent = 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Instantiate a level object.
|
|
||||||
*/
|
|
||||||
protected
|
|
||||||
Priority(int level, String levelStr, int syslogEquivalent) {
|
|
||||||
this.level = level;
|
|
||||||
this.levelStr = levelStr;
|
|
||||||
this.syslogEquivalent = syslogEquivalent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Two priorities are equal if their level fields are equal.
|
|
||||||
@since 1.2
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
boolean equals(Object o) {
|
|
||||||
if(o instanceof Priority) {
|
|
||||||
Priority r = (Priority) o;
|
|
||||||
return (this.level == r.level);
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Return the syslog equivalent of this priority as an integer.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
final
|
|
||||||
int getSyslogEquivalent() {
|
|
||||||
return syslogEquivalent;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns <code>true</code> if this level has a higher or equal
|
|
||||||
level than the level passed as argument, <code>false</code>
|
|
||||||
otherwise.
|
|
||||||
|
|
||||||
<p>You should think twice before overriding the default
|
|
||||||
implementation of <code>isGreaterOrEqual</code> method.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
boolean isGreaterOrEqual(Priority r) {
|
|
||||||
return level >= r.level;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Return all possible priorities as an array of Level objects in
|
|
||||||
descending order.
|
|
||||||
|
|
||||||
@deprecated This method will be removed with no replacement.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
Priority[] getAllPossiblePriorities() {
|
|
||||||
return new Priority[] {Priority.FATAL, Priority.ERROR, Level.WARN,
|
|
||||||
Priority.INFO, Priority.DEBUG};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the string representation of this priority.
|
|
||||||
*/
|
|
||||||
final
|
|
||||||
public
|
|
||||||
String toString() {
|
|
||||||
return levelStr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the integer representation of this level.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
final
|
|
||||||
int toInt() {
|
|
||||||
return level;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Please use the {@link Level#toLevel(String)} method instead.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
Priority toPriority(String sArg) {
|
|
||||||
return Level.toLevel(sArg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Please use the {@link Level#toLevel(int)} method instead.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
Priority toPriority(int val) {
|
|
||||||
return toPriority(val, Priority.DEBUG);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Please use the {@link Level#toLevel(int, Level)} method instead.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
Priority toPriority(int val, Priority defaultPriority) {
|
|
||||||
return Level.toLevel(val, (Level) defaultPriority);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Please use the {@link Level#toLevel(String, Level)} method instead.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
Priority toPriority(String sArg, Priority defaultPriority) {
|
|
||||||
return Level.toLevel(sArg, (Level) defaultPriority);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,963 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
// Contibutors: "Luke Blanshard" <Luke@quiq.com>
|
|
||||||
// "Mark DONSZELMANN" <Mark.Donszelmann@cern.ch>
|
|
||||||
// Anders Kristensen <akristensen@dynamicsoft.com>
|
|
||||||
|
|
||||||
package org.apache.log4j;
|
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InterruptedIOException;
|
|
||||||
import java.net.URLConnection;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.Hashtable;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.StringTokenizer;
|
|
||||||
import java.util.Vector;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.apache.log4j.config.PropertySetter;
|
|
||||||
import org.apache.log4j.helpers.FileWatchdog;
|
|
||||||
import org.apache.log4j.helpers.LogLog;
|
|
||||||
import org.apache.log4j.helpers.OptionConverter;
|
|
||||||
import org.apache.log4j.or.RendererMap;
|
|
||||||
import org.apache.log4j.spi.Configurator;
|
|
||||||
import org.apache.log4j.spi.Filter;
|
|
||||||
import org.apache.log4j.spi.LoggerFactory;
|
|
||||||
import org.apache.log4j.spi.LoggerRepository;
|
|
||||||
import org.apache.log4j.spi.OptionHandler;
|
|
||||||
import org.apache.log4j.spi.RendererSupport;
|
|
||||||
import org.apache.log4j.spi.ThrowableRenderer;
|
|
||||||
import org.apache.log4j.spi.ThrowableRendererSupport;
|
|
||||||
import org.apache.log4j.spi.ErrorHandler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Allows the configuration of log4j from an external file. See
|
|
||||||
<b>{@link #doConfigure(String, LoggerRepository)}</b> for the
|
|
||||||
expected format.
|
|
||||||
|
|
||||||
<p>It is sometimes useful to see how log4j is reading configuration
|
|
||||||
files. You can enable log4j internal logging by defining the
|
|
||||||
<b>log4j.debug</b> variable.
|
|
||||||
|
|
||||||
<P>As of log4j version 0.8.5, at class initialization time class,
|
|
||||||
the file <b>log4j.properties</b> will be searched from the search
|
|
||||||
path used to load classes. If the file can be found, then it will
|
|
||||||
be fed to the {@link PropertyConfigurator#configure(java.net.URL)}
|
|
||||||
method.
|
|
||||||
|
|
||||||
<p>The <code>PropertyConfigurator</code> does not handle the
|
|
||||||
advanced configuration features supported by the {@link
|
|
||||||
org.apache.log4j.xml.DOMConfigurator DOMConfigurator} such as
|
|
||||||
support custom {@link org.apache.log4j.spi.ErrorHandler ErrorHandlers},
|
|
||||||
nested appenders such as the {@link org.apache.log4j.AsyncAppender
|
|
||||||
AsyncAppender}, etc.
|
|
||||||
|
|
||||||
<p>All option <em>values</em> admit variable substitution. The
|
|
||||||
syntax of variable substitution is similar to that of Unix
|
|
||||||
shells. The string between an opening <b>"${"</b> and
|
|
||||||
closing <b>"}"</b> is interpreted as a key. The value of
|
|
||||||
the substituted variable can be defined as a system property or in
|
|
||||||
the configuration file itself. The value of the key is first
|
|
||||||
searched in the system properties, and if not found there, it is
|
|
||||||
then searched in the configuration file being parsed. The
|
|
||||||
corresponding value replaces the ${variableName} sequence. For
|
|
||||||
example, if <code>java.home</code> system property is set to
|
|
||||||
<code>/home/xyz</code>, then every occurrence of the sequence
|
|
||||||
<code>${java.home}</code> will be interpreted as
|
|
||||||
<code>/home/xyz</code>.
|
|
||||||
|
|
||||||
|
|
||||||
@author Ceki Gülcü
|
|
||||||
@author Anders Kristensen
|
|
||||||
@since 0.8.1 */
|
|
||||||
public class PropertyConfigurator implements Configurator {
|
|
||||||
|
|
||||||
/**
|
|
||||||
Used internally to keep track of configured appenders.
|
|
||||||
*/
|
|
||||||
protected Hashtable registry = new Hashtable(11);
|
|
||||||
private LoggerRepository repository;
|
|
||||||
protected LoggerFactory loggerFactory = new DefaultCategoryFactory();
|
|
||||||
|
|
||||||
static final String CATEGORY_PREFIX = "log4j.category.";
|
|
||||||
static final String LOGGER_PREFIX = "log4j.logger.";
|
|
||||||
static final String FACTORY_PREFIX = "log4j.factory";
|
|
||||||
static final String ADDITIVITY_PREFIX = "log4j.additivity.";
|
|
||||||
static final String ROOT_CATEGORY_PREFIX = "log4j.rootCategory";
|
|
||||||
static final String ROOT_LOGGER_PREFIX = "log4j.rootLogger";
|
|
||||||
static final String APPENDER_PREFIX = "log4j.appender.";
|
|
||||||
static final String RENDERER_PREFIX = "log4j.renderer.";
|
|
||||||
static final String THRESHOLD_PREFIX = "log4j.threshold";
|
|
||||||
private static final String THROWABLE_RENDERER_PREFIX = "log4j.throwableRenderer";
|
|
||||||
private static final String LOGGER_REF = "logger-ref";
|
|
||||||
private static final String ROOT_REF = "root-ref";
|
|
||||||
private static final String APPENDER_REF_TAG = "appender-ref";
|
|
||||||
|
|
||||||
|
|
||||||
/** Key for specifying the {@link org.apache.log4j.spi.LoggerFactory
|
|
||||||
LoggerFactory}. Currently set to "<code>log4j.loggerFactory</code>". */
|
|
||||||
public static final String LOGGER_FACTORY_KEY = "log4j.loggerFactory";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If property set to true, then hierarchy will be reset before configuration.
|
|
||||||
*/
|
|
||||||
private static final String RESET_KEY = "log4j.reset";
|
|
||||||
|
|
||||||
static final private String INTERNAL_ROOT_NAME = "root";
|
|
||||||
|
|
||||||
/**
|
|
||||||
Read configuration from a file. <b>The existing configuration is
|
|
||||||
not cleared nor reset.</b> If you require a different behavior,
|
|
||||||
then call {@link LogManager#resetConfiguration
|
|
||||||
resetConfiguration} method before calling
|
|
||||||
<code>doConfigure</code>.
|
|
||||||
|
|
||||||
<p>The configuration file consists of statements in the format
|
|
||||||
<code>key=value</code>. The syntax of different configuration
|
|
||||||
elements are discussed below.
|
|
||||||
|
|
||||||
<h3>Repository-wide threshold</h3>
|
|
||||||
|
|
||||||
<p>The repository-wide threshold filters logging requests by level
|
|
||||||
regardless of logger. The syntax is:
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
log4j.threshold=[level]
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>The level value can consist of the string values OFF, FATAL,
|
|
||||||
ERROR, WARN, INFO, DEBUG, ALL or a <em>custom level</em> value. A
|
|
||||||
custom level value can be specified in the form
|
|
||||||
level#classname. By default the repository-wide threshold is set
|
|
||||||
to the lowest possible value, namely the level <code>ALL</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
|
|
||||||
<h3>Appender configuration</h3>
|
|
||||||
|
|
||||||
<p>Appender configuration syntax is:
|
|
||||||
<pre>
|
|
||||||
# For appender named <i>appenderName</i>, set its class.
|
|
||||||
# Note: The appender name can contain dots.
|
|
||||||
log4j.appender.appenderName=fully.qualified.name.of.appender.class
|
|
||||||
|
|
||||||
# Set appender specific options.
|
|
||||||
log4j.appender.appenderName.option1=value1
|
|
||||||
...
|
|
||||||
log4j.appender.appenderName.optionN=valueN
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
For each named appender you can configure its {@link Layout}. The
|
|
||||||
syntax for configuring an appender's layout is:
|
|
||||||
<pre>
|
|
||||||
log4j.appender.appenderName.layout=fully.qualified.name.of.layout.class
|
|
||||||
log4j.appender.appenderName.layout.option1=value1
|
|
||||||
....
|
|
||||||
log4j.appender.appenderName.layout.optionN=valueN
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
The syntax for adding {@link Filter}s to an appender is:
|
|
||||||
<pre>
|
|
||||||
log4j.appender.appenderName.filter.ID=fully.qualified.name.of.filter.class
|
|
||||||
log4j.appender.appenderName.filter.ID.option1=value1
|
|
||||||
...
|
|
||||||
log4j.appender.appenderName.filter.ID.optionN=valueN
|
|
||||||
</pre>
|
|
||||||
The first line defines the class name of the filter identified by ID;
|
|
||||||
subsequent lines with the same ID specify filter option - value
|
|
||||||
paris. Multiple filters are added to the appender in the lexicographic
|
|
||||||
order of IDs.
|
|
||||||
|
|
||||||
The syntax for adding an {@link ErrorHandler} to an appender is:
|
|
||||||
<pre>
|
|
||||||
log4j.appender.appenderName.errorhandler=fully.qualified.name.of.filter.class
|
|
||||||
log4j.appender.appenderName.errorhandler.root-ref={true|false}
|
|
||||||
log4j.appender.appenderName.errorhandler.logger-ref=loggerName
|
|
||||||
log4j.appender.appenderName.errorhandler.appender-ref=appenderName
|
|
||||||
log4j.appender.appenderName.errorhandler.option1=value1
|
|
||||||
...
|
|
||||||
log4j.appender.appenderName.errorhandler.optionN=valueN
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h3>Configuring loggers</h3>
|
|
||||||
|
|
||||||
<p>The syntax for configuring the root logger is:
|
|
||||||
<pre>
|
|
||||||
log4j.rootLogger=[level], appenderName, appenderName, ...
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>This syntax means that an optional <em>level</em> can be
|
|
||||||
supplied followed by appender names separated by commas.
|
|
||||||
|
|
||||||
<p>The level value can consist of the string values OFF, FATAL,
|
|
||||||
ERROR, WARN, INFO, DEBUG, ALL or a <em>custom level</em> value. A
|
|
||||||
custom level value can be specified in the form
|
|
||||||
<code>level#classname</code>.
|
|
||||||
|
|
||||||
<p>If a level value is specified, then the root level is set
|
|
||||||
to the corresponding level. If no level value is specified,
|
|
||||||
then the root level remains untouched.
|
|
||||||
|
|
||||||
<p>The root logger can be assigned multiple appenders.
|
|
||||||
|
|
||||||
<p>Each <i>appenderName</i> (separated by commas) will be added to
|
|
||||||
the root logger. The named appender is defined using the
|
|
||||||
appender syntax defined above.
|
|
||||||
|
|
||||||
<p>For non-root categories the syntax is almost the same:
|
|
||||||
<pre>
|
|
||||||
log4j.logger.logger_name=[level|INHERITED|NULL], appenderName, appenderName, ...
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>The meaning of the optional level value is discussed above
|
|
||||||
in relation to the root logger. In addition however, the value
|
|
||||||
INHERITED can be specified meaning that the named logger should
|
|
||||||
inherit its level from the logger hierarchy.
|
|
||||||
|
|
||||||
<p>If no level value is supplied, then the level of the
|
|
||||||
named logger remains untouched.
|
|
||||||
|
|
||||||
<p>By default categories inherit their level from the
|
|
||||||
hierarchy. However, if you set the level of a logger and later
|
|
||||||
decide that that logger should inherit its level, then you should
|
|
||||||
specify INHERITED as the value for the level value. NULL is a
|
|
||||||
synonym for INHERITED.
|
|
||||||
|
|
||||||
<p>Similar to the root logger syntax, each <i>appenderName</i>
|
|
||||||
(separated by commas) will be attached to the named logger.
|
|
||||||
|
|
||||||
<p>See the <a href="../../../../manual.html#additivity">appender
|
|
||||||
additivity rule</a> in the user manual for the meaning of the
|
|
||||||
<code>additivity</code> flag.
|
|
||||||
|
|
||||||
<h3>ObjectRenderers</h3>
|
|
||||||
|
|
||||||
You can customize the way message objects of a given type are
|
|
||||||
converted to String before being logged. This is done by
|
|
||||||
specifying an {@link org.apache.log4j.or.ObjectRenderer ObjectRenderer}
|
|
||||||
for the object type would like to customize.
|
|
||||||
|
|
||||||
<p>The syntax is:
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
log4j.renderer.fully.qualified.name.of.rendered.class=fully.qualified.name.of.rendering.class
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
As in,
|
|
||||||
<pre>
|
|
||||||
log4j.renderer.my.Fruit=my.FruitRenderer
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h3>ThrowableRenderer</h3>
|
|
||||||
|
|
||||||
You can customize the way an instance of Throwable is
|
|
||||||
converted to String before being logged. This is done by
|
|
||||||
specifying an {@link org.apache.log4j.spi.ThrowableRenderer ThrowableRenderer}.
|
|
||||||
|
|
||||||
<p>The syntax is:
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
log4j.throwableRenderer=fully.qualified.name.of.rendering.class
|
|
||||||
log4j.throwableRenderer.paramName=paramValue
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
As in,
|
|
||||||
<pre>
|
|
||||||
log4j.throwableRenderer=org.apache.log4j.EnhancedThrowableRenderer
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h3>Logger Factories</h3>
|
|
||||||
|
|
||||||
The usage of custom logger factories is discouraged and no longer
|
|
||||||
documented.
|
|
||||||
|
|
||||||
<h3>Resetting Hierarchy</h3>
|
|
||||||
|
|
||||||
The hierarchy will be reset before configuration when
|
|
||||||
log4j.reset=true is present in the properties file.
|
|
||||||
|
|
||||||
<h3>Example</h3>
|
|
||||||
|
|
||||||
<p>An example configuration is given below. Other configuration
|
|
||||||
file examples are given in the <code>examples</code> folder.
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
|
|
||||||
# Set options for appender named "A1".
|
|
||||||
# Appender "A1" will be a SyslogAppender
|
|
||||||
log4j.appender.A1=org.apache.log4j.net.SyslogAppender
|
|
||||||
|
|
||||||
# The syslog daemon resides on www.abc.net
|
|
||||||
log4j.appender.A1.SyslogHost=www.abc.net
|
|
||||||
|
|
||||||
# A1's layout is a PatternLayout, using the conversion pattern
|
|
||||||
# <b>%r %-5p %c{2} %M.%L %x - %m\n</b>. Thus, the log output will
|
|
||||||
# include # the relative time since the start of the application in
|
|
||||||
# milliseconds, followed by the level of the log request,
|
|
||||||
# followed by the two rightmost components of the logger name,
|
|
||||||
# followed by the callers method name, followed by the line number,
|
|
||||||
# the nested disgnostic context and finally the message itself.
|
|
||||||
# Refer to the documentation of {@link PatternLayout} for further information
|
|
||||||
# on the syntax of the ConversionPattern key.
|
|
||||||
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
|
|
||||||
log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %c{2} %M.%L %x - %m\n
|
|
||||||
|
|
||||||
# Set options for appender named "A2"
|
|
||||||
# A2 should be a RollingFileAppender, with maximum file size of 10 MB
|
|
||||||
# using at most one backup file. A2's layout is TTCC, using the
|
|
||||||
# ISO8061 date format with context printing enabled.
|
|
||||||
log4j.appender.A2=org.apache.log4j.RollingFileAppender
|
|
||||||
log4j.appender.A2.MaxFileSize=10MB
|
|
||||||
log4j.appender.A2.MaxBackupIndex=1
|
|
||||||
log4j.appender.A2.layout=org.apache.log4j.TTCCLayout
|
|
||||||
log4j.appender.A2.layout.ContextPrinting=enabled
|
|
||||||
log4j.appender.A2.layout.DateFormat=ISO8601
|
|
||||||
|
|
||||||
# Root logger set to DEBUG using the A2 appender defined above.
|
|
||||||
log4j.rootLogger=DEBUG, A2
|
|
||||||
|
|
||||||
# Logger definitions:
|
|
||||||
# The SECURITY logger inherits is level from root. However, it's output
|
|
||||||
# will go to A1 appender defined above. It's additivity is non-cumulative.
|
|
||||||
log4j.logger.SECURITY=INHERIT, A1
|
|
||||||
log4j.additivity.SECURITY=false
|
|
||||||
|
|
||||||
# Only warnings or above will be logged for the logger "SECURITY.access".
|
|
||||||
# Output will go to A1.
|
|
||||||
log4j.logger.SECURITY.access=WARN
|
|
||||||
|
|
||||||
|
|
||||||
# The logger "class.of.the.day" inherits its level from the
|
|
||||||
# logger hierarchy. Output will go to the appender's of the root
|
|
||||||
# logger, A2 in this case.
|
|
||||||
log4j.logger.class.of.the.day=INHERIT
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>Refer to the <b>setOption</b> method in each Appender and
|
|
||||||
Layout for class specific options.
|
|
||||||
|
|
||||||
<p>Use the <code>#</code> or <code>!</code> characters at the
|
|
||||||
beginning of a line for comments.
|
|
||||||
|
|
||||||
<p>
|
|
||||||
@param configFileName The name of the configuration file where the
|
|
||||||
configuration information is stored.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void doConfigure(String configFileName, LoggerRepository hierarchy) {
|
|
||||||
Properties props = new Properties();
|
|
||||||
FileInputStream istream = null;
|
|
||||||
try {
|
|
||||||
istream = new FileInputStream(configFileName);
|
|
||||||
props.load(istream);
|
|
||||||
istream.close();
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
if (e instanceof InterruptedIOException || e instanceof InterruptedException) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
LogLog.error("Could not read configuration file ["+configFileName+"].", e);
|
|
||||||
LogLog.error("Ignoring configuration file [" + configFileName+"].");
|
|
||||||
return;
|
|
||||||
} finally {
|
|
||||||
if(istream != null) {
|
|
||||||
try {
|
|
||||||
istream.close();
|
|
||||||
} catch(InterruptedIOException ignore) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
} catch(Throwable ignore) {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If we reach here, then the config file is alright.
|
|
||||||
doConfigure(props, hierarchy);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
static
|
|
||||||
public
|
|
||||||
void configure(String configFilename) {
|
|
||||||
new PropertyConfigurator().doConfigure(configFilename,
|
|
||||||
LogManager.getLoggerRepository());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Read configuration options from url <code>configURL</code>.
|
|
||||||
|
|
||||||
@since 0.8.2
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
void configure(java.net.URL configURL) {
|
|
||||||
new PropertyConfigurator().doConfigure(configURL,
|
|
||||||
LogManager.getLoggerRepository());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Read configuration options from <code>properties</code>.
|
|
||||||
|
|
||||||
See {@link #doConfigure(String, LoggerRepository)} for the expected format.
|
|
||||||
*/
|
|
||||||
static
|
|
||||||
public
|
|
||||||
void configure(Properties properties) {
|
|
||||||
new PropertyConfigurator().doConfigure(properties,
|
|
||||||
LogManager.getLoggerRepository());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Like {@link #configureAndWatch(String, long)} except that the
|
|
||||||
default delay as defined by {@link FileWatchdog#DEFAULT_DELAY} is
|
|
||||||
used.
|
|
||||||
|
|
||||||
@param configFilename A file in key=value format.
|
|
||||||
|
|
||||||
*/
|
|
||||||
static
|
|
||||||
public
|
|
||||||
void configureAndWatch(String configFilename) {
|
|
||||||
configureAndWatch(configFilename, FileWatchdog.DEFAULT_DELAY);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Read the configuration file <code>configFilename</code> if it
|
|
||||||
exists. Moreover, a thread will be created that will periodically
|
|
||||||
check if <code>configFilename</code> has been created or
|
|
||||||
modified. The period is determined by the <code>delay</code>
|
|
||||||
argument. If a change or file creation is detected, then
|
|
||||||
<code>configFilename</code> is read to configure log4j.
|
|
||||||
|
|
||||||
@param configFilename A file in key=value format.
|
|
||||||
@param delay The delay in milliseconds to wait between each check.
|
|
||||||
*/
|
|
||||||
static
|
|
||||||
public
|
|
||||||
void configureAndWatch(String configFilename, long delay) {
|
|
||||||
PropertyWatchdog pdog = new PropertyWatchdog(configFilename);
|
|
||||||
pdog.setDelay(delay);
|
|
||||||
pdog.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Read configuration options from <code>properties</code>.
|
|
||||||
|
|
||||||
See {@link #doConfigure(String, LoggerRepository)} for the expected format.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void doConfigure(Properties properties, LoggerRepository hierarchy) {
|
|
||||||
repository = hierarchy;
|
|
||||||
String value = properties.getProperty(LogLog.DEBUG_KEY);
|
|
||||||
if(value == null) {
|
|
||||||
value = properties.getProperty("log4j.configDebug");
|
|
||||||
if(value != null)
|
|
||||||
LogLog.warn("[log4j.configDebug] is deprecated. Use [log4j.debug] instead.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(value != null) {
|
|
||||||
LogLog.setInternalDebugging(OptionConverter.toBoolean(value, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// if log4j.reset=true then
|
|
||||||
// reset hierarchy
|
|
||||||
String reset = properties.getProperty(RESET_KEY);
|
|
||||||
if (reset != null && OptionConverter.toBoolean(reset, false)) {
|
|
||||||
hierarchy.resetConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
String thresholdStr = OptionConverter.findAndSubst(THRESHOLD_PREFIX,
|
|
||||||
properties);
|
|
||||||
if(thresholdStr != null) {
|
|
||||||
hierarchy.setThreshold(OptionConverter.toLevel(thresholdStr,
|
|
||||||
(Level) Level.ALL));
|
|
||||||
LogLog.debug("Hierarchy threshold set to ["+hierarchy.getThreshold()+"].");
|
|
||||||
}
|
|
||||||
|
|
||||||
configureRootCategory(properties, hierarchy);
|
|
||||||
configureLoggerFactory(properties);
|
|
||||||
parseCatsAndRenderers(properties, hierarchy);
|
|
||||||
|
|
||||||
LogLog.debug("Finished configuring.");
|
|
||||||
// We don't want to hold references to appenders preventing their
|
|
||||||
// garbage collection.
|
|
||||||
registry.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Read configuration options from url <code>configURL</code>.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void doConfigure(java.net.URL configURL, LoggerRepository hierarchy) {
|
|
||||||
Properties props = new Properties();
|
|
||||||
LogLog.debug("Reading configuration from URL " + configURL);
|
|
||||||
InputStream istream = null;
|
|
||||||
URLConnection uConn = null;
|
|
||||||
try {
|
|
||||||
uConn = configURL.openConnection();
|
|
||||||
uConn.setUseCaches(false);
|
|
||||||
istream = uConn.getInputStream();
|
|
||||||
props.load(istream);
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
if (e instanceof InterruptedIOException || e instanceof InterruptedException) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
LogLog.error("Could not read configuration file from URL [" + configURL
|
|
||||||
+ "].", e);
|
|
||||||
LogLog.error("Ignoring configuration file [" + configURL +"].");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
if (istream != null) {
|
|
||||||
try {
|
|
||||||
istream.close();
|
|
||||||
} catch(InterruptedIOException ignore) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
} catch(IOException ignore) {
|
|
||||||
} catch(RuntimeException ignore) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
doConfigure(props, hierarchy);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
|
||||||
// Internal stuff
|
|
||||||
// --------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
Check the provided <code>Properties</code> object for a
|
|
||||||
{@link org.apache.log4j.spi.LoggerFactory LoggerFactory}
|
|
||||||
entry specified by {@link #LOGGER_FACTORY_KEY}. If such an entry
|
|
||||||
exists, an attempt is made to create an instance using the default
|
|
||||||
constructor. This instance is used for subsequent Category creations
|
|
||||||
within this configurator.
|
|
||||||
|
|
||||||
@see #parseCatsAndRenderers
|
|
||||||
*/
|
|
||||||
protected void configureLoggerFactory(Properties props) {
|
|
||||||
String factoryClassName = OptionConverter.findAndSubst(LOGGER_FACTORY_KEY,
|
|
||||||
props);
|
|
||||||
if(factoryClassName != null) {
|
|
||||||
LogLog.debug("Setting category factory to ["+factoryClassName+"].");
|
|
||||||
loggerFactory = (LoggerFactory)
|
|
||||||
OptionConverter.instantiateByClassName(factoryClassName,
|
|
||||||
LoggerFactory.class,
|
|
||||||
loggerFactory);
|
|
||||||
PropertySetter.setProperties(loggerFactory, props, FACTORY_PREFIX + ".");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
void configureOptionHandler(OptionHandler oh, String prefix,
|
|
||||||
Properties props) {
|
|
||||||
String[] options = oh.getOptionStrings();
|
|
||||||
if(options == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
String value;
|
|
||||||
for(int i = 0; i < options.length; i++) {
|
|
||||||
value = OptionConverter.findAndSubst(prefix + options[i], props);
|
|
||||||
LogLog.debug(
|
|
||||||
"Option " + options[i] + "=[" + (value == null? "N/A" : value)+"].");
|
|
||||||
// Some option handlers assume that null value are not passed to them.
|
|
||||||
// So don't remove this check
|
|
||||||
if(value != null) {
|
|
||||||
oh.setOption(options[i], value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
oh.activateOptions();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
void configureRootCategory(Properties props, LoggerRepository hierarchy) {
|
|
||||||
String effectiveFrefix = ROOT_LOGGER_PREFIX;
|
|
||||||
String value = OptionConverter.findAndSubst(ROOT_LOGGER_PREFIX, props);
|
|
||||||
|
|
||||||
if(value == null) {
|
|
||||||
value = OptionConverter.findAndSubst(ROOT_CATEGORY_PREFIX, props);
|
|
||||||
effectiveFrefix = ROOT_CATEGORY_PREFIX;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(value == null)
|
|
||||||
LogLog.debug("Could not find root logger information. Is this OK?");
|
|
||||||
else {
|
|
||||||
Logger root = hierarchy.getRootLogger();
|
|
||||||
synchronized(root) {
|
|
||||||
parseCategory(props, root, effectiveFrefix, INTERNAL_ROOT_NAME, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Parse non-root elements, such non-root categories and renderers.
|
|
||||||
*/
|
|
||||||
protected
|
|
||||||
void parseCatsAndRenderers(Properties props, LoggerRepository hierarchy) {
|
|
||||||
Enumeration enumeration = props.propertyNames();
|
|
||||||
while(enumeration.hasMoreElements()) {
|
|
||||||
String key = (String) enumeration.nextElement();
|
|
||||||
if(key.startsWith(CATEGORY_PREFIX) || key.startsWith(LOGGER_PREFIX)) {
|
|
||||||
String loggerName = null;
|
|
||||||
if(key.startsWith(CATEGORY_PREFIX)) {
|
|
||||||
loggerName = key.substring(CATEGORY_PREFIX.length());
|
|
||||||
} else if(key.startsWith(LOGGER_PREFIX)) {
|
|
||||||
loggerName = key.substring(LOGGER_PREFIX.length());
|
|
||||||
}
|
|
||||||
String value = OptionConverter.findAndSubst(key, props);
|
|
||||||
Logger logger = hierarchy.getLogger(loggerName, loggerFactory);
|
|
||||||
synchronized(logger) {
|
|
||||||
parseCategory(props, logger, key, loggerName, value);
|
|
||||||
parseAdditivityForLogger(props, logger, loggerName);
|
|
||||||
}
|
|
||||||
} else if(key.startsWith(RENDERER_PREFIX)) {
|
|
||||||
String renderedClass = key.substring(RENDERER_PREFIX.length());
|
|
||||||
String renderingClass = OptionConverter.findAndSubst(key, props);
|
|
||||||
if(hierarchy instanceof RendererSupport) {
|
|
||||||
RendererMap.addRenderer((RendererSupport) hierarchy, renderedClass,
|
|
||||||
renderingClass);
|
|
||||||
}
|
|
||||||
} else if (key.equals(THROWABLE_RENDERER_PREFIX)) {
|
|
||||||
if (hierarchy instanceof ThrowableRendererSupport) {
|
|
||||||
ThrowableRenderer tr = (ThrowableRenderer)
|
|
||||||
OptionConverter.instantiateByKey(props,
|
|
||||||
THROWABLE_RENDERER_PREFIX,
|
|
||||||
org.apache.log4j.spi.ThrowableRenderer.class,
|
|
||||||
null);
|
|
||||||
if(tr == null) {
|
|
||||||
LogLog.error(
|
|
||||||
"Could not instantiate throwableRenderer.");
|
|
||||||
} else {
|
|
||||||
PropertySetter setter = new PropertySetter(tr);
|
|
||||||
setter.setProperties(props, THROWABLE_RENDERER_PREFIX + ".");
|
|
||||||
((ThrowableRendererSupport) hierarchy).setThrowableRenderer(tr);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Parse the additivity option for a non-root category.
|
|
||||||
*/
|
|
||||||
void parseAdditivityForLogger(Properties props, Logger cat,
|
|
||||||
String loggerName) {
|
|
||||||
String value = OptionConverter.findAndSubst(ADDITIVITY_PREFIX + loggerName,
|
|
||||||
props);
|
|
||||||
LogLog.debug("Handling "+ADDITIVITY_PREFIX + loggerName+"=["+value+"]");
|
|
||||||
// touch additivity only if necessary
|
|
||||||
if((value != null) && (!value.equals(""))) {
|
|
||||||
boolean additivity = OptionConverter.toBoolean(value, true);
|
|
||||||
LogLog.debug("Setting additivity for \""+loggerName+"\" to "+
|
|
||||||
additivity);
|
|
||||||
cat.setAdditivity(additivity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
This method must work for the root category as well.
|
|
||||||
*/
|
|
||||||
void parseCategory(Properties props, Logger logger, String optionKey,
|
|
||||||
String loggerName, String value) {
|
|
||||||
|
|
||||||
LogLog.debug("Parsing for [" +loggerName +"] with value=[" + value+"].");
|
|
||||||
// We must skip over ',' but not white space
|
|
||||||
StringTokenizer st = new StringTokenizer(value, ",");
|
|
||||||
|
|
||||||
// If value is not in the form ", appender.." or "", then we should set
|
|
||||||
// the level of the loggeregory.
|
|
||||||
|
|
||||||
if(!(value.startsWith(",") || value.equals(""))) {
|
|
||||||
|
|
||||||
// just to be on the safe side...
|
|
||||||
if(!st.hasMoreTokens())
|
|
||||||
return;
|
|
||||||
|
|
||||||
String levelStr = st.nextToken();
|
|
||||||
LogLog.debug("Level token is [" + levelStr + "].");
|
|
||||||
|
|
||||||
// If the level value is inherited, set category level value to
|
|
||||||
// null. We also check that the user has not specified inherited for the
|
|
||||||
// root category.
|
|
||||||
if(INHERITED.equalsIgnoreCase(levelStr) ||
|
|
||||||
NULL.equalsIgnoreCase(levelStr)) {
|
|
||||||
if(loggerName.equals(INTERNAL_ROOT_NAME)) {
|
|
||||||
LogLog.warn("The root logger cannot be set to null.");
|
|
||||||
} else {
|
|
||||||
logger.setLevel(null);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.setLevel(OptionConverter.toLevel(levelStr, (Level) Level.DEBUG));
|
|
||||||
}
|
|
||||||
LogLog.debug("Category " + loggerName + " set to " + logger.getLevel());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Begin by removing all existing appenders.
|
|
||||||
logger.removeAllAppenders();
|
|
||||||
|
|
||||||
Appender appender;
|
|
||||||
String appenderName;
|
|
||||||
while(st.hasMoreTokens()) {
|
|
||||||
appenderName = st.nextToken().trim();
|
|
||||||
if(appenderName == null || appenderName.equals(","))
|
|
||||||
continue;
|
|
||||||
LogLog.debug("Parsing appender named \"" + appenderName +"\".");
|
|
||||||
appender = parseAppender(props, appenderName);
|
|
||||||
if(appender != null) {
|
|
||||||
logger.addAppender(appender);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Appender parseAppender(Properties props, String appenderName) {
|
|
||||||
Appender appender = registryGet(appenderName);
|
|
||||||
if((appender != null)) {
|
|
||||||
LogLog.debug("Appender \"" + appenderName + "\" was already parsed.");
|
|
||||||
return appender;
|
|
||||||
}
|
|
||||||
// Appender was not previously initialized.
|
|
||||||
String prefix = APPENDER_PREFIX + appenderName;
|
|
||||||
String layoutPrefix = prefix + ".layout";
|
|
||||||
|
|
||||||
appender = (Appender) OptionConverter.instantiateByKey(props, prefix,
|
|
||||||
org.apache.log4j.Appender.class,
|
|
||||||
null);
|
|
||||||
if(appender == null) {
|
|
||||||
LogLog.error(
|
|
||||||
"Could not instantiate appender named \"" + appenderName+"\".");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
appender.setName(appenderName);
|
|
||||||
|
|
||||||
if(appender instanceof OptionHandler) {
|
|
||||||
if(appender.requiresLayout()) {
|
|
||||||
Layout layout = (Layout) OptionConverter.instantiateByKey(props,
|
|
||||||
layoutPrefix,
|
|
||||||
Layout.class,
|
|
||||||
null);
|
|
||||||
if(layout != null) {
|
|
||||||
appender.setLayout(layout);
|
|
||||||
LogLog.debug("Parsing layout options for \"" + appenderName +"\".");
|
|
||||||
//configureOptionHandler(layout, layoutPrefix + ".", props);
|
|
||||||
PropertySetter.setProperties(layout, props, layoutPrefix + ".");
|
|
||||||
LogLog.debug("End of parsing for \"" + appenderName +"\".");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final String errorHandlerPrefix = prefix + ".errorhandler";
|
|
||||||
String errorHandlerClass = OptionConverter.findAndSubst(errorHandlerPrefix, props);
|
|
||||||
if (errorHandlerClass != null) {
|
|
||||||
ErrorHandler eh = (ErrorHandler) OptionConverter.instantiateByKey(props,
|
|
||||||
errorHandlerPrefix,
|
|
||||||
ErrorHandler.class,
|
|
||||||
null);
|
|
||||||
if (eh != null) {
|
|
||||||
appender.setErrorHandler(eh);
|
|
||||||
LogLog.debug("Parsing errorhandler options for \"" + appenderName +"\".");
|
|
||||||
parseErrorHandler(eh, errorHandlerPrefix, props, repository);
|
|
||||||
final Properties edited = new Properties();
|
|
||||||
final String[] keys = new String[] {
|
|
||||||
errorHandlerPrefix + "." + ROOT_REF,
|
|
||||||
errorHandlerPrefix + "." + LOGGER_REF,
|
|
||||||
errorHandlerPrefix + "." + APPENDER_REF_TAG
|
|
||||||
};
|
|
||||||
for(Iterator iter = props.entrySet().iterator();iter.hasNext();) {
|
|
||||||
Map.Entry entry = (Map.Entry) iter.next();
|
|
||||||
int i = 0;
|
|
||||||
for(; i < keys.length; i++) {
|
|
||||||
if(keys[i].equals(entry.getKey())) break;
|
|
||||||
}
|
|
||||||
if (i == keys.length) {
|
|
||||||
edited.put(entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PropertySetter.setProperties(eh, edited, errorHandlerPrefix + ".");
|
|
||||||
LogLog.debug("End of errorhandler parsing for \"" + appenderName +"\".");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
//configureOptionHandler((OptionHandler) appender, prefix + ".", props);
|
|
||||||
PropertySetter.setProperties(appender, props, prefix + ".");
|
|
||||||
LogLog.debug("Parsed \"" + appenderName +"\" options.");
|
|
||||||
}
|
|
||||||
parseAppenderFilters(props, appenderName, appender);
|
|
||||||
registryPut(appender);
|
|
||||||
return appender;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void parseErrorHandler(
|
|
||||||
final ErrorHandler eh,
|
|
||||||
final String errorHandlerPrefix,
|
|
||||||
final Properties props,
|
|
||||||
final LoggerRepository hierarchy) {
|
|
||||||
boolean rootRef = OptionConverter.toBoolean(
|
|
||||||
OptionConverter.findAndSubst(errorHandlerPrefix + ROOT_REF, props), false);
|
|
||||||
if (rootRef) {
|
|
||||||
eh.setLogger(hierarchy.getRootLogger());
|
|
||||||
}
|
|
||||||
String loggerName = OptionConverter.findAndSubst(errorHandlerPrefix + LOGGER_REF , props);
|
|
||||||
if (loggerName != null) {
|
|
||||||
Logger logger = (loggerFactory == null) ? hierarchy.getLogger(loggerName)
|
|
||||||
: hierarchy.getLogger(loggerName, loggerFactory);
|
|
||||||
eh.setLogger(logger);
|
|
||||||
}
|
|
||||||
String appenderName = OptionConverter.findAndSubst(errorHandlerPrefix + APPENDER_REF_TAG, props);
|
|
||||||
if (appenderName != null) {
|
|
||||||
Appender backup = parseAppender(props, appenderName);
|
|
||||||
if (backup != null) {
|
|
||||||
eh.setBackupAppender(backup);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void parseAppenderFilters(Properties props, String appenderName, Appender appender) {
|
|
||||||
// extract filters and filter options from props into a hashtable mapping
|
|
||||||
// the property name defining the filter class to a list of pre-parsed
|
|
||||||
// name-value pairs associated to that filter
|
|
||||||
final String filterPrefix = APPENDER_PREFIX + appenderName + ".filter.";
|
|
||||||
int fIdx = filterPrefix.length();
|
|
||||||
Hashtable filters = new Hashtable();
|
|
||||||
Enumeration e = props.keys();
|
|
||||||
String name = "";
|
|
||||||
while (e.hasMoreElements()) {
|
|
||||||
String key = (String) e.nextElement();
|
|
||||||
if (key.startsWith(filterPrefix)) {
|
|
||||||
int dotIdx = key.indexOf('.', fIdx);
|
|
||||||
String filterKey = key;
|
|
||||||
if (dotIdx != -1) {
|
|
||||||
filterKey = key.substring(0, dotIdx);
|
|
||||||
name = key.substring(dotIdx+1);
|
|
||||||
}
|
|
||||||
Vector filterOpts = (Vector) filters.get(filterKey);
|
|
||||||
if (filterOpts == null) {
|
|
||||||
filterOpts = new Vector();
|
|
||||||
filters.put(filterKey, filterOpts);
|
|
||||||
}
|
|
||||||
if (dotIdx != -1) {
|
|
||||||
String value = OptionConverter.findAndSubst(key, props);
|
|
||||||
filterOpts.add(new NameValue(name, value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sort filters by IDs, insantiate filters, set filter options,
|
|
||||||
// add filters to the appender
|
|
||||||
Enumeration g = new SortedKeyEnumeration(filters);
|
|
||||||
while (g.hasMoreElements()) {
|
|
||||||
String key = (String) g.nextElement();
|
|
||||||
String clazz = props.getProperty(key);
|
|
||||||
if (clazz != null) {
|
|
||||||
LogLog.debug("Filter key: ["+key+"] class: ["+props.getProperty(key) +"] props: "+filters.get(key));
|
|
||||||
Filter filter = (Filter) OptionConverter.instantiateByClassName(clazz, Filter.class, null);
|
|
||||||
if (filter != null) {
|
|
||||||
PropertySetter propSetter = new PropertySetter(filter);
|
|
||||||
Vector v = (Vector)filters.get(key);
|
|
||||||
Enumeration filterProps = v.elements();
|
|
||||||
while (filterProps.hasMoreElements()) {
|
|
||||||
NameValue kv = (NameValue)filterProps.nextElement();
|
|
||||||
propSetter.setProperty(kv.key, kv.value);
|
|
||||||
}
|
|
||||||
propSetter.activate();
|
|
||||||
LogLog.debug("Adding filter of type ["+filter.getClass()
|
|
||||||
+"] to appender named ["+appender.getName()+"].");
|
|
||||||
appender.addFilter(filter);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LogLog.warn("Missing class definition for filter: ["+key+"]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void registryPut(Appender appender) {
|
|
||||||
registry.put(appender.getName(), appender);
|
|
||||||
}
|
|
||||||
|
|
||||||
Appender registryGet(String name) {
|
|
||||||
return (Appender) registry.get(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class PropertyWatchdog extends FileWatchdog {
|
|
||||||
|
|
||||||
PropertyWatchdog(String filename) {
|
|
||||||
super(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Call {@link PropertyConfigurator#configure(String)} with the
|
|
||||||
<code>filename</code> to reconfigure log4j. */
|
|
||||||
public
|
|
||||||
void doOnChange() {
|
|
||||||
new PropertyConfigurator().doConfigure(filename,
|
|
||||||
LogManager.getLoggerRepository());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NameValue {
|
|
||||||
String key, value;
|
|
||||||
public NameValue(String key, String value) {
|
|
||||||
this.key = key;
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
public String toString() {
|
|
||||||
return key + "=" + value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SortedKeyEnumeration implements Enumeration {
|
|
||||||
|
|
||||||
private Enumeration e;
|
|
||||||
|
|
||||||
public SortedKeyEnumeration(Hashtable ht) {
|
|
||||||
Enumeration f = ht.keys();
|
|
||||||
Vector keys = new Vector(ht.size());
|
|
||||||
for (int i, last = 0; f.hasMoreElements(); ++last) {
|
|
||||||
String key = (String) f.nextElement();
|
|
||||||
for (i = 0; i < last; ++i) {
|
|
||||||
String s = (String) keys.get(i);
|
|
||||||
if (key.compareTo(s) <= 0) break;
|
|
||||||
}
|
|
||||||
keys.add(i, key);
|
|
||||||
}
|
|
||||||
e = keys.elements();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasMoreElements() {
|
|
||||||
return e.hasMoreElements();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object nextElement() {
|
|
||||||
return e.nextElement();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j;
|
|
||||||
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
class ProvisionNode extends Vector {
|
|
||||||
private static final long serialVersionUID = -4479121426311014469L;
|
|
||||||
|
|
||||||
ProvisionNode(Logger logger) {
|
|
||||||
super();
|
|
||||||
this.addElement(logger);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,284 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.InterruptedIOException;
|
|
||||||
|
|
||||||
import org.apache.log4j.helpers.OptionConverter;
|
|
||||||
import org.apache.log4j.helpers.LogLog;
|
|
||||||
import org.apache.log4j.helpers.CountingQuietWriter;
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
RollingFileAppender extends FileAppender to backup the log files when
|
|
||||||
they reach a certain size.
|
|
||||||
|
|
||||||
The log4j extras companion includes alternatives which should be considered
|
|
||||||
for new deployments and which are discussed in the documentation
|
|
||||||
for org.apache.log4j.rolling.RollingFileAppender.
|
|
||||||
|
|
||||||
|
|
||||||
@author Heinz Richter
|
|
||||||
@author Ceki Gülcü
|
|
||||||
|
|
||||||
*/
|
|
||||||
public class RollingFileAppender extends FileAppender {
|
|
||||||
|
|
||||||
/**
|
|
||||||
The default maximum file size is 10MB.
|
|
||||||
*/
|
|
||||||
protected long maxFileSize = 10*1024*1024;
|
|
||||||
|
|
||||||
/**
|
|
||||||
There is one backup file by default.
|
|
||||||
*/
|
|
||||||
protected int maxBackupIndex = 1;
|
|
||||||
|
|
||||||
private long nextRollover = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
The default constructor simply calls its {@link
|
|
||||||
FileAppender#FileAppender parents constructor}. */
|
|
||||||
public
|
|
||||||
RollingFileAppender() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Instantiate a RollingFileAppender and open the file designated by
|
|
||||||
<code>filename</code>. The opened filename will become the ouput
|
|
||||||
destination for this appender.
|
|
||||||
|
|
||||||
<p>If the <code>append</code> parameter is true, the file will be
|
|
||||||
appended to. Otherwise, the file desginated by
|
|
||||||
<code>filename</code> will be truncated before being opened.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
RollingFileAppender(Layout layout, String filename, boolean append)
|
|
||||||
throws IOException {
|
|
||||||
super(layout, filename, append);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Instantiate a FileAppender and open the file designated by
|
|
||||||
<code>filename</code>. The opened filename will become the output
|
|
||||||
destination for this appender.
|
|
||||||
|
|
||||||
<p>The file will be appended to. */
|
|
||||||
public
|
|
||||||
RollingFileAppender(Layout layout, String filename) throws IOException {
|
|
||||||
super(layout, filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the value of the <b>MaxBackupIndex</b> option.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
int getMaxBackupIndex() {
|
|
||||||
return maxBackupIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get the maximum size that the output file is allowed to reach
|
|
||||||
before being rolled over to backup files.
|
|
||||||
|
|
||||||
@since 1.1
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
long getMaximumFileSize() {
|
|
||||||
return maxFileSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Implements the usual roll over behaviour.
|
|
||||||
|
|
||||||
<p>If <code>MaxBackupIndex</code> is positive, then files
|
|
||||||
{<code>File.1</code>, ..., <code>File.MaxBackupIndex -1</code>}
|
|
||||||
are renamed to {<code>File.2</code>, ...,
|
|
||||||
<code>File.MaxBackupIndex</code>}. Moreover, <code>File</code> is
|
|
||||||
renamed <code>File.1</code> and closed. A new <code>File</code> is
|
|
||||||
created to receive further log output.
|
|
||||||
|
|
||||||
<p>If <code>MaxBackupIndex</code> is equal to zero, then the
|
|
||||||
<code>File</code> is truncated with no backup files created.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public // synchronization not necessary since doAppend is alreasy synched
|
|
||||||
void rollOver() {
|
|
||||||
File target;
|
|
||||||
File file;
|
|
||||||
|
|
||||||
if (qw != null) {
|
|
||||||
long size = ((CountingQuietWriter) qw).getCount();
|
|
||||||
LogLog.debug("rolling over count=" + size);
|
|
||||||
// if operation fails, do not roll again until
|
|
||||||
// maxFileSize more bytes are written
|
|
||||||
nextRollover = size + maxFileSize;
|
|
||||||
}
|
|
||||||
LogLog.debug("maxBackupIndex="+maxBackupIndex);
|
|
||||||
|
|
||||||
boolean renameSucceeded = true;
|
|
||||||
// If maxBackups <= 0, then there is no file renaming to be done.
|
|
||||||
if(maxBackupIndex > 0) {
|
|
||||||
// Delete the oldest file, to keep Windows happy.
|
|
||||||
file = new File(fileName + '.' + maxBackupIndex);
|
|
||||||
if (file.exists())
|
|
||||||
renameSucceeded = file.delete();
|
|
||||||
|
|
||||||
// Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2}
|
|
||||||
for (int i = maxBackupIndex - 1; i >= 1 && renameSucceeded; i--) {
|
|
||||||
file = new File(fileName + "." + i);
|
|
||||||
if (file.exists()) {
|
|
||||||
target = new File(fileName + '.' + (i + 1));
|
|
||||||
LogLog.debug("Renaming file " + file + " to " + target);
|
|
||||||
renameSucceeded = file.renameTo(target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(renameSucceeded) {
|
|
||||||
// Rename fileName to fileName.1
|
|
||||||
target = new File(fileName + "." + 1);
|
|
||||||
|
|
||||||
this.closeFile(); // keep windows happy.
|
|
||||||
|
|
||||||
file = new File(fileName);
|
|
||||||
LogLog.debug("Renaming file " + file + " to " + target);
|
|
||||||
renameSucceeded = file.renameTo(target);
|
|
||||||
//
|
|
||||||
// if file rename failed, reopen file with append = true
|
|
||||||
//
|
|
||||||
if (!renameSucceeded) {
|
|
||||||
try {
|
|
||||||
this.setFile(fileName, true, bufferedIO, bufferSize);
|
|
||||||
}
|
|
||||||
catch(IOException e) {
|
|
||||||
if (e instanceof InterruptedIOException) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
LogLog.error("setFile("+fileName+", true) call failed.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// if all renames were successful, then
|
|
||||||
//
|
|
||||||
if (renameSucceeded) {
|
|
||||||
try {
|
|
||||||
// This will also close the file. This is OK since multiple
|
|
||||||
// close operations are safe.
|
|
||||||
this.setFile(fileName, false, bufferedIO, bufferSize);
|
|
||||||
nextRollover = 0;
|
|
||||||
}
|
|
||||||
catch(IOException e) {
|
|
||||||
if (e instanceof InterruptedIOException) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
LogLog.error("setFile("+fileName+", false) call failed.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
synchronized
|
|
||||||
void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize)
|
|
||||||
throws IOException {
|
|
||||||
super.setFile(fileName, append, this.bufferedIO, this.bufferSize);
|
|
||||||
if(append) {
|
|
||||||
File f = new File(fileName);
|
|
||||||
((CountingQuietWriter) qw).setCount(f.length());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set the maximum number of backup files to keep around.
|
|
||||||
|
|
||||||
<p>The <b>MaxBackupIndex</b> option determines how many backup
|
|
||||||
files are kept before the oldest is erased. This option takes
|
|
||||||
a positive integer value. If set to zero, then there will be no
|
|
||||||
backup files and the log file will be truncated when it reaches
|
|
||||||
<code>MaxFileSize</code>.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setMaxBackupIndex(int maxBackups) {
|
|
||||||
this.maxBackupIndex = maxBackups;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set the maximum size that the output file is allowed to reach
|
|
||||||
before being rolled over to backup files.
|
|
||||||
|
|
||||||
<p>This method is equivalent to {@link #setMaxFileSize} except
|
|
||||||
that it is required for differentiating the setter taking a
|
|
||||||
<code>long</code> argument from the setter taking a
|
|
||||||
<code>String</code> argument by the JavaBeans {@link
|
|
||||||
java.beans.Introspector Introspector}.
|
|
||||||
|
|
||||||
@see #setMaxFileSize(String)
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setMaximumFileSize(long maxFileSize) {
|
|
||||||
this.maxFileSize = maxFileSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set the maximum size that the output file is allowed to reach
|
|
||||||
before being rolled over to backup files.
|
|
||||||
|
|
||||||
<p>In configuration files, the <b>MaxFileSize</b> option takes an
|
|
||||||
long integer in the range 0 - 2^63. You can specify the value
|
|
||||||
with the suffixes "KB", "MB" or "GB" so that the integer is
|
|
||||||
interpreted being expressed respectively in kilobytes, megabytes
|
|
||||||
or gigabytes. For example, the value "10KB" will be interpreted
|
|
||||||
as 10240.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setMaxFileSize(String value) {
|
|
||||||
maxFileSize = OptionConverter.toFileSize(value, maxFileSize + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected
|
|
||||||
void setQWForFiles(Writer writer) {
|
|
||||||
this.qw = new CountingQuietWriter(writer, errorHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
This method differentiates RollingFileAppender from its super
|
|
||||||
class.
|
|
||||||
|
|
||||||
@since 0.9.0
|
|
||||||
*/
|
|
||||||
protected
|
|
||||||
void subAppend(LoggingEvent event) {
|
|
||||||
super.subAppend(event);
|
|
||||||
if(fileName != null && qw != null) {
|
|
||||||
long size = ((CountingQuietWriter) qw).getCount();
|
|
||||||
if (size >= maxFileSize && size >= nextRollover) {
|
|
||||||
rollOver();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j;
|
|
||||||
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
SimpleLayout consists of the level of the log statement,
|
|
||||||
followed by " - " and then the log message itself. For example,
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
DEBUG - Hello world
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
@author Ceki Gülcü
|
|
||||||
@since version 0.7.0
|
|
||||||
|
|
||||||
<p>{@link PatternLayout} offers a much more powerful alternative.
|
|
||||||
*/
|
|
||||||
public class SimpleLayout extends Layout {
|
|
||||||
|
|
||||||
StringBuffer sbuf = new StringBuffer(128);
|
|
||||||
|
|
||||||
public SimpleLayout() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void activateOptions() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the log statement in a format consisting of the
|
|
||||||
<code>level</code>, followed by " - " and then the
|
|
||||||
<code>message</code>. For example, <pre> INFO - "A message"
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>The <code>category</code> parameter is ignored.
|
|
||||||
<p>
|
|
||||||
@return A byte array in SimpleLayout format.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
String format(LoggingEvent event) {
|
|
||||||
|
|
||||||
sbuf.setLength(0);
|
|
||||||
sbuf.append(event.getLevel().toString());
|
|
||||||
sbuf.append(" - ");
|
|
||||||
sbuf.append(event.getRenderedMessage());
|
|
||||||
sbuf.append(LINE_SEP);
|
|
||||||
return sbuf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
The SimpleLayout does not handle the throwable contained within
|
|
||||||
{@link LoggingEvent LoggingEvents}. Thus, it returns
|
|
||||||
<code>true</code>.
|
|
||||||
|
|
||||||
@since version 0.8.4 */
|
|
||||||
public
|
|
||||||
boolean ignoresThrowable() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,217 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Contributors: Christopher Williams
|
|
||||||
// Mathias Bogaert
|
|
||||||
|
|
||||||
package org.apache.log4j;
|
|
||||||
|
|
||||||
import org.apache.log4j.helpers.DateLayout;
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
TTCC layout format consists of time, thread, category and nested
|
|
||||||
diagnostic context information, hence the name.
|
|
||||||
|
|
||||||
<p>Each of the four fields can be individually enabled or
|
|
||||||
disabled. The time format depends on the <code>DateFormat</code>
|
|
||||||
used.
|
|
||||||
|
|
||||||
<p>Here is an example TTCCLayout output with the
|
|
||||||
{@link org.apache.log4j.helpers.RelativeTimeDateFormat}.
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
176 [main] INFO org.apache.log4j.examples.Sort - Populating an array of 2 elements in reverse order.
|
|
||||||
225 [main] INFO org.apache.log4j.examples.SortAlgo - Entered the sort method.
|
|
||||||
262 [main] DEBUG org.apache.log4j.examples.SortAlgo.OUTER i=1 - Outer loop.
|
|
||||||
276 [main] DEBUG org.apache.log4j.examples.SortAlgo.SWAP i=1 j=0 - Swapping intArray[0] = 1 and intArray[1] = 0
|
|
||||||
290 [main] DEBUG org.apache.log4j.examples.SortAlgo.OUTER i=0 - Outer loop.
|
|
||||||
304 [main] INFO org.apache.log4j.examples.SortAlgo.DUMP - Dump of interger array:
|
|
||||||
317 [main] INFO org.apache.log4j.examples.SortAlgo.DUMP - Element [0] = 0
|
|
||||||
331 [main] INFO org.apache.log4j.examples.SortAlgo.DUMP - Element [1] = 1
|
|
||||||
343 [main] INFO org.apache.log4j.examples.Sort - The next log statement should be an error message.
|
|
||||||
346 [main] ERROR org.apache.log4j.examples.SortAlgo.DUMP - Tried to dump an uninitialized array.
|
|
||||||
at org.apache.log4j.examples.SortAlgo.dump(SortAlgo.java:58)
|
|
||||||
at org.apache.log4j.examples.Sort.main(Sort.java:64)
|
|
||||||
467 [main] INFO org.apache.log4j.examples.Sort - Exiting main method.
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>The first field is the number of milliseconds elapsed since the
|
|
||||||
start of the program. The second field is the thread outputting the
|
|
||||||
log statement. The third field is the level, the fourth field is
|
|
||||||
the category to which the statement belongs.
|
|
||||||
|
|
||||||
<p>The fifth field (just before the '-') is the nested diagnostic
|
|
||||||
context. Note the nested diagnostic context may be empty as in the
|
|
||||||
first two statements. The text after the '-' is the message of the
|
|
||||||
statement.
|
|
||||||
|
|
||||||
<p><b>WARNING</b> Do not use the same TTCCLayout instance from
|
|
||||||
within different appenders. The TTCCLayout is not thread safe when
|
|
||||||
used in his way. However, it is perfectly safe to use a TTCCLayout
|
|
||||||
instance from just one appender.
|
|
||||||
|
|
||||||
<p>{@link PatternLayout} offers a much more flexible alternative.
|
|
||||||
|
|
||||||
@author Ceki Gülcü
|
|
||||||
@author <A HREF="mailto:heinz.richter@ecmwf.int">Heinz Richter</a>
|
|
||||||
|
|
||||||
*/
|
|
||||||
public class TTCCLayout extends DateLayout {
|
|
||||||
|
|
||||||
// Internal representation of options
|
|
||||||
private boolean threadPrinting = true;
|
|
||||||
private boolean categoryPrefixing = true;
|
|
||||||
private boolean contextPrinting = true;
|
|
||||||
|
|
||||||
|
|
||||||
protected final StringBuffer buf = new StringBuffer(256);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Instantiate a TTCCLayout object with {@link
|
|
||||||
org.apache.log4j.helpers.RelativeTimeDateFormat} as the date
|
|
||||||
formatter in the local time zone.
|
|
||||||
|
|
||||||
@since 0.7.5 */
|
|
||||||
public TTCCLayout() {
|
|
||||||
this.setDateFormat(RELATIVE_TIME_DATE_FORMAT, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Instantiate a TTCCLayout object using the local time zone. The
|
|
||||||
DateFormat used will depend on the <code>dateFormatType</code>.
|
|
||||||
|
|
||||||
<p>This constructor just calls the {@link
|
|
||||||
DateLayout#setDateFormat} method.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public TTCCLayout(String dateFormatType) {
|
|
||||||
this.setDateFormat(dateFormatType);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
The <b>ThreadPrinting</b> option specifies whether the name of the
|
|
||||||
current thread is part of log output or not. This is true by default.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setThreadPrinting(boolean threadPrinting) {
|
|
||||||
this.threadPrinting = threadPrinting;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns value of the <b>ThreadPrinting</b> option.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
boolean getThreadPrinting() {
|
|
||||||
return threadPrinting;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
The <b>CategoryPrefixing</b> option specifies whether {@link Category}
|
|
||||||
name is part of log output or not. This is true by default.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setCategoryPrefixing(boolean categoryPrefixing) {
|
|
||||||
this.categoryPrefixing = categoryPrefixing;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns value of the <b>CategoryPrefixing</b> option.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
boolean getCategoryPrefixing() {
|
|
||||||
return categoryPrefixing;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
The <b>ContextPrinting</b> option specifies log output will include
|
|
||||||
the nested context information belonging to the current thread.
|
|
||||||
This is true by default.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setContextPrinting(boolean contextPrinting) {
|
|
||||||
this.contextPrinting = contextPrinting;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns value of the <b>ContextPrinting</b> option.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
boolean getContextPrinting() {
|
|
||||||
return contextPrinting;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
In addition to the level of the statement and message, the
|
|
||||||
returned byte array includes time, thread, category and {@link NDC}
|
|
||||||
information.
|
|
||||||
|
|
||||||
<p>Time, thread, category and diagnostic context are printed
|
|
||||||
depending on options.
|
|
||||||
|
|
||||||
@param event The event to format
|
|
||||||
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
String format(LoggingEvent event) {
|
|
||||||
|
|
||||||
// Reset buf
|
|
||||||
buf.setLength(0);
|
|
||||||
|
|
||||||
dateFormat(buf, event);
|
|
||||||
|
|
||||||
if(this.threadPrinting) {
|
|
||||||
buf.append('[');
|
|
||||||
buf.append(event.getThreadName());
|
|
||||||
buf.append("] ");
|
|
||||||
}
|
|
||||||
buf.append(event.getLevel().toString());
|
|
||||||
buf.append(' ');
|
|
||||||
|
|
||||||
if(this.categoryPrefixing) {
|
|
||||||
buf.append(event.getLoggerName());
|
|
||||||
buf.append(' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this.contextPrinting) {
|
|
||||||
String ndc = event.getNDC();
|
|
||||||
|
|
||||||
if(ndc != null) {
|
|
||||||
buf.append(ndc);
|
|
||||||
buf.append(' ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buf.append("- ");
|
|
||||||
buf.append(event.getRenderedMessage());
|
|
||||||
buf.append(LINE_SEP);
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
The TTCCLayout does not handle the throwable contained within
|
|
||||||
{@link LoggingEvent LoggingEvents}. Thus, it returns
|
|
||||||
<code>true</code>.
|
|
||||||
|
|
||||||
@since version 0.8.4 */
|
|
||||||
public
|
|
||||||
boolean ignoresThrowable() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,387 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InterruptedIOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.io.Writer;
|
|
||||||
|
|
||||||
import org.apache.log4j.helpers.LogLog;
|
|
||||||
import org.apache.log4j.helpers.QuietWriter;
|
|
||||||
import org.apache.log4j.spi.ErrorHandler;
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
|
|
||||||
// Contibutors: Jens Uwe Pipka <jens.pipka@gmx.de>
|
|
||||||
// Ben Sandee
|
|
||||||
|
|
||||||
/**
|
|
||||||
WriterAppender appends log events to a {@link java.io.Writer} or an
|
|
||||||
{@link java.io.OutputStream} depending on the user's choice.
|
|
||||||
|
|
||||||
@author Ceki Gülcü
|
|
||||||
@since 1.1 */
|
|
||||||
public class WriterAppender extends AppenderSkeleton {
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Immediate flush means that the underlying writer or output stream
|
|
||||||
will be flushed at the end of each append operation unless shouldFlush()
|
|
||||||
is overridden. Immediate
|
|
||||||
flush is slower but ensures that each append request is actually
|
|
||||||
written. If <code>immediateFlush</code> is set to
|
|
||||||
<code>false</code>, then there is a good chance that the last few
|
|
||||||
logs events are not actually written to persistent media if and
|
|
||||||
when the application crashes.
|
|
||||||
|
|
||||||
<p>The <code>immediateFlush</code> variable is set to
|
|
||||||
<code>true</code> by default.
|
|
||||||
|
|
||||||
*/
|
|
||||||
protected boolean immediateFlush = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
The encoding to use when writing. <p>The
|
|
||||||
<code>encoding</code> variable is set to <code>null</null> by
|
|
||||||
default which results in the utilization of the system's default
|
|
||||||
encoding. */
|
|
||||||
protected String encoding;
|
|
||||||
|
|
||||||
/**
|
|
||||||
This is the {@link QuietWriter quietWriter} where we will write
|
|
||||||
to.
|
|
||||||
*/
|
|
||||||
protected QuietWriter qw;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
This default constructor does nothing. */
|
|
||||||
public
|
|
||||||
WriterAppender() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Instantiate a WriterAppender and set the output destination to a
|
|
||||||
new {@link OutputStreamWriter} initialized with <code>os</code>
|
|
||||||
as its {@link OutputStream}. */
|
|
||||||
public
|
|
||||||
WriterAppender(Layout layout, OutputStream os) {
|
|
||||||
this(layout, new OutputStreamWriter(os));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Instantiate a WriterAppender and set the output destination to
|
|
||||||
<code>writer</code>.
|
|
||||||
|
|
||||||
<p>The <code>writer</code> must have been previously opened by
|
|
||||||
the user. */
|
|
||||||
public
|
|
||||||
WriterAppender(Layout layout, Writer writer) {
|
|
||||||
this.layout = layout;
|
|
||||||
this.setWriter(writer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
If the <b>ImmediateFlush</b> option is set to
|
|
||||||
<code>true</code>, the appender will flush at the end of each
|
|
||||||
write. This is the default behavior. If the option is set to
|
|
||||||
<code>false</code>, then the underlying stream can defer writing
|
|
||||||
to physical medium to a later time.
|
|
||||||
|
|
||||||
<p>Avoiding the flush operation at the end of each append results in
|
|
||||||
a performance gain of 10 to 20 percent. However, there is safety
|
|
||||||
tradeoff involved in skipping flushing. Indeed, when flushing is
|
|
||||||
skipped, then it is likely that the last few log events will not
|
|
||||||
be recorded on disk when the application exits. This is a high
|
|
||||||
price to pay even for a 20% performance gain.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setImmediateFlush(boolean value) {
|
|
||||||
immediateFlush = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns value of the <b>ImmediateFlush</b> option.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
boolean getImmediateFlush() {
|
|
||||||
return immediateFlush;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Does nothing.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void activateOptions() {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
This method is called by the {@link AppenderSkeleton#doAppend}
|
|
||||||
method.
|
|
||||||
|
|
||||||
<p>If the output stream exists and is writable then write a log
|
|
||||||
statement to the output stream. Otherwise, write a single warning
|
|
||||||
message to <code>System.err</code>.
|
|
||||||
|
|
||||||
<p>The format of the output will depend on this appender's
|
|
||||||
layout.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void append(LoggingEvent event) {
|
|
||||||
|
|
||||||
// Reminder: the nesting of calls is:
|
|
||||||
//
|
|
||||||
// doAppend()
|
|
||||||
// - check threshold
|
|
||||||
// - filter
|
|
||||||
// - append();
|
|
||||||
// - checkEntryConditions();
|
|
||||||
// - subAppend();
|
|
||||||
|
|
||||||
if(!checkEntryConditions()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
subAppend(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
This method determines if there is a sense in attempting to append.
|
|
||||||
|
|
||||||
<p>It checks whether there is a set output target and also if
|
|
||||||
there is a set layout. If these checks fail, then the boolean
|
|
||||||
value <code>false</code> is returned. */
|
|
||||||
protected
|
|
||||||
boolean checkEntryConditions() {
|
|
||||||
if(this.closed) {
|
|
||||||
LogLog.warn("Not allowed to write to a closed appender.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this.qw == null) {
|
|
||||||
errorHandler.error("No output stream or file set for the appender named ["+
|
|
||||||
name+"].");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this.layout == null) {
|
|
||||||
errorHandler.error("No layout set for the appender named ["+ name+"].");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Close this appender instance. The underlying stream or writer is
|
|
||||||
also closed.
|
|
||||||
|
|
||||||
<p>Closed appenders cannot be reused.
|
|
||||||
|
|
||||||
@see #setWriter
|
|
||||||
@since 0.8.4 */
|
|
||||||
public
|
|
||||||
synchronized
|
|
||||||
void close() {
|
|
||||||
if(this.closed)
|
|
||||||
return;
|
|
||||||
this.closed = true;
|
|
||||||
writeFooter();
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the underlying {@link java.io.Writer}.
|
|
||||||
* */
|
|
||||||
protected void closeWriter() {
|
|
||||||
if(qw != null) {
|
|
||||||
try {
|
|
||||||
qw.close();
|
|
||||||
} catch(IOException e) {
|
|
||||||
if (e instanceof InterruptedIOException) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
// There is do need to invoke an error handler at this late
|
|
||||||
// stage.
|
|
||||||
LogLog.error("Could not close " + qw, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns an OutputStreamWriter when passed an OutputStream. The
|
|
||||||
encoding used will depend on the value of the
|
|
||||||
<code>encoding</code> property. If the encoding value is
|
|
||||||
specified incorrectly the writer will be opened using the default
|
|
||||||
system encoding (an error message will be printed to the loglog. */
|
|
||||||
protected
|
|
||||||
OutputStreamWriter createWriter(OutputStream os) {
|
|
||||||
OutputStreamWriter retval = null;
|
|
||||||
|
|
||||||
String enc = getEncoding();
|
|
||||||
if(enc != null) {
|
|
||||||
try {
|
|
||||||
retval = new OutputStreamWriter(os, enc);
|
|
||||||
} catch(IOException e) {
|
|
||||||
if (e instanceof InterruptedIOException) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
LogLog.warn("Error initializing output writer.");
|
|
||||||
LogLog.warn("Unsupported encoding?");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(retval == null) {
|
|
||||||
retval = new OutputStreamWriter(os);
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getEncoding() {
|
|
||||||
return encoding;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEncoding(String value) {
|
|
||||||
encoding = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set the {@link ErrorHandler} for this WriterAppender and also the
|
|
||||||
underlying {@link QuietWriter} if any. */
|
|
||||||
public synchronized void setErrorHandler(ErrorHandler eh) {
|
|
||||||
if(eh == null) {
|
|
||||||
LogLog.warn("You have tried to set a null error-handler.");
|
|
||||||
} else {
|
|
||||||
this.errorHandler = eh;
|
|
||||||
if(this.qw != null) {
|
|
||||||
this.qw.setErrorHandler(eh);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
<p>Sets the Writer where the log output will go. The
|
|
||||||
specified Writer must be opened by the user and be
|
|
||||||
writable.
|
|
||||||
|
|
||||||
<p>The <code>java.io.Writer</code> will be closed when the
|
|
||||||
appender instance is closed.
|
|
||||||
|
|
||||||
|
|
||||||
<p><b>WARNING:</b> Logging to an unopened Writer will fail.
|
|
||||||
<p>
|
|
||||||
@param writer An already opened Writer. */
|
|
||||||
public synchronized void setWriter(Writer writer) {
|
|
||||||
reset();
|
|
||||||
this.qw = new QuietWriter(writer, errorHandler);
|
|
||||||
//this.tp = new TracerPrintWriter(qw);
|
|
||||||
writeHeader();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Actual writing occurs here.
|
|
||||||
|
|
||||||
<p>Most subclasses of <code>WriterAppender</code> will need to
|
|
||||||
override this method.
|
|
||||||
|
|
||||||
@since 0.9.0 */
|
|
||||||
protected
|
|
||||||
void subAppend(LoggingEvent event) {
|
|
||||||
this.qw.write(this.layout.format(event));
|
|
||||||
|
|
||||||
if(layout.ignoresThrowable()) {
|
|
||||||
String[] s = event.getThrowableStrRep();
|
|
||||||
if (s != null) {
|
|
||||||
int len = s.length;
|
|
||||||
for(int i = 0; i < len; i++) {
|
|
||||||
this.qw.write(s[i]);
|
|
||||||
this.qw.write(Layout.LINE_SEP);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(shouldFlush(event)) {
|
|
||||||
this.qw.flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
The WriterAppender requires a layout. Hence, this method returns
|
|
||||||
<code>true</code>.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
boolean requiresLayout() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Clear internal references to the writer and other variables.
|
|
||||||
|
|
||||||
Subclasses can override this method for an alternate closing
|
|
||||||
behavior. */
|
|
||||||
protected
|
|
||||||
void reset() {
|
|
||||||
closeWriter();
|
|
||||||
this.qw = null;
|
|
||||||
//this.tp = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Write a footer as produced by the embedded layout's {@link
|
|
||||||
Layout#getFooter} method. */
|
|
||||||
protected
|
|
||||||
void writeFooter() {
|
|
||||||
if(layout != null) {
|
|
||||||
String f = layout.getFooter();
|
|
||||||
if(f != null && this.qw != null) {
|
|
||||||
this.qw.write(f);
|
|
||||||
this.qw.flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Write a header as produced by the embedded layout's {@link
|
|
||||||
Layout#getHeader} method. */
|
|
||||||
protected
|
|
||||||
void writeHeader() {
|
|
||||||
if(layout != null) {
|
|
||||||
String h = layout.getHeader();
|
|
||||||
if(h != null && this.qw != null)
|
|
||||||
this.qw.write(h);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines whether the writer should be flushed after
|
|
||||||
* this event is written.
|
|
||||||
*
|
|
||||||
* @since 1.2.16
|
|
||||||
*/
|
|
||||||
protected boolean shouldFlush(final LoggingEvent event) {
|
|
||||||
return immediateFlush;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,222 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.chainsaw;
|
|
||||||
|
|
||||||
import java.awt.GridBagConstraints;
|
|
||||||
import java.awt.GridBagLayout;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import javax.swing.BorderFactory;
|
|
||||||
import javax.swing.JButton;
|
|
||||||
import javax.swing.JComboBox;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.JTextField;
|
|
||||||
import javax.swing.event.DocumentEvent;
|
|
||||||
import javax.swing.event.DocumentListener;
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
import org.apache.log4j.Priority;
|
|
||||||
import org.apache.log4j.Level;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the controls for filtering, pausing, exiting, etc.
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
|
|
||||||
*/
|
|
||||||
class ControlPanel extends JPanel {
|
|
||||||
/** use the log messages **/
|
|
||||||
private static final Logger LOG =
|
|
||||||
Logger.getLogger(ControlPanel.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new <code>ControlPanel</code> instance.
|
|
||||||
*
|
|
||||||
* @param aModel the model to control
|
|
||||||
*/
|
|
||||||
ControlPanel(final MyTableModel aModel) {
|
|
||||||
setBorder(BorderFactory.createTitledBorder("Controls: "));
|
|
||||||
final GridBagLayout gridbag = new GridBagLayout();
|
|
||||||
final GridBagConstraints c = new GridBagConstraints();
|
|
||||||
setLayout(gridbag);
|
|
||||||
|
|
||||||
// Pad everything
|
|
||||||
c.ipadx = 5;
|
|
||||||
c.ipady = 5;
|
|
||||||
|
|
||||||
// Add the 1st column of labels
|
|
||||||
c.gridx = 0;
|
|
||||||
c.anchor = GridBagConstraints.EAST;
|
|
||||||
|
|
||||||
c.gridy = 0;
|
|
||||||
JLabel label = new JLabel("Filter Level:");
|
|
||||||
gridbag.setConstraints(label, c);
|
|
||||||
add(label);
|
|
||||||
|
|
||||||
c.gridy++;
|
|
||||||
label = new JLabel("Filter Thread:");
|
|
||||||
gridbag.setConstraints(label, c);
|
|
||||||
add(label);
|
|
||||||
|
|
||||||
c.gridy++;
|
|
||||||
label = new JLabel("Filter Logger:");
|
|
||||||
gridbag.setConstraints(label, c);
|
|
||||||
add(label);
|
|
||||||
|
|
||||||
c.gridy++;
|
|
||||||
label = new JLabel("Filter NDC:");
|
|
||||||
gridbag.setConstraints(label, c);
|
|
||||||
add(label);
|
|
||||||
|
|
||||||
c.gridy++;
|
|
||||||
label = new JLabel("Filter Message:");
|
|
||||||
gridbag.setConstraints(label, c);
|
|
||||||
add(label);
|
|
||||||
|
|
||||||
// Add the 2nd column of filters
|
|
||||||
c.weightx = 1;
|
|
||||||
//c.weighty = 1;
|
|
||||||
c.gridx = 1;
|
|
||||||
c.anchor = GridBagConstraints.WEST;
|
|
||||||
|
|
||||||
c.gridy = 0;
|
|
||||||
final Level[] allPriorities = new Level[] {Level.FATAL,
|
|
||||||
Level.ERROR,
|
|
||||||
Level.WARN,
|
|
||||||
Level.INFO,
|
|
||||||
Level.DEBUG,
|
|
||||||
Level.TRACE };
|
|
||||||
|
|
||||||
final JComboBox priorities = new JComboBox(allPriorities);
|
|
||||||
final Level lowest = allPriorities[allPriorities.length - 1];
|
|
||||||
priorities.setSelectedItem(lowest);
|
|
||||||
aModel.setPriorityFilter(lowest);
|
|
||||||
gridbag.setConstraints(priorities, c);
|
|
||||||
add(priorities);
|
|
||||||
priorities.setEditable(false);
|
|
||||||
priorities.addActionListener(new ActionListener() {
|
|
||||||
public void actionPerformed(ActionEvent aEvent) {
|
|
||||||
aModel.setPriorityFilter(
|
|
||||||
(Priority) priorities.getSelectedItem());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
c.fill = GridBagConstraints.HORIZONTAL;
|
|
||||||
c.gridy++;
|
|
||||||
final JTextField threadField = new JTextField("");
|
|
||||||
threadField.getDocument().addDocumentListener(new DocumentListener () {
|
|
||||||
public void insertUpdate(DocumentEvent aEvent) {
|
|
||||||
aModel.setThreadFilter(threadField.getText());
|
|
||||||
}
|
|
||||||
public void removeUpdate(DocumentEvent aEvente) {
|
|
||||||
aModel.setThreadFilter(threadField.getText());
|
|
||||||
}
|
|
||||||
public void changedUpdate(DocumentEvent aEvent) {
|
|
||||||
aModel.setThreadFilter(threadField.getText());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
gridbag.setConstraints(threadField, c);
|
|
||||||
add(threadField);
|
|
||||||
|
|
||||||
c.gridy++;
|
|
||||||
final JTextField catField = new JTextField("");
|
|
||||||
catField.getDocument().addDocumentListener(new DocumentListener () {
|
|
||||||
public void insertUpdate(DocumentEvent aEvent) {
|
|
||||||
aModel.setCategoryFilter(catField.getText());
|
|
||||||
}
|
|
||||||
public void removeUpdate(DocumentEvent aEvent) {
|
|
||||||
aModel.setCategoryFilter(catField.getText());
|
|
||||||
}
|
|
||||||
public void changedUpdate(DocumentEvent aEvent) {
|
|
||||||
aModel.setCategoryFilter(catField.getText());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
gridbag.setConstraints(catField, c);
|
|
||||||
add(catField);
|
|
||||||
|
|
||||||
c.gridy++;
|
|
||||||
final JTextField ndcField = new JTextField("");
|
|
||||||
ndcField.getDocument().addDocumentListener(new DocumentListener () {
|
|
||||||
public void insertUpdate(DocumentEvent aEvent) {
|
|
||||||
aModel.setNDCFilter(ndcField.getText());
|
|
||||||
}
|
|
||||||
public void removeUpdate(DocumentEvent aEvent) {
|
|
||||||
aModel.setNDCFilter(ndcField.getText());
|
|
||||||
}
|
|
||||||
public void changedUpdate(DocumentEvent aEvent) {
|
|
||||||
aModel.setNDCFilter(ndcField.getText());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
gridbag.setConstraints(ndcField, c);
|
|
||||||
add(ndcField);
|
|
||||||
|
|
||||||
c.gridy++;
|
|
||||||
final JTextField msgField = new JTextField("");
|
|
||||||
msgField.getDocument().addDocumentListener(new DocumentListener () {
|
|
||||||
public void insertUpdate(DocumentEvent aEvent) {
|
|
||||||
aModel.setMessageFilter(msgField.getText());
|
|
||||||
}
|
|
||||||
public void removeUpdate(DocumentEvent aEvent) {
|
|
||||||
aModel.setMessageFilter(msgField.getText());
|
|
||||||
}
|
|
||||||
public void changedUpdate(DocumentEvent aEvent) {
|
|
||||||
aModel.setMessageFilter(msgField.getText());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
gridbag.setConstraints(msgField, c);
|
|
||||||
add(msgField);
|
|
||||||
|
|
||||||
// Add the 3rd column of buttons
|
|
||||||
c.weightx = 0;
|
|
||||||
c.fill = GridBagConstraints.HORIZONTAL;
|
|
||||||
c.anchor = GridBagConstraints.EAST;
|
|
||||||
c.gridx = 2;
|
|
||||||
|
|
||||||
c.gridy = 0;
|
|
||||||
final JButton exitButton = new JButton("Exit");
|
|
||||||
exitButton.setMnemonic('x');
|
|
||||||
exitButton.addActionListener(ExitAction.INSTANCE);
|
|
||||||
gridbag.setConstraints(exitButton, c);
|
|
||||||
add(exitButton);
|
|
||||||
|
|
||||||
c.gridy++;
|
|
||||||
final JButton clearButton = new JButton("Clear");
|
|
||||||
clearButton.setMnemonic('c');
|
|
||||||
clearButton.addActionListener(new ActionListener() {
|
|
||||||
public void actionPerformed(ActionEvent aEvent) {
|
|
||||||
aModel.clear();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
gridbag.setConstraints(clearButton, c);
|
|
||||||
add(clearButton);
|
|
||||||
|
|
||||||
c.gridy++;
|
|
||||||
final JButton toggleButton = new JButton("Pause");
|
|
||||||
toggleButton.setMnemonic('p');
|
|
||||||
toggleButton.addActionListener(new ActionListener() {
|
|
||||||
public void actionPerformed(ActionEvent aEvent) {
|
|
||||||
aModel.toggle();
|
|
||||||
toggleButton.setText(
|
|
||||||
aModel.isPaused() ? "Resume" : "Pause");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
gridbag.setConstraints(toggleButton, c);
|
|
||||||
add(toggleButton);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.chainsaw;
|
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
import javax.swing.BorderFactory;
|
|
||||||
import javax.swing.JEditorPane;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.JScrollPane;
|
|
||||||
import javax.swing.JTable;
|
|
||||||
import javax.swing.ListSelectionModel;
|
|
||||||
import javax.swing.event.ListSelectionEvent;
|
|
||||||
import javax.swing.event.ListSelectionListener;
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A panel for showing a stack trace.
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
|
|
||||||
*/
|
|
||||||
class DetailPanel
|
|
||||||
extends JPanel
|
|
||||||
implements ListSelectionListener
|
|
||||||
{
|
|
||||||
/** used to log events **/
|
|
||||||
private static final Logger LOG =
|
|
||||||
Logger.getLogger(DetailPanel.class);
|
|
||||||
|
|
||||||
/** used to format the logging event **/
|
|
||||||
private static final MessageFormat FORMATTER = new MessageFormat(
|
|
||||||
"<b>Time:</b> <code>{0,time,medium}</code>" +
|
|
||||||
" <b>Priority:</b> <code>{1}</code>" +
|
|
||||||
" <b>Thread:</b> <code>{2}</code>" +
|
|
||||||
" <b>NDC:</b> <code>{3}</code>" +
|
|
||||||
"<br><b>Logger:</b> <code>{4}</code>" +
|
|
||||||
"<br><b>Location:</b> <code>{5}</code>" +
|
|
||||||
"<br><b>Message:</b>" +
|
|
||||||
"<pre>{6}</pre>" +
|
|
||||||
"<b>Throwable:</b>" +
|
|
||||||
"<pre>{7}</pre>");
|
|
||||||
|
|
||||||
/** the model for the data to render **/
|
|
||||||
private final MyTableModel mModel;
|
|
||||||
/** pane for rendering detail **/
|
|
||||||
private final JEditorPane mDetails;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new <code>DetailPanel</code> instance.
|
|
||||||
*
|
|
||||||
* @param aTable the table to listen for selections on
|
|
||||||
* @param aModel the model backing the table
|
|
||||||
*/
|
|
||||||
DetailPanel(JTable aTable, final MyTableModel aModel) {
|
|
||||||
mModel = aModel;
|
|
||||||
setLayout(new BorderLayout());
|
|
||||||
setBorder(BorderFactory.createTitledBorder("Details: "));
|
|
||||||
|
|
||||||
mDetails = new JEditorPane();
|
|
||||||
mDetails.setEditable(false);
|
|
||||||
mDetails.setContentType("text/html");
|
|
||||||
add(new JScrollPane(mDetails), BorderLayout.CENTER);
|
|
||||||
|
|
||||||
final ListSelectionModel rowSM = aTable.getSelectionModel();
|
|
||||||
rowSM.addListSelectionListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see ListSelectionListener **/
|
|
||||||
public void valueChanged(ListSelectionEvent aEvent) {
|
|
||||||
//Ignore extra messages.
|
|
||||||
if (aEvent.getValueIsAdjusting()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final ListSelectionModel lsm = (ListSelectionModel) aEvent.getSource();
|
|
||||||
if (lsm.isSelectionEmpty()) {
|
|
||||||
mDetails.setText("Nothing selected");
|
|
||||||
} else {
|
|
||||||
final int selectedRow = lsm.getMinSelectionIndex();
|
|
||||||
final EventDetails e = mModel.getEventDetails(selectedRow);
|
|
||||||
final Object[] args =
|
|
||||||
{
|
|
||||||
new Date(e.getTimeStamp()),
|
|
||||||
e.getPriority(),
|
|
||||||
escape(e.getThreadName()),
|
|
||||||
escape(e.getNDC()),
|
|
||||||
escape(e.getCategoryName()),
|
|
||||||
escape(e.getLocationDetails()),
|
|
||||||
escape(e.getMessage()),
|
|
||||||
escape(getThrowableStrRep(e))
|
|
||||||
};
|
|
||||||
mDetails.setText(FORMATTER.format(args));
|
|
||||||
mDetails.setCaretPosition(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Private methods
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a string representation of a throwable.
|
|
||||||
*
|
|
||||||
* @param aEvent contains the throwable information
|
|
||||||
* @return a <code>String</code> value
|
|
||||||
*/
|
|
||||||
private static String getThrowableStrRep(EventDetails aEvent) {
|
|
||||||
final String[] strs = aEvent.getThrowableStrRep();
|
|
||||||
if (strs == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final StringBuffer sb = new StringBuffer();
|
|
||||||
for (int i = 0; i < strs.length; i++) {
|
|
||||||
sb.append(strs[i]).append("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Escape <, > & and " as their entities. It is very
|
|
||||||
* dumb about & handling.
|
|
||||||
* @param aStr the String to escape.
|
|
||||||
* @return the escaped String
|
|
||||||
*/
|
|
||||||
private String escape(String aStr) {
|
|
||||||
if (aStr == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final StringBuffer buf = new StringBuffer();
|
|
||||||
for (int i = 0; i < aStr.length(); i++) {
|
|
||||||
char c = aStr.charAt(i);
|
|
||||||
switch (c) {
|
|
||||||
case '<':
|
|
||||||
buf.append("<");
|
|
||||||
break;
|
|
||||||
case '>':
|
|
||||||
buf.append(">");
|
|
||||||
break;
|
|
||||||
case '\"':
|
|
||||||
buf.append(""");
|
|
||||||
break;
|
|
||||||
case '&':
|
|
||||||
buf.append("&");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
buf.append(c);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.chainsaw;
|
|
||||||
|
|
||||||
import org.apache.log4j.Priority;
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the details of a logging event. It is intended to overcome the
|
|
||||||
* problem that a LoggingEvent cannot be constructed with purely fake data.
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
|
|
||||||
* @version 1.0
|
|
||||||
*/
|
|
||||||
class EventDetails {
|
|
||||||
|
|
||||||
/** the time of the event **/
|
|
||||||
private final long mTimeStamp;
|
|
||||||
/** the priority of the event **/
|
|
||||||
private final Priority mPriority;
|
|
||||||
/** the category of the event **/
|
|
||||||
private final String mCategoryName;
|
|
||||||
/** the NDC for the event **/
|
|
||||||
private final String mNDC;
|
|
||||||
/** the thread for the event **/
|
|
||||||
private final String mThreadName;
|
|
||||||
/** the msg for the event **/
|
|
||||||
private final String mMessage;
|
|
||||||
/** the throwable details the event **/
|
|
||||||
private final String[] mThrowableStrRep;
|
|
||||||
/** the location details for the event **/
|
|
||||||
private final String mLocationDetails;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new <code>EventDetails</code> instance.
|
|
||||||
* @param aTimeStamp a <code>long</code> value
|
|
||||||
* @param aPriority a <code>Priority</code> value
|
|
||||||
* @param aCategoryName a <code>String</code> value
|
|
||||||
* @param aNDC a <code>String</code> value
|
|
||||||
* @param aThreadName a <code>String</code> value
|
|
||||||
* @param aMessage a <code>String</code> value
|
|
||||||
* @param aThrowableStrRep a <code>String[]</code> value
|
|
||||||
* @param aLocationDetails a <code>String</code> value
|
|
||||||
*/
|
|
||||||
EventDetails(long aTimeStamp,
|
|
||||||
Priority aPriority,
|
|
||||||
String aCategoryName,
|
|
||||||
String aNDC,
|
|
||||||
String aThreadName,
|
|
||||||
String aMessage,
|
|
||||||
String[] aThrowableStrRep,
|
|
||||||
String aLocationDetails)
|
|
||||||
{
|
|
||||||
mTimeStamp = aTimeStamp;
|
|
||||||
mPriority = aPriority;
|
|
||||||
mCategoryName = aCategoryName;
|
|
||||||
mNDC = aNDC;
|
|
||||||
mThreadName = aThreadName;
|
|
||||||
mMessage = aMessage;
|
|
||||||
mThrowableStrRep = aThrowableStrRep;
|
|
||||||
mLocationDetails = aLocationDetails;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new <code>EventDetails</code> instance.
|
|
||||||
*
|
|
||||||
* @param aEvent a <code>LoggingEvent</code> value
|
|
||||||
*/
|
|
||||||
EventDetails(LoggingEvent aEvent) {
|
|
||||||
|
|
||||||
this(aEvent.timeStamp,
|
|
||||||
aEvent.getLevel(),
|
|
||||||
aEvent.getLoggerName(),
|
|
||||||
aEvent.getNDC(),
|
|
||||||
aEvent.getThreadName(),
|
|
||||||
aEvent.getRenderedMessage(),
|
|
||||||
aEvent.getThrowableStrRep(),
|
|
||||||
(aEvent.getLocationInformation() == null)
|
|
||||||
? null : aEvent.getLocationInformation().fullInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see #mTimeStamp **/
|
|
||||||
long getTimeStamp() {
|
|
||||||
return mTimeStamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see #mPriority **/
|
|
||||||
Priority getPriority() {
|
|
||||||
return mPriority;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see #mCategoryName **/
|
|
||||||
String getCategoryName() {
|
|
||||||
return mCategoryName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see #mNDC **/
|
|
||||||
String getNDC() {
|
|
||||||
return mNDC;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see #mThreadName **/
|
|
||||||
String getThreadName() {
|
|
||||||
return mThreadName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see #mMessage **/
|
|
||||||
String getMessage() {
|
|
||||||
return mMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see #mLocationDetails **/
|
|
||||||
String getLocationDetails(){
|
|
||||||
return mLocationDetails;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see #mThrowableStrRep **/
|
|
||||||
String[] getThrowableStrRep() {
|
|
||||||
return mThrowableStrRep;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.chainsaw;
|
|
||||||
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import javax.swing.AbstractAction;
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encapsulates the action to exit.
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
|
|
||||||
* @version 1.0
|
|
||||||
*/
|
|
||||||
class ExitAction
|
|
||||||
extends AbstractAction
|
|
||||||
{
|
|
||||||
/** use to log messages **/
|
|
||||||
private static final Logger LOG = Logger.getLogger(ExitAction.class);
|
|
||||||
/** The instance to share **/
|
|
||||||
public static final ExitAction INSTANCE = new ExitAction();
|
|
||||||
|
|
||||||
/** Stop people creating instances **/
|
|
||||||
private ExitAction() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Will shutdown the application.
|
|
||||||
* @param aIgnore ignored
|
|
||||||
*/
|
|
||||||
public void actionPerformed(ActionEvent aIgnore) {
|
|
||||||
LOG.info("shutting down");
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.chainsaw;
|
|
||||||
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.StringReader;
|
|
||||||
import javax.swing.AbstractAction;
|
|
||||||
import javax.swing.JFileChooser;
|
|
||||||
import javax.swing.JFrame;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
|
||||||
import javax.xml.parsers.SAXParserFactory;
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
import org.xml.sax.InputSource;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
import org.xml.sax.XMLReader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encapsulates the action to load an XML file.
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
|
|
||||||
* @version 1.0
|
|
||||||
*/
|
|
||||||
class LoadXMLAction
|
|
||||||
extends AbstractAction
|
|
||||||
{
|
|
||||||
/** use to log messages **/
|
|
||||||
private static final Logger LOG = Logger.getLogger(LoadXMLAction.class);
|
|
||||||
|
|
||||||
/** the parent frame **/
|
|
||||||
private final JFrame mParent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* the file chooser - configured to allow only the selection of a
|
|
||||||
* single file.
|
|
||||||
*/
|
|
||||||
private final JFileChooser mChooser = new JFileChooser();
|
|
||||||
{
|
|
||||||
mChooser.setMultiSelectionEnabled(false);
|
|
||||||
mChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** parser to read XML files **/
|
|
||||||
private final XMLReader mParser;
|
|
||||||
/** the content handler **/
|
|
||||||
private final XMLFileHandler mHandler;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new <code>LoadXMLAction</code> instance.
|
|
||||||
*
|
|
||||||
* @param aParent the parent frame
|
|
||||||
* @param aModel the model to add events to
|
|
||||||
* @exception SAXException if an error occurs
|
|
||||||
* @throws ParserConfigurationException if an error occurs
|
|
||||||
*/
|
|
||||||
LoadXMLAction(JFrame aParent, MyTableModel aModel)
|
|
||||||
throws SAXException, ParserConfigurationException
|
|
||||||
{
|
|
||||||
mParent = aParent;
|
|
||||||
mHandler = new XMLFileHandler(aModel);
|
|
||||||
mParser = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
|
|
||||||
mParser.setContentHandler(mHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prompts the user for a file to load events from.
|
|
||||||
* @param aIgnore an <code>ActionEvent</code> value
|
|
||||||
*/
|
|
||||||
public void actionPerformed(ActionEvent aIgnore) {
|
|
||||||
LOG.info("load file called");
|
|
||||||
if (mChooser.showOpenDialog(mParent) == JFileChooser.APPROVE_OPTION) {
|
|
||||||
LOG.info("Need to load a file");
|
|
||||||
final File chosen = mChooser.getSelectedFile();
|
|
||||||
LOG.info("loading the contents of " + chosen.getAbsolutePath());
|
|
||||||
try {
|
|
||||||
final int num = loadFile(chosen.getAbsolutePath());
|
|
||||||
JOptionPane.showMessageDialog(
|
|
||||||
mParent,
|
|
||||||
"Loaded " + num + " events.",
|
|
||||||
"CHAINSAW",
|
|
||||||
JOptionPane.INFORMATION_MESSAGE);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.warn("caught an exception loading the file", e);
|
|
||||||
JOptionPane.showMessageDialog(
|
|
||||||
mParent,
|
|
||||||
"Error parsing file - " + e.getMessage(),
|
|
||||||
"CHAINSAW",
|
|
||||||
JOptionPane.ERROR_MESSAGE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads the contents of file into the model
|
|
||||||
*
|
|
||||||
* @param aFile the file to extract events from
|
|
||||||
* @return the number of events loaded
|
|
||||||
* @throws SAXException if an error occurs
|
|
||||||
* @throws IOException if an error occurs
|
|
||||||
*/
|
|
||||||
private int loadFile(String aFile)
|
|
||||||
throws SAXException, IOException
|
|
||||||
{
|
|
||||||
synchronized (mParser) {
|
|
||||||
// Create a dummy document to parse the file
|
|
||||||
final StringBuffer buf = new StringBuffer();
|
|
||||||
buf.append("<?xml version=\"1.0\" standalone=\"yes\"?>\n");
|
|
||||||
buf.append("<!DOCTYPE log4j:eventSet ");
|
|
||||||
buf.append("[<!ENTITY data SYSTEM \"file:///");
|
|
||||||
buf.append(aFile);
|
|
||||||
buf.append("\">]>\n");
|
|
||||||
buf.append("<log4j:eventSet xmlns:log4j=\"Claira\">\n");
|
|
||||||
buf.append("&data;\n");
|
|
||||||
buf.append("</log4j:eventSet>\n");
|
|
||||||
|
|
||||||
final InputSource is =
|
|
||||||
new InputSource(new StringReader(buf.toString()));
|
|
||||||
mParser.parse(is);
|
|
||||||
return mHandler.getNumEvents();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.chainsaw;
|
|
||||||
|
|
||||||
import java.io.EOFException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.net.ServerSocket;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.net.SocketException;
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A daemon thread the processes connections from a
|
|
||||||
* <code>org.apache.log4j.net.SocketAppender.html</code>.
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
|
|
||||||
*/
|
|
||||||
class LoggingReceiver extends Thread {
|
|
||||||
/** used to log messages **/
|
|
||||||
private static final Logger LOG = Logger.getLogger(LoggingReceiver.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper that actually processes a client connection. It receives events
|
|
||||||
* and adds them to the supplied model.
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
|
|
||||||
*/
|
|
||||||
private class Slurper implements Runnable {
|
|
||||||
/** socket connection to read events from **/
|
|
||||||
private final Socket mClient;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new <code>Slurper</code> instance.
|
|
||||||
*
|
|
||||||
* @param aClient socket to receive events from
|
|
||||||
*/
|
|
||||||
Slurper(Socket aClient) {
|
|
||||||
mClient = aClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** loops getting the events **/
|
|
||||||
public void run() {
|
|
||||||
LOG.debug("Starting to get data");
|
|
||||||
try {
|
|
||||||
final ObjectInputStream ois =
|
|
||||||
new ObjectInputStream(mClient.getInputStream());
|
|
||||||
while (true) {
|
|
||||||
final LoggingEvent event = (LoggingEvent) ois.readObject();
|
|
||||||
mModel.addEvent(new EventDetails(event));
|
|
||||||
}
|
|
||||||
} catch (EOFException e) {
|
|
||||||
LOG.info("Reached EOF, closing connection");
|
|
||||||
} catch (SocketException e) {
|
|
||||||
LOG.info("Caught SocketException, closing connection");
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOG.warn("Got IOException, closing connection", e);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
LOG.warn("Got ClassNotFoundException, closing connection", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
mClient.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOG.warn("Error closing connection", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** where to put the events **/
|
|
||||||
private MyTableModel mModel;
|
|
||||||
|
|
||||||
/** server for listening for connections **/
|
|
||||||
private ServerSocket mSvrSock;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new <code>LoggingReceiver</code> instance.
|
|
||||||
*
|
|
||||||
* @param aModel model to place put received into
|
|
||||||
* @param aPort port to listen on
|
|
||||||
* @throws IOException if an error occurs
|
|
||||||
*/
|
|
||||||
LoggingReceiver(MyTableModel aModel, int aPort) throws IOException {
|
|
||||||
setDaemon(true);
|
|
||||||
mModel = aModel;
|
|
||||||
mSvrSock = new ServerSocket(aPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Listens for client connections **/
|
|
||||||
public void run() {
|
|
||||||
LOG.info("Thread started");
|
|
||||||
try {
|
|
||||||
while (true) {
|
|
||||||
LOG.debug("Waiting for a connection");
|
|
||||||
final Socket client = mSvrSock.accept();
|
|
||||||
LOG.debug("Got a connection from " +
|
|
||||||
client.getInetAddress().getHostName());
|
|
||||||
final Thread t = new Thread(new Slurper(client));
|
|
||||||
t.setDaemon(true);
|
|
||||||
t.start();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOG.error("Error in accepting connections, stopping.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,192 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.chainsaw;
|
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.event.WindowAdapter;
|
|
||||||
import java.awt.event.WindowEvent;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Properties;
|
|
||||||
import javax.swing.BorderFactory;
|
|
||||||
import javax.swing.JFrame;
|
|
||||||
import javax.swing.JMenu;
|
|
||||||
import javax.swing.JMenuBar;
|
|
||||||
import javax.swing.JMenuItem;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.JScrollPane;
|
|
||||||
import javax.swing.JSplitPane;
|
|
||||||
import javax.swing.JTable;
|
|
||||||
import javax.swing.ListSelectionModel;
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
import org.apache.log4j.PropertyConfigurator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The main application.
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
|
|
||||||
*/
|
|
||||||
public class Main
|
|
||||||
extends JFrame
|
|
||||||
{
|
|
||||||
/** the default port number to listen on **/
|
|
||||||
private static final int DEFAULT_PORT = 4445;
|
|
||||||
|
|
||||||
/** name of property for port name **/
|
|
||||||
public static final String PORT_PROP_NAME = "chainsaw.port";
|
|
||||||
|
|
||||||
/** use to log messages **/
|
|
||||||
private static final Logger LOG = Logger.getLogger(Main.class);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new <code>NetworkClient</code> instance.
|
|
||||||
*/
|
|
||||||
private Main() {
|
|
||||||
super("CHAINSAW - Log4J Log Viewer");
|
|
||||||
// create the all important model
|
|
||||||
final MyTableModel model = new MyTableModel();
|
|
||||||
|
|
||||||
//Create the menu bar.
|
|
||||||
final JMenuBar menuBar = new JMenuBar();
|
|
||||||
setJMenuBar(menuBar);
|
|
||||||
final JMenu menu = new JMenu("File");
|
|
||||||
menuBar.add(menu);
|
|
||||||
|
|
||||||
try {
|
|
||||||
final LoadXMLAction lxa = new LoadXMLAction(this, model);
|
|
||||||
final JMenuItem loadMenuItem = new JMenuItem("Load file...");
|
|
||||||
menu.add(loadMenuItem);
|
|
||||||
loadMenuItem.addActionListener(lxa);
|
|
||||||
} catch (NoClassDefFoundError e) {
|
|
||||||
LOG.info("Missing classes for XML parser", e);
|
|
||||||
JOptionPane.showMessageDialog(
|
|
||||||
this,
|
|
||||||
"XML parser not in classpath - unable to load XML events.",
|
|
||||||
"CHAINSAW",
|
|
||||||
JOptionPane.ERROR_MESSAGE);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.info("Unable to create the action to load XML files", e);
|
|
||||||
JOptionPane.showMessageDialog(
|
|
||||||
this,
|
|
||||||
"Unable to create a XML parser - unable to load XML events.",
|
|
||||||
"CHAINSAW",
|
|
||||||
JOptionPane.ERROR_MESSAGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
final JMenuItem exitMenuItem = new JMenuItem("Exit");
|
|
||||||
menu.add(exitMenuItem);
|
|
||||||
exitMenuItem.addActionListener(ExitAction.INSTANCE);
|
|
||||||
|
|
||||||
// Add control panel
|
|
||||||
final ControlPanel cp = new ControlPanel(model);
|
|
||||||
getContentPane().add(cp, BorderLayout.NORTH);
|
|
||||||
|
|
||||||
// Create the table
|
|
||||||
final JTable table = new JTable(model);
|
|
||||||
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
|
||||||
final JScrollPane scrollPane = new JScrollPane(table);
|
|
||||||
scrollPane.setBorder(BorderFactory.createTitledBorder("Events: "));
|
|
||||||
scrollPane.setPreferredSize(new Dimension(900, 300));
|
|
||||||
|
|
||||||
// Create the details
|
|
||||||
final JPanel details = new DetailPanel(table, model);
|
|
||||||
details.setPreferredSize(new Dimension(900, 300));
|
|
||||||
|
|
||||||
// Add the table and stack trace into a splitter
|
|
||||||
final JSplitPane jsp =
|
|
||||||
new JSplitPane(JSplitPane.VERTICAL_SPLIT, scrollPane, details);
|
|
||||||
getContentPane().add(jsp, BorderLayout.CENTER);
|
|
||||||
|
|
||||||
addWindowListener(new WindowAdapter() {
|
|
||||||
public void windowClosing(WindowEvent aEvent) {
|
|
||||||
ExitAction.INSTANCE.actionPerformed(null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
pack();
|
|
||||||
setVisible(true);
|
|
||||||
|
|
||||||
setupReceiver(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Setup recieving messages.
|
|
||||||
*
|
|
||||||
* @param aModel a <code>MyTableModel</code> value
|
|
||||||
*/
|
|
||||||
private void setupReceiver(MyTableModel aModel) {
|
|
||||||
int port = DEFAULT_PORT;
|
|
||||||
final String strRep = System.getProperty(PORT_PROP_NAME);
|
|
||||||
if (strRep != null) {
|
|
||||||
try {
|
|
||||||
port = Integer.parseInt(strRep);
|
|
||||||
} catch (NumberFormatException nfe) {
|
|
||||||
LOG.fatal("Unable to parse " + PORT_PROP_NAME +
|
|
||||||
" property with value " + strRep + ".");
|
|
||||||
JOptionPane.showMessageDialog(
|
|
||||||
this,
|
|
||||||
"Unable to parse port number from '" + strRep +
|
|
||||||
"', quitting.",
|
|
||||||
"CHAINSAW",
|
|
||||||
JOptionPane.ERROR_MESSAGE);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
final LoggingReceiver lr = new LoggingReceiver(aModel, port);
|
|
||||||
lr.start();
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOG.fatal("Unable to connect to socket server, quiting", e);
|
|
||||||
JOptionPane.showMessageDialog(
|
|
||||||
this,
|
|
||||||
"Unable to create socket on port " + port + ", quitting.",
|
|
||||||
"CHAINSAW",
|
|
||||||
JOptionPane.ERROR_MESSAGE);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
// static methods
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
/** initialise log4j **/
|
|
||||||
private static void initLog4J() {
|
|
||||||
final Properties props = new Properties();
|
|
||||||
props.setProperty("log4j.rootLogger", "DEBUG, A1");
|
|
||||||
props.setProperty("log4j.appender.A1",
|
|
||||||
"org.apache.log4j.ConsoleAppender");
|
|
||||||
props.setProperty("log4j.appender.A1.layout",
|
|
||||||
"org.apache.log4j.TTCCLayout");
|
|
||||||
PropertyConfigurator.configure(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The main method.
|
|
||||||
*
|
|
||||||
* @param aArgs ignored
|
|
||||||
*/
|
|
||||||
public static void main(String[] aArgs) {
|
|
||||||
initLog4J();
|
|
||||||
new Main();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,390 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.chainsaw;
|
|
||||||
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.SortedSet;
|
|
||||||
import java.util.TreeSet;
|
|
||||||
import javax.swing.table.AbstractTableModel;
|
|
||||||
import org.apache.log4j.Priority;
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a list of <code>EventDetails</code> objects that are sorted on
|
|
||||||
* logging time. Methods are provided to filter the events that are visible.
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
|
|
||||||
*/
|
|
||||||
class MyTableModel
|
|
||||||
extends AbstractTableModel
|
|
||||||
{
|
|
||||||
|
|
||||||
/** used to log messages **/
|
|
||||||
private static final Logger LOG = Logger.getLogger(MyTableModel.class);
|
|
||||||
|
|
||||||
/** use the compare logging events **/
|
|
||||||
private static final Comparator MY_COMP = new Comparator()
|
|
||||||
{
|
|
||||||
/** @see Comparator **/
|
|
||||||
public int compare(Object aObj1, Object aObj2) {
|
|
||||||
if ((aObj1 == null) && (aObj2 == null)) {
|
|
||||||
return 0; // treat as equal
|
|
||||||
} else if (aObj1 == null) {
|
|
||||||
return -1; // null less than everything
|
|
||||||
} else if (aObj2 == null) {
|
|
||||||
return 1; // think about it. :->
|
|
||||||
}
|
|
||||||
|
|
||||||
// will assume only have LoggingEvent
|
|
||||||
final EventDetails le1 = (EventDetails) aObj1;
|
|
||||||
final EventDetails le2 = (EventDetails) aObj2;
|
|
||||||
|
|
||||||
if (le1.getTimeStamp() < le2.getTimeStamp()) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// assume not two events are logged at exactly the same time
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper that actually processes incoming events.
|
|
||||||
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
|
|
||||||
*/
|
|
||||||
private class Processor
|
|
||||||
implements Runnable
|
|
||||||
{
|
|
||||||
/** loops getting the events **/
|
|
||||||
public void run() {
|
|
||||||
while (true) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(1000);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized (mLock) {
|
|
||||||
if (mPaused) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean toHead = true; // were events added to head
|
|
||||||
boolean needUpdate = false;
|
|
||||||
final Iterator it = mPendingEvents.iterator();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
final EventDetails event = (EventDetails) it.next();
|
|
||||||
mAllEvents.add(event);
|
|
||||||
toHead = toHead && (event == mAllEvents.first());
|
|
||||||
needUpdate = needUpdate || matchFilter(event);
|
|
||||||
}
|
|
||||||
mPendingEvents.clear();
|
|
||||||
|
|
||||||
if (needUpdate) {
|
|
||||||
updateFilteredEvents(toHead);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** names of the columns in the table **/
|
|
||||||
private static final String[] COL_NAMES = {
|
|
||||||
"Time", "Priority", "Trace", "Category", "NDC", "Message"};
|
|
||||||
|
|
||||||
/** definition of an empty list **/
|
|
||||||
private static final EventDetails[] EMPTY_LIST = new EventDetails[] {};
|
|
||||||
|
|
||||||
/** used to format dates **/
|
|
||||||
private static final DateFormat DATE_FORMATTER =
|
|
||||||
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM);
|
|
||||||
|
|
||||||
/** the lock to control access **/
|
|
||||||
private final Object mLock = new Object();
|
|
||||||
/** set of all logged events - not filtered **/
|
|
||||||
private final SortedSet mAllEvents = new TreeSet(MY_COMP);
|
|
||||||
/** events that are visible after filtering **/
|
|
||||||
private EventDetails[] mFilteredEvents = EMPTY_LIST;
|
|
||||||
/** list of events that are buffered for processing **/
|
|
||||||
private final List mPendingEvents = new ArrayList();
|
|
||||||
/** indicates whether event collection is paused to the UI **/
|
|
||||||
private boolean mPaused = false;
|
|
||||||
|
|
||||||
/** filter for the thread **/
|
|
||||||
private String mThreadFilter = "";
|
|
||||||
/** filter for the message **/
|
|
||||||
private String mMessageFilter = "";
|
|
||||||
/** filter for the NDC **/
|
|
||||||
private String mNDCFilter = "";
|
|
||||||
/** filter for the category **/
|
|
||||||
private String mCategoryFilter = "";
|
|
||||||
/** filter for the priority **/
|
|
||||||
private Priority mPriorityFilter = Priority.DEBUG;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new <code>MyTableModel</code> instance.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
MyTableModel() {
|
|
||||||
final Thread t = new Thread(new Processor());
|
|
||||||
t.setDaemon(true);
|
|
||||||
t.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Table Methods
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/** @see javax.swing.table.TableModel **/
|
|
||||||
public int getRowCount() {
|
|
||||||
synchronized (mLock) {
|
|
||||||
return mFilteredEvents.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see javax.swing.table.TableModel **/
|
|
||||||
public int getColumnCount() {
|
|
||||||
// does not need to be synchronized
|
|
||||||
return COL_NAMES.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see javax.swing.table.TableModel **/
|
|
||||||
public String getColumnName(int aCol) {
|
|
||||||
// does not need to be synchronized
|
|
||||||
return COL_NAMES[aCol];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see javax.swing.table.TableModel **/
|
|
||||||
public Class getColumnClass(int aCol) {
|
|
||||||
// does not need to be synchronized
|
|
||||||
return (aCol == 2) ? Boolean.class : Object.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see javax.swing.table.TableModel **/
|
|
||||||
public Object getValueAt(int aRow, int aCol) {
|
|
||||||
synchronized (mLock) {
|
|
||||||
final EventDetails event = mFilteredEvents[aRow];
|
|
||||||
|
|
||||||
if (aCol == 0) {
|
|
||||||
return DATE_FORMATTER.format(new Date(event.getTimeStamp()));
|
|
||||||
} else if (aCol == 1) {
|
|
||||||
return event.getPriority();
|
|
||||||
} else if (aCol == 2) {
|
|
||||||
return (event.getThrowableStrRep() == null)
|
|
||||||
? Boolean.FALSE : Boolean.TRUE;
|
|
||||||
} else if (aCol == 3) {
|
|
||||||
return event.getCategoryName();
|
|
||||||
} else if (aCol == 4) {
|
|
||||||
return event.getNDC();
|
|
||||||
}
|
|
||||||
return event.getMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Public Methods
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the priority to filter events on. Only events of equal or higher
|
|
||||||
* property are now displayed.
|
|
||||||
*
|
|
||||||
* @param aPriority the priority to filter on
|
|
||||||
*/
|
|
||||||
public void setPriorityFilter(Priority aPriority) {
|
|
||||||
synchronized (mLock) {
|
|
||||||
mPriorityFilter = aPriority;
|
|
||||||
updateFilteredEvents(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the filter for the thread field.
|
|
||||||
*
|
|
||||||
* @param aStr the string to match
|
|
||||||
*/
|
|
||||||
public void setThreadFilter(String aStr) {
|
|
||||||
synchronized (mLock) {
|
|
||||||
mThreadFilter = aStr.trim();
|
|
||||||
updateFilteredEvents(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the filter for the message field.
|
|
||||||
*
|
|
||||||
* @param aStr the string to match
|
|
||||||
*/
|
|
||||||
public void setMessageFilter(String aStr) {
|
|
||||||
synchronized (mLock) {
|
|
||||||
mMessageFilter = aStr.trim();
|
|
||||||
updateFilteredEvents(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the filter for the NDC field.
|
|
||||||
*
|
|
||||||
* @param aStr the string to match
|
|
||||||
*/
|
|
||||||
public void setNDCFilter(String aStr) {
|
|
||||||
synchronized (mLock) {
|
|
||||||
mNDCFilter = aStr.trim();
|
|
||||||
updateFilteredEvents(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the filter for the category field.
|
|
||||||
*
|
|
||||||
* @param aStr the string to match
|
|
||||||
*/
|
|
||||||
public void setCategoryFilter(String aStr) {
|
|
||||||
synchronized (mLock) {
|
|
||||||
mCategoryFilter = aStr.trim();
|
|
||||||
updateFilteredEvents(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an event to the list.
|
|
||||||
*
|
|
||||||
* @param aEvent a <code>EventDetails</code> value
|
|
||||||
*/
|
|
||||||
public void addEvent(EventDetails aEvent) {
|
|
||||||
synchronized (mLock) {
|
|
||||||
mPendingEvents.add(aEvent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear the list of all events.
|
|
||||||
*/
|
|
||||||
public void clear() {
|
|
||||||
synchronized (mLock) {
|
|
||||||
mAllEvents.clear();
|
|
||||||
mFilteredEvents = new EventDetails[0];
|
|
||||||
mPendingEvents.clear();
|
|
||||||
fireTableDataChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Toggle whether collecting events **/
|
|
||||||
public void toggle() {
|
|
||||||
synchronized (mLock) {
|
|
||||||
mPaused = !mPaused;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return whether currently paused collecting events **/
|
|
||||||
public boolean isPaused() {
|
|
||||||
synchronized (mLock) {
|
|
||||||
return mPaused;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the throwable information at a specified row in the filtered events.
|
|
||||||
*
|
|
||||||
* @param aRow the row index of the event
|
|
||||||
* @return the throwable information
|
|
||||||
*/
|
|
||||||
public EventDetails getEventDetails(int aRow) {
|
|
||||||
synchronized (mLock) {
|
|
||||||
return mFilteredEvents[aRow];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Private methods
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the filtered events data structure.
|
|
||||||
* @param aInsertedToFront indicates whether events were added to front of
|
|
||||||
* the events. If true, then the current first event must still exist
|
|
||||||
* in the list after the filter is applied.
|
|
||||||
*/
|
|
||||||
private void updateFilteredEvents(boolean aInsertedToFront) {
|
|
||||||
final long start = System.currentTimeMillis();
|
|
||||||
final List filtered = new ArrayList();
|
|
||||||
final int size = mAllEvents.size();
|
|
||||||
final Iterator it = mAllEvents.iterator();
|
|
||||||
|
|
||||||
while (it.hasNext()) {
|
|
||||||
final EventDetails event = (EventDetails) it.next();
|
|
||||||
if (matchFilter(event)) {
|
|
||||||
filtered.add(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final EventDetails lastFirst = (mFilteredEvents.length == 0)
|
|
||||||
? null
|
|
||||||
: mFilteredEvents[0];
|
|
||||||
mFilteredEvents = (EventDetails[]) filtered.toArray(EMPTY_LIST);
|
|
||||||
|
|
||||||
if (aInsertedToFront && (lastFirst != null)) {
|
|
||||||
final int index = filtered.indexOf(lastFirst);
|
|
||||||
if (index < 1) {
|
|
||||||
LOG.warn("In strange state");
|
|
||||||
fireTableDataChanged();
|
|
||||||
} else {
|
|
||||||
fireTableRowsInserted(0, index - 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fireTableDataChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
final long end = System.currentTimeMillis();
|
|
||||||
LOG.debug("Total time [ms]: " + (end - start)
|
|
||||||
+ " in update, size: " + size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether an event matches the filters.
|
|
||||||
*
|
|
||||||
* @param aEvent the event to check for a match
|
|
||||||
* @return whether the event matches
|
|
||||||
*/
|
|
||||||
private boolean matchFilter(EventDetails aEvent) {
|
|
||||||
if (aEvent.getPriority().isGreaterOrEqual(mPriorityFilter) &&
|
|
||||||
(aEvent.getThreadName().indexOf(mThreadFilter) >= 0) &&
|
|
||||||
(aEvent.getCategoryName().indexOf(mCategoryFilter) >= 0) &&
|
|
||||||
((mNDCFilter.length() == 0) ||
|
|
||||||
((aEvent.getNDC() != null) &&
|
|
||||||
(aEvent.getNDC().indexOf(mNDCFilter) >= 0))))
|
|
||||||
{
|
|
||||||
final String rm = aEvent.getMessage();
|
|
||||||
if (rm == null) {
|
|
||||||
// only match if we have not filtering in place
|
|
||||||
return (mMessageFilter.length() == 0);
|
|
||||||
} else {
|
|
||||||
return (rm.indexOf(mMessageFilter) >= 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false; // by default not match
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.chainsaw;
|
|
||||||
|
|
||||||
import java.util.StringTokenizer;
|
|
||||||
import org.apache.log4j.Level;
|
|
||||||
import org.xml.sax.Attributes;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
import org.xml.sax.helpers.DefaultHandler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A content handler for document containing Log4J events logged using the
|
|
||||||
* XMLLayout class. It will create events and add them to a supplied model.
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
|
|
||||||
* @version 1.0
|
|
||||||
*/
|
|
||||||
class XMLFileHandler
|
|
||||||
extends DefaultHandler
|
|
||||||
{
|
|
||||||
/** represents the event tag **/
|
|
||||||
private static final String TAG_EVENT = "log4j:event";
|
|
||||||
/** represents the message tag **/
|
|
||||||
private static final String TAG_MESSAGE = "log4j:message";
|
|
||||||
/** represents the ndc tag **/
|
|
||||||
private static final String TAG_NDC = "log4j:NDC";
|
|
||||||
/** represents the throwable tag **/
|
|
||||||
private static final String TAG_THROWABLE = "log4j:throwable";
|
|
||||||
/** represents the location info tag **/
|
|
||||||
private static final String TAG_LOCATION_INFO = "log4j:locationInfo";
|
|
||||||
|
|
||||||
/** where to put the events **/
|
|
||||||
private final MyTableModel mModel;
|
|
||||||
/** the number of events in the document **/
|
|
||||||
private int mNumEvents;
|
|
||||||
|
|
||||||
/** the time of the event **/
|
|
||||||
private long mTimeStamp;
|
|
||||||
/** the priority (level) of the event **/
|
|
||||||
private Level mLevel;
|
|
||||||
/** the category of the event **/
|
|
||||||
private String mCategoryName;
|
|
||||||
/** the NDC for the event **/
|
|
||||||
private String mNDC;
|
|
||||||
/** the thread for the event **/
|
|
||||||
private String mThreadName;
|
|
||||||
/** the msg for the event **/
|
|
||||||
private String mMessage;
|
|
||||||
/** the throwable details the event **/
|
|
||||||
private String[] mThrowableStrRep;
|
|
||||||
/** the location details for the event **/
|
|
||||||
private String mLocationDetails;
|
|
||||||
/** buffer for collecting text **/
|
|
||||||
private final StringBuffer mBuf = new StringBuffer();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new <code>XMLFileHandler</code> instance.
|
|
||||||
*
|
|
||||||
* @param aModel where to add the events
|
|
||||||
*/
|
|
||||||
XMLFileHandler(MyTableModel aModel) {
|
|
||||||
mModel = aModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see DefaultHandler **/
|
|
||||||
public void startDocument()
|
|
||||||
throws SAXException
|
|
||||||
{
|
|
||||||
mNumEvents = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see DefaultHandler **/
|
|
||||||
public void characters(char[] aChars, int aStart, int aLength) {
|
|
||||||
mBuf.append(String.valueOf(aChars, aStart, aLength));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see DefaultHandler **/
|
|
||||||
public void endElement(String aNamespaceURI,
|
|
||||||
String aLocalName,
|
|
||||||
String aQName)
|
|
||||||
{
|
|
||||||
if (TAG_EVENT.equals(aQName)) {
|
|
||||||
addEvent();
|
|
||||||
resetData();
|
|
||||||
} else if (TAG_NDC.equals(aQName)) {
|
|
||||||
mNDC = mBuf.toString();
|
|
||||||
} else if (TAG_MESSAGE.equals(aQName)) {
|
|
||||||
mMessage = mBuf.toString();
|
|
||||||
} else if (TAG_THROWABLE.equals(aQName)) {
|
|
||||||
final StringTokenizer st =
|
|
||||||
new StringTokenizer(mBuf.toString(), "\n\t");
|
|
||||||
mThrowableStrRep = new String[st.countTokens()];
|
|
||||||
if (mThrowableStrRep.length > 0) {
|
|
||||||
mThrowableStrRep[0] = st.nextToken();
|
|
||||||
for (int i = 1; i < mThrowableStrRep.length; i++) {
|
|
||||||
mThrowableStrRep[i] = "\t" + st.nextToken();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see DefaultHandler **/
|
|
||||||
public void startElement(String aNamespaceURI,
|
|
||||||
String aLocalName,
|
|
||||||
String aQName,
|
|
||||||
Attributes aAtts)
|
|
||||||
{
|
|
||||||
mBuf.setLength(0);
|
|
||||||
|
|
||||||
if (TAG_EVENT.equals(aQName)) {
|
|
||||||
mThreadName = aAtts.getValue("thread");
|
|
||||||
mTimeStamp = Long.parseLong(aAtts.getValue("timestamp"));
|
|
||||||
mCategoryName = aAtts.getValue("logger");
|
|
||||||
mLevel = Level.toLevel(aAtts.getValue("level"));
|
|
||||||
} else if (TAG_LOCATION_INFO.equals(aQName)) {
|
|
||||||
mLocationDetails = aAtts.getValue("class") + "."
|
|
||||||
+ aAtts.getValue("method")
|
|
||||||
+ "(" + aAtts.getValue("file") + ":" + aAtts.getValue("line")
|
|
||||||
+ ")";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return the number of events in the document **/
|
|
||||||
int getNumEvents() {
|
|
||||||
return mNumEvents;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Private methods
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/** Add an event to the model **/
|
|
||||||
private void addEvent() {
|
|
||||||
mModel.addEvent(new EventDetails(mTimeStamp,
|
|
||||||
mLevel,
|
|
||||||
mCategoryName,
|
|
||||||
mNDC,
|
|
||||||
mThreadName,
|
|
||||||
mMessage,
|
|
||||||
mThrowableStrRep,
|
|
||||||
mLocationDetails));
|
|
||||||
mNumEvents++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Reset the data for an event **/
|
|
||||||
private void resetData() {
|
|
||||||
mTimeStamp = 0;
|
|
||||||
mLevel = null;
|
|
||||||
mCategoryName = null;
|
|
||||||
mNDC = null;
|
|
||||||
mThreadName = null;
|
|
||||||
mMessage = null;
|
|
||||||
mThrowableStrRep = null;
|
|
||||||
mLocationDetails = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 23 KiB |
@@ -1,118 +0,0 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
||||||
<!--
|
|
||||||
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.
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
<HTML>
|
|
||||||
<HEAD>
|
|
||||||
<TITLE>Chainsaw Tool</TITLE>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<BODY>
|
|
||||||
|
|
||||||
<P>Chainsaw is a GUI log viewer and filter for the log4j
|
|
||||||
package. By default it listens for <a
|
|
||||||
href="../spi/LoggingEvent.html">LoggingEvent</A> objects sent using
|
|
||||||
the <A href="../net/SocketAppender.html">SocketAppender</A> and
|
|
||||||
displays them in a table. The events can be filtered based on:</P>
|
|
||||||
|
|
||||||
<UL>
|
|
||||||
<LI>Level </li>
|
|
||||||
|
|
||||||
<LI>Thread name</li>
|
|
||||||
|
|
||||||
<LI>Logger</li>
|
|
||||||
<LI>Message</li>
|
|
||||||
|
|
||||||
<LI>NDC</LI>
|
|
||||||
</UL>
|
|
||||||
|
|
||||||
<P>All the details for each event can be displayed by selecting
|
|
||||||
the event in the table.</P>
|
|
||||||
|
|
||||||
<P>Chainsaw also supports loading a events logged to a file using
|
|
||||||
the <A href="../xml/XMLLayout.html">XMLLayout</A> format. This
|
|
||||||
is great for analysing log files, and means you do not need to
|
|
||||||
keep Chainsaw running continously. It is easy to add support
|
|
||||||
for loading events from other sources like JDBC.</P>
|
|
||||||
|
|
||||||
<P>A picture is worth a thousand words: </P>
|
|
||||||
|
|
||||||
<P align=center><A
|
|
||||||
href="doc-files/screen_01.png"><IMG
|
|
||||||
height="50%" alt="Screen shot of chainsaw"
|
|
||||||
src="doc-files/screen_01.png"
|
|
||||||
width="50%"></A>.</P>
|
|
||||||
|
|
||||||
<P>Finally, why is it called chainsaw?
|
|
||||||
Because it cuts your log (file) down to size. :-)
|
|
||||||
</P>
|
|
||||||
|
|
||||||
|
|
||||||
<H2>Requirements</H2>
|
|
||||||
|
|
||||||
<P>Chainsaw is based on the Swing API which requires JDK 1.2 or later.</P>
|
|
||||||
|
|
||||||
|
|
||||||
<H2>Running chainsaw</H2>
|
|
||||||
|
|
||||||
<H3>Setup</H3>
|
|
||||||
<P>You need to include the <code>log4j.jar</code> in the classpath.
|
|
||||||
|
|
||||||
<H3>Usage</H3>
|
|
||||||
|
|
||||||
<P>The command line usage is:</P>
|
|
||||||
|
|
||||||
<PRE> java -D<property>=<value> org.apache.log4j.chainsaw.Main </PRE>
|
|
||||||
|
|
||||||
<P>The default behaviour of chainsaw can be changed by setting system properties
|
|
||||||
using the <CODE>-D<property>=<value></CODE> arguments to java. The
|
|
||||||
following table describes what properties can be set:</P>
|
|
||||||
|
|
||||||
<TABLE cellSpacing=0 cellPadding=2 border=1>
|
|
||||||
|
|
||||||
<TR>
|
|
||||||
<TD vAlign=top><B>Property</B></TD>
|
|
||||||
<TD vAlign=top><B>Description</B></TD></TR>
|
|
||||||
<TR>
|
|
||||||
<TD vAlign=top>chainsaw.port</TD>
|
|
||||||
<TD vAlign=top>Indicates which port to listen for connections on. Defaults
|
|
||||||
to <SPAN class=default>"4445"</SPAN>.
|
|
||||||
</TD>
|
|
||||||
</TR>
|
|
||||||
</TBODY>
|
|
||||||
</TABLE>
|
|
||||||
|
|
||||||
<H2>Configuring Log4J</H2>
|
|
||||||
|
|
||||||
<P>You will need to configure log4j to send logging events to
|
|
||||||
Chainsaw. Here is a sample <CODE>log4j.properties</CODE> file
|
|
||||||
for sending logging events to Chainsaw.</P>
|
|
||||||
|
|
||||||
<PRE>
|
|
||||||
log4j.rootLogger=DEBUG, CHAINSAW_CLIENT
|
|
||||||
|
|
||||||
log4j.appender.CHAINSAW_CLIENT=org.apache.log4j.net.SocketAppender
|
|
||||||
log4j.appender.CHAINSAW_CLIENT.RemoteHost=localhost
|
|
||||||
log4j.appender.CHAINSAW_CLIENT.Port=4445
|
|
||||||
log4j.appender.CHAINSAW_CLIENT.LocationInfo=true
|
|
||||||
</PRE>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.config;
|
|
||||||
|
|
||||||
import org.apache.log4j.Priority;
|
|
||||||
import org.apache.log4j.helpers.LogLog;
|
|
||||||
|
|
||||||
import java.beans.BeanInfo;
|
|
||||||
import java.beans.IntrospectionException;
|
|
||||||
import java.beans.Introspector;
|
|
||||||
import java.beans.PropertyDescriptor;
|
|
||||||
import java.io.InterruptedIOException;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Used for inferring configuration information for a log4j's component.
|
|
||||||
|
|
||||||
@author Anders Kristensen
|
|
||||||
*/
|
|
||||||
public class PropertyGetter {
|
|
||||||
protected static final Object[] NULL_ARG = new Object[] {};
|
|
||||||
protected Object obj;
|
|
||||||
protected PropertyDescriptor[] props;
|
|
||||||
|
|
||||||
public interface PropertyCallback {
|
|
||||||
void foundProperty(Object obj, String prefix, String name, Object value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Create a new PropertyGetter for the specified Object. This is done
|
|
||||||
in prepartion for invoking {@link
|
|
||||||
#getProperties(PropertyGetter.PropertyCallback, String)} one or
|
|
||||||
more times.
|
|
||||||
|
|
||||||
@param obj the object for which to set properties */
|
|
||||||
public
|
|
||||||
PropertyGetter(Object obj) throws IntrospectionException {
|
|
||||||
BeanInfo bi = Introspector.getBeanInfo(obj.getClass());
|
|
||||||
props = bi.getPropertyDescriptors();
|
|
||||||
this.obj = obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
static
|
|
||||||
void getProperties(Object obj, PropertyCallback callback, String prefix) {
|
|
||||||
try {
|
|
||||||
new PropertyGetter(obj).getProperties(callback, prefix);
|
|
||||||
} catch (IntrospectionException ex) {
|
|
||||||
LogLog.error("Failed to introspect object " + obj, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void getProperties(PropertyCallback callback, String prefix) {
|
|
||||||
for (int i = 0; i < props.length; i++) {
|
|
||||||
Method getter = props[i].getReadMethod();
|
|
||||||
if (getter == null) continue;
|
|
||||||
if (!isHandledType(getter.getReturnType())) {
|
|
||||||
//System.err.println("Ignoring " + props[i].getName() +" " + getter.getReturnType());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String name = props[i].getName();
|
|
||||||
try {
|
|
||||||
Object result = getter.invoke(obj, NULL_ARG);
|
|
||||||
//System.err.println("PROP " + name +": " + result);
|
|
||||||
if (result != null) {
|
|
||||||
callback.foundProperty(obj, prefix, name, result);
|
|
||||||
}
|
|
||||||
} catch (IllegalAccessException ex) {
|
|
||||||
LogLog.warn("Failed to get value of property " + name);
|
|
||||||
} catch (InvocationTargetException ex) {
|
|
||||||
if (ex.getTargetException() instanceof InterruptedException
|
|
||||||
|| ex.getTargetException() instanceof InterruptedIOException) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
LogLog.warn("Failed to get value of property " + name);
|
|
||||||
} catch (RuntimeException ex) {
|
|
||||||
LogLog.warn("Failed to get value of property " + name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected
|
|
||||||
boolean isHandledType(Class type) {
|
|
||||||
return String.class.isAssignableFrom(type) ||
|
|
||||||
Integer.TYPE.isAssignableFrom(type) ||
|
|
||||||
Long.TYPE.isAssignableFrom(type) ||
|
|
||||||
Boolean.TYPE.isAssignableFrom(type) ||
|
|
||||||
Priority.class.isAssignableFrom(type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,168 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.config;
|
|
||||||
|
|
||||||
import org.apache.log4j.Appender;
|
|
||||||
import org.apache.log4j.Category;
|
|
||||||
import org.apache.log4j.Level;
|
|
||||||
import org.apache.log4j.LogManager;
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.Hashtable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Prints the configuration of the log4j default hierarchy
|
|
||||||
(which needs to be auto-initialized) as a propoperties file
|
|
||||||
on a {@link PrintWriter}.
|
|
||||||
|
|
||||||
@author Anders Kristensen
|
|
||||||
*/
|
|
||||||
public class PropertyPrinter implements PropertyGetter.PropertyCallback {
|
|
||||||
protected int numAppenders = 0;
|
|
||||||
protected Hashtable appenderNames = new Hashtable();
|
|
||||||
protected Hashtable layoutNames = new Hashtable();
|
|
||||||
protected PrintWriter out;
|
|
||||||
protected boolean doCapitalize;
|
|
||||||
|
|
||||||
public
|
|
||||||
PropertyPrinter(PrintWriter out) {
|
|
||||||
this(out, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
PropertyPrinter(PrintWriter out, boolean doCapitalize) {
|
|
||||||
this.out = out;
|
|
||||||
this.doCapitalize = doCapitalize;
|
|
||||||
|
|
||||||
print(out);
|
|
||||||
out.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected
|
|
||||||
String genAppName() {
|
|
||||||
return "A" + numAppenders++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the specified appender name is considered to have
|
|
||||||
* been generated, that is, if it is of the form A[0-9]+.
|
|
||||||
*/
|
|
||||||
protected
|
|
||||||
boolean isGenAppName(String name) {
|
|
||||||
if (name.length() < 2 || name.charAt(0) != 'A') return false;
|
|
||||||
|
|
||||||
for (int i = 0; i < name.length(); i++) {
|
|
||||||
if (name.charAt(i) < '0' || name.charAt(i) > '9') return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prints the configuration of the default log4j hierarchy as a Java
|
|
||||||
* properties file on the specified Writer.
|
|
||||||
*
|
|
||||||
* <p>N.B. print() can be invoked only once!
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void print(PrintWriter out) {
|
|
||||||
printOptions(out, Logger.getRootLogger());
|
|
||||||
|
|
||||||
Enumeration cats = LogManager.getCurrentLoggers();
|
|
||||||
while (cats.hasMoreElements()) {
|
|
||||||
printOptions(out, (Logger) cats.nextElement());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @since 1.2.15
|
|
||||||
*/
|
|
||||||
protected
|
|
||||||
void printOptions(PrintWriter out, Category cat) {
|
|
||||||
Enumeration appenders = cat.getAllAppenders();
|
|
||||||
Level prio = cat.getLevel();
|
|
||||||
String appenderString = (prio == null ? "" : prio.toString());
|
|
||||||
|
|
||||||
while (appenders.hasMoreElements()) {
|
|
||||||
Appender app = (Appender) appenders.nextElement();
|
|
||||||
String name;
|
|
||||||
|
|
||||||
if ((name = (String) appenderNames.get(app)) == null) {
|
|
||||||
|
|
||||||
// first assign name to the appender
|
|
||||||
if ((name = app.getName()) == null || isGenAppName(name)) {
|
|
||||||
name = genAppName();
|
|
||||||
}
|
|
||||||
appenderNames.put(app, name);
|
|
||||||
|
|
||||||
printOptions(out, app, "log4j.appender."+name);
|
|
||||||
if (app.getLayout() != null) {
|
|
||||||
printOptions(out, app.getLayout(), "log4j.appender."+name+".layout");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
appenderString += ", " + name;
|
|
||||||
}
|
|
||||||
String catKey = (cat == Logger.getRootLogger())
|
|
||||||
? "log4j.rootLogger"
|
|
||||||
: "log4j.logger." + cat.getName();
|
|
||||||
if (appenderString != "") {
|
|
||||||
out.println(catKey + "=" + appenderString);
|
|
||||||
}
|
|
||||||
if (!cat.getAdditivity() && cat != Logger.getRootLogger()) {
|
|
||||||
out.println("log4j.additivity." + cat.getName() + "=false");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void printOptions(PrintWriter out, Logger cat) {
|
|
||||||
printOptions(out, (Category) cat);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected
|
|
||||||
void printOptions(PrintWriter out, Object obj, String fullname) {
|
|
||||||
out.println(fullname + "=" + obj.getClass().getName());
|
|
||||||
PropertyGetter.getProperties(obj, this, fullname + ".");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void foundProperty(Object obj, String prefix, String name, Object value) {
|
|
||||||
// XXX: Properties encode value.toString()
|
|
||||||
if (obj instanceof Appender && "name".equals(name)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (doCapitalize) {
|
|
||||||
name = capitalize(name);
|
|
||||||
}
|
|
||||||
out.println(prefix + name + "=" + value.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String capitalize(String name) {
|
|
||||||
if (Character.isLowerCase(name.charAt(0))) {
|
|
||||||
if (name.length() == 1 || Character.isLowerCase(name.charAt(1))) {
|
|
||||||
StringBuffer newname = new StringBuffer(name);
|
|
||||||
newname.setCharAt(0, Character.toUpperCase(name.charAt(0)));
|
|
||||||
return newname.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
// for testing
|
|
||||||
public static void main(String[] args) {
|
|
||||||
new PropertyPrinter(new PrintWriter(System.out));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,310 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Contributors: Georg Lundesgaard
|
|
||||||
|
|
||||||
package org.apache.log4j.config;
|
|
||||||
|
|
||||||
import org.apache.log4j.Appender;
|
|
||||||
import org.apache.log4j.Level;
|
|
||||||
import org.apache.log4j.Priority;
|
|
||||||
import org.apache.log4j.helpers.LogLog;
|
|
||||||
import org.apache.log4j.helpers.OptionConverter;
|
|
||||||
import org.apache.log4j.spi.OptionHandler;
|
|
||||||
import org.apache.log4j.spi.ErrorHandler;
|
|
||||||
|
|
||||||
import java.beans.BeanInfo;
|
|
||||||
import java.beans.IntrospectionException;
|
|
||||||
import java.beans.Introspector;
|
|
||||||
import java.beans.PropertyDescriptor;
|
|
||||||
import java.io.InterruptedIOException;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
General purpose Object property setter. Clients repeatedly invokes
|
|
||||||
{@link #setProperty setProperty(name,value)} in order to invoke setters
|
|
||||||
on the Object specified in the constructor. This class relies on the
|
|
||||||
JavaBeans {@link Introspector} to analyze the given Object Class using
|
|
||||||
reflection.
|
|
||||||
|
|
||||||
<p>Usage:
|
|
||||||
<pre>
|
|
||||||
PropertySetter ps = new PropertySetter(anObject);
|
|
||||||
ps.set("name", "Joe");
|
|
||||||
ps.set("age", "32");
|
|
||||||
ps.set("isMale", "true");
|
|
||||||
</pre>
|
|
||||||
will cause the invocations anObject.setName("Joe"), anObject.setAge(32),
|
|
||||||
and setMale(true) if such methods exist with those signatures.
|
|
||||||
Otherwise an {@link IntrospectionException} are thrown.
|
|
||||||
|
|
||||||
@author Anders Kristensen
|
|
||||||
@since 1.1
|
|
||||||
*/
|
|
||||||
public class PropertySetter {
|
|
||||||
protected Object obj;
|
|
||||||
protected PropertyDescriptor[] props;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Create a new PropertySetter for the specified Object. This is done
|
|
||||||
in prepartion for invoking {@link #setProperty} one or more times.
|
|
||||||
|
|
||||||
@param obj the object for which to set properties
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
PropertySetter(Object obj) {
|
|
||||||
this.obj = obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Uses JavaBeans {@link Introspector} to computer setters of object to be
|
|
||||||
configured.
|
|
||||||
*/
|
|
||||||
protected
|
|
||||||
void introspect() {
|
|
||||||
try {
|
|
||||||
BeanInfo bi = Introspector.getBeanInfo(obj.getClass());
|
|
||||||
props = bi.getPropertyDescriptors();
|
|
||||||
} catch (IntrospectionException ex) {
|
|
||||||
LogLog.error("Failed to introspect "+obj+": " + ex.getMessage());
|
|
||||||
props = new PropertyDescriptor[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set the properties of an object passed as a parameter in one
|
|
||||||
go. The <code>properties</code> are parsed relative to a
|
|
||||||
<code>prefix</code>.
|
|
||||||
|
|
||||||
@param obj The object to configure.
|
|
||||||
@param properties A java.util.Properties containing keys and values.
|
|
||||||
@param prefix Only keys having the specified prefix will be set.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
void setProperties(Object obj, Properties properties, String prefix) {
|
|
||||||
new PropertySetter(obj).setProperties(properties, prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set the properites for the object that match the
|
|
||||||
<code>prefix</code> passed as parameter.
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setProperties(Properties properties, String prefix) {
|
|
||||||
int len = prefix.length();
|
|
||||||
|
|
||||||
for (Enumeration e = properties.propertyNames(); e.hasMoreElements(); ) {
|
|
||||||
String key = (String) e.nextElement();
|
|
||||||
|
|
||||||
// handle only properties that start with the desired frefix.
|
|
||||||
if (key.startsWith(prefix)) {
|
|
||||||
|
|
||||||
|
|
||||||
// ignore key if it contains dots after the prefix
|
|
||||||
if (key.indexOf('.', len + 1) > 0) {
|
|
||||||
//System.err.println("----------Ignoring---["+key
|
|
||||||
// +"], prefix=["+prefix+"].");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String value = OptionConverter.findAndSubst(key, properties);
|
|
||||||
key = key.substring(len);
|
|
||||||
if (("layout".equals(key) || "errorhandler".equals(key)) && obj instanceof Appender) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// if the property type is an OptionHandler
|
|
||||||
// (for example, triggeringPolicy of org.apache.log4j.rolling.RollingFileAppender)
|
|
||||||
PropertyDescriptor prop = getPropertyDescriptor(Introspector.decapitalize(key));
|
|
||||||
if (prop != null
|
|
||||||
&& OptionHandler.class.isAssignableFrom(prop.getPropertyType())
|
|
||||||
&& prop.getWriteMethod() != null) {
|
|
||||||
OptionHandler opt = (OptionHandler)
|
|
||||||
OptionConverter.instantiateByKey(properties, prefix + key,
|
|
||||||
prop.getPropertyType(),
|
|
||||||
null);
|
|
||||||
PropertySetter setter = new PropertySetter(opt);
|
|
||||||
setter.setProperties(properties, prefix + key + ".");
|
|
||||||
try {
|
|
||||||
prop.getWriteMethod().invoke(this.obj, new Object[] { opt });
|
|
||||||
} catch(IllegalAccessException ex) {
|
|
||||||
LogLog.warn("Failed to set property [" + key +
|
|
||||||
"] to value \"" + value + "\". ", ex);
|
|
||||||
} catch(InvocationTargetException ex) {
|
|
||||||
if (ex.getTargetException() instanceof InterruptedException
|
|
||||||
|| ex.getTargetException() instanceof InterruptedIOException) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
LogLog.warn("Failed to set property [" + key +
|
|
||||||
"] to value \"" + value + "\". ", ex);
|
|
||||||
} catch(RuntimeException ex) {
|
|
||||||
LogLog.warn("Failed to set property [" + key +
|
|
||||||
"] to value \"" + value + "\". ", ex);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
setProperty(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
activate();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set a property on this PropertySetter's Object. If successful, this
|
|
||||||
method will invoke a setter method on the underlying Object. The
|
|
||||||
setter is the one for the specified property name and the value is
|
|
||||||
determined partly from the setter argument type and partly from the
|
|
||||||
value specified in the call to this method.
|
|
||||||
|
|
||||||
<p>If the setter expects a String no conversion is necessary.
|
|
||||||
If it expects an int, then an attempt is made to convert 'value'
|
|
||||||
to an int using new Integer(value). If the setter expects a boolean,
|
|
||||||
the conversion is by new Boolean(value).
|
|
||||||
|
|
||||||
@param name name of the property
|
|
||||||
@param value String value of the property
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setProperty(String name, String value) {
|
|
||||||
if (value == null) return;
|
|
||||||
|
|
||||||
name = Introspector.decapitalize(name);
|
|
||||||
PropertyDescriptor prop = getPropertyDescriptor(name);
|
|
||||||
|
|
||||||
//LogLog.debug("---------Key: "+name+", type="+prop.getPropertyType());
|
|
||||||
|
|
||||||
if (prop == null) {
|
|
||||||
LogLog.warn("No such property [" + name + "] in "+
|
|
||||||
obj.getClass().getName()+"." );
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
setProperty(prop, name, value);
|
|
||||||
} catch (PropertySetterException ex) {
|
|
||||||
LogLog.warn("Failed to set property [" + name +
|
|
||||||
"] to value \"" + value + "\". ", ex.rootCause);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set the named property given a {@link PropertyDescriptor}.
|
|
||||||
|
|
||||||
@param prop A PropertyDescriptor describing the characteristics
|
|
||||||
of the property to set.
|
|
||||||
@param name The named of the property to set.
|
|
||||||
@param value The value of the property.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setProperty(PropertyDescriptor prop, String name, String value)
|
|
||||||
throws PropertySetterException {
|
|
||||||
Method setter = prop.getWriteMethod();
|
|
||||||
if (setter == null) {
|
|
||||||
throw new PropertySetterException("No setter for property ["+name+"].");
|
|
||||||
}
|
|
||||||
Class[] paramTypes = setter.getParameterTypes();
|
|
||||||
if (paramTypes.length != 1) {
|
|
||||||
throw new PropertySetterException("#params for setter != 1");
|
|
||||||
}
|
|
||||||
|
|
||||||
Object arg;
|
|
||||||
try {
|
|
||||||
arg = convertArg(value, paramTypes[0]);
|
|
||||||
} catch (Throwable t) {
|
|
||||||
throw new PropertySetterException("Conversion to type ["+paramTypes[0]+
|
|
||||||
"] failed. Reason: "+t);
|
|
||||||
}
|
|
||||||
if (arg == null) {
|
|
||||||
throw new PropertySetterException(
|
|
||||||
"Conversion to type ["+paramTypes[0]+"] failed.");
|
|
||||||
}
|
|
||||||
LogLog.debug("Setting property [" + name + "] to [" +arg+"].");
|
|
||||||
try {
|
|
||||||
setter.invoke(obj, new Object[] { arg });
|
|
||||||
} catch (IllegalAccessException ex) {
|
|
||||||
throw new PropertySetterException(ex);
|
|
||||||
} catch (InvocationTargetException ex) {
|
|
||||||
if (ex.getTargetException() instanceof InterruptedException
|
|
||||||
|| ex.getTargetException() instanceof InterruptedIOException) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
throw new PropertySetterException(ex);
|
|
||||||
} catch (RuntimeException ex) {
|
|
||||||
throw new PropertySetterException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Convert <code>val</code> a String parameter to an object of a
|
|
||||||
given type.
|
|
||||||
*/
|
|
||||||
protected
|
|
||||||
Object convertArg(String val, Class type) {
|
|
||||||
if(val == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
String v = val.trim();
|
|
||||||
if (String.class.isAssignableFrom(type)) {
|
|
||||||
return val;
|
|
||||||
} else if (Integer.TYPE.isAssignableFrom(type)) {
|
|
||||||
return new Integer(v);
|
|
||||||
} else if (Long.TYPE.isAssignableFrom(type)) {
|
|
||||||
return new Long(v);
|
|
||||||
} else if (Boolean.TYPE.isAssignableFrom(type)) {
|
|
||||||
if ("true".equalsIgnoreCase(v)) {
|
|
||||||
return Boolean.TRUE;
|
|
||||||
} else if ("false".equalsIgnoreCase(v)) {
|
|
||||||
return Boolean.FALSE;
|
|
||||||
}
|
|
||||||
} else if (Priority.class.isAssignableFrom(type)) {
|
|
||||||
return OptionConverter.toLevel(v, (Level) Level.DEBUG);
|
|
||||||
} else if (ErrorHandler.class.isAssignableFrom(type)) {
|
|
||||||
return OptionConverter.instantiateByClassName(v,
|
|
||||||
ErrorHandler.class, null);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected
|
|
||||||
PropertyDescriptor getPropertyDescriptor(String name) {
|
|
||||||
if (props == null) introspect();
|
|
||||||
|
|
||||||
for (int i = 0; i < props.length; i++) {
|
|
||||||
if (name.equals(props[i].getName())) {
|
|
||||||
return props[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void activate() {
|
|
||||||
if (obj instanceof OptionHandler) {
|
|
||||||
((OptionHandler) obj).activateOptions();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.config;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Thrown when an error is encountered whilst attempting to set a property
|
|
||||||
* using the {@link PropertySetter} utility class.
|
|
||||||
*
|
|
||||||
* @author Anders Kristensen
|
|
||||||
* @since 1.1
|
|
||||||
*/
|
|
||||||
public class PropertySetterException extends Exception {
|
|
||||||
private static final long serialVersionUID = -1352613734254235861L;
|
|
||||||
protected Throwable rootCause;
|
|
||||||
|
|
||||||
public
|
|
||||||
PropertySetterException(String msg) {
|
|
||||||
super(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
PropertySetterException(Throwable rootCause)
|
|
||||||
{
|
|
||||||
super();
|
|
||||||
this.rootCause = rootCause;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns descriptive text on the cause of this exception.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
String getMessage() {
|
|
||||||
String msg = super.getMessage();
|
|
||||||
if (msg == null && rootCause != null) {
|
|
||||||
msg = rootCause.getMessage();
|
|
||||||
}
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
<html>
|
|
||||||
<!--
|
|
||||||
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.
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
<body>
|
|
||||||
Package used in getting/setting component properties.
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.helpers;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.TimeZone;
|
|
||||||
import java.text.FieldPosition;
|
|
||||||
import java.text.ParsePosition;
|
|
||||||
import java.text.DateFormat;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Formats a {@link Date} in the format "HH:mm:ss,SSS" for example,
|
|
||||||
"15:49:37,459".
|
|
||||||
|
|
||||||
@author Ceki Gülcü
|
|
||||||
@author Andrew Vajoczki
|
|
||||||
|
|
||||||
@since 0.7.5
|
|
||||||
*/
|
|
||||||
public class AbsoluteTimeDateFormat extends DateFormat {
|
|
||||||
private static final long serialVersionUID = -388856345976723342L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
String constant used to specify {@link
|
|
||||||
org.apache.log4j.helpers.AbsoluteTimeDateFormat} in layouts. Current
|
|
||||||
value is <b>ABSOLUTE</b>. */
|
|
||||||
public final static String ABS_TIME_DATE_FORMAT = "ABSOLUTE";
|
|
||||||
|
|
||||||
/**
|
|
||||||
String constant used to specify {@link
|
|
||||||
org.apache.log4j.helpers.DateTimeDateFormat} in layouts. Current
|
|
||||||
value is <b>DATE</b>.
|
|
||||||
*/
|
|
||||||
public final static String DATE_AND_TIME_DATE_FORMAT = "DATE";
|
|
||||||
|
|
||||||
/**
|
|
||||||
String constant used to specify {@link
|
|
||||||
org.apache.log4j.helpers.ISO8601DateFormat} in layouts. Current
|
|
||||||
value is <b>ISO8601</b>.
|
|
||||||
*/
|
|
||||||
public final static String ISO8601_DATE_FORMAT = "ISO8601";
|
|
||||||
|
|
||||||
public
|
|
||||||
AbsoluteTimeDateFormat() {
|
|
||||||
setCalendar(Calendar.getInstance());
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
AbsoluteTimeDateFormat(TimeZone timeZone) {
|
|
||||||
setCalendar(Calendar.getInstance(timeZone));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static long previousTime;
|
|
||||||
private static char[] previousTimeWithoutMillis = new char[9]; // "HH:mm:ss."
|
|
||||||
|
|
||||||
/**
|
|
||||||
Appends to <code>sbuf</code> the time in the format
|
|
||||||
"HH:mm:ss,SSS" for example, "15:49:37,459"
|
|
||||||
|
|
||||||
@param date the date to format
|
|
||||||
@param sbuf the string buffer to write to
|
|
||||||
@param fieldPosition remains untouched
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
StringBuffer format(Date date, StringBuffer sbuf,
|
|
||||||
FieldPosition fieldPosition) {
|
|
||||||
|
|
||||||
long now = date.getTime();
|
|
||||||
int millis = (int)(now % 1000);
|
|
||||||
|
|
||||||
if ((now - millis) != previousTime || previousTimeWithoutMillis[0] == 0) {
|
|
||||||
// We reach this point at most once per second
|
|
||||||
// across all threads instead of each time format()
|
|
||||||
// is called. This saves considerable CPU time.
|
|
||||||
|
|
||||||
calendar.setTime(date);
|
|
||||||
|
|
||||||
int start = sbuf.length();
|
|
||||||
|
|
||||||
int hour = calendar.get(Calendar.HOUR_OF_DAY);
|
|
||||||
if(hour < 10) {
|
|
||||||
sbuf.append('0');
|
|
||||||
}
|
|
||||||
sbuf.append(hour);
|
|
||||||
sbuf.append(':');
|
|
||||||
|
|
||||||
int mins = calendar.get(Calendar.MINUTE);
|
|
||||||
if(mins < 10) {
|
|
||||||
sbuf.append('0');
|
|
||||||
}
|
|
||||||
sbuf.append(mins);
|
|
||||||
sbuf.append(':');
|
|
||||||
|
|
||||||
int secs = calendar.get(Calendar.SECOND);
|
|
||||||
if(secs < 10) {
|
|
||||||
sbuf.append('0');
|
|
||||||
}
|
|
||||||
sbuf.append(secs);
|
|
||||||
sbuf.append(',');
|
|
||||||
|
|
||||||
// store the time string for next time to avoid recomputation
|
|
||||||
sbuf.getChars(start, sbuf.length(), previousTimeWithoutMillis, 0);
|
|
||||||
|
|
||||||
previousTime = now - millis;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sbuf.append(previousTimeWithoutMillis);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if(millis < 100)
|
|
||||||
sbuf.append('0');
|
|
||||||
if(millis < 10)
|
|
||||||
sbuf.append('0');
|
|
||||||
|
|
||||||
sbuf.append(millis);
|
|
||||||
return sbuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
This method does not do anything but return <code>null</code>.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
Date parse(String s, ParsePosition pos) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,176 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.helpers;
|
|
||||||
|
|
||||||
import org.apache.log4j.spi.AppenderAttachable;
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
|
|
||||||
import org.apache.log4j.Appender;
|
|
||||||
import java.util.Vector;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
|
|
||||||
/**
|
|
||||||
A straightforward implementation of the {@link AppenderAttachable}
|
|
||||||
interface.
|
|
||||||
|
|
||||||
@author Ceki Gülcü
|
|
||||||
@since version 0.9.1 */
|
|
||||||
public class AppenderAttachableImpl implements AppenderAttachable {
|
|
||||||
|
|
||||||
/** Array of appenders. */
|
|
||||||
protected Vector appenderList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Attach an appender. If the appender is already in the list in
|
|
||||||
won't be added again.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void addAppender(Appender newAppender) {
|
|
||||||
// Null values for newAppender parameter are strictly forbidden.
|
|
||||||
if(newAppender == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(appenderList == null) {
|
|
||||||
appenderList = new Vector(1);
|
|
||||||
}
|
|
||||||
if(!appenderList.contains(newAppender))
|
|
||||||
appenderList.addElement(newAppender);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Call the <code>doAppend</code> method on all attached appenders. */
|
|
||||||
public
|
|
||||||
int appendLoopOnAppenders(LoggingEvent event) {
|
|
||||||
int size = 0;
|
|
||||||
Appender appender;
|
|
||||||
|
|
||||||
if(appenderList != null) {
|
|
||||||
size = appenderList.size();
|
|
||||||
for(int i = 0; i < size; i++) {
|
|
||||||
appender = (Appender) appenderList.elementAt(i);
|
|
||||||
appender.doAppend(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get all attached appenders as an Enumeration. If there are no
|
|
||||||
attached appenders <code>null</code> is returned.
|
|
||||||
|
|
||||||
@return Enumeration An enumeration of attached appenders.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
Enumeration getAllAppenders() {
|
|
||||||
if(appenderList == null)
|
|
||||||
return null;
|
|
||||||
else
|
|
||||||
return appenderList.elements();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Look for an attached appender named as <code>name</code>.
|
|
||||||
|
|
||||||
<p>Return the appender with that name if in the list. Return null
|
|
||||||
otherwise.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
Appender getAppender(String name) {
|
|
||||||
if(appenderList == null || name == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
int size = appenderList.size();
|
|
||||||
Appender appender;
|
|
||||||
for(int i = 0; i < size; i++) {
|
|
||||||
appender = (Appender) appenderList.elementAt(i);
|
|
||||||
if(name.equals(appender.getName()))
|
|
||||||
return appender;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns <code>true</code> if the specified appender is in the
|
|
||||||
list of attached appenders, <code>false</code> otherwise.
|
|
||||||
|
|
||||||
@since 1.2 */
|
|
||||||
public
|
|
||||||
boolean isAttached(Appender appender) {
|
|
||||||
if(appenderList == null || appender == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
int size = appenderList.size();
|
|
||||||
Appender a;
|
|
||||||
for(int i = 0; i < size; i++) {
|
|
||||||
a = (Appender) appenderList.elementAt(i);
|
|
||||||
if(a == appender)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove and close all previously attached appenders.
|
|
||||||
* */
|
|
||||||
public
|
|
||||||
void removeAllAppenders() {
|
|
||||||
if(appenderList != null) {
|
|
||||||
int len = appenderList.size();
|
|
||||||
for(int i = 0; i < len; i++) {
|
|
||||||
Appender a = (Appender) appenderList.elementAt(i);
|
|
||||||
a.close();
|
|
||||||
}
|
|
||||||
appenderList.removeAllElements();
|
|
||||||
appenderList = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Remove the appender passed as parameter form the list of attached
|
|
||||||
appenders. */
|
|
||||||
public
|
|
||||||
void removeAppender(Appender appender) {
|
|
||||||
if(appender == null || appenderList == null)
|
|
||||||
return;
|
|
||||||
appenderList.removeElement(appender);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Remove the appender with the name passed as parameter form the
|
|
||||||
list of appenders.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void removeAppender(String name) {
|
|
||||||
if(name == null || appenderList == null) return;
|
|
||||||
int size = appenderList.size();
|
|
||||||
for(int i = 0; i < size; i++) {
|
|
||||||
if(name.equals(((Appender)appenderList.elementAt(i)).getName())) {
|
|
||||||
appenderList.removeElementAt(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,181 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Contributors: Mathias Bogaert
|
|
||||||
// joelr@viair.com
|
|
||||||
|
|
||||||
package org.apache.log4j.helpers;
|
|
||||||
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
<code>BoundedFIFO</code> serves as the bounded first-in-first-out
|
|
||||||
buffer heavily used by the {@link org.apache.log4j.AsyncAppender}.
|
|
||||||
|
|
||||||
@author Ceki Gülcü
|
|
||||||
@since version 0.9.1 */
|
|
||||||
public class BoundedFIFO {
|
|
||||||
|
|
||||||
LoggingEvent[] buf;
|
|
||||||
int numElements = 0;
|
|
||||||
int first = 0;
|
|
||||||
int next = 0;
|
|
||||||
int maxSize;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Instantiate a new BoundedFIFO with a maximum size passed as argument.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
BoundedFIFO(int maxSize) {
|
|
||||||
if(maxSize < 1) {
|
|
||||||
throw new IllegalArgumentException("The maxSize argument ("+maxSize+
|
|
||||||
") is not a positive integer.");
|
|
||||||
}
|
|
||||||
this.maxSize = maxSize;
|
|
||||||
buf = new LoggingEvent[maxSize];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get the first element in the buffer. Returns <code>null</code> if
|
|
||||||
there are no elements in the buffer. */
|
|
||||||
public
|
|
||||||
LoggingEvent get() {
|
|
||||||
if(numElements == 0)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
LoggingEvent r = buf[first];
|
|
||||||
buf[first] = null; // help garbage collection
|
|
||||||
|
|
||||||
if(++first == maxSize) {
|
|
||||||
first = 0;
|
|
||||||
}
|
|
||||||
numElements--;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Place a {@link LoggingEvent} in the buffer. If the buffer is full
|
|
||||||
then the event is <b>silently dropped</b>. It is the caller's
|
|
||||||
responsability to make sure that the buffer has free space. */
|
|
||||||
public
|
|
||||||
void put(LoggingEvent o) {
|
|
||||||
if(numElements != maxSize) {
|
|
||||||
buf[next] = o;
|
|
||||||
if(++next == maxSize) {
|
|
||||||
next = 0;
|
|
||||||
}
|
|
||||||
numElements++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get the maximum size of the buffer.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
int getMaxSize() {
|
|
||||||
return maxSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Return <code>true</code> if the buffer is full, that is, whether
|
|
||||||
the number of elements in the buffer equals the buffer size. */
|
|
||||||
public
|
|
||||||
boolean isFull() {
|
|
||||||
return numElements == maxSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get the number of elements in the buffer. This number is
|
|
||||||
guaranteed to be in the range 0 to <code>maxSize</code>
|
|
||||||
(inclusive).
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
int length() {
|
|
||||||
return numElements;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int min(int a, int b) {
|
|
||||||
return a < b ? a : b;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Resize the buffer to a new size. If the new size is smaller than
|
|
||||||
the old size events might be lost.
|
|
||||||
|
|
||||||
@since 1.1
|
|
||||||
*/
|
|
||||||
synchronized
|
|
||||||
public
|
|
||||||
void resize(int newSize) {
|
|
||||||
if(newSize == maxSize)
|
|
||||||
return;
|
|
||||||
|
|
||||||
|
|
||||||
LoggingEvent[] tmp = new LoggingEvent[newSize];
|
|
||||||
|
|
||||||
// we should not copy beyond the buf array
|
|
||||||
int len1 = maxSize - first;
|
|
||||||
|
|
||||||
// we should not copy beyond the tmp array
|
|
||||||
len1 = min(len1, newSize);
|
|
||||||
|
|
||||||
// er.. how much do we actually need to copy?
|
|
||||||
// We should not copy more than the actual number of elements.
|
|
||||||
len1 = min(len1, numElements);
|
|
||||||
|
|
||||||
// Copy from buf starting a first, to tmp, starting at position 0, len1 elements.
|
|
||||||
System.arraycopy(buf, first, tmp, 0, len1);
|
|
||||||
|
|
||||||
// Are there any uncopied elements and is there still space in the new array?
|
|
||||||
int len2 = 0;
|
|
||||||
if((len1 < numElements) && (len1 < newSize)) {
|
|
||||||
len2 = numElements - len1;
|
|
||||||
len2 = min(len2, newSize - len1);
|
|
||||||
System.arraycopy(buf, 0, tmp, len1, len2);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.buf = tmp;
|
|
||||||
this.maxSize = newSize;
|
|
||||||
this.first=0;
|
|
||||||
this.numElements = len1+len2;
|
|
||||||
this.next = this.numElements;
|
|
||||||
if(this.next == this.maxSize) // this should never happen, but again, it just might.
|
|
||||||
this.next = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns <code>true</code> if there is just one element in the
|
|
||||||
buffer. In other words, if there were no elements before the last
|
|
||||||
{@link #put} operation completed. */
|
|
||||||
public
|
|
||||||
boolean wasEmpty() {
|
|
||||||
return numElements == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns <code>true</code> if the number of elements in the
|
|
||||||
buffer plus 1 equals the maximum buffer size, returns
|
|
||||||
<code>false</code> otherwise. */
|
|
||||||
public
|
|
||||||
boolean wasFull() {
|
|
||||||
return (numElements+1 == maxSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.helpers;
|
|
||||||
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.apache.log4j.spi.ErrorHandler;
|
|
||||||
import org.apache.log4j.spi.ErrorCode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Counts the number of bytes written.
|
|
||||||
|
|
||||||
@author Heinz Richter, heinz.richter@frogdot.com
|
|
||||||
@since 0.8.1
|
|
||||||
|
|
||||||
*/
|
|
||||||
public class CountingQuietWriter extends QuietWriter {
|
|
||||||
|
|
||||||
protected long count;
|
|
||||||
|
|
||||||
public
|
|
||||||
CountingQuietWriter(Writer writer, ErrorHandler eh) {
|
|
||||||
super(writer, eh);
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void write(String string) {
|
|
||||||
try {
|
|
||||||
out.write(string);
|
|
||||||
count += string.length();
|
|
||||||
}
|
|
||||||
catch(IOException e) {
|
|
||||||
errorHandler.error("Write failure.", e, ErrorCode.WRITE_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
long getCount() {
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void setCount(long count) {
|
|
||||||
this.count = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.helpers;
|
|
||||||
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
|
|
||||||
CyclicBuffer is used by other appenders to hold {@link LoggingEvent
|
|
||||||
LoggingEvents} for immediate or differed display.
|
|
||||||
|
|
||||||
<p>This buffer gives read access to any element in the buffer not
|
|
||||||
just the first or last element.
|
|
||||||
|
|
||||||
@author Ceki Gülcü
|
|
||||||
@since 0.9.0
|
|
||||||
|
|
||||||
*/
|
|
||||||
public class CyclicBuffer {
|
|
||||||
|
|
||||||
LoggingEvent[] ea;
|
|
||||||
int first;
|
|
||||||
int last;
|
|
||||||
int numElems;
|
|
||||||
int maxSize;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Instantiate a new CyclicBuffer of at most <code>maxSize</code> events.
|
|
||||||
|
|
||||||
The <code>maxSize</code> argument must a positive integer.
|
|
||||||
|
|
||||||
@param maxSize The maximum number of elements in the buffer.
|
|
||||||
*/
|
|
||||||
public CyclicBuffer(int maxSize) throws IllegalArgumentException {
|
|
||||||
if(maxSize < 1) {
|
|
||||||
throw new IllegalArgumentException("The maxSize argument ("+maxSize+
|
|
||||||
") is not a positive integer.");
|
|
||||||
}
|
|
||||||
this.maxSize = maxSize;
|
|
||||||
ea = new LoggingEvent[maxSize];
|
|
||||||
first = 0;
|
|
||||||
last = 0;
|
|
||||||
numElems = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Add an <code>event</code> as the last event in the buffer.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void add(LoggingEvent event) {
|
|
||||||
ea[last] = event;
|
|
||||||
if(++last == maxSize)
|
|
||||||
last = 0;
|
|
||||||
|
|
||||||
if(numElems < maxSize)
|
|
||||||
numElems++;
|
|
||||||
else if(++first == maxSize)
|
|
||||||
first = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get the <i>i</i>th oldest event currently in the buffer. If
|
|
||||||
<em>i</em> is outside the range 0 to the number of elements
|
|
||||||
currently in the buffer, then <code>null</code> is returned.
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
LoggingEvent get(int i) {
|
|
||||||
if(i < 0 || i >= numElems)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return ea[(first + i) % maxSize];
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
int getMaxSize() {
|
|
||||||
return maxSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get the oldest (first) element in the buffer. The oldest element
|
|
||||||
is removed from the buffer.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
LoggingEvent get() {
|
|
||||||
LoggingEvent r = null;
|
|
||||||
if(numElems > 0) {
|
|
||||||
numElems--;
|
|
||||||
r = ea[first];
|
|
||||||
ea[first] = null;
|
|
||||||
if(++first == maxSize)
|
|
||||||
first = 0;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get the number of elements in the buffer. This number is
|
|
||||||
guaranteed to be in the range 0 to <code>maxSize</code>
|
|
||||||
(inclusive).
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
int length() {
|
|
||||||
return numElems;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Resize the cyclic buffer to <code>newSize</code>.
|
|
||||||
|
|
||||||
@throws IllegalArgumentException if <code>newSize</code> is negative.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void resize(int newSize) {
|
|
||||||
if(newSize < 0) {
|
|
||||||
throw new IllegalArgumentException("Negative array size ["+newSize+
|
|
||||||
"] not allowed.");
|
|
||||||
}
|
|
||||||
if(newSize == numElems)
|
|
||||||
return; // nothing to do
|
|
||||||
|
|
||||||
LoggingEvent[] temp = new LoggingEvent[newSize];
|
|
||||||
|
|
||||||
int loopLen = newSize < numElems ? newSize : numElems;
|
|
||||||
|
|
||||||
for(int i = 0; i < loopLen; i++) {
|
|
||||||
temp[i] = ea[first];
|
|
||||||
ea[first] = null;
|
|
||||||
if(++first == numElems)
|
|
||||||
first = 0;
|
|
||||||
}
|
|
||||||
ea = temp;
|
|
||||||
first = 0;
|
|
||||||
numElems = loopLen;
|
|
||||||
maxSize = newSize;
|
|
||||||
if (loopLen == newSize) {
|
|
||||||
last = 0;
|
|
||||||
} else {
|
|
||||||
last = loopLen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,200 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.helpers;
|
|
||||||
|
|
||||||
import org.apache.log4j.Layout;
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.TimeZone;
|
|
||||||
import java.text.FieldPosition;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
This abstract layout takes care of all the date related options and
|
|
||||||
formatting work.
|
|
||||||
|
|
||||||
|
|
||||||
@author Ceki Gülcü
|
|
||||||
*/
|
|
||||||
abstract public class DateLayout extends Layout {
|
|
||||||
|
|
||||||
/**
|
|
||||||
String constant designating no time information. Current value of
|
|
||||||
this constant is <b>NULL</b>.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public final static String NULL_DATE_FORMAT = "NULL";
|
|
||||||
|
|
||||||
/**
|
|
||||||
String constant designating relative time. Current value of
|
|
||||||
this constant is <b>RELATIVE</b>.
|
|
||||||
*/
|
|
||||||
public final static String RELATIVE_TIME_DATE_FORMAT = "RELATIVE";
|
|
||||||
|
|
||||||
protected FieldPosition pos = new FieldPosition(0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
@deprecated Options are now handled using the JavaBeans paradigm.
|
|
||||||
This constant is not longer needed and will be removed in the
|
|
||||||
<em>near</em> term.
|
|
||||||
*/
|
|
||||||
final static public String DATE_FORMAT_OPTION = "DateFormat";
|
|
||||||
|
|
||||||
/**
|
|
||||||
@deprecated Options are now handled using the JavaBeans paradigm.
|
|
||||||
This constant is not longer needed and will be removed in the
|
|
||||||
<em>near</em> term.
|
|
||||||
*/
|
|
||||||
final static public String TIMEZONE_OPTION = "TimeZone";
|
|
||||||
|
|
||||||
private String timeZoneID;
|
|
||||||
private String dateFormatOption;
|
|
||||||
|
|
||||||
protected DateFormat dateFormat;
|
|
||||||
protected Date date = new Date();
|
|
||||||
|
|
||||||
/**
|
|
||||||
@deprecated Use the setter method for the option directly instead
|
|
||||||
of the generic <code>setOption</code> method.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
String[] getOptionStrings() {
|
|
||||||
return new String[] {DATE_FORMAT_OPTION, TIMEZONE_OPTION};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@deprecated Use the setter method for the option directly instead
|
|
||||||
of the generic <code>setOption</code> method.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setOption(String option, String value) {
|
|
||||||
if(option.equalsIgnoreCase(DATE_FORMAT_OPTION)) {
|
|
||||||
dateFormatOption = value.toUpperCase();
|
|
||||||
} else if(option.equalsIgnoreCase(TIMEZONE_OPTION)) {
|
|
||||||
timeZoneID = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
The value of the <b>DateFormat</b> option should be either an
|
|
||||||
argument to the constructor of {@link SimpleDateFormat} or one of
|
|
||||||
the srings "NULL", "RELATIVE", "ABSOLUTE", "DATE" or "ISO8601.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setDateFormat(String dateFormat) {
|
|
||||||
if (dateFormat != null) {
|
|
||||||
dateFormatOption = dateFormat;
|
|
||||||
}
|
|
||||||
setDateFormat(dateFormatOption, TimeZone.getDefault());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns value of the <b>DateFormat</b> option.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
String getDateFormat() {
|
|
||||||
return dateFormatOption;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
The <b>TimeZoneID</b> option is a time zone ID string in the format
|
|
||||||
expected by the {@link TimeZone#getTimeZone} method.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setTimeZone(String timeZone) {
|
|
||||||
this.timeZoneID = timeZone;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns value of the <b>TimeZone</b> option.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
String getTimeZone() {
|
|
||||||
return timeZoneID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void activateOptions() {
|
|
||||||
setDateFormat(dateFormatOption);
|
|
||||||
if(timeZoneID != null && dateFormat != null) {
|
|
||||||
dateFormat.setTimeZone(TimeZone.getTimeZone(timeZoneID));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void dateFormat(StringBuffer buf, LoggingEvent event) {
|
|
||||||
if(dateFormat != null) {
|
|
||||||
date.setTime(event.timeStamp);
|
|
||||||
dateFormat.format(date, buf, this.pos);
|
|
||||||
buf.append(' ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Sets the {@link DateFormat} used to format time and date in the
|
|
||||||
zone determined by <code>timeZone</code>.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setDateFormat(DateFormat dateFormat, TimeZone timeZone) {
|
|
||||||
this.dateFormat = dateFormat;
|
|
||||||
this.dateFormat.setTimeZone(timeZone);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Sets the DateFormat used to format date and time in the time zone
|
|
||||||
determined by <code>timeZone</code> parameter. The {@link DateFormat} used
|
|
||||||
will depend on the <code>dateFormatType</code>.
|
|
||||||
|
|
||||||
<p>The recognized types are {@link #NULL_DATE_FORMAT}, {@link
|
|
||||||
#RELATIVE_TIME_DATE_FORMAT} {@link
|
|
||||||
AbsoluteTimeDateFormat#ABS_TIME_DATE_FORMAT}, {@link
|
|
||||||
AbsoluteTimeDateFormat#DATE_AND_TIME_DATE_FORMAT} and {@link
|
|
||||||
AbsoluteTimeDateFormat#ISO8601_DATE_FORMAT}. If the
|
|
||||||
<code>dateFormatType</code> is not one of the above, then the
|
|
||||||
argument is assumed to be a date pattern for {@link
|
|
||||||
SimpleDateFormat}.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setDateFormat(String dateFormatType, TimeZone timeZone) {
|
|
||||||
if(dateFormatType == null) {
|
|
||||||
this.dateFormat = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(dateFormatType.equalsIgnoreCase(NULL_DATE_FORMAT)) {
|
|
||||||
this.dateFormat = null;
|
|
||||||
} else if (dateFormatType.equalsIgnoreCase(RELATIVE_TIME_DATE_FORMAT)) {
|
|
||||||
this.dateFormat = new RelativeTimeDateFormat();
|
|
||||||
} else if(dateFormatType.equalsIgnoreCase(
|
|
||||||
AbsoluteTimeDateFormat.ABS_TIME_DATE_FORMAT)) {
|
|
||||||
this.dateFormat = new AbsoluteTimeDateFormat(timeZone);
|
|
||||||
} else if(dateFormatType.equalsIgnoreCase(
|
|
||||||
AbsoluteTimeDateFormat.DATE_AND_TIME_DATE_FORMAT)) {
|
|
||||||
this.dateFormat = new DateTimeDateFormat(timeZone);
|
|
||||||
} else if(dateFormatType.equalsIgnoreCase(
|
|
||||||
AbsoluteTimeDateFormat.ISO8601_DATE_FORMAT)) {
|
|
||||||
this.dateFormat = new ISO8601DateFormat(timeZone);
|
|
||||||
} else {
|
|
||||||
this.dateFormat = new SimpleDateFormat(dateFormatType);
|
|
||||||
this.dateFormat.setTimeZone(timeZone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.helpers;
|
|
||||||
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.TimeZone;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.text.FieldPosition;
|
|
||||||
import java.text.ParsePosition;
|
|
||||||
import java.text.DateFormatSymbols;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Formats a {@link Date} in the format "dd MMM yyyy HH:mm:ss,SSS" for example,
|
|
||||||
"06 Nov 1994 15:49:37,459".
|
|
||||||
|
|
||||||
@author Ceki Gülcü
|
|
||||||
@since 0.7.5
|
|
||||||
*/
|
|
||||||
public class DateTimeDateFormat extends AbsoluteTimeDateFormat {
|
|
||||||
private static final long serialVersionUID = 5547637772208514971L;
|
|
||||||
|
|
||||||
String[] shortMonths;
|
|
||||||
|
|
||||||
public
|
|
||||||
DateTimeDateFormat() {
|
|
||||||
super();
|
|
||||||
shortMonths = new DateFormatSymbols().getShortMonths();
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
DateTimeDateFormat(TimeZone timeZone) {
|
|
||||||
this();
|
|
||||||
setCalendar(Calendar.getInstance(timeZone));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Appends to <code>sbuf</code> the date in the format "dd MMM yyyy
|
|
||||||
HH:mm:ss,SSS" for example, "06 Nov 1994 08:49:37,459".
|
|
||||||
|
|
||||||
@param sbuf the string buffer to write to
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
StringBuffer format(Date date, StringBuffer sbuf,
|
|
||||||
FieldPosition fieldPosition) {
|
|
||||||
|
|
||||||
calendar.setTime(date);
|
|
||||||
|
|
||||||
int day = calendar.get(Calendar.DAY_OF_MONTH);
|
|
||||||
if(day < 10)
|
|
||||||
sbuf.append('0');
|
|
||||||
sbuf.append(day);
|
|
||||||
sbuf.append(' ');
|
|
||||||
sbuf.append(shortMonths[calendar.get(Calendar.MONTH)]);
|
|
||||||
sbuf.append(' ');
|
|
||||||
|
|
||||||
int year = calendar.get(Calendar.YEAR);
|
|
||||||
sbuf.append(year);
|
|
||||||
sbuf.append(' ');
|
|
||||||
|
|
||||||
return super.format(date, sbuf, fieldPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
This method does not do anything but return <code>null</code>.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
Date parse(java.lang.String s, ParsePosition pos) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Contributors: Mathias Bogaert
|
|
||||||
|
|
||||||
package org.apache.log4j.helpers;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Check every now and then that a certain file has not changed. If it
|
|
||||||
has, then call the {@link #doOnChange} method.
|
|
||||||
|
|
||||||
|
|
||||||
@author Ceki Gülcü
|
|
||||||
@since version 0.9.1 */
|
|
||||||
public abstract class FileWatchdog extends Thread {
|
|
||||||
|
|
||||||
/**
|
|
||||||
The default delay between every file modification check, set to 60
|
|
||||||
seconds. */
|
|
||||||
static final public long DEFAULT_DELAY = 60000;
|
|
||||||
/**
|
|
||||||
The name of the file to observe for changes.
|
|
||||||
*/
|
|
||||||
protected String filename;
|
|
||||||
|
|
||||||
/**
|
|
||||||
The delay to observe between every check. By default set {@link
|
|
||||||
#DEFAULT_DELAY}. */
|
|
||||||
protected long delay = DEFAULT_DELAY;
|
|
||||||
|
|
||||||
File file;
|
|
||||||
long lastModif = 0;
|
|
||||||
boolean warnedAlready = false;
|
|
||||||
boolean interrupted = false;
|
|
||||||
|
|
||||||
protected
|
|
||||||
FileWatchdog(String filename) {
|
|
||||||
super("FileWatchdog");
|
|
||||||
this.filename = filename;
|
|
||||||
file = new File(filename);
|
|
||||||
setDaemon(true);
|
|
||||||
checkAndConfigure();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set the delay to observe between each check of the file changes.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setDelay(long delay) {
|
|
||||||
this.delay = delay;
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract
|
|
||||||
protected
|
|
||||||
void doOnChange();
|
|
||||||
|
|
||||||
protected
|
|
||||||
void checkAndConfigure() {
|
|
||||||
boolean fileExists;
|
|
||||||
try {
|
|
||||||
fileExists = file.exists();
|
|
||||||
} catch(SecurityException e) {
|
|
||||||
LogLog.warn("Was not allowed to read check file existance, file:["+
|
|
||||||
filename+"].");
|
|
||||||
interrupted = true; // there is no point in continuing
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fileExists) {
|
|
||||||
long l = file.lastModified(); // this can also throw a SecurityException
|
|
||||||
if(l > lastModif) { // however, if we reached this point this
|
|
||||||
lastModif = l; // is very unlikely.
|
|
||||||
doOnChange();
|
|
||||||
warnedAlready = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(!warnedAlready) {
|
|
||||||
LogLog.debug("["+filename+"] does not exist.");
|
|
||||||
warnedAlready = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void run() {
|
|
||||||
while(!interrupted) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(delay);
|
|
||||||
} catch(InterruptedException e) {
|
|
||||||
// no interruption expected
|
|
||||||
}
|
|
||||||
checkAndConfigure();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.helpers;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
FormattingInfo instances contain the information obtained when parsing
|
|
||||||
formatting modifiers in conversion modifiers.
|
|
||||||
|
|
||||||
@author <a href=mailto:jim_cakalic@na.biomerieux.com>Jim Cakalic</a>
|
|
||||||
@author Ceki Gülcü
|
|
||||||
|
|
||||||
@since 0.8.2
|
|
||||||
*/
|
|
||||||
public class FormattingInfo {
|
|
||||||
int min = -1;
|
|
||||||
int max = 0x7FFFFFFF;
|
|
||||||
boolean leftAlign = false;
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
min = -1;
|
|
||||||
max = 0x7FFFFFFF;
|
|
||||||
leftAlign = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dump() {
|
|
||||||
LogLog.debug("min="+min+", max="+max+", leftAlign="+leftAlign);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,155 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.helpers;
|
|
||||||
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.TimeZone;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.text.FieldPosition;
|
|
||||||
import java.text.ParsePosition;
|
|
||||||
|
|
||||||
// Contributors: Arndt Schoenewald <arndt@ibm23093i821.mc.schoenewald.de>
|
|
||||||
|
|
||||||
/**
|
|
||||||
Formats a {@link Date} in the format "yyyy-MM-dd HH:mm:ss,SSS" for example
|
|
||||||
"1999-11-27 15:49:37,459".
|
|
||||||
|
|
||||||
<p>Refer to the <a
|
|
||||||
href=http://www.cl.cam.ac.uk/~mgk25/iso-time.html>summary of the
|
|
||||||
International Standard Date and Time Notation</a> for more
|
|
||||||
information on this format.
|
|
||||||
|
|
||||||
@author Ceki Gülcü
|
|
||||||
@author Andrew Vajoczki
|
|
||||||
|
|
||||||
@since 0.7.5
|
|
||||||
*/
|
|
||||||
public class ISO8601DateFormat extends AbsoluteTimeDateFormat {
|
|
||||||
private static final long serialVersionUID = -759840745298755296L;
|
|
||||||
|
|
||||||
public
|
|
||||||
ISO8601DateFormat() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
ISO8601DateFormat(TimeZone timeZone) {
|
|
||||||
super(timeZone);
|
|
||||||
}
|
|
||||||
|
|
||||||
static private long lastTime;
|
|
||||||
static private char[] lastTimeString = new char[20];
|
|
||||||
|
|
||||||
/**
|
|
||||||
Appends a date in the format "YYYY-mm-dd HH:mm:ss,SSS"
|
|
||||||
to <code>sbuf</code>. For example: "1999-11-27 15:49:37,459".
|
|
||||||
|
|
||||||
@param sbuf the <code>StringBuffer</code> to write to
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
StringBuffer format(Date date, StringBuffer sbuf,
|
|
||||||
FieldPosition fieldPosition) {
|
|
||||||
|
|
||||||
long now = date.getTime();
|
|
||||||
int millis = (int)(now % 1000);
|
|
||||||
|
|
||||||
if ((now - millis) != lastTime || lastTimeString[0] == 0) {
|
|
||||||
// We reach this point at most once per second
|
|
||||||
// across all threads instead of each time format()
|
|
||||||
// is called. This saves considerable CPU time.
|
|
||||||
|
|
||||||
calendar.setTime(date);
|
|
||||||
|
|
||||||
int start = sbuf.length();
|
|
||||||
|
|
||||||
int year = calendar.get(Calendar.YEAR);
|
|
||||||
sbuf.append(year);
|
|
||||||
|
|
||||||
String month;
|
|
||||||
switch(calendar.get(Calendar.MONTH)) {
|
|
||||||
case Calendar.JANUARY: month = "-01-"; break;
|
|
||||||
case Calendar.FEBRUARY: month = "-02-"; break;
|
|
||||||
case Calendar.MARCH: month = "-03-"; break;
|
|
||||||
case Calendar.APRIL: month = "-04-"; break;
|
|
||||||
case Calendar.MAY: month = "-05-"; break;
|
|
||||||
case Calendar.JUNE: month = "-06-"; break;
|
|
||||||
case Calendar.JULY: month = "-07-"; break;
|
|
||||||
case Calendar.AUGUST: month = "-08-"; break;
|
|
||||||
case Calendar.SEPTEMBER: month = "-09-"; break;
|
|
||||||
case Calendar.OCTOBER: month = "-10-"; break;
|
|
||||||
case Calendar.NOVEMBER: month = "-11-"; break;
|
|
||||||
case Calendar.DECEMBER: month = "-12-"; break;
|
|
||||||
default: month = "-NA-"; break;
|
|
||||||
}
|
|
||||||
sbuf.append(month);
|
|
||||||
|
|
||||||
int day = calendar.get(Calendar.DAY_OF_MONTH);
|
|
||||||
if(day < 10)
|
|
||||||
sbuf.append('0');
|
|
||||||
sbuf.append(day);
|
|
||||||
|
|
||||||
sbuf.append(' ');
|
|
||||||
|
|
||||||
int hour = calendar.get(Calendar.HOUR_OF_DAY);
|
|
||||||
if(hour < 10) {
|
|
||||||
sbuf.append('0');
|
|
||||||
}
|
|
||||||
sbuf.append(hour);
|
|
||||||
sbuf.append(':');
|
|
||||||
|
|
||||||
int mins = calendar.get(Calendar.MINUTE);
|
|
||||||
if(mins < 10) {
|
|
||||||
sbuf.append('0');
|
|
||||||
}
|
|
||||||
sbuf.append(mins);
|
|
||||||
sbuf.append(':');
|
|
||||||
|
|
||||||
int secs = calendar.get(Calendar.SECOND);
|
|
||||||
if(secs < 10) {
|
|
||||||
sbuf.append('0');
|
|
||||||
}
|
|
||||||
sbuf.append(secs);
|
|
||||||
|
|
||||||
sbuf.append(',');
|
|
||||||
|
|
||||||
// store the time string for next time to avoid recomputation
|
|
||||||
sbuf.getChars(start, sbuf.length(), lastTimeString, 0);
|
|
||||||
lastTime = now - millis;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sbuf.append(lastTimeString);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (millis < 100)
|
|
||||||
sbuf.append('0');
|
|
||||||
if (millis < 10)
|
|
||||||
sbuf.append('0');
|
|
||||||
|
|
||||||
sbuf.append(millis);
|
|
||||||
return sbuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
This method does not do anything but return <code>null</code>.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
Date parse(java.lang.String s, ParsePosition pos) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,200 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.helpers;
|
|
||||||
|
|
||||||
import java.net.URL;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.io.InterruptedIOException;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Load resources (or images) from various sources.
|
|
||||||
|
|
||||||
@author Ceki Gülcü
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class Loader {
|
|
||||||
|
|
||||||
static final String TSTR = "Caught Exception while in Loader.getResource. This may be innocuous.";
|
|
||||||
|
|
||||||
// We conservatively assume that we are running under Java 1.x
|
|
||||||
static private boolean java1 = true;
|
|
||||||
|
|
||||||
static private boolean ignoreTCL = false;
|
|
||||||
|
|
||||||
static {
|
|
||||||
String prop = OptionConverter.getSystemProperty("java.version", null);
|
|
||||||
|
|
||||||
if(prop != null) {
|
|
||||||
int i = prop.indexOf('.');
|
|
||||||
if(i != -1) {
|
|
||||||
if(prop.charAt(i+1) != '1')
|
|
||||||
java1 = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String ignoreTCLProp = OptionConverter.getSystemProperty("log4j.ignoreTCL", null);
|
|
||||||
if(ignoreTCLProp != null) {
|
|
||||||
ignoreTCL = OptionConverter.toBoolean(ignoreTCLProp, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a resource by delegating to getResource(String).
|
|
||||||
* @param resource resource name
|
|
||||||
* @param clazz class, ignored.
|
|
||||||
* @return URL to resource or null.
|
|
||||||
* @deprecated as of 1.2.
|
|
||||||
*/
|
|
||||||
public static URL getResource(String resource, Class clazz) {
|
|
||||||
return getResource(resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
This method will search for <code>resource</code> in different
|
|
||||||
places. The search order is as follows:
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
|
|
||||||
<p><li>Search for <code>resource</code> using the thread context
|
|
||||||
class loader under Java2. If that fails, search for
|
|
||||||
<code>resource</code> using the class loader that loaded this
|
|
||||||
class (<code>Loader</code>). Under JDK 1.1, only the the class
|
|
||||||
loader that loaded this class (<code>Loader</code>) is used.
|
|
||||||
|
|
||||||
<p><li>Try one last time with
|
|
||||||
<code>ClassLoader.getSystemResource(resource)</code>, that is is
|
|
||||||
using the system class loader in JDK 1.2 and virtual machine's
|
|
||||||
built-in class loader in JDK 1.1.
|
|
||||||
|
|
||||||
</ol>
|
|
||||||
*/
|
|
||||||
static public URL getResource(String resource) {
|
|
||||||
ClassLoader classLoader = null;
|
|
||||||
URL url = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
if(!java1 && !ignoreTCL) {
|
|
||||||
classLoader = getTCL();
|
|
||||||
if(classLoader != null) {
|
|
||||||
LogLog.debug("Trying to find ["+resource+"] using context classloader "
|
|
||||||
+classLoader+".");
|
|
||||||
url = classLoader.getResource(resource);
|
|
||||||
if(url != null) {
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We could not find resource. Ler us now try with the
|
|
||||||
// classloader that loaded this class.
|
|
||||||
classLoader = Loader.class.getClassLoader();
|
|
||||||
if(classLoader != null) {
|
|
||||||
LogLog.debug("Trying to find ["+resource+"] using "+classLoader
|
|
||||||
+" class loader.");
|
|
||||||
url = classLoader.getResource(resource);
|
|
||||||
if(url != null) {
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch(IllegalAccessException t) {
|
|
||||||
LogLog.warn(TSTR, t);
|
|
||||||
} catch(InvocationTargetException t) {
|
|
||||||
if (t.getTargetException() instanceof InterruptedException
|
|
||||||
|| t.getTargetException() instanceof InterruptedIOException) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
LogLog.warn(TSTR, t);
|
|
||||||
} catch(Throwable t) {
|
|
||||||
//
|
|
||||||
// can't be InterruptedException or InterruptedIOException
|
|
||||||
// since not declared, must be error or RuntimeError.
|
|
||||||
LogLog.warn(TSTR, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Last ditch attempt: get the resource from the class path. It
|
|
||||||
// may be the case that clazz was loaded by the Extentsion class
|
|
||||||
// loader which the parent of the system class loader. Hence the
|
|
||||||
// code below.
|
|
||||||
LogLog.debug("Trying to find ["+resource+
|
|
||||||
"] using ClassLoader.getSystemResource().");
|
|
||||||
return ClassLoader.getSystemResource(resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Are we running under JDK 1.x?
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
boolean isJava1() {
|
|
||||||
return java1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the Thread Context Loader which is a JDK 1.2 feature. If we
|
|
||||||
* are running under JDK 1.1 or anything else goes wrong the method
|
|
||||||
* returns <code>null<code>.
|
|
||||||
*
|
|
||||||
* */
|
|
||||||
private static ClassLoader getTCL() throws IllegalAccessException,
|
|
||||||
InvocationTargetException {
|
|
||||||
|
|
||||||
// Are we running on a JDK 1.2 or later system?
|
|
||||||
Method method = null;
|
|
||||||
try {
|
|
||||||
method = Thread.class.getMethod("getContextClassLoader", null);
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
// We are running on JDK 1.1
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (ClassLoader) method.invoke(Thread.currentThread(), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If running under JDK 1.2 load the specified class using the
|
|
||||||
* <code>Thread</code> <code>contextClassLoader</code> if that
|
|
||||||
* fails try Class.forname. Under JDK 1.1 only Class.forName is
|
|
||||||
* used.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static public Class loadClass (String clazz) throws ClassNotFoundException {
|
|
||||||
// Just call Class.forName(clazz) if we are running under JDK 1.1
|
|
||||||
// or if we are instructed to ignore the TCL.
|
|
||||||
if(java1 || ignoreTCL) {
|
|
||||||
return Class.forName(clazz);
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
return getTCL().loadClass(clazz);
|
|
||||||
}
|
|
||||||
// we reached here because tcl was null or because of a
|
|
||||||
// security exception, or because clazz could not be loaded...
|
|
||||||
// In any case we now try one more time
|
|
||||||
catch(InvocationTargetException e) {
|
|
||||||
if (e.getTargetException() instanceof InterruptedException
|
|
||||||
|| e.getTargetException() instanceof InterruptedIOException) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
} catch(Throwable t) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Class.forName(clazz);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,189 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.helpers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
This class used to output log statements from within the log4j package.
|
|
||||||
|
|
||||||
<p>Log4j components cannot make log4j logging calls. However, it is
|
|
||||||
sometimes useful for the user to learn about what log4j is
|
|
||||||
doing. You can enable log4j internal logging by defining the
|
|
||||||
<b>log4j.configDebug</b> variable.
|
|
||||||
|
|
||||||
<p>All log4j internal debug calls go to <code>System.out</code>
|
|
||||||
where as internal error messages are sent to
|
|
||||||
<code>System.err</code>. All internal messages are prepended with
|
|
||||||
the string "log4j: ".
|
|
||||||
|
|
||||||
@since 0.8.2
|
|
||||||
@author Ceki Gülcü
|
|
||||||
*/
|
|
||||||
public class LogLog {
|
|
||||||
|
|
||||||
/**
|
|
||||||
Defining this value makes log4j print log4j-internal debug
|
|
||||||
statements to <code>System.out</code>.
|
|
||||||
|
|
||||||
<p> The value of this string is <b>log4j.debug</b>.
|
|
||||||
|
|
||||||
<p>Note that the search for all option names is case sensitive. */
|
|
||||||
public static final String DEBUG_KEY="log4j.debug";
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Defining this value makes log4j components print log4j-internal
|
|
||||||
debug statements to <code>System.out</code>.
|
|
||||||
|
|
||||||
<p> The value of this string is <b>log4j.configDebug</b>.
|
|
||||||
|
|
||||||
<p>Note that the search for all option names is case sensitive.
|
|
||||||
|
|
||||||
@deprecated Use {@link #DEBUG_KEY} instead.
|
|
||||||
*/
|
|
||||||
public static final String CONFIG_DEBUG_KEY="log4j.configDebug";
|
|
||||||
|
|
||||||
protected static boolean debugEnabled = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
In quietMode not even errors generate any output.
|
|
||||||
*/
|
|
||||||
private static boolean quietMode = false;
|
|
||||||
|
|
||||||
private static final String PREFIX = "log4j: ";
|
|
||||||
private static final String ERR_PREFIX = "log4j:ERROR ";
|
|
||||||
private static final String WARN_PREFIX = "log4j:WARN ";
|
|
||||||
|
|
||||||
static {
|
|
||||||
String key = OptionConverter.getSystemProperty(DEBUG_KEY, null);
|
|
||||||
|
|
||||||
if(key == null) {
|
|
||||||
key = OptionConverter.getSystemProperty(CONFIG_DEBUG_KEY, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(key != null) {
|
|
||||||
debugEnabled = OptionConverter.toBoolean(key, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Allows to enable/disable log4j internal logging.
|
|
||||||
*/
|
|
||||||
static
|
|
||||||
public
|
|
||||||
void setInternalDebugging(boolean enabled) {
|
|
||||||
debugEnabled = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
This method is used to output log4j internal debug
|
|
||||||
statements. Output goes to <code>System.out</code>.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
void debug(String msg) {
|
|
||||||
if(debugEnabled && !quietMode) {
|
|
||||||
System.out.println(PREFIX+msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
This method is used to output log4j internal debug
|
|
||||||
statements. Output goes to <code>System.out</code>.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
void debug(String msg, Throwable t) {
|
|
||||||
if(debugEnabled && !quietMode) {
|
|
||||||
System.out.println(PREFIX+msg);
|
|
||||||
if(t != null)
|
|
||||||
t.printStackTrace(System.out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
This method is used to output log4j internal error
|
|
||||||
statements. There is no way to disable error statements.
|
|
||||||
Output goes to <code>System.err</code>.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
void error(String msg) {
|
|
||||||
if(quietMode)
|
|
||||||
return;
|
|
||||||
System.err.println(ERR_PREFIX+msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
This method is used to output log4j internal error
|
|
||||||
statements. There is no way to disable error statements.
|
|
||||||
Output goes to <code>System.err</code>.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
void error(String msg, Throwable t) {
|
|
||||||
if(quietMode)
|
|
||||||
return;
|
|
||||||
|
|
||||||
System.err.println(ERR_PREFIX+msg);
|
|
||||||
if(t != null) {
|
|
||||||
t.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
In quite mode no LogLog generates strictly no output, not even
|
|
||||||
for errors.
|
|
||||||
|
|
||||||
@param quietMode A true for not
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
void setQuietMode(boolean quietMode) {
|
|
||||||
LogLog.quietMode = quietMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
This method is used to output log4j internal warning
|
|
||||||
statements. There is no way to disable warning statements.
|
|
||||||
Output goes to <code>System.err</code>. */
|
|
||||||
public
|
|
||||||
static
|
|
||||||
void warn(String msg) {
|
|
||||||
if(quietMode)
|
|
||||||
return;
|
|
||||||
|
|
||||||
System.err.println(WARN_PREFIX+msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
This method is used to output log4j internal warnings. There is
|
|
||||||
no way to disable warning statements. Output goes to
|
|
||||||
<code>System.err</code>. */
|
|
||||||
public
|
|
||||||
static
|
|
||||||
void warn(String msg, Throwable t) {
|
|
||||||
if(quietMode)
|
|
||||||
return;
|
|
||||||
|
|
||||||
System.err.println(WARN_PREFIX+msg);
|
|
||||||
if(t != null) {
|
|
||||||
t.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.helpers;
|
|
||||||
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
import org.apache.log4j.pattern.LogEvent;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
|
|
||||||
|
|
||||||
public final class MDCKeySetExtractor {
|
|
||||||
private final Method getKeySetMethod;
|
|
||||||
public static final MDCKeySetExtractor INSTANCE =
|
|
||||||
new MDCKeySetExtractor();
|
|
||||||
|
|
||||||
|
|
||||||
private MDCKeySetExtractor() {
|
|
||||||
//
|
|
||||||
// log4j 1.2.15 and later will have method to get names
|
|
||||||
// of all keys in MDC
|
|
||||||
//
|
|
||||||
Method getMethod = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
getMethod = LoggingEvent.class.getMethod(
|
|
||||||
"getPropertyKeySet", null);
|
|
||||||
} catch(Exception ex) {
|
|
||||||
getMethod = null;
|
|
||||||
}
|
|
||||||
getKeySetMethod = getMethod;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set getPropertyKeySet(final LoggingEvent event) throws Exception {
|
|
||||||
//
|
|
||||||
// MDC keys are not visible prior to log4j 1.2.15
|
|
||||||
//
|
|
||||||
Set keySet = null;
|
|
||||||
if (getKeySetMethod != null) {
|
|
||||||
keySet = (Set) getKeySetMethod.invoke(event, null);
|
|
||||||
} else {
|
|
||||||
//
|
|
||||||
// for 1.2.14 and earlier could serialize and
|
|
||||||
// extract MDC content
|
|
||||||
ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
|
|
||||||
ObjectOutputStream os = new ObjectOutputStream(outBytes);
|
|
||||||
os.writeObject(event);
|
|
||||||
os.close();
|
|
||||||
|
|
||||||
byte[] raw = outBytes.toByteArray();
|
|
||||||
//
|
|
||||||
// bytes 6 and 7 should be the length of the original classname
|
|
||||||
// should be the same as our substitute class name
|
|
||||||
final String subClassName = LogEvent.class.getName();
|
|
||||||
if (raw[6] == 0 || raw[7] == subClassName.length()) {
|
|
||||||
//
|
|
||||||
// manipulate stream to use our class name
|
|
||||||
//
|
|
||||||
for (int i = 0; i < subClassName.length(); i++) {
|
|
||||||
raw[8 + i] = (byte) subClassName.charAt(i);
|
|
||||||
}
|
|
||||||
ByteArrayInputStream inBytes = new ByteArrayInputStream(raw);
|
|
||||||
ObjectInputStream is = new ObjectInputStream(inBytes);
|
|
||||||
Object cracked = is.readObject();
|
|
||||||
if (cracked instanceof LogEvent) {
|
|
||||||
keySet = ((LogEvent) cracked).getPropertyKeySet();
|
|
||||||
}
|
|
||||||
is.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return keySet;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.helpers;
|
|
||||||
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
|
|
||||||
An always-empty Enumerator.
|
|
||||||
|
|
||||||
@author Anders Kristensen
|
|
||||||
@since version 1.0
|
|
||||||
*/
|
|
||||||
public class NullEnumeration implements Enumeration {
|
|
||||||
private static final NullEnumeration instance = new NullEnumeration();
|
|
||||||
|
|
||||||
private
|
|
||||||
NullEnumeration() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static NullEnumeration getInstance() {
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
boolean hasMoreElements() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
Object nextElement() {
|
|
||||||
throw new NoSuchElementException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.helpers;
|
|
||||||
|
|
||||||
import org.apache.log4j.spi.ErrorHandler;
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
import org.apache.log4j.Appender;
|
|
||||||
|
|
||||||
import java.io.InterruptedIOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
|
|
||||||
The <code>OnlyOnceErrorHandler</code> implements log4j's default
|
|
||||||
error handling policy which consists of emitting a message for the
|
|
||||||
first error in an appender and ignoring all following errors.
|
|
||||||
|
|
||||||
<p>The error message is printed on <code>System.err</code>.
|
|
||||||
|
|
||||||
<p>This policy aims at protecting an otherwise working application
|
|
||||||
from being flooded with error messages when logging fails.
|
|
||||||
|
|
||||||
@author Ceki Gülcü
|
|
||||||
@since 0.9.0 */
|
|
||||||
public class OnlyOnceErrorHandler implements ErrorHandler {
|
|
||||||
|
|
||||||
|
|
||||||
final String WARN_PREFIX = "log4j warning: ";
|
|
||||||
final String ERROR_PREFIX = "log4j error: ";
|
|
||||||
|
|
||||||
boolean firstTime = true;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Does not do anything.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setLogger(Logger logger) {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
No options to activate.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void activateOptions() {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Prints the message and the stack trace of the exception on
|
|
||||||
<code>System.err</code>. */
|
|
||||||
public
|
|
||||||
void error(String message, Exception e, int errorCode) {
|
|
||||||
error(message, e, errorCode, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Prints the message and the stack trace of the exception on
|
|
||||||
<code>System.err</code>.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void error(String message, Exception e, int errorCode, LoggingEvent event) {
|
|
||||||
if (e instanceof InterruptedIOException || e instanceof InterruptedException) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
if(firstTime) {
|
|
||||||
LogLog.error(message, e);
|
|
||||||
firstTime = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Print a the error message passed as parameter on
|
|
||||||
<code>System.err</code>.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void error(String message) {
|
|
||||||
if(firstTime) {
|
|
||||||
LogLog.error(message);
|
|
||||||
firstTime = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Does not do anything.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setAppender(Appender appender) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Does not do anything.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setBackupAppender(Appender appender) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,485 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.helpers;
|
|
||||||
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.io.InterruptedIOException;
|
|
||||||
|
|
||||||
import org.apache.log4j.Level;
|
|
||||||
import org.apache.log4j.spi.Configurator;
|
|
||||||
import org.apache.log4j.spi.LoggerRepository;
|
|
||||||
import org.apache.log4j.PropertyConfigurator;
|
|
||||||
|
|
||||||
// Contributors: Avy Sharell (sharell@online.fr)
|
|
||||||
// Matthieu Verbert (mve@zurich.ibm.com)
|
|
||||||
// Colin Sampaleanu
|
|
||||||
|
|
||||||
/**
|
|
||||||
A convenience class to convert property values to specific types.
|
|
||||||
|
|
||||||
@author Ceki Gülcü
|
|
||||||
@author Simon Kitching;
|
|
||||||
@author Anders Kristensen
|
|
||||||
*/
|
|
||||||
public class OptionConverter {
|
|
||||||
|
|
||||||
static String DELIM_START = "${";
|
|
||||||
static char DELIM_STOP = '}';
|
|
||||||
static int DELIM_START_LEN = 2;
|
|
||||||
static int DELIM_STOP_LEN = 1;
|
|
||||||
|
|
||||||
/** OptionConverter is a static class. */
|
|
||||||
private OptionConverter() {}
|
|
||||||
|
|
||||||
public
|
|
||||||
static
|
|
||||||
String[] concatanateArrays(String[] l, String[] r) {
|
|
||||||
int len = l.length + r.length;
|
|
||||||
String[] a = new String[len];
|
|
||||||
|
|
||||||
System.arraycopy(l, 0, a, 0, l.length);
|
|
||||||
System.arraycopy(r, 0, a, l.length, r.length);
|
|
||||||
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
static
|
|
||||||
String convertSpecialChars(String s) {
|
|
||||||
char c;
|
|
||||||
int len = s.length();
|
|
||||||
StringBuffer sbuf = new StringBuffer(len);
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
while(i < len) {
|
|
||||||
c = s.charAt(i++);
|
|
||||||
if (c == '\\') {
|
|
||||||
c = s.charAt(i++);
|
|
||||||
if(c == 'n') c = '\n';
|
|
||||||
else if(c == 'r') c = '\r';
|
|
||||||
else if(c == 't') c = '\t';
|
|
||||||
else if(c == 'f') c = '\f';
|
|
||||||
else if(c == '\b') c = '\b';
|
|
||||||
else if(c == '\"') c = '\"';
|
|
||||||
else if(c == '\'') c = '\'';
|
|
||||||
else if(c == '\\') c = '\\';
|
|
||||||
}
|
|
||||||
sbuf.append(c);
|
|
||||||
}
|
|
||||||
return sbuf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Very similar to <code>System.getProperty</code> except
|
|
||||||
that the {@link SecurityException} is hidden.
|
|
||||||
|
|
||||||
@param key The key to search for.
|
|
||||||
@param def The default value to return.
|
|
||||||
@return the string value of the system property, or the default
|
|
||||||
value if there is no property with that key.
|
|
||||||
|
|
||||||
@since 1.1 */
|
|
||||||
public
|
|
||||||
static
|
|
||||||
String getSystemProperty(String key, String def) {
|
|
||||||
try {
|
|
||||||
return System.getProperty(key, def);
|
|
||||||
} catch(Throwable e) { // MS-Java throws com.ms.security.SecurityExceptionEx
|
|
||||||
LogLog.debug("Was not allowed to read system property \""+key+"\".");
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public
|
|
||||||
static
|
|
||||||
Object instantiateByKey(Properties props, String key, Class superClass,
|
|
||||||
Object defaultValue) {
|
|
||||||
|
|
||||||
// Get the value of the property in string form
|
|
||||||
String className = findAndSubst(key, props);
|
|
||||||
if(className == null) {
|
|
||||||
LogLog.error("Could not find value for key " + key);
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
// Trim className to avoid trailing spaces that cause problems.
|
|
||||||
return OptionConverter.instantiateByClassName(className.trim(), superClass,
|
|
||||||
defaultValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
If <code>value</code> is "true", then <code>true</code> is
|
|
||||||
returned. If <code>value</code> is "false", then
|
|
||||||
<code>true</code> is returned. Otherwise, <code>default</code> is
|
|
||||||
returned.
|
|
||||||
|
|
||||||
<p>Case of value is unimportant. */
|
|
||||||
public
|
|
||||||
static
|
|
||||||
boolean toBoolean(String value, boolean dEfault) {
|
|
||||||
if(value == null)
|
|
||||||
return dEfault;
|
|
||||||
String trimmedVal = value.trim();
|
|
||||||
if("true".equalsIgnoreCase(trimmedVal))
|
|
||||||
return true;
|
|
||||||
if("false".equalsIgnoreCase(trimmedVal))
|
|
||||||
return false;
|
|
||||||
return dEfault;
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
static
|
|
||||||
int toInt(String value, int dEfault) {
|
|
||||||
if(value != null) {
|
|
||||||
String s = value.trim();
|
|
||||||
try {
|
|
||||||
return Integer.valueOf(s).intValue();
|
|
||||||
}
|
|
||||||
catch (NumberFormatException e) {
|
|
||||||
LogLog.error("[" + s + "] is not in proper int form.");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dEfault;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Converts a standard or custom priority level to a Level
|
|
||||||
object. <p> If <code>value</code> is of form
|
|
||||||
"level#classname", then the specified class' toLevel method
|
|
||||||
is called to process the specified level string; if no '#'
|
|
||||||
character is present, then the default {@link org.apache.log4j.Level}
|
|
||||||
class is used to process the level value.
|
|
||||||
|
|
||||||
<p>As a special case, if the <code>value</code> parameter is
|
|
||||||
equal to the string "NULL", then the value <code>null</code> will
|
|
||||||
be returned.
|
|
||||||
|
|
||||||
<p> If any error occurs while converting the value to a level,
|
|
||||||
the <code>defaultValue</code> parameter, which may be
|
|
||||||
<code>null</code>, is returned.
|
|
||||||
|
|
||||||
<p> Case of <code>value</code> is insignificant for the level level, but is
|
|
||||||
significant for the class name part, if present.
|
|
||||||
|
|
||||||
@since 1.1 */
|
|
||||||
public
|
|
||||||
static
|
|
||||||
Level toLevel(String value, Level defaultValue) {
|
|
||||||
if(value == null)
|
|
||||||
return defaultValue;
|
|
||||||
|
|
||||||
value = value.trim();
|
|
||||||
|
|
||||||
int hashIndex = value.indexOf('#');
|
|
||||||
if (hashIndex == -1) {
|
|
||||||
if("NULL".equalsIgnoreCase(value)) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
// no class name specified : use standard Level class
|
|
||||||
return(Level) Level.toLevel(value, defaultValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Level result = defaultValue;
|
|
||||||
|
|
||||||
String clazz = value.substring(hashIndex+1);
|
|
||||||
String levelName = value.substring(0, hashIndex);
|
|
||||||
|
|
||||||
// This is degenerate case but you never know.
|
|
||||||
if("NULL".equalsIgnoreCase(levelName)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
LogLog.debug("toLevel" + ":class=[" + clazz + "]"
|
|
||||||
+ ":pri=[" + levelName + "]");
|
|
||||||
|
|
||||||
try {
|
|
||||||
Class customLevel = Loader.loadClass(clazz);
|
|
||||||
|
|
||||||
// get a ref to the specified class' static method
|
|
||||||
// toLevel(String, org.apache.log4j.Level)
|
|
||||||
Class[] paramTypes = new Class[] { String.class,
|
|
||||||
org.apache.log4j.Level.class
|
|
||||||
};
|
|
||||||
java.lang.reflect.Method toLevelMethod =
|
|
||||||
customLevel.getMethod("toLevel", paramTypes);
|
|
||||||
|
|
||||||
// now call the toLevel method, passing level string + default
|
|
||||||
Object[] params = new Object[] {levelName, defaultValue};
|
|
||||||
Object o = toLevelMethod.invoke(null, params);
|
|
||||||
|
|
||||||
result = (Level) o;
|
|
||||||
} catch(ClassNotFoundException e) {
|
|
||||||
LogLog.warn("custom level class [" + clazz + "] not found.");
|
|
||||||
} catch(NoSuchMethodException e) {
|
|
||||||
LogLog.warn("custom level class [" + clazz + "]"
|
|
||||||
+ " does not have a class function toLevel(String, Level)", e);
|
|
||||||
} catch(java.lang.reflect.InvocationTargetException e) {
|
|
||||||
if (e.getTargetException() instanceof InterruptedException
|
|
||||||
|| e.getTargetException() instanceof InterruptedIOException) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
LogLog.warn("custom level class [" + clazz + "]"
|
|
||||||
+ " could not be instantiated", e);
|
|
||||||
} catch(ClassCastException e) {
|
|
||||||
LogLog.warn("class [" + clazz
|
|
||||||
+ "] is not a subclass of org.apache.log4j.Level", e);
|
|
||||||
} catch(IllegalAccessException e) {
|
|
||||||
LogLog.warn("class ["+clazz+
|
|
||||||
"] cannot be instantiated due to access restrictions", e);
|
|
||||||
} catch(RuntimeException e) {
|
|
||||||
LogLog.warn("class ["+clazz+"], level ["+levelName+
|
|
||||||
"] conversion failed.", e);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
static
|
|
||||||
long toFileSize(String value, long dEfault) {
|
|
||||||
if(value == null)
|
|
||||||
return dEfault;
|
|
||||||
|
|
||||||
String s = value.trim().toUpperCase();
|
|
||||||
long multiplier = 1;
|
|
||||||
int index;
|
|
||||||
|
|
||||||
if((index = s.indexOf("KB")) != -1) {
|
|
||||||
multiplier = 1024;
|
|
||||||
s = s.substring(0, index);
|
|
||||||
}
|
|
||||||
else if((index = s.indexOf("MB")) != -1) {
|
|
||||||
multiplier = 1024*1024;
|
|
||||||
s = s.substring(0, index);
|
|
||||||
}
|
|
||||||
else if((index = s.indexOf("GB")) != -1) {
|
|
||||||
multiplier = 1024*1024*1024;
|
|
||||||
s = s.substring(0, index);
|
|
||||||
}
|
|
||||||
if(s != null) {
|
|
||||||
try {
|
|
||||||
return Long.valueOf(s).longValue() * multiplier;
|
|
||||||
}
|
|
||||||
catch (NumberFormatException e) {
|
|
||||||
LogLog.error("[" + s + "] is not in proper int form.");
|
|
||||||
LogLog.error("[" + value + "] not in expected format.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dEfault;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Find the value corresponding to <code>key</code> in
|
|
||||||
<code>props</code>. Then perform variable substitution on the
|
|
||||||
found value.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
String findAndSubst(String key, Properties props) {
|
|
||||||
String value = props.getProperty(key);
|
|
||||||
if(value == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
return substVars(value, props);
|
|
||||||
} catch(IllegalArgumentException e) {
|
|
||||||
LogLog.error("Bad option value ["+value+"].", e);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Instantiate an object given a class name. Check that the
|
|
||||||
<code>className</code> is a subclass of
|
|
||||||
<code>superClass</code>. If that test fails or the object could
|
|
||||||
not be instantiated, then <code>defaultValue</code> is returned.
|
|
||||||
|
|
||||||
@param className The fully qualified class name of the object to instantiate.
|
|
||||||
@param superClass The class to which the new object should belong.
|
|
||||||
@param defaultValue The object to return in case of non-fulfillment
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
static
|
|
||||||
Object instantiateByClassName(String className, Class superClass,
|
|
||||||
Object defaultValue) {
|
|
||||||
if(className != null) {
|
|
||||||
try {
|
|
||||||
Class classObj = Loader.loadClass(className);
|
|
||||||
if(!superClass.isAssignableFrom(classObj)) {
|
|
||||||
LogLog.error("A \""+className+"\" object is not assignable to a \""+
|
|
||||||
superClass.getName() + "\" variable.");
|
|
||||||
LogLog.error("The class \""+ superClass.getName()+"\" was loaded by ");
|
|
||||||
LogLog.error("["+superClass.getClassLoader()+"] whereas object of type ");
|
|
||||||
LogLog.error("\"" +classObj.getName()+"\" was loaded by ["
|
|
||||||
+classObj.getClassLoader()+"].");
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
return classObj.newInstance();
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
LogLog.error("Could not instantiate class [" + className + "].", e);
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
LogLog.error("Could not instantiate class [" + className + "].", e);
|
|
||||||
} catch (InstantiationException e) {
|
|
||||||
LogLog.error("Could not instantiate class [" + className + "].", e);
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
LogLog.error("Could not instantiate class [" + className + "].", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Perform variable substitution in string <code>val</code> from the
|
|
||||||
values of keys found in the system propeties.
|
|
||||||
|
|
||||||
<p>The variable substitution delimeters are <b>${</b> and <b>}</b>.
|
|
||||||
|
|
||||||
<p>For example, if the System properties contains "key=value", then
|
|
||||||
the call
|
|
||||||
<pre>
|
|
||||||
String s = OptionConverter.substituteVars("Value of key is ${key}.");
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
will set the variable <code>s</code> to "Value of key is value.".
|
|
||||||
|
|
||||||
<p>If no value could be found for the specified key, then the
|
|
||||||
<code>props</code> parameter is searched, if the value could not
|
|
||||||
be found there, then substitution defaults to the empty string.
|
|
||||||
|
|
||||||
<p>For example, if system propeties contains no value for the key
|
|
||||||
"inexistentKey", then the call
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
String s = OptionConverter.subsVars("Value of inexistentKey is [${inexistentKey}]");
|
|
||||||
</pre>
|
|
||||||
will set <code>s</code> to "Value of inexistentKey is []"
|
|
||||||
|
|
||||||
<p>An {@link java.lang.IllegalArgumentException} is thrown if
|
|
||||||
<code>val</code> contains a start delimeter "${" which is not
|
|
||||||
balanced by a stop delimeter "}". </p>
|
|
||||||
|
|
||||||
<p><b>Author</b> Avy Sharell</a></p>
|
|
||||||
|
|
||||||
@param val The string on which variable substitution is performed.
|
|
||||||
@throws IllegalArgumentException if <code>val</code> is malformed.
|
|
||||||
|
|
||||||
*/
|
|
||||||
public static
|
|
||||||
String substVars(String val, Properties props) throws
|
|
||||||
IllegalArgumentException {
|
|
||||||
|
|
||||||
StringBuffer sbuf = new StringBuffer();
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
int j, k;
|
|
||||||
|
|
||||||
while(true) {
|
|
||||||
j=val.indexOf(DELIM_START, i);
|
|
||||||
if(j == -1) {
|
|
||||||
// no more variables
|
|
||||||
if(i==0) { // this is a simple string
|
|
||||||
return val;
|
|
||||||
} else { // add the tail string which contails no variables and return the result.
|
|
||||||
sbuf.append(val.substring(i, val.length()));
|
|
||||||
return sbuf.toString();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sbuf.append(val.substring(i, j));
|
|
||||||
k = val.indexOf(DELIM_STOP, j);
|
|
||||||
if(k == -1) {
|
|
||||||
throw new IllegalArgumentException('"'+val+
|
|
||||||
"\" has no closing brace. Opening brace at position " + j
|
|
||||||
+ '.');
|
|
||||||
} else {
|
|
||||||
j += DELIM_START_LEN;
|
|
||||||
String key = val.substring(j, k);
|
|
||||||
// first try in System properties
|
|
||||||
String replacement = getSystemProperty(key, null);
|
|
||||||
// then try props parameter
|
|
||||||
if(replacement == null && props != null) {
|
|
||||||
replacement = props.getProperty(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(replacement != null) {
|
|
||||||
// Do variable substitution on the replacement string
|
|
||||||
// such that we can solve "Hello ${x2}" as "Hello p1"
|
|
||||||
// the where the properties are
|
|
||||||
// x1=p1
|
|
||||||
// x2=${x1}
|
|
||||||
String recursiveReplacement = substVars(replacement, props);
|
|
||||||
sbuf.append(recursiveReplacement);
|
|
||||||
}
|
|
||||||
i = k + DELIM_STOP_LEN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Configure log4j given a URL.
|
|
||||||
|
|
||||||
<p>The url must point to a file or resource which will be interpreted by
|
|
||||||
a new instance of a log4j configurator.
|
|
||||||
|
|
||||||
<p>All configurations steps are taken on the
|
|
||||||
<code>hierarchy</code> passed as a parameter.
|
|
||||||
|
|
||||||
<p>
|
|
||||||
@param url The location of the configuration file or resource.
|
|
||||||
@param clazz The classname, of the log4j configurator which will parse
|
|
||||||
the file or resource at <code>url</code>. This must be a subclass of
|
|
||||||
{@link Configurator}, or null. If this value is null then a default
|
|
||||||
configurator of {@link PropertyConfigurator} is used, unless the
|
|
||||||
filename pointed to by <code>url</code> ends in '.xml', in which case
|
|
||||||
{@link org.apache.log4j.xml.DOMConfigurator} is used.
|
|
||||||
@param hierarchy The {@link org.apache.log4j.Hierarchy} to act on.
|
|
||||||
|
|
||||||
@since 1.1.4 */
|
|
||||||
|
|
||||||
static
|
|
||||||
public
|
|
||||||
void selectAndConfigure(URL url, String clazz, LoggerRepository hierarchy) {
|
|
||||||
Configurator configurator = null;
|
|
||||||
String filename = url.getFile();
|
|
||||||
|
|
||||||
if(clazz == null && filename != null && filename.endsWith(".xml")) {
|
|
||||||
clazz = "org.apache.log4j.xml.DOMConfigurator";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(clazz != null) {
|
|
||||||
LogLog.debug("Preferred configurator class: " + clazz);
|
|
||||||
configurator = (Configurator) instantiateByClassName(clazz,
|
|
||||||
Configurator.class,
|
|
||||||
null);
|
|
||||||
if(configurator == null) {
|
|
||||||
LogLog.error("Could not instantiate configurator ["+clazz+"].");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
configurator = new PropertyConfigurator();
|
|
||||||
}
|
|
||||||
|
|
||||||
configurator.doConfigure(url, hierarchy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.helpers;
|
|
||||||
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
|
|
||||||
<p>PatternConverter is an abtract class that provides the
|
|
||||||
formatting functionality that derived classes need.
|
|
||||||
|
|
||||||
<p>Conversion specifiers in a conversion patterns are parsed to
|
|
||||||
individual PatternConverters. Each of which is responsible for
|
|
||||||
converting a logging event in a converter specific manner.
|
|
||||||
|
|
||||||
@author <a href="mailto:cakalijp@Maritz.com">James P. Cakalic</a>
|
|
||||||
@author Ceki Gülcü
|
|
||||||
|
|
||||||
@since 0.8.2
|
|
||||||
*/
|
|
||||||
public abstract class PatternConverter {
|
|
||||||
public PatternConverter next;
|
|
||||||
int min = -1;
|
|
||||||
int max = 0x7FFFFFFF;
|
|
||||||
boolean leftAlign = false;
|
|
||||||
|
|
||||||
protected
|
|
||||||
PatternConverter() { }
|
|
||||||
|
|
||||||
protected
|
|
||||||
PatternConverter(FormattingInfo fi) {
|
|
||||||
min = fi.min;
|
|
||||||
max = fi.max;
|
|
||||||
leftAlign = fi.leftAlign;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Derived pattern converters must override this method in order to
|
|
||||||
convert conversion specifiers in the correct way.
|
|
||||||
*/
|
|
||||||
abstract
|
|
||||||
protected
|
|
||||||
String convert(LoggingEvent event);
|
|
||||||
|
|
||||||
/**
|
|
||||||
A template method for formatting in a converter specific way.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void format(StringBuffer sbuf, LoggingEvent e) {
|
|
||||||
String s = convert(e);
|
|
||||||
|
|
||||||
if(s == null) {
|
|
||||||
if(0 < min)
|
|
||||||
spacePad(sbuf, min);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int len = s.length();
|
|
||||||
|
|
||||||
if(len > max)
|
|
||||||
sbuf.append(s.substring(len-max));
|
|
||||||
else if(len < min) {
|
|
||||||
if(leftAlign) {
|
|
||||||
sbuf.append(s);
|
|
||||||
spacePad(sbuf, min-len);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
spacePad(sbuf, min-len);
|
|
||||||
sbuf.append(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
sbuf.append(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
static String[] SPACES = {" ", " ", " ", " ", //1,2,4,8 spaces
|
|
||||||
" ", // 16 spaces
|
|
||||||
" " }; // 32 spaces
|
|
||||||
|
|
||||||
/**
|
|
||||||
Fast space padding method.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void spacePad(StringBuffer sbuf, int length) {
|
|
||||||
while(length >= 32) {
|
|
||||||
sbuf.append(SPACES[5]);
|
|
||||||
length -= 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = 4; i >= 0; i--) {
|
|
||||||
if((length & (1<<i)) != 0) {
|
|
||||||
sbuf.append(SPACES[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,570 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.helpers;
|
|
||||||
|
|
||||||
import org.apache.log4j.Layout;
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
import org.apache.log4j.spi.LocationInfo;
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
// Contributors: Nelson Minar <(nelson@monkey.org>
|
|
||||||
// Igor E. Poteryaev <jah@mail.ru>
|
|
||||||
// Reinhard Deschler <reinhard.deschler@web.de>
|
|
||||||
|
|
||||||
/**
|
|
||||||
Most of the work of the {@link org.apache.log4j.PatternLayout} class
|
|
||||||
is delegated to the PatternParser class.
|
|
||||||
|
|
||||||
<p>It is this class that parses conversion patterns and creates
|
|
||||||
a chained list of {@link OptionConverter OptionConverters}.
|
|
||||||
|
|
||||||
@author <a href=mailto:"cakalijp@Maritz.com">James P. Cakalic</a>
|
|
||||||
@author Ceki Gülcü
|
|
||||||
@author Anders Kristensen
|
|
||||||
|
|
||||||
@since 0.8.2
|
|
||||||
*/
|
|
||||||
public class PatternParser {
|
|
||||||
|
|
||||||
private static final char ESCAPE_CHAR = '%';
|
|
||||||
|
|
||||||
private static final int LITERAL_STATE = 0;
|
|
||||||
private static final int CONVERTER_STATE = 1;
|
|
||||||
private static final int DOT_STATE = 3;
|
|
||||||
private static final int MIN_STATE = 4;
|
|
||||||
private static final int MAX_STATE = 5;
|
|
||||||
|
|
||||||
static final int FULL_LOCATION_CONVERTER = 1000;
|
|
||||||
static final int METHOD_LOCATION_CONVERTER = 1001;
|
|
||||||
static final int CLASS_LOCATION_CONVERTER = 1002;
|
|
||||||
static final int LINE_LOCATION_CONVERTER = 1003;
|
|
||||||
static final int FILE_LOCATION_CONVERTER = 1004;
|
|
||||||
|
|
||||||
static final int RELATIVE_TIME_CONVERTER = 2000;
|
|
||||||
static final int THREAD_CONVERTER = 2001;
|
|
||||||
static final int LEVEL_CONVERTER = 2002;
|
|
||||||
static final int NDC_CONVERTER = 2003;
|
|
||||||
static final int MESSAGE_CONVERTER = 2004;
|
|
||||||
|
|
||||||
int state;
|
|
||||||
protected StringBuffer currentLiteral = new StringBuffer(32);
|
|
||||||
protected int patternLength;
|
|
||||||
protected int i;
|
|
||||||
PatternConverter head;
|
|
||||||
PatternConverter tail;
|
|
||||||
protected FormattingInfo formattingInfo = new FormattingInfo();
|
|
||||||
protected String pattern;
|
|
||||||
|
|
||||||
public
|
|
||||||
PatternParser(String pattern) {
|
|
||||||
this.pattern = pattern;
|
|
||||||
patternLength = pattern.length();
|
|
||||||
state = LITERAL_STATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
private
|
|
||||||
void addToList(PatternConverter pc) {
|
|
||||||
if(head == null) {
|
|
||||||
head = tail = pc;
|
|
||||||
} else {
|
|
||||||
tail.next = pc;
|
|
||||||
tail = pc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected
|
|
||||||
String extractOption() {
|
|
||||||
if((i < patternLength) && (pattern.charAt(i) == '{')) {
|
|
||||||
int end = pattern.indexOf('}', i);
|
|
||||||
if (end > i) {
|
|
||||||
String r = pattern.substring(i + 1, end);
|
|
||||||
i = end+1;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
The option is expected to be in decimal and positive. In case of
|
|
||||||
error, zero is returned. */
|
|
||||||
protected
|
|
||||||
int extractPrecisionOption() {
|
|
||||||
String opt = extractOption();
|
|
||||||
int r = 0;
|
|
||||||
if(opt != null) {
|
|
||||||
try {
|
|
||||||
r = Integer.parseInt(opt);
|
|
||||||
if(r <= 0) {
|
|
||||||
LogLog.error(
|
|
||||||
"Precision option (" + opt + ") isn't a positive integer.");
|
|
||||||
r = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (NumberFormatException e) {
|
|
||||||
LogLog.error("Category option \""+opt+"\" not a decimal integer.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
PatternConverter parse() {
|
|
||||||
char c;
|
|
||||||
i = 0;
|
|
||||||
while(i < patternLength) {
|
|
||||||
c = pattern.charAt(i++);
|
|
||||||
switch(state) {
|
|
||||||
case LITERAL_STATE:
|
|
||||||
// In literal state, the last char is always a literal.
|
|
||||||
if(i == patternLength) {
|
|
||||||
currentLiteral.append(c);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(c == ESCAPE_CHAR) {
|
|
||||||
// peek at the next char.
|
|
||||||
switch(pattern.charAt(i)) {
|
|
||||||
case ESCAPE_CHAR:
|
|
||||||
currentLiteral.append(c);
|
|
||||||
i++; // move pointer
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
currentLiteral.append(Layout.LINE_SEP);
|
|
||||||
i++; // move pointer
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if(currentLiteral.length() != 0) {
|
|
||||||
addToList(new LiteralPatternConverter(
|
|
||||||
currentLiteral.toString()));
|
|
||||||
//LogLog.debug("Parsed LITERAL converter: \""
|
|
||||||
// +currentLiteral+"\".");
|
|
||||||
}
|
|
||||||
currentLiteral.setLength(0);
|
|
||||||
currentLiteral.append(c); // append %
|
|
||||||
state = CONVERTER_STATE;
|
|
||||||
formattingInfo.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
currentLiteral.append(c);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CONVERTER_STATE:
|
|
||||||
currentLiteral.append(c);
|
|
||||||
switch(c) {
|
|
||||||
case '-':
|
|
||||||
formattingInfo.leftAlign = true;
|
|
||||||
break;
|
|
||||||
case '.':
|
|
||||||
state = DOT_STATE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if(c >= '0' && c <= '9') {
|
|
||||||
formattingInfo.min = c - '0';
|
|
||||||
state = MIN_STATE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
finalizeConverter(c);
|
|
||||||
} // switch
|
|
||||||
break;
|
|
||||||
case MIN_STATE:
|
|
||||||
currentLiteral.append(c);
|
|
||||||
if(c >= '0' && c <= '9')
|
|
||||||
formattingInfo.min = formattingInfo.min*10 + (c - '0');
|
|
||||||
else if(c == '.')
|
|
||||||
state = DOT_STATE;
|
|
||||||
else {
|
|
||||||
finalizeConverter(c);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DOT_STATE:
|
|
||||||
currentLiteral.append(c);
|
|
||||||
if(c >= '0' && c <= '9') {
|
|
||||||
formattingInfo.max = c - '0';
|
|
||||||
state = MAX_STATE;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
LogLog.error("Error occured in position "+i
|
|
||||||
+".\n Was expecting digit, instead got char \""+c+"\".");
|
|
||||||
state = LITERAL_STATE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MAX_STATE:
|
|
||||||
currentLiteral.append(c);
|
|
||||||
if(c >= '0' && c <= '9')
|
|
||||||
formattingInfo.max = formattingInfo.max*10 + (c - '0');
|
|
||||||
else {
|
|
||||||
finalizeConverter(c);
|
|
||||||
state = LITERAL_STATE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} // switch
|
|
||||||
} // while
|
|
||||||
if(currentLiteral.length() != 0) {
|
|
||||||
addToList(new LiteralPatternConverter(currentLiteral.toString()));
|
|
||||||
//LogLog.debug("Parsed LITERAL converter: \""+currentLiteral+"\".");
|
|
||||||
}
|
|
||||||
return head;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected
|
|
||||||
void finalizeConverter(char c) {
|
|
||||||
PatternConverter pc = null;
|
|
||||||
switch(c) {
|
|
||||||
case 'c':
|
|
||||||
pc = new CategoryPatternConverter(formattingInfo,
|
|
||||||
extractPrecisionOption());
|
|
||||||
//LogLog.debug("CATEGORY converter.");
|
|
||||||
//formattingInfo.dump();
|
|
||||||
currentLiteral.setLength(0);
|
|
||||||
break;
|
|
||||||
case 'C':
|
|
||||||
pc = new ClassNamePatternConverter(formattingInfo,
|
|
||||||
extractPrecisionOption());
|
|
||||||
//LogLog.debug("CLASS_NAME converter.");
|
|
||||||
//formattingInfo.dump();
|
|
||||||
currentLiteral.setLength(0);
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
String dateFormatStr = AbsoluteTimeDateFormat.ISO8601_DATE_FORMAT;
|
|
||||||
DateFormat df;
|
|
||||||
String dOpt = extractOption();
|
|
||||||
if(dOpt != null)
|
|
||||||
dateFormatStr = dOpt;
|
|
||||||
|
|
||||||
if(dateFormatStr.equalsIgnoreCase(
|
|
||||||
AbsoluteTimeDateFormat.ISO8601_DATE_FORMAT))
|
|
||||||
df = new ISO8601DateFormat();
|
|
||||||
else if(dateFormatStr.equalsIgnoreCase(
|
|
||||||
AbsoluteTimeDateFormat.ABS_TIME_DATE_FORMAT))
|
|
||||||
df = new AbsoluteTimeDateFormat();
|
|
||||||
else if(dateFormatStr.equalsIgnoreCase(
|
|
||||||
AbsoluteTimeDateFormat.DATE_AND_TIME_DATE_FORMAT))
|
|
||||||
df = new DateTimeDateFormat();
|
|
||||||
else {
|
|
||||||
try {
|
|
||||||
df = new SimpleDateFormat(dateFormatStr);
|
|
||||||
}
|
|
||||||
catch (IllegalArgumentException e) {
|
|
||||||
LogLog.error("Could not instantiate SimpleDateFormat with " +
|
|
||||||
dateFormatStr, e);
|
|
||||||
df = (DateFormat) OptionConverter.instantiateByClassName(
|
|
||||||
"org.apache.log4j.helpers.ISO8601DateFormat",
|
|
||||||
DateFormat.class, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pc = new DatePatternConverter(formattingInfo, df);
|
|
||||||
//LogLog.debug("DATE converter {"+dateFormatStr+"}.");
|
|
||||||
//formattingInfo.dump();
|
|
||||||
currentLiteral.setLength(0);
|
|
||||||
break;
|
|
||||||
case 'F':
|
|
||||||
pc = new LocationPatternConverter(formattingInfo,
|
|
||||||
FILE_LOCATION_CONVERTER);
|
|
||||||
//LogLog.debug("File name converter.");
|
|
||||||
//formattingInfo.dump();
|
|
||||||
currentLiteral.setLength(0);
|
|
||||||
break;
|
|
||||||
case 'l':
|
|
||||||
pc = new LocationPatternConverter(formattingInfo,
|
|
||||||
FULL_LOCATION_CONVERTER);
|
|
||||||
//LogLog.debug("Location converter.");
|
|
||||||
//formattingInfo.dump();
|
|
||||||
currentLiteral.setLength(0);
|
|
||||||
break;
|
|
||||||
case 'L':
|
|
||||||
pc = new LocationPatternConverter(formattingInfo,
|
|
||||||
LINE_LOCATION_CONVERTER);
|
|
||||||
//LogLog.debug("LINE NUMBER converter.");
|
|
||||||
//formattingInfo.dump();
|
|
||||||
currentLiteral.setLength(0);
|
|
||||||
break;
|
|
||||||
case 'm':
|
|
||||||
pc = new BasicPatternConverter(formattingInfo, MESSAGE_CONVERTER);
|
|
||||||
//LogLog.debug("MESSAGE converter.");
|
|
||||||
//formattingInfo.dump();
|
|
||||||
currentLiteral.setLength(0);
|
|
||||||
break;
|
|
||||||
case 'M':
|
|
||||||
pc = new LocationPatternConverter(formattingInfo,
|
|
||||||
METHOD_LOCATION_CONVERTER);
|
|
||||||
//LogLog.debug("METHOD converter.");
|
|
||||||
//formattingInfo.dump();
|
|
||||||
currentLiteral.setLength(0);
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
pc = new BasicPatternConverter(formattingInfo, LEVEL_CONVERTER);
|
|
||||||
//LogLog.debug("LEVEL converter.");
|
|
||||||
//formattingInfo.dump();
|
|
||||||
currentLiteral.setLength(0);
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
pc = new BasicPatternConverter(formattingInfo,
|
|
||||||
RELATIVE_TIME_CONVERTER);
|
|
||||||
//LogLog.debug("RELATIVE time converter.");
|
|
||||||
//formattingInfo.dump();
|
|
||||||
currentLiteral.setLength(0);
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
pc = new BasicPatternConverter(formattingInfo, THREAD_CONVERTER);
|
|
||||||
//LogLog.debug("THREAD converter.");
|
|
||||||
//formattingInfo.dump();
|
|
||||||
currentLiteral.setLength(0);
|
|
||||||
break;
|
|
||||||
/*case 'u':
|
|
||||||
if(i < patternLength) {
|
|
||||||
char cNext = pattern.charAt(i);
|
|
||||||
if(cNext >= '0' && cNext <= '9') {
|
|
||||||
pc = new UserFieldPatternConverter(formattingInfo, cNext - '0');
|
|
||||||
LogLog.debug("USER converter ["+cNext+"].");
|
|
||||||
formattingInfo.dump();
|
|
||||||
currentLiteral.setLength(0);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
LogLog.error("Unexpected char" +cNext+" at position "+i);
|
|
||||||
}
|
|
||||||
break;*/
|
|
||||||
case 'x':
|
|
||||||
pc = new BasicPatternConverter(formattingInfo, NDC_CONVERTER);
|
|
||||||
//LogLog.debug("NDC converter.");
|
|
||||||
currentLiteral.setLength(0);
|
|
||||||
break;
|
|
||||||
case 'X':
|
|
||||||
String xOpt = extractOption();
|
|
||||||
pc = new MDCPatternConverter(formattingInfo, xOpt);
|
|
||||||
currentLiteral.setLength(0);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LogLog.error("Unexpected char [" +c+"] at position "+i
|
|
||||||
+" in conversion patterrn.");
|
|
||||||
pc = new LiteralPatternConverter(currentLiteral.toString());
|
|
||||||
currentLiteral.setLength(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
addConverter(pc);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected
|
|
||||||
void addConverter(PatternConverter pc) {
|
|
||||||
currentLiteral.setLength(0);
|
|
||||||
// Add the pattern converter to the list.
|
|
||||||
addToList(pc);
|
|
||||||
// Next pattern is assumed to be a literal.
|
|
||||||
state = LITERAL_STATE;
|
|
||||||
// Reset formatting info
|
|
||||||
formattingInfo.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
|
||||||
// PatternConverters
|
|
||||||
// ---------------------------------------------------------------------
|
|
||||||
|
|
||||||
private static class BasicPatternConverter extends PatternConverter {
|
|
||||||
int type;
|
|
||||||
|
|
||||||
BasicPatternConverter(FormattingInfo formattingInfo, int type) {
|
|
||||||
super(formattingInfo);
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
String convert(LoggingEvent event) {
|
|
||||||
switch(type) {
|
|
||||||
case RELATIVE_TIME_CONVERTER:
|
|
||||||
return (Long.toString(event.timeStamp - LoggingEvent.getStartTime()));
|
|
||||||
case THREAD_CONVERTER:
|
|
||||||
return event.getThreadName();
|
|
||||||
case LEVEL_CONVERTER:
|
|
||||||
return event.getLevel().toString();
|
|
||||||
case NDC_CONVERTER:
|
|
||||||
return event.getNDC();
|
|
||||||
case MESSAGE_CONVERTER: {
|
|
||||||
return event.getRenderedMessage();
|
|
||||||
}
|
|
||||||
default: return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class LiteralPatternConverter extends PatternConverter {
|
|
||||||
private String literal;
|
|
||||||
|
|
||||||
LiteralPatternConverter(String value) {
|
|
||||||
literal = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
final
|
|
||||||
void format(StringBuffer sbuf, LoggingEvent event) {
|
|
||||||
sbuf.append(literal);
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
String convert(LoggingEvent event) {
|
|
||||||
return literal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class DatePatternConverter extends PatternConverter {
|
|
||||||
private DateFormat df;
|
|
||||||
private Date date;
|
|
||||||
|
|
||||||
DatePatternConverter(FormattingInfo formattingInfo, DateFormat df) {
|
|
||||||
super(formattingInfo);
|
|
||||||
date = new Date();
|
|
||||||
this.df = df;
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
String convert(LoggingEvent event) {
|
|
||||||
date.setTime(event.timeStamp);
|
|
||||||
String converted = null;
|
|
||||||
try {
|
|
||||||
converted = df.format(date);
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
LogLog.error("Error occured while converting date.", ex);
|
|
||||||
}
|
|
||||||
return converted;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class MDCPatternConverter extends PatternConverter {
|
|
||||||
private String key;
|
|
||||||
|
|
||||||
MDCPatternConverter(FormattingInfo formattingInfo, String key) {
|
|
||||||
super(formattingInfo);
|
|
||||||
this.key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
String convert(LoggingEvent event) {
|
|
||||||
if (key == null) {
|
|
||||||
StringBuffer buf = new StringBuffer("{");
|
|
||||||
Map properties = event.getProperties();
|
|
||||||
if (properties.size() > 0) {
|
|
||||||
Object[] keys = properties.keySet().toArray();
|
|
||||||
Arrays.sort(keys);
|
|
||||||
for (int i = 0; i < keys.length; i++) {
|
|
||||||
buf.append('{');
|
|
||||||
buf.append(keys[i]);
|
|
||||||
buf.append(',');
|
|
||||||
buf.append(properties.get(keys[i]));
|
|
||||||
buf.append('}');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buf.append('}');
|
|
||||||
return buf.toString();
|
|
||||||
} else {
|
|
||||||
Object val = event.getMDC(key);
|
|
||||||
if(val == null) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return val.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private class LocationPatternConverter extends PatternConverter {
|
|
||||||
int type;
|
|
||||||
|
|
||||||
LocationPatternConverter(FormattingInfo formattingInfo, int type) {
|
|
||||||
super(formattingInfo);
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
String convert(LoggingEvent event) {
|
|
||||||
LocationInfo locationInfo = event.getLocationInformation();
|
|
||||||
switch(type) {
|
|
||||||
case FULL_LOCATION_CONVERTER:
|
|
||||||
return locationInfo.fullInfo;
|
|
||||||
case METHOD_LOCATION_CONVERTER:
|
|
||||||
return locationInfo.getMethodName();
|
|
||||||
case LINE_LOCATION_CONVERTER:
|
|
||||||
return locationInfo.getLineNumber();
|
|
||||||
case FILE_LOCATION_CONVERTER:
|
|
||||||
return locationInfo.getFileName();
|
|
||||||
default: return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static abstract class NamedPatternConverter extends PatternConverter {
|
|
||||||
int precision;
|
|
||||||
|
|
||||||
NamedPatternConverter(FormattingInfo formattingInfo, int precision) {
|
|
||||||
super(formattingInfo);
|
|
||||||
this.precision = precision;
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract
|
|
||||||
String getFullyQualifiedName(LoggingEvent event);
|
|
||||||
|
|
||||||
public
|
|
||||||
String convert(LoggingEvent event) {
|
|
||||||
String n = getFullyQualifiedName(event);
|
|
||||||
if(precision <= 0)
|
|
||||||
return n;
|
|
||||||
else {
|
|
||||||
int len = n.length();
|
|
||||||
|
|
||||||
// We substract 1 from 'len' when assigning to 'end' to avoid out of
|
|
||||||
// bounds exception in return r.substring(end+1, len). This can happen if
|
|
||||||
// precision is 1 and the category name ends with a dot.
|
|
||||||
int end = len -1 ;
|
|
||||||
for(int i = precision; i > 0; i--) {
|
|
||||||
end = n.lastIndexOf('.', end-1);
|
|
||||||
if(end == -1)
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
return n.substring(end+1, len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ClassNamePatternConverter extends NamedPatternConverter {
|
|
||||||
|
|
||||||
ClassNamePatternConverter(FormattingInfo formattingInfo, int precision) {
|
|
||||||
super(formattingInfo, precision);
|
|
||||||
}
|
|
||||||
|
|
||||||
String getFullyQualifiedName(LoggingEvent event) {
|
|
||||||
return event.getLocationInformation().getClassName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class CategoryPatternConverter extends NamedPatternConverter {
|
|
||||||
|
|
||||||
CategoryPatternConverter(FormattingInfo formattingInfo, int precision) {
|
|
||||||
super(formattingInfo, precision);
|
|
||||||
}
|
|
||||||
|
|
||||||
String getFullyQualifiedName(LoggingEvent event) {
|
|
||||||
return event.getLoggerName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.helpers;
|
|
||||||
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.io.FilterWriter;
|
|
||||||
import org.apache.log4j.spi.ErrorHandler;
|
|
||||||
import org.apache.log4j.spi.ErrorCode;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
QuietWriter does not throw exceptions when things go
|
|
||||||
wrong. Instead, it delegates error handling to its {@link ErrorHandler}.
|
|
||||||
|
|
||||||
@author Ceki Gülcü
|
|
||||||
|
|
||||||
@since 0.7.3
|
|
||||||
*/
|
|
||||||
public class QuietWriter extends FilterWriter {
|
|
||||||
|
|
||||||
protected ErrorHandler errorHandler;
|
|
||||||
|
|
||||||
public
|
|
||||||
QuietWriter(Writer writer, ErrorHandler errorHandler) {
|
|
||||||
super(writer);
|
|
||||||
setErrorHandler(errorHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void write(String string) {
|
|
||||||
if (string != null) {
|
|
||||||
try {
|
|
||||||
out.write(string);
|
|
||||||
} catch(Exception e) {
|
|
||||||
errorHandler.error("Failed to write ["+string+"].", e,
|
|
||||||
ErrorCode.WRITE_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void flush() {
|
|
||||||
try {
|
|
||||||
out.flush();
|
|
||||||
} catch(Exception e) {
|
|
||||||
errorHandler.error("Failed to flush writer,", e,
|
|
||||||
ErrorCode.FLUSH_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public
|
|
||||||
void setErrorHandler(ErrorHandler eh) {
|
|
||||||
if(eh == null) {
|
|
||||||
// This is a programming error on the part of the enclosing appender.
|
|
||||||
throw new IllegalArgumentException("Attempted to set null ErrorHandler.");
|
|
||||||
} else {
|
|
||||||
this.errorHandler = eh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.helpers;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
import java.text.FieldPosition;
|
|
||||||
import java.text.ParsePosition;
|
|
||||||
import java.text.DateFormat;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Formats a {@link Date} by printing the number of milliseconds
|
|
||||||
elapsed since construction of the format. This is the fastest
|
|
||||||
printing DateFormat in the package.
|
|
||||||
|
|
||||||
@author Ceki Gülcü
|
|
||||||
|
|
||||||
@since 0.7.5
|
|
||||||
*/
|
|
||||||
public class RelativeTimeDateFormat extends DateFormat {
|
|
||||||
private static final long serialVersionUID = 7055751607085611984L;
|
|
||||||
|
|
||||||
|
|
||||||
protected final long startTime;
|
|
||||||
|
|
||||||
public
|
|
||||||
RelativeTimeDateFormat() {
|
|
||||||
this.startTime = System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Appends to <code>sbuf</code> the number of milliseconds elapsed
|
|
||||||
since the start of the application.
|
|
||||||
|
|
||||||
@since 0.7.5
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
StringBuffer format(Date date, StringBuffer sbuf,
|
|
||||||
FieldPosition fieldPosition) {
|
|
||||||
//System.err.println(":"+ date.getTime() + " - " + startTime);
|
|
||||||
return sbuf.append((date.getTime() - startTime));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
This method does not do anything but return <code>null</code>.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
Date parse(java.lang.String s, ParsePosition pos) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.helpers;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import java.io.Writer;
|
|
||||||
import org.apache.log4j.spi.ErrorHandler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
SyslogQuietWriter extends QuietWriter by prepending the syslog
|
|
||||||
level code before each printed String.
|
|
||||||
|
|
||||||
@since 0.7.3
|
|
||||||
*/
|
|
||||||
public class SyslogQuietWriter extends QuietWriter {
|
|
||||||
|
|
||||||
int syslogFacility;
|
|
||||||
int level;
|
|
||||||
|
|
||||||
public
|
|
||||||
SyslogQuietWriter(Writer writer, int syslogFacility, ErrorHandler eh) {
|
|
||||||
super(writer, eh);
|
|
||||||
this.syslogFacility = syslogFacility;
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void setLevel(int level) {
|
|
||||||
this.level = level;
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void setSyslogFacility(int syslogFacility) {
|
|
||||||
this.syslogFacility = syslogFacility;
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void write(String string) {
|
|
||||||
super.write("<"+(syslogFacility | level)+">" + string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.helpers;
|
|
||||||
|
|
||||||
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.net.DatagramSocket;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.DatagramPacket;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
import java.net.SocketException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
SyslogWriter is a wrapper around the java.net.DatagramSocket class
|
|
||||||
so that it behaves like a java.io.Writer.
|
|
||||||
|
|
||||||
@since 0.7.3
|
|
||||||
*/
|
|
||||||
public class SyslogWriter extends Writer {
|
|
||||||
|
|
||||||
final int SYSLOG_PORT = 514;
|
|
||||||
/**
|
|
||||||
* Host string from last constructed SyslogWriter.
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
static String syslogHost;
|
|
||||||
|
|
||||||
private InetAddress address;
|
|
||||||
private final int port;
|
|
||||||
private DatagramSocket ds;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new instance of SyslogWriter.
|
|
||||||
* @param syslogHost host name, may not be null. A port
|
|
||||||
* may be specified by following the name or IPv4 literal address with
|
|
||||||
* a colon and a decimal port number. To specify a port with an IPv6
|
|
||||||
* address, enclose the IPv6 address in square brackets before appending
|
|
||||||
* the colon and decimal port number.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
SyslogWriter(final String syslogHost) {
|
|
||||||
SyslogWriter.syslogHost = syslogHost;
|
|
||||||
if (syslogHost == null) {
|
|
||||||
throw new NullPointerException("syslogHost");
|
|
||||||
}
|
|
||||||
|
|
||||||
String host = syslogHost;
|
|
||||||
int urlPort = -1;
|
|
||||||
|
|
||||||
//
|
|
||||||
// If not an unbracketed IPv6 address then
|
|
||||||
// parse as a URL
|
|
||||||
//
|
|
||||||
if (host.indexOf("[") != -1 || host.indexOf(':') == host.lastIndexOf(':')) {
|
|
||||||
try {
|
|
||||||
URL url = new URL("http://" + host);
|
|
||||||
if (url.getHost() != null) {
|
|
||||||
host = url.getHost();
|
|
||||||
// if host is a IPv6 literal, strip off the brackets
|
|
||||||
if(host.startsWith("[") && host.charAt(host.length() - 1) == ']') {
|
|
||||||
host = host.substring(1, host.length() - 1);
|
|
||||||
}
|
|
||||||
urlPort = url.getPort();
|
|
||||||
}
|
|
||||||
} catch(MalformedURLException e) {
|
|
||||||
LogLog.error("Malformed URL: will attempt to interpret as InetAddress.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (urlPort == -1) {
|
|
||||||
urlPort = SYSLOG_PORT;
|
|
||||||
}
|
|
||||||
port = urlPort;
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.address = InetAddress.getByName(host);
|
|
||||||
}
|
|
||||||
catch (UnknownHostException e) {
|
|
||||||
LogLog.error("Could not find " + host +
|
|
||||||
". All logging will FAIL.", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.ds = new DatagramSocket();
|
|
||||||
}
|
|
||||||
catch (SocketException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
LogLog.error("Could not instantiate DatagramSocket to " + host +
|
|
||||||
". All logging will FAIL.", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public
|
|
||||||
void write(char[] buf, int off, int len) throws IOException {
|
|
||||||
this.write(new String(buf, off, len));
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void write(final String string) throws IOException {
|
|
||||||
|
|
||||||
if(this.ds != null && this.address != null) {
|
|
||||||
byte[] bytes = string.getBytes();
|
|
||||||
//
|
|
||||||
// syslog packets must be less than 1024 bytes
|
|
||||||
//
|
|
||||||
int bytesLength = bytes.length;
|
|
||||||
if (bytesLength >= 1024) {
|
|
||||||
bytesLength = 1024;
|
|
||||||
}
|
|
||||||
DatagramPacket packet = new DatagramPacket(bytes, bytesLength,
|
|
||||||
address, port);
|
|
||||||
ds.send(packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void flush() {}
|
|
||||||
|
|
||||||
public void close() {
|
|
||||||
if (ds != null) {
|
|
||||||
ds.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.helpers;
|
|
||||||
|
|
||||||
import java.util.Hashtable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
<code>ThreadLocalMap</code> extends {@link InheritableThreadLocal}
|
|
||||||
to bequeath a copy of the hashtable of the MDC of the parent
|
|
||||||
thread.
|
|
||||||
|
|
||||||
@author Ceki Gülcü
|
|
||||||
@since 1.2
|
|
||||||
*/
|
|
||||||
final public class ThreadLocalMap extends InheritableThreadLocal {
|
|
||||||
|
|
||||||
public
|
|
||||||
final
|
|
||||||
Object childValue(Object parentValue) {
|
|
||||||
Hashtable ht = (Hashtable) parentValue;
|
|
||||||
if(ht != null) {
|
|
||||||
return ht.clone();
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.helpers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Utility class for transforming strings.
|
|
||||||
|
|
||||||
@author Ceki Gülcü
|
|
||||||
@author Michael A. McAngus
|
|
||||||
*/
|
|
||||||
public class Transform {
|
|
||||||
|
|
||||||
private static final String CDATA_START = "<![CDATA[";
|
|
||||||
private static final String CDATA_END = "]]>";
|
|
||||||
private static final String CDATA_PSEUDO_END = "]]>";
|
|
||||||
private static final String CDATA_EMBEDED_END = CDATA_END + CDATA_PSEUDO_END + CDATA_START;
|
|
||||||
private static final int CDATA_END_LEN = CDATA_END.length();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method takes a string which may contain HTML tags (ie,
|
|
||||||
* <b>, <table>, etc) and replaces any
|
|
||||||
* '<', '>' , '&' or '"'
|
|
||||||
* characters with respective predefined entity references.
|
|
||||||
*
|
|
||||||
* @param input The text to be converted.
|
|
||||||
* @return The input string with the special characters replaced.
|
|
||||||
* */
|
|
||||||
static public String escapeTags(final String input) {
|
|
||||||
//Check if the string is null, zero length or devoid of special characters
|
|
||||||
// if so, return what was sent in.
|
|
||||||
|
|
||||||
if(input == null
|
|
||||||
|| input.length() == 0
|
|
||||||
|| (input.indexOf('"') == -1 &&
|
|
||||||
input.indexOf('&') == -1 &&
|
|
||||||
input.indexOf('<') == -1 &&
|
|
||||||
input.indexOf('>') == -1)) {
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Use a StringBuffer in lieu of String concatenation -- it is
|
|
||||||
//much more efficient this way.
|
|
||||||
|
|
||||||
StringBuffer buf = new StringBuffer(input.length() + 6);
|
|
||||||
char ch = ' ';
|
|
||||||
|
|
||||||
int len = input.length();
|
|
||||||
for(int i=0; i < len; i++) {
|
|
||||||
ch = input.charAt(i);
|
|
||||||
if (ch > '>') {
|
|
||||||
buf.append(ch);
|
|
||||||
} else if(ch == '<') {
|
|
||||||
buf.append("<");
|
|
||||||
} else if(ch == '>') {
|
|
||||||
buf.append(">");
|
|
||||||
} else if(ch == '&') {
|
|
||||||
buf.append("&");
|
|
||||||
} else if(ch == '"') {
|
|
||||||
buf.append(""");
|
|
||||||
} else {
|
|
||||||
buf.append(ch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensures that embeded CDEnd strings (]]>) are handled properly
|
|
||||||
* within message, NDC and throwable tag text.
|
|
||||||
*
|
|
||||||
* @param buf StringBuffer holding the XML data to this point. The
|
|
||||||
* initial CDStart (<![CDATA[) and final CDEnd (]]>) of the CDATA
|
|
||||||
* section are the responsibility of the calling method.
|
|
||||||
* @param str The String that is inserted into an existing CDATA Section within buf.
|
|
||||||
* */
|
|
||||||
static public void appendEscapingCDATA(final StringBuffer buf,
|
|
||||||
final String str) {
|
|
||||||
if (str != null) {
|
|
||||||
int end = str.indexOf(CDATA_END);
|
|
||||||
if (end < 0) {
|
|
||||||
buf.append(str);
|
|
||||||
} else {
|
|
||||||
int start = 0;
|
|
||||||
while (end > -1) {
|
|
||||||
buf.append(str.substring(start, end));
|
|
||||||
buf.append(CDATA_EMBEDED_END);
|
|
||||||
start = end + CDATA_END_LEN;
|
|
||||||
if (start < str.length()) {
|
|
||||||
end = str.indexOf(CDATA_END, start);
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buf.append(str.substring(start));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
|
||||||
<!--
|
|
||||||
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.
|
|
||||||
|
|
||||||
-->
|
|
||||||
<html> <head>
|
|
||||||
<title></title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<p>This package is used internally.
|
|
||||||
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
<address></address>
|
|
||||||
<!-- hhmts start -->
|
|
||||||
Last modified: Sat Jul 3 15:12:58 MDT 1999
|
|
||||||
<!-- hhmts end -->
|
|
||||||
</body> </html>
|
|
||||||
@@ -1,398 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.jdbc;
|
|
||||||
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.DriverManager;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Statement;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
import org.apache.log4j.PatternLayout;
|
|
||||||
import org.apache.log4j.spi.ErrorCode;
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
The JDBCAppender provides for sending log events to a database.
|
|
||||||
|
|
||||||
<p><b><font color="#FF2222">WARNING: This version of JDBCAppender
|
|
||||||
is very likely to be completely replaced in the future. Moreoever,
|
|
||||||
it does not log exceptions</font></b>.
|
|
||||||
|
|
||||||
<p>Each append call adds to an <code>ArrayList</code> buffer. When
|
|
||||||
the buffer is filled each log event is placed in a sql statement
|
|
||||||
(configurable) and executed.
|
|
||||||
|
|
||||||
<b>BufferSize</b>, <b>db URL</b>, <b>User</b>, & <b>Password</b> are
|
|
||||||
configurable options in the standard log4j ways.
|
|
||||||
|
|
||||||
<p>The <code>setSql(String sql)</code> sets the SQL statement to be
|
|
||||||
used for logging -- this statement is sent to a
|
|
||||||
<code>PatternLayout</code> (either created automaticly by the
|
|
||||||
appender or added by the user). Therefore by default all the
|
|
||||||
conversion patterns in <code>PatternLayout</code> can be used
|
|
||||||
inside of the statement. (see the test cases for examples)
|
|
||||||
|
|
||||||
<p>Overriding the {@link #getLogStatement} method allows more
|
|
||||||
explicit control of the statement used for logging.
|
|
||||||
|
|
||||||
<p>For use as a base class:
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
|
|
||||||
<li>Override <code>getConnection()</code> to pass any connection
|
|
||||||
you want. Typically this is used to enable application wide
|
|
||||||
connection pooling.
|
|
||||||
|
|
||||||
<li>Override <code>closeConnection(Connection con)</code> -- if
|
|
||||||
you override getConnection make sure to implement
|
|
||||||
<code>closeConnection</code> to handle the connection you
|
|
||||||
generated. Typically this would return the connection to the
|
|
||||||
pool it came from.
|
|
||||||
|
|
||||||
<li>Override <code>getLogStatement(LoggingEvent event)</code> to
|
|
||||||
produce specialized or dynamic statements. The default uses the
|
|
||||||
sql option value.
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
@author Kevin Steppe (<A HREF="mailto:ksteppe@pacbell.net">ksteppe@pacbell.net</A>)
|
|
||||||
|
|
||||||
*/
|
|
||||||
public class JDBCAppender extends org.apache.log4j.AppenderSkeleton
|
|
||||||
implements org.apache.log4j.Appender {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* URL of the DB for default connection handling
|
|
||||||
*/
|
|
||||||
protected String databaseURL = "jdbc:odbc:myDB";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User to connect as for default connection handling
|
|
||||||
*/
|
|
||||||
protected String databaseUser = "me";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User to use for default connection handling
|
|
||||||
*/
|
|
||||||
protected String databasePassword = "mypassword";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Connection used by default. The connection is opened the first time it
|
|
||||||
* is needed and then held open until the appender is closed (usually at
|
|
||||||
* garbage collection). This behavior is best modified by creating a
|
|
||||||
* sub-class and overriding the <code>getConnection</code> and
|
|
||||||
* <code>closeConnection</code> methods.
|
|
||||||
*/
|
|
||||||
protected Connection connection = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores the string given to the pattern layout for conversion into a SQL
|
|
||||||
* statement, eg: insert into LogTable (Thread, Class, Message) values
|
|
||||||
* ("%t", "%c", "%m").
|
|
||||||
*
|
|
||||||
* Be careful of quotes in your messages!
|
|
||||||
*
|
|
||||||
* Also see PatternLayout.
|
|
||||||
*/
|
|
||||||
protected String sqlStatement = "";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* size of LoggingEvent buffer before writting to the database.
|
|
||||||
* Default is 1.
|
|
||||||
*/
|
|
||||||
protected int bufferSize = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ArrayList holding the buffer of Logging Events.
|
|
||||||
*/
|
|
||||||
protected ArrayList buffer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper object for clearing out the buffer
|
|
||||||
*/
|
|
||||||
protected ArrayList removes;
|
|
||||||
|
|
||||||
private boolean locationInfo = false;
|
|
||||||
|
|
||||||
public JDBCAppender() {
|
|
||||||
super();
|
|
||||||
buffer = new ArrayList(bufferSize);
|
|
||||||
removes = new ArrayList(bufferSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets whether the location of the logging request call
|
|
||||||
* should be captured.
|
|
||||||
*
|
|
||||||
* @since 1.2.16
|
|
||||||
* @return the current value of the <b>LocationInfo</b> option.
|
|
||||||
*/
|
|
||||||
public boolean getLocationInfo() {
|
|
||||||
return locationInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The <b>LocationInfo</b> option takes a boolean value. By default, it is
|
|
||||||
* set to false which means there will be no effort to extract the location
|
|
||||||
* information related to the event. As a result, the event that will be
|
|
||||||
* ultimately logged will likely to contain the wrong location information
|
|
||||||
* (if present in the log format).
|
|
||||||
* <p/>
|
|
||||||
* <p/>
|
|
||||||
* Location information extraction is comparatively very slow and should be
|
|
||||||
* avoided unless performance is not a concern.
|
|
||||||
* </p>
|
|
||||||
* @since 1.2.16
|
|
||||||
* @param flag true if location information should be extracted.
|
|
||||||
*/
|
|
||||||
public void setLocationInfo(final boolean flag) {
|
|
||||||
locationInfo = flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the event to the buffer. When full the buffer is flushed.
|
|
||||||
*/
|
|
||||||
public void append(LoggingEvent event) {
|
|
||||||
event.getNDC();
|
|
||||||
event.getThreadName();
|
|
||||||
// Get a copy of this thread's MDC.
|
|
||||||
event.getMDCCopy();
|
|
||||||
if (locationInfo) {
|
|
||||||
event.getLocationInformation();
|
|
||||||
}
|
|
||||||
event.getRenderedMessage();
|
|
||||||
event.getThrowableStrRep();
|
|
||||||
buffer.add(event);
|
|
||||||
|
|
||||||
if (buffer.size() >= bufferSize)
|
|
||||||
flushBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* By default getLogStatement sends the event to the required Layout object.
|
|
||||||
* The layout will format the given pattern into a workable SQL string.
|
|
||||||
*
|
|
||||||
* Overriding this provides direct access to the LoggingEvent
|
|
||||||
* when constructing the logging statement.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
protected String getLogStatement(LoggingEvent event) {
|
|
||||||
return getLayout().format(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Override this to provide an alertnate method of getting
|
|
||||||
* connections (such as caching). One method to fix this is to open
|
|
||||||
* connections at the start of flushBuffer() and close them at the
|
|
||||||
* end. I use a connection pool outside of JDBCAppender which is
|
|
||||||
* accessed in an override of this method.
|
|
||||||
* */
|
|
||||||
protected void execute(String sql) throws SQLException {
|
|
||||||
|
|
||||||
Connection con = null;
|
|
||||||
Statement stmt = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
con = getConnection();
|
|
||||||
|
|
||||||
stmt = con.createStatement();
|
|
||||||
stmt.executeUpdate(sql);
|
|
||||||
} catch (SQLException e) {
|
|
||||||
if (stmt != null)
|
|
||||||
stmt.close();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
stmt.close();
|
|
||||||
closeConnection(con);
|
|
||||||
|
|
||||||
//System.out.println("Execute: " + sql);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override this to return the connection to a pool, or to clean up the
|
|
||||||
* resource.
|
|
||||||
*
|
|
||||||
* The default behavior holds a single connection open until the appender
|
|
||||||
* is closed (typically when garbage collected).
|
|
||||||
*/
|
|
||||||
protected void closeConnection(Connection con) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override this to link with your connection pooling system.
|
|
||||||
*
|
|
||||||
* By default this creates a single connection which is held open
|
|
||||||
* until the object is garbage collected.
|
|
||||||
*/
|
|
||||||
protected Connection getConnection() throws SQLException {
|
|
||||||
if (!DriverManager.getDrivers().hasMoreElements())
|
|
||||||
setDriver("sun.jdbc.odbc.JdbcOdbcDriver");
|
|
||||||
|
|
||||||
if (connection == null) {
|
|
||||||
connection = DriverManager.getConnection(databaseURL, databaseUser,
|
|
||||||
databasePassword);
|
|
||||||
}
|
|
||||||
|
|
||||||
return connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes the appender, flushing the buffer first then closing the default
|
|
||||||
* connection if it is open.
|
|
||||||
*/
|
|
||||||
public void close()
|
|
||||||
{
|
|
||||||
flushBuffer();
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (connection != null && !connection.isClosed())
|
|
||||||
connection.close();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
errorHandler.error("Error closing connection", e, ErrorCode.GENERIC_FAILURE);
|
|
||||||
}
|
|
||||||
this.closed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* loops through the buffer of LoggingEvents, gets a
|
|
||||||
* sql string from getLogStatement() and sends it to execute().
|
|
||||||
* Errors are sent to the errorHandler.
|
|
||||||
*
|
|
||||||
* If a statement fails the LoggingEvent stays in the buffer!
|
|
||||||
*/
|
|
||||||
public void flushBuffer() {
|
|
||||||
//Do the actual logging
|
|
||||||
removes.ensureCapacity(buffer.size());
|
|
||||||
for (Iterator i = buffer.iterator(); i.hasNext();) {
|
|
||||||
try {
|
|
||||||
LoggingEvent logEvent = (LoggingEvent)i.next();
|
|
||||||
String sql = getLogStatement(logEvent);
|
|
||||||
execute(sql);
|
|
||||||
removes.add(logEvent);
|
|
||||||
}
|
|
||||||
catch (SQLException e) {
|
|
||||||
errorHandler.error("Failed to excute sql", e,
|
|
||||||
ErrorCode.FLUSH_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove from the buffer any events that were reported
|
|
||||||
buffer.removeAll(removes);
|
|
||||||
|
|
||||||
// clear the buffer of reported events
|
|
||||||
removes.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** closes the appender before disposal */
|
|
||||||
public void finalize() {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JDBCAppender requires a layout.
|
|
||||||
* */
|
|
||||||
public boolean requiresLayout() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void setSql(String s) {
|
|
||||||
sqlStatement = s;
|
|
||||||
if (getLayout() == null) {
|
|
||||||
this.setLayout(new PatternLayout(s));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
((PatternLayout)getLayout()).setConversionPattern(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns pre-formated statement eg: insert into LogTable (msg) values ("%m")
|
|
||||||
*/
|
|
||||||
public String getSql() {
|
|
||||||
return sqlStatement;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setUser(String user) {
|
|
||||||
databaseUser = user;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setURL(String url) {
|
|
||||||
databaseURL = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setPassword(String password) {
|
|
||||||
databasePassword = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setBufferSize(int newBufferSize) {
|
|
||||||
bufferSize = newBufferSize;
|
|
||||||
buffer.ensureCapacity(bufferSize);
|
|
||||||
removes.ensureCapacity(bufferSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String getUser() {
|
|
||||||
return databaseUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String getURL() {
|
|
||||||
return databaseURL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String getPassword() {
|
|
||||||
return databasePassword;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public int getBufferSize() {
|
|
||||||
return bufferSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensures that the given driver class has been loaded for sql connection
|
|
||||||
* creation.
|
|
||||||
*/
|
|
||||||
public void setDriver(String driverClass) {
|
|
||||||
try {
|
|
||||||
Class.forName(driverClass);
|
|
||||||
} catch (Exception e) {
|
|
||||||
errorHandler.error("Failed to load driver", e,
|
|
||||||
ErrorCode.GENERIC_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
<!--
|
|
||||||
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.
|
|
||||||
|
|
||||||
-->
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
The JDBCAppender provides for sending log events to a database.
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,187 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.jmx;
|
|
||||||
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
import javax.management.Attribute;
|
|
||||||
import javax.management.AttributeList;
|
|
||||||
import javax.management.DynamicMBean;
|
|
||||||
import javax.management.InstanceAlreadyExistsException;
|
|
||||||
import javax.management.InstanceNotFoundException;
|
|
||||||
import javax.management.JMException;
|
|
||||||
import javax.management.MBeanRegistration;
|
|
||||||
import javax.management.MBeanRegistrationException;
|
|
||||||
import javax.management.MBeanServer;
|
|
||||||
import javax.management.NotCompliantMBeanException;
|
|
||||||
import javax.management.ObjectName;
|
|
||||||
import javax.management.RuntimeOperationsException;
|
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
import org.apache.log4j.Appender;
|
|
||||||
|
|
||||||
public abstract class AbstractDynamicMBean implements DynamicMBean,
|
|
||||||
MBeanRegistration {
|
|
||||||
|
|
||||||
String dClassName;
|
|
||||||
MBeanServer server;
|
|
||||||
private final Vector mbeanList = new Vector();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get MBean name.
|
|
||||||
* @param appender appender, may not be null.
|
|
||||||
* @return name.
|
|
||||||
* @since 1.2.16
|
|
||||||
*/
|
|
||||||
static protected String getAppenderName(final Appender appender){
|
|
||||||
String name = appender.getName();
|
|
||||||
if (name == null || name.trim().length() == 0) {
|
|
||||||
// try to get some form of a name, because null is not allowed (exception), and empty string certainly isn't useful in JMX..
|
|
||||||
name = appender.toString();
|
|
||||||
}
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enables the to get the values of several attributes of the Dynamic MBean.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
AttributeList getAttributes(String[] attributeNames) {
|
|
||||||
|
|
||||||
// Check attributeNames is not null to avoid NullPointerException later on
|
|
||||||
if (attributeNames == null) {
|
|
||||||
throw new RuntimeOperationsException(
|
|
||||||
new IllegalArgumentException("attributeNames[] cannot be null"),
|
|
||||||
"Cannot invoke a getter of " + dClassName);
|
|
||||||
}
|
|
||||||
|
|
||||||
AttributeList resultList = new AttributeList();
|
|
||||||
|
|
||||||
// if attributeNames is empty, return an empty result list
|
|
||||||
if (attributeNames.length == 0)
|
|
||||||
return resultList;
|
|
||||||
|
|
||||||
// build the result attribute list
|
|
||||||
for (int i=0 ; i<attributeNames.length ; i++){
|
|
||||||
try {
|
|
||||||
Object value = getAttribute((String) attributeNames[i]);
|
|
||||||
resultList.add(new Attribute(attributeNames[i],value));
|
|
||||||
} catch (JMException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return(resultList);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the values of several attributes of the Dynamic MBean, and returns the
|
|
||||||
* list of attributes that have been set.
|
|
||||||
*/
|
|
||||||
public AttributeList setAttributes(AttributeList attributes) {
|
|
||||||
|
|
||||||
// Check attributes is not null to avoid NullPointerException later on
|
|
||||||
if (attributes == null) {
|
|
||||||
throw new RuntimeOperationsException(
|
|
||||||
new IllegalArgumentException("AttributeList attributes cannot be null"),
|
|
||||||
"Cannot invoke a setter of " + dClassName);
|
|
||||||
}
|
|
||||||
AttributeList resultList = new AttributeList();
|
|
||||||
|
|
||||||
// if attributeNames is empty, nothing more to do
|
|
||||||
if (attributes.isEmpty())
|
|
||||||
return resultList;
|
|
||||||
|
|
||||||
// for each attribute, try to set it and add to the result list if successfull
|
|
||||||
for (Iterator i = attributes.iterator(); i.hasNext();) {
|
|
||||||
Attribute attr = (Attribute) i.next();
|
|
||||||
try {
|
|
||||||
setAttribute(attr);
|
|
||||||
String name = attr.getName();
|
|
||||||
Object value = getAttribute(name);
|
|
||||||
resultList.add(new Attribute(name,value));
|
|
||||||
} catch(JMException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch(RuntimeException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return(resultList);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected
|
|
||||||
abstract
|
|
||||||
Logger getLogger();
|
|
||||||
|
|
||||||
public
|
|
||||||
void postDeregister() {
|
|
||||||
getLogger().debug("postDeregister is called.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void postRegister(java.lang.Boolean registrationDone) {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public
|
|
||||||
ObjectName preRegister(MBeanServer server, ObjectName name) {
|
|
||||||
getLogger().debug("preRegister called. Server="+server+ ", name="+name);
|
|
||||||
this.server = server;
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Registers MBean instance in the attached server. Must <em>NOT</em>
|
|
||||||
* be called before registration of this instance.
|
|
||||||
*/
|
|
||||||
protected
|
|
||||||
void registerMBean(Object mbean, ObjectName objectName)
|
|
||||||
throws InstanceAlreadyExistsException, MBeanRegistrationException,
|
|
||||||
NotCompliantMBeanException {
|
|
||||||
server.registerMBean(mbean, objectName);
|
|
||||||
mbeanList.add(objectName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs cleanup for deregistering this MBean. Default implementation
|
|
||||||
* unregisters MBean instances which are registered using
|
|
||||||
* {@link #registerMBean(Object mbean, ObjectName objectName)}.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void preDeregister() {
|
|
||||||
getLogger().debug("preDeregister called.");
|
|
||||||
|
|
||||||
Enumeration iterator = mbeanList.elements();
|
|
||||||
while (iterator.hasMoreElements()) {
|
|
||||||
ObjectName name = (ObjectName) iterator.nextElement();
|
|
||||||
try {
|
|
||||||
server.unregisterMBean(name);
|
|
||||||
} catch (InstanceNotFoundException e) {
|
|
||||||
getLogger().warn("Missing MBean " + name.getCanonicalName());
|
|
||||||
} catch (MBeanRegistrationException e) {
|
|
||||||
getLogger().warn("Failed unregistering " + name.getCanonicalName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.jmx;
|
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
import javax.management.JMException;
|
|
||||||
import javax.management.MBeanServer;
|
|
||||||
import javax.management.MBeanServerFactory;
|
|
||||||
import javax.management.ObjectName;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.io.InterruptedIOException;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manages an instance of com.sun.jdmk.comm.HtmlAdapterServer which
|
|
||||||
* was provided for demonstration purposes in the
|
|
||||||
* Java Management Extensions Reference Implementation 1.2.1.
|
|
||||||
* This class is provided to maintain compatibility with earlier
|
|
||||||
* versions of log4j and use in new code is discouraged.
|
|
||||||
*
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
public class Agent {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Diagnostic logger.
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
static Logger log = Logger.getLogger(Agent.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create new instance.
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
public Agent() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new instance of com.sun.jdmk.comm.HtmlAdapterServer
|
|
||||||
* using reflection.
|
|
||||||
*
|
|
||||||
* @since 1.2.16
|
|
||||||
* @return new instance.
|
|
||||||
*/
|
|
||||||
private static Object createServer() {
|
|
||||||
Object newInstance = null;
|
|
||||||
try {
|
|
||||||
newInstance = Class.forName(
|
|
||||||
"com.sun.jdmk.comm.HtmlAdapterServer").newInstance();
|
|
||||||
} catch (ClassNotFoundException ex) {
|
|
||||||
throw new RuntimeException(ex.toString());
|
|
||||||
} catch (InstantiationException ex) {
|
|
||||||
throw new RuntimeException(ex.toString());
|
|
||||||
} catch (IllegalAccessException ex) {
|
|
||||||
throw new RuntimeException(ex.toString());
|
|
||||||
}
|
|
||||||
return newInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invokes HtmlAdapterServer.start() using reflection.
|
|
||||||
*
|
|
||||||
* @since 1.2.16
|
|
||||||
* @param server instance of com.sun.jdmk.comm.HtmlAdapterServer.
|
|
||||||
*/
|
|
||||||
private static void startServer(final Object server) {
|
|
||||||
try {
|
|
||||||
server.getClass().getMethod("start", new Class[0]).
|
|
||||||
invoke(server, new Object[0]);
|
|
||||||
} catch(InvocationTargetException ex) {
|
|
||||||
Throwable cause = ex.getTargetException();
|
|
||||||
if (cause instanceof RuntimeException) {
|
|
||||||
throw (RuntimeException) cause;
|
|
||||||
} else if (cause != null) {
|
|
||||||
if (cause instanceof InterruptedException
|
|
||||||
|| cause instanceof InterruptedIOException) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
throw new RuntimeException(cause.toString());
|
|
||||||
} else {
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
} catch(NoSuchMethodException ex) {
|
|
||||||
throw new RuntimeException(ex.toString());
|
|
||||||
} catch(IllegalAccessException ex) {
|
|
||||||
throw new RuntimeException(ex.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts instance of HtmlAdapterServer.
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
public void start() {
|
|
||||||
|
|
||||||
MBeanServer server = MBeanServerFactory.createMBeanServer();
|
|
||||||
Object html = createServer();
|
|
||||||
|
|
||||||
try {
|
|
||||||
log.info("Registering HtmlAdaptorServer instance.");
|
|
||||||
server.registerMBean(html, new ObjectName("Adaptor:name=html,port=8082"));
|
|
||||||
log.info("Registering HierarchyDynamicMBean instance.");
|
|
||||||
HierarchyDynamicMBean hdm = new HierarchyDynamicMBean();
|
|
||||||
server.registerMBean(hdm, new ObjectName("log4j:hiearchy=default"));
|
|
||||||
} catch(JMException e) {
|
|
||||||
log.error("Problem while registering MBeans instances.", e);
|
|
||||||
return;
|
|
||||||
} catch(RuntimeException e) {
|
|
||||||
log.error("Problem while registering MBeans instances.", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
startServer(html);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,346 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.jmx;
|
|
||||||
|
|
||||||
import org.apache.log4j.Appender;
|
|
||||||
import org.apache.log4j.Layout;
|
|
||||||
import org.apache.log4j.Level;
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
import org.apache.log4j.Priority;
|
|
||||||
import org.apache.log4j.helpers.OptionConverter;
|
|
||||||
import org.apache.log4j.spi.OptionHandler;
|
|
||||||
|
|
||||||
import javax.management.Attribute;
|
|
||||||
import javax.management.AttributeNotFoundException;
|
|
||||||
import javax.management.InvalidAttributeValueException;
|
|
||||||
import javax.management.JMException;
|
|
||||||
import javax.management.MBeanAttributeInfo;
|
|
||||||
import javax.management.MBeanConstructorInfo;
|
|
||||||
import javax.management.MBeanException;
|
|
||||||
import javax.management.MBeanInfo;
|
|
||||||
import javax.management.MBeanNotificationInfo;
|
|
||||||
import javax.management.MBeanOperationInfo;
|
|
||||||
import javax.management.MBeanParameterInfo;
|
|
||||||
import javax.management.MBeanServer;
|
|
||||||
import javax.management.MalformedObjectNameException;
|
|
||||||
import javax.management.ObjectName;
|
|
||||||
import javax.management.ReflectionException;
|
|
||||||
import javax.management.RuntimeOperationsException;
|
|
||||||
import java.beans.BeanInfo;
|
|
||||||
import java.beans.IntrospectionException;
|
|
||||||
import java.beans.Introspector;
|
|
||||||
import java.beans.PropertyDescriptor;
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.Hashtable;
|
|
||||||
import java.util.Vector;
|
|
||||||
import java.io.InterruptedIOException;
|
|
||||||
|
|
||||||
public class AppenderDynamicMBean extends AbstractDynamicMBean {
|
|
||||||
|
|
||||||
private MBeanConstructorInfo[] dConstructors = new MBeanConstructorInfo[1];
|
|
||||||
private Vector dAttributes = new Vector();
|
|
||||||
private String dClassName = this.getClass().getName();
|
|
||||||
|
|
||||||
private Hashtable dynamicProps = new Hashtable(5);
|
|
||||||
private MBeanOperationInfo[] dOperations = new MBeanOperationInfo[2];
|
|
||||||
private String dDescription =
|
|
||||||
"This MBean acts as a management facade for log4j appenders.";
|
|
||||||
|
|
||||||
// This category instance is for logging.
|
|
||||||
private static Logger cat = Logger.getLogger(AppenderDynamicMBean.class);
|
|
||||||
|
|
||||||
// We wrap this appender instance.
|
|
||||||
private Appender appender;
|
|
||||||
|
|
||||||
public AppenderDynamicMBean(Appender appender) throws IntrospectionException {
|
|
||||||
this.appender = appender;
|
|
||||||
buildDynamicMBeanInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
private
|
|
||||||
void buildDynamicMBeanInfo() throws IntrospectionException {
|
|
||||||
Constructor[] constructors = this.getClass().getConstructors();
|
|
||||||
dConstructors[0] = new MBeanConstructorInfo(
|
|
||||||
"AppenderDynamicMBean(): Constructs a AppenderDynamicMBean instance",
|
|
||||||
constructors[0]);
|
|
||||||
|
|
||||||
|
|
||||||
BeanInfo bi = Introspector.getBeanInfo(appender.getClass());
|
|
||||||
PropertyDescriptor[] pd = bi.getPropertyDescriptors();
|
|
||||||
|
|
||||||
int size = pd.length;
|
|
||||||
|
|
||||||
for(int i = 0; i < size; i++) {
|
|
||||||
String name = pd[i].getName();
|
|
||||||
Method readMethod = pd[i].getReadMethod();
|
|
||||||
Method writeMethod = pd[i].getWriteMethod();
|
|
||||||
if(readMethod != null) {
|
|
||||||
Class returnClass = readMethod.getReturnType();
|
|
||||||
if(isSupportedType(returnClass)) {
|
|
||||||
String returnClassName;
|
|
||||||
if(returnClass.isAssignableFrom(Priority.class)) {
|
|
||||||
returnClassName = "java.lang.String";
|
|
||||||
} else {
|
|
||||||
returnClassName = returnClass.getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
dAttributes.add(new MBeanAttributeInfo(name,
|
|
||||||
returnClassName,
|
|
||||||
"Dynamic",
|
|
||||||
true,
|
|
||||||
writeMethod != null,
|
|
||||||
false));
|
|
||||||
dynamicProps.put(name, new MethodUnion(readMethod, writeMethod));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MBeanParameterInfo[] params = new MBeanParameterInfo[0];
|
|
||||||
|
|
||||||
dOperations[0] = new MBeanOperationInfo("activateOptions",
|
|
||||||
"activateOptions(): add an appender",
|
|
||||||
params,
|
|
||||||
"void",
|
|
||||||
MBeanOperationInfo.ACTION);
|
|
||||||
|
|
||||||
params = new MBeanParameterInfo[1];
|
|
||||||
params[0] = new MBeanParameterInfo("layout class", "java.lang.String",
|
|
||||||
"layout class");
|
|
||||||
|
|
||||||
dOperations[1] = new MBeanOperationInfo("setLayout",
|
|
||||||
"setLayout(): add a layout",
|
|
||||||
params,
|
|
||||||
"void",
|
|
||||||
MBeanOperationInfo.ACTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
private
|
|
||||||
boolean isSupportedType(Class clazz) {
|
|
||||||
if(clazz.isPrimitive()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(clazz == String.class) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(clazz.isAssignableFrom(Priority.class)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public
|
|
||||||
MBeanInfo getMBeanInfo() {
|
|
||||||
cat.debug("getMBeanInfo called.");
|
|
||||||
|
|
||||||
MBeanAttributeInfo[] attribs = new MBeanAttributeInfo[dAttributes.size()];
|
|
||||||
dAttributes.toArray(attribs);
|
|
||||||
|
|
||||||
return new MBeanInfo(dClassName,
|
|
||||||
dDescription,
|
|
||||||
attribs,
|
|
||||||
dConstructors,
|
|
||||||
dOperations,
|
|
||||||
new MBeanNotificationInfo[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
Object invoke(String operationName, Object params[], String signature[])
|
|
||||||
throws MBeanException,
|
|
||||||
ReflectionException {
|
|
||||||
|
|
||||||
if(operationName.equals("activateOptions") &&
|
|
||||||
appender instanceof OptionHandler) {
|
|
||||||
OptionHandler oh = (OptionHandler) appender;
|
|
||||||
oh.activateOptions();
|
|
||||||
return "Options activated.";
|
|
||||||
} else if (operationName.equals("setLayout")) {
|
|
||||||
Layout layout = (Layout) OptionConverter.instantiateByClassName((String)
|
|
||||||
params[0],
|
|
||||||
Layout.class,
|
|
||||||
null);
|
|
||||||
appender.setLayout(layout);
|
|
||||||
registerLayoutMBean(layout);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
void registerLayoutMBean(Layout layout) {
|
|
||||||
if(layout == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
String name = getAppenderName(appender)+",layout="+layout.getClass().getName();
|
|
||||||
cat.debug("Adding LayoutMBean:"+name);
|
|
||||||
ObjectName objectName = null;
|
|
||||||
try {
|
|
||||||
LayoutDynamicMBean appenderMBean = new LayoutDynamicMBean(layout);
|
|
||||||
objectName = new ObjectName("log4j:appender="+name);
|
|
||||||
if (!server.isRegistered(objectName)) {
|
|
||||||
registerMBean(appenderMBean, objectName);
|
|
||||||
dAttributes.add(new MBeanAttributeInfo("appender=" + name, "javax.management.ObjectName",
|
|
||||||
"The " + name + " layout.", true, true, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch(JMException e) {
|
|
||||||
cat.error("Could not add DynamicLayoutMBean for ["+name+"].", e);
|
|
||||||
} catch(java.beans.IntrospectionException e) {
|
|
||||||
cat.error("Could not add DynamicLayoutMBean for ["+name+"].", e);
|
|
||||||
} catch(RuntimeException e) {
|
|
||||||
cat.error("Could not add DynamicLayoutMBean for ["+name+"].", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected
|
|
||||||
Logger getLogger() {
|
|
||||||
return cat;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public
|
|
||||||
Object getAttribute(String attributeName) throws AttributeNotFoundException,
|
|
||||||
MBeanException,
|
|
||||||
ReflectionException {
|
|
||||||
|
|
||||||
// Check attributeName is not null to avoid NullPointerException later on
|
|
||||||
if (attributeName == null) {
|
|
||||||
throw new RuntimeOperationsException(new IllegalArgumentException(
|
|
||||||
"Attribute name cannot be null"),
|
|
||||||
"Cannot invoke a getter of " + dClassName + " with null attribute name");
|
|
||||||
}
|
|
||||||
|
|
||||||
cat.debug("getAttribute called with ["+attributeName+"].");
|
|
||||||
if(attributeName.startsWith("appender="+appender.getName()+",layout")) {
|
|
||||||
try {
|
|
||||||
return new ObjectName("log4j:"+attributeName );
|
|
||||||
} catch(MalformedObjectNameException e) {
|
|
||||||
cat.error("attributeName", e);
|
|
||||||
} catch(RuntimeException e) {
|
|
||||||
cat.error("attributeName", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MethodUnion mu = (MethodUnion) dynamicProps.get(attributeName);
|
|
||||||
|
|
||||||
//cat.debug("----name="+attributeName+", b="+b);
|
|
||||||
|
|
||||||
if(mu != null && mu.readMethod != null) {
|
|
||||||
try {
|
|
||||||
return mu.readMethod.invoke(appender, null);
|
|
||||||
} catch(IllegalAccessException e) {
|
|
||||||
return null;
|
|
||||||
} catch(InvocationTargetException e) {
|
|
||||||
if (e.getTargetException() instanceof InterruptedException
|
|
||||||
|| e.getTargetException() instanceof InterruptedIOException) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
} catch(RuntimeException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// If attributeName has not been recognized throw an AttributeNotFoundException
|
|
||||||
throw(new AttributeNotFoundException("Cannot find " + attributeName +
|
|
||||||
" attribute in " + dClassName));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public
|
|
||||||
void setAttribute(Attribute attribute) throws AttributeNotFoundException,
|
|
||||||
InvalidAttributeValueException,
|
|
||||||
MBeanException,
|
|
||||||
ReflectionException {
|
|
||||||
|
|
||||||
// Check attribute is not null to avoid NullPointerException later on
|
|
||||||
if (attribute == null) {
|
|
||||||
throw new RuntimeOperationsException(
|
|
||||||
new IllegalArgumentException("Attribute cannot be null"),
|
|
||||||
"Cannot invoke a setter of " + dClassName +
|
|
||||||
" with null attribute");
|
|
||||||
}
|
|
||||||
String name = attribute.getName();
|
|
||||||
Object value = attribute.getValue();
|
|
||||||
|
|
||||||
if (name == null) {
|
|
||||||
throw new RuntimeOperationsException(
|
|
||||||
new IllegalArgumentException("Attribute name cannot be null"),
|
|
||||||
"Cannot invoke the setter of "+dClassName+
|
|
||||||
" with null attribute name");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
MethodUnion mu = (MethodUnion) dynamicProps.get(name);
|
|
||||||
|
|
||||||
if(mu != null && mu.writeMethod != null) {
|
|
||||||
Object[] o = new Object[1];
|
|
||||||
|
|
||||||
Class[] params = mu.writeMethod.getParameterTypes();
|
|
||||||
if(params[0] == org.apache.log4j.Priority.class) {
|
|
||||||
value = OptionConverter.toLevel((String) value,
|
|
||||||
(Level) getAttribute(name));
|
|
||||||
}
|
|
||||||
o[0] = value;
|
|
||||||
|
|
||||||
try {
|
|
||||||
mu.writeMethod.invoke(appender, o);
|
|
||||||
|
|
||||||
} catch(InvocationTargetException e) {
|
|
||||||
if (e.getTargetException() instanceof InterruptedException
|
|
||||||
|| e.getTargetException() instanceof InterruptedIOException) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
cat.error("FIXME", e);
|
|
||||||
} catch(IllegalAccessException e) {
|
|
||||||
cat.error("FIXME", e);
|
|
||||||
} catch(RuntimeException e) {
|
|
||||||
cat.error("FIXME", e);
|
|
||||||
}
|
|
||||||
} else if(name.endsWith(".layout")) {
|
|
||||||
|
|
||||||
} else {
|
|
||||||
throw(new AttributeNotFoundException("Attribute " + name +
|
|
||||||
" not found in " +
|
|
||||||
this.getClass().getName()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
ObjectName preRegister(MBeanServer server, ObjectName name) {
|
|
||||||
cat.debug("preRegister called. Server="+server+ ", name="+name);
|
|
||||||
this.server = server;
|
|
||||||
registerLayoutMBean(appender.getLayout());
|
|
||||||
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,302 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.jmx;
|
|
||||||
|
|
||||||
|
|
||||||
import org.apache.log4j.Appender;
|
|
||||||
import org.apache.log4j.Category;
|
|
||||||
import org.apache.log4j.Level;
|
|
||||||
import org.apache.log4j.LogManager;
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
import org.apache.log4j.helpers.OptionConverter;
|
|
||||||
import org.apache.log4j.spi.HierarchyEventListener;
|
|
||||||
import org.apache.log4j.spi.LoggerRepository;
|
|
||||||
|
|
||||||
import javax.management.Attribute;
|
|
||||||
import javax.management.AttributeNotFoundException;
|
|
||||||
import javax.management.InvalidAttributeValueException;
|
|
||||||
import javax.management.JMException;
|
|
||||||
import javax.management.ListenerNotFoundException;
|
|
||||||
import javax.management.MBeanAttributeInfo;
|
|
||||||
import javax.management.MBeanConstructorInfo;
|
|
||||||
import javax.management.MBeanException;
|
|
||||||
import javax.management.MBeanInfo;
|
|
||||||
import javax.management.MBeanNotificationInfo;
|
|
||||||
import javax.management.MBeanOperationInfo;
|
|
||||||
import javax.management.MBeanParameterInfo;
|
|
||||||
import javax.management.Notification;
|
|
||||||
import javax.management.NotificationBroadcaster;
|
|
||||||
import javax.management.NotificationBroadcasterSupport;
|
|
||||||
import javax.management.NotificationFilter;
|
|
||||||
import javax.management.NotificationFilterSupport;
|
|
||||||
import javax.management.NotificationListener;
|
|
||||||
import javax.management.ObjectName;
|
|
||||||
import javax.management.ReflectionException;
|
|
||||||
import javax.management.RuntimeOperationsException;
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
public class HierarchyDynamicMBean extends AbstractDynamicMBean
|
|
||||||
implements HierarchyEventListener,
|
|
||||||
NotificationBroadcaster {
|
|
||||||
|
|
||||||
static final String ADD_APPENDER = "addAppender.";
|
|
||||||
static final String THRESHOLD = "threshold";
|
|
||||||
|
|
||||||
private MBeanConstructorInfo[] dConstructors = new MBeanConstructorInfo[1];
|
|
||||||
private MBeanOperationInfo[] dOperations = new MBeanOperationInfo[1];
|
|
||||||
|
|
||||||
private Vector vAttributes = new Vector();
|
|
||||||
private String dClassName = this.getClass().getName();
|
|
||||||
private String dDescription =
|
|
||||||
"This MBean acts as a management facade for org.apache.log4j.Hierarchy.";
|
|
||||||
|
|
||||||
private NotificationBroadcasterSupport nbs = new NotificationBroadcasterSupport();
|
|
||||||
|
|
||||||
|
|
||||||
private LoggerRepository hierarchy;
|
|
||||||
|
|
||||||
private static Logger log = Logger.getLogger(HierarchyDynamicMBean.class);
|
|
||||||
|
|
||||||
public HierarchyDynamicMBean() {
|
|
||||||
hierarchy = LogManager.getLoggerRepository();
|
|
||||||
buildDynamicMBeanInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
private
|
|
||||||
void buildDynamicMBeanInfo() {
|
|
||||||
Constructor[] constructors = this.getClass().getConstructors();
|
|
||||||
dConstructors[0] = new MBeanConstructorInfo(
|
|
||||||
"HierarchyDynamicMBean(): Constructs a HierarchyDynamicMBean instance",
|
|
||||||
constructors[0]);
|
|
||||||
|
|
||||||
vAttributes.add(new MBeanAttributeInfo(THRESHOLD,
|
|
||||||
"java.lang.String",
|
|
||||||
"The \"threshold\" state of the hiearchy.",
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
false));
|
|
||||||
|
|
||||||
MBeanParameterInfo[] params = new MBeanParameterInfo[1];
|
|
||||||
params[0] = new MBeanParameterInfo("name", "java.lang.String",
|
|
||||||
"Create a logger MBean" );
|
|
||||||
dOperations[0] = new MBeanOperationInfo("addLoggerMBean",
|
|
||||||
"addLoggerMBean(): add a loggerMBean",
|
|
||||||
params ,
|
|
||||||
"javax.management.ObjectName",
|
|
||||||
MBeanOperationInfo.ACTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public
|
|
||||||
ObjectName addLoggerMBean(String name) {
|
|
||||||
Logger cat = LogManager.exists(name);
|
|
||||||
|
|
||||||
if(cat != null) {
|
|
||||||
return addLoggerMBean(cat);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectName addLoggerMBean(Logger logger) {
|
|
||||||
String name = logger.getName();
|
|
||||||
ObjectName objectName = null;
|
|
||||||
try {
|
|
||||||
LoggerDynamicMBean loggerMBean = new LoggerDynamicMBean(logger);
|
|
||||||
objectName = new ObjectName("log4j", "logger", name);
|
|
||||||
|
|
||||||
if (!server.isRegistered(objectName)) {
|
|
||||||
registerMBean(loggerMBean, objectName);
|
|
||||||
NotificationFilterSupport nfs = new NotificationFilterSupport();
|
|
||||||
nfs.enableType(ADD_APPENDER + logger.getName());
|
|
||||||
log.debug("---Adding logger [" + name + "] as listener.");
|
|
||||||
nbs.addNotificationListener(loggerMBean, nfs, null);
|
|
||||||
vAttributes.add(new MBeanAttributeInfo("logger=" + name, "javax.management.ObjectName",
|
|
||||||
"The " + name + " logger.", true, true, // this makes the object
|
|
||||||
// clickable
|
|
||||||
false));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch(JMException e) {
|
|
||||||
log.error("Could not add loggerMBean for ["+name+"].", e);
|
|
||||||
} catch(RuntimeException e) {
|
|
||||||
log.error("Could not add loggerMBean for ["+name+"].", e);
|
|
||||||
}
|
|
||||||
return objectName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void addNotificationListener(NotificationListener listener,
|
|
||||||
NotificationFilter filter,
|
|
||||||
java.lang.Object handback) {
|
|
||||||
nbs.addNotificationListener(listener, filter, handback);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected
|
|
||||||
Logger getLogger() {
|
|
||||||
return log;
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
MBeanInfo getMBeanInfo() {
|
|
||||||
//cat.debug("getMBeanInfo called.");
|
|
||||||
|
|
||||||
MBeanAttributeInfo[] attribs = new MBeanAttributeInfo[vAttributes.size()];
|
|
||||||
vAttributes.toArray(attribs);
|
|
||||||
|
|
||||||
return new MBeanInfo(dClassName,
|
|
||||||
dDescription,
|
|
||||||
attribs,
|
|
||||||
dConstructors,
|
|
||||||
dOperations,
|
|
||||||
new MBeanNotificationInfo[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
MBeanNotificationInfo[] getNotificationInfo(){
|
|
||||||
return nbs.getNotificationInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
Object invoke(String operationName,
|
|
||||||
Object params[],
|
|
||||||
String signature[]) throws MBeanException,
|
|
||||||
ReflectionException {
|
|
||||||
|
|
||||||
if (operationName == null) {
|
|
||||||
throw new RuntimeOperationsException(
|
|
||||||
new IllegalArgumentException("Operation name cannot be null"),
|
|
||||||
"Cannot invoke a null operation in " + dClassName);
|
|
||||||
}
|
|
||||||
// Check for a recognized operation name and call the corresponding operation
|
|
||||||
|
|
||||||
if(operationName.equals("addLoggerMBean")) {
|
|
||||||
return addLoggerMBean((String)params[0]);
|
|
||||||
} else {
|
|
||||||
throw new ReflectionException(
|
|
||||||
new NoSuchMethodException(operationName),
|
|
||||||
"Cannot find the operation " + operationName + " in " + dClassName);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public
|
|
||||||
Object getAttribute(String attributeName) throws AttributeNotFoundException,
|
|
||||||
MBeanException,
|
|
||||||
ReflectionException {
|
|
||||||
|
|
||||||
// Check attributeName is not null to avoid NullPointerException later on
|
|
||||||
if (attributeName == null) {
|
|
||||||
throw new RuntimeOperationsException(new IllegalArgumentException(
|
|
||||||
"Attribute name cannot be null"),
|
|
||||||
"Cannot invoke a getter of " + dClassName + " with null attribute name");
|
|
||||||
}
|
|
||||||
|
|
||||||
log.debug("Called getAttribute with ["+attributeName+"].");
|
|
||||||
|
|
||||||
// Check for a recognized attributeName and call the corresponding getter
|
|
||||||
if (attributeName.equals(THRESHOLD)) {
|
|
||||||
return hierarchy.getThreshold();
|
|
||||||
} else if(attributeName.startsWith("logger")) {
|
|
||||||
int k = attributeName.indexOf("%3D");
|
|
||||||
String val = attributeName;
|
|
||||||
if(k > 0) {
|
|
||||||
val = attributeName.substring(0, k)+'='+ attributeName.substring(k+3);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return new ObjectName("log4j:"+val);
|
|
||||||
} catch(JMException e) {
|
|
||||||
log.error("Could not create ObjectName" + val);
|
|
||||||
} catch(RuntimeException e) {
|
|
||||||
log.error("Could not create ObjectName" + val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// If attributeName has not been recognized throw an AttributeNotFoundException
|
|
||||||
throw(new AttributeNotFoundException("Cannot find " + attributeName +
|
|
||||||
" attribute in " + dClassName));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public
|
|
||||||
void addAppenderEvent(Category logger, Appender appender) {
|
|
||||||
log.debug("addAppenderEvent called: logger="+logger.getName()+
|
|
||||||
", appender="+appender.getName());
|
|
||||||
Notification n = new Notification(ADD_APPENDER+logger.getName(), this, 0);
|
|
||||||
n.setUserData(appender);
|
|
||||||
log.debug("sending notification.");
|
|
||||||
nbs.sendNotification(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void removeAppenderEvent(Category cat, Appender appender) {
|
|
||||||
log.debug("removeAppenderCalled: logger="+cat.getName()+
|
|
||||||
", appender="+appender.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void postRegister(java.lang.Boolean registrationDone) {
|
|
||||||
log.debug("postRegister is called.");
|
|
||||||
hierarchy.addHierarchyEventListener(this);
|
|
||||||
Logger root = hierarchy.getRootLogger();
|
|
||||||
addLoggerMBean(root);
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void removeNotificationListener(NotificationListener listener)
|
|
||||||
throws ListenerNotFoundException {
|
|
||||||
nbs.removeNotificationListener(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void setAttribute(Attribute attribute) throws AttributeNotFoundException,
|
|
||||||
InvalidAttributeValueException,
|
|
||||||
MBeanException,
|
|
||||||
ReflectionException {
|
|
||||||
|
|
||||||
// Check attribute is not null to avoid NullPointerException later on
|
|
||||||
if (attribute == null) {
|
|
||||||
throw new RuntimeOperationsException(
|
|
||||||
new IllegalArgumentException("Attribute cannot be null"),
|
|
||||||
"Cannot invoke a setter of "+dClassName+" with null attribute");
|
|
||||||
}
|
|
||||||
String name = attribute.getName();
|
|
||||||
Object value = attribute.getValue();
|
|
||||||
|
|
||||||
if (name == null) {
|
|
||||||
throw new RuntimeOperationsException(
|
|
||||||
new IllegalArgumentException("Attribute name cannot be null"),
|
|
||||||
"Cannot invoke the setter of "+dClassName+
|
|
||||||
" with null attribute name");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(name.equals(THRESHOLD)) {
|
|
||||||
Level l = OptionConverter.toLevel((String) value,
|
|
||||||
hierarchy.getThreshold());
|
|
||||||
hierarchy.setThreshold(l);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,274 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.jmx;
|
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
import org.apache.log4j.Level;
|
|
||||||
import org.apache.log4j.Layout;
|
|
||||||
import org.apache.log4j.helpers.OptionConverter;
|
|
||||||
import org.apache.log4j.spi.OptionHandler;
|
|
||||||
|
|
||||||
import java.util.Vector;
|
|
||||||
import java.util.Hashtable;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import javax.management.MBeanAttributeInfo;
|
|
||||||
import javax.management.MBeanConstructorInfo;
|
|
||||||
import javax.management.MBeanNotificationInfo;
|
|
||||||
import javax.management.MBeanInfo;
|
|
||||||
import javax.management.Attribute;
|
|
||||||
|
|
||||||
import javax.management.MBeanException;
|
|
||||||
import javax.management.AttributeNotFoundException;
|
|
||||||
import javax.management.RuntimeOperationsException;
|
|
||||||
import javax.management.ReflectionException;
|
|
||||||
import javax.management.InvalidAttributeValueException;
|
|
||||||
import javax.management.MBeanOperationInfo;
|
|
||||||
import javax.management.MBeanParameterInfo;
|
|
||||||
|
|
||||||
import java.beans.Introspector;
|
|
||||||
import java.beans.BeanInfo;
|
|
||||||
import java.beans.PropertyDescriptor;
|
|
||||||
import java.beans.IntrospectionException;
|
|
||||||
import java.io.InterruptedIOException;
|
|
||||||
|
|
||||||
public class LayoutDynamicMBean extends AbstractDynamicMBean {
|
|
||||||
|
|
||||||
private MBeanConstructorInfo[] dConstructors = new MBeanConstructorInfo[1];
|
|
||||||
private Vector dAttributes = new Vector();
|
|
||||||
private String dClassName = this.getClass().getName();
|
|
||||||
|
|
||||||
private Hashtable dynamicProps = new Hashtable(5);
|
|
||||||
private MBeanOperationInfo[] dOperations = new MBeanOperationInfo[1];
|
|
||||||
private String dDescription =
|
|
||||||
"This MBean acts as a management facade for log4j layouts.";
|
|
||||||
|
|
||||||
// This category instance is for logging.
|
|
||||||
private static Logger cat = Logger.getLogger(LayoutDynamicMBean.class);
|
|
||||||
|
|
||||||
// We wrap this layout instance.
|
|
||||||
private Layout layout;
|
|
||||||
|
|
||||||
public LayoutDynamicMBean(Layout layout) throws IntrospectionException {
|
|
||||||
this.layout = layout;
|
|
||||||
buildDynamicMBeanInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
private
|
|
||||||
void buildDynamicMBeanInfo() throws IntrospectionException {
|
|
||||||
Constructor[] constructors = this.getClass().getConstructors();
|
|
||||||
dConstructors[0] = new MBeanConstructorInfo(
|
|
||||||
"LayoutDynamicMBean(): Constructs a LayoutDynamicMBean instance",
|
|
||||||
constructors[0]);
|
|
||||||
|
|
||||||
|
|
||||||
BeanInfo bi = Introspector.getBeanInfo(layout.getClass());
|
|
||||||
PropertyDescriptor[] pd = bi.getPropertyDescriptors();
|
|
||||||
|
|
||||||
int size = pd.length;
|
|
||||||
|
|
||||||
for(int i = 0; i < size; i++) {
|
|
||||||
String name = pd[i].getName();
|
|
||||||
Method readMethod = pd[i].getReadMethod();
|
|
||||||
Method writeMethod = pd[i].getWriteMethod();
|
|
||||||
if(readMethod != null) {
|
|
||||||
Class returnClass = readMethod.getReturnType();
|
|
||||||
if(isSupportedType(returnClass)) {
|
|
||||||
String returnClassName;
|
|
||||||
if(returnClass.isAssignableFrom(Level.class)) {
|
|
||||||
returnClassName = "java.lang.String";
|
|
||||||
} else {
|
|
||||||
returnClassName = returnClass.getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
dAttributes.add(new MBeanAttributeInfo(name,
|
|
||||||
returnClassName,
|
|
||||||
"Dynamic",
|
|
||||||
true,
|
|
||||||
writeMethod != null,
|
|
||||||
false));
|
|
||||||
dynamicProps.put(name, new MethodUnion(readMethod, writeMethod));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MBeanParameterInfo[] params = new MBeanParameterInfo[0];
|
|
||||||
|
|
||||||
dOperations[0] = new MBeanOperationInfo("activateOptions",
|
|
||||||
"activateOptions(): add an layout",
|
|
||||||
params,
|
|
||||||
"void",
|
|
||||||
MBeanOperationInfo.ACTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
private
|
|
||||||
boolean isSupportedType(Class clazz) {
|
|
||||||
if(clazz.isPrimitive()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(clazz == String.class) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if(clazz.isAssignableFrom(Level.class)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public
|
|
||||||
MBeanInfo getMBeanInfo() {
|
|
||||||
cat.debug("getMBeanInfo called.");
|
|
||||||
|
|
||||||
MBeanAttributeInfo[] attribs = new MBeanAttributeInfo[dAttributes.size()];
|
|
||||||
dAttributes.toArray(attribs);
|
|
||||||
|
|
||||||
return new MBeanInfo(dClassName,
|
|
||||||
dDescription,
|
|
||||||
attribs,
|
|
||||||
dConstructors,
|
|
||||||
dOperations,
|
|
||||||
new MBeanNotificationInfo[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
Object invoke(String operationName, Object params[], String signature[])
|
|
||||||
throws MBeanException,
|
|
||||||
ReflectionException {
|
|
||||||
|
|
||||||
if(operationName.equals("activateOptions") &&
|
|
||||||
layout instanceof OptionHandler) {
|
|
||||||
OptionHandler oh = (OptionHandler) layout;
|
|
||||||
oh.activateOptions();
|
|
||||||
return "Options activated.";
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected
|
|
||||||
Logger getLogger() {
|
|
||||||
return cat;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public
|
|
||||||
Object getAttribute(String attributeName) throws AttributeNotFoundException,
|
|
||||||
MBeanException,
|
|
||||||
ReflectionException {
|
|
||||||
|
|
||||||
// Check attributeName is not null to avoid NullPointerException later on
|
|
||||||
if (attributeName == null) {
|
|
||||||
throw new RuntimeOperationsException(new IllegalArgumentException(
|
|
||||||
"Attribute name cannot be null"),
|
|
||||||
"Cannot invoke a getter of " + dClassName + " with null attribute name");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
MethodUnion mu = (MethodUnion) dynamicProps.get(attributeName);
|
|
||||||
|
|
||||||
cat.debug("----name="+attributeName+", mu="+mu);
|
|
||||||
|
|
||||||
if(mu != null && mu.readMethod != null) {
|
|
||||||
try {
|
|
||||||
return mu.readMethod.invoke(layout, null);
|
|
||||||
} catch(InvocationTargetException e) {
|
|
||||||
if (e.getTargetException() instanceof InterruptedException
|
|
||||||
|| e.getTargetException() instanceof InterruptedIOException) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
} catch(IllegalAccessException e) {
|
|
||||||
return null;
|
|
||||||
} catch(RuntimeException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// If attributeName has not been recognized throw an AttributeNotFoundException
|
|
||||||
throw(new AttributeNotFoundException("Cannot find " + attributeName +
|
|
||||||
" attribute in " + dClassName));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public
|
|
||||||
void setAttribute(Attribute attribute) throws AttributeNotFoundException,
|
|
||||||
InvalidAttributeValueException,
|
|
||||||
MBeanException,
|
|
||||||
ReflectionException {
|
|
||||||
|
|
||||||
// Check attribute is not null to avoid NullPointerException later on
|
|
||||||
if (attribute == null) {
|
|
||||||
throw new RuntimeOperationsException(
|
|
||||||
new IllegalArgumentException("Attribute cannot be null"),
|
|
||||||
"Cannot invoke a setter of " + dClassName +
|
|
||||||
" with null attribute");
|
|
||||||
}
|
|
||||||
String name = attribute.getName();
|
|
||||||
Object value = attribute.getValue();
|
|
||||||
|
|
||||||
if (name == null) {
|
|
||||||
throw new RuntimeOperationsException(
|
|
||||||
new IllegalArgumentException("Attribute name cannot be null"),
|
|
||||||
"Cannot invoke the setter of "+dClassName+
|
|
||||||
" with null attribute name");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
MethodUnion mu = (MethodUnion) dynamicProps.get(name);
|
|
||||||
|
|
||||||
if(mu != null && mu.writeMethod != null) {
|
|
||||||
Object[] o = new Object[1];
|
|
||||||
|
|
||||||
Class[] params = mu.writeMethod.getParameterTypes();
|
|
||||||
if(params[0] == org.apache.log4j.Priority.class) {
|
|
||||||
value = OptionConverter.toLevel((String) value,
|
|
||||||
(Level) getAttribute(name));
|
|
||||||
}
|
|
||||||
o[0] = value;
|
|
||||||
|
|
||||||
try {
|
|
||||||
mu.writeMethod.invoke(layout, o);
|
|
||||||
|
|
||||||
} catch(InvocationTargetException e) {
|
|
||||||
if (e.getTargetException() instanceof InterruptedException
|
|
||||||
|| e.getTargetException() instanceof InterruptedIOException) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
cat.error("FIXME", e);
|
|
||||||
} catch(IllegalAccessException e) {
|
|
||||||
cat.error("FIXME", e);
|
|
||||||
} catch(RuntimeException e) {
|
|
||||||
cat.error("FIXME", e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw(new AttributeNotFoundException("Attribute " + name +
|
|
||||||
" not found in " +
|
|
||||||
this.getClass().getName()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,282 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.jmx;
|
|
||||||
|
|
||||||
import org.apache.log4j.Appender;
|
|
||||||
import org.apache.log4j.Level;
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
import org.apache.log4j.helpers.OptionConverter;
|
|
||||||
|
|
||||||
import javax.management.Attribute;
|
|
||||||
import javax.management.AttributeNotFoundException;
|
|
||||||
import javax.management.InvalidAttributeValueException;
|
|
||||||
import javax.management.JMException;
|
|
||||||
import javax.management.MBeanAttributeInfo;
|
|
||||||
import javax.management.MBeanConstructorInfo;
|
|
||||||
import javax.management.MBeanException;
|
|
||||||
import javax.management.MBeanInfo;
|
|
||||||
import javax.management.MBeanNotificationInfo;
|
|
||||||
import javax.management.MBeanOperationInfo;
|
|
||||||
import javax.management.MBeanParameterInfo;
|
|
||||||
import javax.management.MalformedObjectNameException;
|
|
||||||
import javax.management.Notification;
|
|
||||||
import javax.management.NotificationListener;
|
|
||||||
import javax.management.ObjectName;
|
|
||||||
import javax.management.ReflectionException;
|
|
||||||
import javax.management.RuntimeOperationsException;
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
public class LoggerDynamicMBean extends AbstractDynamicMBean
|
|
||||||
implements NotificationListener {
|
|
||||||
|
|
||||||
private MBeanConstructorInfo[] dConstructors = new MBeanConstructorInfo[1];
|
|
||||||
private MBeanOperationInfo[] dOperations = new MBeanOperationInfo[1];
|
|
||||||
|
|
||||||
private Vector dAttributes = new Vector();
|
|
||||||
private String dClassName = this.getClass().getName();
|
|
||||||
|
|
||||||
private String dDescription =
|
|
||||||
"This MBean acts as a management facade for a org.apache.log4j.Logger instance.";
|
|
||||||
|
|
||||||
// This Logger instance is for logging.
|
|
||||||
private static Logger cat = Logger.getLogger(LoggerDynamicMBean.class);
|
|
||||||
|
|
||||||
// We wrap this Logger instance.
|
|
||||||
private Logger logger;
|
|
||||||
|
|
||||||
public LoggerDynamicMBean(Logger logger) {
|
|
||||||
this.logger = logger;
|
|
||||||
buildDynamicMBeanInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void handleNotification(Notification notification, Object handback) {
|
|
||||||
cat.debug("Received notification: "+notification.getType());
|
|
||||||
registerAppenderMBean((Appender) notification.getUserData() );
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private
|
|
||||||
void buildDynamicMBeanInfo() {
|
|
||||||
Constructor[] constructors = this.getClass().getConstructors();
|
|
||||||
dConstructors[0] = new MBeanConstructorInfo(
|
|
||||||
"HierarchyDynamicMBean(): Constructs a HierarchyDynamicMBean instance",
|
|
||||||
constructors[0]);
|
|
||||||
|
|
||||||
dAttributes.add(new MBeanAttributeInfo("name",
|
|
||||||
"java.lang.String",
|
|
||||||
"The name of this Logger.",
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
false));
|
|
||||||
|
|
||||||
dAttributes.add(new MBeanAttributeInfo("priority",
|
|
||||||
"java.lang.String",
|
|
||||||
"The priority of this logger.",
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
false));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
MBeanParameterInfo[] params = new MBeanParameterInfo[2];
|
|
||||||
params[0] = new MBeanParameterInfo("class name", "java.lang.String",
|
|
||||||
"add an appender to this logger");
|
|
||||||
params[1] = new MBeanParameterInfo("appender name", "java.lang.String",
|
|
||||||
"name of the appender");
|
|
||||||
|
|
||||||
dOperations[0] = new MBeanOperationInfo("addAppender",
|
|
||||||
"addAppender(): add an appender",
|
|
||||||
params,
|
|
||||||
"void",
|
|
||||||
MBeanOperationInfo.ACTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected
|
|
||||||
Logger getLogger() {
|
|
||||||
return logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public
|
|
||||||
MBeanInfo getMBeanInfo() {
|
|
||||||
//cat.debug("getMBeanInfo called.");
|
|
||||||
|
|
||||||
MBeanAttributeInfo[] attribs = new MBeanAttributeInfo[dAttributes.size()];
|
|
||||||
dAttributes.toArray(attribs);
|
|
||||||
|
|
||||||
MBeanInfo mb = new MBeanInfo(dClassName,
|
|
||||||
dDescription,
|
|
||||||
attribs,
|
|
||||||
dConstructors,
|
|
||||||
dOperations,
|
|
||||||
new MBeanNotificationInfo[0]);
|
|
||||||
//cat.debug("getMBeanInfo exit.");
|
|
||||||
return mb;
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
Object invoke(String operationName, Object params[], String signature[])
|
|
||||||
throws MBeanException,
|
|
||||||
ReflectionException {
|
|
||||||
|
|
||||||
if(operationName.equals("addAppender")) {
|
|
||||||
addAppender((String) params[0], (String) params[1]);
|
|
||||||
return "Hello world.";
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public
|
|
||||||
Object getAttribute(String attributeName) throws AttributeNotFoundException,
|
|
||||||
MBeanException,
|
|
||||||
ReflectionException {
|
|
||||||
|
|
||||||
// Check attributeName is not null to avoid NullPointerException later on
|
|
||||||
if (attributeName == null) {
|
|
||||||
throw new RuntimeOperationsException(new IllegalArgumentException(
|
|
||||||
"Attribute name cannot be null"),
|
|
||||||
"Cannot invoke a getter of " + dClassName + " with null attribute name");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for a recognized attributeName and call the corresponding getter
|
|
||||||
if (attributeName.equals("name")) {
|
|
||||||
return logger.getName();
|
|
||||||
} else if(attributeName.equals("priority")) {
|
|
||||||
Level l = logger.getLevel();
|
|
||||||
if(l == null) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return l.toString();
|
|
||||||
}
|
|
||||||
} else if(attributeName.startsWith("appender=")) {
|
|
||||||
try {
|
|
||||||
return new ObjectName("log4j:"+attributeName );
|
|
||||||
} catch(MalformedObjectNameException e) {
|
|
||||||
cat.error("Could not create ObjectName" + attributeName);
|
|
||||||
} catch(RuntimeException e) {
|
|
||||||
cat.error("Could not create ObjectName" + attributeName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// If attributeName has not been recognized throw an AttributeNotFoundException
|
|
||||||
throw(new AttributeNotFoundException("Cannot find " + attributeName +
|
|
||||||
" attribute in " + dClassName));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void addAppender(String appenderClass, String appenderName) {
|
|
||||||
cat.debug("addAppender called with "+appenderClass+", "+appenderName);
|
|
||||||
Appender appender = (Appender)
|
|
||||||
OptionConverter.instantiateByClassName(appenderClass,
|
|
||||||
org.apache.log4j.Appender.class,
|
|
||||||
null);
|
|
||||||
appender.setName(appenderName);
|
|
||||||
logger.addAppender(appender);
|
|
||||||
|
|
||||||
//appenderMBeanRegistration();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public
|
|
||||||
void setAttribute(Attribute attribute) throws AttributeNotFoundException,
|
|
||||||
InvalidAttributeValueException,
|
|
||||||
MBeanException,
|
|
||||||
ReflectionException {
|
|
||||||
|
|
||||||
// Check attribute is not null to avoid NullPointerException later on
|
|
||||||
if (attribute == null) {
|
|
||||||
throw new RuntimeOperationsException(
|
|
||||||
new IllegalArgumentException("Attribute cannot be null"),
|
|
||||||
"Cannot invoke a setter of " + dClassName +
|
|
||||||
" with null attribute");
|
|
||||||
}
|
|
||||||
String name = attribute.getName();
|
|
||||||
Object value = attribute.getValue();
|
|
||||||
|
|
||||||
if (name == null) {
|
|
||||||
throw new RuntimeOperationsException(
|
|
||||||
new IllegalArgumentException("Attribute name cannot be null"),
|
|
||||||
"Cannot invoke the setter of "+dClassName+
|
|
||||||
" with null attribute name");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(name.equals("priority")) {
|
|
||||||
if (value instanceof String) {
|
|
||||||
String s = (String) value;
|
|
||||||
Level p = logger.getLevel();
|
|
||||||
if(s.equalsIgnoreCase("NULL")) {
|
|
||||||
p = null;
|
|
||||||
} else {
|
|
||||||
p = OptionConverter.toLevel(s, p);
|
|
||||||
}
|
|
||||||
logger.setLevel(p);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw(new AttributeNotFoundException("Attribute " + name +
|
|
||||||
" not found in " +
|
|
||||||
this.getClass().getName()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void appenderMBeanRegistration() {
|
|
||||||
Enumeration enumeration = logger.getAllAppenders();
|
|
||||||
while(enumeration.hasMoreElements()) {
|
|
||||||
Appender appender = (Appender) enumeration.nextElement();
|
|
||||||
registerAppenderMBean(appender);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void registerAppenderMBean(Appender appender) {
|
|
||||||
String name = getAppenderName(appender);
|
|
||||||
cat.debug("Adding AppenderMBean for appender named "+name);
|
|
||||||
ObjectName objectName = null;
|
|
||||||
try {
|
|
||||||
AppenderDynamicMBean appenderMBean = new AppenderDynamicMBean(appender);
|
|
||||||
objectName = new ObjectName("log4j", "appender", name);
|
|
||||||
if (!server.isRegistered(objectName)) {
|
|
||||||
registerMBean(appenderMBean, objectName);
|
|
||||||
dAttributes.add(new MBeanAttributeInfo("appender=" + name, "javax.management.ObjectName",
|
|
||||||
"The " + name + " appender.", true, true, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch(JMException e) {
|
|
||||||
cat.error("Could not add appenderMBean for ["+name+"].", e);
|
|
||||||
} catch(java.beans.IntrospectionException e) {
|
|
||||||
cat.error("Could not add appenderMBean for ["+name+"].", e);
|
|
||||||
} catch(RuntimeException e) {
|
|
||||||
cat.error("Could not add appenderMBean for ["+name+"].", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void postRegister(java.lang.Boolean registrationDone) {
|
|
||||||
appenderMBeanRegistration();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.jmx;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
class MethodUnion {
|
|
||||||
|
|
||||||
Method readMethod;
|
|
||||||
Method writeMethod;
|
|
||||||
|
|
||||||
MethodUnion( Method readMethod, Method writeMethod) {
|
|
||||||
this.readMethod = readMethod;
|
|
||||||
this.writeMethod = writeMethod;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<!--
|
|
||||||
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.
|
|
||||||
|
|
||||||
-->
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
This package lets you manage log4j settings using JMX. It is
|
|
||||||
unfortunately not of production quality.
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.lf5;
|
|
||||||
|
|
||||||
import org.apache.log4j.lf5.viewer.LogBrokerMonitor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <code>AppenderFinalizer</code> has a single method that will finalize
|
|
||||||
* resources associated with a <code>LogBrokerMonitor</code> in the event
|
|
||||||
* that the <code>LF5Appender</code> class is destroyed, and the class loader
|
|
||||||
* is garbage collected.
|
|
||||||
*
|
|
||||||
* @author Brent Sprecher
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Contributed by ThoughtWorks Inc.
|
|
||||||
|
|
||||||
public class AppenderFinalizer {
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constants:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
protected LogBrokerMonitor _defaultMonitor = null;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constructors:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
public AppenderFinalizer(LogBrokerMonitor defaultMonitor) {
|
|
||||||
_defaultMonitor = defaultMonitor;
|
|
||||||
}
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Public Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws java.lang.Throwable
|
|
||||||
*/
|
|
||||||
protected void finalize() throws Throwable {
|
|
||||||
System.out.println("Disposing of the default LogBrokerMonitor instance");
|
|
||||||
_defaultMonitor.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Nested Top-Level Classes or Interfaces:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.lf5;
|
|
||||||
|
|
||||||
import org.apache.log4j.PropertyConfigurator;
|
|
||||||
import org.apache.log4j.spi.Configurator;
|
|
||||||
import org.apache.log4j.spi.LoggerRepository;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The <code>DefaultLF5Configurator</code> provides a default
|
|
||||||
* configuration for the <code>LF5Appender</code>.
|
|
||||||
*
|
|
||||||
* Note: The preferred method for configuring a <code>LF5Appender</code>
|
|
||||||
* is to use the <code>LF5Manager</code> class. This class ensures
|
|
||||||
* that configuration does not occur multiple times, and improves system
|
|
||||||
* performance. Reconfiguring the monitor multiple times can result in
|
|
||||||
* unexpected behavior.
|
|
||||||
*
|
|
||||||
* @author Brent Sprecher
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Contributed by ThoughtWorks Inc.
|
|
||||||
|
|
||||||
public class DefaultLF5Configurator implements Configurator {
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constants:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constructors:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* This class should never be instantiated! It implements the <code>
|
|
||||||
* Configurator</code>
|
|
||||||
* interface, but does not provide the same functionality as full
|
|
||||||
* configurator class.
|
|
||||||
*/
|
|
||||||
private DefaultLF5Configurator() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Public Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* This method configures the <code>LF5Appender</code> using a
|
|
||||||
* default configuration file. The default configuration file is
|
|
||||||
* <bold>defaultconfig.properties</bold>.
|
|
||||||
* @throws java.io.IOException
|
|
||||||
*/
|
|
||||||
public static void configure() throws IOException {
|
|
||||||
String resource =
|
|
||||||
"/org/apache/log4j/lf5/config/defaultconfig.properties";
|
|
||||||
URL configFileResource =
|
|
||||||
DefaultLF5Configurator.class.getResource(resource);
|
|
||||||
|
|
||||||
if (configFileResource != null) {
|
|
||||||
PropertyConfigurator.configure(configFileResource);
|
|
||||||
} else {
|
|
||||||
throw new IOException("Error: Unable to open the resource" +
|
|
||||||
resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a dummy method that will throw an
|
|
||||||
* <code>IllegalStateException</code> if used.
|
|
||||||
*/
|
|
||||||
public void doConfigure(URL configURL, LoggerRepository repository) {
|
|
||||||
throw new IllegalStateException("This class should NOT be" +
|
|
||||||
" instantiated!");
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Nested Top-Level Classes or Interfaces:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,266 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.lf5;
|
|
||||||
|
|
||||||
import java.awt.Toolkit;
|
|
||||||
|
|
||||||
import org.apache.log4j.AppenderSkeleton;
|
|
||||||
import org.apache.log4j.lf5.viewer.LogBrokerMonitor;
|
|
||||||
import org.apache.log4j.spi.LocationInfo;
|
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <code>LF5Appender</code> logs events to a swing based logging
|
|
||||||
* console. The swing console supports turning categories on and off,
|
|
||||||
* multiple detail level views, as well as full text searching and many
|
|
||||||
* other capabilties.
|
|
||||||
*
|
|
||||||
* @author Brent Sprecher
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Contributed by ThoughtWorks Inc.
|
|
||||||
|
|
||||||
public class LF5Appender extends AppenderSkeleton {
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constants:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
protected LogBrokerMonitor _logMonitor;
|
|
||||||
protected static LogBrokerMonitor _defaultLogMonitor;
|
|
||||||
protected static AppenderFinalizer _finalizer;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constructors:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a <code>LF5Appender</code> using the default instance of
|
|
||||||
* the <code>LogBrokerMonitor</code>. This constructor should <bold>always
|
|
||||||
* </bold> be preferred over the
|
|
||||||
* <code>LF5Appender(LogBrokerMonitor monitor)</code>
|
|
||||||
* constructor, unless you need to spawn additional log monitoring
|
|
||||||
* windows.
|
|
||||||
*/
|
|
||||||
public LF5Appender() {
|
|
||||||
this(getDefaultInstance());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a <code>LF5Appender<code> using an instance of
|
|
||||||
* a <code>LogBrokerMonitor<code> supplied by the user. This
|
|
||||||
* constructor should only be used when you need to spawn
|
|
||||||
* additional log monitoring windows.
|
|
||||||
*
|
|
||||||
* @param monitor An instance of a <code>LogBrokerMonitor<code>
|
|
||||||
* created by the user.
|
|
||||||
*/
|
|
||||||
public LF5Appender(LogBrokerMonitor monitor) {
|
|
||||||
|
|
||||||
if (monitor != null) {
|
|
||||||
_logMonitor = monitor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Public Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Appends a <code>LoggingEvent</code> record to the
|
|
||||||
* <code>LF5Appender</code>.
|
|
||||||
* @param event The <code>LoggingEvent</code>
|
|
||||||
* to be appended.
|
|
||||||
*/
|
|
||||||
public void append(LoggingEvent event) {
|
|
||||||
// Retrieve the information from the log4j LoggingEvent.
|
|
||||||
String category = event.getLoggerName();
|
|
||||||
String logMessage = event.getRenderedMessage();
|
|
||||||
String nestedDiagnosticContext = event.getNDC();
|
|
||||||
String threadDescription = event.getThreadName();
|
|
||||||
String level = event.getLevel().toString();
|
|
||||||
long time = event.timeStamp;
|
|
||||||
LocationInfo locationInfo = event.getLocationInformation();
|
|
||||||
|
|
||||||
// Add the logging event information to a LogRecord
|
|
||||||
Log4JLogRecord record = new Log4JLogRecord();
|
|
||||||
|
|
||||||
record.setCategory(category);
|
|
||||||
record.setMessage(logMessage);
|
|
||||||
record.setLocation(locationInfo.fullInfo);
|
|
||||||
record.setMillis(time);
|
|
||||||
record.setThreadDescription(threadDescription);
|
|
||||||
|
|
||||||
if (nestedDiagnosticContext != null) {
|
|
||||||
record.setNDC(nestedDiagnosticContext);
|
|
||||||
} else {
|
|
||||||
record.setNDC("");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.getThrowableInformation() != null) {
|
|
||||||
record.setThrownStackTrace(event.getThrowableInformation());
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
record.setLevel(LogLevel.valueOf(level));
|
|
||||||
} catch (LogLevelFormatException e) {
|
|
||||||
// If the priority level doesn't match one of the predefined
|
|
||||||
// log levels, then set the level to warning.
|
|
||||||
record.setLevel(LogLevel.WARN);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_logMonitor != null) {
|
|
||||||
_logMonitor.addMessage(record);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is an empty implementation of the close() method inherited
|
|
||||||
* from the <code>org.apache.log4j.Appender</code> interface.
|
|
||||||
*/
|
|
||||||
public void close() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a value that indicates whether this appender requires a
|
|
||||||
* <code>Layout</code>. This method always returns false.
|
|
||||||
* No layout is required for the <code>LF5Appender</code>.
|
|
||||||
*/
|
|
||||||
public boolean requiresLayout() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is used to set the property that controls whether
|
|
||||||
* the <code>LogBrokerMonitor</code> is hidden or closed when a user
|
|
||||||
* exits
|
|
||||||
* the monitor. By default, the <code>LogBrokerMonitor</code> will hide
|
|
||||||
* itself when the log window is exited, and the swing thread will
|
|
||||||
* continue to running in the background. If this property is
|
|
||||||
* set to true, the <code>LogBrokerMonitor</code> will call System.exit(0)
|
|
||||||
* and will shut down swing thread and the virtual machine.
|
|
||||||
*
|
|
||||||
* @param callSystemExitOnClose A boolean value indicating whether
|
|
||||||
* to call System.exit(0) when closing the log window.
|
|
||||||
*/
|
|
||||||
public void setCallSystemExitOnClose(boolean callSystemExitOnClose) {
|
|
||||||
_logMonitor.setCallSystemExitOnClose(callSystemExitOnClose);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The equals method compares two LF5Appenders and determines whether
|
|
||||||
* they are equal. Two <code>Appenders</code> will be considered equal
|
|
||||||
* if, and only if, they both contain references to the same <code>
|
|
||||||
* LogBrokerMonitor</code>.
|
|
||||||
*
|
|
||||||
* @param compareTo A boolean value indicating whether
|
|
||||||
* the two LF5Appenders are equal.
|
|
||||||
*/
|
|
||||||
public boolean equals(LF5Appender compareTo) {
|
|
||||||
// If both reference the same LogBrokerMonitor, they are equal.
|
|
||||||
return _logMonitor == compareTo.getLogBrokerMonitor();
|
|
||||||
}
|
|
||||||
|
|
||||||
public LogBrokerMonitor getLogBrokerMonitor() {
|
|
||||||
return _logMonitor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
new LF5Appender();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMaxNumberOfRecords(int maxNumberOfRecords) {
|
|
||||||
_defaultLogMonitor.setMaxNumberOfLogRecords(maxNumberOfRecords);
|
|
||||||
}
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The default instance of the <code>LogBrokerMonitor</code>.
|
|
||||||
*/
|
|
||||||
protected static synchronized LogBrokerMonitor getDefaultInstance() {
|
|
||||||
if (_defaultLogMonitor == null) {
|
|
||||||
try {
|
|
||||||
_defaultLogMonitor =
|
|
||||||
new LogBrokerMonitor(LogLevel.getLog4JLevels());
|
|
||||||
_finalizer = new AppenderFinalizer(_defaultLogMonitor);
|
|
||||||
|
|
||||||
_defaultLogMonitor.setFrameSize(getDefaultMonitorWidth(),
|
|
||||||
getDefaultMonitorHeight());
|
|
||||||
_defaultLogMonitor.setFontSize(12);
|
|
||||||
_defaultLogMonitor.show();
|
|
||||||
|
|
||||||
} catch (SecurityException e) {
|
|
||||||
_defaultLogMonitor = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return _defaultLogMonitor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the screen width from Toolkit.getScreenSize()
|
|
||||||
* if possible, otherwise returns 800
|
|
||||||
* @see java.awt.Toolkit
|
|
||||||
*/
|
|
||||||
protected static int getScreenWidth() {
|
|
||||||
try {
|
|
||||||
return Toolkit.getDefaultToolkit().getScreenSize().width;
|
|
||||||
} catch (Throwable t) {
|
|
||||||
return 800;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the screen height from Toolkit.getScreenSize()
|
|
||||||
* if possible, otherwise returns 600
|
|
||||||
* @see java.awt.Toolkit
|
|
||||||
*/
|
|
||||||
protected static int getScreenHeight() {
|
|
||||||
try {
|
|
||||||
return Toolkit.getDefaultToolkit().getScreenSize().height;
|
|
||||||
} catch (Throwable t) {
|
|
||||||
return 600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static int getDefaultMonitorWidth() {
|
|
||||||
return (3 * getScreenWidth()) / 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static int getDefaultMonitorHeight() {
|
|
||||||
return (3 * getScreenHeight()) / 4;
|
|
||||||
}
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Nested Top-Level Classes or Interfaces:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.lf5;
|
|
||||||
|
|
||||||
import org.apache.log4j.spi.ThrowableInformation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A <code>Log4JLogRecord</code> encapsulates
|
|
||||||
* the details of your log4j <code>LoggingEvent</code> in a format usable
|
|
||||||
* by the <code>LogBrokerMonitor</code>.
|
|
||||||
*
|
|
||||||
* @author Brent Sprecher
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Contributed by ThoughtWorks Inc.
|
|
||||||
|
|
||||||
public class Log4JLogRecord extends LogRecord {
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constants:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constructors:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs an instance of a <code>Log4JLogRecord</code>.
|
|
||||||
*/
|
|
||||||
public Log4JLogRecord() {
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Public Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Determines which <code>Priority</code> levels will
|
|
||||||
* be displayed in colored font when the <code>LogMonitorAppender</code>
|
|
||||||
* renders this log message. By default, messages will be colored
|
|
||||||
* red if they are of <code>Priority</code> ERROR or FATAL.
|
|
||||||
*
|
|
||||||
* @return true if the log level is ERROR or FATAL.
|
|
||||||
*/
|
|
||||||
public boolean isSevereLevel() {
|
|
||||||
boolean isSevere = false;
|
|
||||||
|
|
||||||
if (LogLevel.ERROR.equals(getLevel()) ||
|
|
||||||
LogLevel.FATAL.equals(getLevel())) {
|
|
||||||
isSevere = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return isSevere;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set stack trace information associated with this Log4JLogRecord.
|
|
||||||
* When this method is called, the stack trace in a
|
|
||||||
* String-based format is made
|
|
||||||
* available via the getThrownStackTrace() method.
|
|
||||||
*
|
|
||||||
* @param throwableInfo An org.apache.log4j.spi.ThrowableInformation to
|
|
||||||
* associate with this Log4JLogRecord.
|
|
||||||
* @see #getThrownStackTrace()
|
|
||||||
*/
|
|
||||||
public void setThrownStackTrace(ThrowableInformation throwableInfo) {
|
|
||||||
String[] stackTraceArray = throwableInfo.getThrowableStrRep();
|
|
||||||
|
|
||||||
StringBuffer stackTrace = new StringBuffer();
|
|
||||||
String nextLine;
|
|
||||||
|
|
||||||
for (int i = 0; i < stackTraceArray.length; i++) {
|
|
||||||
nextLine = stackTraceArray[i] + "\n";
|
|
||||||
stackTrace.append(nextLine);
|
|
||||||
}
|
|
||||||
|
|
||||||
_thrownStackTrace = stackTrace.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Nested Top-Level Classes or Interfaces:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,278 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.lf5;
|
|
||||||
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The LogLevel class defines a set of standard logging levels.
|
|
||||||
*
|
|
||||||
* The logging Level objects are ordered and are specified by ordered
|
|
||||||
* integers. Enabling logging at a given level also enables logging at all
|
|
||||||
* higher levels.
|
|
||||||
*
|
|
||||||
* @author Michael J. Sikorsky
|
|
||||||
* @author Robert Shaw
|
|
||||||
* @author Brent Sprecher
|
|
||||||
* @author Richard Hurst
|
|
||||||
* @author Brad Marlborough
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Contributed by ThoughtWorks Inc.
|
|
||||||
|
|
||||||
public class LogLevel implements java.io.Serializable {
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constants:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// log4j log levels.
|
|
||||||
public final static LogLevel FATAL = new LogLevel("FATAL", 0);
|
|
||||||
public final static LogLevel ERROR = new LogLevel("ERROR", 1);
|
|
||||||
public final static LogLevel WARN = new LogLevel("WARN", 2);
|
|
||||||
public final static LogLevel INFO = new LogLevel("INFO", 3);
|
|
||||||
public final static LogLevel DEBUG = new LogLevel("DEBUG", 4);
|
|
||||||
|
|
||||||
// jdk1.4 log levels NOTE: also includes INFO
|
|
||||||
public final static LogLevel SEVERE = new LogLevel("SEVERE", 1);
|
|
||||||
public final static LogLevel WARNING = new LogLevel("WARNING", 2);
|
|
||||||
public final static LogLevel CONFIG = new LogLevel("CONFIG", 4);
|
|
||||||
public final static LogLevel FINE = new LogLevel("FINE", 5);
|
|
||||||
public final static LogLevel FINER = new LogLevel("FINER", 6);
|
|
||||||
public final static LogLevel FINEST = new LogLevel("FINEST", 7);
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
protected String _label;
|
|
||||||
protected int _precedence;
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
private static LogLevel[] _log4JLevels;
|
|
||||||
private static LogLevel[] _jdk14Levels;
|
|
||||||
private static LogLevel[] _allDefaultLevels;
|
|
||||||
private static Map _logLevelMap;
|
|
||||||
private static Map _logLevelColorMap;
|
|
||||||
private static Map _registeredLogLevelMap = new HashMap();
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constructors:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
static {
|
|
||||||
_log4JLevels = new LogLevel[]{FATAL, ERROR, WARN, INFO, DEBUG};
|
|
||||||
_jdk14Levels = new LogLevel[]{SEVERE, WARNING, INFO,
|
|
||||||
CONFIG, FINE, FINER, FINEST};
|
|
||||||
_allDefaultLevels = new LogLevel[]{FATAL, ERROR, WARN, INFO, DEBUG,
|
|
||||||
SEVERE, WARNING, CONFIG, FINE, FINER, FINEST};
|
|
||||||
|
|
||||||
_logLevelMap = new HashMap();
|
|
||||||
for (int i = 0; i < _allDefaultLevels.length; i++) {
|
|
||||||
_logLevelMap.put(_allDefaultLevels[i].getLabel(), _allDefaultLevels[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepopulate map with levels and text color of black
|
|
||||||
_logLevelColorMap = new HashMap();
|
|
||||||
for (int i = 0; i < _allDefaultLevels.length; i++) {
|
|
||||||
_logLevelColorMap.put(_allDefaultLevels[i], Color.black);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public LogLevel(String label, int precedence) {
|
|
||||||
_label = label;
|
|
||||||
_precedence = precedence;
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Public Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the Label of the LogLevel.
|
|
||||||
*/
|
|
||||||
public String getLabel() {
|
|
||||||
return _label;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the level supplied is encompassed by this level.
|
|
||||||
* For example, LogLevel.SEVERE encompasses no other LogLevels and
|
|
||||||
* LogLevel.FINE encompasses all other LogLevels. By definition,
|
|
||||||
* a LogLevel encompasses itself.
|
|
||||||
*/
|
|
||||||
public boolean encompasses(LogLevel level) {
|
|
||||||
if (level.getPrecedence() <= getPrecedence()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a log level label into a LogLevel object.
|
|
||||||
*
|
|
||||||
* @param level The label of a level to be converted into a LogLevel.
|
|
||||||
* @return LogLevel The LogLevel with a label equal to level.
|
|
||||||
* @throws LogLevelFormatException Is thrown when the level can not be
|
|
||||||
* converted into a LogLevel.
|
|
||||||
*/
|
|
||||||
public static LogLevel valueOf(String level)
|
|
||||||
throws LogLevelFormatException {
|
|
||||||
LogLevel logLevel = null;
|
|
||||||
if (level != null) {
|
|
||||||
level = level.trim().toUpperCase();
|
|
||||||
logLevel = (LogLevel) _logLevelMap.get(level);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Didn't match, Check for registered LogLevels
|
|
||||||
if (logLevel == null && _registeredLogLevelMap.size() > 0) {
|
|
||||||
logLevel = (LogLevel) _registeredLogLevelMap.get(level);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (logLevel == null) {
|
|
||||||
StringBuffer buf = new StringBuffer();
|
|
||||||
buf.append("Error while trying to parse (" + level + ") into");
|
|
||||||
buf.append(" a LogLevel.");
|
|
||||||
throw new LogLevelFormatException(buf.toString());
|
|
||||||
}
|
|
||||||
return logLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers a used defined LogLevel.
|
|
||||||
*
|
|
||||||
* @param logLevel The log level to be registered. Cannot be a default LogLevel
|
|
||||||
* @return LogLevel The replaced log level.
|
|
||||||
*/
|
|
||||||
public static LogLevel register(LogLevel logLevel) {
|
|
||||||
if (logLevel == null) return null;
|
|
||||||
|
|
||||||
// ensure that this is not a default log level
|
|
||||||
if (_logLevelMap.get(logLevel.getLabel()) == null) {
|
|
||||||
return (LogLevel) _registeredLogLevelMap.put(logLevel.getLabel(), logLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void register(LogLevel[] logLevels) {
|
|
||||||
if (logLevels != null) {
|
|
||||||
for (int i = 0; i < logLevels.length; i++) {
|
|
||||||
register(logLevels[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void register(List logLevels) {
|
|
||||||
if (logLevels != null) {
|
|
||||||
Iterator it = logLevels.iterator();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
register((LogLevel) it.next());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
boolean equals = false;
|
|
||||||
|
|
||||||
if (o instanceof LogLevel) {
|
|
||||||
if (this.getPrecedence() ==
|
|
||||||
((LogLevel) o).getPrecedence()) {
|
|
||||||
equals = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return equals;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode() {
|
|
||||||
return _label.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
return _label;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set a text color for a specific log level
|
|
||||||
public void setLogLevelColorMap(LogLevel level, Color color) {
|
|
||||||
// remove the old entry
|
|
||||||
_logLevelColorMap.remove(level);
|
|
||||||
// add the new color entry
|
|
||||||
if (color == null) {
|
|
||||||
color = Color.black;
|
|
||||||
}
|
|
||||||
_logLevelColorMap.put(level, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void resetLogLevelColorMap() {
|
|
||||||
// empty the map
|
|
||||||
_logLevelColorMap.clear();
|
|
||||||
|
|
||||||
// repopulate map and reset text color black
|
|
||||||
for (int i = 0; i < _allDefaultLevels.length; i++) {
|
|
||||||
_logLevelColorMap.put(_allDefaultLevels[i], Color.black);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return A <code>List</code> of <code>LogLevel</code> objects that map
|
|
||||||
* to log4j <code>Priority</code> objects.
|
|
||||||
*/
|
|
||||||
public static List getLog4JLevels() {
|
|
||||||
return Arrays.asList(_log4JLevels);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List getJdk14Levels() {
|
|
||||||
return Arrays.asList(_jdk14Levels);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List getAllDefaultLevels() {
|
|
||||||
return Arrays.asList(_allDefaultLevels);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Map getLogLevelColorMap() {
|
|
||||||
return _logLevelColorMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
protected int getPrecedence() {
|
|
||||||
return _precedence;
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Nested Top-Level Classes or Interfaces:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.lf5;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Thrown to indicate that the client has attempted to convert a string
|
|
||||||
* to one the LogLevel types, but the string does not have the appropriate
|
|
||||||
* format.
|
|
||||||
*
|
|
||||||
* @author Michael J. Sikorsky<
|
|
||||||
* @author Robert Shaw
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Contributed by ThoughtWorks Inc.
|
|
||||||
|
|
||||||
public class LogLevelFormatException extends Exception {
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constants:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constructors:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
public LogLevelFormatException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Public Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Nested Top-Level Classes or Interfaces:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,395 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.lf5;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LogRecord. A LogRecord encapsulates the details of your desired log
|
|
||||||
* request.
|
|
||||||
*
|
|
||||||
* @author Michael J. Sikorsky
|
|
||||||
* @author Robert Shaw
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Contributed by ThoughtWorks Inc.
|
|
||||||
|
|
||||||
public abstract class LogRecord implements java.io.Serializable {
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constants:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
protected static long _seqCount = 0;
|
|
||||||
|
|
||||||
protected LogLevel _level;
|
|
||||||
protected String _message;
|
|
||||||
protected long _sequenceNumber;
|
|
||||||
protected long _millis;
|
|
||||||
protected String _category;
|
|
||||||
protected String _thread;
|
|
||||||
protected String _thrownStackTrace;
|
|
||||||
protected Throwable _thrown;
|
|
||||||
protected String _ndc;
|
|
||||||
protected String _location;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constructors:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
public LogRecord() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
_millis = System.currentTimeMillis();
|
|
||||||
_category = "Debug";
|
|
||||||
_message = "";
|
|
||||||
_level = LogLevel.INFO;
|
|
||||||
_sequenceNumber = getNextId();
|
|
||||||
_thread = Thread.currentThread().toString();
|
|
||||||
_ndc = "";
|
|
||||||
_location = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Public Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the level of this LogRecord.
|
|
||||||
*
|
|
||||||
* @return The LogLevel of this record.
|
|
||||||
* @see #setLevel(LogLevel)
|
|
||||||
* @see LogLevel
|
|
||||||
*/
|
|
||||||
public LogLevel getLevel() {
|
|
||||||
return (_level);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the level of this LogRecord.
|
|
||||||
*
|
|
||||||
* @param level The LogLevel for this record.
|
|
||||||
* @see #getLevel()
|
|
||||||
* @see LogLevel
|
|
||||||
*/
|
|
||||||
public void setLevel(LogLevel level) {
|
|
||||||
_level = level;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract method. Must be overridden to indicate what log level
|
|
||||||
* to show in red.
|
|
||||||
*/
|
|
||||||
public abstract boolean isSevereLevel();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if getThrown().toString() is a non-empty string.
|
|
||||||
*/
|
|
||||||
public boolean hasThrown() {
|
|
||||||
Throwable thrown = getThrown();
|
|
||||||
if (thrown == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
String thrownString = thrown.toString();
|
|
||||||
return thrownString != null && thrownString.trim().length() != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if isSevereLevel() or hasThrown() returns true.
|
|
||||||
*/
|
|
||||||
public boolean isFatal() {
|
|
||||||
return isSevereLevel() || hasThrown();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the category asscociated with this LogRecord. For a more detailed
|
|
||||||
* description of what a category is see setCategory().
|
|
||||||
*
|
|
||||||
* @return The category of this record.
|
|
||||||
* @see #setCategory(String)
|
|
||||||
*/
|
|
||||||
public String getCategory() {
|
|
||||||
return (_category);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the category associated with this LogRecord. A category represents
|
|
||||||
* a hierarchical dot (".") separated namespace for messages.
|
|
||||||
* The definition of a category is application specific, but a common convention
|
|
||||||
* is as follows:
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* When logging messages
|
|
||||||
* for a particluar class you can use its class name:
|
|
||||||
* com.thoughtworks.framework.servlet.ServletServiceBroker.<br><br>
|
|
||||||
* Futhermore, to log a message for a particular method in a class
|
|
||||||
* add the method name:
|
|
||||||
* com.thoughtworks.framework.servlet.ServletServiceBroker.init().
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param category The category for this record.
|
|
||||||
* @see #getCategory()
|
|
||||||
*/
|
|
||||||
public void setCategory(String category) {
|
|
||||||
_category = category;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the message asscociated with this LogRecord.
|
|
||||||
*
|
|
||||||
* @return The message of this record.
|
|
||||||
* @see #setMessage(String)
|
|
||||||
*/
|
|
||||||
public String getMessage() {
|
|
||||||
return (_message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the message associated with this LogRecord.
|
|
||||||
*
|
|
||||||
* @param message The message for this record.
|
|
||||||
* @see #getMessage()
|
|
||||||
*/
|
|
||||||
public void setMessage(String message) {
|
|
||||||
_message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the sequence number associated with this LogRecord. Sequence numbers
|
|
||||||
* are generally assigned when a LogRecord is constructed. Sequence numbers
|
|
||||||
* start at 0 and increase with each newly constructed LogRocord.
|
|
||||||
*
|
|
||||||
* @return The sequence number of this record.
|
|
||||||
* @see #setSequenceNumber(long)
|
|
||||||
*/
|
|
||||||
public long getSequenceNumber() {
|
|
||||||
return (_sequenceNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the sequence number assocsiated with this LogRecord. A sequence number
|
|
||||||
* will automatically be assigned to evey newly constructed LogRecord, however,
|
|
||||||
* this method can override the value.
|
|
||||||
*
|
|
||||||
* @param number The sequence number.
|
|
||||||
* @see #getSequenceNumber()
|
|
||||||
*/
|
|
||||||
public void setSequenceNumber(long number) {
|
|
||||||
_sequenceNumber = number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the event time of this record in milliseconds from 1970.
|
|
||||||
* When a LogRecord is constructed the event time is set but may be
|
|
||||||
* overridden by calling setMillis();
|
|
||||||
*
|
|
||||||
* @return The event time of this record in milliseconds from 1970.
|
|
||||||
* @see #setMillis(long)
|
|
||||||
*/
|
|
||||||
public long getMillis() {
|
|
||||||
return _millis;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the event time of this record. When a LogRecord is constructed
|
|
||||||
* the event time is set but may be overridden by calling this method.
|
|
||||||
*
|
|
||||||
* @param millis The time in milliseconds from 1970.
|
|
||||||
* @see #getMillis()
|
|
||||||
*/
|
|
||||||
public void setMillis(long millis) {
|
|
||||||
_millis = millis;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the thread description asscociated with this LogRecord. When a
|
|
||||||
* LogRecord is constructed, the thread description is set by calling:
|
|
||||||
* Thread.currentThread().toString(). You may supply a thread description
|
|
||||||
* of your own by calling the setThreadDescription(String) method.
|
|
||||||
*
|
|
||||||
* @return The thread description of this record.
|
|
||||||
* @see #setThreadDescription(String)
|
|
||||||
*/
|
|
||||||
public String getThreadDescription() {
|
|
||||||
return (_thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the thread description associated with this LogRecord. When a
|
|
||||||
* LogRecord is constructed, the thread description is set by calling:
|
|
||||||
* Thread.currentThread().toString(). You may supply a thread description
|
|
||||||
* of your own by calling this method.
|
|
||||||
*
|
|
||||||
* @param threadDescription The description of the thread for this record.
|
|
||||||
* @see #getThreadDescription()
|
|
||||||
*/
|
|
||||||
public void setThreadDescription(String threadDescription) {
|
|
||||||
_thread = threadDescription;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the stack trace in a String-based format for the associated Throwable
|
|
||||||
* of this LogRecord. The stack trace in a String-based format is set
|
|
||||||
* when the setThrown(Throwable) method is called.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* Why do we need this method considering that we
|
|
||||||
* have the getThrown() and setThrown() methods?
|
|
||||||
* A Throwable object may not be serializable, however, a String representation
|
|
||||||
* of it is. Users of LogRecords should generally call this method over
|
|
||||||
* getThrown() for the reasons of serialization.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return The Stack Trace for the asscoiated Throwable of this LogRecord.
|
|
||||||
* @see #setThrown(Throwable)
|
|
||||||
* @see #getThrown()
|
|
||||||
*/
|
|
||||||
public String getThrownStackTrace() {
|
|
||||||
return (_thrownStackTrace);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the ThrownStackTrace for the log record.
|
|
||||||
*
|
|
||||||
* @param trace A String to associate with this LogRecord
|
|
||||||
* @see #getThrownStackTrace()
|
|
||||||
*/
|
|
||||||
public void setThrownStackTrace(String trace) {
|
|
||||||
_thrownStackTrace = trace;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the Throwable associated with this LogRecord.
|
|
||||||
*
|
|
||||||
* @return The LogLevel of this record.
|
|
||||||
* @see #setThrown(Throwable)
|
|
||||||
* @see #getThrownStackTrace()
|
|
||||||
*/
|
|
||||||
public Throwable getThrown() {
|
|
||||||
return (_thrown);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the Throwable associated with this LogRecord. When this method
|
|
||||||
* is called, the stack trace in a String-based format is made
|
|
||||||
* available via the getThrownStackTrace() method.
|
|
||||||
*
|
|
||||||
* @param thrown A Throwable to associate with this LogRecord.
|
|
||||||
* @see #getThrown()
|
|
||||||
* @see #getThrownStackTrace()
|
|
||||||
*/
|
|
||||||
public void setThrown(Throwable thrown) {
|
|
||||||
if (thrown == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_thrown = thrown;
|
|
||||||
StringWriter sw = new StringWriter();
|
|
||||||
PrintWriter out = new PrintWriter(sw);
|
|
||||||
thrown.printStackTrace(out);
|
|
||||||
out.flush();
|
|
||||||
_thrownStackTrace = sw.toString();
|
|
||||||
try {
|
|
||||||
out.close();
|
|
||||||
sw.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// Do nothing, this should not happen as it is StringWriter.
|
|
||||||
}
|
|
||||||
out = null;
|
|
||||||
sw = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a String representation of this LogRecord.
|
|
||||||
*/
|
|
||||||
public String toString() {
|
|
||||||
StringBuffer buf = new StringBuffer();
|
|
||||||
buf.append("LogRecord: [" + _level + ", " + _message + "]");
|
|
||||||
return (buf.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the NDC (nested diagnostic context) for this record.
|
|
||||||
*
|
|
||||||
* @return The string representing the NDC.
|
|
||||||
*/
|
|
||||||
public String getNDC() {
|
|
||||||
return _ndc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the NDC (nested diagnostic context) for this record.
|
|
||||||
*
|
|
||||||
* @param ndc A string representing the NDC.
|
|
||||||
*/
|
|
||||||
public void setNDC(String ndc) {
|
|
||||||
_ndc = ndc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the location in code where this LogRecord originated.
|
|
||||||
*
|
|
||||||
* @return The string containing the location information.
|
|
||||||
*/
|
|
||||||
public String getLocation() {
|
|
||||||
return _location;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the location in code where this LogRecord originated.
|
|
||||||
*
|
|
||||||
* @param location A string containing location information.
|
|
||||||
*/
|
|
||||||
public void setLocation(String location) {
|
|
||||||
_location = location;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets that sequence number to 0.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static synchronized void resetSequenceNumber() {
|
|
||||||
_seqCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
protected static synchronized long getNextId() {
|
|
||||||
_seqCount++;
|
|
||||||
return _seqCount;
|
|
||||||
}
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Nested Top-Level Classes or Interfaces:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.lf5;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An interface for classes which filters LogRecords. Implementations
|
|
||||||
* represent a rule or condition which LogRecords may pass or fail.
|
|
||||||
* @see LogRecord
|
|
||||||
*
|
|
||||||
* @author Richard Wan
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Contributed by ThoughtWorks Inc.
|
|
||||||
|
|
||||||
public interface LogRecordFilter {
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constants:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Public Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if the specified LogRecord satisfies whatever condition
|
|
||||||
* implementing class tests for.
|
|
||||||
*/
|
|
||||||
public boolean passes(LogRecord record);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.lf5;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An implementation of LogRecordFilter which always returns true.
|
|
||||||
*
|
|
||||||
* @author Richard Wan
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Contributed by ThoughtWorks Inc.
|
|
||||||
|
|
||||||
public class PassingLogRecordFilter implements LogRecordFilter {
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constants:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constructors:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Public Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true;
|
|
||||||
*/
|
|
||||||
public boolean passes(LogRecord record) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does nothing.
|
|
||||||
*/
|
|
||||||
public void reset() {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Nested Top-Level Classes or Interfaces
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.lf5;
|
|
||||||
|
|
||||||
import org.apache.log4j.lf5.viewer.LogBrokerMonitor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts an instance of the LogFactor5 console for off-line viewing.
|
|
||||||
*
|
|
||||||
* @author Brad Marlborough
|
|
||||||
* @author Richard Hurst
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Contributed by ThoughtWorks Inc.
|
|
||||||
|
|
||||||
public class StartLogFactor5 {
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constants:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constructors:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Public Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* NetworkClient - starts a an instance of the LogFactor5 console and configures
|
|
||||||
* the console settings.
|
|
||||||
*/
|
|
||||||
public final static void main(String[] args) {
|
|
||||||
|
|
||||||
LogBrokerMonitor monitor = new LogBrokerMonitor(
|
|
||||||
LogLevel.getLog4JLevels());
|
|
||||||
|
|
||||||
monitor.setFrameSize(LF5Appender.getDefaultMonitorWidth(),
|
|
||||||
LF5Appender.getDefaultMonitorHeight());
|
|
||||||
monitor.setFontSize(12);
|
|
||||||
monitor.show();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Nested Top-Level Classes or Interfaces
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.lf5.util;
|
|
||||||
|
|
||||||
import org.apache.log4j.lf5.LogLevel;
|
|
||||||
import org.apache.log4j.lf5.LogRecord;
|
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>A LogRecord to be used with the LogMonitorAdapter</p>
|
|
||||||
*
|
|
||||||
* @author Richard Hurst
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Contributed by ThoughtWorks Inc.
|
|
||||||
|
|
||||||
public class AdapterLogRecord extends LogRecord {
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constants:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
private static LogLevel severeLevel = null;
|
|
||||||
|
|
||||||
private static StringWriter sw = new StringWriter();
|
|
||||||
private static PrintWriter pw = new PrintWriter(sw);
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constructors:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
public AdapterLogRecord() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Public Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
public void setCategory(String category) {
|
|
||||||
super.setCategory(category);
|
|
||||||
super.setLocation(getLocationInfo(category));
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSevereLevel() {
|
|
||||||
if (severeLevel == null) return false;
|
|
||||||
return severeLevel.equals(getLevel());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setSevereLevel(LogLevel level) {
|
|
||||||
severeLevel = level;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LogLevel getSevereLevel() {
|
|
||||||
return severeLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
protected String getLocationInfo(String category) {
|
|
||||||
String stackTrace = stackTraceToString(new Throwable());
|
|
||||||
String line = parseLine(stackTrace, category);
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String stackTraceToString(Throwable t) {
|
|
||||||
String s = null;
|
|
||||||
|
|
||||||
synchronized (sw) {
|
|
||||||
t.printStackTrace(pw);
|
|
||||||
s = sw.toString();
|
|
||||||
sw.getBuffer().setLength(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String parseLine(String trace, String category) {
|
|
||||||
int index = trace.indexOf(category);
|
|
||||||
if (index == -1) return null;
|
|
||||||
trace = trace.substring(index);
|
|
||||||
trace = trace.substring(0, trace.indexOf(")") + 1);
|
|
||||||
return trace;
|
|
||||||
}
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Nested Top-Level Classes or Interfaces
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,243 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.lf5.util;
|
|
||||||
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.TimeZone;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Date format manager.
|
|
||||||
* Utility class to help manage consistent date formatting and parsing.
|
|
||||||
* It may be advantageous to have multiple DateFormatManagers per
|
|
||||||
* application. For example, one for handling the output (formatting) of
|
|
||||||
* dates, and another one for handling the input (parsing) of dates.
|
|
||||||
*
|
|
||||||
* @author Robert Shaw
|
|
||||||
* @author Michael J. Sikorsky
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Contributed by ThoughtWorks Inc.
|
|
||||||
public class DateFormatManager {
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constants:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
private TimeZone _timeZone = null;
|
|
||||||
private Locale _locale = null;
|
|
||||||
|
|
||||||
private String _pattern = null;
|
|
||||||
private DateFormat _dateFormat = null;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constructors:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
public DateFormatManager() {
|
|
||||||
super();
|
|
||||||
configure();
|
|
||||||
}
|
|
||||||
|
|
||||||
public DateFormatManager(TimeZone timeZone) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
_timeZone = timeZone;
|
|
||||||
configure();
|
|
||||||
}
|
|
||||||
|
|
||||||
public DateFormatManager(Locale locale) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
_locale = locale;
|
|
||||||
configure();
|
|
||||||
}
|
|
||||||
|
|
||||||
public DateFormatManager(String pattern) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
_pattern = pattern;
|
|
||||||
configure();
|
|
||||||
}
|
|
||||||
|
|
||||||
public DateFormatManager(TimeZone timeZone, Locale locale) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
_timeZone = timeZone;
|
|
||||||
_locale = locale;
|
|
||||||
configure();
|
|
||||||
}
|
|
||||||
|
|
||||||
public DateFormatManager(TimeZone timeZone, String pattern) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
_timeZone = timeZone;
|
|
||||||
_pattern = pattern;
|
|
||||||
configure();
|
|
||||||
}
|
|
||||||
|
|
||||||
public DateFormatManager(Locale locale, String pattern) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
_locale = locale;
|
|
||||||
_pattern = pattern;
|
|
||||||
configure();
|
|
||||||
}
|
|
||||||
|
|
||||||
public DateFormatManager(TimeZone timeZone, Locale locale, String pattern) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
_timeZone = timeZone;
|
|
||||||
_locale = locale;
|
|
||||||
_pattern = pattern;
|
|
||||||
configure();
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Public Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
public synchronized TimeZone getTimeZone() {
|
|
||||||
if (_timeZone == null) {
|
|
||||||
return TimeZone.getDefault();
|
|
||||||
} else {
|
|
||||||
return _timeZone;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void setTimeZone(TimeZone timeZone) {
|
|
||||||
_timeZone = timeZone;
|
|
||||||
configure();
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized Locale getLocale() {
|
|
||||||
if (_locale == null) {
|
|
||||||
return Locale.getDefault();
|
|
||||||
} else {
|
|
||||||
return _locale;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void setLocale(Locale locale) {
|
|
||||||
_locale = locale;
|
|
||||||
configure();
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized String getPattern() {
|
|
||||||
return _pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the pattern. i.e. "EEEEE, MMMMM d, yyyy hh:mm aaa"
|
|
||||||
*/
|
|
||||||
public synchronized void setPattern(String pattern) {
|
|
||||||
_pattern = pattern;
|
|
||||||
configure();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method has been deprecated in favour of getPattern().
|
|
||||||
* @deprecated Use getPattern().
|
|
||||||
*/
|
|
||||||
public synchronized String getOutputFormat() {
|
|
||||||
return _pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method has been deprecated in favour of setPattern().
|
|
||||||
* @deprecated Use setPattern().
|
|
||||||
*/
|
|
||||||
public synchronized void setOutputFormat(String pattern) {
|
|
||||||
_pattern = pattern;
|
|
||||||
configure();
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized DateFormat getDateFormatInstance() {
|
|
||||||
return _dateFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void setDateFormatInstance(DateFormat dateFormat) {
|
|
||||||
_dateFormat = dateFormat;
|
|
||||||
// No reconfiguration necessary!
|
|
||||||
}
|
|
||||||
|
|
||||||
public String format(Date date) {
|
|
||||||
return getDateFormatInstance().format(date);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String format(Date date, String pattern) {
|
|
||||||
DateFormat formatter = null;
|
|
||||||
formatter = getDateFormatInstance();
|
|
||||||
if (formatter instanceof SimpleDateFormat) {
|
|
||||||
formatter = (SimpleDateFormat) (formatter.clone());
|
|
||||||
((SimpleDateFormat) formatter).applyPattern(pattern);
|
|
||||||
}
|
|
||||||
return formatter.format(date);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws java.text.ParseException
|
|
||||||
*/
|
|
||||||
public Date parse(String date) throws ParseException {
|
|
||||||
return getDateFormatInstance().parse(date);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws java.text.ParseException
|
|
||||||
*/
|
|
||||||
public Date parse(String date, String pattern) throws ParseException {
|
|
||||||
DateFormat formatter = null;
|
|
||||||
formatter = getDateFormatInstance();
|
|
||||||
if (formatter instanceof SimpleDateFormat) {
|
|
||||||
formatter = (SimpleDateFormat) (formatter.clone());
|
|
||||||
((SimpleDateFormat) formatter).applyPattern(pattern);
|
|
||||||
}
|
|
||||||
return formatter.parse(date);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
private synchronized void configure() {
|
|
||||||
_dateFormat = SimpleDateFormat.getDateTimeInstance(DateFormat.FULL,
|
|
||||||
DateFormat.FULL,
|
|
||||||
getLocale());
|
|
||||||
_dateFormat.setTimeZone(getTimeZone());
|
|
||||||
|
|
||||||
if (_pattern != null) {
|
|
||||||
((SimpleDateFormat) _dateFormat).applyPattern(_pattern);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Nested Top-Level Classes or Interfaces:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,301 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.lf5.util;
|
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
|
|
||||||
import org.apache.log4j.lf5.Log4JLogRecord;
|
|
||||||
import org.apache.log4j.lf5.LogLevel;
|
|
||||||
import org.apache.log4j.lf5.LogLevelFormatException;
|
|
||||||
import org.apache.log4j.lf5.LogRecord;
|
|
||||||
import org.apache.log4j.lf5.viewer.LogBrokerMonitor;
|
|
||||||
import org.apache.log4j.lf5.viewer.LogFactor5ErrorDialog;
|
|
||||||
import org.apache.log4j.lf5.viewer.LogFactor5LoadingDialog;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides utility methods for input and output streams.
|
|
||||||
*
|
|
||||||
* @author Brad Marlborough
|
|
||||||
* @author Richard Hurst
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Contributed by ThoughtWorks Inc.
|
|
||||||
|
|
||||||
public class LogFileParser implements Runnable {
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constants:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
public static final String RECORD_DELIMITER = "[slf5s.start]";
|
|
||||||
public static final String ATTRIBUTE_DELIMITER = "[slf5s.";
|
|
||||||
public static final String DATE_DELIMITER = ATTRIBUTE_DELIMITER + "DATE]";
|
|
||||||
public static final String THREAD_DELIMITER = ATTRIBUTE_DELIMITER + "THREAD]";
|
|
||||||
public static final String CATEGORY_DELIMITER = ATTRIBUTE_DELIMITER + "CATEGORY]";
|
|
||||||
public static final String LOCATION_DELIMITER = ATTRIBUTE_DELIMITER + "LOCATION]";
|
|
||||||
public static final String MESSAGE_DELIMITER = ATTRIBUTE_DELIMITER + "MESSAGE]";
|
|
||||||
public static final String PRIORITY_DELIMITER = ATTRIBUTE_DELIMITER + "PRIORITY]";
|
|
||||||
public static final String NDC_DELIMITER = ATTRIBUTE_DELIMITER + "NDC]";
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
private static SimpleDateFormat _sdf = new SimpleDateFormat("dd MMM yyyy HH:mm:ss,S");
|
|
||||||
private LogBrokerMonitor _monitor;
|
|
||||||
LogFactor5LoadingDialog _loadDialog;
|
|
||||||
private InputStream _in = null;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constructors:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
public LogFileParser(File file) throws IOException,
|
|
||||||
FileNotFoundException {
|
|
||||||
this(new FileInputStream(file));
|
|
||||||
}
|
|
||||||
|
|
||||||
public LogFileParser(InputStream stream) throws IOException {
|
|
||||||
_in = stream;
|
|
||||||
}
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Public Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts a new thread to parse the log file and create a LogRecord.
|
|
||||||
* See running().
|
|
||||||
* @param monitor LogBrokerMonitor
|
|
||||||
*/
|
|
||||||
public void parse(LogBrokerMonitor monitor) throws RuntimeException {
|
|
||||||
_monitor = monitor;
|
|
||||||
Thread t = new Thread(this);
|
|
||||||
t.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the file and creates new log records and adds the record
|
|
||||||
* to the monitor.
|
|
||||||
*/
|
|
||||||
public void run() {
|
|
||||||
|
|
||||||
int index = 0;
|
|
||||||
int counter = 0;
|
|
||||||
LogRecord temp;
|
|
||||||
boolean isLogFile = false;
|
|
||||||
|
|
||||||
_loadDialog = new LogFactor5LoadingDialog(
|
|
||||||
_monitor.getBaseFrame(), "Loading file...");
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
|
||||||
String logRecords = loadLogFile(_in);
|
|
||||||
|
|
||||||
while ((counter = logRecords.indexOf(RECORD_DELIMITER, index)) != -1) {
|
|
||||||
temp = createLogRecord(logRecords.substring(index, counter));
|
|
||||||
isLogFile = true;
|
|
||||||
|
|
||||||
if (temp != null) {
|
|
||||||
_monitor.addMessage(temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
index = counter + RECORD_DELIMITER.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index < logRecords.length() && isLogFile) {
|
|
||||||
temp = createLogRecord(logRecords.substring(index));
|
|
||||||
|
|
||||||
if (temp != null) {
|
|
||||||
_monitor.addMessage(temp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isLogFile == false) {
|
|
||||||
throw new RuntimeException("Invalid log file format");
|
|
||||||
}
|
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
destroyDialog();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
destroyDialog();
|
|
||||||
displayError("Error - Invalid log file format.\nPlease see documentation"
|
|
||||||
+ " on how to load log files.");
|
|
||||||
} catch (IOException e) {
|
|
||||||
destroyDialog();
|
|
||||||
displayError("Error - Unable to load log file!");
|
|
||||||
}
|
|
||||||
|
|
||||||
_in = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
protected void displayError(String message) {
|
|
||||||
LogFactor5ErrorDialog error = new LogFactor5ErrorDialog(
|
|
||||||
_monitor.getBaseFrame(), message);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
private void destroyDialog() {
|
|
||||||
_loadDialog.hide();
|
|
||||||
_loadDialog.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads a log file from a web server into the LogFactor5 GUI.
|
|
||||||
*/
|
|
||||||
private String loadLogFile(InputStream stream) throws IOException {
|
|
||||||
BufferedInputStream br = new BufferedInputStream(stream);
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
int size = br.available();
|
|
||||||
|
|
||||||
StringBuffer sb = null;
|
|
||||||
if (size > 0) {
|
|
||||||
sb = new StringBuffer(size);
|
|
||||||
} else {
|
|
||||||
sb = new StringBuffer(1024);
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((count = br.read()) != -1) {
|
|
||||||
sb.append((char) count);
|
|
||||||
}
|
|
||||||
|
|
||||||
br.close();
|
|
||||||
br = null;
|
|
||||||
return sb.toString();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private String parseAttribute(String name, String record) {
|
|
||||||
|
|
||||||
int index = record.indexOf(name);
|
|
||||||
|
|
||||||
if (index == -1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return getAttribute(index, record);
|
|
||||||
}
|
|
||||||
|
|
||||||
private long parseDate(String record) {
|
|
||||||
try {
|
|
||||||
String s = parseAttribute(DATE_DELIMITER, record);
|
|
||||||
|
|
||||||
if (s == null) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Date d = _sdf.parse(s);
|
|
||||||
|
|
||||||
return d.getTime();
|
|
||||||
} catch (ParseException e) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private LogLevel parsePriority(String record) {
|
|
||||||
String temp = parseAttribute(PRIORITY_DELIMITER, record);
|
|
||||||
|
|
||||||
if (temp != null) {
|
|
||||||
try {
|
|
||||||
return LogLevel.valueOf(temp);
|
|
||||||
} catch (LogLevelFormatException e) {
|
|
||||||
return LogLevel.DEBUG;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return LogLevel.DEBUG;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String parseThread(String record) {
|
|
||||||
return parseAttribute(THREAD_DELIMITER, record);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String parseCategory(String record) {
|
|
||||||
return parseAttribute(CATEGORY_DELIMITER, record);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String parseLocation(String record) {
|
|
||||||
return parseAttribute(LOCATION_DELIMITER, record);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String parseMessage(String record) {
|
|
||||||
return parseAttribute(MESSAGE_DELIMITER, record);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String parseNDC(String record) {
|
|
||||||
return parseAttribute(NDC_DELIMITER, record);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String parseThrowable(String record) {
|
|
||||||
return getAttribute(record.length(), record);
|
|
||||||
}
|
|
||||||
|
|
||||||
private LogRecord createLogRecord(String record) {
|
|
||||||
if (record == null || record.trim().length() == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
LogRecord lr = new Log4JLogRecord();
|
|
||||||
lr.setMillis(parseDate(record));
|
|
||||||
lr.setLevel(parsePriority(record));
|
|
||||||
lr.setCategory(parseCategory(record));
|
|
||||||
lr.setLocation(parseLocation(record));
|
|
||||||
lr.setThreadDescription(parseThread(record));
|
|
||||||
lr.setNDC(parseNDC(record));
|
|
||||||
lr.setMessage(parseMessage(record));
|
|
||||||
lr.setThrownStackTrace(parseThrowable(record));
|
|
||||||
|
|
||||||
return lr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private String getAttribute(int index, String record) {
|
|
||||||
int start = record.lastIndexOf(ATTRIBUTE_DELIMITER, index - 1);
|
|
||||||
|
|
||||||
if (start == -1) {
|
|
||||||
return record.substring(0, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
start = record.indexOf("]", start);
|
|
||||||
|
|
||||||
return record.substring(start + 1, index).trim();
|
|
||||||
}
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Nested Top-Level Classes or Interfaces
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,289 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.lf5.util;
|
|
||||||
|
|
||||||
import java.awt.Toolkit;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.apache.log4j.lf5.LogLevel;
|
|
||||||
import org.apache.log4j.lf5.LogRecord;
|
|
||||||
import org.apache.log4j.lf5.viewer.LogBrokerMonitor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>LogMonitorAdapter facilitates the usage of the LogMonitor</p>
|
|
||||||
*
|
|
||||||
* @author Richard Hurst
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Contributed by ThoughtWorks Inc.
|
|
||||||
|
|
||||||
public class LogMonitorAdapter {
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constants:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
public static final int LOG4J_LOG_LEVELS = 0;
|
|
||||||
public static final int JDK14_LOG_LEVELS = 1;
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
private LogBrokerMonitor _logMonitor;
|
|
||||||
private LogLevel _defaultLevel = null;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constructors:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
private LogMonitorAdapter(List userDefinedLevels) {
|
|
||||||
super();
|
|
||||||
// set the default level to be the first entry in the list
|
|
||||||
_defaultLevel = (LogLevel) userDefinedLevels.get(0);
|
|
||||||
_logMonitor = new LogBrokerMonitor(userDefinedLevels);
|
|
||||||
|
|
||||||
_logMonitor.setFrameSize(getDefaultMonitorWidth(),
|
|
||||||
getDefaultMonitorHeight());
|
|
||||||
_logMonitor.setFontSize(12);
|
|
||||||
_logMonitor.show();
|
|
||||||
}
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Public Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* <p>Creates an instance of LogMonitorAdapter using the
|
|
||||||
* log levels inticated by the parameter. Log4J and JDK1.4 both have default
|
|
||||||
* LogLevels which are set but these levels can be overriden.<p>
|
|
||||||
*
|
|
||||||
* @param loglevels An integer representing either Log4J or JDK1.4 logging levels
|
|
||||||
* @return LogMonitorAdapter
|
|
||||||
*/
|
|
||||||
public static LogMonitorAdapter newInstance(int loglevels) {
|
|
||||||
LogMonitorAdapter adapter;
|
|
||||||
if (loglevels == JDK14_LOG_LEVELS) {
|
|
||||||
adapter = newInstance(LogLevel.getJdk14Levels());
|
|
||||||
adapter.setDefaultLevel(LogLevel.FINEST);
|
|
||||||
adapter.setSevereLevel(LogLevel.SEVERE);
|
|
||||||
} else {
|
|
||||||
adapter = newInstance(LogLevel.getLog4JLevels());
|
|
||||||
adapter.setDefaultLevel(LogLevel.DEBUG);
|
|
||||||
adapter.setSevereLevel(LogLevel.FATAL);
|
|
||||||
}
|
|
||||||
return adapter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Creates an instance of LogMonitorAdapter using the specified LogLevels.
|
|
||||||
* The first LogLevel in the array is used as the default LogLevel unless
|
|
||||||
* changed using the setDefaultLevel method.<p>
|
|
||||||
*
|
|
||||||
* @param userDefined An array of user defined LogLevel objects.
|
|
||||||
* @return LogMonitorAdapter
|
|
||||||
*/
|
|
||||||
public static LogMonitorAdapter newInstance(LogLevel[] userDefined) {
|
|
||||||
if (userDefined == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return newInstance(Arrays.asList(userDefined));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Creates an instance of LogMonitorAdapter using the specified LogLevels.
|
|
||||||
* The first LogLevel in the List is used as the default LogLevel unless
|
|
||||||
* changed using the setDefaultLevel method.<p>
|
|
||||||
*
|
|
||||||
* @param userDefinedLevels A list of user defined LogLevel objects.
|
|
||||||
* @return LogMonitorAdapter
|
|
||||||
*/
|
|
||||||
public static LogMonitorAdapter newInstance(List userDefinedLevels) {
|
|
||||||
return new LogMonitorAdapter(userDefinedLevels);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Adds a LogRecord to the LogMonitor.<p>
|
|
||||||
*
|
|
||||||
* @param record The LogRecord object to be logged in the logging monitor.
|
|
||||||
*/
|
|
||||||
public void addMessage(LogRecord record) {
|
|
||||||
_logMonitor.addMessage(record);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Set the maximum number of records to be displayed in the monitor<p>
|
|
||||||
*
|
|
||||||
* @param maxNumberOfRecords
|
|
||||||
*/
|
|
||||||
public void setMaxNumberOfRecords(int maxNumberOfRecords) {
|
|
||||||
_logMonitor.setMaxNumberOfLogRecords(maxNumberOfRecords);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Set the default log level to be used when logging messages without
|
|
||||||
* specifying a LogLevel.<p>
|
|
||||||
*
|
|
||||||
* @param level
|
|
||||||
*/
|
|
||||||
public void setDefaultLevel(LogLevel level) {
|
|
||||||
_defaultLevel = level;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Gets the default LogLevel for the Adapter.<p>
|
|
||||||
*
|
|
||||||
* @return LogLevel
|
|
||||||
*/
|
|
||||||
public LogLevel getDefaultLevel() {
|
|
||||||
return _defaultLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Sets the Severe LogLevel.</p>
|
|
||||||
*
|
|
||||||
* @param level
|
|
||||||
*/
|
|
||||||
public void setSevereLevel(LogLevel level) {
|
|
||||||
AdapterLogRecord.setSevereLevel(level);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Gets the current Severe LogLevel <p>
|
|
||||||
*
|
|
||||||
* @return LogLevel
|
|
||||||
*/
|
|
||||||
public LogLevel getSevereLevel() {
|
|
||||||
return AdapterLogRecord.getSevereLevel();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Log a complete message to the Monitor.<p>
|
|
||||||
*
|
|
||||||
* @param category The category to be used
|
|
||||||
* @param level The log level to apply to the message
|
|
||||||
* @param message The message
|
|
||||||
* @param t The throwable content of the message
|
|
||||||
* @param NDC The NDC really only applies to Log4J and the parameter can
|
|
||||||
* usually be ignored.
|
|
||||||
*/
|
|
||||||
public void log(String category, LogLevel level, String message,
|
|
||||||
Throwable t, String NDC) {
|
|
||||||
AdapterLogRecord record = new AdapterLogRecord();
|
|
||||||
record.setCategory(category);
|
|
||||||
record.setMessage(message);
|
|
||||||
record.setNDC(NDC);
|
|
||||||
record.setThrown(t);
|
|
||||||
|
|
||||||
if (level == null) {
|
|
||||||
record.setLevel(getDefaultLevel());
|
|
||||||
} else {
|
|
||||||
record.setLevel(level);
|
|
||||||
}
|
|
||||||
|
|
||||||
addMessage(record);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Log a message to the Monitor and use the default LogLevel.<p>
|
|
||||||
*
|
|
||||||
* @param category The category to be used
|
|
||||||
* @param message The message
|
|
||||||
*/
|
|
||||||
public void log(String category, String message) {
|
|
||||||
log(category, null, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Log a message to the Monitor.<p>
|
|
||||||
*
|
|
||||||
* @param category The category to be used
|
|
||||||
* @param level The log level to apply to the message
|
|
||||||
* @param message The message
|
|
||||||
* @param NDC
|
|
||||||
*/
|
|
||||||
public void log(String category, LogLevel level, String message, String NDC) {
|
|
||||||
log(category, level, message, null, NDC);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Log a message to the Monitor.<p>
|
|
||||||
*
|
|
||||||
* @param category The category to be used
|
|
||||||
* @param level The log level to apply to the message
|
|
||||||
* @param message The message
|
|
||||||
* @param t The throwable content of the message
|
|
||||||
*/
|
|
||||||
public void log(String category, LogLevel level, String message,
|
|
||||||
Throwable t) {
|
|
||||||
log(category, level, message, t, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Log a message to the Monitor.<p>
|
|
||||||
*
|
|
||||||
* @param category The category to be used
|
|
||||||
* @param level The log level to apply to the message
|
|
||||||
* @param message The message
|
|
||||||
*/
|
|
||||||
public void log(String category, LogLevel level, String message) {
|
|
||||||
log(category, level, message, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* @return the screen width from Toolkit.getScreenSize()
|
|
||||||
* if possible, otherwise returns 800
|
|
||||||
* @see java.awt.Toolkit
|
|
||||||
*/
|
|
||||||
protected static int getScreenWidth() {
|
|
||||||
try {
|
|
||||||
return Toolkit.getDefaultToolkit().getScreenSize().width;
|
|
||||||
} catch (Throwable t) {
|
|
||||||
return 800;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the screen height from Toolkit.getScreenSize()
|
|
||||||
* if possible, otherwise returns 600
|
|
||||||
* @see java.awt.Toolkit
|
|
||||||
*/
|
|
||||||
protected static int getScreenHeight() {
|
|
||||||
try {
|
|
||||||
return Toolkit.getDefaultToolkit().getScreenSize().height;
|
|
||||||
} catch (Throwable t) {
|
|
||||||
return 600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static int getDefaultMonitorWidth() {
|
|
||||||
return (3 * getScreenWidth()) / 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static int getDefaultMonitorHeight() {
|
|
||||||
return (3 * getScreenHeight()) / 4;
|
|
||||||
}
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Nested Top-Level Classes or Interfaces
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,156 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.log4j.lf5.util;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.net.URL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resource encapsulates access to Resources via the Classloader.
|
|
||||||
*
|
|
||||||
* @author Michael J. Sikorsky
|
|
||||||
* @author Robert Shaw
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Contributed by ThoughtWorks Inc.
|
|
||||||
|
|
||||||
public class Resource {
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constants:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
protected String _name;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Variables:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Constructors:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default, no argument constructor.
|
|
||||||
*/
|
|
||||||
public Resource() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a Resource given a name.
|
|
||||||
*
|
|
||||||
* @see #setName(String)
|
|
||||||
*/
|
|
||||||
public Resource(String name) {
|
|
||||||
_name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Public Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the name of the resource.
|
|
||||||
* <p>
|
|
||||||
* A resource is some data (images, audio, text, etc) that can be accessed
|
|
||||||
* by class code in a way that is independent of the location of the code.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* The name of a resource is a "/"-separated path name that identifies
|
|
||||||
* the resource.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @see #getName()
|
|
||||||
*/
|
|
||||||
public void setName(String name) {
|
|
||||||
_name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the name of the resource. Set setName() for a description of
|
|
||||||
* a resource.
|
|
||||||
*
|
|
||||||
* @see #setName
|
|
||||||
*/
|
|
||||||
public String getName() {
|
|
||||||
return (_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the InputStream for this Resource. Uses the classloader
|
|
||||||
* from this Resource.
|
|
||||||
*
|
|
||||||
* @see #getInputStreamReader
|
|
||||||
* @see ResourceUtils
|
|
||||||
*/
|
|
||||||
public InputStream getInputStream() {
|
|
||||||
InputStream in = ResourceUtils.getResourceAsStream(this, this);
|
|
||||||
|
|
||||||
return (in);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the InputStreamReader for this Resource. Uses the classloader from
|
|
||||||
* this Resource.
|
|
||||||
*
|
|
||||||
* @see #getInputStream
|
|
||||||
* @see ResourceUtils
|
|
||||||
*/
|
|
||||||
public InputStreamReader getInputStreamReader() {
|
|
||||||
InputStream in = ResourceUtils.getResourceAsStream(this, this);
|
|
||||||
|
|
||||||
if (in == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
InputStreamReader reader = new InputStreamReader(in);
|
|
||||||
|
|
||||||
return reader;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the URL of the Resource. Uses the classloader from this Resource.
|
|
||||||
*
|
|
||||||
* @see ResourceUtils
|
|
||||||
*/
|
|
||||||
public URL getURL() {
|
|
||||||
return (ResourceUtils.getResourceAsURL(this, this));
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Protected Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Private Methods:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Nested Top-Level Classes or Interfaces:
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user