概述


以ActiveMQ + Log4j + Spring的技术组合,实现基于消息队列的统一日志服务。

与参考文章的比较

1. 更新了技术的版本
    e.g. Spring升级到4.2.0,ActiveMQ升级到5.13.2

2. 更新了依赖
    e.g. 使用activemq-client 5.13.2替换activemq-core最高版本是5.7.0,并取消了多余的spring-jms依赖

3. 精简了配置
    e.g. 去掉spring.xml中的jmsTemplate

4. 其他略述

前提

为理解文章的内容,你可能需要先了解下面的知识:

1. 了解基于Maven的项目结构

2. 下载并运行ActiveMQ

3. 了解log4j基于properties配置的简单用法

4. 了解基于Spring-webmvc的框架的搭建

当然,这只是建议......

技术版本

  1. ActiveMQ - 5.13.2
  2. Log4j - 1.2.17
  3. Spring - 4.2.4

结构图


1.节点拓扑图

说明:
  1. 应用系统基于log4j规范,通过JMSAppender将日志发送到ActiveMQ
  2. Log Server向ActiveMQ订阅消息,并指定MessageListener的实现来接收ActiveMQ发布的消息

实现


1.Log Server

你可以从amqlog-server拿到源代码。

1.1.文件目录结构

 1 pom.xml
2 src/main/webapp/
3 |---- WEB-INF/
4 |---- web.xml
5 |---- index.jsp # 忽略
6 src/main/resources/
7 |---- spring-beans.xml
8 |---- topic.properties # 集中管理修改概率比较高的属性配置
9 src/main/java/
10 |---- cn.sinobest.asj.logserver
11 |---- LogListener.java # 接收并输出log message

1.2.文件内容

1.2.1. pom.xml

 1 <project xmlns="http://maven.apache.org/POM/4.0.0"
2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4 <modelVersion>4.0.0</modelVersion>
5 <groupId>cn.sinobest.asj</groupId>
6 <artifactId>log-servler</artifactId>
7 <packaging>war</packaging>
8 <version>0.0.1-SNAPSHOT</version>
9 <name>amqlog-servler Maven Webapp</name>
10 <url>http://maven.apache.org</url>
11 <description>日志服务器,从ActiveMQ订阅主题,从而获取相关的日志数据</description>
12 <dependencies>
13 <dependency>
14 <groupId>junit</groupId>
15 <artifactId>junit</artifactId>
16 <version>3.8.1</version>
17 <scope>test</scope>
18 </dependency>
19 <!-- use to import spring-webmvc framework -->
20 <dependency>
21 <groupId>org.springframework</groupId>
22 <artifactId>spring-web</artifactId>
23 <version>4.2.4.RELEASE</version>
24 </dependency>
25 <dependency>
26 <groupId>org.springframework</groupId>
27 <artifactId>spring-jms</artifactId>
28 <version>4.2.4.RELEASE</version>
29 </dependency>
30 <!-- use to subscribe topic message from ActiveMQ -->
31 <dependency>
32 <groupId>org.apache.activemq</groupId>
33 <artifactId>activemq-client</artifactId>
34 <version>5.13.2</version>
35 </dependency>
36 <!-- use to extract log content from message -->
37 <dependency>
38 <groupId>log4j</groupId>
39 <artifactId>log4j</artifactId>
40 <version>1.2.17</version>
41 </dependency>
42 </dependencies>
43 <build>
44 <finalName>amqlog-servler</finalName>
45 </build>
46 </project>

1.2.2. web.xml

 1 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2 xmlns="http://java.sun.com/xml/ns/javaee"
3 xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
4 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
5 id="WebApp_ID" version="3.0" metadata-complete="false">
6 <display-name>Archetype Created Web Application</display-name>
7 <context-param>
8 <param-name>contextConfigLocation</param-name>
9 <param-value>
10 classpath:spring-beans.xml
11 </param-value>
12 </context-param>
13 <listener>
14 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
15 </listener>
16 </web-app>

1.2.3. spring-beans.xml

