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,120 +1,142 @@
1
- require 'json'
2
- require 'net/http'
3
-
4
- module TDAnalytics
5
- # BatchConsumer 批量同步的发送数据.
6
- # 有数据时,首先会加入本地缓冲区,当条数到达上限后会发起上报
7
- class BatchConsumer
8
- # 默认缓冲区大小
9
- DEFAULT_LENGTH = 20
10
- MAX_LENGTH = 2000
11
-
12
- def initialize(server_url, app_id, max_buffer_length = DEFAULT_LENGTH)
13
- @server_uri = URI.parse(server_url)
14
- @server_uri.path = '/sync_server'
15
- @app_id = app_id
16
- @compress = true
17
- @max_length = [max_buffer_length, MAX_LENGTH].min
18
- @buffers = []
19
- end
20
-
21
- def _set_compress(compress)
22
- @compress = compress
23
- end
24
-
25
- def add(message)
26
- @buffers << message
27
- flush if @buffers.length >= @max_length
28
- end
29
-
30
- def close
31
- flush
32
- end
33
-
34
- def flush
35
- begin
36
- @buffers.each_slice(@max_length) do |chunk|
37
- if @compress
38
- wio = StringIO.new("w")
39
- gzip_io = Zlib::GzipWriter.new(wio)
40
- gzip_io.write(chunk.to_json)
41
- gzip_io.close
42
- data = wio.string
43
- else
44
- data = chunk.to_json
45
- end
46
- compress_type = @compress ? 'gzip' : 'none'
47
- headers = {'Content-Type' => 'application/plaintext',
48
- 'appid' => @app_id,
49
- 'compress' => compress_type,
50
- 'TA-Integration-Type'=>'Ruby',
51
- 'TA-Integration-Version'=>TDAnalytics::VERSION,
52
- 'TA-Integration-Count'=>@buffers.count,
53
- 'TA_Integration-Extra'=>'batch'}
54
- request = CaseSensitivePost.new(@server_uri.request_uri, headers)
55
- request.body = data
56
-
57
- begin
58
- response_code, response_body = _request(@server_uri, request)
59
- rescue => e
60
- raise ConnectionError.new("Could not connect to TA server, with error \"#{e.message}\".")
61
- end
62
-
63
- result = {}
64
- if response_code.to_i == 200
65
- begin
66
- result = JSON.parse(response_body.to_s)
67
- rescue JSON::JSONError
68
- raise ServerError.new("Could not interpret TA server response: '#{response_body}'")
69
- end
70
- end
71
-
72
- if result['code'] != 0
73
- raise ServerError.new("Could not write to TA, server responded with #{response_code} returning: '#{response_body}'")
74
- end
75
- end
76
- rescue
77
- raise
78
- end
79
- @buffers = []
80
- end
81
-
82
- private
83
- def _request(uri, request)
84
- client = Net::HTTP.new(uri.host, uri.port)
85
- client.use_ssl = uri.scheme === 'https' ? true : false
86
- client.open_timeout = 10
87
- client.continue_timeout = 10
88
- client.read_timeout = 10
89
- client.ssl_timeout = 10
90
-
91
- response = client.request(request)
92
- [response.code, response.body]
93
- end
94
- end
95
-
96
- # 内部使用,为了兼容老版本服务端,将 Header 名称限定为小写
97
- class CaseSensitivePost < Net::HTTP::Post
98
- def initialize_http_header(headers)
99
- @header = {}
100
- headers.each{|k,v| @header[k.to_s] = [v] }
101
- end
102
-
103
- def [](name)
104
- @header[name.to_s]
105
- end
106
-
107
- def []=(name, val)
108
- if val
109
- @header[name.to_s] = [val]
110
- else
111
- @header.delete(name.to_s)
112
- end
113
- end
114
-
115
- def capitalize(name)
116
- name
117
- end
118
- end
119
-
120
- 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
+ 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
@@ -0,0 +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
@@ -0,0 +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
38
+ end
@@ -0,0 +1,77 @@
1
+ require 'logger'
2
+ require 'thinkingdata-ruby/td_errors'
3
+
4
+ module ThinkingData
5
+
6
+ ##
7
+ # Dismantle the header and save it under another name
8
+ class HeadlessLogger < Logger
9
+ def initialize(logdev, shift_age = 0, shift_size = 1048576)
10
+ super(nil)
11
+ if logdev
12
+ @logdev = HeadlessLogger::LogDevice.new(logdev, shift_age: shift_age, shift_size: shift_size)
13
+ end
14
+ end
15
+
16
+ class LogDevice < ::Logger::LogDevice
17
+ def add_log_header(file); end
18
+ end
19
+ end
20
+
21
+ ##
22
+ # Write data to file, it works with LogBus
23
+ class TDLoggerConsumer
24
+
25
+ ##
26
+ # Init logger consumer
27
+ # @param log_path: log file's path
28
+ # @param mode: file rotate mode
29
+ # @param prefix: file prefix
30
+ def initialize(log_path='.', mode='daily', prefix:'te.log')
31
+ case mode
32
+ when 'hourly'
33
+ @suffix_mode = '%Y-%m-%d-%H'
34
+ when 'daily'
35
+ @suffix_mode = '%Y-%m-%d'
36
+ else
37
+ raise IllegalParameterError.new("#{mode} is unsupported for LoggerConsumer. Replaced it by daily or hourly")
38
+ end
39
+
40
+ raise IllegalParameterError.new("prefix couldn't be empty") if prefix.nil? || prefix.length == 0
41
+
42
+ @current_suffix = Time.now.strftime(@suffix_mode)
43
+ @log_path = log_path
44
+ @full_prefix = "#{log_path}/#{prefix}"
45
+ TDLog.info("TDLoggerConsumer init success. LogPath: #{log_path}")
46
+ _reset
47
+ end
48
+
49
+ def add(msg)
50
+ unless Time.now.strftime(@suffix_mode) == @current_suffix
51
+ @logger.close
52
+ @current_suffix = Time.now.strftime(@suffix_mode)
53
+ _reset
54
+ end
55
+ msg_json_str = msg.to_json
56
+ TDLog.info("Write data to file: #{msg_json_str}")
57
+ @logger.info(msg_json_str)
58
+ end
59
+
60
+ def close
61
+ @logger.close
62
+ TDLog.info("TDLoggerConsumer close.")
63
+ end
64
+
65
+ private
66
+
67
+ def _reset
68
+ Dir::mkdir(@log_path) unless Dir::exist?(@log_path)
69
+ @logger = HeadlessLogger.new("#{@full_prefix}.#{@current_suffix}")
70
+ @logger.level = HeadlessLogger::INFO
71
+ @logger.formatter = proc do |severity, datetime, progname, msg|
72
+ "#{msg}\n"
73
+ end
74
+ end
75
+
76
+ end
77
+ end
@@ -0,0 +1,3 @@
1
+ module ThinkingData
2
+ VERSION = '2.0.0'
3
+ end
@@ -1,5 +1,5 @@
1
- require 'thinkingdata-ruby/logger_consumer'
2
- require 'thinkingdata-ruby/debug_consumer'
3
- require 'thinkingdata-ruby/batch_consumer'
4
- require 'thinkingdata-ruby/tracker'
5
- require 'thinkingdata-ruby/errors'
1
+ require 'thinkingdata-ruby/td_logger_consumer'
2
+ require 'thinkingdata-ruby/td_debug_consumer'
3
+ require 'thinkingdata-ruby/td_batch_consumer'
4
+ require 'thinkingdata-ruby/td_analytics'
5
+ require 'thinkingdata-ruby/td_errors'
@@ -1,16 +1,16 @@
1
- require File.join(File.dirname(__FILE__), 'lib/thinkingdata-ruby/version.rb')
2
-
3
- spec = Gem::Specification.new do |spec|
4
- spec.name = 'thinkingdata-ruby'
5
- spec.version = TDAnalytics::VERSION
6
- spec.files = Dir.glob(`git ls-files`.split("\n"))
7
- spec.require_paths = ['lib']
8
- spec.summary = 'Official ThinkingData Analytics API for ruby'
9
- spec.description = 'The official ThinkingData Analytics API for ruby'
10
- spec.authors = [ 'ThinkingData' ]
11
- spec.email = 'sdk@thinkingdata.cn'
12
- spec.homepage = 'https://github.com/ThinkingDataAnalytics/ruby-sdk'
13
- spec.license = 'Apache-2.0'
14
-
15
- spec.required_ruby_version = '>= 2.0.0'
16
- end
1
+ require File.join(File.dirname(__FILE__), 'lib/thinkingdata-ruby/td_version.rb')
2
+
3
+ spec = Gem::Specification.new do |spec|
4
+ spec.name = 'thinkingdata-ruby'
5
+ spec.version = ThinkingData::VERSION
6
+ spec.files = Dir.glob(`git ls-files`.split("\n"))
7
+ spec.require_paths = ['lib']
8
+ spec.summary = 'Official ThinkingData Analytics API for ruby'
9
+ spec.description = 'The official ThinkingData Analytics API for ruby'
10
+ spec.authors = [ 'ThinkingData' ]
11
+ spec.email = 'sdk@thinkingdata.cn'
12
+ spec.homepage = 'https://github.com/ThinkingDataAnalytics/ruby-sdk'
13
+ spec.license = 'Apache-2.0'
14
+
15
+ spec.required_ruby_version = '>= 2.0.0'
16
+ 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.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ThinkingData
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-28 00:00:00.000000000 Z
11
+ date: 2023-10-26 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,24 +16,25 @@ executables: []
16
16
  extensions: []
