I am fairly new to the web services world but have knowledge of log4j
.
I need to implement a functionality which will send the log messages to a web service rather than to a file using web service appender.
I read by searching on Google that WebServiceAppender
is one of the log4j
class, but I couldn't verify this.
log4j.appender.CONSOLE=main.WSAppender
log4j.appender.CONSOLE.endpoint=http://localhost:8080/Logging/services/logging?wsdl
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%p [%t] %c{2} (%M:%L) :: %m%n
WSAppender.java extends AppenderSkeleton, can't resolve endpoint, hostname in append()
if (endpoint == null) {
System.out.println("no endpoint set. Check configuration file");
System.out.println("[" + hostname + "] " + this.layout.format(event));
return;
}
when you extend the class AppenderSkeleton
I would assume that you should initialize your webservice class in the public void activateOptions()
method which you should override. I've written DatabaseAppender and JmsAppender log4j loggers and I've always found that I have to initialize the db connection or jms connection or in your case the webservice properties in the public void activateOptions()
method.
Then as usual in the append(LoggingEvent)
method you would just invoke the webservice.
Might I suggest to implement a BlockingQueue to store all the LoggingEvent objects so that if you are getting an influx of log messages they are queued and sent to the webservice asynchronously.
Updated to include a Template Log4j Class
Try to use the below template. I added comments in important sections. Basically in the activateOptions and processEvent method is where you would initialize your "connection" and send your event objects. Can be DB, JMS, WebService ...etc.
package mypackage;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.LoggingEvent;
public class WebServiceAppender extends AppenderSkeleton {
private static final BlockingQueue<LoggingEvent> loggingEventQueue = new LinkedBlockingQueue<LoggingEvent>();
private static WebServiceAppender instance;
private static Thread thread = null;
//Your custom properties for your web service
private String property1;
private String property2;
private String property3;
static {
thread = new Thread(new Runnable() {
public void run() {
processQueue();
}
});
thread.setDaemon(true);
thread.start();
}
private static void processQueue() {
while(true) {
try {
LoggingEvent event = loggingEventQueue.poll(1L, TimeUnit.SECONDS);
if (event != null) {
instance.processEvent(event);
}
}
catch(InterruptedException e) {
// No operations.
}
}
}
private final void processEvent(LoggingEvent loggingEvent) {
if(loggingEvent != null) {
//Send the loggingEvent object or you can
//get data out of it and package it in another
//java class and send that, to your web service.
//Web Service is invoked here
}
}
public synchronized void close() {
// The synchronized modifier avoids concurrent append and close operations
if(this.closed) {
return;
}
closeWS();
thread.interrupt();
LogLog.debug("Closing appender [" + name + "].");
this.closed = true;
}
private void closeWS() {
try {
//Close the webservice connection
//or whatever here.
}
catch(Exception ex) {
LogLog.error("Error while closing WebServiceAppender [" + name + "].", ex);
}
}
public boolean requiresLayout() {
//Does not need a layout because
//we are sending serialized events
//to an external source
return false;
}
@Override
public void activateOptions() {
instance = this;
try {
LogLog.debug("Getting web service properties.");
if(property1 != null) {
//Do something with your property
}
if(property2 != null) {
//Do something with your property
}
if(property3 != null) {
//Do something with your property
}
//Initialize your web-service connection and objects here
LogLog.debug("Web Service created.");
}
catch(Exception ex) {
LogLog.error("Error while activating options for WebServiceAppender [" + name + "].", ex);
}
}
/*
* These methods are set from the log4j properties file like:
* log4j.appender.WS=mypackage.WebServiceAppender
* log4j.appender.WS.property1=bla
* log4j.appender.WS.property2=ble
* log4j.appender.WS.property3=blo
*/
public final String getProperty1() {
return property1;
}
public final String getProperty2() {
return property2;
}
public final String getProperty3() {
return property3;
}
public final void setProperty1(String property1) {
this.property1 = property1;
}
public final void setProperty2(String property2) {
this.property2 = property2;
}
public final void setProperty3(String property3) {
this.property3 = property3;
}
@Override
protected void append(LoggingEvent event) {
loggingEventQueue.add(event);
}
@Override
public void finalize() {
close();
super.finalize();
}
}
I suggest you have a look at this article: http://www.ibm.com/developerworks/webservices/library/ws-log4j/index.html
It specifically describes using the WebServiceAppender.
Ah, Google!