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,406 @@
|
|
|
1
|
+
# 一、环境配置
|
|
2
|
+
|
|
3
|
+
当前文档统一按 Java SDK v3.x 新 API 编写,示例面向技术开发人员,可直接作为接入模板参考。已过期:`cn.thinkingdata.tga.javasdk` 包、`ThinkingDataAnalytics` / `LoggerConsumer` / `BatchConsumer` / `DebugConsumer` 类,以及 `user_set`、`user_add`、`track_first`、`track_update`、`track_overwrite` 等 snake_case 方法。根据参考文档的更新日志,截至 2026-01-07 最新发布版本为 v3.0.4-beta.1;其中 fastjson1、lzo、lz4 已不再支持。生产环境请优先固定已验证版本,并在升级前对照更新日志完成回归验证。
|
|
4
|
+
|
|
5
|
+
Java SDK 最低兼容 JDK 8。Java 的常用 IDE 有 **IntelliJ IDEA**、**Eclipse**、**NetBeans** 等,本文示例使用 **IntelliJ IDEA**。使用 Maven 集成 SDK,请在 `pom.xml` 中添加依赖。若需最新版本,请以官方文档或更新日志为准:
|
|
6
|
+
|
|
7
|
+
```xml
|
|
8
|
+
<dependencies>
|
|
9
|
+
<!-- others... -->
|
|
10
|
+
<dependency>
|
|
11
|
+
<groupId>cn.thinkingdata</groupId>
|
|
12
|
+
<artifactId>thinkingdatasdk</artifactId>
|
|
13
|
+
<version>3.0.2</version>
|
|
14
|
+
</dependency>
|
|
15
|
+
</dependencies>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
#### TDLoggerConsumer 样例代码
|
|
19
|
+
|
|
20
|
+
```java
|
|
21
|
+
import cn.thinkingdata.analytics.TDAnalytics;
|
|
22
|
+
import cn.thinkingdata.analytics.TDLoggerConsumer;
|
|
23
|
+
|
|
24
|
+
import java.util.ArrayList;
|
|
25
|
+
import java.util.Date;
|
|
26
|
+
import java.util.HashMap;
|
|
27
|
+
import java.util.List;
|
|
28
|
+
import java.util.Map;
|
|
29
|
+
|
|
30
|
+
public class LoggerExample {
|
|
31
|
+
public static void main(String[] args) {
|
|
32
|
+
TDAnalytics ta = null;
|
|
33
|
+
try {
|
|
34
|
+
// 初始化 SDK,LOG_DIRECTORY 为本地日志目录
|
|
35
|
+
ta = new TDAnalytics(new TDLoggerConsumer("LOG_DIRECTORY"), true);
|
|
36
|
+
|
|
37
|
+
Map<String, Object> properties = new HashMap<>();
|
|
38
|
+
properties.put("#ip", "192.168.1.1");
|
|
39
|
+
properties.put("channel", "te");
|
|
40
|
+
properties.put("age", 1);
|
|
41
|
+
properties.put("is_success", true);
|
|
42
|
+
properties.put("birthday", new Date());
|
|
43
|
+
|
|
44
|
+
Map<String, Object> object = new HashMap<>();
|
|
45
|
+
object.put("key", "value");
|
|
46
|
+
properties.put("object", object);
|
|
47
|
+
|
|
48
|
+
List<Map<String, Object>> objectArray = new ArrayList<>();
|
|
49
|
+
objectArray.add(object);
|
|
50
|
+
properties.put("object_arr", objectArray);
|
|
51
|
+
|
|
52
|
+
List<String> tags = new ArrayList<>();
|
|
53
|
+
tags.add("value");
|
|
54
|
+
properties.put("arr_string", tags);
|
|
55
|
+
|
|
56
|
+
ta.track("account_id", "distinct_id", "payment", properties);
|
|
57
|
+
|
|
58
|
+
Map<String, Object> userProperties = new HashMap<>();
|
|
59
|
+
userProperties.put("user_name", "TE");
|
|
60
|
+
ta.userSet("account_id", "distinct_id", userProperties);
|
|
61
|
+
|
|
62
|
+
// 仅在需要立即落盘时调用,避免高频 flush 带来额外 IO 开销
|
|
63
|
+
ta.flush();
|
|
64
|
+
} catch (Exception e) {
|
|
65
|
+
e.printStackTrace();
|
|
66
|
+
} finally {
|
|
67
|
+
if (ta != null) {
|
|
68
|
+
try {
|
|
69
|
+
ta.close();
|
|
70
|
+
} catch (Exception e) {
|
|
71
|
+
e.printStackTrace();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
#### TDBatchConsumer 样例代码
|
|
80
|
+
|
|
81
|
+
```java
|
|
82
|
+
import cn.thinkingdata.analytics.TDAnalytics;
|
|
83
|
+
import cn.thinkingdata.analytics.TDBatchConsumer;
|
|
84
|
+
|
|
85
|
+
import java.util.Date;
|
|
86
|
+
import java.util.HashMap;
|
|
87
|
+
import java.util.Map;
|
|
88
|
+
|
|
89
|
+
public class BatchExample {
|
|
90
|
+
public static void main(String[] args) {
|
|
91
|
+
TDAnalytics ta = null;
|
|
92
|
+
try {
|
|
93
|
+
ta = new TDAnalytics(new TDBatchConsumer("SERVER_URL", "APP_ID"));
|
|
94
|
+
|
|
95
|
+
String distinctId = "ABCDEFG123456789";
|
|
96
|
+
String accountId = "TA_10001";
|
|
97
|
+
|
|
98
|
+
Map<String, Object> properties = new HashMap<>();
|
|
99
|
+
properties.put("#time", new Date());
|
|
100
|
+
properties.put("#ip", "192.168.1.1");
|
|
101
|
+
properties.put("product_name", "商品A");
|
|
102
|
+
properties.put("price", 30);
|
|
103
|
+
properties.put("order_id", "abc_123");
|
|
104
|
+
|
|
105
|
+
ta.track(accountId, distinctId, "payment", properties);
|
|
106
|
+
|
|
107
|
+
// Batch 模式通常依赖批量阈值或定时机制触发发送
|
|
108
|
+
ta.flush();
|
|
109
|
+
} catch (Exception e) {
|
|
110
|
+
e.printStackTrace();
|
|
111
|
+
} finally {
|
|
112
|
+
if (ta != null) {
|
|
113
|
+
try {
|
|
114
|
+
ta.close();
|
|
115
|
+
} catch (Exception e) {
|
|
116
|
+
e.printStackTrace();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
#### TDDebugConsumer 样例代码
|
|
125
|
+
|
|
126
|
+
```java
|
|
127
|
+
import cn.thinkingdata.analytics.TDAnalytics;
|
|
128
|
+
import cn.thinkingdata.analytics.TDDebugConsumer;
|
|
129
|
+
|
|
130
|
+
import java.util.HashMap;
|
|
131
|
+
import java.util.Map;
|
|
132
|
+
|
|
133
|
+
public class DebugExample {
|
|
134
|
+
public static void main(String[] args) {
|
|
135
|
+
TDAnalytics ta = null;
|
|
136
|
+
try {
|
|
137
|
+
TDAnalytics.enableLog(true);
|
|
138
|
+
ta = new TDAnalytics(new TDDebugConsumer("SERVER_URL", "APP_ID", "DEBUG_DEVICE_ID"));
|
|
139
|
+
|
|
140
|
+
Map<String, Object> properties = new HashMap<>();
|
|
141
|
+
properties.put("product_name", "shoes");
|
|
142
|
+
properties.put("price", 199);
|
|
143
|
+
|
|
144
|
+
ta.track("account_id", "distinct_id", "payment", properties);
|
|
145
|
+
} catch (Exception e) {
|
|
146
|
+
e.printStackTrace();
|
|
147
|
+
} finally {
|
|
148
|
+
if (ta != null) {
|
|
149
|
+
try {
|
|
150
|
+
ta.close();
|
|
151
|
+
} catch (Exception e) {
|
|
152
|
+
e.printStackTrace();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
> 开启 Debug 模式需要两步:
|
|
161
|
+
> 1. 在代码中使用 `TDDebugConsumer` 并传入 `DEBUG_DEVICE_ID`。
|
|
162
|
+
> 2. 在 TE 后台"数据 > 埋点管理 > Debug 数据"中配置同一个 Debug 设备 ID。只有已配置的设备才能真正开启 Debug 模式。
|
|
163
|
+
|
|
164
|
+
# 二、工作原理
|
|
165
|
+
|
|
166
|
+
#### **Java SDK支持几种工作模式?分别适用于什么场景?**
|
|
167
|
+
|
|
168
|
+
Java SDK v3.x 常见的三种工作模式如下:
|
|
169
|
+
|
|
170
|
+
1. **TDLoggerConsumer**:将数据批量写入本地日志,再由 LogBus 负责传输。适合生产环境、需要更高可恢复性和更稳妥丢数控制的场景,也是官方更推荐的服务端接入方案。
|
|
171
|
+
2. **TDBatchConsumer**:直接批量发送数据到 TA 服务端,接入简单,但缓存仅保存在内存中。适合中小流量、网络质量稳定、可以接受一定重试与缓存上限约束的场景。
|
|
172
|
+
3. **TDDebugConsumer**:逐条发送并进行严格校验,便于接入验证和实时调试。仅建议在开发调试阶段使用,严禁用于生产环境。
|
|
173
|
+
|
|
174
|
+
#### **如何获取上报地址和APP_ID?**
|
|
175
|
+
|
|
176
|
+
项目管理者可以在数数 Web 界面选择具体项目后,进入"项目管理 > 项目配置 > 接入配置"获取 APP_ID 及数据上报地址。上报地址通常分为公网地址和私网地址:
|
|
177
|
+
|
|
178
|
+
- 公网地址:适用于客户端上报,以及公网环境下的服务端接入。
|
|
179
|
+
- 私网地址:适用于内网环境下的数据接入和测试。如果使用私有化部署,建议为数据接入地址绑定域名并配置 HTTPS 证书;如果是云服务,请直接使用平台提供的接入地址。
|
|
180
|
+
|
|
181
|
+
#### **LoggerConsumer的工作原理是什么?有哪些配置参数?**
|
|
182
|
+
|
|
183
|
+
v3.x 对应实现为 `TDLoggerConsumer`。事件先写入内存缓存,达到阈值后再刷写到本地日志文件;若开启自动刷新,也会按固定时间间隔刷写。该模式线程安全,但单个实例的调用默认是同步的;如果多个线程频繁竞争同一个实例,吞吐提升通常有限。生产环境中推荐配合 LogBus 使用,将"落盘"和"上传"解耦。
|
|
184
|
+
|
|
185
|
+
`TDLoggerConsumer.Config` 常用参数如下:
|
|
186
|
+
|
|
187
|
+
| 参数 | 描述 | 默认值 | 取值范围 | 备注 |
|
|
188
|
+
|------|------|--------|----------|------|
|
|
189
|
+
| `logDirectory` | 日志文件写入目录 | 无 | 字符串 | 多级目录会自动创建 |
|
|
190
|
+
| `rotateMode` | 日志切分模式 | `DAILY` | `HOURLY`、`DAILY` | 按小时或按天切分 |
|
|
191
|
+
| `lockFileName` | 文件锁名称 | 无 | 字符串 | 如无明确需求,不建议启用 |
|
|
192
|
+
| `filenamePrefix` | 日志文件名前缀 | 无 | 字符串 | 便于多实例或多业务区分文件 |
|
|
193
|
+
| `interval` | 自动 flush 间隔 | `3` | 整数 | 与 `autoFlush` 配合使用,单位秒 |
|
|
194
|
+
| `fileSize` | 文件大小切分阈值 | `0` | 整数 | 单位 MB,`0` 表示不按大小切分 |
|
|
195
|
+
| `bufferSize` | 内存缓冲区大小 | `8192` | 整数 | 单位字节 |
|
|
196
|
+
| `autoFlush` | 是否自动刷写 | `false` | 布尔值 | 仅在确有实时性要求时开启 |
|
|
197
|
+
|
|
198
|
+
#### **BatchConsumer的工作原理是什么?有哪些配置参数?**
|
|
199
|
+
|
|
200
|
+
v3.x 对应实现为 `TDBatchConsumer`。事件先写入内存队列,满足批量阈值或触发 `flush()` 时再发送到服务端;网络发送失败会进入重试与缓存逻辑。它的优点是接入简单,不依赖 LogBus;缺点是缓存只存在于内存中,服务异常退出或长时间网络问题都可能导致数据丢失,因此不建议作为高可靠生产方案的首选。
|
|
201
|
+
|
|
202
|
+
`TDBatchConsumer.Config` 常用参数如下:
|
|
203
|
+
|
|
204
|
+
| 参数 | 描述 | 默认值 | 取值范围 | 备注 |
|
|
205
|
+
|------|------|--------|----------|------|
|
|
206
|
+
| `batchSize` | 单批发送条数阈值 | `20` | 整数 | 达到阈值后触发发送 |
|
|
207
|
+
| `interval` | 自动发送间隔 | `3` | 整数 | 与 `autoFlush` 配合使用,单位秒 |
|
|
208
|
+
| `compress` | 数据压缩格式 | `gzip` | `gzip`、`none` | `lzo`、`lz4` 已在新版本中不再支持 |
|
|
209
|
+
| `timeout` | 网络请求超时时长 | `30000` | 整数 | 单位毫秒 |
|
|
210
|
+
| `autoFlush` | 是否自动发送 | `false` | 布尔值 | 根据业务实时性要求开启 |
|
|
211
|
+
| `maxCacheSize` | 失败批次缓存上限 | `50` | 整数 | 默认最多缓存 `20 * 50` 条数据 |
|
|
212
|
+
| `isThrowException` | 发送失败时是否抛异常 | `true` | 布尔值 | 建议保留默认值,便于业务侧感知风险 |
|
|
213
|
+
|
|
214
|
+
#### **DebugConsumer的工作原理是什么?有哪些配置参数?**
|
|
215
|
+
|
|
216
|
+
旧版 `DebugConsumer` 已过期,v3.x 对应实现为 `TDDebugConsumer`。该模式逐条通过 HTTP 请求发送数据,并在服务端进行严格校验;适合联调阶段快速定位字段格式、事件命名和数据合法性问题。
|
|
217
|
+
|
|
218
|
+
`TDDebugConsumer` 常用参数如下:
|
|
219
|
+
|
|
220
|
+
| 参数 | 描述 | 默认值 | 取值范围 | 备注 |
|
|
221
|
+
|------|------|--------|----------|------|
|
|
222
|
+
| `serverUrl` | 数据接入地址 | 无 | 字符串 | 需要与项目配置匹配 |
|
|
223
|
+
| `appId` | 项目 APP_ID | 无 | 字符串 | 可在项目配置页获取 |
|
|
224
|
+
| `deviceId` | Debug 设备 ID | 无 | 字符串 | 需在 TE 后台配置为 Debug 设备 |
|
|
225
|
+
|
|
226
|
+
调试时建议同时打开 SDK 日志:
|
|
227
|
+
|
|
228
|
+
```java
|
|
229
|
+
TDAnalytics.enableLog(true);
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
# 三、常见问题
|
|
233
|
+
|
|
234
|
+
#### **使用 LoggerConsumer 有哪些注意事项?**
|
|
235
|
+
|
|
236
|
+
- **搭配 LogBus 上报**
|
|
237
|
+
- `TDLoggerConsumer + LogBus` 是更推荐的服务端接入组合,既能保证本地持久化,也能降低应用进程直接承担传输压力。
|
|
238
|
+
- **文件写权限**
|
|
239
|
+
- 日志目录需要具备稳定的读写权限,Windows 或容器环境下尤其要提前验证目录权限和挂载策略。
|
|
240
|
+
- **磁盘空间**
|
|
241
|
+
- 生产环境需要持续监控日志目录的剩余容量,并在 LogBus 或外部清理策略中配置保留与删除规则。
|
|
242
|
+
- **磁盘性能与 NFS**
|
|
243
|
+
- 如果日志目录位于 NFS 等网络文件系统,需要重点评估写入延迟、吞吐和网络抖动带来的影响。
|
|
244
|
+
- **去重标识**
|
|
245
|
+
- 建议补充可用于幂等控制的字段,降低极端网络场景下的重复数据风险。
|
|
246
|
+
- **多进程写入策略**
|
|
247
|
+
- 可以多进程写不同文件或不同目录,但不要让多个进程写同一个日志文件。
|
|
248
|
+
- **容器环境**
|
|
249
|
+
- 建议将日志目录映射到容器外部持久化存储,避免容器销毁后数据一并丢失。
|
|
250
|
+
|
|
251
|
+
#### **LoggerConsumer 是否支持多线程?是否支持多进程?**
|
|
252
|
+
|
|
253
|
+
支持多线程。SDK 的相关写入和 flush 逻辑具备线程安全保证,但单个实例默认仍是同步调用模型,多线程共享同一个实例未必能显著提升吞吐。不支持多个进程写同一个文件。若多个进程同时写同一日志文件,可能触发 `OverlappingFileLockException`。正确做法是让不同进程写入不同文件或不同目录。
|
|
254
|
+
|
|
255
|
+
#### **LoggerConsumer 性能指标如何?**
|
|
256
|
+
|
|
257
|
+
具体的性能测试报告请查看 Server-Java-sdk 性能测试报告。
|
|
258
|
+
|
|
259
|
+
#### **LoggerConsumer 是否存在丢数风险?如何避免?**
|
|
260
|
+
|
|
261
|
+
如果磁盘写满、宿主机异常宕机、日志未及时刷盘或日志目录不可用,仍然存在丢数风险。建议:
|
|
262
|
+
|
|
263
|
+
1. 定期检查日志目录磁盘容量与 inode 使用情况。
|
|
264
|
+
2. 根据业务实时性合理调整 `bufferSize` 与 `autoFlush`,不要盲目追求极大缓存。
|
|
265
|
+
3. 程序退出前确保调用 `close()`,给 SDK 留出刷盘时间。
|
|
266
|
+
4. 在容器或弹性环境中,将日志目录放到持久化存储。
|
|
267
|
+
|
|
268
|
+
#### **BatchConsumer 为什么会存在丢数风险?如何避免?**
|
|
269
|
+
|
|
270
|
+
`TDBatchConsumer` 基于内存维护待发送队列和失败重试缓存。只要数据还未成功发送到服务端,就仍然存在因进程退出、内存溢出、长时间网络异常或缓存上限被打满而丢失的风险。建议:
|
|
271
|
+
|
|
272
|
+
1. 生产环境优先使用 `TDLoggerConsumer + LogBus`。
|
|
273
|
+
2. 根据网络质量和流量规模合理调大 `maxCacheSize`,但同时评估内存占用。
|
|
274
|
+
3. 不要把 `batchSize` 设得过大,以免单批发送时间过长、重试成本变高。
|
|
275
|
+
4. 在需要降低内存驻留时间时开启 `autoFlush`。
|
|
276
|
+
5. 对 `NeedRetryException` 做业务级处理,而不是简单吞掉异常。
|
|
277
|
+
|
|
278
|
+
#### **BatchConsumer 性能指标如何?适合在什么场景下使用?**
|
|
279
|
+
|
|
280
|
+
具体的性能测试报告请查看 Server-Java-sdk 性能测试报告。`TDBatchConsumer` 更适合中小数据量、网络稳定、接入简单优先且能接受内存缓存局限的场景;如果你需要更高可靠性,仍然建议优先评估 `TDLoggerConsumer + LogBus`。
|
|
281
|
+
|
|
282
|
+
#### **DebugConsumer 为什么在生产环境禁用?**
|
|
283
|
+
|
|
284
|
+
因为 Debug 模式逐条发送并严格校验,每条请求都会增加额外网络与校验开销,吞吐和稳定性都不适合作为生产链路。
|
|
285
|
+
|
|
286
|
+
#### **什么时候需要调用 `close()` 方法?**
|
|
287
|
+
|
|
288
|
+
在应用准备正常退出时调用。`close()` 会尝试将缓存中的数据继续刷盘或发送,是避免尾部数据丢失的必要步骤。建议在应用生命周期的关闭钩子中统一执行。
|
|
289
|
+
|
|
290
|
+
#### **在程序中调用了 `track()` 或者 `userSet()` 方法, 为什么在 TE 后台没有看到数据?**
|
|
291
|
+
|
|
292
|
+
请依次检查以下情况:
|
|
293
|
+
|
|
294
|
+
- **检查上报地址和 APP_ID**
|
|
295
|
+
- `curl https://push_url/health-check`,返回 `ok` 代表接入地址可达。
|
|
296
|
+
- `curl https://push_url/check_appid?appid=目标APPID`,返回 `{"code":0}` 代表接入地址和 APP_ID 匹配。
|
|
297
|
+
- **数据太少,尚未触发写入或发送**
|
|
298
|
+
- `TDLoggerConsumer` 和 `TDBatchConsumer` 都依赖缓存阈值、自动刷新或手动 `flush()` 才会真正落盘/上报。
|
|
299
|
+
- `flush()` 可以用于排查问题,但不建议在生产代码中高频调用。
|
|
300
|
+
- **错误数据**
|
|
301
|
+
- 可以在 Web 界面查看错误数据原因。
|
|
302
|
+
- **数据时间**
|
|
303
|
+
- 服务端数据接收时间范围上限为相对服务器时间前三年至后三天。
|
|
304
|
+
- 客户端数据接收时间范围上限为相对服务器时间前十天至后三天。
|
|
305
|
+
- **历史通道**
|
|
306
|
+
- 若项目启用了历史通道,上报十天前的历史数据时,需要确认是否已正确进入历史通道链路。
|
|
307
|
+
- **埋点方案**
|
|
308
|
+
- 如果项目开启了埋点方案,并设置"不在埋点方案中的事件:不允许入库",那么不在方案内的事件会被直接拦截。
|
|
309
|
+
- **白名单**
|
|
310
|
+
- 如果项目配置了 IP 白名单,需要确认当前上报来源 IP 是否已在白名单内;白名单生效通常存在短暂延迟。
|
|
311
|
+
|
|
312
|
+
#### **上报数据中为什么没有 #ip?**
|
|
313
|
+
|
|
314
|
+
请优先检查以下几点:
|
|
315
|
+
|
|
316
|
+
- `#ip` 是否被显式写入事件属性中。
|
|
317
|
+
- `#ip` 的值是否为合法 IP。
|
|
318
|
+
- 当前是否误用了历史代码中的旧版自定义封装。对于 v3.x SDK,建议直接按照官方示例将 `#ip` 写入事件属性 `Map<String, Object>`,不要继续沿用旧版手工拼装报文的写法。
|
|
319
|
+
|
|
320
|
+
# 四、预置属性、特殊类型上报
|
|
321
|
+
|
|
322
|
+
#### **Java SDK 如何上报对象和对象组类型?**
|
|
323
|
+
|
|
324
|
+
Java SDK 1.9.0 及以上版本支持对象和对象组类型。v3.x 中可继续按对象和 `List<Map<String, Object>>` 的方式组织属性,复杂类型示例可参考服务端 SDK 复杂类型上报。
|
|
325
|
+
|
|
326
|
+
#### **某属性首次上报为空值,应该如何上报?**
|
|
327
|
+
|
|
328
|
+
对象组:
|
|
329
|
+
|
|
330
|
+
```java
|
|
331
|
+
Map<String, Object> properties = new HashMap<>();
|
|
332
|
+
|
|
333
|
+
List<Map<String, Object>> arrayRowTest = new ArrayList<>();
|
|
334
|
+
// 至少放入一个空对象,避免被识别成普通列表类型
|
|
335
|
+
arrayRowTest.add(new HashMap<>());
|
|
336
|
+
|
|
337
|
+
properties.put("array_row_test", arrayRowTest);
|
|
338
|
+
// 上报逻辑...
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
列表:
|
|
342
|
+
|
|
343
|
+
```java
|
|
344
|
+
Map<String, Object> properties = new HashMap<>();
|
|
345
|
+
|
|
346
|
+
List<String> arrayTest = new ArrayList<>();
|
|
347
|
+
properties.put("array_test", arrayTest);
|
|
348
|
+
// 上报逻辑...
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
对象、数值、文本、时间、布尔类型属性都不支持直接上传 `null`。如果该字段当前无值,请不要传该属性,让结果在数据表中保持为空。
|
|
352
|
+
|
|
353
|
+
#### **公共属性**
|
|
354
|
+
|
|
355
|
+
服务端公共属性无法精确到用户级别。多线程或并发请求场景下,如果把用户级字段放进公共属性,容易出现用户维度错配。建议只在公共属性中放入稳定且全局一致的字段,例如区服 ID、部署环境、服务节点标识等;用户级、请求级、事件级字段应直接放在本次事件属性中。
|
|
356
|
+
|
|
357
|
+
#### **时区**
|
|
358
|
+
|
|
359
|
+
如果事件时间不是 UTC+8,且希望保留原始时区偏移信息,可以在普通属性内增加 `#zone_offset` 字段。例如事件时间是 UTC+0,则可以将 `#zone_offset` 设为数值 `0`。
|
|
360
|
+
|
|
361
|
+
#### **可更新事件**
|
|
362
|
+
|
|
363
|
+
在集群环境中,可更新事件如果存在毫秒级并发更新,可能出现乱序消费,导致最终结果不符合预期。遇到这类场景时,建议在事件属性中增加一个用于排序的普通属性,例如 `order`,并在事件中设置事务属性,让服务端按顺序决定是否覆盖。示例:
|
|
364
|
+
|
|
365
|
+
```java
|
|
366
|
+
Map<String, Object> properties = new HashMap<>();
|
|
367
|
+
properties.put("status", 2);
|
|
368
|
+
properties.put("order", 1);
|
|
369
|
+
properties.put("#transaction_property", "order");
|
|
370
|
+
|
|
371
|
+
ta.trackUpdate("account_id", "distinct_id", "order_status_changed", "event_id_1", properties);
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
# 五、异常报错
|
|
375
|
+
|
|
376
|
+
#### **多进程写文件出现 OverlappingFileLockException 异常,如何处理?**
|
|
377
|
+
|
|
378
|
+
`TDLoggerConsumer` 不支持多个进程写同一个文件。出现该异常时,应调整为"多进程写不同文件"或"多进程写不同目录",不要通过重试硬顶。
|
|
379
|
+
|
|
380
|
+
#### **track() 报异常 "exception : cn.thinkingdata.tga.javasdk.exception.InvalidArgumentException: The supported data type including: Number, String, Date, Boolean,List. Invalid property: xxx",如何处理?**
|
|
381
|
+
|
|
382
|
+
如果异常类名仍然来自 `cn.thinkingdata.tga.javasdk.exception`,说明当前项目仍在使用旧版 SDK 或旧版 API。建议直接升级到 v3.x,并统一替换为新包名 `cn.thinkingdata.analytics` 以及 camelCase 方法。同时检查属性值类型是否符合要求。支持的常见类型包括字符串、数值、布尔、时间、对象、对象组和数组;不支持的类型请先在业务侧转换后再上报。
|
|
383
|
+
|
|
384
|
+
#### **应该如何处理 NeedRetryException?**
|
|
385
|
+
|
|
386
|
+
当 SDK 在发送数据时连续重试失败,可能抛出 `NeedRetryException`。这通常意味着网络链路、服务端可达性或接入配置存在问题。建议:
|
|
387
|
+
|
|
388
|
+
1. 记录异常并打出关键信息,不要直接吞掉。
|
|
389
|
+
2. 结合监控判断是短时网络抖动还是持续故障。
|
|
390
|
+
3. 持续异常时,优先暂停高频上报或切换为更稳妥的链路,避免缓存持续打满。
|
|
391
|
+
4. 故障恢复后再逐步恢复业务流量。
|
|
392
|
+
|
|
393
|
+
#### **BatchConsumer 能否获取上报失败的数据?**
|
|
394
|
+
|
|
395
|
+
SDK 本身不会直接暴露一份"失败数据列表"供业务侧读取。失败批次通常由内部缓存和重试机制处理,超过缓存上限后会发生丢弃。因此如果你对失败可追溯性要求较高,应优先使用落盘方案,而不是依赖内存缓存。
|
|
396
|
+
|
|
397
|
+
#### **用线程池上报发现线程队列堆积,线程池被阻塞,什么原因?如何处理?**
|
|
398
|
+
|
|
399
|
+
如果多个线程频繁共享同一个 `TDAnalytics` 实例进行上报,内部同步控制会让发送顺序与调用顺序保持一致,但也会带来阻塞和堆积。处理方式通常有两种:
|
|
400
|
+
|
|
401
|
+
1. 如果不同线程之间没有严格顺序依赖,可按线程或按分片拆分多个 SDK 实例。
|
|
402
|
+
2. 如果场景更关注稳定性和削峰能力,可改用 `TDLoggerConsumer + LogBus`。
|
|
403
|
+
|
|
404
|
+
#### **调用数据上报接口(track、userSet等)时报错 NullPointerException**
|
|
405
|
+
|
|
406
|
+
请重点检查传入的属性 `Map` 是否包含 `null` 键或 `null` 值。业务代码在组装属性前,应该先做空值过滤;对于"没有值"的字段,直接不传,不要显式放入 `null`。
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "JavaScript SDK FAQ"
|
|
3
|
+
code: "javascript_sdk_faq"
|
|
4
|
+
source: "Feishu MCP"
|
|
5
|
+
doc_id: "FVlZw0Q3wig1svk13CEcGlQonHd"
|
|
6
|
+
fetched_at: "2026-04-20T17:29:40Z"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# 集成 & 初始化 SDK
|
|
10
|
+
## SDK 集成方式
|
|
11
|
+
### 自动集成(npm)
|
|
12
|
+
```shell
|
|
13
|
+
npm install thinkingdata-browser --save
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### 手动集成
|
|
17
|
+
- 同步加载或异步加载
|
|
18
|
+
|
|
19
|
+
## SDK 兼容性说明
|
|
20
|
+
- 运行环境需为浏览器,暂不兼容 IE 8 及以下版本
|
|
21
|
+
|
|
22
|
+
# SDK 数据上报策略
|
|
23
|
+
## 网络请求方式参数(send_method)
|
|
24
|
+
|
|
25
|
+
| 方式 | 请求方式 | 介绍 |
|
|
26
|
+
|------|----------|------|
|
|
27
|
+
| image | get | 拼接数据在图片请求后面,跨域兼容 |
|
|
28
|
+
| ajax | post | 使用 XMLHttpRequest,可发送大量数据 |
|
|
29
|
+
| beacon | post | 浏览器后台发送,不阻塞页面卸载 |
|
|
30
|
+
|
|
31
|
+
## 立即上报
|
|
32
|
+
- normal 模式未开启批量上报时立即上报
|
|
33
|
+
- debug 或 debugOnly 模式立即上报
|
|
34
|
+
- 手动调用 flush() 接口
|
|
35
|
+
|
|
36
|
+
## 批量上报
|
|
37
|
+
```javascript
|
|
38
|
+
var config = {
|
|
39
|
+
appId: 'APP_ID',
|
|
40
|
+
serverUrl: 'SERVER_URL',
|
|
41
|
+
send_method: 'ajax',
|
|
42
|
+
batch: {
|
|
43
|
+
size: 5,
|
|
44
|
+
interval: 5000,
|
|
45
|
+
maxLimit: 200
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
# SDK 缓存机制
|
|
51
|
+
## 存储内容
|
|
52
|
+
- 访客 ID、设备 ID、事件数据等
|
|
53
|
+
- 使用 localStorage 存储
|
|
54
|
+
|
|
55
|
+
## 缓存数量限制
|
|
56
|
+
- 默认最大缓存 500 条
|
|
57
|
+
|
|
58
|
+
# 访客 ID(#distinct_id)
|
|
59
|
+
## 默认格式
|
|
60
|
+
- 时间戳16进制-随机数16进制-UA16进制-屏幕宽高处理-时间戳16进制
|
|
61
|
+
|
|
62
|
+
## 手动设置
|
|
63
|
+
```javascript
|
|
64
|
+
ta.identify("your_distinct_id");
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## 长度限制
|
|
68
|
+
- 最大长度 128 位
|
|
69
|
+
|
|
70
|
+
# Debug 模式
|
|
71
|
+
## mode 三种取值
|
|
72
|
+
- normal:Normal 模式
|
|
73
|
+
- debug:数据在 TE Debug 模式中看到
|
|
74
|
+
- debug_only:只校验,不入库
|
|
75
|
+
|
|
76
|
+
# 自动采集
|
|
77
|
+
## ta_page_show
|
|
78
|
+
- 页面打开、刷新、标签切换回当前页时触发
|
|
79
|
+
- 监听 visibilitychange 事件,document.hidden = false
|
|
80
|
+
|
|
81
|
+
## ta_page_hide
|
|
82
|
+
- 页面关闭、标签切换、最小化时触发
|
|
83
|
+
- 监听 visibilitychange 事件,document.hidden = true
|
|
84
|
+
|
|
85
|
+
## ta_pageview
|
|
86
|
+
- 需调用 quick() 方法手动上报
|
|
87
|
+
- 与 ta_page_show 区别:ta_page_show 自动采集,ta_pageview 需手动调用
|
|
88
|
+
|
|
89
|
+
# 公共事件属性
|
|
90
|
+
## 静态公共事件属性
|
|
91
|
+
```javascript
|
|
92
|
+
ta.setSuperProperties({ channel: "渠道名", user_name: "用户名" });
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## 动态公共事件属性
|
|
96
|
+
```javascript
|
|
97
|
+
ta.setDynamicSuperProperties(function () {
|
|
98
|
+
return { gold_coin: getGold() };
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## 页面公共属性
|
|
103
|
+
```javascript
|
|
104
|
+
ta.setPageProperty({ page_id: "page10001" });
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## 属性优先级
|
|
108
|
+
- 用户自定义 > 页面公共 > 动态公共 > 静态公共
|
|
109
|
+
|
|
110
|
+
# 预置属性
|
|
111
|
+
## 设备 ID(#device_id)
|
|
112
|
+
- 默认和访客 ID 一致
|
|
113
|
+
|
|
114
|
+
## IP 地址(#ip)
|
|
115
|
+
- 服务端从请求头解析
|
|
116
|
+
- 可手动上报 #ip
|
|
117
|
+
|
|
118
|
+
# 常见问题
|
|
119
|
+
## 报错 Cannot read properties of undefined (reading 'getOptTracking')
|
|
120
|
+
- SDK 接口在初始化前被调用,需在初始化后调用
|
|
121
|
+
|
|
122
|
+
## 报错 net::ERR_BLOCKED_BY_ORB
|
|
123
|
+
- 默认使用 image 模式上传,可设置 imgUseCrossorigin: true
|
|
124
|
+
|
|
125
|
+
## 如何在 pagehide 中上报数据
|
|
126
|
+
- 使用 trackWithBeacon 方法
|
|
127
|
+
|
|
128
|
+
# 已知问题
|
|
129
|
+
详见文档完整内容。
|