peak_flow_utils 0.1.15 → 0.1.16
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/services/peak_flow_utils/deep_merger.rb +24 -7
- data/lib/peak_flow_utils/inherited_local_var.rb +84 -0
- data/lib/peak_flow_utils/notifier.rb +59 -47
- data/lib/peak_flow_utils/thread_callbacks_patch.rb +23 -0
- data/lib/peak_flow_utils/version.rb +1 -1
- data/lib/peak_flow_utils.rb +4 -0
- metadata +32 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c01a814a1aad134f668f7144f6addea59f8b8afdc75a2ae8ff2280dbe3a9867c
|
4
|
+
data.tar.gz: b6746741a1ff204c7b2a31319409d84a4529c14a55f8e9cfbf7b7fcad37eacea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a82e952b87453cfde4fbcb42fd43a0f2bca93f43dc2b3dbdca3109c6d25a21dd587745c602680d89c446cda1c1be251167b46248b98bc1e5354f408ae9f2758
|
7
|
+
data.tar.gz: d2020073122505feaa6cb3923f79a76ff6f8608ac45af16625cae83f79c6232a9f4ac677e834faa015bfd1d9e287946b4cc0662557507dcfab89ea7c3faf665e
|
@@ -1,18 +1,35 @@
|
|
1
1
|
class PeakFlowUtils::DeepMerger < PeakFlowUtils::ApplicationService
|
2
|
-
|
2
|
+
attr_reader :hashes, :object_mappings
|
3
|
+
|
4
|
+
def initialize(hashes:, object_mappings: {})
|
3
5
|
@hashes = hashes
|
6
|
+
@object_mappings = object_mappings
|
4
7
|
end
|
5
8
|
|
6
9
|
def perform
|
7
10
|
merged = {}
|
8
11
|
|
9
|
-
|
12
|
+
hashes.each do |hash|
|
10
13
|
merge_hash(hash, merged)
|
11
14
|
end
|
12
15
|
|
13
16
|
succeed! merged
|
14
17
|
end
|
15
18
|
|
19
|
+
def clone_something(object)
|
20
|
+
if object.is_a?(Hash)
|
21
|
+
new_hash = {}
|
22
|
+
merge_hash(object, new_hash)
|
23
|
+
new_hash
|
24
|
+
elsif object.is_a?(Array)
|
25
|
+
new_array = []
|
26
|
+
merge_array(object, new_array)
|
27
|
+
new_array
|
28
|
+
else
|
29
|
+
object
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
16
33
|
def merge_something(object, merged)
|
17
34
|
if object.is_a?(Array)
|
18
35
|
merge_array(object, merged)
|
@@ -25,20 +42,20 @@ class PeakFlowUtils::DeepMerger < PeakFlowUtils::ApplicationService
|
|
25
42
|
|
26
43
|
def merge_array(array, merged)
|
27
44
|
array.each do |value|
|
28
|
-
merged << value
|
45
|
+
merged << clone_something(value)
|
29
46
|
end
|
30
47
|
end
|
31
48
|
|
32
49
|
def merge_hash(hash, merged)
|
33
50
|
hash.each do |key, value|
|
34
|
-
if
|
35
|
-
merged[key] =
|
36
|
-
elsif value.is_a?(Array)
|
51
|
+
if value.is_a?(Array)
|
52
|
+
merged[key] = []
|
37
53
|
merge_array(value, merged[key])
|
38
54
|
elsif value.is_a?(Hash)
|
55
|
+
merged[key] ||= {}
|
39
56
|
merge_hash(value, merged[key])
|
40
57
|
else
|
41
|
-
|
58
|
+
merged[key] = clone_something(value)
|
42
59
|
end
|
43
60
|
end
|
44
61
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require "monitor"
|
2
|
+
require_relative "thread_callbacks_patch"
|
3
|
+
|
4
|
+
Thread.on_initialize do |parent:, thread:|
|
5
|
+
thread.instance_variable_set(:@_inherited_local_vars, parent.instance_variable_get(:@_inherited_local_vars))
|
6
|
+
end
|
7
|
+
|
8
|
+
Thread.class_eval do
|
9
|
+
def self.inherited_local_vars_mutex
|
10
|
+
@inherited_local_vars_mutex ||= Mutex.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def self._inherited_local_vars
|
14
|
+
Thread.current.instance_variable_set(:@_inherited_local_vars, {}) unless Thread.current.instance_variable_get(:@_inherited_local_vars)
|
15
|
+
Thread.current.instance_variable_get(:@_inherited_local_vars)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.inherited_local_vars_reset
|
19
|
+
ObjectSpace.each_object(Thread) do |thread|
|
20
|
+
inherited_local_vars_mutex.synchronize do
|
21
|
+
thread.instance_variable_set(:@_inherited_local_vars, nil)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.inherited_local_vars_delete(key)
|
27
|
+
inherited_local_vars_mutex.synchronize do
|
28
|
+
raise "Key didn't exist: #{key}" unless _inherited_local_vars.key?(key)
|
29
|
+
|
30
|
+
_inherited_local_vars.delete(key)
|
31
|
+
end
|
32
|
+
rescue ThreadError # This can happen when process is closing down
|
33
|
+
_inherited_local_vars.delete(key)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.inherited_local_vars_fetch(key)
|
37
|
+
inherited_local_vars_mutex.synchronize do
|
38
|
+
return _inherited_local_vars.fetch(key)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.inherited_local_vars_get(key)
|
43
|
+
inherited_local_vars_mutex.synchronize do
|
44
|
+
return _inherited_local_vars[key]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.inherited_local_vars_set(values)
|
49
|
+
inherited_local_vars_mutex.synchronize do
|
50
|
+
current_vars = _inherited_local_vars
|
51
|
+
new_vars = PeakFlowUtils::DeepMerger.execute!(hashes: [current_vars, values])
|
52
|
+
Thread.current.instance_variable_set(:@_inherited_local_vars, new_vars)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class PeakFlowUtils::InheritedLocalVar
|
58
|
+
attr_reader :identifier
|
59
|
+
|
60
|
+
def self.finalize(inherited_local_var_object_id)
|
61
|
+
Thread.inherited_local_vars_delete("inherited_local_var_#{inherited_local_var_object_id}")
|
62
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
63
|
+
puts e.inspect # rubocop:disable Rails/Output
|
64
|
+
puts e.backtrace # rubocop:disable Rails/Output
|
65
|
+
|
66
|
+
raise e
|
67
|
+
end
|
68
|
+
|
69
|
+
def initialize(new_value = nil)
|
70
|
+
ObjectSpace.define_finalizer(self, PeakFlowUtils::InheritedLocalVar.method(:finalize))
|
71
|
+
|
72
|
+
@identifier = "inherited_local_var_#{__id__}"
|
73
|
+
|
74
|
+
Thread.inherited_local_vars_set(identifier => new_value)
|
75
|
+
end
|
76
|
+
|
77
|
+
def value
|
78
|
+
Thread.inherited_local_vars_fetch(identifier)
|
79
|
+
end
|
80
|
+
|
81
|
+
def value=(new_value)
|
82
|
+
Thread.inherited_local_vars_set(identifier => new_value)
|
83
|
+
end
|
84
|
+
end
|
@@ -2,73 +2,89 @@ class PeakFlowUtils::Notifier
|
|
2
2
|
class FailedToReportError < RuntimeError; end
|
3
3
|
class NotConfiguredError < RuntimeError; end
|
4
4
|
|
5
|
-
attr_reader :auth_token
|
5
|
+
attr_reader :auth_token, :mutex, :parameters
|
6
6
|
|
7
7
|
def self.configure(auth_token:)
|
8
8
|
@current = PeakFlowUtils::Notifier.new(auth_token: auth_token)
|
9
9
|
end
|
10
10
|
|
11
|
-
def self.current
|
12
|
-
raise PeakFlowUtils::Notifier::NotConfiguredError, "Hasn't been configured" if !@current && Rails.env.test?
|
13
|
-
|
11
|
+
def self.current # rubocop:disable Style/TrivialAccessors
|
14
12
|
@current
|
15
13
|
end
|
16
14
|
|
17
|
-
def self.
|
18
|
-
|
19
|
-
hashes << parameters if parameters
|
20
|
-
|
21
|
-
PeakFlowUtils::DeepMerger.execute!(hashes: hashes)
|
15
|
+
def self.notify(*args, **opts, &blk)
|
16
|
+
PeakFlowUtils::Notifier.current&.notify(*args, **opts, &blk)
|
22
17
|
end
|
23
18
|
|
24
|
-
def self.
|
25
|
-
|
19
|
+
def self.reset_parameters
|
20
|
+
::PeakFlowUtils::Notifier.current&.instance_variable_set(:@parameters, ::PeakFlowUtils::InheritedLocalVar.new({}))
|
21
|
+
end
|
26
22
|
|
27
|
-
|
28
|
-
|
29
|
-
hashes << more_parameters
|
30
|
-
end
|
23
|
+
def self.with_parameters(parameters)
|
24
|
+
return yield unless ::PeakFlowUtils::Notifier.current
|
31
25
|
|
32
|
-
|
33
|
-
end
|
26
|
+
random_id = ::SecureRandom.hex(16)
|
34
27
|
|
35
|
-
|
36
|
-
|
37
|
-
end
|
28
|
+
::PeakFlowUtils::Notifier.current.mutex.synchronize do
|
29
|
+
raise "'parameters' was nil?" if ::PeakFlowUtils::Notifier.current.parameters.value.nil?
|
38
30
|
|
39
|
-
|
40
|
-
|
31
|
+
parameters_with = ::PeakFlowUtils::Notifier.current.parameters.value.clone
|
32
|
+
parameters_with[random_id] = parameters
|
41
33
|
|
42
|
-
|
43
|
-
|
44
|
-
Thread.current[:peakflow_utils][:notifier][:with_parameters] ||= {}
|
45
|
-
Thread.current[:peakflow_utils][:notifier][:with_parameters][random_id] = parameters
|
34
|
+
::PeakFlowUtils::Notifier.current.parameters.value = parameters_with
|
35
|
+
end
|
46
36
|
|
47
37
|
begin
|
48
38
|
yield
|
49
39
|
ensure
|
50
|
-
|
40
|
+
::PeakFlowUtils::Notifier.current.mutex.synchronize do
|
41
|
+
parameters_without = ::PeakFlowUtils::Notifier.current.parameters.value.clone
|
42
|
+
parameters_without.delete(random_id)
|
43
|
+
|
44
|
+
::PeakFlowUtils::Notifier.current.parameters.value = parameters_without
|
45
|
+
end
|
51
46
|
end
|
52
47
|
end
|
53
48
|
|
54
49
|
def initialize(auth_token:)
|
55
50
|
@auth_token = auth_token
|
51
|
+
@mutex = ::Mutex.new
|
52
|
+
@parameters = ::PeakFlowUtils::InheritedLocalVar.new({})
|
53
|
+
end
|
54
|
+
|
55
|
+
def current_parameters(parameters: nil)
|
56
|
+
hashes = current_parameters_hashes
|
57
|
+
hashes << parameters if parameters
|
58
|
+
|
59
|
+
::PeakFlowUtils::DeepMerger.execute!(hashes: hashes)
|
60
|
+
end
|
61
|
+
|
62
|
+
def current_parameters_hashes
|
63
|
+
parameters.value.values
|
64
|
+
end
|
65
|
+
|
66
|
+
def error_message_from_response(response)
|
67
|
+
message = "Couldn't report error to Peakflow (code #{response.code})"
|
68
|
+
|
69
|
+
if response["content-type"]&.starts_with?("application/json")
|
70
|
+
response_data = ::JSON.parse(response.body)
|
71
|
+
message << ": #{response_data.fetch("errors").join(". ")}" if response_data["errors"]
|
72
|
+
end
|
73
|
+
|
74
|
+
message
|
56
75
|
end
|
57
76
|
|
58
77
|
def notify(error:, environment: nil, parameters: nil)
|
59
|
-
error_parser = PeakFlowUtils::NotifierErrorParser.new(
|
78
|
+
error_parser = ::PeakFlowUtils::NotifierErrorParser.new(
|
60
79
|
backtrace: error.backtrace,
|
61
80
|
environment: environment,
|
62
81
|
error: error
|
63
82
|
)
|
64
83
|
|
65
|
-
merged_parameters =
|
84
|
+
merged_parameters = current_parameters(parameters: parameters)
|
66
85
|
|
67
86
|
uri = URI("https://www.peakflow.io/errors/reports")
|
68
87
|
|
69
|
-
https = Net::HTTP.new(uri.host, uri.port)
|
70
|
-
https.use_ssl = true
|
71
|
-
|
72
88
|
data = {
|
73
89
|
auth_token: auth_token,
|
74
90
|
error: {
|
@@ -85,18 +101,25 @@ class PeakFlowUtils::Notifier
|
|
85
101
|
}
|
86
102
|
}
|
87
103
|
|
88
|
-
|
104
|
+
send_notify_request(data: data, uri: uri)
|
105
|
+
end
|
106
|
+
|
107
|
+
def send_notify_request(data:, uri:)
|
108
|
+
https = ::Net::HTTP.new(uri.host, uri.port)
|
109
|
+
https.use_ssl = true
|
110
|
+
|
111
|
+
request = ::Net::HTTP::Post.new(uri.path)
|
89
112
|
request["Content-Type"] = "application/json"
|
90
|
-
request.body = JSON.generate(data)
|
113
|
+
request.body = ::JSON.generate(data)
|
91
114
|
|
92
115
|
response = https.request(request)
|
93
116
|
|
94
117
|
raise FailedToReportError, error_message_from_response(response) unless response.code == "200"
|
95
118
|
|
96
|
-
response_data = JSON.parse(response.body)
|
119
|
+
response_data = ::JSON.parse(response.body)
|
97
120
|
|
98
121
|
# Data not always present so dont use fetch
|
99
|
-
PeakFlowUtils::NotifierResponse.new(
|
122
|
+
::PeakFlowUtils::NotifierResponse.new(
|
100
123
|
bug_report_id: response_data["bug_report_id"],
|
101
124
|
bug_report_instance_id: response_data["bug_report_instance_id"],
|
102
125
|
project_id: response_data["project_id"],
|
@@ -104,15 +127,4 @@ class PeakFlowUtils::Notifier
|
|
104
127
|
url: response_data["url"]
|
105
128
|
)
|
106
129
|
end
|
107
|
-
|
108
|
-
def error_message_from_response(response)
|
109
|
-
message = "Couldn't report error to Peakflow (code #{response.code})"
|
110
|
-
|
111
|
-
if response["content-type"]&.starts_with?("application/json")
|
112
|
-
response_data = JSON.parse(response.body)
|
113
|
-
message << ": #{response_data.fetch("errors").join(". ")}" if response_data["errors"]
|
114
|
-
end
|
115
|
-
|
116
|
-
message
|
117
|
-
end
|
118
130
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class Thread
|
2
|
+
alias_method :_initialize, :initialize # rubocop:disable Style/Alias
|
3
|
+
|
4
|
+
def self.on_initialize(&callback)
|
5
|
+
@@on_initialize_count = 0 if @on_initialize_count.nil? # rubocop:disable Style/ClassVars
|
6
|
+
count_to_use = @@on_initialize_count
|
7
|
+
@@on_initialize_count += 1 # rubocop:disable Style/ClassVars
|
8
|
+
|
9
|
+
@@on_initialize_callbacks ||= {} # rubocop:disable Style/ClassVars
|
10
|
+
@@on_initialize_callbacks[count_to_use] = callback
|
11
|
+
|
12
|
+
count_to_use
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(*args, &block)
|
16
|
+
@@on_initialize_callbacks ||= {} # rubocop:disable Style/ClassVars
|
17
|
+
@@on_initialize_callbacks.each_value do |callback|
|
18
|
+
callback.call(parent: Thread.current, thread: self)
|
19
|
+
end
|
20
|
+
|
21
|
+
_initialize(*args, &block)
|
22
|
+
end
|
23
|
+
end
|
data/lib/peak_flow_utils.rb
CHANGED
@@ -6,7 +6,11 @@ require "service_pattern"
|
|
6
6
|
module PeakFlowUtils
|
7
7
|
path = "#{__dir__}/peak_flow_utils"
|
8
8
|
models_path = "#{__dir__}/peak_flow_utils/models"
|
9
|
+
services_path = File.realpath("#{__dir__}/../app/services/peak_flow_utils")
|
9
10
|
|
11
|
+
autoload :ApplicationService, "#{services_path}/application_service"
|
12
|
+
autoload :DeepMerger, "#{services_path}/deep_merger"
|
13
|
+
autoload :InheritedLocalVar, "#{path}/inherited_local_var"
|
10
14
|
autoload :Notifier, "#{path}/notifier"
|
11
15
|
autoload :NotifierErrorParser, "#{path}/notifier_error_parser"
|
12
16
|
autoload :NotifierRack, "#{path}/notifier_rack"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: peak_flow_utils
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.16
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- kaspernj
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-02-
|
11
|
+
date: 2022-02-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -66,6 +66,34 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: 1.0.5
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: appraisal
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: pry-rails
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
69
97
|
- !ruby/object:Gem::Dependency
|
70
98
|
name: redis
|
71
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -147,6 +175,7 @@ files:
|
|
147
175
|
- lib/peak_flow_utils.rb
|
148
176
|
- lib/peak_flow_utils/engine.rb
|
149
177
|
- lib/peak_flow_utils/handler_helper.rb
|
178
|
+
- lib/peak_flow_utils/inherited_local_var.rb
|
150
179
|
- lib/peak_flow_utils/migrations/20150902155200_create_translation_keys.rb
|
151
180
|
- lib/peak_flow_utils/migrations/20150907070908_create_handlers.rb
|
152
181
|
- lib/peak_flow_utils/migrations/20150907070909_create_groups.rb
|
@@ -166,6 +195,7 @@ files:
|
|
166
195
|
- lib/peak_flow_utils/notifier_rails.rb
|
167
196
|
- lib/peak_flow_utils/notifier_response.rb
|
168
197
|
- lib/peak_flow_utils/notifier_sidekiq.rb
|
198
|
+
- lib/peak_flow_utils/thread_callbacks_patch.rb
|
169
199
|
- lib/peak_flow_utils/version.rb
|
170
200
|
- lib/tasks/peak_flow_utils_tasks.rake
|
171
201
|
homepage: https://github.com/kaspernj/peak_flow_utils
|