Home PC Games Linux Windows Database Network Programming Server Mobile  
           
  Home \ Server \ Spring + Log4j + ActiveMQ remote logging - Analysis of combat     - Talk about Java EE Learning (Programming)

- WebLogic administrator account and reset the password (Database)

- How to Install Redis server on CentOS 7 (Server)

- The Java ThreadLocal (Programming)

- Ubuntu 14.10 Apache installation and configuration (Server)

- MySQL configuration file my.cnf increase the log file parameter error (Database)

- 29 practical examples Linux system / network administrator of nmap (Linux)

- Linux smart small switch rfkill (Linux)

- How MAT Android application memory leak analysis (Programming)

- Ubuntu users Steam controller does not work solutions (Linux)

- Linux installed PCRE (Linux)

- To install Spotify in Ubuntu / Mint (Linux)

- Linux process or thread is bound to a CPU (Programming)

- Python format string (Programming)

- Linux SSH login without a password (Linux)

- Java-- get the reflection object information (Programming)

- CentOS 6.7 compile and install LAMP (Server)

- Linux environment RabbitMQ installation and monitoring of plug-in installation (Linux)

- Python Basics Tutorial - lambda keyword (Programming)

- Under CentOS 7 installation and deployment environment Ceph (Server)

 
         
  Spring + Log4j + ActiveMQ remote logging - Analysis of combat
     
  Add Date : 2017-01-08      
         
         
         
  These days due to the need to work, study a little way remote printing log, so the results will be recorded in this for everyone to share, we want to help.

Scenarios

With the gradual expansion of the project, increase the log has become faster. Log4j logging tools are commonly used, in some cases, we may need to Log4j log to a remote server dedicated to logging, especially for slightly larger applications. There are advantages to do so:

You can centrally manage log: You can log on to multiple servers are sent to a log server, easy to manage, view and analyze
You can reduce server overhead: the log is not on the server, so the server has more available disk space
Can improve the performance of the server: asynchronously, when the log server is only responsible for sending the message, do not care about the time and location of the logging, the server logs do not even care about in the end there is no record of success
Principle remote printing log: A project need to print the log, and Log4j A call to print logs Log4j configuration of JMSAppender gave an address (ActiveMQ address) send a JMS message, this time bound to the project B Queue Listener finds a message arrives, and immediately wake up the listener way to start output log.

This article will use two Java projects Product and Logging, which the project is to simulate the Product line item, and Logging project simulation run the project on a dedicated log server. Note: This article is an example of the Windows platform.
 
Installation ActiveMQ

1. Download: http: //activemq.apache.org/download.html

2. Unzip no configuration, go to the bin under the corresponding system architecture folder

3. Double-click activemq.bat start, if you see something like the following pages, on behalf activemq good start

Then open the browser, enter the address: http: // localhost: 8161 into the management page, the user name admin, password admin:

Click Manage ActiveMQ broker may enter Queue viewing interface.

Real

I use Maven to manage the project, easy to maintain a variety of dependent jar package. Look under the project structure:

Project is not complicated, mainly the four files: pom.xml, Main.java, log4j.properties and jndi.properties

pom.xml is mainly dependent on the package declaration project, there is nothing the rest:

<-! Use to call write log methods ->
< Dependency>
    < GroupId> log4j < / groupId>
    < ArtifactId> log4j < / artifactId>
    < Version> 1.2.17 < / version>
< / Dependency>
 
< -! Log4j uses this lib ->
< Dependency>
    < GroupId> org.slf4j < / groupId>
    < ArtifactId> slf4j-log4j12 < / artifactId>
    < Version> 1.7.13 < / version>
< / Dependency>
 
< -! Spring jms lib ->
< Dependency>
    < GroupId> org.springframework < / groupId>
    < ArtifactId> spring-jms < / artifactId>
    < Version> 4.0.0.RELEASE < / version>
< / Dependency>
 
< -! ActiveMQ lib ->
< Dependency>
    < GroupId> org.apache.activemq < / groupId>
    < ArtifactId> activemq-core < / artifactId>
    < Version> 5.7.0 < / version>
