timber 2.5.1 → 2.6.0.pre.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -1
- data/lib/timber/config.rb +2 -1
- data/lib/timber/contexts/custom.rb +10 -3
- data/lib/timber/contexts/http.rb +23 -7
- data/lib/timber/contexts/organization.rb +14 -3
- data/lib/timber/contexts/release.rb +17 -4
- data/lib/timber/contexts/runtime.rb +28 -9
- data/lib/timber/contexts/session.rb +11 -2
- data/lib/timber/contexts/system.rb +13 -3
- data/lib/timber/contexts/user.rb +22 -6
- data/lib/timber/events/controller_call.rb +14 -24
- data/lib/timber/events/custom.rb +8 -5
- data/lib/timber/events/error.rb +11 -31
- data/lib/timber/events/http_request.rb +39 -13
- data/lib/timber/events/http_response.rb +32 -14
- data/lib/timber/events/sql_query.rb +10 -7
- data/lib/timber/events/template_render.rb +11 -5
- data/lib/timber/log_entry.rb +7 -31
- data/lib/timber/logger.rb +1 -5
- data/lib/timber/util.rb +2 -2
- data/lib/timber/util/attribute_normalizer.rb +90 -0
- data/lib/timber/util/hash.rb +51 -1
- data/lib/timber/util/non_nil_hash_builder.rb +38 -0
- data/lib/timber/version.rb +1 -1
- data/spec/timber/events/error_spec.rb +8 -22
- data/spec/timber/events/http_request_spec.rb +1 -1
- data/spec/timber/events_spec.rb +1 -1
- data/spec/timber/integrations/action_dispatch/debug_exceptions_spec.rb +1 -1
- data/spec/timber/log_entry_spec.rb +0 -39
- data/spec/timber/logger_spec.rb +0 -5
- data/spec/timber/util/attribute_normalizer_spec.rb +90 -0
- metadata +8 -8
- data/lib/timber/util/http_event.rb +0 -69
- data/lib/timber/util/object.rb +0 -15
- data/spec/timber/util/http_event_spec.rb +0 -15
data/lib/timber/util/hash.rb
CHANGED
@@ -2,6 +2,7 @@ module Timber
|
|
2
2
|
module Util
|
3
3
|
# @private
|
4
4
|
module Hash
|
5
|
+
BINARY_LIMIT_THRESHOLD = 1_000.freeze
|
5
6
|
SANITIZED_VALUE = '[sanitized]'.freeze
|
6
7
|
|
7
8
|
extend self
|
@@ -25,7 +26,37 @@ module Timber
|
|
25
26
|
new_hash
|
26
27
|
end
|
27
28
|
|
28
|
-
|
29
|
+
# Recursively traverses a hash, dropping non-JSON compatible types.
|
30
|
+
# If the string is a binary, and it is > 1000 characters, it is dropped.
|
31
|
+
# We are assuming it represents file contents that should not be included
|
32
|
+
# in the logs.
|
33
|
+
def jsonify(hash)
|
34
|
+
deep_reduce(hash) do |k, v, h|
|
35
|
+
if v.is_a?(String)
|
36
|
+
if v.encoding == ::Encoding::ASCII_8BIT
|
37
|
+
# Only keep binary values less than a certain size. Sizes larger than this
|
38
|
+
# are almost always file uploads and data we do not want to log.
|
39
|
+
if v.length < BINARY_LIMIT_THRESHOLD
|
40
|
+
# Attempt to safely encode the data to UTF-8
|
41
|
+
encoded_value = encode_string(v)
|
42
|
+
if !encoded_value.nil?
|
43
|
+
h[k] = encoded_value
|
44
|
+
end
|
45
|
+
end
|
46
|
+
elsif v.encoding != ::Encoding::UTF_8
|
47
|
+
h[k] = encode_string(v)
|
48
|
+
else
|
49
|
+
h[k] = v
|
50
|
+
end
|
51
|
+
elsif is_a_primitive_type?(v)
|
52
|
+
# Keep all other primitive types
|
53
|
+
h[k] = v
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Replaces matching keys with a `[Sanitized]` value.
|
59
|
+
def sanitize_keys(hash, keys_to_sanitize)
|
29
60
|
hash.each_with_object({}) do |(k, v), h|
|
30
61
|
k = k.to_s.downcase
|
31
62
|
if keys_to_sanitize.include?(k)
|
@@ -35,6 +66,25 @@ module Timber
|
|
35
66
|
end
|
36
67
|
end
|
37
68
|
end
|
69
|
+
|
70
|
+
private
|
71
|
+
# Attempts to encode a non UTF-8 string into UTF-8, discarding invalid characters.
|
72
|
+
# If it fails, a nil is returned.
|
73
|
+
def encode_string(string)
|
74
|
+
string.encode('UTF-8', {
|
75
|
+
:invalid => :replace,
|
76
|
+
:undef => :replace,
|
77
|
+
:replace => '?'
|
78
|
+
})
|
79
|
+
rescue Exception
|
80
|
+
nil
|
81
|
+
end
|
82
|
+
|
83
|
+
# We use is_a? because it accounts for inheritance.
|
84
|
+
def is_a_primitive_type?(v)
|
85
|
+
v.is_a?(Array) || v.is_a?(Integer) || v.is_a?(Float) || v.is_a?(TrueClass) ||
|
86
|
+
v.is_a?(FalseClass) || v.is_a?(String) || v.is_a?(Time)
|
87
|
+
end
|
38
88
|
end
|
39
89
|
end
|
40
90
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Timber
|
2
|
+
module Util
|
3
|
+
# @private
|
4
|
+
#
|
5
|
+
# The purpose of this class is to efficiently build a hash that does not
|
6
|
+
# include nil values. It's proactive instead of reactive, avoiding the
|
7
|
+
# need to traverse and reduce a new hash dropping blanks.
|
8
|
+
class NonNilHashBuilder
|
9
|
+
class << self
|
10
|
+
def build(&block)
|
11
|
+
builder = new
|
12
|
+
yield builder
|
13
|
+
builder.target
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :target
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
@target = {}
|
21
|
+
end
|
22
|
+
|
23
|
+
def add(k, v, options = {})
|
24
|
+
if !v.nil?
|
25
|
+
if options[:json_encode]
|
26
|
+
v = v.to_json
|
27
|
+
end
|
28
|
+
|
29
|
+
if options[:limit]
|
30
|
+
v = v.byteslice(0, options[:limit])
|
31
|
+
end
|
32
|
+
|
33
|
+
@target[k] = v
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/timber/version.rb
CHANGED
@@ -1,34 +1,20 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe Timber::Events::Error, :rails_23 => true do
|
4
|
-
describe "
|
5
|
-
it "should
|
4
|
+
describe "#to_hash" do
|
5
|
+
it "should jsonify the stacktrace" do
|
6
6
|
backtrace = [
|
7
7
|
"/path/to/file1.rb:26:in `function1'",
|
8
8
|
"path/to/file2.rb:86:in `function2'"
|
9
9
|
]
|
10
|
-
|
11
10
|
exception_event = described_class.new(name: "RuntimeError", error_message: "Boom", backtrace: backtrace)
|
12
|
-
expect(exception_event.backtrace).to eq([{:file=>"/path/to/file1.rb", :line=>26, :function=>"function1"}, {:file=>"path/to/file2.rb", :line=>86, :function=>"function2"}])
|
13
|
-
end
|
14
|
-
|
15
|
-
it "parses valid lines" do
|
16
|
-
backtrace = [
|
17
|
-
"/path/to/file1.rb:26:in `function1'",
|
18
|
-
"path/to/file2.rb:86" # function names are optional
|
19
|
-
]
|
20
11
|
|
21
|
-
|
22
|
-
|
12
|
+
expected_hash = {
|
13
|
+
:name => "RuntimeError",
|
14
|
+
:message => "Boom",
|
15
|
+
:backtrace_json => "[\"/path/to/file1.rb:26:in `function1'\",\"path/to/file2.rb:86:in `function2'\"]"
|
16
|
+
}
|
17
|
+
expect(exception_event.to_hash).to eq(expected_hash)
|
23
18
|
end
|
24
|
-
|
25
|
-
it "handles malformed lines" do
|
26
|
-
backtrace = [
|
27
|
-
"malformed"
|
28
|
-
]
|
29
|
-
|
30
|
-
exception_event = described_class.new(name: "RuntimeError", error_message: "Boom", backtrace: backtrace)
|
31
|
-
expect(exception_event.backtrace).to eq([{:file=>"malformed"}])
|
32
|
-
end
|
33
19
|
end
|
34
20
|
end
|
@@ -26,7 +26,7 @@ describe Timber::Events::HTTPRequest, :rails_23 => true do
|
|
26
26
|
it "should handle header encoding" do
|
27
27
|
referer = 'http://www.metrojobb.se/jobb/1013893-skadeadministratör'.force_encoding('ASCII-8BIT')
|
28
28
|
event = described_class.new(:headers => {'Referer' => referer}, :host => 'my.host.com', :method => 'GET', :path => '/path', :scheme => 'https')
|
29
|
-
expect(event.headers
|
29
|
+
expect(event.headers["referer"].encoding).to eq(::Encoding::UTF_8)
|
30
30
|
end
|
31
31
|
end
|
32
32
|
end
|
data/spec/timber/events_spec.rb
CHANGED
@@ -18,7 +18,7 @@ describe Timber::Events, :rails_23 => true do
|
|
18
18
|
Timber::Events::Custom.new(
|
19
19
|
type: :payment_rejected,
|
20
20
|
message: "Payment rejected for #{customer_id}",
|
21
|
-
data: respond_to?(:
|
21
|
+
data: respond_to?(:to_h) ? to_h : hash
|
22
22
|
)
|
23
23
|
end
|
24
24
|
end
|
@@ -41,7 +41,7 @@ if defined?(::ActionDispatch)
|
|
41
41
|
lines = clean_lines(io.string.split("\n"))
|
42
42
|
expect(lines.length).to eq(3)
|
43
43
|
expect(lines[2]).to start_with('RuntimeError (boom) @metadata {"level":"fatal",')
|
44
|
-
expect(lines[2]).to include("\"event\":{\"error\":{\"name\":\"RuntimeError\",\"message\":\"boom\",\"
|
44
|
+
expect(lines[2]).to include("\"event\":{\"error\":{\"name\":\"RuntimeError\",\"message\":\"boom\",\"backtrace_json\":\"[")
|
45
45
|
end
|
46
46
|
|
47
47
|
# Remove blank lines since Rails does this to space out requests in the logs
|
@@ -3,45 +3,6 @@ require "spec_helper"
|
|
3
3
|
describe Timber::LogEntry, :rails_23 => true do
|
4
4
|
let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
|
5
5
|
|
6
|
-
describe "#as_json" do
|
7
|
-
it "should drop nil value keys" do
|
8
|
-
event = Timber::Events::Custom.new(type: :event_type, message: "event_message", data: {a: nil})
|
9
|
-
log_entry = described_class.new("INFO", time, nil, "log message", {}, event)
|
10
|
-
hash = log_entry.as_json
|
11
|
-
expect(hash.key?(:event)).to be false
|
12
|
-
end
|
13
|
-
|
14
|
-
it "should drop blank string value keys" do
|
15
|
-
event = Timber::Events::Custom.new(type: :event_type, message: "event_message", data: {a: ""})
|
16
|
-
log_entry = described_class.new("INFO", time, nil, "log message", {}, event)
|
17
|
-
hash = log_entry.as_json
|
18
|
-
expect(hash.key?(:event)).to be false
|
19
|
-
end
|
20
|
-
|
21
|
-
it "should drop empty array value keys" do
|
22
|
-
event = Timber::Events::Custom.new(type: :event_type, message: "event_message", data: {a: []})
|
23
|
-
log_entry = described_class.new("INFO", time, nil, "log message", {}, event)
|
24
|
-
hash = log_entry.as_json
|
25
|
-
expect(hash.key?(:event)).to be false
|
26
|
-
end
|
27
|
-
|
28
|
-
it "should drop ascii-8bit (binary) value keys" do
|
29
|
-
binary = ("a" * 1001).force_encoding("ASCII-8BIT")
|
30
|
-
event = Timber::Events::Custom.new(type: :event_type, message: "event_message", data: {a: binary})
|
31
|
-
log_entry = described_class.new("INFO", time, nil, "log message", {}, event)
|
32
|
-
hash = log_entry.as_json
|
33
|
-
expect(hash.key?(:event)).to be false
|
34
|
-
end
|
35
|
-
|
36
|
-
it "should keep ascii-8bit (binary) values below the threshold" do
|
37
|
-
binary = "test".force_encoding("ASCII-8BIT")
|
38
|
-
event = Timber::Events::Custom.new(type: :event_type, message: "event_message", data: {a: binary})
|
39
|
-
log_entry = described_class.new("INFO", time, nil, "log message", {}, event)
|
40
|
-
hash = log_entry.as_json
|
41
|
-
expect(hash[:event][:custom][:event_type][:a].encoding).to eq(::Encoding::UTF_8)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
6
|
describe "#to_msgpack" do
|
46
7
|
it "should encode properly with an event and context" do
|
47
8
|
event = Timber::Events::Custom.new(type: :event_type, message: "event_message", data: {a: 1})
|
data/spec/timber/logger_spec.rb
CHANGED
@@ -130,11 +130,6 @@ describe Timber::Logger, :rails_23 => true do
|
|
130
130
|
expect(io.string).to include("\"event\":{\"sql_query\":{\"sql\":\"select * from users\",\"time_ms\":56.0}}")
|
131
131
|
end
|
132
132
|
|
133
|
-
it "should allow :time_ms" do
|
134
|
-
logger.info("event complete", time_ms: 54.5)
|
135
|
-
expect(io.string).to include("\"time_ms\":54.5")
|
136
|
-
end
|
137
|
-
|
138
133
|
it "should allow :tag" do
|
139
134
|
logger.info("event complete", tag: "tag1")
|
140
135
|
expect(io.string).to include("\"tags\":[\"tag1\"]")
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Timber::Util::AttributeNormalizer, :rails_23 => true do
|
4
|
+
describe "#fetch" do
|
5
|
+
it "should return nil values" do
|
6
|
+
normalizer = described_class.new({:key => nil})
|
7
|
+
v = normalizer.fetch(:key, :string)
|
8
|
+
expect(v).to be_nil
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should nillify blank strings" do
|
12
|
+
normalizer = described_class.new({:key => ""})
|
13
|
+
v = normalizer.fetch(:key, :string)
|
14
|
+
expect(v).to be_nil
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should nillify empty arrays" do
|
18
|
+
normalizer = described_class.new({:key => []})
|
19
|
+
v = normalizer.fetch(:key, :string)
|
20
|
+
expect(v).to be_nil
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should nillify empty hashes" do
|
24
|
+
normalizer = described_class.new({:key => {}})
|
25
|
+
v = normalizer.fetch(:key, :string)
|
26
|
+
expect(v).to be_nil
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should raise an error for non arrays" do
|
30
|
+
normalizer = described_class.new({:key => "value"})
|
31
|
+
expect(lambda { normalizer.fetch(:key, :array) }).to raise_error(ArgumentError)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should return arrays" do
|
35
|
+
normalizer = described_class.new({:key => [1]})
|
36
|
+
v = normalizer.fetch(:key, :array)
|
37
|
+
expect(v).to eq([1])
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should return a float with the correct precision" do
|
41
|
+
normalizer = described_class.new({:key => 1.111111})
|
42
|
+
v = normalizer.fetch(:key, :float, :precision => 2)
|
43
|
+
expect(v).to eq(1.11)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should sanitize a hash" do
|
47
|
+
normalizer = described_class.new({:key => {:PASSWORD => "password"}})
|
48
|
+
v = normalizer.fetch(:key, :hash, :sanitize => ["password"])
|
49
|
+
expect(v).to eq({"password"=>"[sanitized]"})
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should normalize encodings" do
|
53
|
+
value = "test".force_encoding('ASCII-8BIT')
|
54
|
+
normalizer = described_class.new({:key => {:key => value}})
|
55
|
+
v = normalizer.fetch(:key, :hash)
|
56
|
+
expect(v[:key].encoding).to eq(::Encoding::UTF_8)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should drop large binaries" do
|
60
|
+
value = ("a" * 1_001).force_encoding('ASCII-8BIT')
|
61
|
+
normalizer = described_class.new({:key => {:key => value}})
|
62
|
+
v = normalizer.fetch(:key, :hash)
|
63
|
+
expect(v).to be_nil
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should return an integer" do
|
67
|
+
normalizer = described_class.new({:key => "1"})
|
68
|
+
v = normalizer.fetch(:key, :integer)
|
69
|
+
expect(v).to eq(1)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should limit a string" do
|
73
|
+
normalizer = described_class.new({:key => "aaa"})
|
74
|
+
v = normalizer.fetch(:key, :string, :limit => 1)
|
75
|
+
expect(v).to eq("a")
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should upcase a string" do
|
79
|
+
normalizer = described_class.new({:key => "aaa"})
|
80
|
+
v = normalizer.fetch(:key, :string, :upcase => true)
|
81
|
+
expect(v).to eq("AAA")
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should return a symbol" do
|
85
|
+
normalizer = described_class.new({:key => "sym"})
|
86
|
+
v = normalizer.fetch(:key, :symbol)
|
87
|
+
expect(v).to eq(:sym)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: timber
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.6.0.pre.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Timber Technologies, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-10-
|
11
|
+
date: 2017-10-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: msgpack
|
@@ -242,9 +242,9 @@ files:
|
|
242
242
|
- lib/timber/timer.rb
|
243
243
|
- lib/timber/util.rb
|
244
244
|
- lib/timber/util/active_support_log_subscriber.rb
|
245
|
+
- lib/timber/util/attribute_normalizer.rb
|
245
246
|
- lib/timber/util/hash.rb
|
246
|
-
- lib/timber/util/
|
247
|
-
- lib/timber/util/object.rb
|
247
|
+
- lib/timber/util/non_nil_hash_builder.rb
|
248
248
|
- lib/timber/util/request.rb
|
249
249
|
- lib/timber/util/struct.rb
|
250
250
|
- lib/timber/version.rb
|
@@ -291,7 +291,7 @@ files:
|
|
291
291
|
- spec/timber/log_devices/http_spec.rb
|
292
292
|
- spec/timber/log_entry_spec.rb
|
293
293
|
- spec/timber/logger_spec.rb
|
294
|
-
- spec/timber/util/
|
294
|
+
- spec/timber/util/attribute_normalizer_spec.rb
|
295
295
|
- spec/timber/util/request_spec.rb
|
296
296
|
- timber.gemspec
|
297
297
|
homepage: https://github.com/timberio/timber-ruby
|
@@ -308,9 +308,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
308
308
|
version: 1.9.0
|
309
309
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
310
310
|
requirements:
|
311
|
-
- - "
|
311
|
+
- - ">"
|
312
312
|
- !ruby/object:Gem::Version
|
313
|
-
version:
|
313
|
+
version: 1.3.1
|
314
314
|
requirements: []
|
315
315
|
rubyforge_project:
|
316
316
|
rubygems_version: 2.4.5.2
|
@@ -361,5 +361,5 @@ test_files:
|
|
361
361
|
- spec/timber/log_devices/http_spec.rb
|
362
362
|
- spec/timber/log_entry_spec.rb
|
363
363
|
- spec/timber/logger_spec.rb
|
364
|
-
- spec/timber/util/
|
364
|
+
- spec/timber/util/attribute_normalizer_spec.rb
|
365
365
|
- spec/timber/util/request_spec.rb
|
@@ -1,69 +0,0 @@
|
|
1
|
-
module Timber
|
2
|
-
module Util
|
3
|
-
# Utility module for dealing with HTTP events {Events::HTTPRequest} and {Events::HTTPResponse}.
|
4
|
-
module HTTPEvent
|
5
|
-
HEADERS_TO_SANITIZE = ['authorization', 'x-amz-security-token'].freeze
|
6
|
-
MAX_QUERY_STRING_BYTES = 2048.freeze
|
7
|
-
STRING_CLASS_NAME = 'String'.freeze
|
8
|
-
|
9
|
-
extend self
|
10
|
-
|
11
|
-
def full_path(path, query_string)
|
12
|
-
if query_string
|
13
|
-
"#{path}?#{query_string}"
|
14
|
-
else
|
15
|
-
path
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
# Normalizes the body. If limit if passed it will truncate the body to that limit.
|
20
|
-
def normalize_body(body)
|
21
|
-
if body.respond_to?(:body)
|
22
|
-
body = body.body.to_s
|
23
|
-
end
|
24
|
-
|
25
|
-
limit = Config.instance.http_body_limit
|
26
|
-
if limit
|
27
|
-
body.byteslice(0, limit)
|
28
|
-
else
|
29
|
-
body
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
# Normalizes headers to:
|
34
|
-
#
|
35
|
-
# 1. Only select values that are UTF8, otherwise they will throw errors when serializing.
|
36
|
-
# 2. Sanitize sensitive headers such as `Authorization` or custom headers specified in
|
37
|
-
def normalize_headers(headers)
|
38
|
-
if headers.is_a?(::Hash)
|
39
|
-
h = headers.each_with_object({}) do |(k, v), h|
|
40
|
-
if v
|
41
|
-
v = v.to_s
|
42
|
-
if [Encoding::UTF_8, Encoding::US_ASCII].include?(v.encoding)
|
43
|
-
h[k] = v
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
keys_to_sanitize = HEADERS_TO_SANITIZE + (Config.instance.http_header_filters || [])
|
49
|
-
Util::Hash.sanitize(h, keys_to_sanitize)
|
50
|
-
else
|
51
|
-
headers
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
# Normalizes the HTTP method into an uppercase string.
|
56
|
-
def normalize_method(method)
|
57
|
-
method.is_a?(::String) ? method.upcase : method
|
58
|
-
end
|
59
|
-
|
60
|
-
def normalize_query_string(query_string)
|
61
|
-
if !query_string.nil?
|
62
|
-
query_string = query_string.to_s
|
63
|
-
end
|
64
|
-
|
65
|
-
query_string && query_string.byteslice(0, MAX_QUERY_STRING_BYTES)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|