thinkingdata-ruby 2.0.0 → 2.0.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 +58 -58
- data/CHANGELOG.md +28 -21
- data/Gemfile +7 -7
- data/LICENSE +201 -201
- data/README.md +11 -11
- data/demo/demo.rb +104 -104
- data/lib/thinkingdata-ruby/td_analytics.rb +509 -495
- data/lib/thinkingdata-ruby/td_batch_consumer.rb +154 -142
- data/lib/thinkingdata-ruby/td_debug_consumer.rb +73 -73
- data/lib/thinkingdata-ruby/td_errors.rb +37 -37
- data/lib/thinkingdata-ruby/td_logger_consumer.rb +86 -76
- data/lib/thinkingdata-ruby/td_version.rb +3 -3
- data/lib/thinkingdata-ruby.rb +4 -4
- data/thinkingdata-ruby.gemspec +16 -16
- metadata +6 -6
|
@@ -1,142 +1,154 @@
|
|
|
1
|
-
require 'json'
|
|
2
|
-
require 'net/http'
|
|
3
|
-
require 'stringio'
|
|
4
|
-
|
|
5
|
-
module ThinkingData
|
|
6
|
-
##
|
|
7
|
-
# Upload data by http
|
|
8
|
-
class TDBatchConsumer
|
|
9
|
-
|
|
10
|
-
# buffer count
|
|
11
|
-
DEFAULT_LENGTH = 20
|
|
12
|
-
MAX_LENGTH = 2000
|
|
13
|
-
|
|
14
|
-
##
|
|
15
|
-
# Init batch consumer
|
|
16
|
-
def initialize(server_url, app_id, max_buffer_length = DEFAULT_LENGTH)
|
|
17
|
-
@server_uri = URI.parse(server_url)
|
|
18
|
-
@server_uri.path = '/sync_server'
|
|
19
|
-
@app_id = app_id
|
|
20
|
-
@compress = true
|
|
21
|
-
@max_length = [max_buffer_length, MAX_LENGTH].min
|
|
22
|
-
@buffers = []
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
#
|
|
29
|
-
# @
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
#
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
@buffers
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
raise
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def
|
|
138
|
-
name
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'net/http'
|
|
3
|
+
require 'stringio'
|
|
4
|
+
|
|
5
|
+
module ThinkingData
|
|
6
|
+
##
|
|
7
|
+
# Upload data by http
|
|
8
|
+
class TDBatchConsumer
|
|
9
|
+
|
|
10
|
+
# buffer count
|
|
11
|
+
DEFAULT_LENGTH = 20
|
|
12
|
+
MAX_LENGTH = 2000
|
|
13
|
+
|
|
14
|
+
##
|
|
15
|
+
# Init batch consumer
|
|
16
|
+
def initialize(server_url, app_id, max_buffer_length = DEFAULT_LENGTH)
|
|
17
|
+
@server_uri = URI.parse(server_url)
|
|
18
|
+
@server_uri.path = '/sync_server'
|
|
19
|
+
@app_id = app_id
|
|
20
|
+
@compress = true
|
|
21
|
+
@max_length = [max_buffer_length, MAX_LENGTH].min
|
|
22
|
+
@buffers = []
|
|
23
|
+
@mutex = Mutex.new
|
|
24
|
+
TDLog.info("TDBatchConsumer init success. ServerUrl: #{server_url}, appId: #{app_id}")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
##
|
|
28
|
+
# http request compress
|
|
29
|
+
# @param compress [Boolean] compress or not
|
|
30
|
+
# @deprecated please use: set_compress
|
|
31
|
+
def _set_compress(compress)
|
|
32
|
+
@compress = compress
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
##
|
|
36
|
+
# http request compress
|
|
37
|
+
# @param compress [Boolean] compress or not
|
|
38
|
+
def set_compress(compress)
|
|
39
|
+
@compress = compress
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def add(message)
|
|
43
|
+
TDLog.info("Enqueue data to buffer. buffer size: #{@buffers.length}, data: #{message}")
|
|
44
|
+
need_flush = false
|
|
45
|
+
@mutex.synchronize do
|
|
46
|
+
@buffers << message
|
|
47
|
+
need_flush = @buffers.length >= @max_length
|
|
48
|
+
end
|
|
49
|
+
flush if need_flush
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def close
|
|
53
|
+
flush
|
|
54
|
+
TDLog.info("TDBatchConsumer close.")
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def flush
|
|
58
|
+
TDLog.info("TDBatchConsumer flush data.")
|
|
59
|
+
data_to_send = nil
|
|
60
|
+
@mutex.synchronize do
|
|
61
|
+
data_to_send = @buffers.dup
|
|
62
|
+
@buffers = []
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
return if data_to_send.empty?
|
|
66
|
+
|
|
67
|
+
begin
|
|
68
|
+
data_to_send.each_slice(@max_length) do |chunk|
|
|
69
|
+
if @compress
|
|
70
|
+
wio = StringIO.new("w")
|
|
71
|
+
gzip_io = Zlib::GzipWriter.new(wio)
|
|
72
|
+
gzip_io.write(chunk.to_json)
|
|
73
|
+
gzip_io.close
|
|
74
|
+
data = wio.string
|
|
75
|
+
else
|
|
76
|
+
data = chunk.to_json
|
|
77
|
+
end
|
|
78
|
+
compress_type = @compress ? 'gzip' : 'none'
|
|
79
|
+
headers = {'Content-Type' => 'application/plaintext',
|
|
80
|
+
'appid' => @app_id,
|
|
81
|
+
'compress' => compress_type,
|
|
82
|
+
'TE-Integration-Type'=>'Ruby',
|
|
83
|
+
'TE-Integration-Version'=>ThinkingData::VERSION,
|
|
84
|
+
'TE-Integration-Count'=>data_to_send.count,
|
|
85
|
+
'TA_Integration-Extra'=>'batch'}
|
|
86
|
+
request = CaseSensitivePost.new(@server_uri.request_uri, headers)
|
|
87
|
+
request.body = data
|
|
88
|
+
|
|
89
|
+
TDLog.info("Send data, request: #{data}")
|
|
90
|
+
begin
|
|
91
|
+
response_code, response_body = _request(@server_uri, request)
|
|
92
|
+
TDLog.info("Send data, response: #{response_body}")
|
|
93
|
+
rescue => e
|
|
94
|
+
raise ConnectionError.new("Could not connect to TE server, with error \"#{e.message}\".")
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
result = {}
|
|
98
|
+
if response_code.to_i == 200
|
|
99
|
+
begin
|
|
100
|
+
result = JSON.parse(response_body.to_s)
|
|
101
|
+
rescue JSON::JSONError
|
|
102
|
+
raise ServerError.new("Could not interpret TE server response: '#{response_body}'")
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
if result['code'] != 0
|
|
107
|
+
raise ServerError.new("Could not write to TE, server responded with #{response_code} returning: '#{response_body}'")
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
rescue
|
|
111
|
+
raise
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
private
|
|
116
|
+
def _request(uri, request)
|
|
117
|
+
client = Net::HTTP.new(uri.host, uri.port)
|
|
118
|
+
client.use_ssl = uri.scheme === 'https' ? true : false
|
|
119
|
+
client.open_timeout = 10
|
|
120
|
+
client.continue_timeout = 10
|
|
121
|
+
client.read_timeout = 10
|
|
122
|
+
client.ssl_timeout = 10
|
|
123
|
+
|
|
124
|
+
response = client.request(request)
|
|
125
|
+
[response.code, response.body]
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
##
|
|
130
|
+
# Private class. Send data tools
|
|
131
|
+
class CaseSensitivePost < Net::HTTP::Post
|
|
132
|
+
def initialize_http_header(headers)
|
|
133
|
+
@header = {}
|
|
134
|
+
headers.each{|k,v| @header[k.to_s] = [v] }
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def [](name)
|
|
138
|
+
@header[name.to_s]
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def []=(name, val)
|
|
142
|
+
if val
|
|
143
|
+
@header[name.to_s] = [val]
|
|
144
|
+
else
|
|
145
|
+
@header.delete(name.to_s)
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def capitalize(name)
|
|
150
|
+
name
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
end
|
|
@@ -1,73 +1,73 @@
|
|
|
1
|
-
require 'json'
|
|
2
|
-
require 'net/http'
|
|
3
|
-
|
|
4
|
-
module ThinkingData
|
|
5
|
-
##
|
|
6
|
-
# The data is reported one by one, and when an error occurs, the log will be printed on the console.
|
|
7
|
-
class TDDebugConsumer
|
|
8
|
-
|
|
9
|
-
##
|
|
10
|
-
# Init debug consumer
|
|
11
|
-
# @param server_url: server url
|
|
12
|
-
# @param app_id: app id
|
|
13
|
-
# @param write_data: is write data to TE
|
|
14
|
-
# @param device_id: device id
|
|
15
|
-
def initialize(server_url, app_id, write_data = true, device_id: nil)
|
|
16
|
-
@server_uri = URI.parse(server_url)
|
|
17
|
-
@server_uri.path = '/data_debug'
|
|
18
|
-
@app_id = app_id
|
|
19
|
-
@write_data = write_data
|
|
20
|
-
@device_id = device_id
|
|
21
|
-
TDLog.info("TDDebugConsumer init success. ServerUrl: #{server_url}, appId: #{app_id}, deviceId: #{device_id}")
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def add(message)
|
|
25
|
-
msg_json_str = message.to_json
|
|
26
|
-
TDLog.info("Send data, request: #{msg_json_str}")
|
|
27
|
-
headers = {
|
|
28
|
-
'TE-Integration-Type'=>'Ruby',
|
|
29
|
-
'TE-Integration-Version'=>ThinkingData::VERSION,
|
|
30
|
-
'TE-Integration-Count'=>'1',
|
|
31
|
-
'TA_Integration-Extra'=>'debug'
|
|
32
|
-
}
|
|
33
|
-
form_data = {"data" => msg_json_str, "appid" => @app_id, "dryRun" => @write_data ? "0" : "1", "source" => "server"}
|
|
34
|
-
@device_id.is_a?(String) ? form_data["deviceId"] = @device_id : nil
|
|
35
|
-
|
|
36
|
-
begin
|
|
37
|
-
response_code, response_body = request(@server_uri, form_data,headers)
|
|
38
|
-
TDLog.info("Send data, response: #{response_body}")
|
|
39
|
-
rescue => e
|
|
40
|
-
raise ConnectionError.new("Could not connect to TE server, with error \"#{e.message}\".")
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
result = {}
|
|
44
|
-
if response_code.to_i == 200
|
|
45
|
-
begin
|
|
46
|
-
result = JSON.parse(response_body.to_s)
|
|
47
|
-
rescue JSON::JSONError
|
|
48
|
-
raise ServerError.new("Could not interpret TE server response: '#{response_body}'")
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
if result['errorLevel'] != 0
|
|
53
|
-
raise ServerError.new("Could not write to TE, server responded with #{response_code} returning: '#{response_body}'")
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def request(uri, form_data,headers)
|
|
58
|
-
request = Net::HTTP::Post.new(uri.request_uri, headers)
|
|
59
|
-
request.set_form_data(form_data)
|
|
60
|
-
|
|
61
|
-
client = Net::HTTP.new(uri.host, uri.port)
|
|
62
|
-
client.use_ssl = uri.scheme === 'https' ? true : false
|
|
63
|
-
client.open_timeout = 10
|
|
64
|
-
client.continue_timeout = 10
|
|
65
|
-
client.read_timeout = 10
|
|
66
|
-
client.ssl_timeout = 10
|
|
67
|
-
|
|
68
|
-
response = client.request(request)
|
|
69
|
-
[response.code, response.body]
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
end
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'net/http'
|
|
3
|
+
|
|
4
|
+
module ThinkingData
|
|
5
|
+
##
|
|
6
|
+
# The data is reported one by one, and when an error occurs, the log will be printed on the console.
|
|
7
|
+
class TDDebugConsumer
|
|
8
|
+
|
|
9
|
+
##
|
|
10
|
+
# Init debug consumer
|
|
11
|
+
# @param server_url: server url
|
|
12
|
+
# @param app_id: app id
|
|
13
|
+
# @param write_data: is write data to TE
|
|
14
|
+
# @param device_id: device id
|
|
15
|
+
def initialize(server_url, app_id, write_data = true, device_id: nil)
|
|
16
|
+
@server_uri = URI.parse(server_url)
|
|
17
|
+
@server_uri.path = '/data_debug'
|
|
18
|
+
@app_id = app_id
|
|
19
|
+
@write_data = write_data
|
|
20
|
+
@device_id = device_id
|
|
21
|
+
TDLog.info("TDDebugConsumer init success. ServerUrl: #{server_url}, appId: #{app_id}, deviceId: #{device_id}")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def add(message)
|
|
25
|
+
msg_json_str = message.to_json
|
|
26
|
+
TDLog.info("Send data, request: #{msg_json_str}")
|
|
27
|
+
headers = {
|
|
28
|
+
'TE-Integration-Type'=>'Ruby',
|
|
29
|
+
'TE-Integration-Version'=>ThinkingData::VERSION,
|
|
30
|
+
'TE-Integration-Count'=>'1',
|
|
31
|
+
'TA_Integration-Extra'=>'debug'
|
|
32
|
+
}
|
|
33
|
+
form_data = {"data" => msg_json_str, "appid" => @app_id, "dryRun" => @write_data ? "0" : "1", "source" => "server"}
|
|
34
|
+
@device_id.is_a?(String) ? form_data["deviceId"] = @device_id : nil
|
|
35
|
+
|
|
36
|
+
begin
|
|
37
|
+
response_code, response_body = request(@server_uri, form_data,headers)
|
|
38
|
+
TDLog.info("Send data, response: #{response_body}")
|
|
39
|
+
rescue => e
|
|
40
|
+
raise ConnectionError.new("Could not connect to TE server, with error \"#{e.message}\".")
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
result = {}
|
|
44
|
+
if response_code.to_i == 200
|
|
45
|
+
begin
|
|
46
|
+
result = JSON.parse(response_body.to_s)
|
|
47
|
+
rescue JSON::JSONError
|
|
48
|
+
raise ServerError.new("Could not interpret TE server response: '#{response_body}'")
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
if result['errorLevel'] != 0
|
|
53
|
+
raise ServerError.new("Could not write to TE, server responded with #{response_code} returning: '#{response_body}'")
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def request(uri, form_data,headers)
|
|
58
|
+
request = Net::HTTP::Post.new(uri.request_uri, headers)
|
|
59
|
+
request.set_form_data(form_data)
|
|
60
|
+
|
|
61
|
+
client = Net::HTTP.new(uri.host, uri.port)
|
|
62
|
+
client.use_ssl = uri.scheme === 'https' ? true : false
|
|
63
|
+
client.open_timeout = 10
|
|
64
|
+
client.continue_timeout = 10
|
|
65
|
+
client.read_timeout = 10
|
|
66
|
+
client.ssl_timeout = 10
|
|
67
|
+
|
|
68
|
+
response = client.request(request)
|
|
69
|
+
[response.code, response.body]
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
end
|
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
module ThinkingData
|
|
2
|
-
##
|
|
3
|
-
# SDK error
|
|
4
|
-
TDAnalyticsError = Class.new(StandardError)
|
|
5
|
-
|
|
6
|
-
##
|
|
7
|
-
# SDK error: illegal parameter
|
|
8
|
-
IllegalParameterError = Class.new(TDAnalyticsError)
|
|
9
|
-
|
|
10
|
-
##
|
|
11
|
-
# SDK error: connection error
|
|
12
|
-
ConnectionError = Class.new(TDAnalyticsError)
|
|
13
|
-
|
|
14
|
-
##
|
|
15
|
-
# SDK error: server error
|
|
16
|
-
ServerError = Class.new(TDAnalyticsError)
|
|
17
|
-
|
|
18
|
-
##
|
|
19
|
-
# Error handler
|
|
20
|
-
#
|
|
21
|
-
# e.g.
|
|
22
|
-
# class MyErrorHandler < ThinkingData::ErrorHandler
|
|
23
|
-
# def handle(error)
|
|
24
|
-
# puts error
|
|
25
|
-
# raise error
|
|
26
|
-
# end
|
|
27
|
-
# end
|
|
28
|
-
#
|
|
29
|
-
# my_error_handler = MyErrorHandler.new
|
|
30
|
-
# tracker = ThinkingData::TDAnalytics.new(consumer, my_error_handler)
|
|
31
|
-
class TDErrorHandler
|
|
32
|
-
##
|
|
33
|
-
# Override #handle to customize error handling
|
|
34
|
-
def handle(error)
|
|
35
|
-
false
|
|
36
|
-
end
|
|
37
|
-
end
|
|
1
|
+
module ThinkingData
|
|
2
|
+
##
|
|
3
|
+
# SDK error
|
|
4
|
+
TDAnalyticsError = Class.new(StandardError)
|
|
5
|
+
|
|
6
|
+
##
|
|
7
|
+
# SDK error: illegal parameter
|
|
8
|
+
IllegalParameterError = Class.new(TDAnalyticsError)
|
|
9
|
+
|
|
10
|
+
##
|
|
11
|
+
# SDK error: connection error
|
|
12
|
+
ConnectionError = Class.new(TDAnalyticsError)
|
|
13
|
+
|
|
14
|
+
##
|
|
15
|
+
# SDK error: server error
|
|
16
|
+
ServerError = Class.new(TDAnalyticsError)
|
|
17
|
+
|
|
18
|
+
##
|
|
19
|
+
# Error handler
|
|
20
|
+
#
|
|
21
|
+
# e.g.
|
|
22
|
+
# class MyErrorHandler < ThinkingData::ErrorHandler
|
|
23
|
+
# def handle(error)
|
|
24
|
+
# puts error
|
|
25
|
+
# raise error
|
|
26
|
+
# end
|
|
27
|
+
# end
|
|
28
|
+
#
|
|
29
|
+
# my_error_handler = MyErrorHandler.new
|
|
30
|
+
# tracker = ThinkingData::TDAnalytics.new(consumer, my_error_handler)
|
|
31
|
+
class TDErrorHandler
|
|
32
|
+
##
|
|
33
|
+
# Override #handle to customize error handling
|
|
34
|
+
def handle(error)
|
|
35
|
+
false
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
38
|
end
|