
# 云日志服务LogBack SDK
云日志服务Java SDK提供了与logback适配的扩展插件，可以直接在logback中配置华为云appender，将通过logback产生的日志直接上报至云日志服务。
#### 传输协议
HTTPS
#### 使用前提
- 参考[注册华为账号并开通华为云](https://support.huaweicloud.com/usermanual-account/account_id_001.html)中操作，完成注册。
- 确认云日志服务的区域，请用户根据所在区域，选择RegionName。
- [获取华为账号的AK/SK](https://support.huaweicloud.com/iam_faq/iam_01_0618.html)。
- 获取华为云账号的项目ID（project id），详细步骤请参见[API凭证](https://support.huaweicloud.com/usermanual-ca/ca_01_0002.html)。
- 获取需要上报到LTS的[日志组ID]和[日志流ID]。
- 已安装Java开发环境。云日志服务Java SDK支持JDK1.8及以上，您可以执行**java --version** 命令检查您已安装的Java版本。如未安装，可以从[Java官方网站下载安装包](https://www.oracle.com/java/technologies/)进行安装。
- SDK支持跨云/本地上报日志，当前仅支持华北-北京四、华东-上海一、华南-广州、西南-贵阳一。
- 支持将logback.xml变为logback-spring.xml（SpringBoot），且读取springProfile中的配置。
- 支持读取logback.xml、logback-spring.xml中的自定义标签。
- 通过LogBack SDK上报日志到LTS的时间相距当前时间不超过2天，否则上报日志会被LTS删除。
- 建议设置上报周期小于1分钟（例如50秒）上报一次，设置1分钟或超过1分钟上报一次，可能会出现连接失败，因为SDK连接默认1分钟超时。
 
#### 安装SDK
在Maven项目中加入依赖项。
1. 使用Maven构建项目时，settings.xml文件的mirrors节点需要增加[华为外部开源仓](https://repo1.maven.org/maven2/io/github/huaweicloud/)。如下：
   ```
   <mirror>
       <id>huaweicloud</id>
       <mirrorOf>*</mirrorOf>
       <url>https://repo.huaweicloud.com/repository/maven/</url>
   </mirror>
   ```
   
2. 您可以在[华为外部开源仓](https://repo1.maven.org/maven2/io/github/huaweicloud/)中获取云日志服务LogBack SDK依赖的最新版本。
3. 在Maven工程中使用云日志服务LogBack SDK，只需在pom.xml中加入相应依赖即可，Maven项目管理工具会自动下载相关JAR包。在\<dependencies\>中加入如下内容：
   推荐使用最新版本version：1.1.3，第2步中查看SDK版本。
   ```
   <dependency> 
        <groupId>io.github.huaweicloud</groupId> 
        <artifactId>lts-sdk-common</artifactId> 
        <version>version</version> 
   <exclusions>
           <exclusion>
               <groupId>org.slf4j</groupId>
               <artifactId>slf4j-simple</artifactId>
           </exclusion>
       </exclusions>
    </dependency> 
    <dependency> 
        <groupId>io.github.huaweicloud</groupId> 
        <artifactId>lts-sdk-logback</artifactId> 
        <version>version</version> 
    </dependency>
   ```
   
 
#### 示例代码
1. 编写logback.xml、logback-spring.xml中LogbackSDKAppender，示例如下：
   ```
   <configuration scan="true" debug="false"> 
      <appender name="LogInfoTest" class="com.huaweicloud.lts.appender.LogbackSDKAppender"> 
        <!--  华为云账号的项目ID（project id）  --> 
        <projectId>xxxxxxxxxxxxxxxxxxxxxx</projectId> 
        <!--  华为云日志服务日志组ID  --> 
        <logGroupId>xxxxxxxxxxxxxxxxxxxxxx</logGroupId> 
        <!--  华为云日志服务日志流ID  --> 
        <logStreamId>xxxxxxxxxxxxxxxxxxxxxx</logStreamId> 
        <!--  华为云账号的AK, 认证用的AK硬编码到代码中或者明文存储都有很大的安全风险, 建议密文存放, 使用时解密, 确保安全  --> 
        <accessKeyId>xxxxxxxxxxxxxxxxxxxxxx</accessKeyId> 
        <!--  华为云账号的SK, 认证用的SK硬编码到代码中或者明文存储都有很大的安全风险, 建议密文存放, 使用时解密, 确保安全  --> 
        <accessKeySecret>xxxxxxxxxxxxxxxxxxxxxx</accessKeySecret> 
        <!--  云日志服务的区域  --> 
        <regionName>cn-nxxxxx</regionName> 
        <encoder> 
          <pattern>%d %-5level [%thread] [%customerParam] %logger{0}: %msg</pattern> 
        </encoder> 
        <!--  单个Appender能缓存的日志大小上限  --> 
        <totalSizeInBytes>104857600</totalSizeInBytes> 
        <!--  producer发送日志时阻塞时间  --> 
        <maxBlockMs>0</maxBlockMs> 
        <!--  执行日志发送任务的线程池大小  --> 
        <ioThreadCount>8</ioThreadCount> 
        <!--  producer发送单批日志量上限  --> 
        <batchSizeThresholdInBytes>524288</batchSizeThresholdInBytes> 
        <!--  producer发送单批日志条数上限  --> 
        <batchCountThreshold>4096</batchCountThreshold> 
        <!--  producer发送单批日志等待时间  --> 
        <lingerMs>2000</lingerMs> 
        <!--  producer发送日志失败后重试次数  --> 
        <retries>5</retries> 
        <!--  首次重试的退避时间  --> 
        <baseRetryBackoffMs>500</baseRetryBackoffMs> 
        <!--  重试的最大退避时间  --> 
        <maxRetryBackoffMs>500</maxRetryBackoffMs> 
        <!-- 默认false, true: 可以跨云上报日志, false: 仅能在华为云ecs主机上报日志 -->
        <enableLocalTest>false</enableLocalTest>
        <!-- 超过1M的日志, 拆分后放弃1M以外的 -->         
        <!-- <giveUpExtraLongSingleLog>true</giveUpExtraLongSingleLog>--> 
        <!-- 是否使用日志组/日志流名称上报日志-->  
        <!-- <logGroupStreamByName>false</logGroupStreamByName>-->
      </appender> 
      <logger name="com.huawei.test.logback.info" level="INFO"> 
        <appender-ref ref="LogInfoTest"/> 
      </logger> 
    </configuration>
   ```
   
2. 编写代码中产生日志，示例如下：
   ```
   package com.huawei.test.logback.info; 
     
    import org.slf4j.Logger; 
    import org.slf4j.LoggerFactory; 
     
    public class TestLogBackAppenderInfo { 
     
        private static final Logger LOGGER = LoggerFactory.getLogger(TestLogBackAppenderInfo.class); 
     
        public void run() throws InterruptedException { 
            LOGGER.info("test~logback~~~info"); 
        } 
     
    }
   ```
   
 
#### producer性能基线
上报日志时，请参考如下参数的测试性能基线，若超出基线值，可能会导致日志上报异常。
**ECS虚拟机配置**：
- 实例规格：通用计算增强型 c7.xlarge.2
- CPU：4 vCPU
- 内存：8 GB
- 基准带宽：100 Mbit/s
- OS：Huawei Cloud EulerOS release 2.0
- JVM：OpenJDK 64-Bit Server VM (build 17.0.7+7, mixed mode)
**测试程序说明（单个producer）**：
- totalSizeInBytes: 104857600
- maxBlockMs：0
- batchSizeThresholdInBytes: 1048576
- batchCountThreshold：40960
- lingerMs：2000
- ioThreadCount：具体用例中调整

- JVM 初始堆/最大堆大小：1GB
- 发送日志总条数：100,000,000
- 发送日志总大小：约50GB
按照参数基线值设置后，使用华为云ECS机器作为日志上报环境，通过华为云内网服务入口进行上报。
**SDK上报性能基线测试结果参考：**
- 上报日志：测试中使用的单条日志大小约为550字节。为了模拟数据的随机性，测试使用的数据为随机字符串。

- 性能基线如下：
  表1性能基线 
  | IO 线程数量 | 数据吞吐量    | 数据吞吐速率  | CPU 使用率 |
  |:---|:---|:---|:---|
  | 2       | 8.4MB/S  | 1.7W条/s | 15%     |
  | 4       | 15.3MB/S | 3W条/s   | 29%     |
  | 6       | 21.5MB/S | 4.2W条/s | 36%     |
     
  
**总结如下**：
- CPU时间主要花费在对象的序列化和压缩上，在吞吐量较高的情况下CPU使用率比较高。但在日常环境中，单机数据流量均值为100KB/S，因此造成的CPU消耗几乎可以忽略不计。
- 增加IO线程数量可以显著提高吞吐量，尤其是当IO线程数量少于可用处理器个数时。
- 调整totalSizeInBytes对吞吐量影响不够显著，增加totalSizeInBytes会造成更多的CPU消耗，建议使用默认值。
- 当日志上报量超过单个producer时：
  1. 建议拆分日志流，使用多个producer上报日志，分摊流量，以保障SDK处于正常上报状态。
  
  2. 如果maxBlockMs为0时，SDK处于非阻塞状态，会触发保护机制自动降级，可能会对部分日志做丢弃处理。
  
  3. 如果maxBlockMs大于0时，SDK处于阻塞状态，阻塞时间为maxBlockMs，可能会造成SDK发送日志处于阻塞状态。
   
 
#### 配置参数说明
- Appender配置参数说明。
  表2Appender配置参数说明表 
  | 参数名称                      | 描述                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | 类型      | 是否需要填写 | 默认值                |
  |:---|:---|:---|:---|:---|
  | projectId                 | 华为云账号的项目ID（project id）。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            | String  | 必填     | -                  |
  | accessKeyId               | 华为云账号的AK。认证用的AK硬编码到代码中或者明文存储都有很大的安全风险，建议密文存放，使用时解密，确保安全。                                                                                                                                                                                                                                                                                                                                                                                                                                                           | String  | 必填     | -                  |
  | accessKeySecret           | 华为云账号的SK。认证用的SK硬编码到代码中或者明文存储都有很大的安全风险，建议密文存放，使用时解密，确保安全。                                                                                                                                                                                                                                                                                                                                                                                                                                                           | String  | 必填     | -                  |
  | regionName                | 云日志服务的区域。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          | String  | 必填     | -                  |
  | logGroupId                | LTS的日志组ID。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | String  | 必填     | -                  |
  | logStreamId               | LTS的日志流ID。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | String  | 必填     | -                  |
  | appName                   | 日志标签appName字段。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     | String  | 选填     | -                  |
  | pathFile                  | 日志标签pathFile字段。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | String  | 选填     | -                  |
  | totalSizeInBytes          | 单个producer实例能缓存的日志大小上限。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            | int     | 选填     | 104857600（即100MB）  |
  | maxBlockMs                | 如果producer可用空间不足，调用者在send方法上的最大阻塞时间，单位为毫秒。默认60000毫秒，建议0毫秒。 - 当maxBlockMs值\>=0时，则阻塞到设置的时间，如果到达阻塞时间，还是不能获取到内存，即报错且丢弃日志。  - 当maxBlockMs值=-1时，则一直阻塞到发送成功，且不会丢弃日志。   | long    | 选填     | 60000毫秒            |
  | ioThreadCount             | 执行日志发送任务的线程池大小。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | int     | 选填     | 客户机器空闲CPU数量，但一定大于1 |
  | batchSizeThresholdInBytes | 当一个ProducerBatch中缓存的日志大小大于等于batchSizeThresholdInBytes 时，该ProducerBatch缓存的日志将被发送到LTS。                                                                                                                                                                                                                                                                                                                                                                                                                               | int     | 选填     | 524288（即0.5MB）     |
  | batchCountThreshold       | 当一个ProducerBatch中缓存的日志条数大于等于batchCountThreshold时，该ProducerBatch缓存的日志将被发送到LTS。                                                                                                                                                                                                                                                                                                                                                                                                                                      | int     | 选填     | 4096               |
  | lingerMs                  | 一个ProducerBatch从创建到可发送的逗留时间。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       | int     | 选填     | 2s                 |
  | retries                   | 如果某个ProducerBatch首次发送失败，能够对其重试的次数，建议为5次。如果retries小于等于0，该ProducerBatch首次发送失败后将直接进入失败队列。                                                                                                                                                                                                                                                                                                                                                                                                                             | int     | 选填     | 10                 |
  | baseRetryBackoffMs        | 首次重试的退避时间。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | long    | 选填     | 0.1s               |
  | maxRetryBackoffMs         | 重试的最大退避时间。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | long    | 选填     | 50s                |
  | giveUpExtraLongSingleLog  | 超过1M的日志，拆分后丢弃大于1M的数据。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              | boolean | 选填     | false              |
  | enableLocalTest           | 是否开启跨云上报日志。（此功能仅适用于开发调测，对于上报性能不做保障） - 选true时，开启跨云后用户能通过公网（仅支持华北-北京四、华东-上海一、华南-广州、西南-贵阳一）访问。  - 选false时，关闭跨云后用户是通过华为云当前区域主机访问。                                    | boolean | 选填     | false              |
  | logGroupStreamByName      | 是否使用日志组/日志流名称上报日志（SDK版本最低必须为1.1.0支持此功能）。如果为true，表明使用名称上报，则logGroupId、logStreamId参数值分别填入日志组、日志流名称即可。                                                                                                                                                                                                                                                                                                                                                                                                                | boolean | 选填     | false              |
  | proxyIp                   | 使用自定义ip端口上报日志。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     | String  | 选填     | -                  |
     
  
- 如果是SpringBoot项目，则可以将logback.xml替换为logback-spring.xml，且支持读取springProfile中的配置，可以自由切换开发、测试等环境的日志采集环境。 使用说明如下：
  1. 在SpringBoot项目中的application.properties可以自由指定使用的配置项。 ![](https://support.huaweicloud.com/usermanual-lts/zh-cn_image_0000002235723885.png "点击放大")
     
  
  2. logback-spring.xml中配置
     ```
     <springProfile name="dev">
             <root level="INFO">
                 <appender-ref ref="customerAppender"/>
             </root>
         </springProfile>
     ```
     
     
   
- logback.xml支持logstash-logback-encoder功能。 在xml文件中可以新增logstash的appender，与LTS的appender平级即可，LTS-SDK不会影响logstash功能。
  ```
  <appender name="logStash" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <file>/root/lts/lts-logback-sdk-json.log</file>
      <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
          <fileNamePattern>logs/lts-logback-sdk-json.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
          <maxFileSize>200MB</maxFileSize>
          <maxHistory>30</maxHistory>
          <totalSizeCap>5GB</totalSizeCap>
      </rollingPolicy>
      <encoder class="net.logstash.logback.encoder.LogstashEncoder">
          <customFields>{"app":"LtsLogBackSdk"}</customFields>
          <includeContext>true</includeContext>
          <includeMdc>true</includeMdc>
          <includeStructuredArguments>true</includeStructuredArguments>
          <includeNonStructuredArguments>false</includeNonStructuredArguments>
          <includeTags>true</includeTags>
          <includeCallerData>true</includeCallerData>
          <shortenedLoggerNameLength>36</shortenedLoggerNameLength>
      </encoder>
  </appender>
  <logger name="com.huawei.log.LtsLogBackSdk" level="WARN">
      <appender-ref ref="logStash"/>
  </logger>
  ```
  
- 如果需要logback.xml、logback-spring.xml支持自定义标签，且将标签中的value打印到日志中。执行以下步骤：
  1. 需要继承ClassicConverter类，重写convert方法，返回值为自定义标签的value。
     ```
     public class CustomerParam extends ClassicConverter {
         @Override
         public String convert(ILoggingEvent iLoggingEvent) {
             return "自定义标签value";
         }
     }
     ```
     
  
  2. 在logback.xml或者logback-spring.xml中引用ClassicConverter类，使用%自定义标签的名称，然后就可以使用该标签了。
     ```
     <conversionRule conversionWord="customerParam" converterClass="com.huawei.test.logback.CustomerParam"/>
      
         <appender name="customer" class="com.huawei.appender.LogbackSDKAppender">
             <encoder>
                 <pattern>%d %-5level [%thread] [%customerParam] %logger{0}: %msg</pattern>
             </encoder>
         </appender>
     ```
     
   
 
#### 参数获取方法
- 区域表
  表3区域表 
  | 区域名称   | 区域             |
  |:---|:---|
  | 华北-北京二 | cn-north-2     |
  | 华北-北京四 | cn-north-4     |
  | 华北-北京一 | cn-north-1     |
  | 华东-上海二 | cn-east-2      |
  | 华东-上海一 | cn-east-3      |
  | 华南-广州  | cn-south-1     |
  | 华南-深圳  | cn-south-2     |
  | 西南-贵阳一 | cn-southwest-2 |
  | 亚太-新加坡 | ap-southeast-3 |
     
  
- 日志组ID：在云日志服务控制台，选择"日志管理"，鼠标悬浮在日志组名称上，可查看日志组名称和日志组ID。
- 日志流ID：单击日志组名称对应的![](https://support.huaweicloud.com/usermanual-lts/zh-cn_image_0000002200563796.png)按钮，鼠标悬浮在日志流名称上，可查看日志流名称和日志流ID。
 
