# structlog4j
**Repository Path**: ibit-tech/structlog4j
## Basic Information
- **Project Name**: structlog4j
- **Description**: 结构化日志
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-06-04
- **Last Updated**: 2020-12-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# structlog4j
结构化日志对于日志的收集的作用挺大的,借鉴了[jacek99/structlog4j](https://github.com/jacek99/structlog4j),根据自身的业务场景,基于`SLF4J`实现了`structlog4j`。
## 相关引用
### Gradle
```
// 基础包
compile 'tech.ibit:structlog4j-api:1.2'
// 支持json, yaml格式等扩展
compile 'tech.ibit:structlog4j-extend:1.2'
```
### Maven
```xml
tech.ibit
structlog4j-api
1.2
tech.ibit
structlog4j-extend
1.2
```
## 概述
structlog4j的核心思想就是将日志已key-value的方式呈现,方便日期切分。
### 日志保留字段
```
_message: 消息内容
_errorMessage: 异常信息
_stackTrace: 异常stack trace信息
```
### 字符串处理
业务需要,将日志单行输入,所以对以下字符进行了处理, ":"前原字符串,":" 后的是处理后的字符
```
\t: \\t
\r: \\r
\n: \\n
```
### 引入logger
```java
import tech.ibit.structlog4j.Logger;
import tech.ibit.structlog4j.StructLoggerFactory;
private static final Logger log = StructLoggerFactory.getLogger(Test.class);
```
### 默认日志格式(key\-value)
```
_message=Something error!&user=ibit-tech_errorMessage=Test Exception
```
**说明**
* 默认方式引入`structlog4j-api`即可
* `key-value`的方式通过`&`进行分割,将`&`转为`'%26'`
### json日志格式
```json
{"_message":"Something error!","user":"ibit-tech","_errorMessage":"Test Exception"}
```
**修改全局formatter方法**:
```
方法1(java代码):
StructLog4J.setFormatter(JsonFormatter.getInstance());
方法2(classpath:/structlog4j.properties):
formatter=tech.ibit.structlog4j.extend.JsonFormatter#getInstance
```
**说明**
* 需要引入`structlog4j-extend`
* "#"后面为获取实例方法
### yaml日志格式
```
hostname: localhost\nip: 127.0.0.1
```
**修改全局formatter方法**:
```
方法1(java代码):
StructLog4J.setFormatter(YamlFormatter.getInstance());
方法2(classpath:/structlog4j.properties):
formatter=tech.ibit.structlog4j.extend.YamlFormatter#getInstance
```
**说明**
* 需要引入`structlog4j-extend`
* "\\n":表示换行符号,读取到日志之后,需要将"\\n"转为"\n"才能正确显示
* "#"后面为获取实例方法
### 自定义日志格式
实现`tech.ibit.structlog4j.Formatter#format`方法即可
```
tech.ibit.structlog4j.Formatter {
/**
* 格式化(待实现)
*
* @param kvMap 兼职map
* @return 格式化后的文本
*/
String format(Map kvMap);
}
```
### 异常信息处理
* 默认方式,`StructLog4J.isTransStackTrace()` == `true`, 日志中会出现`_errorMessage`和`_stackTrace`字段,`_stackTrace`进行了转义,单行显示
* 当`StructLog4J.isTransStackTrace()` == `false`, 日志中只出现`_errorMessage`,然后之后就将异常信息在接下来的日志打印出来(多行)
**eg**:
```
# 单行打印stackTrace
_message=Something error&user=ibit-tech&_errorMessage=Test Exception&_stackTrace=java.lang.RuntimeException: Test Exception\n\tat tech.ibit.demo.structlog4j.Demo.main(Demo.java:32)\n
# 多行答应stackTrace
_message=Something error&user=ibit-tech&_errorMessage=Test Exception
java.lang.RuntimeException: Test Exception
at tech.ibit.demo.structlog4j.Demo.main(Demo.java:33)
```
**修改全局transStackTrace方法**:
```
方法1(java代码):
StructLog4J.setTransStackTrace(true|false);
方法2(classpath:/structlog4j.properties):
transStackTrace=true|false
```
### structlog4j.properties说明:
```
# 指定formatter 创建方式(工厂方法)
formatter=tech.ibit.structlog4j.extend.JsonFormatter#getInstance
# 指定异常的stackTrace日志是否需要转化
transStackTrace=true
```
## 用法
### \_message说明(以error为例子)
**Logger**存在一下方法支持**error**级别日志
```
/**
* ERROR日志
*
* @param message 消息
* @param params 参数
*/
void error(String message, Object... params);
/**
* ERROR日志
*
* @param messages 消息片段
* @param params 参数
*/
void error(Object[] messages, Object... params);
```
其中message和messages的区别在于,messages支持传入占位符,eg:
```
logger.error("Something error, id: 12, username: ibit-tech");
等价于:
logger.error(new Object[] {"Something error, id: {}, username: {}", 12, "ibit-tech"});
```
### 使用key-value的方式
```
log.error("Something error", "user", "ibit-tech", "age", 100);
```
### 实现`ToLog`对key-value进行包装
```
log.error("Something error", (ToLog) () -> new Object[] {"user", "ibit-tech", "age", 1.2});
```
### 异常处理
```
log.error("Something error", "user", "ibit-tech", "age", 100, new RuntimeException("Test Exception"));
```
### 混合使用
```
log.error("Something error", (ToLog) () -> new Object[] {"user", "ibit-tech"}, "age", 1.2);
log.error("Something error", (ToLog) () -> new Object[] {"user", "ibit-tech"}, "age", 1.2, (ToLog) () -> new Object[] {"city", "sz"}, new RuntimeException("Test Exception"));
```
### POJO实现`MapToLog`,toLog()会返回POJO中所有字段
```
@Test
public void toLog() {
User user = new User("ibit-tech", 21);
Assert.assertEquals("[name, ibit-tech, age, 21]", Arrays.asList(user.toLog()).toString());
}
@Value
public class User implements MapToLog {
private String name;
private int age;
}
```
**说明**
* 需要引入`structlog4j-extend`
## License
Apache License 2.0