resurfaceio-logger 1.10.0 → 2.1.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
  SHA256:
3
- metadata.gz: '081b638ef0c63585d851de54a9b30ef9b54de58cf68f880785c2e1a8d214cb54'
4
- data.tar.gz: a71c49ec92a27637f7d77b52177df39d0b197757a056154e5247f5e40aa350d1
3
+ metadata.gz: 03fa4df93d4d741b9be0085279b48a975fa926d761fba5efc1176ecc6f5a0360
4
+ data.tar.gz: 35549694475210ba9e1729045d5ee7c90833711cf60ea335cd3a88f6dc1b7a04
5
5
  SHA512:
6
- metadata.gz: f2f2c6be12c8977756ab185cc34c64cc29b0956940139315a1d9c023f4df0756cbea1c3fdb8eaab9207070ddda63ee1dac34688d8272d1782d5664b531de94a3
7
- data.tar.gz: 8eed5ac226184687025edf8d3f213585b73d1577c8c6a5420f71b4bc5205add88470672e350746edef7e2a48bf3441276517fcb7ec176bdb16f88b21f9059c7a
6
+ metadata.gz: 8e43befe93d7cdbc4ac1da54fe7a704002695da151912df186c0885f82f96e8f1d7be5c3be2385c6c4304727e36735c67ebe0df80327c89e645e236238bd21e9
7
+ data.tar.gz: efa856a43b1561fbe39b939a78d5f22bdbe3dbf249a9ef2208a4efdbd7d287afa18f45b83a23246dca32c86b21d4643c1f746449992e8a448efcd8f1609ba40b
@@ -1,5 +1,5 @@
1
1
  # coding: utf-8
2
- # © 2016-2019 Resurface Labs Inc.
2
+ # © 2016-2021 Resurface Labs Inc.
3
3
 
4
4
  require 'resurfaceio/base_logger'
5
5
  require 'resurfaceio/http_logger'
@@ -1,5 +1,5 @@
1
1
  # coding: utf-8
2
- # © 2016-2019 Resurface Labs Inc.
2
+ # © 2016-2021 Resurface Labs Inc.
3
3
 
4
4
  require 'uri'
5
5
  require 'net/http'
@@ -44,14 +44,21 @@ class BaseLogger
44
44
  # validate url when present
45
45
  unless @url.nil?
46
46
  begin
47
- raise Exception unless URI.parse(@url).scheme.include?('http')
47
+ @url_parsed = URI.parse(@url)
48
+ raise Exception unless @url_parsed.scheme.include?('http')
48
49
  rescue Exception
49
50
  @url = nil
51
+ @url_parsed = nil
50
52
  @enabled = false
51
53
  end
52
54
  end
53
55
 
56
+ # finalize internal properties
54
57
  @enableable = !@queue.nil? || !@url.nil?
58
+ @submit_failures = 0
59
+ @submit_failures_lock = Mutex.new
60
+ @submit_successes = 0
61
+ @submit_successes_lock = Mutex.new
55
62
  end
56
63
 
57
64
  def agent
@@ -102,31 +109,43 @@ class BaseLogger
102
109
 
103
110
  def submit(msg)
104
111
  if msg.nil? || @skip_submission || !enabled?
105
- true
112
+ # do nothing
106
113
  elsif @queue
107
114
  @queue << msg
108
- true
115
+ @submit_successes_lock.synchronize { @submit_successes += 1 }
109
116
  else
110
117
  begin
111
- @url_parsed ||= URI.parse(@url)
112
- @url_connection ||= Net::HTTP.new(@url_parsed.host, @url_parsed.port)
113
- @url_connection.use_ssl = @url.include?('https')
118
+ url_connection = Net::HTTP.new(@url_parsed.host, @url_parsed.port)
119
+ url_connection.use_ssl = @url.include?('https')
114
120
  request = Net::HTTP::Post.new(@url_parsed.path)
121
+ request.add_field('Content-Type', 'application/json; charset=UTF-8')
122
+ request.add_field('User-Agent', "Resurface/#{@version} (#{@agent})")
115
123
  if @skip_compression
116
124
  request.body = msg
117
125
  else
118
126
  request.add_field('Content-Encoding', 'deflated')
119
127
  request.body = Zlib::Deflate.deflate(msg)
120
128
  end