< / Dependency>

Main.java:

package com.demo.product;
 
import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Session;
 
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQObjectMessage;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggingEvent;
 
public class Main implements MessageListener {
    
    public Main () throws Exception {
        // Create consumer and listen queue
        ActiveMQConnectionFactory factory =
                new ActiveMQConnectionFactory ( "tcp: // localhost: 61616");
        Connection connection = factory.createConnection ();
        Session session = connection.createSession (false, Session.AUTO_ACKNOWLEDGE);
        connection.start ();
        Note that only supports ////////////// JMSAppender TopicDestination, the following will talk ////////////////
        Destination topicDestination = session.createTopic ( "logTopic");
        MessageConsumer consumer = session.createConsumer (topicDestination);
        consumer.setMessageListener (this);
        
        // Log a message
        Logger logger = Logger.getLogger (Main.class);
        logger.info ( "Info Log.");
        logger.warn ( "Warn Log");
        logger.error ( "Error Log.");
        
        // Clean up
        Thread.sleep (1000);
        consumer.close ();
        session.close ();
        connection.close ();
        System.exit (1);
    }
    
    public static void main (String [] args) throws Exception {
        new Main ();
    }
    
    public void onMessage (Message message) {
        try {
            // Receive log event in your consumer
            LoggingEvent event = (LoggingEvent) ((ActiveMQObjectMessage) message) .getObject ();
            System.out.println ( "Received log [" + event.getLevel () + "]:" + event.getMessage ());
        } Catch (Exception e) {
            e.printStackTrace ();
        }
    }
    
}

Description: Then log4j.properties:

log4j.rootLogger = INFO, stdout, jms
  
## Be sure that ActiveMQ messages are not logged to 'jms' appender
log4j.logger.org.apache.activemq = INFO, stdout
  
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 = logTopic
log4j.appender.jms.TopicConnectionFactoryBindingName = ConnectionFactory

In fact, arguably only need three files so you can, but this time the execution error:

javax.naming.NameNotFoundException: logTopic
    at org.apache.activemq.jndi.ReadOnlyContext.lookup (ReadOnlyContext.java:235)
    at javax.naming.InitialContext.lookup (Unknown Source)
    at org.apache.log4j.net.JMSAppender.lookup (JMSAppender.java:245)
    at org.apache.log4j.net.JMSAppender.activateOptions (JMSAppender.java:222)
    at org.apache.log4j.config.PropertySetter.activate (PropertySetter.java:307)
        ...
    at org.apache.activemq.ActiveMQPrefetchPolicy. < clinit> (ActiveMQPrefetchPolicy.java:39)
    at org.apache.activemq.ActiveMQConnectionFactory. < init> (ActiveMQConnectionFactory.java:84)
    at org.apache.activemq.ActiveMQConnectionFactory. < init> (ActiveMQConnectionFactory.java:137)
    at com.demo.product.Main. < init> (Main.java:20)
    at com.demo.product.Main.main (Main.java:43)
 

Why is it being given? Take a look at the javadoc JMSAppender document, it is so described:

To the effect that, JMSAppender need a jndi configured to initialize a JNDI context (Context). Because of this connection to manage JMS Topic and context of the topic. So called jndi.properties configuration file for the project, which reads:

topic.logTopic = logTopic

Then run not being given. Let's look at ActiveMQ (Topic attention switches to the next tab):

You can see, the theme of logTopic news, there are three feed Queue, these three are out of the Queue. Out Queue message has been received to our listeners and printed out:

Spring Integration

Note that, in this case just a very simple example, the purpose is to clarify the principles of remote printing log. Actual project, running on a common log server, not a project, but a dedicated logger. Here, we put this project is split into two projects, and use Spring to manage these used Bean
 
Modify Product Project

Product of the revised project structure does not change, change only the Main class:

package com.demo.product;
 
import org.apache.log4j.Logger;
 
public class Main {
    private static final Logger logger = Logger.getLogger (Main.class);
    public static void main (String [] args) throws Exception {
        // Just log a message
        logger.info ( "Info Log.");
        logger.warn ( "Warn Log");
        logger.error ( "Error Log.");
        System.exit (0);
    }
}

