云日志服务Java SDK (结构化日志上报)
云日志服务SDK提供了Java语言上报结构化日志的一系列方法,方便用户直接使用编码方式上报结构化日志到云日志服务后台。
传输协议
HTTPS
使用前提
- 参考注册华为账号并开通华为云中操作,完成注册。
- 确认云日志服务的区域,请用户根据所在区域,选择RegionName。
- 获取华为账号的AK/SK。
- 获取华为云账号的项目ID(project id),详细步骤请参见“我的凭证 > API凭证”。
- 获取需要上报到LTS的日志组ID和日志流ID。
- 已安装Java开发环境。云日志服务Java SDK支持JDK1.8及以上,您可以执行java –version命令检查您已安装的Java版本。如未安装,可以从Java官方网站下载安装包进行安装。
使用说明
- 当用户修改权限后,权限信息在一天后生效。
- SDK支持跨云/本地上报日志,当前仅支持华北-北京四、华东-上海一、华南-广州、西南-贵阳一。使用详情见Appender配置参数说明表中的“enableLocalTest”参数,当该参数为true时,上报日志规格为单个机器200次/秒(即每秒只能发送200次,每次批量发送数量/大小详情见参数“batchSizeThresholdInBytes、batchCountThreshold、lingerMs”)。
- 通过SDK上报日志到LTS的时间相距当前时间不超过2天,否则上报日志会被LTS删除。
注意事项
由于Java-SDK默认对SK明文存储,不符合某些对于安全有更高要求的用户,lts提供了一种用户自定义的加解密方式,建议用户优先使用加解密方式。
加密过程如下:
- 用户编写一个java类,比如com.demo.DecryptDemo类,在该类中增加一个解密方法,比如decrypt方法,输入和输出均为字符串。
- 编写decrypt的方法内容,客户自行实现SK加解密算法,返回解密后的值。
- 当用户调用Java-SDK初始化时,会需要传入SK,这时使用DecryptDemo.decrypt方法即可。
安装SDK
您可以通过以下两种方式安装日志服务Java SDK。
方式一:在Maven项目中加入依赖项(推荐方式)。
- maven构建时,settings.xml文件的mirrors节点需要增加华为外部开源仓。如下:
<mirror> <id>huaweicloud</id> <mirrorOf>*</mirrorOf> <url>https://repo.huaweicloud.com/repository/maven/</url> </mirror>
- 您可以在华为外部开源仓中获取日志服务Java SDK依赖的最新版本,仅支持1.0.3及以上版本。
- 在Maven工程中使用日志服务Java SDK,只需在pom.xml中加入相应依赖即可,Maven项目管理工具会自动下载相关JAR包。
<dependency> <groupId>io.github.huaweicloud</groupId> <artifactId>lts-sdk-common</artifactId> <version>此功能在1.0.3版本以上支持,建议在第2步中获取最新版本</version> </dependency> <dependency> <groupId>io.github.huaweicloud</groupId> <artifactId>lts-sdk-java</artifactId> <version>此功能在1.0.3版本以上支持,建议在第2步中获取最新版本</version> </dependency>
方式二:在项目中直接依赖Java SDK的jar包。
- 下载lts-sdk-common和lts-sdk-java包。(建议使用最新版本的jar包。)
- 请确保您的项目中有以下依赖,因为SDK的jar包中需要该依赖。
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.83</version> </dependency> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>2.10.14</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.11</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.13</version> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>30.1.1-jre</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.11.0</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>2.0.7</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>2.0.7</version> </dependency>
- 以0.6.75版本的IntelliJ IDEA为例:项目中导入JAR包
- 在IntelliJ IDEA中选择您的工程,选择File > Project Structure。
- 在Project Structure对话框,左侧单击Modules。
- 在Dependencies页签,选择+ > JARs or directories。
- 在Attach Files or Directories对话框中,选中已下载的JAR文件,单击OK。
示例代码
import java.util.ArrayList; import java.util.List; import com.alibaba.fastjson.JSONObject; import com.huaweicloud.lts.appender.JavaSDKAppender; import com.huaweicloud.lts.producer.Producer; import com.huaweicloud.lts.producer.exception.ProducerException; import com.huaweicloud.lts.producer.model.log.StructLog; import com.huaweicloud.lts.producer.model.log.StructLogItem; public class JavaSdkStructLogPush implements Runnable { /* 此结构体为一次批量上报结构化日志 { // 所用日志共用的自定义label "labels" : { "label" : "label" }, // 批量日志 "logs" : [ { // 构建一批日志,这批日志共用time,即它们都是此time上报的日志 "contents" : [ // 构建一条日志, { "k1" : "v1", "k2" : "v2", "content" : "log content1" },{ "k3" : "v3", "k4" : "v4", "content" : "log content2" } ], "time" : 1721784021037 },{ "contents" : [ { "k5" : "v5", "k6" : "v6", "content" : "log content3" } ], "time" : 1721784021038 }, ], // 所有日志共用的采集路径 "path" : "path", // 所有日志共用的来源 "source" : "source" } */ @Override public void run() { /* 认证用的ak和sk硬编码到代码中或者明文存储都有很大的安全风险, 建议在配置文件或者环境变量中密文存放, 使用时解密, 确保安全; 本示例以ak和sk保存在环境变量中为例, 运行本示例前请先在本地环境中设置环境变量HUAWEICLOUD_SDK_AK和HUAWEICLOUD_SDK_SK. */ String ak = System.getenv("HUAWEICLOUD_SDK_AK"); String sk = System.getenv("HUAWEICLOUD_SDK_SK"); // 构建appender JavaSDKAppender appender = JavaSDKAppender.custom() // 华为云账号的项目ID(project id) .setProjectId("project id") // 华为云账号的AK .setAccessKeyId(ak) // 华为云账号的SK .setAccessKeySecret(sk) // 云日志服务的区域 .setRegionName("region name") // 单个Appender能缓存的日志大小上限 .setTotalSizeInBytes(104857600) // producer发送日志时阻塞时间 .setMaxBlockMs(0L) // 执行日志发送任务的线程池大小 .setIoThreadCount(8) // producer发送单批日志量上限 .setBatchSizeThresholdInBytes(524288) // producer发送单批日志条数上限 .setBatchCountThreshold(4096) // producer发送单批日志等待时间 .setLingerMs(2000) // producer发送日志失败后重试次数 .setRetries(3) // 首次重试的退避时间 .setBaseRetryBackoffMs(2000L) // 重试的最大退避时间 .setMaxRetryBackoffMs(2000L) // 默认false, true: 可以跨云上报日志, false: 仅能在华为云ecs主机上报日志 //.setEnableLocalTest(false) .builder(); // 获取发送producer Producer producer = appender.getProducer(); while (true) { try { // 构建批量结构化日志 StructLogItem structLog = getStructLogItem(); // 发送日志 (日志组ID,日志流ID,日志) producer.send("日志组ID", "日志流ID", structLog); } catch (ProducerException | InterruptedException e) { e.printStackTrace(); } } } private StructLogItem getStructLogItem() { // 构建日志结构体 StructLogItem structLogItem = new StructLogItem(); // 设置此批日志公共标签 structLogItem.setLabels(getLabels()); // 添加日志List structLogItem.setLogs(getLogs()); // 设置此批日志公共路径 structLogItem.setPath("path"); // 设置此批日志公共来源 structLogItem.setSource("source"); return structLogItem; } private JSONObject getLabels() { JSONObject jsonObject = new JSONObject(); jsonObject.put("label", "label"); return jsonObject; } private List<StructLog> getLogs() { // 构建发送日志List,即每次可以发送多条日志 List<StructLog> logs = new ArrayList<>(); // 创建结构化日志 StructLog structLog = getStructLog(); // 添加一条结构化日志 logs.add(structLog); return logs; } private StructLog getStructLog() { StructLog structLog = new StructLog(); // 此条日志产生时间, 建议为当前时间ms值即可 structLog.setTime(System.currentTimeMillis()); // 构建日志List,即此List中的日志,均为此ms产生的日志 List<JSONObject> contents = new ArrayList<>(); // 创建一条日志 JSONObject ongLog = getOneLog(); contents.add(ongLog); // 添加日志 structLog.setContents(contents); return structLog; } private static JSONObject getOneLog() { JSONObject jsonObject = new JSONObject(); // 直接添加k-v结构 jsonObject.put("k1", "v1"); jsonObject.put("k2", "v2"); // 添加原始日志字段 content jsonObject.put("content", "log content"); return jsonObject; } }
单个producer性能基线
上报日志时,请参考如下参数的测试性能基线,若超出基线值,可能会导致日志上报异常。
- totalSizeInBytes:524288000
- ioThreadCount:8
- maxBlockMs:0
- batchSizeThresholdInBytes:524288
- batchCountThreshold:4096
- lingerMs:2000
按照参数基线值设置后,使用8U16GB的机器规格测试,上报单条日志大小为1KB。
测试结果:SDK上报日志的数据量为60MB/s,速率为6w条/s。
当日志上报量超过单个producer时:
- 建议拆分日志流,使用多个producer上报日志,分摊流量,以保障SDK处于正常上报状态。
- 如果maxBlockMs为0时,SDK处于非阻塞状态,会触发保护机制自动降级,可能会对部分日志做丢弃处理。
- 如果maxBlockMs大于0时,SDK处于阻塞状态,阻塞时间为maxBlockMs,可能会造成prodcuer.send()发送日志方法处于阻塞状态。
配置参数说明
- Appender中配置参数说明
表1 Appender配置参数说明表 参数名称
描述
类型
是否需要填写
默认值
projectId
华为云账号的项目ID(project id)。
String
必填
-
accessKeyId
华为云账号的AK。认证用的AK硬编码到代码中或者明文存储都有很大的安全风险,建议密文存放,使用时解密,确保安全。
String
必填
-
accessKeySecret
华为云账号的SK。认证用的SK硬编码到代码中或者明文存储都有很大的安全风险,建议密文存放,使用时解密,确保安全。
String
必填
-
regionName
云日志服务的区域。
String
必填
-
logGroupId
LTS的日志组ID。
String
必填
-
logStreamId
LTS的日志流ID。
String
必填
-
totalSizeInBytes
单个producer实例能缓存的日志大小上限。
int
选填
100M(100 * 1024 * 1024)
maxBlockMs
如果 producer 可用空间不足,调用者在 send 方法上的最大阻塞时间,单位为毫秒。默认为 60 秒(60000毫秒),建议为0秒。
- 当maxBlockMs值>=0时,则阻塞到设置的时间,如果到达阻塞时间,还是不能获取到内存,即报错且丢弃日志。
- 当maxBlockMs值=-1时,则一直阻塞到发送成功,且不会丢弃日志。
long
选填
60秒(60000毫秒),建议值0ms
ioThreadCount
执行日志发送任务的线程池大小。
int
选填
客户机器空闲CPU数量,但一定大于1
batchSizeThresholdInBytes
当一个 ProducerBatch 中缓存的日志大小大于等于 batchSizeThresholdInBytes 时,该 batch 将被发送。
int
选填
0.5M(512 * 1024)
batchCountThreshold
当一个 ProducerBatch 中缓存的日志条数大于等于 batchCountThreshold 时,该 batch 将被发送。
int
选填
4096
lingerMs
一个 ProducerBatch 从创建到可发送的逗留时间。
int
选填
2S
retries
如果某个 ProducerBatch 首次发送失败,能够对其重试的次数,建议为 5 次。如果 retries 小于等于 0,该 ProducerBatch 首次发送失败后将直接进入失败队列。
int
选填
10
baseRetryBackoffMs
首次重试的退避时间。
long
选填
0.1S
maxRetryBackoffMs
重试的最大退避时间。
long
选填
50S
enableLocalTest
是否开启跨云上报日志。
- 选true时,开启跨云后用户能通过公网(仅支持华北-北京四、华东-上海一、华南-广州、西南-贵阳一)访问(建议调测使用)。
- 选false时,关闭跨云后用户是通过华为云当前区域主机访问。
boolean
选填
false
- 日志上报StructLogItem类参数说明
表2 日志上报StructLogItem类参数说明表 参数名称
描述
类型
是否需要填写
logs
批量日志内容。
Array<StructLog>
是
labels
此批日志共用的自定义标签
JSONObject
否
source
此批日志共用的日志来源
String
否
path
此批日志共用的采集路径
String
否
- 日志上报StructLog类参数说明
参数名称
描述
类型
是否需要填写
time
日志时间(单位:ms)
long
是
contents
日志内容,此List中的每条日志,LTS认为他们都属于此time,即此time时,上报了多条日志
Array<JSONObject>
是
参数获取方式
- 区域表
区域名称
RegionName
华北-北京二
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:单击日志组名称对应的按钮,鼠标悬浮在日志流名称上,可查看日志流名称和日志流ID。