121
- response = @url_connection.request(request)
122
- response.code.to_i == 204
123
- rescue SocketError
124
- @url_connection = nil
125
- false
129
+ response = url_connection.request(request)
130
+ if response.code.to_i == 204
131
+ @submit_successes_lock.synchronize { @submit_successes += 1 }
132
+ else
133
+ @submit_failures_lock.synchronize { @submit_failures += 1 }
134
+ end
135
+ rescue Exception
136
+ @submit_failures_lock.synchronize { @submit_failures += 1 }
126
137
  end
127
138
  end
128
139
  end
129
140
 
141
+ def submit_failures
142
+ @submit_failures
143
+ end
144
+
145
+ def submit_successes
146
+ @submit_successes
147
+ end
148
+
130
149
  def url
131
150
  @url
132
151
  end
@@ -1,5 +1,5 @@
1
1
  # coding: utf-8
2
- # © 2016-2019 Resurface Labs Inc.
2
+ # © 2016-2021 Resurface Labs Inc.
3
3
 
4
4
  require 'json'
5
5
  require 'resurfaceio/base_logger'
@@ -11,53 +11,20 @@ class HttpLogger < BaseLogger
11
11
 
12
12
  AGENT = 'http_logger.rb'.freeze
13
13
 
14
- @@default_rules = HttpRules.strict_rules
15
-
16
- def self.default_rules
17
- @@default_rules
18
- end
19
-
20
- def self.default_rules=(val)
21
- @@default_rules = val.gsub(/^\s*include default\s*$/, '')
22
- end
23
-
24
- def self.string_content_type?(s)
25
- !s.nil? && !(s =~ /^(text\/(html|plain|xml))|(application\/(json|soap|xml|x-www-form-urlencoded))/i).nil?
26
- end
27
-
28
14
  def initialize(options = {})
29
15
  super(AGENT, options)
30
16
 
31
- # read rules from param or defaults
17
+ # parse specified rules
32
18
  if options.respond_to?(:has_key?) && options.has_key?(:rules)
33
- @rules = options[:rules].gsub(/^\s*include default\s*$/, @@default_rules)
34
- @rules = @@default_rules unless @rules.strip.length > 0
19
+ @rules = HttpRules.new(options[:rules])
35
20
  else
36
- @rules = @@default_rules
21
+ @rules = HttpRules.new(nil)
37
22
  end
38
23
 
39
- # parse and break rules out by verb
40
- prs = HttpRules.parse(@rules)
41
- @rules_allow_http_url = prs.select {|r| 'allow_http_url' == r.verb}.length > 0
42
- @rules_copy_session_field = prs.select {|r| 'copy_session_field' == r.verb}
43
- @rules_remove = prs.select {|r| 'remove' == r.verb}
44
- @rules_remove_if = prs.select {|r| 'remove_if' == r.verb}
45
- @rules_remove_if_found = prs.select {|r| 'remove_if_found' == r.verb}
46
- @rules_remove_unless = prs.select {|r| 'remove_unless' == r.verb}
47
- @rules_remove_unless_found = prs.select {|r| 'remove_unless_found' == r.verb}
48
- @rules_replace = prs.select {|r| 'replace' == r.verb}
49
- @rules_sample = prs.select {|r| 'sample' == r.verb}
50
- @rules_stop = prs.select {|r| 'stop' == r.verb}
51
- @rules_stop_if = prs.select {|r| 'stop_if' == r.verb}
52
- @rules_stop_if_found = prs.select {|r| 'stop_if_found' == r.verb}
53
- @rules_stop_unless = prs.select {|r| 'stop_unless' == r.verb}
54
- @rules_stop_unless_found = prs.select {|r| 'stop_unless_found' == r.verb}
55
- @skip_compression = prs.select {|r| 'skip_compression' == r.verb}.length > 0
56
- @skip_submission = prs.select {|r| 'skip_submission' == r.verb}.length > 0
57
-
58
- # finish validating rules
59
- raise RuntimeError.new('Multiple sample rules') if @rules_sample.length > 1
60
- unless @url.nil? || @url.start_with?('https') || @rules_allow_http_url
24
+ # apply configuration rules
25
+ @skip_compression = @rules.skip_compression
26
+ @skip_submission = @rules.skip_submission
27
+ unless @url.nil? || @url.start_with?('https') || @rules.allow_http_url
61
28
  @enableable = false
62
29
  @enabled = false
63
30
  end
