ae-tracking 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/dist/src/cli/init.js +1 -1
- package/package.json +1 -1
- package/skills/data-integration-helper/SKILL.md +198 -0
- package/skills/data-integration-helper/references/android_sdk_faq.md +179 -0
- package/skills/data-integration-helper/references/c_sdk_compilation.md +83 -0
- package/skills/data-integration-helper/references/c_sdk_faq.md +416 -0
- package/skills/data-integration-helper/references/cocoscreator_sdk_faq.md +123 -0
- package/skills/data-integration-helper/references/cpp_server_sdk_faq.md +365 -0
- package/skills/data-integration-helper/references/index.md +56 -0
- package/skills/data-integration-helper/references/ios_sdk_faq.md +118 -0
- package/skills/data-integration-helper/references/java_sdk_faq.md +406 -0
- package/skills/data-integration-helper/references/javascript_sdk_faq.md +129 -0
- package/skills/data-integration-helper/references/logbus2_guide.md +307 -0
- package/skills/data-integration-helper/references/logbus2_parser_plugin.md +346 -0
- package/skills/data-integration-helper/references/minigame_sdk_faq.md +115 -0
- package/skills/data-integration-helper/references/miniprogram_sdk_faq.md +118 -0
- package/skills/data-integration-helper/references/python_sdk_faq.md +232 -0
- package/skills/data-integration-helper/references/restful_api_notes.md +72 -0
- package/skills/data-integration-helper/references/sdk_log_guide.md +314 -0
- package/skills/data-integration-helper/references/sdk_usage_notes.md +105 -0
- package/skills/data-integration-helper/references/unity_sdk_faq.md +115 -0
- package/skills/generate-tracking-code/SKILL.md +33 -10
- package/skills/generate-tracking-code/references/client-sdk-insert.md +33 -0
- package/skills/generate-tracking-code/references/server-sdk-insert.md +29 -0
- package/skills/generate-tracking-code/references/snippet-delivery.md +14 -7
- package/skills/generate-tracking-plan/SKILL.md +2 -2
- package/wiki/te-docs/raw//346/216/245/345/205/245/346/214/207/345/215/227//345/256/242/346/210/267/347/253/257-sdk/ios.md +2 -2
- package/wiki/te-docs/raw//346/216/245/345/205/245/346/214/207/345/215/227//345/256/242/346/210/267/347/253/257-sdk/macos.md +1 -1
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
# LogBus2 使用建议
|
|
2
|
+
|
|
3
|
+
## 一、简介
|
|
4
|
+
|
|
5
|
+
LogBus2 是数数科技在原 LogBus 基础上,使用 Go 语言重新开发的日志同步工具。相比 LogBus1,具有以下优势:
|
|
6
|
+
|
|
7
|
+
- **内存占用更低**:减少至原先的五分之一(约 100-200M)
|
|
8
|
+
- **传输速度更快**:提升至 3-5万条/秒
|
|
9
|
+
- **运行更稳定**:logbus1在一些特殊场景下,文件缓存区修复难度较高
|
|
10
|
+
- **部署更简单**:无需 JDK 环境,直接运行
|
|
11
|
+
|
|
12
|
+
## 二、使用前准备
|
|
13
|
+
|
|
14
|
+
1. **数据格式转换**:将需要传输的数据转换成 TE 的数据格式,支持 TA 格式和神策格式
|
|
15
|
+
2. **确定数据源**:确定文件存放目录或 Kafka 地址与 topic
|
|
16
|
+
3. **磁盘空间**:相比 LogBus1,LogBus2 去掉了本地磁盘队列,磁盘占用更小
|
|
17
|
+
|
|
18
|
+
## 三、应用场景
|
|
19
|
+
|
|
20
|
+
- 使用数数服务端 SDK 中 LogConsumer 模式的用户
|
|
21
|
+
- 对数据准确性及维度要求较高的场景
|
|
22
|
+
- 需要传输大批量历史数据
|
|
23
|
+
- 需要数据分流到多个项目的场景
|
|
24
|
+
- 需要对接神策数据的场景
|
|
25
|
+
|
|
26
|
+
## 四、性能指标
|
|
27
|
+
|
|
28
|
+
| 指标 | 说明 |
|
|
29
|
+
|------|------|
|
|
30
|
+
| 传输速度 | 3-5万条/秒(单个LogBus) |
|
|
31
|
+
| 内存占用 | 约 100-200M |
|
|
32
|
+
| CPU 限制 | 支持 cpu_limit 配置 |
|
|
33
|
+
| 带宽占用 | 峰值约 70Mbps |
|
|
34
|
+
|
|
35
|
+
> 传输效率受网络条件、磁盘 IO、系统分配资源、监听文件数量等因素影响。
|
|
36
|
+
|
|
37
|
+
## 五、支持环境
|
|
38
|
+
|
|
39
|
+
| 操作系统 | 架构 | 说明 |
|
|
40
|
+
|----------|------|------|
|
|
41
|
+
| Linux | amd64 | 推荐 |
|
|
42
|
+
| Linux | arm64 | 支持 |
|
|
43
|
+
| Windows | amd64 | 支持 |
|
|
44
|
+
| macOS | amd64 | 支持 |
|
|
45
|
+
| Docker | - | 宿主机持久化 |
|
|
46
|
+
| K8S | - | 支持 Helm 部署 |
|
|
47
|
+
|
|
48
|
+
下载地址:[官网下载](https://docs.thinkingdata.cn/ta-manual/latest/installation/installation_menu/data_import/logbus2_installation.html#二、下载-logbus2)
|
|
49
|
+
|
|
50
|
+
## 六、配置指南
|
|
51
|
+
|
|
52
|
+
### 文件数据源配置
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"push_url": "http://RECEIVER_URL",
|
|
57
|
+
"cpu_limit": 4,
|
|
58
|
+
"datasource": [
|
|
59
|
+
{
|
|
60
|
+
"type": "file",
|
|
61
|
+
"file_patterns": ["/data/log/*.log"],
|
|
62
|
+
"app_id": "your_app_id",
|
|
63
|
+
"http_compress": "gzip",
|
|
64
|
+
"unit_remove": "day",
|
|
65
|
+
"offset_remove": 7
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Kafka 数据源配置
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"datasource": [
|
|
76
|
+
{
|
|
77
|
+
"type": "kafka",
|
|
78
|
+
"topic": "topic1,topic2",
|
|
79
|
+
"consumer_group": "consumer_group_name",
|
|
80
|
+
"brokers": ["localhost:9092"],
|
|
81
|
+
"auto_commit": false,
|
|
82
|
+
"app_id": "your_app_id"
|
|
83
|
+
}
|
|
84
|
+
],
|
|
85
|
+
"push_url": "http://RECEIVER_URL"
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 多项目数据分流配置
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"datasource": [
|
|
94
|
+
{
|
|
95
|
+
"file_patterns": ["/data/log/*.log"],
|
|
96
|
+
"app_id": "default_app_id",
|
|
97
|
+
"app_pipe": {
|
|
98
|
+
"attribute": "#lib_version",
|
|
99
|
+
"id_map": {
|
|
100
|
+
"app_id_1": "1.0.0",
|
|
101
|
+
"app_id_2": "2.0.0"
|
|
102
|
+
},
|
|
103
|
+
"default": "app_id_1"
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
],
|
|
107
|
+
"push_url": "http://RECEIVER_URL"
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 告警配置
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"alert": {
|
|
116
|
+
"enabled": true,
|
|
117
|
+
"receiver": "feishu_robot",
|
|
118
|
+
"extra": "logbus_instance_1",
|
|
119
|
+
"out_cfg": {
|
|
120
|
+
"feishu_robot_hook": "https://open.feishu.cn/open-apis/bot/v2/hook/xxx"
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## 七、常用操作命令
|
|
127
|
+
|
|
128
|
+
### 环境检查
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
./logbus env
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 启动服务
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
./logbus start
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### 停止服务
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
./logbus stop
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### 查看同步进度
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
./logbus progress
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### 升级版本
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
./logbus stop
|
|
156
|
+
./logbus update
|
|
157
|
+
./logbus start
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### 查看传输速度
|
|
161
|
+
|
|
162
|
+
查看 `logbus/log/transporter.log` 确认发送效率。
|
|
163
|
+
|
|
164
|
+
## 八、配置参数详解
|
|
165
|
+
|
|
166
|
+
### 全局配置
|
|
167
|
+
|
|
168
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
169
|
+
|------|------|--------|------|
|
|
170
|
+
| push_url | string | - | Receiver 地址,必填 |
|
|
171
|
+
| cpu_limit | int | - | CPU 核心限制 |
|
|
172
|
+
| ignore_app_id_verify | bool | false | 是否跳过 appid 和 push_url 校验 |
|
|
173
|
+
|
|
174
|
+
### 数据上报配置
|
|
175
|
+
|
|
176
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
177
|
+
|------|------|--------|------|
|
|
178
|
+
| batch | int | 1000 | 数据发送条数条件,最小10,最大100000 |
|
|
179
|
+
| interval_seconds | int | 2 | 数据发送时间间隔,最大60秒 |
|
|
180
|
+
| send_thread_num | int | 3 | 数据上报线程数 |
|
|
181
|
+
| http_timeout | string | 30s | HTTP 请求超时时间 |
|
|
182
|
+
| http_compress | string | - | HTTP 压缩协议,支持 gzip/snappy |
|
|
183
|
+
|
|
184
|
+
### 文件数据源配置
|
|
185
|
+
|
|
186
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
187
|
+
|------|------|--------|------|
|
|
188
|
+
| file_patterns | []string | - | 文件 glob 匹配模式,必填 |
|
|
189
|
+
| traverse_dir_interval | string | 30s | 扫描目录间隔时间 |
|
|
190
|
+
|
|
191
|
+
### Kafka 数据源配置
|
|
192
|
+
|
|
193
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
194
|
+
|------|------|--------|------|
|
|
195
|
+
| topic | string | - | Kafka topic,支持多 topic(逗号分隔) |
|
|
196
|
+
| brokers | []string | - | Kafka broker 地址 |
|
|
197
|
+
| consumer_group | string | - | 消费者组 |
|
|
198
|
+
| auto_commit | bool | false | 是否自动提交 |
|
|
199
|
+
| protocol | string | none | 认证协议:plain/scramsha256/scramsha512/iam/none |
|
|
200
|
+
| fetch_count | int | 1000 | 一次性拉取数据条数 |
|
|
201
|
+
|
|
202
|
+
### 文件删除配置
|
|
203
|
+
|
|
204
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
205
|
+
|------|------|--------|------|
|
|
206
|
+
| offset_remove | int | - | 删除周期 |
|
|
207
|
+
| unit_remove | string | d | 删除单位:d(天)/h(小时) |
|
|
208
|
+
| RemoveDirs | bool | false | 是否删除文件夹,不建议配置,可能导致服务端写入异常 |
|
|
209
|
+
|
|
210
|
+
## 九、注意事项
|
|
211
|
+
|
|
212
|
+
### 文件操作相关
|
|
213
|
+
|
|
214
|
+
> **禁止对 LogBus 监听的文件进行重命名操作**,否则会导致数据丢失或数据重复。
|
|
215
|
+
|
|
216
|
+
### 监听文件要求
|
|
217
|
+
|
|
218
|
+
- LogBus 监听路径下文件必须是纯净的数据文件
|
|
219
|
+
- 不能有 gz/.iso/.rpm/.zip/.bz/.rar/.bz2 后缀的文件
|
|
220
|
+
- LogBus-v2 默认会绕过这些文件
|
|
221
|
+
|
|
222
|
+
### 多实例运行
|
|
223
|
+
|
|
224
|
+
- 可运行多个 LogBus,但多个 LogBus 不能监听相同路径下的文件上报到同一个项目
|
|
225
|
+
|
|
226
|
+
### Kafka 消费优化
|
|
227
|
+
|
|
228
|
+
- 消费者线程数建议与分区数相等
|
|
229
|
+
- 避免单个 LogBus 消费 hash 模余结果一致的分区
|
|
230
|
+
- 可通过增加分区数和 LogBus 消费者数来加快消费
|
|
231
|
+
|
|
232
|
+
### 数据补报注意事项
|
|
233
|
+
|
|
234
|
+
- 如果是历史数据,建议开启历史通道
|
|
235
|
+
- 及时关注 Kafka 集群是否有数据积压
|
|
236
|
+
- 补数据建议发送到单独的 topic,避免与正式数据混淆
|
|
237
|
+
|
|
238
|
+
## 十、常见问题
|
|
239
|
+
|
|
240
|
+
### 如何确认网络是否通畅?
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
curl 数据接收地址/health-check
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### 如何确认 APPID 是否正确?
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
curl "数据接收地址/check_appid?appid=目标APPID"
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
返回 `{"code":0}` 即为正常。
|
|
253
|
+
|
|
254
|
+
### 数据重复的原因?
|
|
255
|
+
|
|
256
|
+
1. 是否对已同步完成的文件进行重命名
|
|
257
|
+
2. 源数据文件中数据是否有重复
|
|
258
|
+
3. 是否执行了 reset 操作
|
|
259
|
+
|
|
260
|
+
### 传输较慢怎么办?
|
|
261
|
+
|
|
262
|
+
1. 调大 `send_thread_num` 发送线程数
|
|
263
|
+
2. 开启 HTTP 压缩:`http_compress: "gzip"`
|
|
264
|
+
3. 检查网络延迟、带宽,建议 LogBus 与 Receiver 在同一内网
|
|
265
|
+
4. 检查是否有限制 CPU、内存
|
|
266
|
+
|
|
267
|
+
### Kafka 消费较慢怎么办?
|
|
268
|
+
|
|
269
|
+
1. 增加 LogBus 实例
|
|
270
|
+
2. 调大单个 LogBus 的 `send_thread_num`
|
|
271
|
+
3. 增加分区数
|
|
272
|
+
4. 最佳策略:LogBus 消费者线程数 = 分区数
|
|
273
|
+
|
|
274
|
+
### 读取策略差异导致上报延迟?
|
|
275
|
+
|
|
276
|
+
如果服务端数据存在多进程同时写入数据到不同文件的情况,logbus2老版本会出现串行读取的情况,导致部分实时写入的文件没有实时上报,新版本已兼容此场景。
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
# 停止 LogBus
|
|
280
|
+
./logbus stop
|
|
281
|
+
|
|
282
|
+
# 升级 LogBus
|
|
283
|
+
./logbus update
|
|
284
|
+
|
|
285
|
+
# 重启 LogBus
|
|
286
|
+
./logbus start
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## 十一、最佳实践建议
|
|
290
|
+
|
|
291
|
+
### 部署建议
|
|
292
|
+
|
|
293
|
+
1. **资源规划**:根据数据量合理配置 CPU 和内存
|
|
294
|
+
2. **网络优化**:LogBus 与 Receiver 部署在同一内网
|
|
295
|
+
3. **监控告警**:配置告警通知,及时发现异常
|
|
296
|
+
|
|
297
|
+
### 配置建议
|
|
298
|
+
|
|
299
|
+
1. **压缩传输**:建议开启 gzip 压缩,减少网络传输量
|
|
300
|
+
2. **文件清理**:配置自动删除策略,避免磁盘空间不足
|
|
301
|
+
3. **线程配置**:根据数据量调整发送线程数
|
|
302
|
+
|
|
303
|
+
### 运维建议
|
|
304
|
+
|
|
305
|
+
1. **版本升级**:定期关注发版记录,及时升级
|
|
306
|
+
2. **日志留存**:合理配置日志留存时间
|
|
307
|
+
3. **进程监控**:对 LogBus 进程进行监控
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
# LogBus2 数据转译插件
|
|
2
|
+
|
|
3
|
+
> Logbus2从2.1.0.0版本开始支持客户自定义数据解析器,用于原数据格式与 TE 数据格式不一致时自定义转换格式,功能对标Logbus1的Custom Interceptor功能。
|
|
4
|
+
|
|
5
|
+
## 一、准备工作
|
|
6
|
+
|
|
7
|
+
### 数据格式
|
|
8
|
+
|
|
9
|
+
1. gRPC插件服务端接收数据进行批量处理,多条数据以Logbus2配置参数 parser.separator(默认 :: )拼接
|
|
10
|
+
2. 单条数据则拼接文件名称或者Kafka的topic名称,以配置参数 parser.index_separator(默认 |ta| )拼接
|
|
11
|
+
|
|
12
|
+
示例:
|
|
13
|
+
|
|
14
|
+
```python
|
|
15
|
+
# 文件名称为:event.log
|
|
16
|
+
# 原始数据2条:
|
|
17
|
+
{"user_id": "abc", "distinct_id": "123"}
|
|
18
|
+
{"user_id": "def", "distinct_id": "456"}
|
|
19
|
+
|
|
20
|
+
# gRPC插件服务端接收到的数据为:
|
|
21
|
+
event.log|ta|{"user_id": "abc", "distinct_id": "123"} ::event.log|ta|{"user_id": "def", "distinct_id": "456"}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
gRPC插件服务端返回数据格式,以parser.separator拼接转换为标准ta格式的数据:
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
# 返回数据应为:
|
|
28
|
+
{"#account_id": "abc", "#distinct_id": "123"}::{\"#account_id\": \"def\", \"distinct_id\": \"456\"}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
错误处理:
|
|
32
|
+
- 返回非正确json数据,则主程序会跳过错误行
|
|
33
|
+
- 返回非标准ta数据,则数据上报会产生错误
|
|
34
|
+
- 返回第二个参数为error,则会进行无限重试,防止错误数据进入te集群。可搭配告警功能,提前预知错误信息。
|
|
35
|
+
|
|
36
|
+
### proto文件
|
|
37
|
+
|
|
38
|
+
parser.proto 文件用于生成各语言的 gRPC 服务端代码。
|
|
39
|
+
|
|
40
|
+
### Java
|
|
41
|
+
|
|
42
|
+
1. JDK 8+ (Logbus部署环境和开发环境保持一致)、Maven
|
|
43
|
+
2. 下载 protobuf 编译工具:https://github.com/protocolbuffers/protobuf/releases
|
|
44
|
+
3. 下载 grpc-java 编译工具:https://repo.maven.apache.org/maven2/io/grpc/protoc-gen-grpc-java/
|
|
45
|
+
|
|
46
|
+
编译步骤:
|
|
47
|
+
|
|
48
|
+
```shell
|
|
49
|
+
# 生成ParserGrpc.java文件
|
|
50
|
+
protoc --plugin=protoc-gen-grpc-java=protoc-gen-grpc-java-1.51.0-osx-aarch_64.exe --grpc-java_out=/ta/path/ -I=/ta/path/ /ta/path/parser.proto
|
|
51
|
+
|
|
52
|
+
# 生成ParserOuterClass.java文件
|
|
53
|
+
protoc --experimental_allow_proto3_optional -I /ta/path/ --java_out=/ta/path/ /ta/path/parser.proto
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Python
|
|
57
|
+
|
|
58
|
+
1. Python3.6+
|
|
59
|
+
2. 安装三方库:
|
|
60
|
+
|
|
61
|
+
```shell
|
|
62
|
+
pip3 install grpcio-tools==1.48.2 -i https://pypi.tuna.tsinghua.edu.cn/simple
|
|
63
|
+
pip3 install grpcio-health-checking==1.48.2 -i https://pypi.tuna.tsinghua.edu.cn/simple
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
编译步骤:
|
|
67
|
+
|
|
68
|
+
```shell
|
|
69
|
+
python -m grpc_tools.protoc -I /ta/path/ --python_out=/ta/path/ --grpc_python_out=/ta/path/ /ta/path/parser.proto
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## 二、gRPC服务端开发
|
|
73
|
+
|
|
74
|
+
### Java版本(所需版本JDK 8+)
|
|
75
|
+
|
|
76
|
+
Maven依赖:
|
|
77
|
+
|
|
78
|
+
```xml
|
|
79
|
+
<dependencies>
|
|
80
|
+
<dependency>
|
|
81
|
+
<groupId>com.google.protobuf</groupId>
|
|
82
|
+
<artifactId>protobuf-java</artifactId>
|
|
83
|
+
<version>3.19.4</version>
|
|
84
|
+
</dependency>
|
|
85
|
+
<dependency>
|
|
86
|
+
<groupId>io.grpc</groupId>
|
|
87
|
+
<artifactId>grpc-all</artifactId>
|
|
88
|
+
<version>1.51.0</version>
|
|
89
|
+
</dependency>
|
|
90
|
+
</dependencies>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
开发转译逻辑demo:
|
|
94
|
+
|
|
95
|
+
```java
|
|
96
|
+
package org.interceptor.logbus2.service;
|
|
97
|
+
|
|
98
|
+
import org.interceptor.logbus2.proto.ParserGrpc;
|
|
99
|
+
import org.interceptor.logbus2.proto.ParserOuterClass;
|
|
100
|
+
import com.google.protobuf.ByteString;
|
|
101
|
+
import io.grpc.Server;
|
|
102
|
+
import io.grpc.ServerBuilder;
|
|
103
|
+
import io.grpc.stub.StreamObserver;
|
|
104
|
+
import java.util.*;
|
|
105
|
+
|
|
106
|
+
public class Demo extends ParserGrpc.ParserImplBase {
|
|
107
|
+
|
|
108
|
+
// 对应logbus2参数parser.separator,多条数据之间自定义的分隔符,默认 ::
|
|
109
|
+
private static final String separator = ":ta:";
|
|
110
|
+
|
|
111
|
+
// 对应logbus2参数parser.index_separator,单条数据,索引与数据之间的分隔符,默认 |ta|
|
|
112
|
+
private static final String indexSeparator = "\\|ta\\|";
|
|
113
|
+
|
|
114
|
+
// 对应logbus2参数parser.batch_separator,用于数据一条转多条的分隔符,默认 0x01
|
|
115
|
+
private static final String batchSeparator = new String(new byte[]{0x01}, StandardCharsets.UTF_8);
|
|
116
|
+
|
|
117
|
+
public static String parseData(final String rawData) {
|
|
118
|
+
try {
|
|
119
|
+
// 处理逻辑:将接收到的数据中的test字符转为product,并将数据增加为3条返回
|
|
120
|
+
String parseData = JSON.toJSONString(JSON.parseObject(rawData.replaceAll("test", "product"), TaDataDo.class));
|
|
121
|
+
return parseData + batchSeparator + parseData + batchSeparator + parseData;
|
|
122
|
+
} catch (Exception e) {
|
|
123
|
+
e.printStackTrace();
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
@Override
|
|
129
|
+
public void parse(ParserOuterClass.Request request, StreamObserver<ParserOuterClass.Response> responseObserver) {
|
|
130
|
+
String content = request.getContent().toStringUtf8();
|
|
131
|
+
String[] datas = content.split(separator);
|
|
132
|
+
List<String> responseList = new ArrayList<>();
|
|
133
|
+
|
|
134
|
+
for (String data : datas) {
|
|
135
|
+
try {
|
|
136
|
+
String[] split = data.split(indexSeparator);
|
|
137
|
+
responseList.add(parseData(split[1]));
|
|
138
|
+
} catch (Exception e) {
|
|
139
|
+
responseList.add("{}");
|
|
140
|
+
e.printStackTrace();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
String join = String.join(separator, responseList);
|
|
144
|
+
|
|
145
|
+
ParserOuterClass.Response response = ParserOuterClass.Response.newBuilder().setContent(ByteString.copyFrom(join.getBytes())).build();
|
|
146
|
+
responseObserver.onNext(response);
|
|
147
|
+
responseObserver.onCompleted();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
public static void main(String[] args) throws InterruptedException {
|
|
151
|
+
int availablePort = RandomUtils.nextInt(10000, 12000);
|
|
152
|
+
Server server = null;
|
|
153
|
+
for (int i = availablePort; i < 60000; i++) {
|
|
154
|
+
try {
|
|
155
|
+
server = ServerBuilder.forPort(i)
|
|
156
|
+
.maxInboundMessageSize(100 * 1024 * 1024)
|
|
157
|
+
.addService(new Demo())
|
|
158
|
+
.build()
|
|
159
|
+
.start();
|
|
160
|
+
break;
|
|
161
|
+
} catch (IOException e) {
|
|
162
|
+
// Port unavailable, try the next one
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
assert server != null;
|
|
166
|
+
// ‼️重要:此行输出信息供logbus获取,格式不能变动
|
|
167
|
+
System.out.println("1|1|tcp|127.0.0.1:" + server.getPort() + "|grpc");
|
|
168
|
+
server.awaitTermination();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Python版本
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
import random
|
|
177
|
+
from concurrent import futures
|
|
178
|
+
import socket
|
|
179
|
+
import sys
|
|
180
|
+
import json
|
|
181
|
+
import grpc
|
|
182
|
+
import parser_pb2
|
|
183
|
+
import parser_pb2_grpc
|
|
184
|
+
from grpc_health.v1.health import HealthServicer
|
|
185
|
+
from grpc_health.v1 import health_pb2, health_pb2_grpc
|
|
186
|
+
|
|
187
|
+
separator = ":ta:"
|
|
188
|
+
index_separator = "|ta|"
|
|
189
|
+
|
|
190
|
+
class ParserServicer(parser_pb2_grpc.ParserServicer):
|
|
191
|
+
def Parse(self, request, context):
|
|
192
|
+
data = request.content
|
|
193
|
+
result = parser_pb2.Response()
|
|
194
|
+
data_list = data.decode('utf-8').split(separator)
|
|
195
|
+
return_data_list = []
|
|
196
|
+
for data in data_list:
|
|
197
|
+
try:
|
|
198
|
+
raw_data_list = data.replace('\r\n', '').split(index_separator)
|
|
199
|
+
parse_data = json.loads(raw_data_list[1])
|
|
200
|
+
new_parse_data = {}
|
|
201
|
+
new_parse_data["properties"] = parse_data.copy()
|
|
202
|
+
new_parse_data["#account_id"] = parse_data["ACCOUNTID"]
|
|
203
|
+
new_parse_data["#distinct_id"] = parse_data["OSTYPE"]
|
|
204
|
+
new_parse_data["#type"] = "track"
|
|
205
|
+
new_parse_data["#ip"] = parse_data["IP"]
|
|
206
|
+
new_parse_data["#uuid"] = parse_data["UID"]
|
|
207
|
+
new_parse_data["#time"] = parse_data["LOGTM"]
|
|
208
|
+
new_parse_data["#event_name"] = "event_" + str(parse_data["CODE"])
|
|
209
|
+
return_data_list.append(json.dumps(new_parse_data))
|
|
210
|
+
except Exception as ve:
|
|
211
|
+
return_data_list.append('{}')
|
|
212
|
+
result.content = separator.join(return_data_list).encode('utf-8')
|
|
213
|
+
return result
|
|
214
|
+
|
|
215
|
+
def serve():
|
|
216
|
+
health = HealthServicer()
|
|
217
|
+
health.set("plugin", health_pb2.HealthCheckResponse.ServingStatus.Value('SERVING'))
|
|
218
|
+
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10), options=[
|
|
219
|
+
('grpc.max_send_message_length', 4 * 1024 * 1024),
|
|
220
|
+
('grpc.max_receive_message_length', 4 * 1024 * 1024),
|
|
221
|
+
])
|
|
222
|
+
parser_pb2_grpc.add_ParserServicer_to_server(ParserServicer(), server)
|
|
223
|
+
health_pb2_grpc.add_HealthServicer_to_server(health, server)
|
|
224
|
+
port = get_open_port_in_random_range()
|
|
225
|
+
server.add_insecure_port(f'127.0.0.1:{port}')
|
|
226
|
+
server.start()
|
|
227
|
+
try:
|
|
228
|
+
# ‼️重要:此行输出信息供logbus获取,格式不能变动
|
|
229
|
+
print(f'1|1|tcp|127.0.0.1:{port}|grpc')
|
|
230
|
+
sys.stdout.flush()
|
|
231
|
+
while True:
|
|
232
|
+
time.sleep(60*60*24)
|
|
233
|
+
except KeyboardInterrupt:
|
|
234
|
+
server.stop(0)
|
|
235
|
+
|
|
236
|
+
if __name__ == '__main__':
|
|
237
|
+
serve()
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## 三、本地gRPC调试
|
|
241
|
+
|
|
242
|
+
创建本地调试 gRPC 客户端,服务端启动后再启动客户端发送消息。
|
|
243
|
+
|
|
244
|
+
### Java客户端
|
|
245
|
+
|
|
246
|
+
```java
|
|
247
|
+
public class ProtoClient {
|
|
248
|
+
private static final String indexSeparator = "|ta|";
|
|
249
|
+
|
|
250
|
+
public static void main(String[] args) {
|
|
251
|
+
String event = "{\"#type\":\"track\",\"#time\":\"2023-09-05 18:58:17.021\",\"#event_name\":\"test\",\"#account_id\":\"test\",\"properties\":{\"#lib\":\"tga_python_sdk\"}}";
|
|
252
|
+
|
|
253
|
+
ManagedChannel channel = ManagedChannelBuilder.forAddress("127.0.0.1", 12345)
|
|
254
|
+
.usePlaintext()
|
|
255
|
+
.build();
|
|
256
|
+
ParserGrpc.ParserBlockingStub stub = ParserGrpc.newBlockingStub(channel);
|
|
257
|
+
ParserOuterClass.Request request = ParserOuterClass.Request.newBuilder()
|
|
258
|
+
.setContent(ByteString.copyFrom(("ta.log"+ indexSeparator + event).getBytes()))
|
|
259
|
+
.build();
|
|
260
|
+
|
|
261
|
+
try {
|
|
262
|
+
ParserOuterClass.Response response = stub.parse(request);
|
|
263
|
+
System.out.println("Server Response: " + response.getContent().toStringUtf8());
|
|
264
|
+
} catch (Exception e) {
|
|
265
|
+
e.printStackTrace();
|
|
266
|
+
} finally {
|
|
267
|
+
channel.shutdown();
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Python客户端
|
|
274
|
+
|
|
275
|
+
```python
|
|
276
|
+
import grpc
|
|
277
|
+
import parser_pb2
|
|
278
|
+
import parser_pb2_grpc
|
|
279
|
+
|
|
280
|
+
def send_grpc_request():
|
|
281
|
+
channel = grpc.insecure_channel('127.0.0.1:12345')
|
|
282
|
+
stub = parser_pb2_grpc.ParserStub(channel)
|
|
283
|
+
event = '{"#type":"track","#time":"2023-09-04 16:46:06.055","#event_name":"test","#distinct_id":"test"}'
|
|
284
|
+
request = parser_pb2.Request(content=f'1.log|ta|{event}'.encode('utf-8'))
|
|
285
|
+
response = stub.Parse(request)
|
|
286
|
+
print("Response received:", response.content)
|
|
287
|
+
|
|
288
|
+
if __name__ == '__main__':
|
|
289
|
+
send_grpc_request()
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## 四、配置
|
|
293
|
+
|
|
294
|
+
### Logbus2配置文件
|
|
295
|
+
|
|
296
|
+
```json
|
|
297
|
+
{
|
|
298
|
+
"datasource": [
|
|
299
|
+
{
|
|
300
|
+
"file_patterns": ["/path/server_log/*log"],
|
|
301
|
+
"app_id": "debug-appid",
|
|
302
|
+
"parser": {
|
|
303
|
+
"cmd": "java -jar /path/lib/xxx.jar",
|
|
304
|
+
"depend_sh": "true",
|
|
305
|
+
"separator": ":ta:",
|
|
306
|
+
"hand_shake": {
|
|
307
|
+
"protocol_version": 1,
|
|
308
|
+
"magic_cookie_key": "LogBus",
|
|
309
|
+
"magic_cookie_value": "v2"
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
],
|
|
314
|
+
"push_url": "http://push_url"
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
> 注:注释部分启动前要去除
|
|
319
|
+
|
|
320
|
+
## 五、FAQ
|
|
321
|
+
|
|
322
|
+
1. **启动时报错:Unrecongnized remote plugin message......latest protocol**
|
|
323
|
+
|
|
324
|
+
原因:程序使用的proto生成文件非最新,Logbus客户端校验失败
|
|
325
|
+
|
|
326
|
+
解决:参考准备工作部分,重新根据proto文件生成java类或python文件
|
|
327
|
+
|
|
328
|
+
2. **日志中报错:Parser return data is invalid: length is changed**
|
|
329
|
+
|
|
330
|
+
原因:目前版本Logbus2转译插件会校验数据转译前后条数是否相同,如果不同会导致校验失败
|
|
331
|
+
|
|
332
|
+
解决:确认转译前后数据条数是否相同,如果需要一转多功能,请使用parser.batch_separator进行数据拼接
|
|
333
|
+
|
|
334
|
+
3. **Logbus日志中报错:rpc error: code = Canceled desc = stream terminated by RST_STREAM with error code: CANCEL**
|
|
335
|
+
|
|
336
|
+
同时Java程序报错:io.grpc.StatusRuntimeException: RESOURCE_EXHAUSTED: gRPC message exceeds maximum size
|
|
337
|
+
|
|
338
|
+
原因:转译程序设置的传输数据字节数过小,导致logbus和Java转移程序RPC通信传输数据失败
|
|
339
|
+
|
|
340
|
+
解决:增加程序中的最大传输字节数,Java设置:maxInboundMessageSize(100*1024*1024)
|
|
341
|
+
|
|
342
|
+
4. **启动时报错:plugin [parser] start failed: fork/exec /bin/sh: bad file descriptor**
|
|
343
|
+
|
|
344
|
+
原因:由于插件编译器兼容性问题当前无法在mac环境运行
|
|
345
|
+
|
|
346
|
+
解决:需在linux / windows环境运行
|