thinkingdata-ruby 1.2.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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