thinkingdata-ruby 1.2.0 → 1.2.1
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.
- 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
|
+

|
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
|