背景
在分布式系统中,我们有多个web app,这些web app可能分别部署在不同的物理服务器上,并且有各自的日志输出。当生产问题来临时,很多时候都需要去各个日志文件中查找可能的异常,相当耗费人力。日志存储多以文本文件形式存在,当有需求需要对日志进行分析挖掘时,这个处理起来也是诸多不便,而且效率低下。
系统的侵入性低。二是因为它与大型的关系型数据库相比有很多优势,比如查询快速、bson存储结构利于扩展、免费等。
解决方案
整合mongodb和log4j
1、安装mongodb数据库,并在本地启动,默认端口是27017,详细请参考:玩转mongodb(一):初识mongodb
2、新建一个maven(maven版本要求3.0以上)工程,选择maven-archetype-quickstart,工程名:log4j2mongo
3、在pom.xml文件中,添加log4j、log4mongo-java、mongo-java-driver三个依赖。具体代码如下:
1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3 <modelVersion>4.0.0</modelVersion>
4
5 <groupId>com.manyjar</groupId>
6 <artifactId>log4j2mongo</artifactId>
7 <version>0.0.1-SNAPSHOT</version>
8 <packaging>jar</packaging>
9
10 <name>log4j2mongo</name>
11 <url>http://maven.apache.org</url>
12
13 <properties>
14 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
15 <junit.version>3.8.1</junit.version>
16 <log4j.version>1.2.17</log4j.version>
17 <log4mongo.version>0.7.4</log4mongo.version>
18 <mongo-java-driver.version>2.8.0</mongo-java-driver.version>
19 </properties>
20
21 <dependencies>
22 <dependency>
23 <groupId>junit</groupId>
24 <artifactId>junit</artifactId>
25 <version>${junit.version}</version>
26 <scope>test</scope>
27 </dependency>
28
29 <dependency>
30 <groupId>log4j</groupId>
31 <artifactId>log4j</artifactId>
32 <version>${log4j.version}</version>
33 </dependency>
34
35 <dependency>
36 <groupId>org.log4mongo</groupId>
37 <artifactId>log4mongo-java</artifactId>
38 <version>${log4mongo.version}</version>
39 </dependency>
40
41 <dependency>
42 <groupId>org.mongodb</groupId>
43 <artifactId>mongo-java-driver</artifactId>
44 <version>${mongo-java-driver.version}</version>
45 </dependency>
46 </dependencies>
47 </project>
pom.xml
4、在resources文件夹中,添加log4j.properties文件。文件中主要添加log4j对mongodb的适配器org.log4mongo.MongoDbAppender。这里的适配器是log4mongo-java这个jar包提供。mongodb数据库的ip:127.0.0.1,port:27017,库名:logs,集合名:log。具体配置如下:
1 log4j.rootLogger=DEBUG,MongoDB
2 log4j.appender.MongoDB=org.log4mongo.MongoDbAppender
3 log4j.appender.MongoDB.databaseName=logs
4 log4j.appender.MongoDB.collectionName=log
5 log4j.appender.MongoDB.hostname=127.0.0.1
6 log4j.appender.MongoDB.port=27017
7
8 log4j.appender.stdout=org.apache.log4j.ConsoleAppender
9 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
10 log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n
log4j.properties
5、在java文件夹中,com.manyjar.log4j2mongo这个包中,添加Main.java文件,观察文件中的代码可以发现,和我们平时用log4j来写日志一模一样,把日志流到mongodb这件事情,对业务开发的程序员完全透明。具体代码如下:
1 package com.manyjar.log4j2mongo;
2
3 import org.apache.log4j.Logger;
4
5 import com.mongodb.BasicDBObject;
6 import com.mongodb.DBObject;
7
8 public class Main {
9
10 public static void main(String[] args) {
11 Logger logger = Logger.getLogger(Main.class);
12
13 for (int i = 0; i < 10000000; i++) {
14 DBObject bson = new BasicDBObject();
15 bson.put("name", "ryan"+i);
16 logger.debug(bson);
17 }
18 }
19 }
Main.java
6、步骤5中,我们执行了1000万次的日志插入,数据结构如下:
默认的数据量大小有10G:
这里,我们可以看到,日志的数据存储量相对不小。如果需要修改日志数据的存储结构,可以用log4mongo的源代码进行二次开发。
如果数据量过大,我们可以用TTL索引(过期自动删除)或固定集合大小两种方式来解决:
TTL索引:db.log_events.createIndex({
"timestamp"
: 1},{expireAfterSeconds: 60*60*24*30})
将log集合修改成固定大小集合:db.runCommand({"convertToCapped":"log",size:10000})。