Skip to content

Instantly share code, notes, and snippets.

@actsasflinn
Created June 2, 2011 05:13
Show Gist options
  • Save actsasflinn/1003970 to your computer and use it in GitHub Desktop.
Save actsasflinn/1003970 to your computer and use it in GitHub Desktop.
Web Service Log4j Appender, loosely based on SMTPAppender
package client;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Layout;
import org.apache.log4j.Level;
import org.apache.log4j.helpers.CyclicBuffer;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.spi.ErrorCode;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.OptionHandler;
import org.apache.log4j.spi.TriggeringEventEvaluator;
/**
*
* @author fmueller
*/
public class WSAppender extends AppenderSkeleton {
private int bufferSize = 512;
private boolean locationInfo = false;
private boolean sendOnClose = true;
protected CyclicBuffer cb = new CyclicBuffer(bufferSize);
protected TriggeringEventEvaluator evaluator;
/**
The default constructor will instantiate the appender with a
{@link TriggeringEventEvaluator} that will trigger on events with
level ERROR or higher.*/
public
WSAppender() {
this(new DefaultEvaluator());
}
/**
Use <code>evaluator</code> passed as parameter as the {@link
TriggeringEventEvaluator} for this WSAppender. */
public
WSAppender(TriggeringEventEvaluator evaluator) {
this.evaluator = evaluator;
}
/**
Activate the specified options, such as the smtp host, the
recipient, from, etc. */
public
void activateOptions() {
if (evaluator instanceof OptionHandler) {
((OptionHandler) evaluator).activateOptions();
}
}
/**
Perform WSAppender specific appending actions, mainly adding
the event to a cyclic buffer and checking if the event triggers
an e-mail to be sent. */
public
void append(LoggingEvent event) {
if(!checkEntryConditions()) {
return;
}
event.getThreadName();
event.getNDC();
event.getMDCCopy();
if(locationInfo) {
event.getLocationInformation();
}
event.getRenderedMessage();
event.getThrowableStrRep();
cb.add(event);
if(evaluator.isTriggeringEvent(event)) {
sendBuffer();
}
}
/**
The <code>WSAppender</code> requires a {@link
org.apache.log4j.Layout layout}. */
public
boolean requiresLayout() {
return true;
}
/**
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.evaluator == null) {
errorHandler.error("No TriggeringEventEvaluator is set for appender ["+
name+"].");
return false;
}
if(this.layout == null) {
errorHandler.error("No layout set for appender named ["+name+"].");
return false;
}
return true;
}
synchronized
public
void close() {
this.closed = true;
if (sendOnClose && cb.length() > 0) {
sendBuffer();
}
}
/**
* Layout body of email message.
* @since 1.2.16
*/
protected String formatBody() {
// Note: this code already owns the monitor for this
// appender. This frees us from needing to synchronize on 'cb'.
StringBuffer sbuf = new StringBuffer();
String t = layout.getHeader();
if(t != null)
sbuf.append(t);
int len = cb.length();
for(int i = 0; i < len; i++) {
//sbuf.append(MimeUtility.encodeText(layout.format(cb.get())));
LoggingEvent event = cb.get();
sbuf.append(layout.format(event));
if(layout.ignoresThrowable()) {
String[] s = event.getThrowableStrRep();
if (s != null) {
for(int j = 0; j < s.length; j++) {
sbuf.append(s[j]);
sbuf.append(Layout.LINE_SEP);
}
}
}
}
t = layout.getFooter();
if(t != null) {
sbuf.append(t);
}
return sbuf.toString();
}
/**
Send the contents of the cyclic buffer as an e-mail message.
*/
protected
void sendBuffer() {
try {
client.Hello_Service service =
new client.Hello_Service();
client.Hello port = service.getHelloPort();
// TODO initialize WS operation arguments here
String arg0 = formatBody();
// TODO process result here
String result = port.hello(arg0);
//System.out.println("Result = "+result);
} catch(RuntimeException e) {
LogLog.error("Error occured.", e);
}
}
/**
The <b>BufferSize</b> option takes a positive integer
representing the maximum number of logging events to collect in a
cyclic buffer. When the <code>BufferSize</code> is reached,
oldest events are deleted as new events are added to the
buffer. By default the size of the cyclic buffer is 512 events.
*/
public
void setBufferSize(int bufferSize) {
this.bufferSize = bufferSize;
cb.resize(bufferSize);
}
/**
Returns value of the <b>BufferSize</b> option.
*/
public
int getBufferSize() {
return bufferSize;
}
/**
The <b>EvaluatorClass</b> option takes a string value
representing the name of the class implementing the {@link
TriggeringEventEvaluator} interface. A corresponding object will
be instantiated and assigned as the triggering event evaluator
for the WSAppender.
*/
public
void setEvaluatorClass(String value) {
evaluator = (TriggeringEventEvaluator)
OptionConverter.instantiateByClassName(value,
TriggeringEventEvaluator.class,
evaluator);
}
/**
* Sets triggering evaluator.
* @param trigger triggering event evaluator.
* @since 1.2.15
*/
public final void setEvaluator(final TriggeringEventEvaluator trigger) {
if (trigger == null) {
throw new NullPointerException("trigger");
}
this.evaluator = trigger;
}
/**
* Get triggering evaluator.
* @return triggering event evaluator.
* @since 1.2.15
*/
public final TriggeringEventEvaluator getEvaluator() {
return evaluator;
}
/**
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 layout that formats the events as they are sent out
in an e-mail is likely to place the wrong location information
(if present in the format).
<p>Location information extraction is comparatively very slow and
should be avoided unless performance is not a concern.
*/
public
void setLocationInfo(boolean locationInfo) {
this.locationInfo = locationInfo;
}
/**
Returns value of the <b>LocationInfo</b> option.
*/
public
boolean getLocationInfo() {
return locationInfo;
}
/**
Returns value of the <b>EvaluatorClass</b> option.
*/
public
String getEvaluatorClass() {
return evaluator == null ? null : evaluator.getClass().getName();
}
/**
* Set sendOnClose.
*
* @param val if true all buffered logging events will be sent when appender is closed.
* @since 1.2.16
*/
public final void setSendOnClose(final boolean val) {
sendOnClose = val;
}
}
class DefaultEvaluator implements TriggeringEventEvaluator {
/**
Is this <code>event</code> the e-mail triggering event?
<p>This method returns <code>true</code>, if the event level
has ERROR level or higher. Otherwise it returns
<code>false</code>. */
public
boolean isTriggeringEvent(LoggingEvent event) {
return event.getLevel().isGreaterOrEqual(Level.ERROR);
}
}
@devdepvenezuela
Copy link

Hi dude!

I need to send all the error msg from log4j 1.2 to a web service :(

Could you help me giving me some clues about how this work?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment