resurfaceio-logger 1.8.4 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/lib/resurfaceio/all.rb +11 -3
- data/lib/resurfaceio/base_logger.rb +47 -10
- data/lib/resurfaceio/http_logger.rb +36 -14
- data/lib/resurfaceio/http_logger_for_rack.rb +3 -3
- data/lib/resurfaceio/http_logger_for_rails.rb +3 -3
- data/lib/resurfaceio/{http_message_impl.rb → http_message.rb} +34 -13
- data/lib/resurfaceio/http_request_impl.rb +6 -1
- data/lib/resurfaceio/http_response_impl.rb +1 -1
- data/lib/resurfaceio/http_rule.rb +15 -0
- data/lib/resurfaceio/http_rules.rb +278 -0
- data/lib/resurfaceio/usage_loggers.rb +4 -4
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 78d67f05915dcaee82ef7e3809856549bf09d01ac1f26d32f4dcb02003d317f3
|
4
|
+
data.tar.gz: f3d3598661aed83877882554183991ef228ac92d3f875f087eafddd3221cfa59
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5aa5de88c997daddb5f345e4e41d5a173e59adb449dec141ee015747a48ef2f82a7ec623a6b1630d913f5a018f72c4aa1907e310fa1a7808f5c5c579db0281d9
|
7
|
+
data.tar.gz: e998c80806e0488c0790e551285e3ae90b7897aa7e027019ad18fd9c9794f0bb37add6d5aaeddb8eb275e66da18b3b9e21b042af636009966d9b6773f200ae88
|
data/lib/resurfaceio/all.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
# © 2016-
|
2
|
+
# © 2016-2020 Resurface Labs Inc.
|
3
3
|
|
4
4
|
require 'resurfaceio/base_logger'
|
5
5
|
require 'resurfaceio/http_logger'
|
6
6
|
require 'resurfaceio/http_logger_for_rack'
|
7
7
|
require 'resurfaceio/http_logger_for_rails'
|
8
|
-
require 'resurfaceio/
|
8
|
+
require 'resurfaceio/http_message'
|
9
9
|
require 'resurfaceio/http_request_impl'
|
10
10
|
require 'resurfaceio/http_response_impl'
|
11
|
+
require 'resurfaceio/http_rule'
|
12
|
+
require 'resurfaceio/http_rules'
|
11
13
|
require 'resurfaceio/usage_loggers'
|
12
14
|
|
13
15
|
module Resurfaceio
|
@@ -24,7 +26,7 @@ module Resurfaceio
|
|
24
26
|
class HttpLoggerForRails < HttpLoggerForRails
|
25
27
|
end
|
26
28
|
|
27
|
-
class
|
29
|
+
class HttpMessage < HttpMessage
|
28
30
|
end
|
29
31
|
|
30
32
|
class HttpRequestImpl < HttpRequestImpl
|
@@ -33,6 +35,12 @@ module Resurfaceio
|
|
33
35
|
class HttpResponseImpl < HttpResponseImpl
|
34
36
|
end
|
35
37
|
|
38
|
+
class HttpRule < HttpRule
|
39
|
+
end
|
40
|
+
|
41
|
+
class HttpRules < HttpRules
|
42
|
+
end
|
43
|
+
|
36
44
|
class UsageLoggers < UsageLoggers
|
37
45
|
end
|
38
46
|
|
@@ -1,9 +1,10 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
# © 2016-
|
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,12 +105,12 @@ class BaseLogger
|
|
90
105
|
@skip_submission = value
|
91
106
|
end
|
92
107
|
|
93
|
-
def submit(
|
94
|
-
if @skip_submission || !enabled?
|
95
|
-
|
108
|
+
def submit(msg)
|
109
|
+
if msg.nil? || @skip_submission || !enabled?
|
110
|
+
# do nothing
|
96
111
|
elsif @queue
|
97
|
-
@queue <<
|
98
|
-
|
112
|
+
@queue << msg
|
113
|
+
@submit_successes_lock.synchronize { @submit_successes += 1 }
|
99
114
|
else
|
100
115
|
begin
|
101
116
|
@url_parsed ||= URI.parse(@url)
|
@@ -103,20 +118,32 @@ class BaseLogger
|
|
103
118
|
@url_connection.use_ssl = @url.include?('https')
|
104
119
|
request = Net::HTTP::Post.new(@url_parsed.path)
|
105
120
|
if @skip_compression
|
106
|
-
request.body =
|
121
|
+
request.body = msg
|
107
122
|
else
|
108
123
|
request.add_field('Content-Encoding', 'deflated')
|
109
|
-
request.body = Zlib::Deflate.deflate(
|
124
|
+
request.body = Zlib::Deflate.deflate(msg)
|
110
125
|
end
|
111
126
|
response = @url_connection.request(request)
|
112
|
-
response.code.to_i == 204
|
127
|
+
if response.code.to_i == 204
|
128
|
+
@submit_successes_lock.synchronize { @submit_successes += 1 }
|
129
|
+
else
|
130
|
+
@submit_failures_lock.synchronize { @submit_failures += 1 }
|
131
|
+
end
|
113
132
|
rescue SocketError
|
133
|
+
@submit_failures_lock.synchronize { @submit_failures += 1 }
|
114
134
|
@url_connection = nil
|
115
|
-
false
|
116
135
|
end
|
117
136
|
end
|
118
137
|
end
|
119
138
|
|
139
|
+
def submit_failures
|
140
|
+
@submit_failures
|
141
|
+
end
|
142
|
+
|
143
|
+
def submit_successes
|
144
|
+
@submit_successes
|
145
|
+
end
|
146
|
+
|
120
147
|
def url
|
121
148
|
@url
|
122
149
|
end
|
@@ -125,6 +152,16 @@ class BaseLogger
|
|
125
152
|
@version
|
126
153
|
end
|
127
154
|
|
155
|
+
def self.host_lookup
|
156
|
+
dyno = ENV['DYNO']
|
157
|
+
return dyno unless dyno.nil?
|
158
|
+
begin
|
159
|
+
Socket.gethostname
|
160
|
+
rescue
|
161
|
+
'unknown'
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
128
165
|
def self.version_lookup
|
129
166
|
Gem.loaded_specs['resurfaceio-logger'].version.to_s
|
130
167
|
end
|
@@ -1,32 +1,54 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
# © 2016-
|
2
|
+
# © 2016-2020 Resurface Labs Inc.
|
3
3
|
|
4
4
|
require 'json'
|
5
5
|
require 'resurfaceio/base_logger'
|
6
|
-
require 'resurfaceio/
|
6
|
+
require 'resurfaceio/http_message'
|
7
|
+
require 'resurfaceio/http_rule'
|
8
|
+
require 'resurfaceio/http_rules'
|
7
9
|
|
8
10
|
class HttpLogger < BaseLogger
|
9
11
|
|
10
12
|
AGENT = 'http_logger.rb'.freeze
|
11
13
|
|
12
|
-
def self.string_content_type?(s)
|
13
|
-
!s.nil? && !(s =~ /^(text\/(html|plain|xml))|(application\/(json|soap|xml|x-www-form-urlencoded))/i).nil?
|
14
|
-
end
|
15
|
-
|
16
14
|
def initialize(options = {})
|
17
15
|
super(AGENT, options)
|
16
|
+
|
17
|
+
# parse specified rules
|
18
|
+
if options.respond_to?(:has_key?) && options.has_key?(:rules)
|
19
|
+
@rules = HttpRules.new(options[:rules])
|
20
|
+
else
|
21
|
+
@rules = HttpRules.new(nil)
|
22
|
+
end
|
23
|
+
|
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
|
28
|
+
@enableable = false
|
29
|
+
@enabled = false
|
30
|
+
end
|
18
31
|
end
|
19
32
|
|
20
|
-
def
|
21
|
-
|
22
|
-
message << ['agent', @agent]
|
23
|
-
message << ['version', @version]
|
24
|
-
message << ['now', now.nil? ? (Time.now.to_f * 1000).floor.to_s : now]
|
25
|
-
JSON.generate message
|
33
|
+
def rules
|
34
|
+
@rules
|
26
35
|
end
|
27
36
|
|
28
|
-
def
|
29
|
-
|
37
|
+
def submit_if_passing(details)
|
38
|
+
# apply active rules
|
39
|
+
details = @rules.apply(details)
|
40
|
+
return nil if details.nil?
|
41
|
+
|
42
|
+
# finalize message
|
43
|
+
details << ['agent', @agent]
|
44
|
+
details << ['host', @host]
|
45
|
+
details << ['version', @version]
|
46
|
+
|
47
|
+
# let's do this thing
|
48
|
+
submit(JSON.generate(details))
|
30
49
|
end
|
31
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
|
32
54
|
end
|
@@ -1,8 +1,9 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
# © 2016-
|
2
|
+
# © 2016-2020 Resurface Labs Inc.
|
3
3
|
|
4
4
|
require 'rack'
|
5
5
|
require 'resurfaceio/http_logger'
|
6
|
+
require 'resurfaceio/http_message'
|
6
7
|
|
7
8
|
class HttpLoggerForRack # http://rack.rubyforge.org/doc/SPEC.html
|
8
9
|
|
@@ -21,8 +22,7 @@ class HttpLoggerForRack # http://rack.rubyforge.org/doc/SPEC.html
|
|
21
22
|
response = Rack::Response.new(body, status, headers)
|
22
23
|
if HttpLogger::string_content_type?(response.content_type)
|
23
24
|
request = Rack::Request.new(env)
|
24
|
-
|
25
|
-
@logger.submit(message)
|
25
|
+
HttpMessage.send(logger, request, response) # todo add timing details
|
26
26
|
end
|
27
27
|
end
|
28
28
|
[status, headers, body]
|
@@ -1,7 +1,8 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
# © 2016-
|
2
|
+
# © 2016-2020 Resurface Labs Inc.
|
3
3
|
|
4
4
|
require 'resurfaceio/http_logger'
|
5
|
+
require 'resurfaceio/http_message'
|
5
6
|
|
6
7
|
class HttpLoggerForRails
|
7
8
|
|
@@ -20,8 +21,7 @@ class HttpLoggerForRails
|
|
20
21
|
response = controller.response
|
21
22
|
status = response.status
|
22
23
|
if (status < 300 || status == 302) && HttpLogger::string_content_type?(response.content_type)
|
23
|
-
|
24
|
-
@logger.submit(message)
|
24
|
+
HttpMessage.send(logger, request, response) # todo add timing details
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
@@ -1,15 +1,38 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
# © 2016-
|
2
|
+
# © 2016-2020 Resurface Labs Inc.
|
3
3
|
|
4
4
|
require 'json'
|
5
5
|
|
6
|
-
class
|
6
|
+
class HttpMessage
|
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
|
7
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 HttpMessageImpl
|
|
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 HttpMessageImpl
|
|
74
95
|
unless key.nil?
|
75
96
|
unless value.nil?
|
76
97
|
case value
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
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-
|
2
|
+
# © 2016-2020 Resurface Labs Inc.
|
3
3
|
|
4
4
|
class HttpRequestImpl
|
5
5
|
|
@@ -7,6 +7,7 @@ class HttpRequestImpl
|
|
7
7
|
@form_hash = Hash.new
|
8
8
|
@headers = Hash.new
|
9
9
|
@query_hash = Hash.new
|
10
|
+
@session = Hash.new
|
10
11
|
end
|
11
12
|
|
12
13
|
def add_header(key, value)
|
@@ -40,6 +41,10 @@ class HttpRequestImpl
|
|
40
41
|
@query_hash
|
41
42
|
end
|
42
43
|
|
44
|
+
def session
|
45
|
+
@session
|
46
|
+
end
|
47
|
+
|
43
48
|
attr_accessor :request_method
|
44
49
|
attr_accessor :url
|
45
50
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# © 2016-2020 Resurface Labs Inc.
|
3
|
+
|
4
|
+
class HttpRule
|
5
|
+
|
6
|
+
def initialize(verb, scope = nil, param1 = nil, param2 = nil)
|
7
|
+
@verb = verb
|
8
|
+
@scope = scope
|
9
|
+
@param1 = param1
|
10
|
+
@param2 = param2
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :verb, :scope, :param1, :param2
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,278 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# © 2016-2020 Resurface Labs Inc.
|
3
|
+
|
4
|
+
class HttpRules
|
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
|
+
|
27
|
+
def self.debug_rules
|
28
|
+
DEBUG_RULES
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.standard_rules
|
32
|
+
STANDARD_RULES
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.strict_rules
|
36
|
+
STRICT_RULES
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.parse_rule(r)
|
40
|
+
if r.nil? || r.match(REGEX_BLANK_OR_COMMENT)
|
41
|
+
nil
|
42
|
+
elsif r.match(REGEX_ALLOW_HTTP_URL)
|
43
|
+
HttpRule.new('allow_http_url')
|
44
|
+
elsif (m = r.match(REGEX_COPY_SESSION_FIELD))
|
45
|
+
HttpRule.new('copy_session_field', nil, parse_regex(r, m[1]))
|
46
|
+
elsif (m = r.match(REGEX_REMOVE))
|
47
|
+
HttpRule.new('remove', parse_regex(r, m[1]))
|
48
|
+
elsif (m = r.match(REGEX_REMOVE_IF))
|
49
|
+
HttpRule.new('remove_if', parse_regex(r, m[1]), parse_regex(r, m[2]))
|
50
|
+
elsif (m = r.match(REGEX_REMOVE_IF_FOUND))
|
51
|
+
HttpRule.new('remove_if_found', parse_regex(r, m[1]), parse_regex_find(r, m[2]))
|
52
|
+
elsif (m = r.match(REGEX_REMOVE_UNLESS))
|
53
|
+
HttpRule.new('remove_unless', parse_regex(r, m[1]), parse_regex(r, m[2]))
|
54
|
+
elsif (m = r.match(REGEX_REMOVE_UNLESS_FOUND))
|
55
|
+
HttpRule.new('remove_unless_found', parse_regex(r, m[1]), parse_regex_find(r, m[2]))
|
56
|
+
elsif (m = r.match(REGEX_REPLACE))
|
57
|
+
HttpRule.new('replace', parse_regex(r, m[1]), parse_regex_find(r, m[2]), parse_string(r, m[3]))
|
58
|
+
elsif (m = r.match(REGEX_SAMPLE))
|
59
|
+
m1 = m[1].to_i
|
60
|
+
raise RuntimeError.new("Invalid sample percent: #{m1}") if m1 < 1 || m1 > 99
|
61
|
+
HttpRule.new('sample', nil, m1)
|
62
|
+
elsif r.match(REGEX_SKIP_COMPRESSION)
|
63
|
+
HttpRule.new('skip_compression')
|
64
|
+
elsif r.match(REGEX_SKIP_SUBMISSION)
|
65
|
+
HttpRule.new('skip_submission')
|
66
|
+
elsif (m = r.match(REGEX_STOP))
|
67
|
+
HttpRule.new('stop', parse_regex(r, m[1]))
|
68
|
+
elsif (m = r.match(REGEX_STOP_IF))
|
69
|
+
HttpRule.new('stop_if', parse_regex(r, m[1]), parse_regex(r, m[2]))
|
70
|
+
elsif (m = r.match(REGEX_STOP_IF_FOUND))
|
71
|
+
HttpRule.new('stop_if_found', parse_regex(r, m[1]), parse_regex_find(r, m[2]))
|
72
|
+
elsif (m = r.match(REGEX_STOP_UNLESS))
|
73
|
+
HttpRule.new('stop_unless', parse_regex(r, m[1]), parse_regex(r, m[2]))
|
74
|
+
elsif (m = r.match(REGEX_STOP_UNLESS_FOUND))
|
75
|
+
HttpRule.new('stop_unless_found', parse_regex(r, m[1]), parse_regex_find(r, m[2]))
|
76
|
+
else
|
77
|
+
raise RuntimeError.new("Invalid rule: #{r}")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.parse_regex(r, regex)
|
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
|
+
begin
|
87
|
+
return Regexp.compile(s)
|
88
|
+
rescue RegexpError
|
89
|
+
raise RuntimeError.new("Invalid regex (#{regex}) in rule: #{r}")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.parse_regex_find(r, regex)
|
94
|
+
begin
|
95
|
+
return Regexp.compile(parse_string(r, regex))
|
96
|
+
rescue RegexpError
|
97
|
+
raise RuntimeError.new("Invalid regex (#{regex}) in rule: #{r}")
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.parse_string(r, expr)
|
102
|
+
%w(~ ! % | /).each do |sep|
|
103
|
+
if (m = expr.match(/^[#{sep}](.*)[#{sep}]$/))
|
104
|
+
m1 = m[1]
|
105
|
+
raise RuntimeError.new("Unescaped separator (#{sep}) in rule: #{r}") if m1.match(/^[#{sep}].*|.*[^\\][#{sep}].*/)
|
106
|
+
return m1.gsub("\\#{sep}", sep)
|
107
|
+
end
|
108
|
+
end
|
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
|
+
# todo load rules from external files
|
116
|
+
|
117
|
+
# force default rules if necessary
|
118
|
+
rules = rules.gsub(/^\s*include default\s*$/, HttpRules.default_rules)
|
119
|
+
rules = HttpRules.default_rules unless rules.strip.length > 0
|
120
|
+
|
121
|
+
# expand rule inclues
|
122
|
+
rules = rules.gsub(/^\s*include debug\s*$/, DEBUG_RULES)
|
123
|
+
rules = rules.gsub(/^\s*include standard\s*$/, STANDARD_RULES)
|
124
|
+
rules = rules.gsub(/^\s*include strict\s*$/, STRICT_RULES)
|
125
|
+
@text = rules
|
126
|
+
|
127
|
+
# parse all rules
|
128
|
+
prs = []
|
129
|
+
rules.each_line do |rule|
|
130
|
+
parsed = HttpRules.parse_rule(rule)
|
131
|
+
prs << parsed unless parsed.nil?
|
132
|
+
end
|
133
|
+
@length = prs.length
|
134
|
+
|
135
|
+
# break out rules by verb
|
136
|
+
@allow_http_url = prs.select {|r| 'allow_http_url' == r.verb}.length > 0
|
137
|
+
@copy_session_field = prs.select {|r| 'copy_session_field' == r.verb}
|
138
|
+
@remove = prs.select {|r| 'remove' == r.verb}
|
139
|
+
@remove_if = prs.select {|r| 'remove_if' == r.verb}
|
140
|
+
@remove_if_found = prs.select {|r| 'remove_if_found' == r.verb}
|
141
|
+
@remove_unless = prs.select {|r| 'remove_unless' == r.verb}
|
142
|
+
@remove_unless_found = prs.select {|r| 'remove_unless_found' == r.verb}
|
143
|
+
@replace = prs.select {|r| 'replace' == r.verb}
|
144
|
+
@sample = prs.select {|r| 'sample' == r.verb}
|
145
|
+
@skip_compression = prs.select {|r| 'skip_compression' == r.verb}.length > 0
|
146
|
+
@skip_submission = prs.select {|r| 'skip_submission' == r.verb}.length > 0
|
147
|
+
@stop = prs.select {|r| 'stop' == r.verb}
|
148
|
+
@stop_if = prs.select {|r| 'stop_if' == r.verb}
|
149
|
+
@stop_if_found = prs.select {|r| 'stop_if_found' == r.verb}
|
150
|
+
@stop_unless = prs.select {|r| 'stop_unless' == r.verb}
|
151
|
+
@stop_unless_found = prs.select {|r| 'stop_unless_found' == r.verb}
|
152
|
+
|
153
|
+
# validate rules
|
154
|
+
raise RuntimeError.new('Multiple sample rules') if @sample.length > 1
|
155
|
+
end
|
156
|
+
|
157
|
+
def allow_http_url
|
158
|
+
@allow_http_url
|
159
|
+
end
|
160
|
+
|
161
|
+
def copy_session_field
|
162
|
+
@copy_session_field
|
163
|
+
end
|
164
|
+
|
165
|
+
def length
|
166
|
+
@length
|
167
|
+
end
|
168
|
+
|
169
|
+
def remove
|
170
|
+
@remove
|
171
|
+
end
|
172
|
+
|
173
|
+
def remove_if
|
174
|
+
@remove_if
|
175
|
+
end
|
176
|
+
|
177
|
+
def remove_if_found
|
178
|
+
@remove_if_found
|
179
|
+
end
|
180
|
+
|
181
|
+
def remove_unless
|
182
|
+
@remove_unless
|
183
|
+
end
|
184
|
+
|
185
|
+
def remove_unless_found
|
186
|
+
@remove_unless_found
|
187
|
+
end
|
188
|
+
|
189
|
+
def replace
|
190
|
+
@replace
|
191
|
+
end
|
192
|
+
|
193
|
+
def sample
|
194
|
+
@sample
|
195
|
+
end
|
196
|
+
|
197
|
+
def skip_compression
|
198
|
+
@skip_compression
|
199
|
+
end
|
200
|
+
|
201
|
+
def skip_submission
|
202
|
+
@skip_submission
|
203
|
+
end
|
204
|
+
|
205
|
+
def stop
|
206
|
+
@stop
|
207
|
+
end
|
208
|
+
|
209
|
+
def stop_if
|
210
|
+
@stop_if
|
211
|
+
end
|
212
|
+
|
213
|
+
def stop_if_found
|
214
|
+
@stop_if_found
|
215
|
+
end
|
216
|
+
|
217
|
+
def stop_unless
|
218
|
+
@stop_unless
|
219
|
+
end
|
220
|
+
|
221
|
+
def stop_unless_found
|
222
|
+
@stop_unless_found
|
223
|
+
end
|
224
|
+
|
225
|
+
def text
|
226
|
+
@text
|
227
|
+
end
|
228
|
+
|
229
|
+
def apply(details)
|
230
|
+
# stop rules come first
|
231
|
+
@stop.each {|r| details.each {|d| return nil if r.scope.match(d[0])}}
|
232
|
+
@stop_if_found.each {|r| details.each {|d| return nil if r.scope.match(d[0]) && r.param1.match(d[1])}}
|
233
|
+
@stop_if.each {|r| details.each {|d| return nil if r.scope.match(d[0]) && r.param1.match(d[1])}}
|
234
|
+
passed = 0
|
235
|
+
@stop_unless_found.each {|r| details.each {|d| passed += 1 if r.scope.match(d[0]) && r.param1.match(d[1])}}
|
236
|
+
return nil if passed != @stop_unless_found.length
|
237
|
+
passed = 0
|
238
|
+
@stop_unless.each {|r| details.each {|d| passed += 1 if r.scope.match(d[0]) && r.param1.match(d[1])}}
|
239
|
+
return nil if passed != @stop_unless.length
|
240
|
+
|
241
|
+
# do sampling if configured
|
242
|
+
return nil if !@sample[0].nil? && (rand * 100 >= @sample[0].param1)
|
243
|
+
|
244
|
+
# winnow sensitive details based on remove rules if configured
|
245
|
+
@remove.each {|r| details.delete_if {|d| r.scope.match(d[0])}}
|
246
|
+
@remove_unless_found.each {|r| details.delete_if {|d| r.scope.match(d[0]) && !r.param1.match(d[1])}}
|
247
|
+
@remove_if_found.each {|r| details.delete_if {|d| r.scope.match(d[0]) && r.param1.match(d[1])}}
|
248
|
+
@remove_unless.each {|r| details.delete_if {|d| r.scope.match(d[0]) && !r.param1.match(d[1])}}
|
249
|
+
@remove_if.each {|r| details.delete_if {|d| r.scope.match(d[0]) && r.param1.match(d[1])}}
|
250
|
+
return nil if details.empty?
|
251
|
+
|
252
|
+
# mask sensitive details based on replace rules if configured
|
253
|
+
@replace.each {|r| details.each {|d| d[1] = d[1].gsub(r.param1, r.param2) if r.scope.match(d[0])}}
|
254
|
+
|
255
|
+
# remove any details with empty values
|
256
|
+
details.delete_if {|d| '' == d[1]}
|
257
|
+
details.empty? ? nil : details
|
258
|
+
end
|
259
|
+
|
260
|
+
REGEX_ALLOW_HTTP_URL = /^\s*allow_http_url\s*(#.*)?$/.freeze
|
261
|
+
REGEX_BLANK_OR_COMMENT = /^\s*([#].*)*$/.freeze
|
262
|
+
REGEX_COPY_SESSION_FIELD = /^\s*copy_session_field\s+([~!%|\/].+[~!%|\/])\s*(#.*)?$/.freeze
|
263
|
+
REGEX_REMOVE = /^\s*([~!%|\/].+[~!%|\/])\s*remove\s*(#.*)?$/.freeze
|
264
|
+
REGEX_REMOVE_IF = /^\s*([~!%|\/].+[~!%|\/])\s*remove_if\s+([~!%|\/].+[~!%|\/])\s*(#.*)?$/.freeze
|
265
|
+
REGEX_REMOVE_IF_FOUND = /^\s*([~!%|\/].+[~!%|\/])\s*remove_if_found\s+([~!%|\/].+[~!%|\/])\s*(#.*)?$/.freeze
|
266
|
+
REGEX_REMOVE_UNLESS = /^\s*([~!%|\/].+[~!%|\/])\s*remove_unless\s+([~!%|\/].+[~!%|\/])\s*(#.*)?$/.freeze
|
267
|
+
REGEX_REMOVE_UNLESS_FOUND = /^\s*([~!%|\/].+[~!%|\/])\s*remove_unless_found\s+([~!%|\/].+[~!%|\/])\s*(#.*)?$/.freeze
|
268
|
+
REGEX_REPLACE = /^\s*([~!%|\/].+[~!%|\/])\s*replace[\s]+([~!%|\/].+[~!%|\/]),[\s]+([~!%|\/].*[~!%|\/])\s*(#.*)?$/.freeze
|
269
|
+
REGEX_SAMPLE = /^\s*sample\s+(\d+)\s*(#.*)?$/.freeze
|
270
|
+
REGEX_SKIP_COMPRESSION = /^\s*skip_compression\s*(#.*)?$/.freeze
|
271
|
+
REGEX_SKIP_SUBMISSION = /^\s*skip_submission\s*(#.*)?$/.freeze
|
272
|
+
REGEX_STOP = /^\s*([~!%|\/].+[~!%|\/])\s*stop\s*(#.*)?$/.freeze
|
273
|
+
REGEX_STOP_IF = /^\s*([~!%|\/].+[~!%|\/])\s*stop_if\s+([~!%|\/].+[~!%|\/])\s*(#.*)?$/.freeze
|
274
|
+
REGEX_STOP_IF_FOUND = /^\s*([~!%|\/].+[~!%|\/])\s*stop_if_found\s+([~!%|\/].+[~!%|\/])\s*(#.*)?$/.freeze
|
275
|
+
REGEX_STOP_UNLESS = /^\s*([~!%|\/].+[~!%|\/])\s*stop_unless\s+([~!%|\/].+[~!%|\/])\s*(#.*)?$/.freeze
|
276
|
+
REGEX_STOP_UNLESS_FOUND = /^\s*([~!%|\/].+[~!%|\/])\s*stop_unless_found\s+([~!%|\/].+[~!%|\/])\s*(#.*)?$/.freeze
|
277
|
+
|
278
|
+
end
|
@@ -1,18 +1,18 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
# © 2016-
|
2
|
+
# © 2016-2020 Resurface Labs Inc.
|
3
3
|
|
4
4
|
class UsageLoggers
|
5
5
|
|
6
|
-
@@
|
6
|
+
@@BRICKED = 'true'.eql?(ENV['USAGE_LOGGERS_DISABLE'])
|
7
7
|
|
8
|
-
@@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 @@
|
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:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- RobDickinson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-01-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -77,9 +77,11 @@ files:
|
|
77
77
|
- lib/resurfaceio/http_logger.rb
|
78
78
|
- lib/resurfaceio/http_logger_for_rack.rb
|
79
79
|
- lib/resurfaceio/http_logger_for_rails.rb
|
80
|
-
- lib/resurfaceio/
|
80
|
+
- lib/resurfaceio/http_message.rb
|
81
81
|
- lib/resurfaceio/http_request_impl.rb
|
82
82
|
- lib/resurfaceio/http_response_impl.rb
|
83
|
+
- lib/resurfaceio/http_rule.rb
|
84
|
+
- lib/resurfaceio/http_rules.rb
|
83
85
|
- lib/resurfaceio/usage_loggers.rb
|
84
86
|
homepage: https://github.com/resurfaceio/logger-ruby
|
85
87
|
licenses:
|
@@ -101,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
101
103
|
version: '0'
|
102
104
|
requirements: []
|
103
105
|
rubyforge_project:
|
104
|
-
rubygems_version: 2.
|
106
|
+
rubygems_version: 2.7.7
|
105
107
|
signing_key:
|
106
108
|
specification_version: 4
|
107
109
|
summary: Library for usage logging
|