利用logback封装了输出日志到oracle、mysql等主流关系型数据库的适配器来把日志实时输出到mongodb

       为了后期的日志统计分析方便,需要把日志保存到数据库,logback封装了输出日志到oracle、mysql等主流关系型数据库的适配器,但由于考虑mongoDB非关系数据库的存取速度和性能比较好以及可以满足日志存储的需求,所以需要自定义实现一个mongoDB的适配器,把日志输出到mongoDB。目前logback配置根据操作日志、性能日志、系统异常日志和sql日志定义四种适配器输出,分别输出到mongoDB的四个集合:log_invokelog_performancelog_exceptionlog_execsql

 MongoDBAppender:自定义Mongodb输出类,用于logback输出方式的<appender>适配器扩展类,把日志自定义输出到mongodb数据库。

MongoDBAppenderBase:MongoDB日志输出扩展基础类,主要是初始化和映射logback.xml的属性来获取mongoDB的连接和collection数据集。

注意:需要在logback.xml引入自己系统的配置文件,在定义mongoDB适配器使用该配置文件的mongoDB配置信息定义数据库连接项。



大致适配器类代码示例:

package xxx.xxx.logstatistics.service;

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.StackTraceElementProxy;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.bson.Document;

import xxxx.logstatistics.consts.LogItemNames;
import xxxx.utils.CheckUtil;

/**
 * 
 * 
 * 类说明:自定义Mongodb输出类
 * 
 * @author 作者 wu
 * 
 */
public class MongoDBAppender extends MongoDBAppenderBase<ILoggingEvent>
{
	@Override
	protected Document toMongoDocument(ILoggingEvent eventObject){
		final Document doc = new Document();
		String marker = eventObject.getMarker().toString();
		doc.append("marker", marker);
		doc.append("date", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").
				format(new Date(eventObject.getTimeStamp())));
		//doc.append("logger", eventObject.getLoggerName());
		//doc.append("thread", eventObject.getThreadName());
		//doc.append("message", eventObject.getFormattedMessage());
		//获取异常日志的异常报错信息
		if(StringUtils.equals(LogItemNames.EXCEPTION_MARKER, marker)){
			StackTraceElementProxy[] stackTraceElementProxys = eventObject.getThrowableProxy().
					getStackTraceElementProxyArray().clone();
			String throwableMessage = eventObject.getThrowableProxy().getMessage();
			int proxySize = stackTraceElementProxys.length;
			if(proxySize > 0){
				StringBuilder sb = new StringBuilder();
				sb.append(eventObject.getThrowableProxy().getClassName());
				sb.append(throwableMessage!=null?":"+throwableMessage:"");
				for(int i = 0;i < proxySize;i++){
					StackTraceElementProxy stackTraceElementProxy = stackTraceElementProxys[i];
					sb.append(',');
					sb.append(stackTraceElementProxy.toString());
				}
				doc.append("exception", sb.toString());
			}
		}
		Map<String, String> mdc = eventObject.getMDCPropertyMap();
		if (mdc != null && !mdc.isEmpty()){
			doc.append("requestUrl", mdc.get(LogItemNames.REQUEST_URI));
			doc.append("methodName", mdc.get(LogItemNames.METHOD_NAME));
			doc.append("args", mdc.get(LogItemNames.ARGS));
			doc.append("userId", mdc.get(LogItemNames.USER_ID));
			doc.append("ip", mdc.get(LogItemNames.CLIENT_ID));
			doc.append("description", mdc.get(LogItemNames.DESCRIPTION));
			//获取性能日志的请求处理时间
			if(StringUtils.equals(LogItemNames.PERFORMANCE_MARKER, marker)){
				doc.append("elapseTime", Long.parseLong(!CheckUtil.isNullorEmpty(mdc.get(LogItemNames.ELAPSE_TIME))?
						mdc.get(LogItemNames.ELAPSE_TIME):"0"));
			}
			//获取SQL日志的sql类型和表名
			if(StringUtils.equals(LogItemNames.SQL_MARKER, marker)){
				doc.append("sql", mdc.get(LogItemNames.SQL));
				doc.append("table", mdc.get(LogItemNames.TABLE));
			}
			
		}
		return doc;
	}

}
package xxx.xxx.logstatistics.service;

import ch.qos.logback.core.UnsynchronizedAppenderBase;
import java.net.UnknownHostException;
import org.bson.Document;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.ServerAddress;
import com.mongodb.client.ListIndexesIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;

