将 Log4J JMSAppender 与 ActiveMQ 结合使用

发布于 2024-08-18 14:38:35 字数 8281 浏览 3 评论 0原文

我正在尝试使用 log4J JMSAppender 生成从 Log4J 通过 JMS 传送日志记录的概念证明。我已经尝试过 ActiveMQ 及其附带的示例。我把这个例子拆开了,使它更通用并且与多个平台兼容。

看起来我已经把一切都搞定了,因为我可以看到与 ActiveMQ 的连接正在发生,但是当我获取 InitialContext (使用 -Dlog4j.debug 设置 ActiveMQ 客户端类似乎)时,代码挂起调用 log4J 并加载属性,这些属性又尝试为 JMSAppender 建立与 JMS 的连接,然后代码就会挂起。我尝试通过仅为单个命名记录器定义附加程序来隔离发送到 JMS 的日志消息,并将 org.apache.activemq 包配置为使用 ConsoleAppender >

当指向配置了 JMS 队列的 Weblogic 服务器时,相同的代码工作得很好,但为了获得最大兼容性,我需要尝试使其与 ActiveMQ 一起工作是否

有一些我缺少的“神奇”配置来使 ActiveMQ 工作正确吗?

-- 到目前为止,工作中的一些示例可以使这个问题更加具体化,现在我有了要处理的代码

log4j-jms.properties

log4j.rootLogger=INFO, stdout

## Be sure that ActiveMQ messages are not logged to 'jms' appender

log4j.logger.org.apache=ERROR, stdout
log4j.logger.javax=ERROR,stdout
log4j.logger.java=ERROR,stdout

log4j.logger.demo=DEBUG,jms

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %-5p %c - %m%n

## Configure 'jms' appender. You'll also need jndi.properties file in order to make it work
log4j.appender.jms=org.apache.log4j.net.JMSAppender
log4j.appender.jms.InitialContextFactoryName=org.apache.activemq.jndi.ActiveMQInitialContextFactory
log4j.appender.jms.ProviderURL=tcp://localhost:61616
log4j.appender.jms.TopicBindingName=topic.logTopic
log4j.appender.jms.TopicConnectionFactoryBindingName=ConnectionFactory

这样做的目的是创建一个命名的附加程序“演示”并且在示例代码中,抓取该记录以确保 activemq 日志记录不会尝试将其自身发送到 JMS

代码示例。它有点混乱,因为我一直在尝试让它工作。按照目前的情况,当我将其指向 Weblogic 并以类似方式切换 log4j 配置时,它将起作用。此代码中的目的是确保我有在单独的线程中运行的主题的侦听器

NewLog4jJMSAppenderExample.java

import javax.jms.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggingEvent;

import java.util.Properties;
/**
 * A simple example of log4j jms appender in conjuction with ActiveMQ
 */
public class NewLog4jJMSAppenderExample {
    Runnable listener;
    Thread runner;

    private enum MQImplementation {
        ActiveMQ, Weblogic
    };