The Main class and ordinary logger calls, only responsible for printing the log. Do you feel it too simple?
 
Logging Project


In order for the listener has been alive, I wrote a Web Logging project, running on Tomcat. index.jsp is a Hello World string only, to verify Logging alive. Note that, in the Logging project, the project has no Product log4j.properties and jndi.properties two files

Take a look at several other files:

pom.xml (purpose of each packet are written in the comments in a):

< -! Use to cast object to LogEvent when received a log ->
< Dependency>
    < GroupId> log4j < / groupId>
    < ArtifactId> log4j < / artifactId>
    < Version> 1.2.17 < / version>
< / Dependency>
 
< -! Use to receive jms message ->
< Dependency>
    < GroupId> org.springframework < / groupId>
    < ArtifactId> spring-jms < / artifactId>
    < Version> 4.0.0.RELEASE < / version>
< / Dependency>
 
< -! Use to load spring.xml ->
< Dependency>
    < GroupId> org.springframework < / groupId>
    < ArtifactId> spring-web < / artifactId>
    < Version> 4.0.0.RELEASE < / version>
< / Dependency>
 
< -! ActiveMQ lib ->
< Dependency>
    < GroupId> org.apache.activemq < / groupId>
    < ArtifactId> activemq-core < / artifactId>
    < Version> 5.7.0 < / version>
< / Dependency>

web.xml

< ! DOCTYPE web-app PUBLIC
 "- // Sun Microsystems, Inc.//DTD Web Application 2.3 // EN"
 "Http://java.sun.com/dtd/web-app_2_3.dtd">
 
< Web-app>
    < Context-param>
        < Param-name> contextConfigLocation < / param-name>
        < Param-value> classpath: spring.xml < / param-value>
    < / Context-param>
    
    < -! Use to load spring.xml ->
    < Listener>
        < Listener-class>
            org.springframework.web.context.ContextLoaderListener
        < / Listener-class>
    < / Listener>
    
    < Welcome-file-list>
        < Welcome-file> index.jsp < / welcome-file>
    < / Welcome-file-list>
< / Web-app>

spring.xml

< ? Xml version = "1.0" encoding = "UTF-8"?>
< Beans xmlns = "http://www.springframework.org/schema/beans"
    xmlns: xsi = "http://www.w3.org/2001/XMLSchema-instance"
    xsi: schemaLocation = "
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd ">
 
    < Bean id = "jmsTemplate" class = "org.springframework.jms.core.JmsTemplate">
        < Property name = "connectionFactory" ref = "connectionFactory" />
    < / Bean>
     < Bean id = "connectionFactory" class = "org.springframework.jms.connection.SingleConnectionFactory">
        < Property name = "targetConnectionFactory" ref = "targetConnectionFactory" />
    < / Bean>
    < Bean id = "targetConnectionFactory" class = "org.apache.activemq.ActiveMQConnectionFactory">
        < Property name = "brokerURL" value = "tcp: // localhost: 61616" />
    < / Bean>
< -! As JMSAppender only support the topic way to send messages,
    thus queueDestination here is useless.
    < Bean id = "queueDestination" class = "org.apache.activemq.command.ActiveMQQueue">
        < Constructor-arg name = "name" value = "queue" />
    < / Bean>
 ->
    < Bean id = "topicDestination" class = "org.apache.activemq.command.ActiveMQTopic">
        < Constructor-arg name = "name" value = "logTopic" />
    < / Bean>
    < Bean id = "jmsContainer" class = "org.springframework.jms.listener.DefaultMessageListenerContainer">
        < Property name = "connectionFactory" ref = "connectionFactory" />
        < -! ->
        < Property name = "destination" ref = "topicDestination" />
        < Property name = "messageListener" ref = "logMessageListener" />
    < / Bean>
    < Bean id = "logMessageListener" class = "com.demo.logging.LogMessageListener" />
< / Beans>

