我已经在不同类型的项目中使用过log4j,并且有一些使用log4j2的经验。所有实现都使用默认的附加器和布局。目前,我需要写一个应用程序写在json格式。因此,我通过设置一个非常简单的log4j2记录器来尝试log4j2 JSONLayout布局。
public class JSONLogger {
private static final Logger LOGGER = LogManager.getLogger();
public static void main(String[] args) {
JSONLogger jsonlogger = new JSONLogger() ;
}
public JSONLogger() {
LOGGER.log(Level.FATAL, "hi mum!") ;
int val1 = 10, val2 = 11, val3 = 12;
LOGGER.log(Level.FATAL,"val1={}, val2={}, val3={}", val1, val2, val3);
}
}
jsonLoggerProperties.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="DEBUG">
<Properties>
<Property name="log-path">/Users/petervannes/NetBeansProjects/JSONLogger/logfiles</Property>
</Properties>
<Appenders>
<RollingFile name="json_file_appender" fileName="${log-path}/jsonlogger.json"
filePattern="${log-path}/%d{yyyyMMdd}_jsonlogger-%i.json" >
<JSONLayout complete="true" compact="false"/>
<Policies>
<SizeBasedTriggeringPolicy size="1 KB" />
</Policies>
<DefaultRolloverStrategy max="4"/>
</RollingFile>
</Appenders>
<Loggers>
<root level="debug" additivity="false">
<AppenderRef ref="json_file_appender"/>
</root>
</Loggers>
</Configuration>
导致类似于的日志条目;
, {
"timeMillis" : 1474573600359,
"thread" : "main",
"level" : "FATAL",
"loggerName" : "JSONLogger",
"message" : "val1=10, val2=11, val3=12",
"contextStack" : [ "fieldName2" ],
"endOfBatch" : false,
"loggerFqcn" : "org.apache.logging.log4j.spi.AbstractLogger",
"threadId" : 1,
"threadPriority" : 5
}
我需要的是像这样的JSON格式的日志;
, {
"DateTime" : "08/01/2016 21:33:22.334",
"level" : "FATAL",
"Summary" : "Something has gone wrong",
"ChainManager" : "Manager A",
"Optionals" : { "Key_1": "Value1",
"Key_2": "Value2" }
}
在log4j2 JSONLayout中可以这样做吗?或者有没有其他布局可以用来获得这种格式?
发布于 2018-05-18 01:08:06
问题是关于使用log4j2编写自定义json消息。
从log4j2版本2.11开始,这是可能的:
https://issues.apache.org/jira/browse/LOG4J2-2190
for JSONLayout的新参数称为
objectMessageAsJsonObject
。示例项目文件;
log4j2.properties
status = error
appender.ana_whitespace.type = RollingFile
appender.ana_whitespace.name = ana_whitespace
appender.ana_whitespace.fileName = ${sys:es.logs.base_path:-target}${sys:file.separator}ana_whitespace.log
appender.ana_whitespace.layout.type = JsonLayout
appender.ana_whitespace.layout.propertiesAsList = false
appender.ana_whitespace.layout.compact = false
appender.ana_whitespace.layout.eventEol = true
appender.ana_whitespace.layout.objectMessageAsJsonObject = true
appender.ana_whitespace.layout.complete= true
appender.ana_whitespace.layout.properties= true
appender.ana_whitespace.filePattern = ${sys:es.logs.base_path:-target}${sys:file.separator}ana_whitespace-%d{yyyy-MM-dd}.log
appender.ana_whitespace.filter.1.type = MarkerFilter
appender.ana_whitespace.filter.1.onMismatch=DENY
appender.ana_whitespace.filter.1.onMatch=ACCEPT
appender.ana_whitespace.filter.1.marker=ANA_WHITESPACE
appender.ana_whitespace.policies.type = Policies
appender.ana_whitespace.policies.time.type = TimeBasedTriggeringPolicy
appender.ana_whitespace.policies.time.interval = 1
appender.ana_whitespace.policies.time.modulate = true
appender.ana_whitespace.policies.size.type = SizeBasedTriggeringPolicy
appender.ana_whitespace.policies.size.size = 10 MB
rootLogger.level = info
rootLogger.appenderRef.ana_whitespace.ref = ana_whitespace
示例Java代码
package de.es.stemmer;
import java.io.IOException;
import java.util.Map;
import java.util.TreeMap;
import org.apache.http.client.ClientProtocolException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.message.ObjectMessage;
public class JsonLoggerTest {
final static Logger log = LogManager.getLogger(JsonLoggerTest.class);
final static Marker MARKER_WHITESPACE = MarkerManager.getMarker("ANA_WHITESPACE");
public static void main(String[] args) throws ClientProtocolException, IOException {
System.setProperty("es.logs.base_path", "target");
System.setProperty("es.logs.cluster_name", "_cluster");
LoggerContext.getContext().reconfigure();
ThreadContext.put("orig", "MDC_origValue");
ThreadContext.put("source", "MDC_sourceSnippet");
Map<String, String> map = new TreeMap<>();
map.put("orig", "msg_origValue");
map.put("source", "msg_sourceSnippet");
ObjectMessage msg = new ObjectMessage(map);
log.info(MARKER_WHITESPACE, msg);
ThreadContext.remove("orig");
ThreadContext.remove("source");
}
}
JSON日志条目
[
{
"thread" : "main",
"level" : "INFO",
"loggerName" : "de.es.stemmer.JsonLoggerTest",
"marker" : {
"name" : "ANA_WHITESPACE"
},
"message" : {
"orig" : "msg_origValue",
"source" : "msg_sourceSnippet"
},
"endOfBatch" : false,
"loggerFqcn" : "org.apache.logging.log4j.spi.AbstractLogger",
"instant" : {
"epochSecond" : 1526576578,
"nanoOfSecond" : 184000000
},
"contextMap" : {
"orig" : "MDC_origValue",
"source" : "MDC_sourceSnippet"
},
"threadId" : 1,
"threadPriority" : 5
}
]
发布于 2020-05-12 09:41:01
如果您正在寻找一种方法来生成自定义的JSON日志消息,并且没有任何由log4j2添加的“噪声”,那么您可以创建Message
接口的实现并使用不同的布局-例如PatternLayout
。下面是此方法的一个示例:
首先是一个实现Message
接口的类
import java.util.HashMap;
import java.util.Map;
import org.apache.logging.log4j.message.Message;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class JSONMessage implements Message {
private static final long serialVersionUID = 538439258494853324L;
private String messageString;
private static final Gson GSON = new GsonBuilder()
.setPrettyPrinting()
.create();
public JSONMessage(){
this(null);
}
public JSONMessage(Object msgObj){
parseMessageAsJson(msgObj);
}
public JSONMessage(String msgStr){
Map<String,String> msgObj = new HashMap<>();
msgObj.put("message", msgStr);
parseMessageAsJson(msgObj);
}
private void parseMessageAsJson(Object msgObj){
messageString = GSON.toJson(msgObj);
}
@Override
public String getFormattedMessage() {
return messageString;
}
@Override
public String getFormat() {
return messageString;
}
@Override
public Object[] getParameters() {
return null;
}
@Override
public Throwable getThrowable() {
return null;
}
}
接下来是log4j2.xml配置:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" name="App">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%m%n" />
</Console>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>
现在是一个简单的应用程序类,用于生成日志事件
import java.util.HashMap;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class App {
private static final Logger logger = LogManager.getLogger();
public static void main( String[] args )
{
HashMap<String,Object> msgMap = new HashMap<>();
msgMap.put("someInt", 123);
msgMap.put("note", "Maybe you put a message here");
HashMap<String,Object> anotherMap = new HashMap<>();
anotherMap.put("key1", "value1");
anotherMap.put("key2", "value2");
msgMap.put("map", anotherMap);
logger.info(new JSONMessage(msgMap));
}
}
以下是一些示例输出:
{
"note": "Maybe you put a message here",
"map": {
"key1": "value1",
"key2": "value2"
},
"someInt": 123
}
注意,我使用Gson来创建JSON输出,但是您可以使用所需的任何库。还要注意,此代码不会生成“完整的”JSON,因为它不会在日志的开头和结尾添加方括号,也不会在消息对象之间添加逗号。
发布于 2016-09-24 18:28:07
我找到了一个适合我的解决方案:slf4j-json-logger。它是一个slf4j框架,所以应该包含在pom.xml中。示例项目文件;
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.reddipped</groupId>
<artifactId>JSONLogger_2</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.6</maven.compiler.source>
<maven.compiler.target>1.6</maven.compiler.target>
<mainClass>com.reddipped.jsonlogger_2.Test</mainClass>
<slf4j.version>1.7.21</slf4j.version>
<!-- current log4j 2 release -->
<log4j.version>2.6.2</log4j.version>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- Binding for Log4J -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>${log4j.version}</version>
</dependency>
<!-- Log4j API and Core implementation required for binding -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
</dependency>
<!-- Logger slf4j-json-logger -->
<dependency>
<groupId>com.savoirtech.logging</groupId>
<artifactId>slf4j-json-logger</artifactId>
<version>2.0.2</version>
</dependency>
</dependencies>
</project>
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
Use java property log4j.configurationFile to specify log4j2.xml location
if not available in classpath
- Dlog4j.configurationFile="/Users/petervannes/NetBeansProjects/JSONLogger_2/src/mann/java/resources/log4j2.xml"
-->
<configuration status="trace">
<Properties>
<Property name="log-path">/Users/petervannes/NetBeansProjects/JSONLogger_2/logfiles</Property>
</Properties>
<appenders>
<RollingFile name="RollingFile" fileName="${log-path}/jsonlogger.json"
filePattern="${log-path}/%d{yyyyMMdd}_jsonlogger-%i.json" >
<PatternLayout>
<pattern>%m%n</pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="1 KB" />
</Policies>
<DefaultRolloverStrategy max="4"/>
</RollingFile>
</appenders>
<Loggers>
<Logger name="JSONLogger" level="debug" additivity="false">
<AppenderRef ref="RollingFile" />
</Logger>
<Root level="debug">
<AppenderRef ref="RollingFile" />
</Root>
</Loggers>
</configuration>
示例Java代码
package com.reddipped.jsonlogger_2;
import com.savoirtech.logging.slf4j.json.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
/**
*
* @author petervannes
*/
public class Test {
public static void main(String[] args) {
Test t = new Test() ;
}
public Test() {
LoggerFactory.setIncludeLoggerName(false);
LoggerFactory.setDateFormatString("yyyy-MM-dd HH:mm:ss.SSS");
com.savoirtech.logging.slf4j.json.logger.Logger LOGGER = LoggerFactory.getLogger("JSONLogger");
Map<String, String> optionalFields = new HashMap();
optionalFields.put("CaseNumber", "C12.12343");
optionalFields.put("Step","Assignment") ;
optionalFields.put("Department","BPM") ;
String LOB = "Business Administration" ;
String Service = "DocumentService" ;
String Process = "AddAttachements" ;
String Reason = "Technical" ;
LOGGER.error().message("Conversion error 'incompatible PDF document'")
.field("LOB",LOB)
.field("Service", Service)
.field("Process",Process)
.field("Reason", Reason)
.map("OptionalFields", optionalFields).log() ;
}
}
JSON日志条目
{
"message": "Conversion error 'incompatible PDF document'",
"LOB": "Business Administration",
"Service": "DocumentService",
"Process": "AddAttachements",
"Reason": "Technical",
"OptionalFields": {
"Step": "Assignment",
"Department": "BPM",
"CaseNumber": "C12.12343"
},
"level": "ERROR",
"thread_name": "main",
"class": "com.reddipped.jsonlogger_2.Test",
"@timestamp": "2016-09-23 10:18:06.623"
}
https://stackoverflow.com/questions/39647900
复制相似问题