装配图
说明:左上角标识由谁提供具体的实现,没有标识的有自己提供实现。
内容
 1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xmlns:context="http://www.springframework.org/schema/context"
5 xsi:schemaLocation="http://www.springframework.org/schema/beans
6 http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
7 http://www.springframework.org/schema/context
8 http://www.springframework.org/schema/context/spring-context-4.2.xsd">
9 <context:property-placeholder location="classpath:topic.properties" />
10 <bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
11 <property name="brokerURL" value="${topic.brokerURL}" />
12 <!-- add trusted packages. see http://activemq.apache.org/objectmessage.html -->
13 <property name="trustedPackages">
14 <list>
15 <value>org.apache.log4j.spi</value>
16 </list>
17 </property>
18 </bean>
19 <bean id="connectionFactory"
20 class="org.springframework.jms.connection.SingleConnectionFactory">
21 <property name="targetConnectionFactory" ref="targetConnectionFactory" />
22 </bean>
23 <bean id="destination" class="org.apache.activemq.command.ActiveMQTopic">
24 <constructor-arg name="name" value="${topic.topicName}" />
25 </bean>
26 <!-- define the message-listener to receive and dipose log data. -->
27 <bean id="messageListener" class="cn.sinobest.asj.logserver.LogListener" />
28 <bean id="jmsContainer"
29 class="org.springframework.jms.listener.DefaultMessageListenerContainer">
30 <property name="connectionFactory" ref="connectionFactory" />
31 <property name="destination" ref="destination" />
32 <property name="messageListener" ref="messageListener" />
33 </bean>
34 </beans>
说明:
在targetConnectionFactory的属性中,指定了trustedPackages。ActiveMQ自5.12.2版本之后,强制用户指定一份可信任的packages白名单,以对付ObjectMessage存在的安全漏洞。具体内容可参考:http://activemq.apache.org/objectmessage.html

1.2.4. topic.properties

topic.brokerURL=tcp://localhost:61616
topic.topicName=demo
注意:brokerURL的值必须和ActiveMQ的监听地址一致。

1.2.5. LogListener.java

 1 package cn.sinobest.asj.logserver;
2 import javax.jms.JMSException;
3 import javax.jms.Message;
4 import javax.jms.MessageListener;
5 import org.apache.activemq.command.ActiveMQObjectMessage;
6 import org.apache.log4j.spi.LoggingEvent;
7 public class LogListener implements MessageListener {
8 private static final String TEMPLATE = "[%-5s] %s";
9 public void onMessage(Message message) {
10 try {
11 // extract LoggingEvent from message
12 // you must set org.apache.log4j.spi into the trusted packages list
13 // see spring-beans.xml in classpath
14 LoggingEvent event = (LoggingEvent) ((ActiveMQObjectMessage) message)
15 .getObject();
16 String content = String.format(TEMPLATE, event.getLevel()
17 .toString(), event.getMessage().toString());
18 System.out.println(content);
19 } catch (JMSException e) {
20 e.printStackTrace();
21 }
22 }
23 }
说明:这里的LoggingEvent来自package org.apache.log4j.spi,该package在spring-beans.xml的白名单中。

2.Log Client

log client模拟一般的应用系统。该应用系统有日志存储的需要,将日志发送给ActiveMQ而不用关心日志最终的存储方式。这里仅用一个简单的JavaSE project来模拟,但是已经足够提供完整的核心代码。
你可以从amqlog-client拿到源代码。

2.1.文件目录结构

1 pom.xml
2 src/main/resources/
3 |---- log4j.properties # 配置日志输出地点,及ActiveMQ的相关参数
4 |---- jndi.properties # 配置topic
5 src/main/java/
6 |---- cn.sinobest.asj.logclient
7 |---- LogProducer.java # 生成并输出日志

2.2.文件内容

2.2.1. pom.xml

 1 <project xmlns="http://maven.apache.org/POM/4.0.0"