17
17
  extra_rdoc_files: []
18
18
  files:
19
+ - ".gitignore"
19
20
  - CHANGELOG.md
20
21
  - Gemfile
21
22
  - LICENSE
22
23
  - README.md
23
24
  - demo/demo.rb
24
25
  - lib/thinkingdata-ruby.rb
25
- - lib/thinkingdata-ruby/batch_consumer.rb
26
- - lib/thinkingdata-ruby/debug_consumer.rb
27
- - lib/thinkingdata-ruby/errors.rb
28
- - lib/thinkingdata-ruby/logger_consumer.rb
29
- - lib/thinkingdata-ruby/tracker.rb
30
- - lib/thinkingdata-ruby/version.rb
26
+ - lib/thinkingdata-ruby/td_analytics.rb
27
+ - lib/thinkingdata-ruby/td_batch_consumer.rb
28
+ - lib/thinkingdata-ruby/td_debug_consumer.rb
29
+ - lib/thinkingdata-ruby/td_errors.rb
30
+ - lib/thinkingdata-ruby/td_logger_consumer.rb
31
+ - lib/thinkingdata-ruby/td_version.rb
31
32
  - thinkingdata-ruby.gemspec
32
33
  homepage: https://github.com/ThinkingDataAnalytics/ruby-sdk
