【问题标题】:Sending logs using log4j to web service in Java使用 log4j 将日志发送到 Java 中的 Web 服务
【发布时间】:2012-10-09 16:04:59
【问题描述】:

我对 Web 服务领域还很陌生,但对 log4j 有所了解。

我需要实现一个功能,它将日志消息发送到 Web 服务,而不是使用 Web 服务附加程序的文件。

我通过在 Google 上搜索得知 WebServiceAppenderlog4j 类之一,但我无法验证这一点。

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

【问题讨论】:

  • 到目前为止,您有尝试过使用的任何代码吗?如果您需要帮助,您首先需要对此进行一些研究。使用一些代码,它将为我们提供一些起点,而不是为您实现它。告诉我们你被困在哪里。您唯一的另一个希望是,如果有人能从里到外了解这一点并愿意发布完整的解决方案。祝你好运!
  • 嗨,dulcet,您对 Craig 的评论让我觉得您应该一次迈出这一步。您收到什么错误消息?您在资源链接中获得了多远。您提供的详细信息越多,帮助就越容易,您将获得更好的答案。希望这会有所帮助!
  • 我猜测 log4j.properties 文件没有被拾取,我在 eclipse 中使用了axis2实现并且可以看到文件已经存在。所以我添加了上面的内容。基本上需要从某个地方选择端点,因为错误消息很明显,endpoint 无法解析为变量

标签: java web-services log4j appender


【解决方案1】:

当您扩展类AppenderSkeleton 时,我假设您应该在您应该覆盖的public void activateOptions() 方法中初始化您的webservice 类。我已经编写了 DatabaseAppender 和 JmsAppender log4j 记录器,我总是发现我必须初始化 db 连接或 jms 连接,或者在你的情况下,public void activateOptions() 方法中的 web 服务属性。

然后像往常一样在append(LoggingEvent) 方法中调用网络服务。

我是否建议实现一个 BlockingQueue 来存储所有 LoggingEvent 对象,这样如果您收到大量日志消息,它们就会排队并异步发送到 Web 服务。

更新为包含模板 Log4j 类

尝试使用以下模板。我在重要部分添加了 cmets。基本上在 activateOptions 和 processEvent 方法中,您将初始化您的“连接”并发送您的事件对象。可以是DB、JMS、WebService ...等。

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

【讨论】:

  • 这有帮助,但我是 Queue 的新手,会尝试学习和实施您的建议。另外我想知道JMSAppender 是否可以用于将日志发送到网络服务
  • 可能不是,JMSAppender 只是通过 JMS 连接将日志发送到 JMS 主题。如果您愿意,我可以更新我的答案并包含带有存根的代码以制作自定义附加程序。
  • 非常感谢代码,这将帮助我快速构建应用程序!
【解决方案2】:

我建议你看看这篇文章:http://www.ibm.com/developerworks/webservices/library/ws-log4j/index.html

它具体描述了使用WebServiceAppender。

啊,谷歌!

【讨论】:

  • 感谢@craigmj,我首先检查了这篇文章,但我很困惑,因为有代码 sn-ps,而且作为新手,我迷失了所有部分的位置
  • 嗨,克雷格,虽然此链接可能会有所帮助,但如果链接断开,您的回答将毫无用处。 Stack Overflow 上的最佳答案包含示例和解释,这些示例和解释不仅可以帮助最初的提问者,而且还可以帮助未来几年的许多未来访问者。请考虑创建edit 以改进您的答案。这不仅会帮助其他人,还会让您获得更多支持!祝你好运! :)
  • 嗨@jmort253,这是一个好点。但是没有复制整个 DeveloperWorks 文章,如何解决这个问题? (因为在这种情况下,DW的文章写的挺详细的……)
  • @craigmj,在这种情况下,我认为您确实有点道理。如果没有更多细节,这可能是你能做的最好的事情,这就是我没有尝试自己编辑的原因。我希望 dulcet 可以将问题编辑为更具体的内容,这将导致更具体的答案,而不是他已经尝试过的东西。这个问题略微倾向于“不是一个真正的问题”领域。感谢您尝试提供帮助! ;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-28
  • 1970-01-01
相关资源
最近更新 更多