liveqa 1.8.3 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: eedcd2fa28e813d0ebde999b52507b9dd8517668
4
- data.tar.gz: a7739558d0b587260136c1d9a364dead5c283d43
3
+ metadata.gz: 9e2af9cc4ebfb7e97a8330c769db5ffb49989ec9
4
+ data.tar.gz: 4261ba5bbe8cbebd535f876fe9f8762e460286cf
5
5
  SHA512:
6
- metadata.gz: fd51dba298a81bc4f67a98db6ec8a2adc0cb418f9c474f787c39b6ffa9ed57393dff40c4d1e333f9afdebac25003872c9cbac51e34c53dddb754e18bde58eeb1
7
- data.tar.gz: ecbb7fa596f45776d43abb4b7fc3c2e1f2d5b4e2853b6702da72a045c22d963a32a964e108c7075fe228dbbd09715130b4eb4147c4820fc640d1ac86d1ad78bf
6
+ metadata.gz: 0f5fc2bd622bdf4e98573f3205ced2fce4ae9b569e398ab28633654cffaf2a3c1e2532c63da9f8352bcc74482d787fd6958104d0c02d52afe83baf3596374595
7
+ data.tar.gz: 7e2fccdb0c9a117a852989f3ab3e7744b958a0f31f3014cff519614492b3d3cdc862956e375ef6f715c747908170674708ca034a2b578d41201b3c9034f84a91
data/.rubocop.yml CHANGED
@@ -22,7 +22,13 @@ Layout/EmptyLinesAroundBlockBody:
22
22
 
23
23
  Style/FrozenStringLiteralComment:
24
24
  Enabled: false
25
- Style/MethodMissing:
25
+ Style/MissingRespondToMissing:
26
+ Enabled: false
27
+ Style/TrailingCommaInHashLiteral:
28
+ EnforcedStyleForMultiline: comma
29
+ Style/TrailingCommaInArrayLiteral:
30
+ EnforcedStyleForMultiline: comma
31
+ Style/TrailingCommaInArguments:
26
32
  Enabled: false
27
33
 
28
34
  Documentation:
@@ -32,7 +38,7 @@ Bundler/DuplicatedGem:
32
38
  Enabled: false
33
39
 
34
40
  AllCops:
35
- TargetRubyVersion: 2.3
41
+ TargetRubyVersion: 2.2
36
42
  Exclude:
37
43
  - 'spec/**/*'
38
44
  Exclude:
data/.travis.yml CHANGED
@@ -1,7 +1,6 @@
1
1
  cache: bundler
2
2
  language: ruby
3
3
  rvm:
4
- - 2.1
5
4
  - 2.2
6
5
  - 2.3
7
6
  - 2.4