logMessageListener point to our own implementation of the log message processing logic classes, topicDestination the concern for the topic "logTopic" message, while jmsContainer these two objects tied together, so that we can receive and process the message.

The last is the great listeners of the LogMessageListener:

package com.demo.logging;
 
import javax.jms.Message;
import javax.jms.MessageListener;
import org.apache.activemq.command.ActiveMQObjectMessage;
import org.apache.log4j.spi.LoggingEvent;
 
public class LogMessageListener implements MessageListener {
    public void onMessage (Message message) {
        try {
            // Receive log event in your consumer
            LoggingEvent event = (LoggingEvent) ((ActiveMQObjectMessage) message) .getObject ();
            System.out.println ( "Logging project: [" + event.getLevel () + "]:" + event.getMessage ());
        } Catch (Exception e) {
            e.printStackTrace ();
        }
    }
}
 

Haha that great, in fact, too simple. But we can see, there is a listener before the project Main Product class which implements the removal MessageListener interface code.
 
test

Before performing the test, delete ActiveMQ all Queue, ensure that the test results.

Logging to run the project, beginning Queue monitoring. Then run the main function Main Product class, you can see the Main class print to the console log:

Then take a look Queue in the case of:

You can see a man named logTopic theme message into three, out of the three. Do not think a Queue of three logs have been received and printed out Listener Logging project, and now to see Tomcat's console:

Also note that the Queue Consumer logTopic number 1 instead of 0, which is the beginning of a different theme. We all know that this is the Logging project Consumer LogMessageListener object that has been alive, because the Tomcat has been alive; the number is 0 Consumer before, because after the implementation of the main function, Queue Listener (also written log objects) exits.

By Product Logging and projects are executed on different machines, deploy ActiveMQ on the third machine (of course you can put in place to build any ActiveMQ accessible), and then click log4j.properties configuration file Product project and Logging spring.xml project file can be used in production environments friends.
 
Analysis JMSAppender class

JMSAppender class LoggingEvent instance serializes ObjectMessage, and sends it to a specified Topic JMS Server in, so use this to send logs to remotely send support only Topic does not support Queue sent. We then log4j.properties configured in this sentence:

log4j.appender.jms = org.apache.log4j.net.JMSAppender

This sentence specifies Appender use, open the Appender, in which you can see a lot of setter

The setter is not a coincidence, and it corresponds to several other options we set in the log4j.properties:

log4j.appender.jms.InitialContextFactoryName = org.apache.activemq.jndi.ActiveMQInitialContextFactory
log4j.appender.jms.ProviderURL = tcp: // localhost: 61616
log4j.appender.jms.TopicBindingName = logTopic
log4j.appender.jms.TopicConnectionFactoryBindingName = ConnectionFactory

JMSAppender activeOptions look at the method, which is used to configure the log4j.properties we are in force:

/ **
 * Options are activated and become effective only after calling this method.
 * /
