# aliyun-log-logback-appender
**Repository Path**: aliyun/aliyun-log-logback-appender
## Basic Information
- **Project Name**: aliyun-log-logback-appender
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2025-05-08
- **Last Updated**: 2025-06-11
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Logback Appender
[](https://travis-ci.org/aliyun/aliyun-log-logback-appender)
[](/LICENSE)
[README in English](/README.md)
## Aliyun Log Logback Appender
Logback是由log4j创始人设计的又一个开源日志组件。通过使用Logback,您可以控制日志信息输送的目的地是控制台、文件、GUI 组件、甚至是套接口服务器、NT 的事件记录器、UNIX Syslog 守护进程等;您也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,您能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
通过Aliyun Log Logback Appender,您可以控制日志的输出目的地为阿里云日志服务,写到日志服务中的日志的样式如下:
```
level: ERROR
location: com.aliyun.openservices.log.logback.example.LogbackAppenderExample.main(LogbackAppenderExample.java:18)
message: error log
throwable: java.lang.RuntimeException: xxx
thread: main
time: 2018-01-02T03:15+0000
log: 2018-01-02 11:15:29,682 ERROR [main] com.aliyun.openservices.log.logback.example.LogbackAppenderExample: error log
__source__: xxx
__topic__: yyy
```
其中:
+ level 日志级别。
+ location 日志打印语句的代码位置,可以通过配置关闭此选项。
+ message 日志内容。
+ throwable 日志异常信息(只有记录了异常信息,这个字段才会出现)。
+ thread 线程名称。
+ time 日志打印时间(可以通过 timeFormat 或 timeZone 配置 time 字段呈现的格式和时区)。
+ log 自定义日志格式(只有设置了 encoder,这个字段才会出现)。
+ \_\_source\_\_ 日志来源,用户可在配置文件中指定。
+ \_\_topic\_\_ 日志主题,用户可在配置文件中指定。
## 功能优势
+ 日志不落盘:产生数据实时通过网络发给服务端。
+ 无需改造:对已使用logback应用,只需简单配置即可采集。
+ 异步高吞吐:高并发设计,后台异步发送,适合高并发写入。
+ 上下文查询:服务端除了通过关键词检索外,给定日志能够精确还原原始日志文件上下文日志信息。
## 版本支持
* logback 1.2.3
* aliyun-log-producer 0.3.8
* protobuf-java 2.5.0
## 配置步骤
### 1. maven 工程中引入依赖
```
com.google.protobuf
protobuf-java
2.5.0
com.aliyun.openservices
aliyun-log-logback-appender
0.1.28
```
### 2. 修改配置文件
以xml型配置文件`logback.xml`为例(不存在则在项目根目录创建),配置Loghub相关的appender与 Logger,例如:
```
your project endpoint
your accesskey id
your accesskey
your project
your logStore
your topic
your source
104857600
0
8
524288
4096
2000
10
100
50000
%d %-5level [%thread] %logger{0}: %msg
yyyy-MM-dd'T'HH:mmZ
UTC
true
true
${accessKeyId}
${accessKeySecret}
500
```
**注意**:
+ 为了防止进程退出时,LoghubAppender缓存在内存中的少量数据丢失,请记得加上`DelayingShutdownHook`标签。
+ LoghubAppender在运行过程中产生的异常会被捕获并放入logback的`BasicStatusManager`类中,您可以通过配置`OnConsoleStatusListener`或其他方式查看出错信息。参阅:https://logback.qos.ch/access.html
## 参数说明
Aliyun Log Logback Appender 可供配置的属性(参数)如下,其中注释为必选参数的是必须填写的,可选参数在不填写的情况下,使用默认值。
```
#日志服务的 project 名,必选参数
project = [your project]
#日志服务的 logstore 名,必选参数
logStore = [your logStore]
#日志服务的 HTTP 地址,必选参数
endpoint = [your project endpoint]
#用户身份标识,必选参数
accessKeyId = [your accesskey id]
accessKeySecret = [your accessKeySecret]
#单个 producer 实例能缓存的日志大小上限,默认为 100MB。
totalSizeInBytes=104857600
#如果 producer 可用空间不足,调用者在 send 方法上的最大阻塞时间,默认为 60 秒。为了不阻塞打印日志的线程,强烈建议将该值设置成 0。
maxBlockMs=0
#执行日志发送任务的线程池大小,默认为可用处理器个数。
ioThreadCount=8
#当一个 ProducerBatch 中缓存的日志大小大于等于 batchSizeThresholdInBytes 时,该 batch 将被发送,默认为 512 KB,最大可设置成 5MB。
batchSizeThresholdInBytes=524288
#当一个 ProducerBatch 中缓存的日志条数大于等于 batchCountThreshold 时,该 batch 将被发送,默认为 4096,最大可设置成 40960。
batchCountThreshold=4096
#一个 ProducerBatch 从创建到可发送的逗留时间,默认为 2 秒,最小可设置成 100 毫秒。
lingerMs=2000
#如果某个 ProducerBatch 首次发送失败,能够对其重试的次数,默认为 10 次。
#如果 retries 小于等于 0,该 ProducerBatch 首次发送失败后将直接进入失败队列。
retries=10
#该参数越大能让您追溯更多的信息,但同时也会消耗更多的内存。
maxReservedAttempts=11
#首次重试的退避时间,默认为 100 毫秒。
#Producer 采样指数退避算法,第 N 次重试的计划等待时间为 baseRetryBackoffMs * 2^(N-1)。
baseRetryBackoffMs=100
#重试的最大退避时间,默认为 50 秒。
maxRetryBackoffMs=50000
#指定日志主题,默认为 "",可选参数
topic = [your topic]
#指的日志来源,默认为应用程序所在宿主机的 IP,可选参数
source = [your source]
#输出到日志服务的时间的格式,默认是 yyyy-MM-dd'T'HH:mmZ,可选参数
timeFormat = yyyy-MM-dd'T'HH:mmZ
#输出到日志服务的时间的时区,默认是 UTC,可选参数(如果希望 time 字段的时区为东八区,可将该值设定为 Asia/Shanghai)
timeZone = UTC
#是否要记录 Location 字段(日志打印位置),默认为 true,如果希望减少该选项对性能的影响,可以设为 false
includeLocation = true
#当 encoder 不为空时,是否要包含 message 字段,默认为 true
includeMessage = true
# 可选项,exception 堆栈最大记录长度,超出此长度会被截断,默认值为 500 -->
maxThrowable=500
# 写入处理器,默认为 "",可选参数
processor = [ingest processor]
```
参阅:https://github.com/aliyun/aliyun-log-producer-java
## 自定义凭证提供者 CredentialsProvider
logback-appender 支持您自定义凭证提供者 `CredentialsProvider`。通过实现凭证获取接口,您能够灵活地实现访问密钥 (AK) 凭证的动态轮换等高级功能。
> 一旦启用自定义 `CredentialsProvider` 后,就无需再额外配置静态凭证参数(AccessKeyId/AccessKeySecret/SecurityToken),系统将通过您提供的 `CredentialsProvider` 自动获取 AK 凭证。。
1. 创建一个类(例如 `MyCredentialsProvider`),并实现 `CredentialsProvider` 接口,来支持动态获取 AK 凭证,请确保该实现是线程安全的。
> 为了优化性能,建议 `getCredentials` 方法在内部缓存 AK 凭证,并确保在缓存即将过期之前主动刷新。
```java
class MyCredentialsProvider implements CredentialsProvider {
@Override
public synchronized Credentials getCredentials() {
// 获取 AK 与缓存 AK 的逻辑
}
// 构造函数
MyCredentialsProvider(String param1, long paramField2) {}
}
```
2. 创建一个类(比如叫 `MyBuilder`),并实现 `CredentialsProviderBuilder` 接口。
- `getCredentialsProvider` 方法应该在每次调用时都返回一个新的 `CredentialsProvider` 实例。
```java
class MyBuilder implements CredentialsProviderBuilder {
@Override
public CredentialsProvider getCredentialsProvider() {
return new MyCredentialsProvider(param1, paramField2);
}
private String param1;
private long paramField2;
// 自定义参数 param1
public void setParam1(String param1) {
this.param1 = param1;
}
// 自定义参数 paramField2
public void setParamField2(long paramField2) {
this.paramField2 = paramField2;
}
}
```
3. 在 logback 的配置文件中,设置 `credentialsProviderBuilder` 的 class 属性为您的自定义类的全限定名,例如 `com.example.MyBuilder`,并根据需要添加自定义参数。
```xml
hello
123
```
### 自定义参数
若需向 `MyBuilder` 类提供自定义参数,如 `param1` 或 `paramField2`,您应在该类中定义相应的 setter 方法,例如 `setParam1` 和 `setParamField2`。
```java
class MyBuilder implements CredentialsProviderBuilder {
private String param1;
private long paramField2;
public void setParam1(String param1) {
this.param1 = param1;
}
public void setParamField2(long paramField2) {
this.paramField2 = paramField2;
}
// 省略其他方法
}
```
然后在 logback 的配置文件中,`credentialsProviderBuilder` 选项下,为自定义参数配置参数值即可。
```xml
hello
123
```
## 使用实例
项目中提供了一个名为`com.aliyun.openservices.log.logback.LogbackAppenderExample`的实例,它会加载resources目录下的`logback.xml`文件进行logback配置。
**logback.xml样例说明**
+ 配置了三个appender:loghubAppender1、loghubAppender2、STDOUT。
+ loghubAppender1:将日志输出到project=test-proj,logstore=store1。输出WARN、ERROR级别的日志。
+ loghubAppender2:将日志输出到project=test-proj,logstore=store2。只输出INFO级别的日志。
+ STDOUT:将日志输出到控制台。由于没有对日志级别进行过滤,会输出root中配置的日志级及以上的所有日志。
[LogbackAppenderExample.java](/src/main/java/com/aliyun/openservices/log/logback/example/LogbackAppenderExample.java)
[logback-example.xml](/src/main/resources/logback-example.xml)
## 错误诊断
如果您发现数据没有写入日志服务,可通过如下步骤进行错误诊断。
1. 检查配置文件 logback.xml 是否限定了 appender 只输出特定级别的日志。比如,是否设置了 root 或 logger 的 level 属性,是否在 appender 中设置了 [filter](https://logback.qos.ch/manual/filters.html)。
2. 检查您项目中引入的 protobuf-java,aliyun-log-logback-appender 这两个 jar 包的版本是否和文档中`maven 工程中引入依赖`部分列出的 jar 包版本一致。
3. 通过观察控制台的输出来诊断您的问题。Aliyun Log Logback Appender 会将 appender 运行过程中产生的异常写入 `ch.qos.logback.core.BasicStatusManager` 中。您可以通过配置 statusListener 来获取 BasicStatusManager 中的数据。例如,`` 会将 BasicStatusManager 中的数据输出到控制台。
4. 请检查您的 `logback.xml` 中是否包含选项 ``。数据会定期异步地发往服务端,加上此选项可以保证您的程序在正常退出时,内存中缓存的数据不丢失。
## 常见问题
**Q**:使用Pandora Boot+Spring Boot 启动异常退出?
**A**:将logback.xml 改成 logback-spring.xml
**Q**:在debug模式下,大量打印十六进制信息,程序异常退出?
**A**:在configuration标签中加入:
```
```
**Q**:是否支持自定义 log 格式?
**A**:在 0.1.12 及以上版本新增了 log 字段。您可以通过在 encoder 中设置 pattern 来自定义 log 格式,例如:
```
%d %-5level [%thread] %logger{0}: %msg
```
log 输出样例:
```
log: 2018-07-15 21:12:29,682 INFO [main] TestAppender: info message.
```
**Q**:日志中为何没有 time 字段?
**A**:0.1.6 以及之前的版本的 LogItem 没有包含 time 字段,请升级至最新版本。
**Q**:用户可以自定义 source 字段的取值吗?
**A**:0.1.8 以及之前的版本不支持,在这些版本中 source 字段会被设置成应用程序所在宿主机的 IP。在最新的版本中,您可以参考上面的配置文件指定 source 的取值。
**Q**: 如何采集宿主机 IP?
**A**: 不要在 logback.xml 中设置 source 字段的值,这种情况下 source 字段会被设置成应用程序所在宿主机的 IP。
**Q**:在网络发生异常的情况下,`aliyun-log-logback-appender` 会如何处理待发送的日志?
**A**:`aliyun-log-logback-appender` 底层使用 `aliyun-log-producer-java` 发送数据。producer 会根据您在配置文件中设置的 `retryTimes` 进行重试,如果超过 `retryTimes` 次数据仍没有发送成功,会将错误信息输出,并丢弃该条日志。关于如何查看错误输出,可以参考错误诊断部分。
**Q**:如何关闭某些类输出的日志?
**A**:通过在 logback.xml 文件中添加 `` 可屏蔽相应包下日志的输出。
例如,当您在 logback.xml 文件中添加如下内容会屏蔽 package 名为 `com.aliyun.openservices.log.producer.inner` 下所有类的日志输出。
```
```
**Q**:应用初始化时出现这样的信息 `A number (N) of logging calls during the initialization phase have been intercepted and are now being replayed. These are subject to the filtering rules of the underlying logging system.`?
**A**:该信息只会在日志系统初始化阶段产生,并不影响后续日志记录的功能。
当应用首次调用`LoggerFactory.getLogger()`方法时,日志系统进入初始化流程。初始化流程还未结束,再次调用`LoggerFactory.getLogger()`方法便会出现上述信息。这时,slf4j 会创建替代记录器(substitute loggers)并返回。在完成初始化后,替代记录器(substitute loggers)会将日志记录请求委托给合适的 logger。
`aliyun-log-logback-appender` 的依赖库 `aliyun-log-producer-java` 也会使用 slf4j 记录日志,所以会出现上述信息。
参阅:https://www.slf4j.org/codes.html#replay
**Q**:如果想设置 `time` 字段的时区为东八区或其他时区,该如何指定 `timeZone` 的取值?
**A**:当您将 `timeZone` 指定为 `Asia/Shanghai` 时,`time` 字段的时区将为东八区。timeZone 字段可能的取值请参考 [java-util-timezone](http://tutorials.jenkov.com/java-date-time/java-util-timezone.html)。
**Q**:为什么程序在运行时会抛出`java.lang.InterruptedException`?
**A**:aliyun-log-logback-appender 会调用 [Producer.send()](https://github.com/aliyun/aliyun-log-java-producer/blob/master/src/main/java/com/aliyun/openservices/aliyun/log/producer/Producer.java#L16) 方法发送数据。执行 send() 方法的线程如果被中断了,如调用了 Thread.interrupted() 方法,就会抛出这样的异常。
调用 [Producer.send()](https://github.com/aliyun/aliyun-log-java-producer/blob/master/src/main/java/com/aliyun/openservices/aliyun/log/producer/Producer.java#L16) 方法所属的线程和您调用 LOGGER.info() 打印日志的线程是相同的线程,请检查您的程序在何时会调用 Thread.interrupted() 方法。
## 贡献者
[@lionbule](https://github.com/lionbule) [@zzboy](https://github.com/zzboy) 对项目作了很大贡献。
感谢 [@lionbule](https://github.com/lionbule) [@zzboy](https://github.com/zzboy) 的杰出工作。