thinkingdata-ruby 2.0.0 → 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.
@@ -1,142 +1,171 @@
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
- TDLog.info("TDBatchConsumer init success. ServerUrl: #{server_url}, appId: #{app_id}")
24
- end
25
-
26
- ##
27
- # http request compress
28
- # @param compress [Boolean] compress or not
29
- # @deprecated please use: set_compress
30
- def _set_compress(compress)
31
- @compress = compress
32
- end
33
-
34
- ##
35
- # http request compress
36
- # @param compress [Boolean] compress or not
37
- def set_compress(compress)
38
- @compress = compress
39
- end
40
-
41
- def add(message)
42
- TDLog.info("Enqueue data to buffer. buffer size: #{@buffers.length}, data: #{message}")
43
- @buffers << message
44
- flush if @buffers.length >= @max_length
45
- end
46
-
47
- def close
48
- flush
49
- TDLog.info("TDBatchConsumer close.")
50
- end
51
-
52
- def flush
53
- TDLog.info("TDBatchConsumer flush data.")
54
- begin
55
- @buffers.each_slice(@max_length) do |chunk|
56
- if @compress
57
- wio = StringIO.new("w")
58
- gzip_io = Zlib::GzipWriter.new(wio)
59
- gzip_io.write(chunk.to_json)
60
- gzip_io.close
61
- data = wio.string
62
- else
63
- data = chunk.to_json
64
- end
65
- compress_type = @compress ? 'gzip' : 'none'
66
- headers = {'Content-Type' => 'application/plaintext',
67
- 'appid' => @app_id,
68
- 'compress' => compress_type,
69
- 'TE-Integration-Type'=>'Ruby',
70
- 'TE-Integration-Version'=>ThinkingData::VERSION,
71
- 'TE-Integration-Count'=>@buffers.count,
72
- 'TA_Integration-Extra'=>'batch'}
73
- request = CaseSensitivePost.new(@server_uri.request_uri, headers)
74
- request.body = data
75
-
76
- TDLog.info("Send data, request: #{data}")
77
- begin
78
- response_code, response_body = _request(@server_uri, request)
79
- TDLog.info("Send data, response: #{response_body}")
80
- rescue => e
81
- raise ConnectionError.new("Could not connect to TE server, with error \"#{e.message}\".")
82
- end
83
-
84
- result = {}
85
- if response_code.to_i == 200
86
- begin
87
- result = JSON.parse(response_body.to_s)
88
- rescue JSON::JSONError
89
- raise ServerError.new("Could not interpret TE server response: '#{response_body}'")
90
- end
91
- end
92
-
93
- if result['code'] != 0
94
- raise ServerError.new("Could not write to TE, server responded with #{response_code} returning: '#{response_body}'")
95
- end
96
- end
97
- rescue
98
- raise
99
- end
100
- @buffers = []
101
- end
102
-
103
- private
104
- def _request(uri, request)
105
- client = Net::HTTP.new(uri.host, uri.port)
106
- client.use_ssl = uri.scheme === 'https' ? true : false
107
- client.open_timeout = 10
108
- client.continue_timeout = 10
109
- client.read_timeout = 10
110
- client.ssl_timeout = 10
111
-
112
- response = client.request(request)
113
- [response.code, response.body]
114
- end
115
- end
116
-
117
- ##
118
- # Private class. Send data tools
119
- class CaseSensitivePost < Net::HTTP::Post
120
- def initialize_http_header(headers)
121
- @header = {}
122
- headers.each{|k,v| @header[k.to_s] = [v] }
123
- end
124
-
125
- def [](name)
126
- @header[name.to_s]
127
- end
128
-
129
- def []=(name, val)
130
- if val
131
- @header[name.to_s] = [val]
132
- else
133
- @header.delete(name.to_s)
134
- end
135
- end
136
-
137
- def capitalize(name)
138
- name
139
- end
140
- end
141
-
142
- end
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
+ @owner_pid = Process.pid
25
+ TDLog.info("TDBatchConsumer init success. ServerUrl: #{server_url}, appId: #{app_id}")
26
+ end
27
+
28
+ ##
29
+ # http request compress
30
+ # @param compress [Boolean] compress or not
31
+ # @deprecated please use: set_compress
32
+ def _set_compress(compress)
33
+ @compress = compress
34
+ end
35
+
36
+ ##
37
+ # http request compress
38
+ # @param compress [Boolean] compress or not
39
+ def set_compress(compress)
40
+ @compress = compress
41
+ end
42
+
43
+ def add(message)
44
+ TDLog.info("Enqueue data to buffer. buffer size: #{@buffers.length}, data: #{message}")
45
+ need_flush = false
46
+ _reset_after_fork_if_needed
47
+ @mutex.synchronize do
48
+ @buffers << message
49
+ need_flush = @buffers.length >= @max_length
50
+ end
51
+ flush if need_flush
52
+ end
53
+
54
+ def close
55
+ _reset_after_fork_if_needed
56
+ flush
57
+ TDLog.info("TDBatchConsumer close.")
58
+ end
59
+
60
+ def flush
61
+ _reset_after_fork_if_needed
62
+ TDLog.info("TDBatchConsumer flush data.")
63
+ data_to_send = nil
64
+ @mutex.synchronize do
65
+ data_to_send = @buffers.dup
66
+ @buffers = []
67
+ end
68
+
69
+ return if data_to_send.empty?
70
+
71
+ chunks = data_to_send.each_slice(@max_length).to_a
72
+ chunks.each_with_index do |chunk, idx|
73
+ begin
74
+ if @compress
75
+ wio = StringIO.new("w")
76
+ gzip_io = Zlib::GzipWriter.new(wio)
77
+ gzip_io.write(chunk.to_json)
78
+ gzip_io.close
79
+ data = wio.string
80
+ else
81
+ data = chunk.to_json
82
+ end
83
+ compress_type = @compress ? 'gzip' : 'none'
84
+ headers = {'Content-Type' => 'application/plaintext',
85
+ 'appid' => @app_id,
86
+ 'compress' => compress_type,
87
+ 'TE-Integration-Type'=>'Ruby',
88
+ 'TE-Integration-Version'=>ThinkingData::VERSION,
89
+ 'TE-Integration-Count'=>chunk.count,
90
+ 'TA_Integration-Extra'=>'batch'}
91
+ request = CaseSensitivePost.new(@server_uri.request_uri, headers)
92
+ request.body = data
93
+
94
+ TDLog.info("Send data, request: #{data}")
95
+ begin
96
+ response_code, response_body = _request(@server_uri, request)
97
+ TDLog.info("Send data, response: #{response_body}")
98
+ rescue => e
99
+ raise ConnectionError.new("Could not connect to TE server, with error \"#{e.message}\".")
100
+ end
101
+
102
+ result = {}
103
+ if response_code.to_i == 200
104
+ begin
105
+ result = JSON.parse(response_body.to_s)
106
+ rescue JSON::JSONError
107
+ raise ServerError.new("Could not interpret TE server response: '#{response_body}'")
108
+ end
109
+ end
110
+
111
+ if result['code'] != 0
112
+ raise ServerError.new("Could not write to TE, server responded with #{response_code} returning: '#{response_body}'")
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
121
+ end
122
+ end
123
+ end
124
+
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
+
133
+ def _request(uri, request)
134
+ client = Net::HTTP.new(uri.host, uri.port)
135
+ client.use_ssl = uri.scheme === 'https' ? true : false
136
+ client.open_timeout = 10
137
+ client.continue_timeout = 10
138
+ client.read_timeout = 10
139
+ client.ssl_timeout = 10
140
+
141
+ response = client.request(request)
142
+ [response.code, response.body]
143
+ end
144
+ end
145
+
146
+ ##
147
+ # Private class. Send data tools
148
+ class CaseSensitivePost < Net::HTTP::Post
149
+ def initialize_http_header(headers)
150
+ @header = {}
151
+ headers.each{|k,v| @header[k.to_s] = [v] }
152
+ end
153
+
154
+ def [](name)
155
+ @header[name.to_s]
156
+ end
157
+
158
+ def []=(name, val)
159
+ if val
160
+ @header[name.to_s] = [val]
161
+ else
162
+ @header.delete(name.to_s)
163
+ end
164
+ end
165
+
166
+ def capitalize(name)
167
+ name
168
+ end
169
+ end
170
+
171
+ 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