/**
 * 类说明:logback的日志扩展基础类
 *
 * @author 作者 wu
 *
 */
public abstract class MongoDBAppenderBase<E>
					extends UnsynchronizedAppenderBase<E> {

		private MongoClient mongoClient;
		private MongoDatabase mongoDataBase;
		private MongoCollection<Document> mongoCollection;
    private String host = "localhost";
    private int port = 27017;
    private String dbName = "logname";
    private String collectionName="logEvents";
    private Integer timeOut=null;
    //保存的数据库用户名密码,暂时不需要
    @SuppressWarnings("unused")
		private String username;
    @SuppressWarnings("unused")
		private String password;

    @Override
    public void start() {
        try {
            connectToMongoDB();
            super.start();
        } catch (UnknownHostException e) {
            addError("Error connecting to MongoDB server: " + host + ":" + port, e);
        }
    }

    private void connectToMongoDB() throws UnknownHostException {
    	MongoClientOptions.Builder options=new MongoClientOptions.Builder();
    	if(timeOut!=null && timeOut>0)
    		options.serverSelectionTimeout(timeOut);
    	mongoClient = new MongoClient(new ServerAddress(host, port),options.build());
    	mongoDataBase = mongoClient.getDatabase(dbName);
    	mongoCollection = mongoDataBase.getCollection(collectionName);
    	//获取所有索引列表
    	ListIndexesIterable<Document> indexList = mongoCollection.listIndexes();
    	//判断mongodb的日志集合是否存在date字段索引,不存在则自动创建该字段索引
    	boolean isCreatedDateIndex = false;
    	for (Document document : indexList) {
    		Document doc = (Document)document.get("key");
    		if(doc.get("date") != null){
    			isCreatedDateIndex = true;
    		}
    	}
    	if(!isCreatedDateIndex){
    		//建立索引
      	mongoCollection.createIndex(new Document("date",-1));
    	}
    }

    protected abstract Document toMongoDocument(E event);

    @Override
    protected void append(E eventObject) {
    	Document document = toMongoDocument(eventObject);
    	mongoCollection.insertOne(document);
    }

    @Override
    public void stop() {
        if (mongoClient != null)
        	mongoClient.close();
        super.stop();
    }

    public void setHost(String host) {
        this.host = host;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public void setDbName(String dbName) {
        this.dbName = dbName;
    }

    public void setCollectionName(String collectionName) {
        this.collectionName = collectionName;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以通过在logback.xml文件中添加一个Appender,将日志输出到JTextArea。以下是一个示例logback.xml配置: ```xml <?xml version="1.0" encoding="UTF-8"?> <configuration> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <appender name="jtextArea" class="com.example.logback.JTextAreaAppender"> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern> </layout> </appender> <root level="info"> <appender-ref ref="console" /> <appender-ref ref="jtextArea" /> </root> </configuration> ``` 其中,`class`为`com.example.logback.JTextAreaAppender`的`jtextArea`是自定义的Appender,用于将日志输出到JTextArea中。可以通过以下代码实现: ```java public class JTextAreaAppender extends AppenderBase<ILoggingEvent> { private static final Map<String, JTextArea> jTextAreaMap = new ConcurrentHashMap<>(); private String loggerName; public void setLoggerName(String loggerName) { this.loggerName = loggerName; } public static void addJTextArea(String name, JTextArea jTextArea) { jTextAreaMap.put(name, jTextArea); } public static void removeJTextArea(String name) { jTextAreaMap.remove(name); } @Override protected void append(ILoggingEvent event) { if (event.getLoggerName().equals(loggerName)) { for (JTextArea jTextArea : jTextAreaMap.values()) { SwingUtilities.invokeLater(() -> jTextArea.append(event.getFormattedMessage() + "\n")); } } } } ``` 在Swing应用程序中,可以在JTextArea上调用`setDocument()`方法,将其传递给`JTextAreaAppender`,并将Appender添加到logback.xml配置文件中: ```java public class MyApp extends JFrame { public MyApp() { JTextArea jTextArea = new JTextArea(); JScrollPane scrollPane = new JScrollPane(jTextArea); JTextAreaAppender.addJTextArea("myapp", jTextArea); Logger logger = (Logger) LoggerFactory.getLogger("myapp"); logger.addAppender(JTextAreaAppender.getInstance("myapp")); // ... } // ... } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值