2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4 <modelVersion>4.0.0</modelVersion>
5 <groupId>cn.sinobest.asj</groupId>
6 <artifactId>amqlog-client</artifactId>
7 <version>0.0.1-SNAPSHOT</version>
8 <name>Simple app to send log to ActiveMQ</name>
9 <description>模拟一般的应用系统,通过log4j发送日志到ActiveMQ</description>
10 <dependencies>
11 <!-- use to write log -->
12 <dependency>
13 <groupId>log4j</groupId>
14 <artifactId>log4j</artifactId>
15 <version>1.2.17</version>
16 </dependency>
17 <dependency>
18 <groupId>commons-logging</groupId>
19 <artifactId>commons-logging</artifactId>
20 <version>1.1.1</version>
21 </dependency>
22 <!-- use to import class org.apache.activemq.jndi.ActiveMQInitialContextFactory
23 to write log to ActiveMQ -->
24 <dependency>
25 <groupId>org.apache.activemq</groupId>
26 <artifactId>activemq-client</artifactId>
27 <version>5.13.2</version>
28 </dependency>
29 </dependencies>
30 </project>

2.2.2. log4j.properties

 1 # define the stand out appender
2 log4j.appender.stdout=org.apache.log4j.ConsoleAppender
3 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
4 log4j.appender.stdout.layout.ConversionPattern=[%-5p] %-d{yyyy-MM-dd HH:mm:ss z}%n %m%n%n
5
6 # define the jms appender
7 log4j.appender.jms=org.apache.log4j.net.JMSAppender
8 log4j.appender.jms.InitialContextFactoryName=org.apache.activemq.jndi.ActiveMQInitialContextFactory
9 log4j.appender.jms.ProviderURL=tcp://localhost:61616
10 # TopicBindingName可以自由配置,只需要确保提供对应的jndi属性即可
11 log4j.appender.jms.TopicBindingName=topicName
12 # TopicConnectionFactoryBindingName目前不能自由配置
13 log4j.appender.jms.TopicConnectionFactoryBindingName=ConnectionFactory
14
15 # define the logger
16 log4j.rootLogger=INFO, stdout, jms

注意:log4j.appender.jms.ProviderURL的值必须和ActiveMQ的监听地址一致。

2.2.3. jndi.properties

topic.topicName=demo
注意:key的后半部分(topicName)必须与log4j.properties中的log4j.appender.jms.TopicBindingName一致。
属性间的对应关系

2.2.4. LogProducer.java

 1 package cn.sinobest.asj.logclient;
2 import org.apache.commons.logging.Log;
3 import org.apache.commons.logging.LogFactory;
4 public class LogProducer {
5 private static final Log log = LogFactory.getLog(LogProducer.class);
6 /**
7 * @param args
8 */
9 public static void main(String[] args) {
10 log.debug("this is a debug message.");
11 log.info("this is a info message.");
12 log.warn("this is a warn message.");
13 log.error("this is a error message");
14 System.exit(0);
15 }
16 }
说明:debug的内容不会发送到ActiveMQ。

测试


    1. 启动ActiveMQ
      cd到ActiveMQ的解压缩目录,在cmd执行bin\activemq start
    2. 部署Log Server到Tomcat并启动
    3. 运行Log Client的LogProducer main方法
    4. Log Server的Console会有:

