thinkingdata-ruby 1.2.0 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +59 -0
- data/CHANGELOG.md +16 -14
- data/README.md +7 -199
- data/demo/demo.rb +50 -87
- data/lib/thinkingdata-ruby/batch_consumer.rb +2 -4
- data/lib/thinkingdata-ruby/debug_consumer.rb +9 -3
- data/lib/thinkingdata-ruby/errors.rb +2 -7
- data/lib/thinkingdata-ruby/logger_consumer.rb +23 -14
- data/lib/thinkingdata-ruby/tracker.rb +129 -122
- data/lib/thinkingdata-ruby/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cdd6d7eb248bfbddc35fdc947a9323ff6a1a16d10c2e396b5cd3f80dd272f866
|
4
|
+
data.tar.gz: e6ee651f3d35226a5f640f0c57868964abe0eba5841335249b262a81b264a018
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 442a30338ce592df0f6c9e3dd505255390e8797d405326009064531f45637bd2c86f1bbca10efd14a8e6dd8b12ebbfe183be0795c8e029fcec19362627024033
|
7
|
+
data.tar.gz: 605e8773859e0147486ed023c7ab187cd308aaf4e810cc1f633d9e72810cbadfd01fe19b45bebd1042e8741b1ac0e791d8662c36c5097e6d94694d5b051d0a0d
|
data/.gitignore
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/spec/examples.txt
|
9
|
+
/test/tmp/
|
10
|
+
/test/version_tmp/
|
11
|
+
/tmp/
|
12
|
+
|
13
|
+
# Used by dotenv library to load environment variables.
|
14
|
+
# .env
|
15
|
+
|
16
|
+
# Ignore Byebug command history file.
|
17
|
+
.byebug_history
|
18
|
+
|
19
|
+
## Specific to RubyMotion:
|
20
|
+
.dat*
|
21
|
+
.repl_history
|
22
|
+
build/
|
23
|
+
*.bridgesupport
|
24
|
+
build-iPhoneOS/
|
25
|
+
build-iPhoneSimulator/
|
26
|
+
|
27
|
+
## Specific to RubyMotion (use of CocoaPods):
|
28
|
+
#
|
29
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
30
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
31
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
32
|
+
#
|
33
|
+
# vendor/Pods/
|
34
|
+
|
35
|
+
## Documentation cache and generated files:
|
36
|
+
/.yardoc/
|
37
|
+
/_yardoc/
|
38
|
+
/doc/
|
39
|
+
/rdoc/
|
40
|
+
|
41
|
+
## Environment normalization:
|
42
|
+
/.bundle/
|
43
|
+
/vendor/bundle
|
44
|
+
/lib/bundler/man/
|
45
|
+
|
46
|
+
# for a library or gem, you might want to ignore these files since the code is
|
47
|
+
# intended to run in multiple environments; otherwise, check them in:
|
48
|
+
# Gemfile.lock
|
49
|
+
# .ruby-version
|
50
|
+
# .ruby-gemset
|
51
|
+
|
52
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
53
|
+
.rvmrc
|
54
|
+
|
55
|
+
# Used by RuboCop. Remote config files pulled in from inherit_from directive.
|
56
|
+
# .rubocop-https?--*
|
57
|
+
|
58
|
+
.idea/*
|
59
|
+
Gemfile.lock
|
data/CHANGELOG.md
CHANGED
@@ -1,14 +1,16 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
**
|
12
|
-
|
13
|
-
|
14
|
-
|
1
|
+
### v1.2.1
|
2
|
+
**Date:** 2023/03/20
|
3
|
+
|
4
|
+
**Notes:**
|
5
|
+
|
6
|
+
* Compatible ruby 3
|
7
|
+
* Supports a different '#app_id' for each event
|
8
|
+
|
9
|
+
|
10
|
+
### v1.2.0
|
11
|
+
**Date:** 2020/08/28
|
12
|
+
|
13
|
+
**Notes:**
|
14
|
+
|
15
|
+
* Added track_update interface to support updatable events
|
16
|
+
* Added track_overwrite interface to support rewritable events
|
data/README.md
CHANGED
@@ -1,202 +1,10 @@
|
|
1
|
-
# ThinkingData
|
1
|
+
# ThinkingData SDK for Ruby
|
2
|
+
![output](https://user-images.githubusercontent.com/53337625/205621683-ed9b97ef-6a52-4903-a2c0-a955dddebb7d.png)
|
2
3
|
|
3
|
-
|
4
|
+
This is the [ThinkingData](https://www.thinkingdata.cn)™ SDK for Ruby. Documentation is available on our help center in the following languages:
|
4
5
|
|
5
|
-
|
6
|
+
- [English](https://docs.thinkingdata.cn/ta-manual/latest/en/installation/installation_menu/server_sdk/ruby_sdk_installation/ruby_sdk_installation.html)
|
7
|
+
- [中文](https://docs.thinkingdata.cn/ta-manual/latest/installation/installation_menu/server_sdk/ruby_sdk_installation/ruby_sdk_installation.html)
|
8
|
+
- [日本語](https://docs.thinkingdata.io/ta-manual/v4.0/ja/installation/installation_menu/server_sdk/ruby_sdk_installation/ruby_sdk_installation.html)
|
6
9
|
|
7
|
-
|
8
|
-
|
9
|
-
```sh
|
10
|
-
# 获取 SDK
|
11
|
-
gem install thinkingdata-ruby
|
12
|
-
```
|
13
|
-
#### 2. 创建 SDK 实例
|
14
|
-
首先在代码文件开头引入 `thinkingdata-ruby`:
|
15
|
-
```ruby
|
16
|
-
require 'thinkingdata-ruby'
|
17
|
-
```
|
18
|
-
|
19
|
-
使用 SDK 上传数据,需要首先创建 `TDAnalytics::Tracker` 对象. `TDAnalytics::Tracker` 是数据上报的核心类,使用此类上报事件数据和更新用户属性. 创建 `Tracker` 对象需要传入 consumer 对象,consumer 决定了如何处理格式化的数据(存储在本地日志文件还是上传到服务端).
|
20
|
-
|
21
|
-
```ruby
|
22
|
-
ta = TDAnalytics::Tracker.new(consumer)
|
23
|
-
ta.track('your_event', distinct_id: 'distinct_id_of_user')
|
24
|
-
```
|
25
|
-
TDAnalytics 提供了三种 consumer 实现:
|
26
|
-
|
27
|
-
**(1) LoggerConsumer**: 将数据实时写入本地文件,文件以 天/小时 切分,并需要与 LogBus 搭配使用进行数据上传.
|
28
|
-
```ruby
|
29
|
-
# 默认写入当前目录的文件,按日期命名(daily),例如: tda.log.2019-11-15
|
30
|
-
consumer = TDAnalytics::LoggerConsumer.new
|
31
|
-
|
32
|
-
# 也可以修改配置,如下配置会创建 LoggerConsumer,并将数据写入: /path/to/log/demolog.2019-11-15-18 (18 为小时)
|
33
|
-
consumer = TDAnalytics::LoggerConsumer.new('/path/to/log', 'hourly', prefix: 'demolog')
|
34
|
-
```
|
35
|
-
|
36
|
-
**(2) DebugConsumer**: 逐条实时向 TA 服务器传输数据,当数据格式错误时会返回详细的错误信息。建议先使用 DebugConsumer 校验数据格式。初始化传入项目 APP ID 和接收端地址.
|
37
|
-
```ruby
|
38
|
-
# 创建 DebugConsumer
|
39
|
-
consumer = TDAnalytics::DebugConsumer.new(SERVER_URL, YOUR_APPID)
|
40
|
-
```
|
41
|
-
|
42
|
-
**(3) BatchConsumer**: 批量实时地向 TA 服务器传输数据,不需要搭配传输工具。在网络条件不好的情况下有可能会导致数据丢失,因此不建议在生产环境中大量使用. 初始化传入项目 APP ID 和接收端地址.
|
43
|
-
|
44
|
-
BatchConsumer 会先将数据存放在缓冲区中,当数据条数超过设定的缓冲区最大值(max_buffer_length, 默认为20),触发上报. 您也可以在初始化 SDK 时传入整数类型的参数配置缓冲区大小:
|
45
|
-
```ruby
|
46
|
-
# BatchConsumer,数据将先存入缓冲区,达到指定条数时上报,默认为 20 条
|
47
|
-
consumer = TDAnalytics::BatchConsumer.new(SERVER_URL, YOUR_APPID)
|
48
|
-
|
49
|
-
# 创建指定缓冲区大小为 3 条的 BatchConsumer
|
50
|
-
consumer = TDAnalytics::BatchConsumer.new(SERVER_URL, YOUR_APPID, 3)
|
51
|
-
```
|
52
|
-
|
53
|
-
您也可以传入自己实现的 Consumer,只需实现以下接口:
|
54
|
-
- add(message): (必须) 接受 Hash 类型的数据对象
|
55
|
-
- flush: (可选) 将缓冲区的数据发送到指定地址
|
56
|
-
- close: (可选) 程序退出时用户可以主动调用此接口以保证安全退出
|
57
|
-
|
58
|
-
#### 3. 上报数据
|
59
|
-
SDK 初始化完成后,后续即可使用 ta 的接口来上报数据.
|
60
|
-
|
61
|
-
### 使用示例
|
62
|
-
|
63
|
-
#### a. 发送事件
|
64
|
-
您可以调用 track 来上传事件,建议您根据预先梳理的文档来设置事件的属性以及发送信息的条件。上传事件示例如下:
|
65
|
-
```ruby
|
66
|
-
# 定义事件数据
|
67
|
-
event = {
|
68
|
-
# 事件名称 (必填)
|
69
|
-
event_name: 'test_event',
|
70
|
-
# 账号 ID (可选)
|
71
|
-
account_id: 'ruby_test_aid',
|
72
|
-
# 访客 ID (可选),账号 ID 和访客 ID 不可以都为空
|
73
|
-
distinct_id: 'ruby_distinct_id',
|
74
|
-
# 事件时间 (可选) 如果不填,将以调用接口时的时间作为事件时间
|
75
|
-
time: Time.now,
|
76
|
-
# 事件 IP (可选) 当传入 IP 地址时,后台可以解析所在地
|
77
|
-
ip: '202.38.64.1',
|
78
|
-
# 事件属性 (可选)
|
79
|
-
properties: {
|
80
|
-
prop_date: Time.now,
|
81
|
-
prop_double: 134.1,
|
82
|
-
prop_string: 'hello world',
|
83
|
-
prop_bool: true,
|
84
|
-
},
|
85
|
-
# 跳过本地格式校验 (可选)
|
86
|
-
# skip_local_check: true,
|
87
|
-
}
|
88
|
-
|
89
|
-
# 上传事件
|
90
|
-
ta.track(event)
|
91
|
-
```
|
92
|
-
|
93
|
-
参数说明:
|
94
|
-
* 事件的名称只能以字母开头,可包含数字,字母和下划线“_”,长度最大为 50 个字符,对字母大小写不敏感
|
95
|
-
* 事件的属性是 Hash 类型,其中每个元素代表一个属性
|
96
|
-
* 事件属性的 Key 值为属性的名称,为 string 类型,规定只能以字母开头,包含数字,字母和下划线“_”,长度最大为 50 个字符,对字母大小写不敏感
|
97
|
-
* 事件属性的 Value 值为该属性的值,支持 String、数值类型、bool、Time
|
98
|
-
|
99
|
-
SDK 会在本地对数据格式做校验,如果希望跳过本地校验,可以在调用 track 接口的时候传入 skip_local_check 参数.
|
100
|
-
|
101
|
-
#### 2. 设置公共事件属性
|
102
|
-
公共事件属性是每个事件都会包含的属性. 也可以设置动态公共属性。如果有相同的属性,则动态公共属性会覆盖公共事件属性。
|
103
|
-
|
104
|
-
```ruby
|
105
|
-
# 定义公共属性
|
106
|
-
super_properties = {
|
107
|
-
super_string: 'super_string',
|
108
|
-
super_int: 1,
|
109
|
-
super_bool: false,
|
110
|
-
super_date: Time.rfc2822("Thu, 26 Oct 2019 02:26:12 +0545")
|
111
|
-
}
|
112
|
-
|
113
|
-
# 设置公共事件属性,公共事件属性会添加到每个事件中
|
114
|
-
ta.set_super_properties(super_properties)
|
115
|
-
|
116
|
-
# 清空公共事件属性
|
117
|
-
ta.clear_super_properties
|
118
|
-
```
|
119
|
-
|
120
|
-
#### 3. 设置用户属性
|
121
|
-
对于一般的用户属性,您可以调用 user_set 来进行设置. 使用该接口上传的属性将会覆盖原有的属性值,如果之前不存在该用户属性,则会新建该用户属性:
|
122
|
-
```ruby
|
123
|
-
# 定义用户属性数据
|
124
|
-
user_data = {
|
125
|
-
# 账号 ID (可选)
|
126
|
-
account_id: 'ruby_test_aid',
|
127
|
-
# 访客 ID (可选),账号 ID 和访客 ID 不可以都为空
|
128
|
-
distinct_id: 'ruby_distinct_id',
|
129
|
-
# 用户属性
|
130
|
-
properties: {
|
131
|
-
prop_date: Time.now,
|
132
|
-
prop_double: 134.12,
|
133
|
-
prop_string: 'hello',
|
134
|
-
prop_int: 666,
|
135
|
-
},
|
136
|
-
}
|
137
|
-
|
138
|
-
# 设置用户属性
|
139
|
-
ta.user_set(user_data);
|
140
|
-
```
|
141
|
-
如果您要上传的用户属性只要设置一次,则可以调用 user_set_once 来进行设置,当该属性之前已经有值的时候,将会忽略这条信息:
|
142
|
-
```ruby
|
143
|
-
# 设置用户属性,如果已有同名属性,则忽略新设置属性
|
144
|
-
ta.user_set_once(user_data);
|
145
|
-
```
|
146
|
-
当您要上传数值型的属性时,可以调用 user_add 来对该属性进行累加操作,如果该属性还未被设置,则会赋值 0 后再进行计算:
|
147
|
-
```ruby
|
148
|
-
# 对数值类型的属性进行累加操作
|
149
|
-
ta.user_add(distinct_id: 'ruby_distinct_id', properties: {prop_int: 10, prop_double: 15.88})
|
150
|
-
```
|
151
|
-
|
152
|
-
当您需要删除某个用户属性的值时,可以调用 user_unset.
|
153
|
-
```ruby
|
154
|
-
# 删除某个用户属性
|
155
|
-
ta.user_unset(distinct_id: 'ruby_distinct_id', property: :prop_string)
|
156
|
-
|
157
|
-
# 删除一组用户属性
|
158
|
-
ta.user_unset(distinct_id: 'ruby_distinct_id', property: Array.[](:prop_a, :prop_b, :prob_c))
|
159
|
-
```
|
160
|
-
|
161
|
-
如果您要删除某个用户,可以调用 user_del 将这名用户删除. 之后您将无法再查询该用户的用户属性,但该用户产生的事件仍然可以被查询到:
|
162
|
-
```ruby
|
163
|
-
# 删除用户
|
164
|
-
ta.user_del(
|
165
|
-
# 账号 ID (可选)
|
166
|
-
account_id: 'ruby_test_aid',
|
167
|
-
# 访客 ID (可选),账号 ID 和访客 ID 不可以都为空
|
168
|
-
distinct_id: 'ruby_distinct_id',
|
169
|
-
);
|
170
|
-
```
|
171
|
-
|
172
|
-
#### 4. 立即进行数据 IO
|
173
|
-
此操作与具体的 Consumer 实现有关. 在收到数据时, Consumer 可以先将数据存放在缓冲区, 并在特定情况下触发真正的数据 IO 操作, 以提高整体性能. 在某些情况下需要立即提交数据,可以调用 flush 接口:
|
174
|
-
```ruby
|
175
|
-
# 立即提交数据到相应的接收端
|
176
|
-
ta.flush
|
177
|
-
```
|
178
|
-
|
179
|
-
#### 5. 关闭 SDK
|
180
|
-
请在退出程序前调用本接口,以避免缓存内的数据丢失:
|
181
|
-
```ruby
|
182
|
-
# 关闭并退出 SDK
|
183
|
-
ta.close
|
184
|
-
```
|
185
|
-
|
186
|
-
#### 6 其他说明
|
187
|
-
默认情况下,除初始化参数不合法外,其他 Error 会被忽略,如果您希望自己处理接口调用中的 Error,可以传入自定义的 error handler.
|
188
|
-
|
189
|
-
```ruby
|
190
|
-
# (可选) 定义一个错误处理器,当出现 Error 时会调用
|
191
|
-
class MyErrorHandler < TDAnalytics::ErrorHandler
|
192
|
-
def handle(error)
|
193
|
-
puts error
|
194
|
-
raise error
|
195
|
-
end
|
196
|
-
end
|
197
|
-
my_error_handler = MyErrorHandler.new
|
198
|
-
|
199
|
-
# 创建 TA 实例, 第一个参数为任意一种 Consumer, 第二个参数可选,如果设定了会在出错时调用
|
200
|
-
ta = TDAnalytics::Tracker.new(consumer, my_error_handler, uuid: true)
|
201
|
-
```
|
202
|
-
uuid 如果为 true,每条数据都会被带上随机 UUID 作为 #uuid 属性的值上报,该值不会入库,仅仅用于后台做数据重复检测.
|
10
|
+
---
|
data/demo/demo.rb
CHANGED
@@ -2,19 +2,13 @@ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
|
2
2
|
|
3
3
|
require 'thinkingdata-ruby'
|
4
4
|
require 'time'
|
5
|
-
#require 'pry'
|
6
5
|
|
7
6
|
if __FILE__ == $0
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
DEMO_ACCOUNT_ID = 'ruby_demo_aid'
|
14
|
-
# 访客 ID
|
15
|
-
DEMO_DISTINCT_ID = 'ruby_demo_did'
|
16
|
-
|
17
|
-
# (可选) 定义一个错误处理器,当出现 Error 时会调用
|
7
|
+
DEMO_APPID = 'app id'
|
8
|
+
SERVER_URL = 'server url'
|
9
|
+
DEMO_ACCOUNT_ID = '123'
|
10
|
+
DEMO_DISTINCT_ID = 'aaa'
|
11
|
+
|
18
12
|
class MyErrorHandler < TDAnalytics::ErrorHandler
|
19
13
|
def handle(error)
|
20
14
|
puts error
|
@@ -23,120 +17,89 @@ if __FILE__ == $0
|
|
23
17
|
end
|
24
18
|
my_error_handler = MyErrorHandler.new
|
25
19
|
|
26
|
-
|
20
|
+
TDAnalytics::set_stringent(false)
|
21
|
+
TDAnalytics::set_enable_log(true)
|
22
|
+
|
27
23
|
consumer = nil
|
28
|
-
$ARGV =
|
24
|
+
$ARGV = 0
|
29
25
|
case $ARGV
|
30
26
|
when 0
|
31
|
-
|
32
|
-
consumer = TDAnalytics::LoggerConsumer.new '.', 'hourly', prefix: 'demolog'
|
27
|
+
consumer = TDAnalytics::LoggerConsumer.new './log', 'hourly'
|
33
28
|
when 1
|
34
|
-
|
35
|
-
consumer = TDAnalytics::DebugConsumer.new(SERVER_URL, DEMO_APPID)
|
36
|
-
# 如果不想上传到TA,只想校验数据格式,可以如下初始化
|
29
|
+
consumer = TDAnalytics::DebugConsumer.new(SERVER_URL, DEMO_APPID, device_id: "123456789")
|
37
30
|
# consumer = TDAnalytics::DebugConsumer.new(SERVER_URL, DEMO_APPID,false)
|
38
31
|
when 2
|
39
|
-
# BatchConsumer,数据将先存入缓冲区,达到指定条数时上报,默认为 20 条
|
40
32
|
consumer = TDAnalytics::BatchConsumer.new(SERVER_URL, DEMO_APPID, 30)
|
41
|
-
#设置是否压缩数据,默认gzip压缩,内网可以这样设置
|
42
33
|
#consumer._set_compress(false)
|
43
34
|
else
|
44
|
-
# LoggerConsumer,数据将写入本地文件(当前目录,按天切分,前缀为 tda.log),需要配合 Logbus 上传数据到 TA 服务器
|
45
35
|
consumer = TDAnalytics::LoggerConsumer.new
|
46
36
|
end
|
47
37
|
|
48
|
-
# 创建 TA 实例, 第一个参数为任意一种 Consumer, 第二个参数可选,如果设定了会在出错时调用
|
49
38
|
ta = TDAnalytics::Tracker.new(consumer, my_error_handler, uuid: true)
|
50
39
|
|
51
|
-
# 定义公共属性
|
52
40
|
super_properties = {
|
53
41
|
super_string: 'super_string',
|
54
42
|
super_int: 1,
|
55
43
|
super_bool: false,
|
56
|
-
super_date: Time.rfc2822("Thu, 26 Oct 2019 02:26:12 +0545")
|
44
|
+
super_date: Time.rfc2822("Thu, 26 Oct 2019 02:26:12 +0545"),
|
45
|
+
'#app_id': "123123123123123"
|
57
46
|
}
|
58
47
|
|
59
|
-
# 设置公共事件属性,公共事件属性会添加到每个事件中
|
60
48
|
ta.set_super_properties(super_properties)
|
61
49
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
# 事件时间 (可选) 如果不填,将以调用接口时的时间作为事件时间
|
71
|
-
time: Time.now,
|
72
|
-
# 事件 IP (可选) 当传入 IP 地址时,后台可以解析所在地
|
73
|
-
ip: '202.38.64.1',
|
74
|
-
# 事件属性 (可选)
|
75
|
-
properties: {
|
76
|
-
array: ["str1", "11", "22.22", "2020-02-11 17:02:52.415"],
|
77
|
-
prop_date: Time.now,
|
78
|
-
prop_double: 134.1,
|
79
|
-
prop_string: 'hello world',
|
80
|
-
prop_bool: true,
|
81
|
-
},
|
50
|
+
properties = {
|
51
|
+
array: ["str1", "11", Time.now, "2020-02-11 17:02:52.415"],
|
52
|
+
prop_date: Time.now,
|
53
|
+
prop_double: 134.1,
|
54
|
+
prop_string: 'hello world',
|
55
|
+
prop_bool: true,
|
56
|
+
'#ip': '123.123.123.123',
|
57
|
+
'#uuid': 'aaabbbccc',
|
82
58
|
}
|
83
59
|
|
84
|
-
|
85
|
-
|
86
|
-
ta.track(event)
|
87
|
-
ta.clear_super_properties
|
60
|
+
ta.set_dynamic_super_properties do
|
61
|
+
{:dynamic_time => Time.now}
|
88
62
|
end
|
89
63
|
|
90
|
-
|
64
|
+
ta.track(event_name: 'test_event', distinct_id: DEMO_DISTINCT_ID, account_id: DEMO_ACCOUNT_ID, properties: properties)
|
65
|
+
|
66
|
+
ta.clear_dynamic_super_properties
|
67
|
+
ta.clear_super_properties
|
68
|
+
|
69
|
+
ta.track(event_name: 'test_event', distinct_id: DEMO_DISTINCT_ID, account_id: DEMO_ACCOUNT_ID, properties: properties)
|
70
|
+
|
91
71
|
user_data = {
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
properties: {
|
98
|
-
array: ["str1", 11, 22.22],
|
99
|
-
prop_date: Time.now,
|
100
|
-
prop_double: 134.12,
|
101
|
-
prop_string: 'hello',
|
102
|
-
prop_int: 666,
|
103
|
-
},
|
72
|
+
array: ["str1", 11, 22.22],
|
73
|
+
prop_date: Time.now,
|
74
|
+
prop_double: 134.12,
|
75
|
+
prop_string: 'hello',
|
76
|
+
prop_int: 666,
|
104
77
|
}
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
user_data_arr = {
|
110
|
-
# 账号 ID (可选)
|
111
|
-
account_id: DEMO_ACCOUNT_ID,
|
112
|
-
# 访客 ID (可选),账号 ID 和访客 ID 不可以都为空
|
113
|
-
distinct_id: DEMO_DISTINCT_ID,
|
114
|
-
# 用户属性
|
115
|
-
properties: {
|
116
|
-
array: ["33", "44"],
|
117
|
-
},
|
78
|
+
ta.user_set(distinct_id: DEMO_DISTINCT_ID, account_id: DEMO_ACCOUNT_ID, properties: user_data)
|
79
|
+
|
80
|
+
user_append_data = {
|
81
|
+
array: %w[33 44]
|
118
82
|
}
|
83
|
+
ta.user_append(distinct_id: DEMO_DISTINCT_ID, account_id: DEMO_ACCOUNT_ID, properties: user_append_data)
|
119
84
|
|
120
|
-
|
85
|
+
user_uniq_append_data = {
|
86
|
+
array: %w[44 55]
|
87
|
+
}
|
88
|
+
ta.user_uniq_append(distinct_id: DEMO_DISTINCT_ID, account_id: DEMO_ACCOUNT_ID, properties: user_uniq_append_data)
|
121
89
|
|
122
|
-
|
123
|
-
|
124
|
-
|
90
|
+
user_set_once_data = {
|
91
|
+
prop_int_new: 888,
|
92
|
+
}
|
93
|
+
ta.user_set_once(distinct_id: DEMO_DISTINCT_ID, account_id: DEMO_ACCOUNT_ID, properties: user_set_once_data)
|
125
94
|
|
126
|
-
# 累加用户属性
|
127
95
|
ta.user_add(distinct_id: DEMO_DISTINCT_ID, properties: {prop_int: 10, prop_double: 15.88})
|
128
96
|
|
129
|
-
|
130
|
-
# 删除某个用户属性
|
131
97
|
ta.user_unset(distinct_id: DEMO_DISTINCT_ID, property: [:prop_string, :prop_int])
|
132
98
|
|
99
|
+
ta.user_del(distinct_id: DEMO_DISTINCT_ID)
|
133
100
|
|
134
|
-
|
135
|
-
# ta.user_del(distinct_id: DEMO_DISTINCT_ID)
|
136
|
-
|
137
|
-
#binding.pry
|
101
|
+
ta.flush
|
138
102
|
|
139
|
-
# 退出前调用此接口
|
140
103
|
ta.close
|
141
104
|
end
|
142
105
|
|
@@ -2,10 +2,9 @@ require 'json'
|
|
2
2
|
require 'net/http'
|
3
3
|
|
4
4
|
module TDAnalytics
|
5
|
-
# BatchConsumer 批量同步的发送数据.
|
6
|
-
# 有数据时,首先会加入本地缓冲区,当条数到达上限后会发起上报
|
7
5
|
class BatchConsumer
|
8
|
-
|
6
|
+
|
7
|
+
# buffer count
|
9
8
|
DEFAULT_LENGTH = 20
|
10
9
|
MAX_LENGTH = 2000
|
11
10
|
|
@@ -93,7 +92,6 @@ module TDAnalytics
|
|
93
92
|
end
|
94
93
|
end
|
95
94
|
|
96
|
-
# 内部使用,为了兼容老版本服务端,将 Header 名称限定为小写
|
97
95
|
class CaseSensitivePost < Net::HTTP::Post
|
98
96
|
def initialize_http_header(headers)
|
99
97
|
@header = {}
|
@@ -2,15 +2,19 @@ require 'json'
|
|
2
2
|
require 'net/http'
|
3
3
|
|
4
4
|
module TDAnalytics
|
5
|
-
#
|
6
|
-
# DebugConsumer 会返回详细的报错信息,建议在集成阶段先使用 DebugConsumer 调试接口
|
5
|
+
# The data is reported one by one, and when an error occurs, the log will be printed on the console.
|
7
6
|
class DebugConsumer
|
8
7
|
|
9
|
-
def
|
8
|
+
def test
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(server_url, app_id, write_data = true, device_id: nil)
|
10
13
|
@server_uri = URI.parse(server_url)
|
11
14
|
@server_uri.path = '/data_debug'
|
12
15
|
@app_id = app_id
|
13
16
|
@write_data = write_data
|
17
|
+
@device_id = device_id
|
14
18
|
end
|
15
19
|
|
16
20
|
def add(message)
|
@@ -22,6 +26,8 @@ module TDAnalytics
|
|
22
26
|
'TA_Integration-Extra'=>'debug'
|
23
27
|
}
|
24
28
|
form_data = {"data" => message.to_json, "appid" => @app_id, "dryRun" => @write_data ? "0" : "1", "source" => "server"}
|
29
|
+
@device_id.is_a?(String) ? form_data["deviceId"] = @device_id : nil
|
30
|
+
|
25
31
|
begin
|
26
32
|
response_code, response_body = request(@server_uri, form_data,headers)
|
27
33
|
rescue => e
|
@@ -1,21 +1,16 @@
|
|
1
1
|
module TDAnalytics
|
2
2
|
|
3
|
-
# TD Analytics SDK 的错误
|
4
3
|
TDAnalyticsError = Class.new(StandardError)
|
5
4
|
|
6
|
-
# 参数不合法
|
7
5
|
IllegalParameterError = Class.new(TDAnalyticsError)
|
8
6
|
|
9
|
-
# 网络连接错误
|
10
7
|
ConnectionError = Class.new(TDAnalyticsError)
|
11
8
|
|
12
|
-
# 服务器返回错误
|
13
9
|
ServerError = Class.new(TDAnalyticsError)
|
14
10
|
|
15
11
|
|
16
|
-
#
|
17
|
-
#
|
18
|
-
# 例如:
|
12
|
+
# use example:
|
13
|
+
#
|
19
14
|
# class MyErrorHandler < TDAnalytics::ErrorHandler
|
20
15
|
# def handle(error)
|
21
16
|
# puts error
|
@@ -2,14 +2,25 @@ require 'logger'
|
|
2
2
|
require 'thinkingdata-ruby/errors'
|
3
3
|
|
4
4
|
module TDAnalytics
|
5
|
-
|
6
|
-
#
|
5
|
+
|
6
|
+
# dismantle the header and save it under another name
|
7
|
+
class HeadlessLogger < Logger
|
8
|
+
def initialize(logdev, shift_age = 0, shift_size = 1048576)
|
9
|
+
super(nil )
|
10
|
+
if logdev
|
11
|
+
@logdev = HeadlessLogger::LogDevice.new(logdev, shift_age: shift_age, shift_size: shift_size)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class LogDevice < ::Logger::LogDevice
|
16
|
+
def add_log_header(file); end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# write data to file, it works with LogBus
|
7
21
|
class LoggerConsumer
|
8
|
-
|
9
|
-
|
10
|
-
# mode: 日志文件切分模式,可选 daily/hourly
|
11
|
-
# prefix: 日志文件前缀,默认为 'tda.log', 日志文件名格式为: tda.log.2019-11-15
|
12
|
-
def initialize(log_path='.', mode='daily', prefix:'tda.log')
|
22
|
+
|
23
|
+
def initialize(log_path='.', mode='daily', prefix:'te.log')
|
13
24
|
case mode
|
14
25
|
when 'hourly'
|
15
26
|
@suffix_mode = '%Y-%m-%d-%H'
|
@@ -22,9 +33,8 @@ module TDAnalytics
|
|
22
33
|
raise IllegalParameterError.new("prefix couldn't be empty") if prefix.nil? || prefix.length == 0
|
23
34
|
|
24
35
|
@current_suffix = Time.now.strftime(@suffix_mode)
|
25
|
-
|
26
|
-
@full_prefix = "#{log_path}/#{prefix}
|
27
|
-
|
36
|
+
@log_path = log_path
|
37
|
+
@full_prefix = "#{log_path}/#{prefix}"
|
28
38
|
_reset
|
29
39
|
end
|
30
40
|
|
@@ -37,17 +47,16 @@ module TDAnalytics
|
|
37
47
|
@logger.info(msg.to_json)
|
38
48
|
end
|
39
49
|
|
40
|
-
# 关闭 logger
|
41
50
|
def close
|
42
51
|
@logger.close
|
43
52
|
end
|
44
53
|
|
45
54
|
private
|
46
55
|
|
47
|
-
# 重新创建 logger 对象. LogBus 判断新文件会同时考虑文件名和 inode,因此默认的切分方式会导致数据重传
|
48
56
|
def _reset
|
49
|
-
@
|
50
|
-
@logger
|
57
|
+
Dir::mkdir(@log_path) unless Dir::exist?(@log_path)
|
58
|
+
@logger = HeadlessLogger.new("#{@full_prefix}.#{@current_suffix}")
|
59
|
+
@logger.level = HeadlessLogger::INFO
|
51
60
|
@logger.formatter = proc do |severity, datetime, progname, msg|
|
52
61
|
"#{msg}\n"
|
53
62
|
end
|
@@ -3,34 +3,39 @@ require 'thinkingdata-ruby/errors'
|
|
3
3
|
require 'thinkingdata-ruby/version'
|
4
4
|
|
5
5
|
module TDAnalytics
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
6
|
+
@is_enable_log = false
|
7
|
+
@is_stringent = false
|
8
|
+
|
9
|
+
def self.set_enable_log(enable)
|
10
|
+
unless [true, false].include? enable
|
11
|
+
enable = false
|
12
|
+
end
|
13
|
+
@is_enable_log = enable
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.get_enable_log
|
17
|
+
@is_enable_log
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.set_stringent(enable)
|
21
|
+
unless [true, false].include? enable
|
22
|
+
enable = false
|
23
|
+
end
|
24
|
+
@is_stringent = enable
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.get_stringent
|
28
|
+
@is_stringent
|
29
|
+
end
|
22
30
|
|
31
|
+
class Tracker
|
23
32
|
LIB_PROPERTIES = {
|
24
33
|
'#lib' => 'ruby',
|
25
34
|
'#lib_version' => TDAnalytics::VERSION,
|
26
35
|
}
|
27
36
|
|
28
|
-
|
29
|
-
|
30
|
-
# 默认情况下,除参数不合法外,其他 Error 会被忽略,如果您希望自己处理接口调用中的 Error,可以传入自定义的 error handler.
|
31
|
-
# ErrorHandler 的定义可以参考 thinkingdata-ruby/errors.rb
|
32
|
-
#
|
33
|
-
# uuid 如果为 true,每条数据都会被带上随机 UUID 作为 #uuid 属性的值上报,该值不会入库,仅仅用于后台做数据重复检测
|
37
|
+
@@dynamic_block = nil
|
38
|
+
|
34
39
|
def initialize(consumer, error_handler = nil, uuid: false)
|
35
40
|
@error_handler = error_handler || ErrorHandler.new
|
36
41
|
@consumer = consumer
|
@@ -38,10 +43,9 @@ module TDAnalytics
|
|
38
43
|
@uuid = uuid
|
39
44
|
end
|
40
45
|
|
41
|
-
#
|
42
|
-
# 如果希望跳过本地格式校验,可以传入值为 true 的 skip_local_check 参数
|
46
|
+
# set common properties
|
43
47
|
def set_super_properties(properties, skip_local_check = false)
|
44
|
-
unless skip_local_check || _check_properties(:track, properties)
|
48
|
+
unless TDAnalytics::get_stringent == false || skip_local_check || _check_properties(:track, properties)
|
45
49
|
@error_handler.handle(IllegalParameterError.new("Invalid super properties"))
|
46
50
|
return false
|
47
51
|
end
|
@@ -54,19 +58,27 @@ module TDAnalytics
|
|
54
58
|
end
|
55
59
|
end
|
56
60
|
|
57
|
-
# 清除公共事件属性
|
58
61
|
def clear_super_properties
|
59
62
|
@super_properties = {}
|
60
63
|
end
|
61
64
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
65
|
+
def set_dynamic_super_properties(&block)
|
66
|
+
@@dynamic_block = block
|
67
|
+
end
|
68
|
+
|
69
|
+
def clear_dynamic_super_properties
|
70
|
+
@@dynamic_block = nil
|
71
|
+
end
|
72
|
+
|
73
|
+
# report ordinary event
|
74
|
+
# event_name: (require) A string of 50 letters and digits that starts with '#' or a letter
|
75
|
+
# distinct_id: (optional) distinct ID
|
76
|
+
# account_id: (optional) account ID. distinct_id, account_id can't both be empty.
|
77
|
+
# properties: (optional) string、number、Time、boolean
|
78
|
+
# time: (optional)Time
|
79
|
+
# ip: (optional) ip
|
80
|
+
# first_check_id: (optional) The value cannot be null for the first event
|
81
|
+
# skip_local_check: (optional) check data or not
|
70
82
|
def track(event_name: nil, distinct_id: nil, account_id: nil, properties: {}, time: nil, ip: nil,first_check_id:nil, skip_local_check: false)
|
71
83
|
begin
|
72
84
|
_check_name event_name
|
@@ -79,27 +91,10 @@ module TDAnalytics
|
|
79
91
|
return false
|
80
92
|
end
|
81
93
|
|
82
|
-
|
83
|
-
data[:event_name] = event_name
|
84
|
-
data[:distinct_id] = distinct_id if distinct_id
|
85
|
-
data[:account_id] = account_id if account_id
|
86
|
-
data[:time] = time if time
|
87
|
-
data[:ip] = ip if ip
|
88
|
-
data[:first_check_id] = first_check_id if first_check_id
|
89
|
-
data[:properties] = properties
|
90
|
-
|
91
|
-
_internal_track(:track, data)
|
94
|
+
_internal_track(:track, event_name: event_name, distinct_id: distinct_id, account_id: account_id, properties: properties, time: time, ip: ip, first_check_id: first_check_id)
|
92
95
|
end
|
93
96
|
|
94
|
-
#
|
95
|
-
# event_name: (必须) 事件名 必须是英文字母开头,可以包含字母、数字和 _, 长度不超过 50 个字符.
|
96
|
-
# event_id:(必须) event_name + event_id 会作为一条事件的唯一键
|
97
|
-
# distinct_id: (可选) 访客 ID
|
98
|
-
# account_id: (可选) 账号ID distinct_id 和 account_id 不能同时为空
|
99
|
-
# properties: (可选) Hash 事件属性。支持四种类型的值:字符串、数值、Time、boolean
|
100
|
-
# time: (可选)Time 事件发生时间,如果不传默认为系统当前时间
|
101
|
-
# ip: (可选) 事件 IP,如果传入 IP 地址,后端可以通过 IP 地址解析事件发生地点
|
102
|
-
# skip_local_check: (可选) boolean 表示是否跳过本地检测
|
97
|
+
# report overridable event
|
103
98
|
def track_overwrite(event_name: nil,event_id: nil, distinct_id: nil, account_id: nil, properties: {}, time: nil, ip: nil, skip_local_check: false)
|
104
99
|
begin
|
105
100
|
_check_name event_name
|
@@ -113,28 +108,10 @@ module TDAnalytics
|
|
113
108
|
return false
|
114
109
|
end
|
115
110
|
|
116
|
-
|
117
|
-
data[:event_name] = event_name
|
118
|
-
data[:event_id] = event_id
|
119
|
-
data[:distinct_id] = distinct_id if distinct_id
|
120
|
-
data[:account_id] = account_id if account_id
|
121
|
-
data[:time] = time if time
|
122
|
-
data[:ip] = ip if ip
|
123
|
-
data[:properties] = properties
|
124
|
-
_internal_track(:track_overwrite, data)
|
111
|
+
_internal_track(:track_overwrite, event_name: event_name, event_id: event_id, distinct_id: distinct_id, account_id: account_id, properties: properties, time: time, ip: ip)
|
125
112
|
end
|
126
113
|
|
127
|
-
|
128
|
-
|
129
|
-
# 上报事件数据可进行覆盖. 每个事件都包含一个事件名和事件ID以及 Hash 对象的时间属性. 其参数说明如下:
|
130
|
-
# event_name: (必须) 事件名 必须是英文字母开头,可以包含字母、数字和 _, 长度不超过 50 个字符.
|
131
|
-
# event_id:(必须) event_name + event_id 会作为一条事件的唯一键
|
132
|
-
# distinct_id: (可选) 访客 ID
|
133
|
-
# account_id: (可选) 账号ID distinct_id 和 account_id 不能同时为空
|
134
|
-
# properties: (可选) Hash 事件属性。支持四种类型的值:字符串、数值、Time、boolean
|
135
|
-
# time: (可选)Time 事件发生时间,如果不传默认为系统当前时间
|
136
|
-
# ip: (可选) 事件 IP,如果传入 IP 地址,后端可以通过 IP 地址解析事件发生地点
|
137
|
-
# skip_local_check: (可选) boolean 表示是否跳过本地检测
|
114
|
+
# report updatable event
|
138
115
|
def track_update(event_name: nil,event_id: nil, distinct_id: nil, account_id: nil, properties: {}, time: nil, ip: nil, skip_local_check: false)
|
139
116
|
begin
|
140
117
|
_check_name event_name
|
@@ -148,21 +125,10 @@ module TDAnalytics
|
|
148
125
|
return false
|
149
126
|
end
|
150
127
|
|
151
|
-
|
152
|
-
data[:event_name] = event_name
|
153
|
-
data[:event_id] = event_id
|
154
|
-
data[:distinct_id] = distinct_id if distinct_id
|
155
|
-
data[:account_id] = account_id if account_id
|
156
|
-
data[:time] = time if time
|
157
|
-
data[:ip] = ip if ip
|
158
|
-
data[:properties] = properties
|
159
|
-
_internal_track(:track_update, data)
|
128
|
+
_internal_track(:track_update, event_name: event_name, event_id: event_id, distinct_id: distinct_id, account_id: account_id, properties: properties, time: time, ip: ip)
|
160
129
|
end
|
161
130
|
|
162
|
-
#
|
163
|
-
# distinct_id: (可选) 访客 ID
|
164
|
-
# account_id: (可选) 账号ID distinct_id 和 account_id 不能同时为空
|
165
|
-
# properties: (可选) Hash 用户属性。支持四种类型的值:字符串、数值、Time、boolean
|
131
|
+
# set user properties. would overwrite existing names.
|
166
132
|
def user_set(distinct_id: nil, account_id: nil, properties: {}, ip: nil)
|
167
133
|
begin
|
168
134
|
_check_id(distinct_id, account_id)
|
@@ -172,15 +138,10 @@ module TDAnalytics
|
|
172
138
|
return false
|
173
139
|
end
|
174
140
|
|
175
|
-
_internal_track(:user_set,
|
176
|
-
distinct_id: distinct_id,
|
177
|
-
account_id: account_id,
|
178
|
-
properties: properties,
|
179
|
-
ip: ip,
|
180
|
-
)
|
141
|
+
_internal_track(:user_set, distinct_id: distinct_id, account_id: account_id, properties: properties, ip: ip)
|
181
142
|
end
|
182
143
|
|
183
|
-
#
|
144
|
+
# set user properties, If such property had been set before, this message would be neglected.
|
184
145
|
def user_set_once(distinct_id: nil, account_id: nil, properties: {}, ip: nil)
|
185
146
|
begin
|
186
147
|
_check_id(distinct_id, account_id)
|
@@ -198,7 +159,7 @@ module TDAnalytics
|
|
198
159
|
)
|
199
160
|
end
|
200
161
|
|
201
|
-
#
|
162
|
+
# to add user properties of array type.
|
202
163
|
def user_append(distinct_id: nil, account_id: nil, properties: {})
|
203
164
|
begin
|
204
165
|
_check_id(distinct_id, account_id)
|
@@ -215,7 +176,23 @@ module TDAnalytics
|
|
215
176
|
)
|
216
177
|
end
|
217
178
|
|
218
|
-
|
179
|
+
def user_uniq_append(distinct_id: nil, account_id: nil, properties: {})
|
180
|
+
begin
|
181
|
+
_check_id(distinct_id, account_id)
|
182
|
+
_check_properties(:user_uniq_append, properties)
|
183
|
+
rescue TDAnalyticsError => e
|
184
|
+
@error_handler.handle(e)
|
185
|
+
return false
|
186
|
+
end
|
187
|
+
|
188
|
+
_internal_track(:user_uniq_append,
|
189
|
+
distinct_id: distinct_id,
|
190
|
+
account_id: account_id,
|
191
|
+
properties: properties,
|
192
|
+
)
|
193
|
+
end
|
194
|
+
|
195
|
+
# clear the user properties of users.
|
219
196
|
def user_unset(distinct_id: nil, account_id: nil, property: nil)
|
220
197
|
properties = {}
|
221
198
|
if property.is_a?(Array)
|
@@ -241,10 +218,7 @@ module TDAnalytics
|
|
241
218
|
)
|
242
219
|
end
|
243
220
|
|
244
|
-
#
|
245
|
-
# distinct_id: (可选) 访客 ID
|
246
|
-
# account_id: (可选) 账号ID distinct_id 和 account_id 不能同时为空
|
247
|
-
# properties: (可选) Hash 数值类型的用户属性
|
221
|
+
# to accumulate operations against the property.
|
248
222
|
def user_add(distinct_id: nil, account_id: nil, properties: {})
|
249
223
|
begin
|
250
224
|
_check_id(distinct_id, account_id)
|
@@ -261,7 +235,7 @@ module TDAnalytics
|
|
261
235
|
)
|
262
236
|
end
|
263
237
|
|
264
|
-
#
|
238
|
+
# delete a user, This operation cannot be undone.
|
265
239
|
def user_del(distinct_id: nil, account_id: nil)
|
266
240
|
begin
|
267
241
|
_check_id(distinct_id, account_id)
|
@@ -276,7 +250,7 @@ module TDAnalytics
|
|
276
250
|
)
|
277
251
|
end
|
278
252
|
|
279
|
-
#
|
253
|
+
# report data immediately.
|
280
254
|
def flush
|
281
255
|
return true unless defined? @consumer.flush
|
282
256
|
ret = true
|
@@ -289,7 +263,7 @@ module TDAnalytics
|
|
289
263
|
ret
|
290
264
|
end
|
291
265
|
|
292
|
-
#
|
266
|
+
# Close and exit sdk
|
293
267
|
def close
|
294
268
|
return true unless defined? @consumer.close
|
295
269
|
ret = true
|
@@ -304,37 +278,39 @@ module TDAnalytics
|
|
304
278
|
|
305
279
|
private
|
306
280
|
|
307
|
-
|
308
|
-
def _internal_track(type, properties: {}, event_name: nil, event_id:nil, account_id: nil, distinct_id: nil, ip: nil,first_check_id: nil, time: Time.now)
|
309
|
-
if account_id == nil && distinct_id == nil
|
310
|
-
raise IllegalParameterError.new('account id or distinct id must be provided.')
|
311
|
-
end
|
312
|
-
|
281
|
+
def _internal_track(type, properties: {}, event_name: nil, event_id:nil, account_id: nil, distinct_id: nil, ip: nil,first_check_id: nil, time: nil)
|
313
282
|
if type == :track || type == :track_update || type == :track_overwrite
|
314
|
-
|
315
|
-
properties =
|
283
|
+
dynamic_properties = @@dynamic_block.respond_to?(:call) ? @@dynamic_block.call : {}
|
284
|
+
properties = LIB_PROPERTIES.merge(@super_properties).merge(dynamic_properties).merge(properties)
|
316
285
|
end
|
317
286
|
|
318
|
-
|
287
|
+
data = {
|
288
|
+
'#type' => type,
|
289
|
+
}
|
290
|
+
|
319
291
|
properties.each do |k, v|
|
320
292
|
if v.is_a?(Time)
|
321
293
|
properties[k] = _format_time(v)
|
322
294
|
end
|
323
295
|
end
|
324
296
|
|
325
|
-
data
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
297
|
+
_move_preset_properties([:'#ip', :"#time", :"#app_id", :"#uuid"], data, properties: properties)
|
298
|
+
|
299
|
+
if data[:'#time'] == nil
|
300
|
+
if time == nil
|
301
|
+
time = Time.now
|
302
|
+
end
|
303
|
+
data[:'#time'] = _format_time(time)
|
304
|
+
end
|
330
305
|
|
331
|
-
data['
|
306
|
+
data['properties'] = properties
|
307
|
+
data['#event_name'] = event_name if (type == :track || type == :track_update || type == :track_overwrite)
|
332
308
|
data['#event_id'] = event_id if (type == :track_update || type == :track_overwrite)
|
333
309
|
data['#account_id'] = account_id if account_id
|
334
310
|
data['#distinct_id'] = distinct_id if distinct_id
|
335
311
|
data['#ip'] = ip if ip
|
336
312
|
data['#first_check_id'] = first_check_id if first_check_id
|
337
|
-
data['#uuid'] = SecureRandom.uuid if @uuid
|
313
|
+
data[:'#uuid'] = SecureRandom.uuid if @uuid and data[:'#uuid'] == nil
|
338
314
|
|
339
315
|
ret = true
|
340
316
|
begin
|
@@ -347,18 +323,24 @@ module TDAnalytics
|
|
347
323
|
ret
|
348
324
|
end
|
349
325
|
|
350
|
-
# 将 Time 类型格式化为数数指定格式的字符串
|
351
326
|
def _format_time(time)
|
352
327
|
time.strftime("%Y-%m-%d %H:%M:%S.#{((time.to_f * 1000.0).to_i % 1000).to_s.rjust(3, "0")}")
|
353
328
|
end
|
354
329
|
|
355
330
|
def _check_event_id(event_id)
|
331
|
+
if TDAnalytics::get_stringent == false
|
332
|
+
return true
|
333
|
+
end
|
334
|
+
|
356
335
|
raise IllegalParameterError.new("the event_id or property cannot be nil") if event_id.nil?
|
357
336
|
true
|
358
337
|
end
|
359
338
|
|
360
|
-
# 属性名或者事件名检查
|
361
339
|
def _check_name(name)
|
340
|
+
if TDAnalytics::get_stringent == false
|
341
|
+
return true
|
342
|
+
end
|
343
|
+
|
362
344
|
raise IllegalParameterError.new("the name of event or property cannot be nil") if name.nil?
|
363
345
|
|
364
346
|
unless name.instance_of?(String) || name.instance_of?(Symbol)
|
@@ -367,8 +349,11 @@ module TDAnalytics
|
|
367
349
|
true
|
368
350
|
end
|
369
351
|
|
370
|
-
# 属性类型检查
|
371
352
|
def _check_properties(type, properties)
|
353
|
+
if TDAnalytics::get_stringent == false
|
354
|
+
return true
|
355
|
+
end
|
356
|
+
|
372
357
|
unless properties.instance_of? Hash
|
373
358
|
return false
|
374
359
|
end
|
@@ -394,9 +379,31 @@ module TDAnalytics
|
|
394
379
|
true
|
395
380
|
end
|
396
381
|
|
397
|
-
# 检查用户 ID 合法性
|
398
382
|
def _check_id(distinct_id, account_id)
|
383
|
+
if TDAnalytics::get_stringent == false
|
384
|
+
return true
|
385
|
+
end
|
386
|
+
|
399
387
|
raise IllegalParameterError.new("account id or distinct id must be provided.") if distinct_id.nil? && account_id.nil?
|
400
388
|
end
|
389
|
+
|
390
|
+
def _move_preset_properties(keys, data, properties: {})
|
391
|
+
property_keys = properties.keys
|
392
|
+
keys.each { |k|
|
393
|
+
if property_keys.include? k
|
394
|
+
data[k] = properties[k]
|
395
|
+
properties.delete(k)
|
396
|
+
end
|
397
|
+
}
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
class TELog
|
402
|
+
def self.info(*msg)
|
403
|
+
if TDAnalytics::get_enable_log
|
404
|
+
print("[ThinkingEngine][#{Time.now}][info]-")
|
405
|
+
puts(msg)
|
406
|
+
end
|
407
|
+
end
|
401
408
|
end
|
402
409
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thinkingdata-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ThinkingData
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-03-21 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: The official ThinkingData Analytics API for ruby
|
14
14
|
email: sdk@thinkingdata.cn
|
@@ -16,6 +16,7 @@ executables: []
|
|
16
16
|
extensions: []
|
17
17
|
extra_rdoc_files: []
|
18
18
|
files:
|
19
|
+
- ".gitignore"
|
19
20
|
- CHANGELOG.md
|
20
21
|
- Gemfile
|
21
22
|
- LICENSE
|
@@ -48,7 +49,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
48
49
|
- !ruby/object:Gem::Version
|
49
50
|
version: '0'
|
50
51
|
requirements: []
|
51
|
-
rubygems_version: 3.0.
|
52
|
+
rubygems_version: 3.0.9
|
52
53
|
signing_key:
|
53
54
|
specification_version: 4
|
54
55
|
summary: Official ThinkingData Analytics API for ruby
|