@@ -67,58 +34,16 @@ class HttpLogger < BaseLogger
67
34
  @rules
68
35
  end
69
36
 
70
- def log(request, response, response_body = nil, request_body = nil)
71
- !enabled? || submit(format(request, response, response_body, request_body))
72
- end
73
-
74
- def format(request, response, response_body = nil, request_body = nil, now = nil)
75
- details = HttpMessage.build(request, response, response_body, request_body)
76
-
77
- # copy data from session if configured
78
- unless @rules_copy_session_field.empty?
79
- ssn = request.session
80
- if !ssn.nil? && ssn.respond_to?(:keys)
81
- @rules_copy_session_field.each do |r|
82
- ssn.keys.each {|d| (details << ["session_field:#{d}", ssn[d].to_s]) if r.param1.match(d)}
83
- end
84
- end
85
- end
86
-
87
- # quit early based on stop rules if configured
88
- @rules_stop.each {|r| details.each {|d| return nil if r.scope.match(d[0])}}
89
- @rules_stop_if_found.each {|r| details.each {|d| return nil if r.scope.match(d[0]) && r.param1.match(d[1])}}
90
- @rules_stop_if.each {|r| details.each {|d| return nil if r.scope.match(d[0]) && r.param1.match(d[1])}}
91
- passed = 0
92
- @rules_stop_unless_found.each {|r| details.each {|d| passed += 1 if r.scope.match(d[0]) && r.param1.match(d[1])}}
93
- return nil if passed != @rules_stop_unless_found.length
94
- passed = 0
95
- @rules_stop_unless.each {|r| details.each {|d| passed += 1 if r.scope.match(d[0]) && r.param1.match(d[1])}}
96
- return nil if passed != @rules_stop_unless.length
97
-
98
- # do sampling if configured
99
- return nil if !@rules_sample[0].nil? && (rand * 100 >= @rules_sample[0].param1)
37
+ def submit_if_passing(details)
38
+ # apply active rules
39
+ details = @rules.apply(details)
40
+ return nil if details.nil?
100
41
 
101
- # winnow sensitive details based on remove rules if configured
102
- @rules_remove.each {|r| details.delete_if {|d| r.scope.match(d[0])}}
103
- @rules_remove_unless_found.each {|r| details.delete_if {|d| r.scope.match(d[0]) && !r.param1.match(d[1])}}
104
- @rules_remove_if_found.each {|r| details.delete_if {|d| r.scope.match(d[0]) && r.param1.match(d[1])}}
105
- @rules_remove_unless.each {|r| details.delete_if {|d| r.scope.match(d[0]) && !r.param1.match(d[1])}}
106
- @rules_remove_if.each {|r| details.delete_if {|d| r.scope.match(d[0]) && r.param1.match(d[1])}}
107
- return nil if details.empty?
108
-
109
- # mask sensitive details based on replace rules if configured
110
- @rules_replace.each {|r| details.each {|d| d[1] = d[1].gsub(r.param1, r.param2) if r.scope.match(d[0])}}
111
-
112
- # remove any details with empty values
113
- details.delete_if {|d| '' == d[1]}
114
- return nil if details.empty?
115
-
116
- # finish message
117
- details << ['now', now.nil? ? (Time.now.to_f * 1000).floor.to_s : now]
118
- details << ['agent', @agent]
42
+ # finalize message
119
43
  details << ['host', @host]
120
- details << ['version', @version]
121
- JSON.generate details
44
+
45
+ # let's do this thing
46
+ submit(JSON.generate(details))
122
47
  end
123
48
 
124
49
  end
@@ -1,8 +1,10 @@
1
1
  # coding: utf-8
2
- # © 2016-2019 Resurface Labs Inc.
2
+ # © 2016-2021 Resurface Labs Inc.
3
3
 
4
4
  require 'rack'
5
5
  require 'resurfaceio/http_logger'
6
+ require 'resurfaceio/http_message'
7
+ require 'resurfaceio/timer'
6
8
 
7
9
  class HttpLoggerForRack # http://rack.rubyforge.org/doc/SPEC.html
8
10
 
@@ -16,13 +18,12 @@ class HttpLoggerForRack # http://rack.rubyforge.org/doc/SPEC.html
16
18
  end
17
19
 
18
20
  def call(env)
21
+ timer = Timer.new
19
22
  status, headers, body = @app.call(env)