    public NewLog4jJMSAppenderExample() {
        // create a logTopic topic consumer

        listener = new BigEars();
        System.out.println("******* Listener Created **********");

        runner = new Thread(listener);
        runner.start();

        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }

    }

    public static void main(String[] args) throws Exception {
        System.out.println("******* I HAVE STARTED **********");


        new NewLog4jJMSAppenderExample();


        System.out.println("******* LOGGING **********");

        // log a message

        Logger log = Logger.getLogger("demo");
        log.error("Test log");

        Thread.sleep(100000);

        System.exit(1);

    }

    public class BigEars implements Runnable, MessageListener {
        ConnectionFactory factory;
        Connection conn;
        Session sess;
        MessageConsumer consumer;

        public BigEars() {

            MQImplementation inUse = MQImplementation.ActiveMQ;

            System.out.println("Constructing Bigears");
            try {
                Properties env = new Properties();

                switch (inUse) {

                    case Weblogic:
                        env.put(Context.INITIAL_CONTEXT_FACTORY,
                                "weblogic.jndi.WLInitialContextFactory");
                        env.put(Context.PROVIDER_URL,
                                "t3://localhost:7001");
                        break;

                    case ActiveMQ:
                        env.put(Context.INITIAL_CONTEXT_FACTORY,
                                "org.apache.activemq.jndi.ActiveMQInitialContextFactory");
                        env.put(Context.PROVIDER_URL,
                                "tcp://localhost:61616");
                        break;
                }

                System.out.println("Initial Context");

                InitialContext jndi = new InitialContext(env);
                System.out.println("Factory");
                factory = (TopicConnectionFactory) jndi.lookup("ConnectionFactory");

                Topic theTopic = (Topic) jndi.lookup("topic.logTopic");


                System.out.println("Connection");
                conn = factory.createConnection();

                System.out.println("******* I HAVE set up and created connection **********");
                System.out.println("session");
                sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
                System.out.println("consumer");
                consumer = sess.createConsumer(theTopic);
                System.out.println("listener");
                consumer.setMessageListener(this);

                conn.start();



            } catch (JMSException jme) {
                System.out.println(jme);
            } catch (NamingException ne) {
                System.out.println(ne);
            }
        }


        public void run() {
            try {
                System.out.println("******* zzzzzzzz! **********");

                Thread.sleep(100000);
            } catch (Exception e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
        }

        public void onMessage(Message message) {
            try {
                try {
                    System.out.println("******* I GOT A MESSAGE **********");
                    // receive log event in your consumer
                    System.out.println(message.toString());

                    LoggingEvent event = (LoggingEvent) (((ObjectMessage) message).getObject());
                    System.out.println("Received log [" + event.getLevel() + "]: " + event.getMessage());
                } catch (Exception e) {
                    e.printStackTrace();
                }

            } finally {

                try {
                    consumer.close();
                    sess.close();
                    conn.close();
                } catch (JMSException jme) {
                    System.out.println(jme);
                }
            }
        }

}

设置 -Dlog4j.debug 时显示日志记录

******* I HAVE STARTED **********
Constructing Bigears
Initial Context
log4j: Trying to find [log4j-jms.properties] using context classloader sun.misc.Launcher$AppClassLoader@2c2bbd86.
log4j: Using URL [file:/Users/kevin/Desktop/apache-activemq-5.3.0/example/target/classes/log4j-jms.properties] for automatic log4j configuration.
log4j: Reading configuration from URL file:/Users/kevin/Desktop/apache-activemq-5.3.0/example/target/classes/log4j-jms.properties
log4j: Parsing for [root] with value=[INFO, stdout].
log4j: Level token is [INFO].
log4j: Category root set to INFO
log4j: Parsing appender named "stdout".
log4j: Parsing layout options for "stdout".
log4j: Setting property [conversionPattern] to [%d %-5p %c - %m%n].
log4j: End of parsing for "stdout".
log4j: Parsed "stdout" options.
log4j: Parsing for [org.apache] with value=[ERROR, stdout].
log4j: Level token is [ERROR].
log4j: Category org.apache set to ERROR
log4j: Parsing appender named "stdout".
log4j: Appender "stdout" was already parsed.
log4j: Handling log4j.additivity.org.apache=[null]
log4j: Parsing for [demo] with value=[DEBUG,jms].
log4j: Level token is [DEBUG].
log4j: Category demo set to DEBUG
log4j: Parsing appender named "jms".
log4j: Setting property [initialContextFactoryName] to [org.apache.activemq.jndi.ActiveMQInitialContextFactory].
log4j: Setting property [topicBindingName] to [topic.logTopic].
log4j: Setting property [topicConnectionFactoryBindingName] to [ConnectionFactory].
log4j: Setting property [providerURL] to [tcp://localhost:61616].
log4j: Getting initial context.
log4j: Looking up [ConnectionFactory]
log4j: About to create TopicConnection.
log4j: Creating TopicSession, non-transactional, in AUTO_ACKNOWLEDGE mode.

这里它只是挂起并最终超时

I am trying to produce a proof of concept shipping logging from Log4J through JMS using the log4J JMSAppender. I have tried ActiveMQ and the example supplied with it. I have torn this example apart, and made it more generic and compatible with multiple platforms.

It looks like I have it all plumbed up OK as I can see a connection to the ActiveMQ happening, but the code hangs when I get the InitialContext ( with -Dlog4j.debug set the ActiveMQ client classes seem to invoke log4J and load the properties which in turn try to make a connection to the JMS for the JMSAppender) and then the code just hangs. I have tried to isolate the log messages heading to the JMS by only defining the appender for a single named logger, and the org.apache.activemq package is configured to use the ConsoleAppender

The same code works just fine when pointed to a Weblogic Server with a JMS queue configured up but for maximum compatibility I need to try to make it work with ActiveMQ

Is there some 'magic' bit of configuration that I am missing to make ActiveMQ work correctly?

-- some sample bits from the work so far to flesh this question out a bit now I have the code to hand

log4j-jms.properties

log4j.rootLogger=INFO, stdout

## Be sure that ActiveMQ messages are not logged to 'jms' appender

log4j.logger.org.apache=ERROR, stdout
log4j.logger.javax=ERROR,stdout
log4j.logger.java=ERROR,stdout

log4j.logger.demo=DEBUG,jms

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %-5p %c - %m%n

## Configure 'jms' appender. You'll also need jndi.properties file in order to make it work
log4j.appender.jms=org.apache.log4j.net.JMSAppender
log4j.appender.jms.InitialContextFactoryName=org.apache.activemq.jndi.ActiveMQInitialContextFactory
log4j.appender.jms.ProviderURL=tcp://localhost:61616
log4j.appender.jms.TopicBindingName=topic.logTopic
log4j.appender.jms.TopicConnectionFactoryBindingName=ConnectionFactory

The object of this was to create a named appender 'demo' and in the sample code grab that to log to make sure that activemq logging was not trying to send itself to JMS

code example. Its a bit of a mess as I have been hacking around with it to try to make things work. As it stands it will work when I point it to Weblogic, and switch the log4j config similarly. The object in this code was to make sure I had the listener for the topic running in a separate thread

NewLog4jJMSAppenderExample.java

import javax.jms.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggingEvent;

import java.util.Properties;
/**
 * A simple example of log4j jms appender in conjuction with ActiveMQ
 */
public class NewLog4jJMSAppenderExample {
    Runnable listener;
    Thread runner;

    private enum MQImplementation {
        ActiveMQ, Weblogic
    };

    public NewLog4jJMSAppenderExample() {
        // create a logTopic topic consumer

        listener = new BigEars();
        System.out.println("******* Listener Created **********");

        runner = new Thread(listener);
        runner.start();

        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }

    }

    public static void main(String[] args) throws Exception {
        System.out.println("******* I HAVE STARTED **********");


        new NewLog4jJMSAppenderExample();


        System.out.println("******* LOGGING **********");

        // log a message

        Logger log = Logger.getLogger("demo");
        log.error("Test log");

        Thread.sleep(100000);

        System.exit(1);

    }

    public class BigEars implements Runnable, MessageListener {
        ConnectionFactory factory;
        Connection conn;
        Session sess;
        MessageConsumer consumer;

        public BigEars() {

            MQImplementation inUse = MQImplementation.ActiveMQ;

            System.out.println("Constructing Bigears");
            try {
                Properties env = new Properties();

                switch (inUse) {

                    case Weblogic:
                        env.put(Context.INITIAL_CONTEXT_FACTORY,
                                "weblogic.jndi.WLInitialContextFactory");
                        env.put(Context.PROVIDER_URL,
                                "t3://localhost:7001");
                        break;

                    case ActiveMQ:
                        env.put(Context.INITIAL_CONTEXT_FACTORY,
                                "org.apache.activemq.jndi.ActiveMQInitialContextFactory");
                        env.put(Context.PROVIDER_URL,
                                "tcp://localhost:61616");
                        break;
                }

                System.out.println("Initial Context");

                InitialContext jndi = new InitialContext(env);
                System.out.println("Factory");
                factory = (TopicConnectionFactory) jndi.lookup("ConnectionFactory");

                Topic theTopic = (Topic) jndi.lookup("topic.logTopic");


                System.out.println("Connection");
                conn = factory.createConnection();

                System.out.println("******* I HAVE set up and created connection **********");
                System.out.println("session");
                sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
                System.out.println("consumer");
                consumer = sess.createConsumer(theTopic);
                System.out.println("listener");
                consumer.setMessageListener(this);

                conn.start();



            } catch (JMSException jme) {
                System.out.println(jme);
            } catch (NamingException ne) {
                System.out.println(ne);
            }
        }


        public void run() {
            try {
                System.out.println("******* zzzzzzzz! **********");

                Thread.sleep(100000);
            } catch (Exception e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
        }

        public void onMessage(Message message) {
            try {
                try {
                    System.out.println("******* I GOT A MESSAGE **********");
                    // receive log event in your consumer
                    System.out.println(message.toString());

                    LoggingEvent event = (LoggingEvent) (((ObjectMessage) message).getObject());
                    System.out.println("Received log [" + event.getLevel() + "]: " + event.getMessage());
                } catch (Exception e) {
                    e.printStackTrace();
                }

            } finally {

                try {
                    consumer.close();
                    sess.close();
                    conn.close();
                } catch (JMSException jme) {
                    System.out.println(jme);
                }
            }
        }

}
}

logging presented when -Dlog4j.debug set

******* I HAVE STARTED **********
Constructing Bigears
Initial Context
log4j: Trying to find [log4j-jms.properties] using context classloader sun.misc.Launcher$AppClassLoader@2c2bbd86.
log4j: Using URL [file:/Users/kevin/Desktop/apache-activemq-5.3.0/example/target/classes/log4j-jms.properties] for automatic log4j configuration.
log4j: Reading configuration from URL file:/Users/kevin/Desktop/apache-activemq-5.3.0/example/target/classes/log4j-jms.properties
log4j: Parsing for [root] with value=[INFO, stdout].
log4j: Level token is [INFO].
log4j: Category root set to INFO
log4j: Parsing appender named "stdout".
log4j: Parsing layout options for "stdout".
log4j: Setting property [conversionPattern] to [%d %-5p %c - %m%n].
log4j: End of parsing for "stdout".
log4j: Parsed "stdout" options.
log4j: Parsing for [org.apache] with value=[ERROR, stdout].
log4j: Level token is [ERROR].
log4j: Category org.apache set to ERROR
log4j: Parsing appender named "stdout".
log4j: Appender "stdout" was already parsed.
log4j: Handling log4j.additivity.org.apache=[null]
log4j: Parsing for [demo] with value=[DEBUG,jms].
log4j: Level token is [DEBUG].
log4j: Category demo set to DEBUG
log4j: Parsing appender named "jms".
log4j: Setting property [initialContextFactoryName] to [org.apache.activemq.jndi.ActiveMQInitialContextFactory].
log4j: Setting property [topicBindingName] to [topic.logTopic].
log4j: Setting property [topicConnectionFactoryBindingName] to [ConnectionFactory].
log4j: Setting property [providerURL] to [tcp://localhost:61616].
log4j: Getting initial context.
log4j: Looking up [ConnectionFactory]
log4j: About to create TopicConnection.
log4j: Creating TopicSession, non-transactional, in AUTO_ACKNOWLEDGE mode.

Here it just hangs and eventually times out

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

旧情别恋 2024-08-25 14:38:35

最后似乎是 log4j 配置的加载问题,当 JMS 附加程序建立连接时,JMS 配置就出现了。如果我加载没有定义 ActiveMQ 日志级别或附加程序的配置,那么一旦附加 JMSAppender 就不会出现问题,然后我可以加载附加配置以允许它登录到 JMS

Finally seemed to be an issue with the loading of the log4j config, with the JMS config in when the JMS appender was making the connection. If I load the config with no ActiveMQ log levels or appenders defined then the problem does not occur once the JMSAppender is attached then I can load the additional config to allow it to log to JMS

如果没有 2024-08-25 14:38:35

由于您没有提供太多详细信息(关于配置、日志、跟踪等),请问您是否遵循了 如何将 log4j JMS 附加程序与 ActiveMQ 结合使用。如果是,并且该示例有效,您做了哪些更改。

顺便说一句,我会考虑使用它的后继者 logback 来代替 log4j。查看其 Appender

As you didn't provide much details (on the configuration, logs, traces, etc), may I ask if you followed How do I use log4j JMS appender with ActiveMQ. If yes, and if this sample was working, what changes did you make.

As a side note, instead of log4j, I would consider using logback, its successor. Check out its Appenders.

茶底世界 2024-08-25 14:38:35

您可以尝试使用 AsynchAppender,它允许 log4j 线程在出现错误时不会阻塞(即挂起)日志语句。我能够对 AsynAppender 中的 JMSAppender 和控制台附加器执行此操作。但是,您必须将 log4j.properties 文件更改为 log4j.xml 文件配置。格式。

You might try using the AsynchAppender which allows for the log4j threads to NOT block (i.e. hang) on a log statement if there's an error. I was able to do this for a JMSAppender and a console appender both within an AsynAppender. However, you have to change your log4j.properties file to a log4j.xml file config. format.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文