resurfaceio-logger 1.9.1 → 2.0.2

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: f745e986a52a415313ca922f66c119d3de17234d1c9c7c654e0dd104be45237f
4
- data.tar.gz: 8a48a6124d974ef7082566aef5c4190d5de17d6b58f1e8b950efa61620f96646
3
+ metadata.gz: 96d9dcd75c1689a944d72d80ed12692efbdc75b8c10b391bece364c26090efc1
4
+ data.tar.gz: 6851901ff3dba16d290c479cd8262f6ff3789997089bb213ead746ccb74ebb93
5
5
  SHA512:
6
- metadata.gz: 35375e533763567753fcb9947a144b81d0908c2b812a96dc3f1c17c11cbdb3ec6f97e3ace13896f6fe5eec71f22d80efea4ed1bbc913e93aeb9907ab9d7e7435
7
- data.tar.gz: 75b8e7e419e755621b78b3f602a40deadfef1a78ee57e86caf4a5528c6dfa7655901991f1fc4f019b310f763fb3881ed6bd6358b4ff54a18df5c268d0e98bccf
6
+ metadata.gz: bf5eb2c3775d016416f6e55a35a1422f4ae33d89887ffe7bf69ac280e4f569d98eed2aacb4715efcf20af4e07527726f262ad268131605174d038231a152ce3c
7
+ data.tar.gz: 715e09307d21578168425a94ef905a00bcf5497153e3902d2a3a5b0f8e058caa8d14a158ea571b0fbc81c04dd1a6c2416a4342c892a941eaf0c26fbcdb0972a1
@@ -1,5 +1,5 @@
1
1
  # coding: utf-8
2
- # © 2016-2019 Resurface Labs Inc.
2
+ # © 2016-2020 Resurface Labs Inc.
3
3
 
4
4
  require 'resurfaceio/base_logger'
5
5
  require 'resurfaceio/http_logger'
@@ -1,9 +1,10 @@
1
1
  # coding: utf-8
2
- # © 2016-2019 Resurface Labs Inc.
2
+ # © 2016-2020 Resurface Labs Inc.
3
3
 
4
4
  require 'uri'
5
5
  require 'net/http'
6
6
  require 'net/https'
7
+ require 'socket'
7
8
  require 'zlib'
8
9
  require 'resurfaceio/usage_loggers'
9
10
 
@@ -11,6 +12,7 @@ class BaseLogger
11
12
 
12
13
  def initialize(agent, options = {})
13
14
  @agent = agent
15
+ @host = BaseLogger.host_lookup
14
16
  @skip_compression = false
15
17
  @skip_submission = false
16
18
  @version = BaseLogger.version_lookup
@@ -49,7 +51,12 @@ class BaseLogger
49
51
  end
50
52
  end
51
53
 
54
+ # finalize internal properties
52
55
  @enableable = !@queue.nil? || !@url.nil?
56
+ @submit_failures = 0
57
+ @submit_failures_lock = Mutex.new
58
+ @submit_successes = 0
59
+ @submit_successes_lock = Mutex.new
53
60
  end
54
61
 
55
62
  def agent
@@ -74,6 +81,14 @@ class BaseLogger
74
81
  @enabled && UsageLoggers.enabled?
75
82
  end
76
83
 
84
+ def host
85
+ @host
86
+ end
87
+
88
+ def queue
89
+ @queue
90
+ end
91
+
77
92
  def skip_compression?
78
93
  @skip_compression
79
94
  end
@@ -90,33 +105,46 @@ class BaseLogger
90
105
  @skip_submission = value
91
106
  end
92
107
 
93
- def submit(json)
94
- if json.nil? || @skip_submission || !enabled?
95
- true
108
+ def submit(msg)
109
+ if msg.nil? || @skip_submission || !enabled?
110
+ # do nothing
96
111
  elsif @queue
97
- @queue << json
98
- true
112
+ @queue << msg
113
+ @submit_successes_lock.synchronize { @submit_successes += 1 }
99
114
  else
100
115
  begin