20
- if @logger.enabled? && (status < 300 || status == 302)
23
+ if @logger.enabled?
21
24
  response = Rack::Response.new(body, status, headers)
22
- if HttpLogger::string_content_type?(response.content_type)
23
- request = Rack::Request.new(env)
24
- @logger.submit(@logger.format(request, response))
25
- end
25
+ request = Rack::Request.new(env)
26
+ HttpMessage.send(logger, request, response, nil, nil, nil, timer.millis)
26
27
  end
27
28
  [status, headers, body]
28
29
  end
@@ -1,7 +1,9 @@
1
1
  # coding: utf-8
2
- # © 2016-2019 Resurface Labs Inc.
2
+ # © 2016-2021 Resurface Labs Inc.
3
3
 
4
4
  require 'resurfaceio/http_logger'
5
+ require 'resurfaceio/http_message'
6
+ require 'resurfaceio/timer'
5
7
 
6
8
  class HttpLoggerForRails
7
9
 
@@ -14,14 +16,12 @@ class HttpLoggerForRails
14
16
  end
15
17
 
16
18
  def around(controller)
19
+ timer = Timer.new
17
20
  yield
18
21
  if @logger.enabled?
19
22
  request = controller.request
20
23
  response = controller.response
21
- status = response.status
22
- if (status < 300 || status == 302) && HttpLogger::string_content_type?(response.content_type)
23
- @logger.submit(@logger.format(request, response))
24
- end
24
+ HttpMessage.send(logger, request, response, nil, nil, nil, timer.millis)
25
25
  end
26
26
  end
27
27
 
@@ -1,10 +1,33 @@
1
1
  # coding: utf-8
2
- # © 2016-2019 Resurface Labs Inc.
2
+ # © 2016-2021 Resurface Labs Inc.
3
3
 
4
4
  require 'json'
5
5
 
6
6
  class HttpMessage
7
7
 
8
+ def self.send(logger, request, response, response_body = nil, request_body = nil, now = nil, interval = nil)
9
+ return unless logger.enabled?
10
+
11
+ # copy details from request & response
12
+ message = build(request, response, response_body, request_body)
13
+
14
+ # copy details from active session
15
+ unless logger.rules.copy_session_field.empty?
16
+ ssn = request.session
17
+ if !ssn.nil? && ssn.respond_to?(:keys)
18
+ logger.rules.copy_session_field.each do |r|
19
+ ssn.keys.each {|d| (message << ["session_field:#{d}", ssn[d].to_s]) if r.param1.match(d)}
20
+ end
21
+ end
22
+ end
23
+
24
+ # add timing details
25
+ message << ['now', now.nil? ? (Time.now.to_f * 1000).floor.to_s : now]
26
+ message << ['interval', interval] unless interval.nil?
27
+
28
+ logger.submit_if_passing(message)
29
+ end
30
+
8
31
  def self.build(request, response, response_body = nil, request_body = nil)
9
32
  message = []
10
33
  append_value message, 'request_method', request.request_method unless request.request_method.nil?
@@ -19,8 +42,6 @@ class HttpMessage
19
42
  return message
20
43
  end
21
44
 
22
- protected
23
-
24
45
  def self.append_request_headers(message, request)
25
46
  respond_to_env = request.respond_to?(:env)
26
47
  if respond_to_env || request.respond_to?(:headers)
@@ -74,12 +95,12 @@ class HttpMessage
74
95
  unless key.nil?
75
96
  unless value.nil?
76
97
  case value
77
- when Array
78
- message << [key, value.join]
79
- when String
80
- message << [key, value]
81
- else
82
- message << [key, value.to_s]
98
+ when Array
99
+ message << [key, value.join]
100
+ when String
101
+ message << [key, value]
102
+ else
103
+ message << [key, value.to_s]
83
104
  end
84
105
  end
85
106
  end
@@ -1,5 +1,5 @@
1
1
  # coding: utf-8
2
- # © 2016-2019 Resurface Labs Inc.
2
+ # © 2016-2021 Resurface Labs Inc.
3
3
 
4
4
  class HttpRequestImpl
5
5
 
@@ -1,5 +1,5 @@
1
1
  # coding: utf-8
2
- # © 2016-2019 Resurface Labs Inc.
2
+ # © 2016-2021 Resurface Labs Inc.
3
3
 
4
4
  class HttpResponseImpl
