Sending logs using log4j to web service in Java

2019-01-23 00:52发布

问题:

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?w‌​sdl 
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; 
}

回答1:

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();
            }
      }


回答2:

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!