thinkingdata-ruby 1.2.0 → 2.0.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.
@@ -1,57 +0,0 @@
1
- require 'logger'
2
- require 'thinkingdata-ruby/errors'
3
-
4
- module TDAnalytics
5
- # 将数据写入本地文件, 需配合 LogBus 将数据上传到服务器
6
- # 由于 LogBus 有完善的失败重传机制,因此建议用户首先考虑此方案
7
- class LoggerConsumer
8
- # LoggerConsumer 构造函数
9
- # log_path: 日志文件存放目录
10
- # mode: 日志文件切分模式,可选 daily/hourly
11
- # prefix: 日志文件前缀,默认为 'tda.log', 日志文件名格式为: tda.log.2019-11-15
12
- def initialize(log_path='.', mode='daily', prefix:'tda.log')
13
- case mode
14
- when 'hourly'
15
- @suffix_mode = '%Y-%m-%d-%H'
16
- when 'daily'
17
- @suffix_mode = '%Y-%m-%d'
18
- else
19
- raise IllegalParameterError.new("#{mode} is unsupported for LoggerConsumer. Replaced it by daily or hourly")
20
- end
21
-
22
- raise IllegalParameterError.new("prefix couldn't be empty") if prefix.nil? || prefix.length == 0
23
-
24
- @current_suffix = Time.now.strftime(@suffix_mode)
25
-
26
- @full_prefix = "#{log_path}/#{prefix}."
27
-
28
- _reset
29
- end
30
-
31
- def add(msg)
32
- unless Time.now.strftime(@suffix_mode) == @current_suffix
33
- @logger.close
34
- @current_suffix = Time.now.strftime(@suffix_mode)
35
- _reset
36
- end
37
- @logger.info(msg.to_json)
38
- end
39
-
40
- # 关闭 logger
41
- def close
42
- @logger.close
43
- end
44
-
45
- private
46
-
47
- # 重新创建 logger 对象. LogBus 判断新文件会同时考虑文件名和 inode,因此默认的切分方式会导致数据重传
48
- def _reset
49
- @logger = Logger.new("#{@full_prefix}#{@current_suffix}")
50
- @logger.level = Logger::INFO
51
- @logger.formatter = proc do |severity, datetime, progname, msg|
52
- "#{msg}\n"
53
- end
54
- end
55
-
56
- end
57
- end
@@ -1,402 +0,0 @@
1
- require 'securerandom'
2
- require 'thinkingdata-ruby/errors'
3
- require 'thinkingdata-ruby/version'
4
-
5
- module TDAnalytics
6
- # TDAnalytics::Tracker 是数据上报的核心类,使用此类上报事件数据和更新用户属性.
7
- # 创建 Tracker 类需要传入 consumer 对象,consumer 决定了如何处理格式化的数据(存储在本地日志文件还是上传到服务端).
8
- #
9
- # ta = TDAnalytics::Tracker.new(consumer)
10
- # ta.track('your_event', distinct_id: 'distinct_id_of_user')
11
- #
12
- # TDAnalytics 提供了三种 consumer 实现:
13
- # LoggerConsumer: 数据写入本地文件
14
- # DebugConsumer: 数据逐条、同步的发送到服务端,并返回详细的报错信息
15
- # BatchConsumer: 数据批量、同步的发送到服务端
16
- #
17
- # 您也可以传入自己实现的 Consumer,只需实现以下接口:
18
- # add(message): 接受 hash 类型的数据对象
19
- # flush: (可选) 将缓冲区的数据发送到指定地址
20
- # close: (可选) 程序退出时用户可以主动调用此接口以保证安全退出
21
- class Tracker
22
-
23
- LIB_PROPERTIES = {
24
- '#lib' => 'ruby',
25
- '#lib_version' => TDAnalytics::VERSION,
26
- }
27
-
28
- # SDK 构造函数,传入 consumer 对象
29
- #
30
- # 默认情况下,除参数不合法外,其他 Error 会被忽略,如果您希望自己处理接口调用中的 Error,可以传入自定义的 error handler.
31
- # ErrorHandler 的定义可以参考 thinkingdata-ruby/errors.rb
32
- #
33
- # uuid 如果为 true,每条数据都会被带上随机 UUID 作为 #uuid 属性的值上报,该值不会入库,仅仅用于后台做数据重复检测
34
- def initialize(consumer, error_handler = nil, uuid: false)
35
- @error_handler = error_handler || ErrorHandler.new
36
- @consumer = consumer
37
- @super_properties = {}
38
- @uuid = uuid
39
- end
40
-
41
- # 设置公共事件属性,公共事件属性是所有事件都会带上的属性. 此方法会将传入的属性与当前公共属性合并.
42
- # 如果希望跳过本地格式校验,可以传入值为 true 的 skip_local_check 参数
43
- def set_super_properties(properties, skip_local_check = false)
44
- unless skip_local_check || _check_properties(:track, properties)
45
- @error_handler.handle(IllegalParameterError.new("Invalid super properties"))
46
- return false
47
- end
48
- properties.each do |k, v|
49
- if v.is_a?(Time)
50
- @super_properties[k] = _format_time(v)
51
- else
52
- @super_properties[k] = v
53
- end
54
- end
55
- end
56
-
57
- # 清除公共事件属性
58
- def clear_super_properties
59
- @super_properties = {}
60
- end
61
-
62
- # 上报事件. 每个事件都包含一个事件名和 Hash 对象的时间属性. 其参数说明如下:
63
- # event_name: (必须) 事件名 必须是英文字母开头,可以包含字母、数字和 _, 长度不超过 50 个字符.
64
- # distinct_id: (可选) 访客 ID
65
- # account_id: (可选) 账号ID distinct_id 和 account_id 不能同时为空
66
- # properties: (可选) Hash 事件属性。支持四种类型的值:字符串、数值、Time、boolean
67
- # time: (可选)Time 事件发生时间,如果不传默认为系统当前时间
68
- # ip: (可选) 事件 IP,如果传入 IP 地址,后端可以通过 IP 地址解析事件发生地点
69
- # skip_local_check: (可选) boolean 表示是否跳过本地检测
70
- 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
- begin
72
- _check_name event_name
73
- _check_id(distinct_id, account_id)
74
- unless skip_local_check
75
- _check_properties(:track, properties)
76
- end
77
- rescue TDAnalyticsError => e
78
- @error_handler.handle(e)
79
- return false
80
- end
81
-
82
- data = {}
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)
92
- end
93
-
94
- # 上报事件数据可进行更新. 每个事件都包含一个事件名和事件ID以及 Hash 对象的时间属性. 其参数说明如下:
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 表示是否跳过本地检测
103
- 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
- begin
105
- _check_name event_name
106
- _check_event_id event_id
107
- _check_id(distinct_id, account_id)
108
- unless skip_local_check
109
- _check_properties(:track_overwrite, properties)
110
- end
111
- rescue TDAnalyticsError => e
112
- @error_handler.handle(e)
113
- return false
114
- end
115
-
116
- data = {}
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)
125
- end
126
-
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 表示是否跳过本地检测
138
- 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
- begin
140
- _check_name event_name
141
- _check_event_id event_id
142
- _check_id(distinct_id, account_id)
143
- unless skip_local_check
144
- _check_properties(:track_update, properties)
145
- end
146
- rescue TDAnalyticsError => e
147
- @error_handler.handle(e)
148
- return false
149
- end
150
-
151
- data = {}
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)
160
- end
161
-
162
- # 设置用户属性. 如果出现同名属性,则会覆盖之前的值.
163
- # distinct_id: (可选) 访客 ID
164
- # account_id: (可选) 账号ID distinct_id 和 account_id 不能同时为空
165
- # properties: (可选) Hash 用户属性。支持四种类型的值:字符串、数值、Time、boolean
166
- def user_set(distinct_id: nil, account_id: nil, properties: {}, ip: nil)
167
- begin
168
- _check_id(distinct_id, account_id)
169
- _check_properties(:user_set, properties)
170
- rescue TDAnalyticsError => e
171
- @error_handler.handle(e)
172
- return false
173
- end
174
-
175
- _internal_track(:user_set,
176
- distinct_id: distinct_id,
177
- account_id: account_id,
178
- properties: properties,
179
- ip: ip,
180
- )
181
- end
182
-
183
- # 设置用户属性. 如果有重名属性,则丢弃, 参数与 user_set 相同
184
- def user_set_once(distinct_id: nil, account_id: nil, properties: {}, ip: nil)
185
- begin
186
- _check_id(distinct_id, account_id)
187
- _check_properties(:user_setOnce, properties)
188
- rescue TDAnalyticsError => e
189
- @error_handler.handle(e)
190
- return false
191
- end
192
-
193
- _internal_track(:user_setOnce,
194
- distinct_id: distinct_id,
195
- account_id: account_id,
196
- properties: properties,
197
- ip: ip,
198
- )
199
- end
200
-
201
- # 追加用户的一个或多个列表类型的属性
202
- def user_append(distinct_id: nil, account_id: nil, properties: {})
203
- begin
204
- _check_id(distinct_id, account_id)
205
- _check_properties(:user_append, properties)
206
- rescue TDAnalyticsError => e
207
- @error_handler.handle(e)
208
- return false
209
- end
210
-
211
- _internal_track(:user_append,
212
- distinct_id: distinct_id,
213
- account_id: account_id,
214
- properties: properties,
215
- )
216
- end
217
-
218
- # 删除用户属性, property 可以传入需要删除的用户属性的 key 值,或者 key 值数组
219
- def user_unset(distinct_id: nil, account_id: nil, property: nil)
220
- properties = {}
221
- if property.is_a?(Array)
222
- property.each do |k|
223
- properties[k] = 0
224
- end
225
- else
226
- properties[property] = 0
227
- end
228
-
229
- begin
230
- _check_id(distinct_id, account_id)
231
- _check_properties(:user_unset, properties)
232
- rescue TDAnalyticsError => e
233
- @error_handler.handle(e)
234
- return false
235
- end
236
-
237
- _internal_track(:user_unset,
238
- distinct_id: distinct_id,
239
- account_id: account_id,
240
- properties: properties,
241
- )
242
- end
243
-
244
- # 累加用户属性, 如果用户属性不存在,则会设置为 0,然后再累加
245
- # distinct_id: (可选) 访客 ID
246
- # account_id: (可选) 账号ID distinct_id 和 account_id 不能同时为空
247
- # properties: (可选) Hash 数值类型的用户属性
248
- def user_add(distinct_id: nil, account_id: nil, properties: {})
249
- begin
250
- _check_id(distinct_id, account_id)
251
- _check_properties(:user_add, properties)
252
- rescue TDAnalyticsError => e
253
- @error_handler.handle(e)
254
- return false
255
- end
256
-
257
- _internal_track(:user_add,
258
- distinct_id: distinct_id,
259
- account_id: account_id,
260
- properties: properties,
261
- )
262
- end
263
-
264
- # 删除用户,用户之前的事件数据不会被删除
265
- def user_del(distinct_id: nil, account_id: nil)
266
- begin
267
- _check_id(distinct_id, account_id)
268
- rescue TDAnalyticsError => e
269
- @error_handler.handle(e)
270
- return false
271
- end
272
-
273
- _internal_track(:user_del,
274
- distinct_id: distinct_id,
275
- account_id: account_id,
276
- )
277
- end
278
-
279
- # 立即上报数据,对于 BatchConsumer 会触发上报
280
- def flush
281
- return true unless defined? @consumer.flush
282
- ret = true
283
- begin
284
- @consumer.flush
285
- rescue TDAnalyticsError => e
286
- @error_handler.handle(e)
287
- ret = false
288
- end
289
- ret
290
- end
291
-
292
- # 退出前调用,保证 Consumer 安全退出
293
- def close
294
- return true unless defined? @consumer.close
295
- ret = true
296
- begin
297
- @consumer.close
298
- rescue TDAnalyticsError => e
299
- @error_handler.handle(e)
300
- ret = false
301
- end
302
- ret
303
- end
304
-
305
- private
306
-
307
- # 出现异常的时候返回 false, 否则 true
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
-
313
- if type == :track || type == :track_update || type == :track_overwrite
314
- raise IllegalParameterError.new('event name is empty') if event_name == nil
315
- properties = {'#zone_offset': time.utc_offset / 3600.0}.merge(LIB_PROPERTIES).merge(@super_properties).merge(properties)
316
- end
317
-
318
- # 格式化 Time 类型
319
- properties.each do |k, v|
320
- if v.is_a?(Time)
321
- properties[k] = _format_time(v)
322
- end
323
- end
324
-
325
- data = {
326
- '#type' => type,
327
- '#time' => _format_time(time),
328
- 'properties' => properties,
329
- }
330
-
331
- data['#event_name'] = event_name if (type == :track || type == :track_update || :track_overwrite)
332
- data['#event_id'] = event_id if (type == :track_update || type == :track_overwrite)
333
- data['#account_id'] = account_id if account_id
334
- data['#distinct_id'] = distinct_id if distinct_id
335
- data['#ip'] = ip if ip
336
- data['#first_check_id'] = first_check_id if first_check_id
337
- data['#uuid'] = SecureRandom.uuid if @uuid
338
-
339
- ret = true
340
- begin
341
- @consumer.add(data)
342
- rescue TDAnalyticsError => e
343
- @error_handler.handle(e)
344
- ret = false
345
- end
346
-
347
- ret
348
- end
349
-
350
- # 将 Time 类型格式化为数数指定格式的字符串
351
- def _format_time(time)
352
- time.strftime("%Y-%m-%d %H:%M:%S.#{((time.to_f * 1000.0).to_i % 1000).to_s.rjust(3, "0")}")
353
- end
354
-
355
- def _check_event_id(event_id)
356
- raise IllegalParameterError.new("the event_id or property cannot be nil") if event_id.nil?
357
- true
358
- end
359
-
360
- # 属性名或者事件名检查
361
- def _check_name(name)
362
- raise IllegalParameterError.new("the name of event or property cannot be nil") if name.nil?
363
-
364
- unless name.instance_of?(String) || name.instance_of?(Symbol)
365
- raise IllegalParameterError.new("#{name} is invalid. It must be String or Symbol")
366
- end
367
- true
368
- end
369
-
370
- # 属性类型检查
371
- def _check_properties(type, properties)
372
- unless properties.instance_of? Hash
373
- return false
374
- end
375
-
376
- properties.each do |k, v|
377
- _check_name k
378
- next if v.nil?
379
- unless v.is_a?(Integer) || v.is_a?(Float) || v.is_a?(Symbol) || v.is_a?(String) || v.is_a?(Time) || !!v == v || v.is_a?(Array)
380
- raise IllegalParameterError.new("The value of properties must be type in Integer, Float, Symbol, String, Array,and Time")
381
- end
382
-
383
- if type == :user_add
384
- raise IllegalParameterError.new("Property value for user add must be numbers") unless v.is_a?(Integer) || v.is_a?(Float)
385
- end
386
- if v.is_a?(Array)
387
- v.each_index do |i|
388
- if v[i].is_a?(Time)
389
- v[i] = _format_time(v[i])
390
- end
391
- end
392
- end
393
- end
394
- true
395
- end
396
-
397
- # 检查用户 ID 合法性
398
- def _check_id(distinct_id, account_id)
399
- raise IllegalParameterError.new("account id or distinct id must be provided.") if distinct_id.nil? && account_id.nil?
400
- end
401
- end
402
- end
@@ -1,3 +0,0 @@
1
- module TDAnalytics
2
- VERSION = '1.2.0'
3
- end