101
116
  @url_parsed ||= URI.parse(@url)
102
117
  @url_connection ||= Net::HTTP.new(@url_parsed.host, @url_parsed.port)
103
118
  @url_connection.use_ssl = @url.include?('https')
104
119
  request = Net::HTTP::Post.new(@url_parsed.path)
120
+ request.add_field('Content-Type', 'application/json; charset=UTF-8')
105
121
  if @skip_compression
106
- request.body = json
122
+ request.body = msg
107
123
  else
108
124
  request.add_field('Content-Encoding', 'deflated')
109
- request.body = Zlib::Deflate.deflate(json)
125
+ request.body = Zlib::Deflate.deflate(msg)
110
126
  end
111
127
  response = @url_connection.request(request)
112
- response.code.to_i == 204
128
+ if response.code.to_i == 204
129
+ @submit_successes_lock.synchronize { @submit_successes += 1 }
130
+ else
131
+ @submit_failures_lock.synchronize { @submit_failures += 1 }
132
+ end
113
133
  rescue SocketError
134
+ @submit_failures_lock.synchronize { @submit_failures += 1 }
114
135
  @url_connection = nil
115
- false
116
136
  end
117
137
  end
118
138
  end
119
139
 
140
+ def submit_failures
141
+ @submit_failures
142
+ end
143
+
144
+ def submit_successes
145
+ @submit_successes
146
+ end
147
+
120
148
  def url
121
149
  @url
122
150
  end
@@ -125,6 +153,16 @@ class BaseLogger
125
153
  @version
126
154
  end
127
155
 
156
+ def self.host_lookup
157
+ dyno = ENV['DYNO']
158
+ return dyno unless dyno.nil?
159
+ begin
160
+ Socket.gethostname
161
+ rescue
162
+ 'unknown'
163
+ end
164
+ end
165
+
128
166
  def self.version_lookup
129
167
  Gem.loaded_specs['resurfaceio-logger'].version.to_s
130
168
  end
@@ -1,5 +1,5 @@
1
1
  # coding: utf-8
2
- # © 2016-2019 Resurface Labs Inc.
2
+ # © 2016-2020 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,57 +34,21 @@ 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)
37
+ def submit_if_passing(details)
38
+ # apply active rules
39
+ details = @rules.apply(details)
40
+ return nil if details.nil?
76
41
 
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)
100
-
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]
42
+ # finalize message
118
43
  details << ['agent', @agent]
44
+ details << ['host', @host]
119
45
  details << ['version', @version]
120
- JSON.generate details
46
+
47
+ # let's do this thing
48
+ submit(JSON.generate(details))
121
49
  end
122
50
 
51
+ def self.string_content_type?(s)
52
+ !s.nil? && !(s =~ /^(text\/(html|plain|xml))|(application\/(json|soap|xml|x-www-form-urlencoded))/i).nil?
53
+ end
123
54
  end
@@ -1,8 +1,10 @@
1
1
  # coding: utf-8
2
- # © 2016-2019 Resurface Labs Inc.
2
+ # © 2016-2020 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,12 +18,13 @@ 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
23
  if @logger.enabled? && (status < 300 || status == 302)
21
24
  response = Rack::Response.new(body, status, headers)
22
25
  if HttpLogger::string_content_type?(response.content_type)
23
26
  request = Rack::Request.new(env)
24
- @logger.submit(@logger.format(request, response))
27
+ HttpMessage.send(logger, request, response, nil, nil, nil, timer.millis)
25
28
  end
26
29
  end
27
30
  [status, headers, body]
@@ -1,7 +1,9 @@
1
1
  # coding: utf-8
2
- # © 2016-2019 Resurface Labs Inc.
2
+ # © 2016-2020 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,13 +16,14 @@ 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
24
  status = response.status
22
25
  if (status < 300 || status == 302) && HttpLogger::string_content_type?(response.content_type)
23
- @logger.submit(@logger.format(request, response))
26
+ HttpMessage.send(logger, request, response, nil, nil, nil, timer.millis)
24
27
  end
25
28
  end