33
34
  licenses:
34
35
  - Apache-2.0
35
36
  metadata: {}
36
- post_install_message:
37
+ post_install_message:
37
38
  rdoc_options: []
38
39
  require_paths:
39
40
  - lib
@@ -48,8 +49,8 @@ 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.3
52
- signing_key:
52
+ rubygems_version: 3.4.6
53
+ signing_key:
53
54
  specification_version: 4
54
55
  summary: Official ThinkingData Analytics API for ruby
55
56
  test_files: []
@@ -1,61 +0,0 @@
1
- require 'json'
2
- require 'net/http'
3
-
4
- module TDAnalytics
5
- # DebugConsumer 逐条、同步地向服务端上报数据
6
- # DebugConsumer 会返回详细的报错信息,建议在集成阶段先使用 DebugConsumer 调试接口
7
- class DebugConsumer
8
-
9
- def initialize(server_url, app_id, write_data = true)
10
- @server_uri = URI.parse(server_url)
11
- @server_uri.path = '/data_debug'
12
- @app_id = app_id
13
- @write_data = write_data
14
- end
15
-
16
- def add(message)
17
- puts message.to_json
18
- headers = {
19
- 'TA-Integration-Type'=>'Ruby',
20
- 'TA-Integration-Version'=>TDAnalytics::VERSION,
21
- 'TA-Integration-Count'=>'1',
22
- 'TA_Integration-Extra'=>'debug'
23
- }
24
- form_data = {"data" => message.to_json, "appid" => @app_id, "dryRun" => @write_data ? "0" : "1", "source" => "server"}
25
- begin
26
- response_code, response_body = request(@server_uri, form_data,headers)
27
- rescue => e
28
- raise ConnectionError.new("Could not connect to TA server, with error \"#{e.message}\".")
29
- end
30
-
31
- result = {}
32
- if response_code.to_i == 200
33
- begin
34
- result = JSON.parse(response_body.to_s)
35
- rescue JSON::JSONError
36
- raise ServerError.new("Could not interpret TA server response: '#{response_body}'")
37
- end
38
- end
39
-
40
- if result['errorLevel'] != 0
41
- raise ServerError.new("Could not write to TA, server responded with #{response_code} returning: '#{response_body}'")
42
- end
43
- end
44
-
45
- def request(uri, form_data,headers)
46
- request = Net::HTTP::Post.new(uri.request_uri,headers)
47
- request.set_form_data(form_data)
48
-
49
- client = Net::HTTP.new(uri.host, uri.port)
50
- client.use_ssl = uri.scheme === 'https' ? true : false
51
- client.open_timeout = 10
52
- client.continue_timeout = 10
53
- client.read_timeout = 10
54
- client.ssl_timeout = 10
55
-
56
- response = client.request(request)
57
- [response.code, response.body]
58
- end
59
- end
60
-
61
- end
@@ -1,35 +0,0 @@
1
- module TDAnalytics
2
-
3
- # TD Analytics SDK 的错误
4
- TDAnalyticsError = Class.new(StandardError)
5
-
6
- # 参数不合法
7
- IllegalParameterError = Class.new(TDAnalyticsError)
8
-
9
- # 网络连接错误
10
- ConnectionError = Class.new(TDAnalyticsError)
11
-
12
- # 服务器返回错误
13
- ServerError = Class.new(TDAnalyticsError)
14
-
15
-
16
- # 默认情况下,所有异常都不会被抛出。如果希望自己处理异常,可以实现继承自 ErrorHandler 的
17
- # 错误处理类,并在初始化 SDK 的时候作为参数传入.
18
- # 例如:
19
- # class MyErrorHandler < TDAnalytics::ErrorHandler
20
- # def handle(error)
21
- # puts error
22
- # raise error
23
- # end
24
- # end
25
- #
26
- # my_error_handler = MyErrorHandler.new
27
- # tracker = TDAnalytics::Tracker.new(consumer, my_error_handler)
28
- class ErrorHandler
29
-
30
- # Override #handle to customize error handling
31
- def handle(error)
32
- false
33
- end
34
- end
35
- end