对于分布式系统,提供一个集中式的日志监控平台是非常有必要的,具体参见笔者前面的一片文章:日志监控系统。这里介绍一下客户端要怎么使用。

首先需要配置pom.xml,引入logging-client包:

<dependency>
	<groupId>com.baidu.global.mobile.server.logging.client</groupId>
	<artifactId>logging-client</artifactId>
	<version>1.0.0</version>
</dependency>

方式一:通过log4j

# Remote Log Server
log4j.appender.remote=com.baidu.global.mobile.server.logging.client.AsyncSocketAppender
log4j.appender.remote.Port=4560
log4j.appender.remote.RemoteHost=10.242.112.38,10.242.116.27,10.242.117.36
log4j.appender.remote.Application=guanxing
#log4j.appender.remote.threadPoolSize=2
#log4j.appender.remote.loadBalancerName=WRR
log4j.appender.remote.Threshold=ERROR

然后在对于想要集中日志的logger配置该appender,比如

# Global logging configuration
log4j.rootLogger=WARN,console, system, remote

# My logging(Application) logging configuration
log4j.logger.com.baidu.global.mobile.server.guanxing=info, guanxing, remote
log4j.additivity.com.baidu.global.mobile.server.guanxing=false

NOTE

  1. 注意配置好你的Application,不要混淆了。
  2. 如果rootLogger和应用Logger都配置了AsyncSocketAppender,那么注意配置应用的Logger的additivity配置为false,否则会记录两次。

方式二:应用直接调用接口发送

通过log4j可以在一定程度上对应用透明,但是其实log4j并不是很灵活。所以你也可以选择直接发送日志给logging-server。接口很简单:

package com.baidu.global.mobile.server.logging.client;

import com.baidu.global.mobile.server.logging.common.LoggingMessage;

public interface Logger {
	public void log(LoggingMessage loggingMessage);

	public void destroy();
}

你可以通过LoggerFactory获取:

package com.baidu.global.mobile.server.logging.client;

/**
 * <pre>
 * 因为Agent的本身是有线程池和网络连接池,开销比较大,不适合于每次都New一个,最好是一个应用共用一个,所以提供这么一个单例工厂方法。
 * 
 * 建议如果使用Spring的话,直接在Spring配置就可以了。默认就是单例,而且可以很方便的注入。
 * 
 * <bean id="logger"
 * 		class="com.baidu.global.mobile.server.logging.client.LogClient">
 * 		<constructor-arg value="classpath:${env}_logger.xml" />
 * </bean>
 * 
 * </pre>
 * 
 * @author argan
 */
public class LoggerFactory {
	private static volatile Logger instance = null;

	public static Logger getInstance(String configLocation) {
		if (instance == null) {
			synchronized (LoggerFactory.class) {
				if (instance == null) {
					instance = new LogClient(configLocation);
				}
			}
		}
		return instance;
	}

	public static Logger getInstance(LoggerConfig config) {
		if (instance == null) {
			synchronized (LoggerFactory.class) {
				if (instance == null) {
					instance = new LogClient(config);
				}
			}
		}
		return instance;
	}

}

获取方式很简单:

Logger logClient = LoggerFactory.getInstance("classpath:logger.xml");

或者Spring配置:

<bean id="logger"
  		class="com.baidu.global.mobile.server.logging.client.LogClient">
 		<constructor-arg value="classpath:${env}_logger.xml" />
 	</bean>

其中logger.xml配置如下:

<logger>
	<region>HK</region>
	<application>monitor</application>
	<threadPoolSize>2</threadPoolSize>
	<loadBalancerName>WRR</loadBalancerName>
	<servers>10.242.112.38,10.242.116.27,10.242.117.36</servers>
	<endpoints>
		<endpoint>
			<host>10.242.112.38</host>
			<port>4567</port>
			<weight>5</weight>
			<maxFails>1</maxFails>
			<failTimeout>10</failTimeout>
			<timeout>2</timeout>
		</endpoint>
		<endpoint>
			<host>10.242.116.27</host>
			<port>4567</port>
		</endpoint>
		<endpoint>
			<host>10.242.117.36</host>
			<port>4567</port>
		</endpoint>
	</endpoints>
</logger>

LoggingMessage定义如下:

public String env; // optional
public long timestamp; // optional
public String host;

public String application; 

public String threadName; // optional
public String locationInfo; // optional
public String level; // required
public String message; // optional
public String stackTrace; // optional	

可以看到这里其实就是log4j的LogEvent定义,所以其实还是有点语言相关的,要做成通用的可以把stackTrace之类的字段改成detail之类的通用名称。

– That’s all. –