data/LICENCE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2018- LiveQA, Inc. (https://www.liveqa.com)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md CHANGED
@@ -1,127 +1,20 @@
1
1
  # LiveQA
2
2
 
3
- [![Build Status](https://travis-ci.org/arkes/liveqa-ruby.svg?branch=master)](https://travis-ci.org/arkes/liveqa-ruby)
3
+ [![Build Status](https://travis-ci.org/LiveQA/liveqa-ruby.svg?branch=master)](https://travis-ci.org/LiveQA/liveqa-ruby)
4
4
 
5
- LiveQA ruby integration for [LiveQA](https://www.liveqa.io)
6
-
7
- ## Installation
8
-
9
- ```sh
10
- gem install liveqa
11
- ```
12
-
13
- For Rails in your Gemfile
14
-
15
- ```ruby
16
- gem 'liveqa'
17
- ```
18
-
19
- ## Configuration
20
-
21
- ```ruby
22
- LiveQA.configure do |config|
23
- ##
24
- # Account token can be found inside your environment settings
25
- config.account_token = 'acc_xx'
26
-
27
- ##
28
- # The name of your space
29
- config.space_name = 'LiveQA'
30
-
31
- ##
32
- # The name of your environement
33
- config.environment_name = 'production'
34
-
35
- ##
36
- # If you use a proxy.
37
- # default: nil
38
- # config.proxy_url = ENV['HTTP_PROXY']
39
-
40
- ##
41
- # If enabled is set to false nothing is send to the server
42
- # default: true
43
- # config.enabled = true
44
-
45
- ##
46
- # Extra attributes to be obfuscated
47
- # default: []
48
- # config.obfuscated_fields = ['credit_card_number']
49
-
50
- ##
51
- # Use an async handler to send data to the liveqa to
52
- # avoid slowing down your application
53
- # available option: :sidekiq
54
- # default: nil
55
- # config.async_handler = :sidekiq
56
-
57
- ##
58
- # Options to be passed to the async handler
59
- # default: {}
60
- # config.async_options = { queue: 'liveqa' }
5
+ [LiveQA](https://www.liveqa.io) Ruby library
61
6
 
62
- ##
63
- # Metadata is passed with every request to the server
64
- # default: nil
65
- # config.metadata = {
66
- #. customer: -> { current_customer.id},
67
- #. version: 42
68
- # }
69
- #
70
- end
71
- ```
7
+ Our Ruby library let's you interact easily with our API. All the request will go to our servers and will be display processed and display inside our debugger.
72
8
 
73
- ## Usage
9
+ ## Setup
74
10
 
75
- ### Track
11
+ - [Start by creating an account](https://www.liveqa.io/register)
12
+ - Follow the [Quick Start Guide](https://docs.liveqa.io/docs/quick-start) to get set up
13
+ - Use our [Ruby Library](https://docs.liveqa.io/docs/ruby) to install and configure LiveQA for your platform.
76
14
 
77
- Track an event
78
15
 
79
- Attributes:
16
+ ## Documentation & Usage
80
17
 
81
- * `String` event name
82
- * `Hash` event attributes
18
+ Documentation is available at [docs.liveqa.io/docs/ruby](https://docs.liveqa.io/docs/ruby)
83
19
 
84
- ```ruby
85
- LiveQA.track('my event',
86
- user_id: 42,
87
- properties: {
88
- order_id: 84
89
- }
90
- );
91
- ```
92
-
93
- ### Identify
94
-
95
- Identify a user
96
-
97
- Attributes:
98
-
99
- * `String` user id from your database
100
- * `Hash` user attributes
101
-
102
- ```ruby
103
- LiveQA.identify(42,
104
- properties: {
105
- name: 'John Doe'
106
- }
107
- );
108
- ```
109
-
110
- ### Watch
111
-
112
- Create a watcher
113
-
114
- Attributes:
115
-
116
- * `String|Integer` template flow name or id
117
- * `Hash` watcher attributes
118
-
119
- ```ruby
120
- LiveQA.watch('My Flow',
121
- expected_times: 42
122
- );
123
- ```
124
-
125
- ## Issues
126
-
127
- If you have any issue you can report them on github, or contact support@liveqa.io
20
+ LiveQA ruby integration for [LiveQA](https://www.liveqa.io)
@@ -60,7 +60,9 @@ module LiveQA
60
60
  #
61
61
  # @return [Hash] response
62
62
  # @raise [LiveQA::RequestError] if the request is invalid
63
+ # rubocop:disable Metrics/AbcSize
63
64
  def request(method, path, payload = {}, options = {})
65
+ payload[:sent_at] = Time.now.utc.iso8601(3)
64
66
  payload = Util.deep_obfuscate_value(payload, configurations.obfuscated_fields)
65
67
  url_params = Util.encode_parameters(payload) if method == :get
66
68
  uri = build_endpoint_url(path, url_params)
@@ -76,7 +78,9 @@ module LiveQA
76
78
  Request.execute(request_options).body
77
79
  rescue LiveQA::RequestError => error
78
80
  return error.http_body if error.http_status == 422
81
+ raise
79
82
  end
83
+ # rubocop:enable Metrics/AbcSize
80
84
 
81
85
  private
82
86
 
@@ -99,7 +103,7 @@ module LiveQA
99
103
  return {} unless configurations.http_secure
100
104
  {
101
105
  ca_file: File.expand_path(File.dirname(__FILE__) + '/../../vendor/cacert.pem'),
102
- verify_mode: OpenSSL::SSL::VERIFY_PEER
106
+ verify_mode: OpenSSL::SSL::VERIFY_PEER,
103
107
  }
104
108
  end
105
109
 
@@ -110,8 +114,8 @@ module LiveQA
110
114
  content_type: 'application/json',
111
115
  x_account_token: options.delete(:account_token) || configurations.account_token,
112
116
  x_space_name: options.delete(:space_name) || configurations.space_name,
113
- x_environment_name: options.delete(:environment_name) || configurations.environment_name
114
- }
117
+ x_environment_name: options.delete(:environment_name) || configurations.environment_name,
118
+ },
115
119
  }
116
120
  end
117
121
 
@@ -0,0 +1,18 @@
1
+ module LiveQA
2
+ ##
3
+ # == LiveQA \Batch
4
+ #
5
+ # Accepted Methods:
6
+ #
7
+ # * create
8
+ #
9
+ # @example: Usage
10
+ #
11
+ # request = LiveQA::Batch.create(...) #=> #<LiveQA::Response...>
12
+ #
13
+ class Batch < APIResource
14
+ @resource_name = 'batches'
15
+
16
+ include LiveQA::APIOperation::Save
17
+ end
18
+ end
data/lib/liveqa/config.rb CHANGED
@@ -5,13 +5,6 @@ module LiveQA
5
5
  # Represent the LiveQA configuration for the API
6
6
  class Config
7
7
 
8
- ASYNC_HANDLERS = {
9
- sidekiq: {
10
- class: 'LiveQA::AsyncHandlers::Sidekiq',
11
- require: 'liveqa/async_handlers/sidekiq'
12
- }
13
- }.freeze
14
-
15
8
  DEFAULT_OBFUSCATED_FIELDS = %w[
16
9
  password
17
10
  password_confirmation
@@ -63,12 +56,8 @@ module LiveQA
63
56
  attr_accessor :obfuscated_fields
64
57
 
65
58
  ##
66
- # @return [Null|Symbol|Proc] asynchronous handler
67
- attr_accessor :async_handler
68
-
69
- ##
70
- # @return [Hash] options for asynchronous handler
71
- attr_accessor :async_options
59
+ # @return [Boolean] send
60
+ attr_accessor :async
72
61
 
73
62
  ##
74
63
  # @return [Hash] custom object properties
@@ -78,6 +67,14 @@ module LiveQA
78
67
  # @return [Hash] metadata to be attach to the payload
79
68
  attr_accessor :metadata
80
69
 
70
+ ##
71
+ # @return [Boolean] enable the logger
72
+ attr_accessor :log
73
+
74
+ ##
75
+ # @return [Logger] logger
76
+ attr_accessor :logger
77
+
81
78
  ##
82
79
  # @param [Hash{Symbol=>Object}]
83
80
  # Initialize and validate the configuration
@@ -93,10 +90,11 @@ module LiveQA
93
90
  self.http_secure = options[:http_secure] || true
94
91
  self.enabled = options[:enabled] || true
95
92
  self.obfuscated_fields = options[:obfuscated_fields] || []
96
- self.async_handler = options[:async_handler]
97
- self.async_options = options[:async_options] || {}
93
+ self.async = options[:async] || true
98
94
  self.custom_object_properties = options[:custom_object_properties] || {}
99
95
  self.metadata = options[:metadata]
96
+ self.log = options[:log] || true
97
+ self.logger = FormatedLogger.build(options[:logger])
100
98
  end
101
99
  # rubocop:enable Metrics/CyclomaticComplexity
102
100
  # rubocop:enable Metrics/PerceivedComplexity
@@ -121,15 +119,9 @@ module LiveQA
121
119
  # Format configuration fields
122
120
  #
123
121
  # * Set obfuscated_fields to string
124
- # * Change to the class for async handler
125
122
  #
126
123
  def format!
127
124
  self.obfuscated_fields = (obfuscated_fields.map(&:to_s) + DEFAULT_OBFUSCATED_FIELDS).uniq
128
-
129
- return unless ASYNC_HANDLERS[async_handler]
130
-
131
- require ASYNC_HANDLERS[async_handler][:require]
132
- self.async_handler = Object.const_get(ASYNC_HANDLERS[async_handler][:class]).new(async_options)
133
125
  end
134
126
 
135
127
  def validate_presence(field)
data/lib/liveqa/event.rb CHANGED
@@ -4,7 +4,7 @@ module LiveQA
4
4
  #
5
5
  # Accepted Methods:
6
6
  #
7
- # * update
7
+ # * create
8
8
  #
9
9
  # @example: Usage
10
10
  #
@@ -0,0 +1,45 @@
1
+ module LiveQA
2
+ ##
3
+ # Display formated log
4
+ class FormatedLogger
5
+
6
+ class << self
7
+
8
+ def build(logger)
9
+ return new(logger) if logger
10
+ return new(Rails.logger) if defined?(Rails)
11
+
12
+ new(::Logger.new(STDOUT))
13
+ end
14
+
15
+ end
16
+
17
+ attr_reader :logger
18
+
19
+ PREFIX = '[LiveQA]'.freeze
20
+ METHODS = %i[debug info warn error].freeze
21
+
22
+ def initialize(logger)
23
+ @logger = logger
24
+ end
25
+
26
+ METHODS.each do |method|
27
+ define_method(method) do |message|
28
+ log(method, message)
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def log(type, message)
35
+ return unless configurations.log
36
+
37
+ logger.send(type, "#{PREFIX} #{message}")
38
+ end
39
+
40
+ def configurations
41
+ LiveQA.configurations
42
+ end
43
+
44
+ end
45
+ end
@@ -37,7 +37,7 @@ module LiveQA
37
37
  {
38
38
  name: LiveQA::LIBRARY_NAME,
39
39
  language: 'ruby',
40
- version: LiveQA::VERSION
40
+ version: LiveQA::VERSION,
41
41
  }
42
42
  end
43
43
 
@@ -45,7 +45,7 @@ module LiveQA
45
45
  {
46
46
  host: Socket.gethostname,
47
47
  pid: Process.pid,
48
- software: LiveQA::Store.get(:server_software)
48
+ software: LiveQA::Store.get(:server_software),
49
49
  }
50
50
  end
51
51
 
@@ -56,7 +56,7 @@ module LiveQA
56
56
  if value.is_a?(Proc)
57
57
  begin
58
58
  hash[key] = value.call
59
- rescue
59
+ rescue StandardError => _e
60
60
  nil
61
61
  end
62
62
  next
@@ -90,7 +90,7 @@ module LiveQA
90
90
  uri.merge(
91
91
  "?#{::Rack::Utils.build_query(params)}"
92
92
  ).to_s
93
- rescue
93
+ rescue StandardError => _e
94
94
  ''
95
95
  end
96
96
 
@@ -99,7 +99,7 @@ module LiveQA
99
99
  request.send(type),
100
100
  LiveQA.configurations.obfuscated_fields
101
101
  )
102
- rescue
102
+ rescue StandardError => _e
103
103
  {}
104
104
  end
105
105
 
@@ -125,7 +125,7 @@ module LiveQA
125
125
  headers,
126
126
  LiveQA.configurations.obfuscated_fields
127
127
  )
128
- rescue
128
+ rescue StandardError => _e
129
129
  {}
130
130
  end
131
131
 
@@ -37,7 +37,7 @@ module LiveQA
37
37
 
38
38
  def convert_to_iso8601(int_time)
39
39
  Time.at(int_time).utc.iso8601(3)
40
- rescue
40
+ rescue StandardError => _e
41
41
  nil
42
42
  end
43
43
 
@@ -0,0 +1,48 @@
1
+ module LiveQA
2
+ module Processor
3
+ class Async
4
+
5
+ def initialize
6
+ @max_queue_size = 10_000
7
+ @queue = Queue.new
8
+ @worker = Worker.new(@queue)
9
+ @worker_mutex = Mutex.new
10
+
11
+ at_exit do
12
+ @worker_thread && @worker_thread[:should_exit] = true
13
+ end
14
+ end
15
+
16
+ def enqueue(attributes)
17
+ return false if @queue.length > @max_queue_size
18
+
19
+ @queue << attributes
20
+ ensure_worker_running
21
+
22
+ true
23
+ end
24
+
25
+ def flush
26
+ while !@queue.empty? || @worker.is_requesting?
27
+ ensure_worker_running
28
+ sleep(0.1)
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def ensure_worker_running
35
+ return if worker_running?
36
+ @worker_mutex.synchronize do
37
+ return if worker_running?
38
+ @worker_thread = Thread.new { @worker.run }
39
+ end
40
+ end
41
+
42
+ def worker_running?
43
+ @worker_thread && @worker_thread.alive?
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,81 @@
1
+ module LiveQA
2
+ module Processor
3
+ class Batch
4
+
5
+ attr_reader :messages
6
+
7
+ MAX_BYTES = 204_800 # 200Kb
8
+ MAX_MESSAGES = 100
9
+ MAX_MESSAGE_BYTES = 32_768 # 32Kb
10
+
11
+ MAX_RETRY = 10
12
+ RETRY_MAP = {
13
+ 1 => 2,
14
+ 2 => 5,
15
+ 3 => 10,
16
+ 4 => 20,
17
+ 5 => 30,
18
+ 6 => 30,
19
+ 7 => 30,
20
+ 8 => 30,
21
+ 9 => 30,
22
+ 10 => 30,
23
+ }.freeze
24
+
25
+ def initialize
26
+ @retry_count = 0
27
+ @total_bytes = 0
28
+ @messages = []
29
+ end
30
+
31
+ def <<(message)
32
+ message_json_size = message.to_json.bytesize
33
+
34
+ if max_message_reached?(message_json_size)
35
+ LiveQA.configurations.logger.error('Message is too big to be send')
36
+ return false
37
+ end
38
+
39
+ @total_bytes += message_json_size
40
+
41
+ @messages << message
42
+
43
+ true
44
+ end
45
+
46
+ def full?
47
+ max_messages_reached? || max_size_reached?
48
+ end
49
+
50
+ def update_retry
51
+ @retry_count += 1
52
+ @retry_at = Time.now + (RETRY_MAP[@retry_count] || 120)
53
+ end
54
+
55
+ def can_run?
56
+ return true if @retry_count.zero?
57
+
58
+ Time.now >= @retry_at
59
+ end
60
+
61
+ def can_retry?
62
+ @retry_count < MAX_RETRY
63
+ end
64
+
65
+ private
66
+
67
+ def max_messages_reached?
68
+ @messages.length >= MAX_MESSAGES
69
+ end
70
+
71
+ def max_size_reached?
72
+ @total_bytes >= MAX_BYTES
73
+ end
74
+
75
+ def max_message_reached?(message_json_size)
76
+ message_json_size > MAX_MESSAGE_BYTES
77
+ end
78
+
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,66 @@
1
+ module LiveQA
2
+ module Processor
3
+ class Worker
4
+
5
+ DEFAULT_WAIT_TIME = 2
6
+
7
+ attr_reader :queue
8
+ attr_reader :lock
9
+ attr_reader :batches
10
+
11
+ def initialize(queue)
12
+ @queue = queue
13
+ @lock = Mutex.new
14
+ @batches = []
15
+ end
16
+
17
+ def run
18
+ until Thread.current[:should_exit]
19
+ return if queue.empty? && batches.empty?
20
+
21
+ sleep(DEFAULT_WAIT_TIME) if queue.empty?
22
+
23
+ create_new_batch unless queue.empty?
24
+
25
+ send_batches
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def create_new_batch
32
+ batch = Batch.new
33
+ lock.synchronize do
34
+ batch << queue.pop until batch.full? || queue.empty?
35
+ end
36
+ batches.push(batch)
37
+ end
38
+
39
+ def send_batches
40
+ batches.dup.each do
41
+ batch = batches.pop
42
+
43
+ unless batch.can_run?
44
+ batches.push(batch)
45
+ next
46
+ end
47
+
48
+ begin
49
+ LiveQA::Batch.create(Message.base.merge(data: batch.messages))
50
+ rescue LiveQA::RequestError => error
51
+ return LiveQA.configurations.logger.error(error.message) if [401, 404].include?(error.http_status)
52
+ batch_retry(batch)
53
+ rescue Errno::ECONNREFUSED => _error
54
+ batch_retry(batch)
55
+ end
56
+ end
57
+ end
58
+
59
+ def batch_retry(batch)
60
+ batch.update_retry
61
+ batches.push(batch) if batch.can_retry?
62
+ end
63
+
64
+ end
65
+ end
66
+ end
data/lib/liveqa/util.rb CHANGED
@@ -94,7 +94,7 @@ module LiveQA
94
94
  deep_transform_keys_in_object(hash_object) do |key|
95
95
  begin
96
96
  underscore(key).to_sym
97
- rescue
97
+ rescue StandardError => _e
98
98
  key
99
99
  end
100
100
  end
@@ -110,7 +110,7 @@ module LiveQA
110
110
  deep_transform_keys_in_object(hash_object) do |key|
111
111
  begin
112
112
  key.to_s
113
- rescue
113
+ rescue StandardError => _e
114
114
  key
115
115
  end
116
116
  end
@@ -126,7 +126,7 @@ module LiveQA
126
126
  deep_transform_keys_in_object(hash_object) do |key|
127
127
  begin
128
128
  key.to_sym
129
- rescue
129
+ rescue StandardError => _e
130
130
  key
131
131
  end
132
132
  end
@@ -1,3 +1,3 @@
1
1
  module LiveQA # :nodoc:
2
- VERSION = '1.8.3'.freeze
2
+ VERSION = '1.9.0'.freeze
3
3
  end