基于ActiveMQ的统一日志服务的更多相关文章

  1. AMQ学习笔记 - 15. 实践方案:基于ActiveMQ的统一日志服务

    概述 以ActiveMQ + Log4j + Spring的技术组合,实现基于消息队列的统一日志服务. 参考:Spring+Log4j+ActiveMQ实现远程记录日志——实战+分析 与参考文章的比较 ...

  2. 基于Log4Net本地日志服务简单实现

    背景 项目开发中,我们或多或少会使用诸如NLog,Log4Net,Kafka+ELK等等日志套件: 基于关注点分离原则,业务开发的时候不应该关注日志具体实现:并且后续能方便切换其他日志套件: 这里先实 ...

  3. 基于日志服务的GrowthHacking(1):数据埋点和采集(APP、Web、邮件、短信、二维码埋点技术)

    数据质量决定运营分析的质量 在上文中,我们介绍了GrowthHacking的整体架构,其中数据采集是整个数据分析的基础,只有有了数据,才能进行有价值的分析:只有高质量的数据,才能驱动高质量的运营分析. ...

  4. go-zero docker-compose 搭建课件服务(九):http统一返回和集成日志服务

    0.索引 go-zero docker-compose 搭建课件服务(九):http统一返回和集成日志服务 0.1源码地址 https://github.com/liuyuede123/go-zero ...

  5. 基于Flume的美团日志收集系统(一)架构和设计

    美团的日志收集系统负责美团的所有业务日志的收集,并分别给Hadoop平台提供离线数据和Storm平台提供实时数据流.美团的日志收集系统基于Flume设计和搭建而成. <基于Flume的美团日志收 ...

  6. 基于Flume的美团日志收集系统(一)架构和设计【转】

    美团的日志收集系统负责美团的所有业务日志的收集,并分别给Hadoop平台提供离线数据和Storm平台提供实时数据流.美团的日志收集系统基于Flume设计和搭建而成. <基于Flume的美团日志收 ...

  7. 转:基于Flume的美团日志收集系统(一)架构和设计

    美团的日志收集系统负责美团的所有业务日志的收集,并分别给Hadoop平台提供离线数据和Storm平台提供实时数据流.美团的日志收集系统基于Flume设计和搭建而成. <基于Flume的美团日志收 ...

  8. 基于Flume的美团日志收集系统 架构和设计 改进和优化

    3种解决办法 https://tech.meituan.com/mt-log-system-arch.html 基于Flume的美团日志收集系统(一)架构和设计 - https://tech.meit ...

  9. Spring MVC 中使用AOP 进行统一日志管理--注解实现

    1.AOP简介 AOP称为面向切面编程 AOP的基本概念 (1)Aspect(切面):通常是一个类,里面可以定义切入点和通知 (2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的 ...

随机推荐

  1. 【windows核心编程】一个API拦截的例子

    API拦截 修改PE文件导入段中的导入函数地址 为 新的函数地址 这涉及PE文件格式中的导入表和IAT,PE文件中每个隐式链接的DLL对应一个IMAGE_IMPORT_DESCRIPTOR描述符结构, ...

  2. [.NET源码学习]实例化Font,遭遇字体不存在的情况。

    实例化Font类时,当传入参数为不存在或未安装的字体时,Windows系统会用Microsoft Sans Serif字体替代该字体. Msdn: "For more information ...

  3. mybatis系列-05-SqlMapConfig.xml详解

    mybatis的全局配置文件SqlMapConfig.xml,配置内容如下: properties(属性) settings(全局配置参数) typeAliases(类型别名) typeHandler ...

  4. Hadoop 2.6.0 POM.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...

  5. 快速备份sqlserver2005以上版本数据库的方法-摘自网络

    使用优化参数的备份命令 BACKUP DATABASE [test]TO DISK = N'D:\test_FULL_20110311_050001_1.bak',DISK = N'D:\test_F ...

  6. Java多线程编程模式实战指南:Active Object模式(下)

    Active Object模式的评价与实现考量 Active Object模式通过将方法的调用与执行分离,实现了异步编程.有利于提高并发性,从而提高系统的吞吐率. Active Object模式还有个 ...

  7. keil中编译时出现*** ERROR L107: ADDRESS SPACE OVERFLOW

    解决方法: http://zhidao.baidu.com/link?url=DWTVVdALVqPtUt0sWPURD6c1eEppyu9CXocLTeRZlZlhwHOA1P1xdesqmUQNw ...

  8. hdu 1689 Just a Hook

    http://acm.hdu.edu.cn/showproblem.php?pid=1698 Just a Hook Time Limit: 4000/2000 MS (Java/Others)    ...

  9. TypeScript学习笔记(三):类

    类 在TypeScript中,类似于C#的结构,即一个文件中可以存在多个类,且文件名可以任意取,我们先看一个简单的类的示例. class Person { private name: string; ...

  10. linux使用getopt解析参数

    getopt是linux下解析命令行参数的api.以linux内核代码的一个例子来说明:   static void cmdline(int argc, char *argv[]){    int o ...