26
29
  end
@@ -1,15 +1,38 @@
1
1
  # coding: utf-8
2
- # © 2016-2019 Resurface Labs Inc.
2
+ # © 2016-2020 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
- append_value message, 'request_method', request.request_method
11
- append_value message, 'request_url', request.url
12
- append_value message, 'response_code', response.status
33
+ append_value message, 'request_method', request.request_method unless request.request_method.nil?
34
+ append_value message, 'request_url', request.url unless request.url.nil?
35
+ append_value message, 'response_code', response.status unless response.status.nil?
13
36
  append_request_headers message, request
14
37
  append_request_params message, request
15
38
  append_response_headers message, response
@@ -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-2020 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-2020 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-2020 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-2020 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,15 +78,13 @@ class HttpRules
76
78
  end
77
79
  end
78
80
 
79
- protected
80
-
81
81
  def self.parse_regex(r, regex)
82
- str = parse_string(r, regex)
83
- raise RuntimeError.new("Invalid regex (#{regex}) in rule: #{r}") if '*' == str || '+' == str || '?' == str
84
- str = "^#{str}" unless str.start_with?('^')
85
- str = "#{str}$" unless str.end_with?('$')
82
+ s = parse_string(r, regex)
83
+ raise RuntimeError.new("Invalid regex (#{regex}) in rule: #{r}") if '*' == s || '+' == s || '?' == s
84
+ s = "^#{s}" unless s.start_with?('^')
85
+ s = "#{s}$" unless s.end_with?('$')
86
86
  begin
87
- return Regexp.compile(str)
87
+ return Regexp.compile(s)
88
88
  rescue RegexpError
89
89
  raise RuntimeError.new("Invalid regex (#{regex}) in rule: #{r}")
90
90
  end
@@ -98,15 +98,171 @@ class HttpRules
98
98
  end
99
99
  end
100
100
 
101
- def self.parse_string(r, str)
101
+ def self.parse_string(r, expr)
102
102
  %w(~ ! % | /).each do |sep|
103
- if (m = str.match(/^[#{sep}](.*)[#{sep}]$/))
103
+ if (m = expr.match(/^[#{sep}](.*)[#{sep}]$/))
104
104
  m1 = m[1]
105
105
  raise RuntimeError.new("Unescaped separator (#{sep}) in rule: #{r}") if m1.match(/^[#{sep}].*|.*[^\\][#{sep}].*/)
106
106
  return m1.gsub("\\#{sep}", sep)
107
107
  end
108
108
  end
109
- raise RuntimeError.new("Invalid expression (#{str}) in rule: #{r}")
109
+ raise RuntimeError.new("Invalid expression (#{expr}) in rule: #{r}")
110
+ end
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
110
266
  end
111
267
 
112
268
  REGEX_ALLOW_HTTP_URL = /^\s*allow_http_url\s*(#.*)?$/.freeze
@@ -0,0 +1,14 @@
1
+ # coding: utf-8
2
+ # © 2016-2020 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,18 +1,18 @@
1
1
  # coding: utf-8
2
- # © 2016-2019 Resurface Labs Inc.
2
+ # © 2016-2020 Resurface Labs Inc.
3
3
 
4
4
  class UsageLoggers
5
5
 
6
- @@DISABLED = 'true'.eql?(ENV['USAGE_LOGGERS_DISABLE'])
6
+ @@BRICKED = 'true'.eql?(ENV['USAGE_LOGGERS_DISABLE'])
7
7
 
8
- @@disabled = @@DISABLED
8
+ @@disabled = @@BRICKED
9
9
 
10
10
  def self.disable
11
11
  @@disabled = true
12
12
  end
13
13
 
14
14
  def self.enable
15
- @@disabled = false unless @@DISABLED
15
+ @@disabled = false unless @@BRICKED
16
16
  end
17
17
 
18
18
  def self.enabled?
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.9.1
4
+ version: 2.0.2
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-05-25 00:00:00.000000000 Z
11
+ date: 2020-07-18 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'
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'
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.9'
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.9'
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: []