thinkingdata-ruby 2.0.1 → 2.0.2
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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5faa8253295effbc9ff765bc22bca617bd822ee9d4c7de19bbbce266413f3c1f
|
|
4
|
+
data.tar.gz: 4872918901d705fc9ae980279dfdae1a15b2e266a7372df3a4ae9e1d8c9b676d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4aba5b203c92631de33b27362947fed059eb6b9ff8d2b1946e2a196d99fcf9b832087f528df72c6a37e5f2424bc2a59eaf556493182b83bf7542761ea5053c93
|
|
7
|
+
data.tar.gz: 975676199eb20cac647afafff3982d220fd11814c84f538819cb58741c9ab3e27493dba586110a3d02c2fd73843815df5ef74baac8a85b16a4aac7abe4456676
|
data/CHANGELOG.md
CHANGED
|
@@ -48,9 +48,7 @@ module ThinkingData
|
|
|
48
48
|
LIB_PROPERTIES = {
|
|
49
49
|
'#lib' => 'ruby',
|
|
50
50
|
'#lib_version' => ThinkingData::VERSION,
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
@dynamic_block = nil
|
|
51
|
+
}.freeze
|
|
54
52
|
|
|
55
53
|
##
|
|
56
54
|
# Init function
|
|
@@ -60,7 +58,7 @@ module ThinkingData
|
|
|
60
58
|
def initialize(consumer, error_handler = nil, uuid: false)
|
|
61
59
|
@error_handler = error_handler || TDErrorHandler.new
|
|
62
60
|
@consumer = consumer
|
|
63
|
-
@super_properties = {}
|
|
61
|
+
@super_properties = {}.freeze
|
|
64
62
|
@uuid_enable = uuid
|
|
65
63
|
@mutex = Mutex.new
|
|
66
64
|
TDLog.info("SDK init success.")
|
|
@@ -74,13 +72,11 @@ module ThinkingData
|
|
|
74
72
|
@error_handler.handle(IllegalParameterError.new("Invalid super properties"))
|
|
75
73
|
return false
|
|
76
74
|
end
|
|
75
|
+
formatted = {}
|
|
77
76
|
properties.each do |k, v|
|
|
78
|
-
|
|
79
|
-
@super_properties[k] = _format_time(v)
|
|
80
|
-
else
|
|
81
|
-
@super_properties[k] = v
|
|
82
|
-
end
|
|
77
|
+
formatted[k] = v.is_a?(Time) ? _format_time(v) : v
|
|
83
78
|
end
|
|
79
|
+
@super_properties = @super_properties.merge(formatted).freeze
|
|
84
80
|
end
|
|
85
81
|
end
|
|
86
82
|
|
|
@@ -88,7 +84,7 @@ module ThinkingData
|
|
|
88
84
|
# Clear super properties
|
|
89
85
|
def clear_super_properties
|
|
90
86
|
@mutex.synchronize do
|
|
91
|
-
@super_properties = {}
|
|
87
|
+
@super_properties = {}.freeze
|
|
92
88
|
end
|
|
93
89
|
end
|
|
94
90
|
|
|
@@ -341,7 +337,7 @@ module ThinkingData
|
|
|
341
337
|
# Report data immediately
|
|
342
338
|
def flush
|
|
343
339
|
TDLog.info("SDK flush data.")
|
|
344
|
-
return true unless
|
|
340
|
+
return true unless @consumer.respond_to?(:flush)
|
|
345
341
|
ret = true
|
|
346
342
|
begin
|
|
347
343
|
@consumer.flush
|
|
@@ -355,7 +351,7 @@ module ThinkingData
|
|
|
355
351
|
##
|
|
356
352
|
# Close and exit sdk
|
|
357
353
|
def close
|
|
358
|
-
return true unless
|
|
354
|
+
return true unless @consumer.respond_to?(:close)
|
|
359
355
|
ret = true
|
|
360
356
|
# Consumer 自身已有锁保护,无需在此加锁
|
|
361
357
|
begin
|
|
@@ -375,12 +371,17 @@ module ThinkingData
|
|
|
375
371
|
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)
|
|
376
372
|
ret = true
|
|
377
373
|
|
|
378
|
-
#
|
|
374
|
+
# Snapshot @dynamic_block under the mutex for memory visibility;
|
|
375
|
+
# @super_properties is a frozen hash replaced atomically — safe lock-free read.
|
|
376
|
+
# The dynamic block is called OUTSIDE the mutex to prevent deadlocks
|
|
377
|
+
# (if the block calls back into TDAnalytics) and throughput collapse.
|
|
379
378
|
if type == :track || type == :track_update || type == :track_overwrite
|
|
380
|
-
@mutex.synchronize
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
379
|
+
block = @mutex.synchronize { @dynamic_block }
|
|
380
|
+
dynamic_properties = block.respond_to?(:call) ? block.call : {}
|
|
381
|
+
properties = LIB_PROPERTIES.merge(@super_properties).merge(dynamic_properties).merge(properties)
|
|
382
|
+
else
|
|
383
|
+
# user_* methods: dup to avoid mutating the caller's hash
|
|
384
|
+
properties = properties.dup
|
|
384
385
|
end
|
|
385
386
|
|
|
386
387
|
data = {
|
|
@@ -390,6 +391,8 @@ module ThinkingData
|
|
|
390
391
|
properties.each do |k, v|
|
|
391
392
|
if v.is_a?(Time)
|
|
392
393
|
properties[k] = _format_time(v)
|
|
394
|
+
elsif v.is_a?(Array)
|
|
395
|
+
properties[k] = v.map { |e| e.is_a?(Time) ? _format_time(e) : e }
|
|
393
396
|
end
|
|
394
397
|
end
|
|
395
398
|
|
|
@@ -466,13 +469,6 @@ module ThinkingData
|
|
|
466
469
|
if type == :user_add
|
|
467
470
|
raise IllegalParameterError.new("Property value for user add must be numbers") unless v.is_a?(Integer) || v.is_a?(Float)
|
|
468
471
|
end
|
|
469
|
-
if v.is_a?(Array)
|
|
470
|
-
v.each_index do |i|
|
|
471
|
-
if v[i].is_a?(Time)
|
|
472
|
-
v[i] = _format_time(v[i])
|
|
473
|
-
end
|
|
474
|
-
end
|
|
475
|
-
end
|
|
476
472
|
end
|
|
477
473
|
true
|
|
478
474
|
end
|
|
@@ -21,6 +21,7 @@ module ThinkingData
|
|
|
21
21
|
@max_length = [max_buffer_length, MAX_LENGTH].min
|
|
22
22
|
@buffers = []
|
|
23
23
|
@mutex = Mutex.new
|
|
24
|
+
@owner_pid = Process.pid
|
|
24
25
|
TDLog.info("TDBatchConsumer init success. ServerUrl: #{server_url}, appId: #{app_id}")
|
|
25
26
|
end
|
|
26
27
|
|
|
@@ -42,6 +43,7 @@ module ThinkingData
|
|
|
42
43
|
def add(message)
|
|
43
44
|
TDLog.info("Enqueue data to buffer. buffer size: #{@buffers.length}, data: #{message}")
|
|
44
45
|
need_flush = false
|
|
46
|
+
_reset_after_fork_if_needed
|
|
45
47
|
@mutex.synchronize do
|
|
46
48
|
@buffers << message
|
|
47
49
|
need_flush = @buffers.length >= @max_length
|
|
@@ -50,11 +52,13 @@ module ThinkingData
|
|
|
50
52
|
end
|
|
51
53
|
|
|
52
54
|
def close
|
|
55
|
+
_reset_after_fork_if_needed
|
|
53
56
|
flush
|
|
54
57
|
TDLog.info("TDBatchConsumer close.")
|
|
55
58
|
end
|
|
56
59
|
|
|
57
60
|
def flush
|
|
61
|
+
_reset_after_fork_if_needed
|
|
58
62
|
TDLog.info("TDBatchConsumer flush data.")
|
|
59
63
|
data_to_send = nil
|
|
60
64
|
@mutex.synchronize do
|
|
@@ -64,8 +68,9 @@ module ThinkingData
|
|
|
64
68
|
|
|
65
69
|
return if data_to_send.empty?
|
|
66
70
|
|
|
67
|
-
|
|
68
|
-
|
|
71
|
+
chunks = data_to_send.each_slice(@max_length).to_a
|
|
72
|
+
chunks.each_with_index do |chunk, idx|
|
|
73
|
+
begin
|
|
69
74
|
if @compress
|
|
70
75
|
wio = StringIO.new("w")
|
|
71
76
|
gzip_io = Zlib::GzipWriter.new(wio)
|
|
@@ -81,7 +86,7 @@ module ThinkingData
|
|
|
81
86
|
'compress' => compress_type,
|
|
82
87
|
'TE-Integration-Type'=>'Ruby',
|
|
83
88
|
'TE-Integration-Version'=>ThinkingData::VERSION,
|
|
84
|
-
'TE-Integration-Count'=>
|
|
89
|
+
'TE-Integration-Count'=>chunk.count,
|
|
85
90
|
'TA_Integration-Extra'=>'batch'}
|
|
86
91
|
request = CaseSensitivePost.new(@server_uri.request_uri, headers)
|
|
87
92
|
request.body = data
|
|
@@ -106,13 +111,25 @@ module ThinkingData
|
|
|
106
111
|
if result['code'] != 0
|
|
107
112
|
raise ServerError.new("Could not write to TE, server responded with #{response_code} returning: '#{response_body}'")
|
|
108
113
|
end
|
|
114
|
+
rescue => e
|
|
115
|
+
# Re-enqueue the failed chunk AND every not-yet-sent chunk to the back,
|
|
116
|
+
# so that raising here never drops data still pending in this flush.
|
|
117
|
+
# New data already in @buffers stays ahead, failed data retries next flush.
|
|
118
|
+
remaining = chunks[idx..-1].flatten(1)
|
|
119
|
+
@mutex.synchronize { @buffers = @buffers + remaining }
|
|
120
|
+
raise e
|
|
109
121
|
end
|
|
110
|
-
rescue
|
|
111
|
-
raise
|
|
112
122
|
end
|
|
113
123
|
end
|
|
114
124
|
|
|
115
125
|
private
|
|
126
|
+
def _reset_after_fork_if_needed
|
|
127
|
+
return if @owner_pid == Process.pid
|
|
128
|
+
@owner_pid = Process.pid
|
|
129
|
+
@mutex = Mutex.new
|
|
130
|
+
@buffers = []
|
|
131
|
+
end
|
|
132
|
+
|
|
116
133
|
def _request(uri, request)
|
|
117
134
|
client = Net::HTTP.new(uri.host, uri.port)
|
|
118
135
|
client.use_ssl = uri.scheme === 'https' ? true : false
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'logger'
|
|
2
|
+
require 'fileutils'
|
|
2
3
|
require 'thinkingdata-ruby/td_errors'
|
|
3
4
|
|
|
4
5
|
module ThinkingData
|
|
@@ -43,11 +44,13 @@ module ThinkingData
|
|
|
43
44
|
@log_path = log_path
|
|
44
45
|
@full_prefix = "#{log_path}/#{prefix}"
|
|
45
46
|
@mutex = Mutex.new
|
|
47
|
+
@owner_pid = Process.pid
|
|
46
48
|
TDLog.info("TDLoggerConsumer init success. LogPath: #{log_path}")
|
|
47
49
|
_reset
|
|
48
50
|
end
|
|
49
51
|
|
|
50
52
|
def add(msg)
|
|
53
|
+
_reset_after_fork_if_needed
|
|
51
54
|
@mutex.synchronize do
|
|
52
55
|
unless Time.now.strftime(@suffix_mode) == @current_suffix
|
|
53
56
|
@logger.close
|
|
@@ -66,6 +69,7 @@ module ThinkingData
|
|
|
66
69
|
end
|
|
67
70
|
|
|
68
71
|
def close
|
|
72
|
+
_reset_after_fork_if_needed
|
|
69
73
|
@mutex.synchronize do
|
|
70
74
|
@logger.close
|
|
71
75
|
end
|
|
@@ -75,7 +79,7 @@ module ThinkingData
|
|
|
75
79
|
private
|
|
76
80
|
|
|
77
81
|
def _reset
|
|
78
|
-
|
|
82
|
+
FileUtils.mkdir_p(@log_path)
|
|
79
83
|
@logger = HeadlessLogger.new("#{@full_prefix}.#{@current_suffix}")
|
|
80
84
|
@logger.level = HeadlessLogger::INFO
|
|
81
85
|
@logger.formatter = proc do |severity, datetime, progname, msg|
|
|
@@ -83,5 +87,13 @@ module ThinkingData
|
|
|
83
87
|
end
|
|
84
88
|
end
|
|
85
89
|
|
|
90
|
+
def _reset_after_fork_if_needed
|
|
91
|
+
return if @owner_pid == Process.pid
|
|
92
|
+
@owner_pid = Process.pid
|
|
93
|
+
@mutex = Mutex.new
|
|
94
|
+
@logger = nil # Don't close — FD is shared with parent
|
|
95
|
+
_reset
|
|
96
|
+
end
|
|
97
|
+
|
|
86
98
|
end
|
|
87
99
|
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: 2.0.
|
|
4
|
+
version: 2.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- ThinkingData
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-05
|
|
11
|
+
date: 2026-06-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: The official ThinkingData Analytics API for ruby
|
|
14
14
|
email: sdk@thinkingdata.cn
|