5
5
 
@@ -1,5 +1,5 @@
1
1
  # coding: utf-8
2
- # © 2016-2019 Resurface Labs Inc.
2
+ # © 2016-2021 Resurface Labs Inc.
3
3
 
4
4
  class HttpRule
5
5
 
@@ -1,37 +1,39 @@
1
1
  # coding: utf-8
2
- # © 2016-2019 Resurface Labs Inc.
2
+ # © 2016-2021 Resurface Labs Inc.
3
3
 
4
4
  class HttpRules
5
5
 
6
+ DEBUG_RULES = "allow_http_url\ncopy_session_field /.*/\n".freeze
7
+
8
+ STANDARD_RULES = %q(/request_header:cookie|response_header:set-cookie/ remove
9
+ /(request|response)_body|request_param/ replace /[a-zA-Z0-9.!#$%&’*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)/, /x@y.com/
10
+ /request_body|request_param|response_body/ replace /[0-9\.\-\/]{9,}/, /xyxy/
11
+ ).freeze
12
+
13
+ STRICT_RULES = %q(/request_url/ replace /([^\?;]+).*/, !\\\\1!
14
+ /request_body|response_body|request_param:.*|request_header:(?!user-agent).*|response_header:(?!(content-length)|(content-type)).*/ remove
15
+ ).freeze
16
+
17
+ @@default_rules = STRICT_RULES
18
+
19
+ def self.default_rules
20
+ @@default_rules
21
+ end
22
+
23
+ def self.default_rules=(val)
24
+ @@default_rules = val.gsub(/^\s*include default\s*$/, '')
25
+ end
26
+
6
27
  def self.debug_rules
7
- "allow_http_url\ncopy_session_field /.*/\n"
28
+ DEBUG_RULES
8
29
  end
9
30
 
10
31
  def self.standard_rules
11
- %q(/request_header:cookie|response_header:set-cookie/ remove
12
- /(request|response)_body|request_param/ replace /[a-zA-Z0-9.!#$%&’*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)/, /x@y.com/
13
- /request_body|request_param|response_body/ replace /[0-9\.\-\/]{9,}/, /xyxy/
14
- )
32
+ STANDARD_RULES
15
33
  end
16
34
 
17
35
  def self.strict_rules
18
- %q(/request_url/ replace /([^\?;]+).*/, !\\\\1!
19
- /request_body|response_body|request_param:.*|request_header:(?!user-agent).*|response_header:(?!(content-length)|(content-type)).*/ remove
20
- )
21
- end
22
-
23
- def self.parse(rules)
24
- result = []
25
- unless rules.nil?
26
- rules = rules.gsub(/^\s*include debug\s*$/, debug_rules)
27
- rules = rules.gsub(/^\s*include standard\s*$/, standard_rules)
28
- rules = rules.gsub(/^\s*include strict\s*$/, strict_rules)
29
- rules.each_line do |rule|
30
- parsed = parse_rule(rule)
31
- result << parsed unless parsed.nil?
32
- end
33
- end
34
- result
36
+ STRICT_RULES
35
37
  end
36
38
 
37
39
  def self.parse_rule(r)
@@ -76,8 +78,6 @@ class HttpRules
76
78
  end
77
79
  end
78
80
 
79
- protected
80
-
81
81
  def self.parse_regex(r, regex)
82
82
  s = parse_string(r, regex)
83
83
  raise RuntimeError.new("Invalid regex (#{regex}) in rule: #{r}") if '*' == s || '+' == s || '?' == s
@@ -109,6 +109,162 @@ class HttpRules
109
109
  raise RuntimeError.new("Invalid expression (#{expr}) in rule: #{r}")
110
110
  end
111
111
 
112
+ def initialize(rules)
113
+ rules = HttpRules.default_rules if rules.nil?
114
+
115
+ # load rules from external files
116
+ if rules.start_with?('file://')
117
+ rfile = rules[7..]
118
+ begin
119
+ rules = File.read(rfile)
120
+ rescue
121
+ raise RuntimeError.new("Failed to load rules: #{rfile}")
122
+ end
123
+ end
124
+
125
+ # force default rules if necessary
126
+ rules = rules.gsub(/^\s*include default\s*$/, HttpRules.default_rules)
127
+ rules = HttpRules.default_rules unless rules.strip.length > 0
128
+
129
+ # expand rule inclues
130
+ rules = rules.gsub(/^\s*include debug\s*$/, DEBUG_RULES)
131
+ rules = rules.gsub(/^\s*include standard\s*$/, STANDARD_RULES)
132
+ rules = rules.gsub(/^\s*include strict\s*$/, STRICT_RULES)
133
+ @text = rules
134
+
135
+ # parse all rules
136
+ prs = []
137
+ rules.each_line do |rule|
138
+ parsed = HttpRules.parse_rule(rule)
139
+ prs << parsed unless parsed.nil?
140
+ end
141
+ @length = prs.length
142
+
143
+ # break out rules by verb
144
+ @allow_http_url = prs.select {|r| 'allow_http_url' == r.verb}.length > 0
145
+ @copy_session_field = prs.select {|r| 'copy_session_field' == r.verb}
146
+ @remove = prs.select {|r| 'remove' == r.verb}
147
+ @remove_if = prs.select {|r| 'remove_if' == r.verb}
148
+ @remove_if_found = prs.select {|r| 'remove_if_found' == r.verb}
149
+ @remove_unless = prs.select {|r| 'remove_unless' == r.verb}
150
+ @remove_unless_found = prs.select {|r| 'remove_unless_found' == r.verb}
151
+ @replace = prs.select {|r| 'replace' == r.verb}
152
+ @sample = prs.select {|r| 'sample' == r.verb}
153
+ @skip_compression = prs.select {|r| 'skip_compression' == r.verb}.length > 0
154
+ @skip_submission = prs.select {|r| 'skip_submission' == r.verb}.length > 0
155
+ @stop = prs.select {|r| 'stop' == r.verb}
156
+ @stop_if = prs.select {|r| 'stop_if' == r.verb}
157
+ @stop_if_found = prs.select {|r| 'stop_if_found' == r.verb}
158
+ @stop_unless = prs.select {|r| 'stop_unless' == r.verb}
159
+ @stop_unless_found = prs.select {|r| 'stop_unless_found' == r.verb}
160
+
161
+ # validate rules
162
+ raise RuntimeError.new('Multiple sample rules') if @sample.length > 1
163
+ end
164
+
165
+ def allow_http_url
166
+ @allow_http_url
167
+ end
168
+
169
+ def copy_session_field
170
+ @copy_session_field
171
+ end
172
+
173
+ def length
174
+ @length
175
+ end
176
+
177
+ def remove
178
+ @remove
179
+ end
180
+
181
+ def remove_if
182
+ @remove_if
183
+ end
184
+
185
+ def remove_if_found
186
+ @remove_if_found
187
+ end
188
+
189
+ def remove_unless
190
+ @remove_unless
191
+ end
192
+
193
+ def remove_unless_found
194
+ @remove_unless_found
195
+ end
196
+
197
+ def replace
198
+ @replace
199
+ end
200
+
201
+ def sample
202
+ @sample
203
+ end
204
+
205
+ def skip_compression
206
+ @skip_compression
207
+ end
208
+
209
+ def skip_submission
210
+ @skip_submission
211
+ end
212
+
213
+ def stop
214
+ @stop
215
+ end
216
+
217
+ def stop_if
218
+ @stop_if
219
+ end
220
+
221
+ def stop_if_found
222
+ @stop_if_found
223
+ end
224
+
225
+ def stop_unless
226
+ @stop_unless
227
+ end
228
+
229
+ def stop_unless_found
230
+ @stop_unless_found
231
+ end
232
+
233
+ def text
234
+ @text
235
+ end
236
+
237
+ def apply(details)
238
+ # stop rules come first
239
+ @stop.each {|r| details.each {|d| return nil if r.scope.match(d[0])}}
240
+ @stop_if_found.each {|r| details.each {|d| return nil if r.scope.match(d[0]) && r.param1.match(d[1])}}
241
+ @stop_if.each {|r| details.each {|d| return nil if r.scope.match(d[0]) && r.param1.match(d[1])}}
242
+ passed = 0
243
+ @stop_unless_found.each {|r| details.each {|d| passed += 1 if r.scope.match(d[0]) && r.param1.match(d[1])}}
244
+ return nil if passed != @stop_unless_found.length
245
+ passed = 0
246
+ @stop_unless.each {|r| details.each {|d| passed += 1 if r.scope.match(d[0]) && r.param1.match(d[1])}}
247
+ return nil if passed != @stop_unless.length
248
+
249
+ # do sampling if configured
250
+ return nil if !@sample[0].nil? && (rand * 100 >= @sample[0].param1)
251
+
252
+ # winnow sensitive details based on remove rules if configured
253
+ @remove.each {|r| details.delete_if {|d| r.scope.match(d[0])}}
254
+ @remove_unless_found.each {|r| details.delete_if {|d| r.scope.match(d[0]) && !r.param1.match(d[1])}}
255
+ @remove_if_found.each {|r| details.delete_if {|d| r.scope.match(d[0]) && r.param1.match(d[1])}}
256
+ @remove_unless.each {|r| details.delete_if {|d| r.scope.match(d[0]) && !r.param1.match(d[1])}}
257
+ @remove_if.each {|r| details.delete_if {|d| r.scope.match(d[0]) && r.param1.match(d[1])}}
258
+ return nil if details.empty?
259
+
260
+ # mask sensitive details based on replace rules if configured
261
+ @replace.each {|r| details.each {|d| d[1] = d[1].gsub(r.param1, r.param2) if r.scope.match(d[0])}}
262
+
263
+ # remove any details with empty values
264
+ details.delete_if {|d| '' == d[1]}
265
+ details.empty? ? nil : details
266
+ end
267
+
112
268
  REGEX_ALLOW_HTTP_URL = /^\s*allow_http_url\s*(#.*)?$/.freeze
113
269
  REGEX_BLANK_OR_COMMENT = /^\s*([#].*)*$/.freeze
114
270
  REGEX_COPY_SESSION_FIELD = /^\s*copy_session_field\s+([~!%|\/].+[~!%|\/])\s*(#.*)?$/.freeze
@@ -0,0 +1,14 @@
1
+ # coding: utf-8
2
+ # © 2016-2021 Resurface Labs Inc.
3
+
4
+ class Timer
5
+
6
+ def initialize
7
+ @started = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
8
+ end
9
+
10
+ def millis
11
+ (Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) - @started).to_s
12
+ end
13
+
14
+ end
@@ -1,5 +1,5 @@
1
1
  # coding: utf-8
2
- # © 2016-2019 Resurface Labs Inc.
2
+ # © 2016-2021 Resurface Labs Inc.
3
3
 
4
4
  class UsageLoggers
5
5
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resurfaceio-logger
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.10.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - RobDickinson
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-06 00:00:00.000000000 Z
11
+ date: 2021-02-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,58 +16,58 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.11'
19
+ version: '1.17'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.11'
26
+ version: '1.17'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rack
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.6'
33
+ version: '2.2'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.6'
40
+ version: '2.2'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '10.0'
47
+ version: 13.0.3
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '10.0'
54
+ version: 13.0.3
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '3.0'
61
+ version: '3.10'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '3.0'
68
+ version: '3.10'
69
69
  description: Library for usage logging
70
- email:
70
+ email:
71
71
  executables: []
72
72
  extensions: []
73
73
  extra_rdoc_files: []
@@ -82,12 +82,13 @@ files:
82
82
  - lib/resurfaceio/http_response_impl.rb
83
83
  - lib/resurfaceio/http_rule.rb
84
84
  - lib/resurfaceio/http_rules.rb
85
+ - lib/resurfaceio/timer.rb
85
86
  - lib/resurfaceio/usage_loggers.rb
86
87
  homepage: https://github.com/resurfaceio/logger-ruby
87
88
  licenses:
88
89
  - Apache-2.0
89
90
  metadata: {}
90
- post_install_message:
91
+ post_install_message:
91
92
  rdoc_options: []
92
93
  require_paths:
93
94
  - lib
@@ -95,16 +96,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
95
96
  requirements:
96
97
  - - "~>"
97
98
  - !ruby/object:Gem::Version
98
- version: '2.2'
99
+ version: '2.6'
99
100
  required_rubygems_version: !ruby/object:Gem::Requirement
100
101
  requirements:
101
102
  - - ">="
102
103
  - !ruby/object:Gem::Version
103
104
  version: '0'
104
105
  requirements: []
105
- rubyforge_project:
106
- rubygems_version: 2.7.7
107
- signing_key:
106
+ rubygems_version: 3.0.3
107
+ signing_key:
108
108
  specification_version: 4
109
109
  summary: Library for usage logging
110
110
  test_files: []