public void activateOptions () {
    TopicConnectionFactory topicConnectionFactory;
    try {
        Context jndi;
        LogLog.debug ( "Getting initial context.");
        if (initialContextFactoryName! = null) {
            Properties env = new Properties ();
            env.put (Context.INITIAL_CONTEXT_FACTORY, initialContextFactoryName);
            if (providerURL! = null) {
                env.put (Context.PROVIDER_URL, providerURL);
            } Else {
                LogLog.warn ( "You have set InitialContextFactoryName option but not the"
                        + ". ProviderURL This is likely to cause problems.");
            }
            if (urlPkgPrefixes! = null) {
                env.put (Context.URL_PKG_PREFIXES, urlPkgPrefixes);
            }
 
            if (securityPrincipalName! = null) {
                env.put (Context.SECURITY_PRINCIPAL, securityPrincipalName);
                if (securityCredentials! = null) {
                    env.put (Context.SECURITY_CREDENTIALS, securityCredentials);
                } Else {
                    LogLog.warn ( "You have set SecurityPrincipalName option but not the"
                            + ". SecurityCredentials This is likely to cause problems.");
                }
            }
            jndi = new InitialContext (env);
        } Else {
            jndi = new InitialContext ();
        }
 
        LogLog.debug ( "Looking up [" + tcfBindingName + "]");
        topicConnectionFactory = (TopicConnectionFactory) lookup (jndi, tcfBindingName);
        LogLog.debug ( "About to create TopicConnection.");
        
        Note that this will only create /////////////////////////////// TopicConnection ///////////// ///////////////
        if (userName! = null) {
            topicConnection = topicConnectionFactory.createTopicConnection (userName, password);
        } Else {
            topicConnection = topicConnectionFactory.createTopicConnection ();
        }
 
        LogLog.debug ( "Creating TopicSession, non-transactional," + "in AUTO_ACKNOWLEDGE mode.");
        topicSession = topicConnection.createTopicSession (false, Session.AUTO_ACKNOWLEDGE);
 
        LogLog.debug ( "Looking up topic name [" + topicBindingName + "].");
        Topic topic = (Topic) lookup (jndi, topicBindingName);
 
        LogLog.debug ( "Creating TopicPublisher.");
        topicPublisher = topicSession.createPublisher (topic);
 
        LogLog.debug ( "Starting TopicConnection.");
        topicConnection.start ();
 
        jndi.close ();
    } Catch (JMSException e) {
        errorHandler.error ( "Error while activating options for appender named [" + name + "].", e,
                ErrorCode.GENERIC_FAILURE);
    } Catch (NamingException e) {
        errorHandler.error ( "Error while activating options for appender named [" + name + "].", e,
                ErrorCode.GENERIC_FAILURE);
    } Catch (RuntimeException e) {
        errorHandler.error ( "Error while activating options for appender named [" + name + "].", e,
                ErrorCode.GENERIC_FAILURE);
    }
}
 

It initializes above a TopicConnection, a TopicSession, a TopicPublisher. Let's look at this Appender the append method:

/ **
 * This method called by {@link AppenderSkeleton # doAppend} method to do most
 * Of the real appending work.
 * /
public void append (LoggingEvent event) {
    if (! checkEntryConditions ()) {
        return;
    }
    try {
        ObjectMessage msg = topicSession.createObjectMessage ();
        if (locationInfo) {
            event.getLocationInformation ();
        }
        msg.setObject (event);
        topicPublisher.publish (msg); /////////////// note this sentence //////////////
    } Catch (JMSException e) {
        errorHandler.error ( "Could not publish message in JMSAppender [" + name + "].",
            e, ErrorCode.GENERIC_FAILURE);
    } Catch (RuntimeException e) {
        errorHandler.error ( "Could not publish message in JMSAppender [" + name + "].",
            e, ErrorCode.GENERIC_FAILURE);
    }
}

As used herein, TopicPublisher.publish () method, the sequence of the messages advertised. This also proves the visible support Topic JMSAppender only way to send a message.
     
         
         
         
  More:      
 
- Oracle background processes daemons (Database)
- ORA-04031 Error Resolution (Database)
- Autojump: an advanced cd command in the Linux file system fast navigation (Linux)
- Linux reserves the rest of the file to delete several (Linux)
- CentOS install SVN server configuration and automatically synchronized to the Web directory (Server)
- Use Python automatically cleared Android Engineering excess resources (Programming)
- Linux in order to make NMAP hide and seek with the firewall (Linux)
- True and false in Perl (Programming)
- Vim simple configuration (Linux)
- How to add and delete bookmarks in Ubuntu (Linux)
- Forgot Linux root password (Linux)
- What is a logical partition management LVM, how to use in Ubuntu (Linux)
- Ubuntu root user profiles (Programming)
- Build your own Web server under Ubuntu Linux system (Server)
- ASP.NET 5 is connected with the Redis server on the Linux platform (Server)
- Security Knowledge: How to hide a backdoor PHP file tips (Linux)
- Depth understanding of Python character set encoding (Programming)
- 5 tips to improve your Linux desktop security (Linux)
- Ubuntu dual-card system configuration method (Server)
- Linux text processing tool of awk (Linux)
     
           
     
  CopyRight 2002-2022 newfreesoft.com, All Rights Reserved.