honeycomb-beeline 2.1.2 → 2.4.2
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 +4 -4
- data/.circleci/bundler_version.sh +4 -0
- data/.circleci/config.yml +102 -43
- data/.editorconfig +12 -0
- data/.github/dependabot.yml +13 -0
- data/.github/workflows/apply-labels.yml +16 -0
- data/.gitignore +1 -0
- data/.rspec +4 -0
- data/.rubocop.yml +6 -0
- data/CHANGELOG.md +104 -0
- data/Gemfile.lock +15 -5
- data/README.md +8 -0
- data/UPGRADING.md +10 -0
- data/honeycomb-beeline.gemspec +2 -0
- data/lib/honeycomb-beeline.rb +2 -1
- data/lib/honeycomb/beeline/version.rb +1 -1
- data/lib/honeycomb/client.rb +10 -0
- data/lib/honeycomb/configuration.rb +23 -0
- data/lib/honeycomb/integrations/faraday.rb +3 -1
- data/lib/honeycomb/integrations/rack.rb +17 -7
- data/lib/honeycomb/integrations/rails.rb +10 -0
- data/lib/honeycomb/integrations/redis.rb +103 -94
- data/lib/honeycomb/propagation.rb +4 -51
- data/lib/honeycomb/propagation/aws.rb +85 -0
- data/lib/honeycomb/propagation/context.rb +11 -0
- data/lib/honeycomb/propagation/honeycomb.rb +96 -0
- data/lib/honeycomb/propagation/w3c.rb +79 -0
- data/lib/honeycomb/span.rb +32 -4
- data/lib/honeycomb/trace.rb +14 -1
- metadata +39 -3
data/README.md
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
[](https://circleci.com/gh/honeycombio/beeline-ruby)
|
4
4
|
[](https://badge.fury.io/rb/honeycomb-beeline)
|
5
|
+
[](https://codecov.io/gh/honeycombio/beeline-ruby)
|
5
6
|
|
6
7
|
This package makes it easy to instrument your Ruby web app to send useful events to [Honeycomb](https://www.honeycomb.io), a service for debugging your software in production.
|
7
8
|
- [Usage and Examples](https://docs.honeycomb.io/getting-data-in/beelines/ruby-beeline/)
|
@@ -24,6 +25,13 @@ Built in instrumentation for:
|
|
24
25
|
- Sequel
|
25
26
|
- Sinatra
|
26
27
|
|
28
|
+
## Testing
|
29
|
+
Find `rspec` test files in the `spec` directory.
|
30
|
+
|
31
|
+
To run tests on gem-specific instrumentations or across various dependency versions, use [appraisal](https://github.com/thoughtbot/appraisal) (further instructions in the readme for that gem). Find gem sets in the `Appraisals` config.
|
32
|
+
|
33
|
+
To run a specific file: `bundle exec appraisal <gem set> rspec <path/to/file>`
|
34
|
+
|
27
35
|
## Get in touch
|
28
36
|
|
29
37
|
Please reach out to [support@honeycomb.io](mailto:support@honeycomb.io) or ping
|
data/UPGRADING.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# Upgrade Guide
|
2
2
|
|
3
|
+
## 1.0.0 - 2.0.0
|
4
|
+
|
5
|
+
1. See release notes: https://github.com/honeycombio/beeline-ruby/releases/tag/v2.0.0
|
6
|
+
1. This update requires no code changes, but you must be aware of certain instrumentation changes. New fields will be added to your dataset and other fields will be removed.
|
7
|
+
1. ActionController::Parameters will now result in extra fields, or nested json, depending on your unfurl settings.
|
8
|
+
1. aws.params are now exploded into separate fields.
|
9
|
+
1. request.error becomes error.
|
10
|
+
1. request.error_detail becomes error_detail
|
11
|
+
1. request.protocol becomes request.scheme
|
12
|
+
|
3
13
|
## 0.8.0 - 1.0.0
|
4
14
|
|
5
15
|
1. If you have a web application, remove beeline configuration from the `config.ru` file
|
data/honeycomb-beeline.gemspec
CHANGED
@@ -42,11 +42,13 @@ Gem::Specification.new do |spec|
|
|
42
42
|
spec.add_development_dependency "appraisal"
|
43
43
|
spec.add_development_dependency "bump"
|
44
44
|
spec.add_development_dependency "bundler"
|
45
|
+
spec.add_development_dependency "codecov"
|
45
46
|
spec.add_development_dependency "overcommit", "~> 0.46.0"
|
46
47
|
spec.add_development_dependency "pry", "< 0.13.0"
|
47
48
|
spec.add_development_dependency "pry-byebug", "~> 3.6.0"
|
48
49
|
spec.add_development_dependency "rake"
|
49
50
|
spec.add_development_dependency "rspec", "~> 3.0"
|
51
|
+
spec.add_development_dependency "rspec_junit_formatter"
|
50
52
|
spec.add_development_dependency "rubocop", "< 0.69"
|
51
53
|
spec.add_development_dependency "rubocop-performance", "< 1.3.0"
|
52
54
|
spec.add_development_dependency "simplecov"
|
data/lib/honeycomb-beeline.rb
CHANGED
@@ -26,7 +26,8 @@ module Honeycomb
|
|
26
26
|
attr_reader :client
|
27
27
|
|
28
28
|
def_delegators :@client, :libhoney, :start_span, :add_field,
|
29
|
-
:add_field_to_trace, :current_span, :current_trace
|
29
|
+
:add_field_to_trace, :current_span, :current_trace,
|
30
|
+
:with_field, :with_trace_field
|
30
31
|
|
31
32
|
def configure
|
32
33
|
Configuration.new.tap do |config|
|
data/lib/honeycomb/client.rb
CHANGED
@@ -35,6 +35,8 @@ module Honeycomb
|
|
35
35
|
@additional_trace_options = {
|
36
36
|
presend_hook: configuration.presend_hook,
|
37
37
|
sample_hook: configuration.sample_hook,
|
38
|
+
parser_hook: configuration.http_trace_parser_hook,
|
39
|
+
propagation_hook: configuration.http_trace_propagation_hook,
|
38
40
|
}
|
39
41
|
|
40
42
|
configuration.after_initialize(self)
|
@@ -87,6 +89,14 @@ module Honeycomb
|
|
87
89
|
context.current_span.trace.add_field("app.#{key}", value)
|
88
90
|
end
|
89
91
|
|
92
|
+
def with_field(key)
|
93
|
+
yield.tap { |value| add_field(key, value) }
|
94
|
+
end
|
95
|
+
|
96
|
+
def with_trace_field(key)
|
97
|
+
yield.tap { |value| add_field_to_trace(key, value) }
|
98
|
+
end
|
99
|
+
|
90
100
|
private
|
91
101
|
|
92
102
|
attr_reader :context
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "socket"
|
4
|
+
require "honeycomb/propagation/honeycomb"
|
4
5
|
|
5
6
|
module Honeycomb
|
6
7
|
# Used to configure the Honeycomb client
|
@@ -60,5 +61,27 @@ module Honeycomb
|
|
60
61
|
@sample_hook
|
61
62
|
end
|
62
63
|
end
|
64
|
+
|
65
|
+
def http_trace_parser_hook(&hook)
|
66
|
+
if block_given?
|
67
|
+
@http_trace_parser_hook = hook
|
68
|
+
elsif @http_trace_parser_hook
|
69
|
+
@http_trace_parser_hook
|
70
|
+
else
|
71
|
+
# by default we try to parse incoming honeycomb traces
|
72
|
+
HoneycombPropagation::UnmarshalTraceContext.method(:parse_rack_env)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def http_trace_propagation_hook(&hook)
|
77
|
+
if block_given?
|
78
|
+
@http_trace_propagation_hook = hook
|
79
|
+
elsif @http_trace_propagation_hook
|
80
|
+
@http_trace_propagation_hook
|
81
|
+
else
|
82
|
+
# by default we send outgoing honeycomb trace headers
|
83
|
+
HoneycombPropagation::MarshalTraceContext.method(:parse_faraday_env)
|
84
|
+
end
|
85
|
+
end
|
63
86
|
end
|
64
87
|
end
|
@@ -22,7 +22,9 @@ module Honeycomb
|
|
22
22
|
span.add_field "meta.package", "faraday"
|
23
23
|
span.add_field "meta.package_version", ::Faraday::VERSION
|
24
24
|
|
25
|
-
|
25
|
+
if (headers = span.trace_headers(env)).is_a?(Hash)
|
26
|
+
env.request_headers.merge!(headers)
|
27
|
+
end
|
26
28
|
|
27
29
|
@app.call(env).tap do |response|
|
28
30
|
span.add_field "response.status_code", response.status
|
@@ -17,6 +17,7 @@ module Honeycomb
|
|
17
17
|
["HTTP_X_FORWARDED_PROTO", "request.header.x_forwarded_proto"],
|
18
18
|
["HTTP_X_FORWARDED_PORT", "request.header.x_forwarded_port"],
|
19
19
|
["HTTP_ACCEPT", "request.header.accept"],
|
20
|
+
["HTTP_ACCEPT_ENCODING", "request.header.accept_encoding"],
|
20
21
|
["HTTP_ACCEPT_LANGUAGE", "request.header.accept_language"],
|
21
22
|
["CONTENT_TYPE", "request.header.content_type"],
|
22
23
|
["HTTP_USER_AGENT", "request.header.user_agent"],
|
@@ -32,8 +33,10 @@ module Honeycomb
|
|
32
33
|
|
33
34
|
def call(env)
|
34
35
|
req = ::Rack::Request.new(env)
|
35
|
-
|
36
|
-
|
36
|
+
client.start_span(
|
37
|
+
name: "http_request",
|
38
|
+
serialized_trace: env,
|
39
|
+
) do |span|
|
37
40
|
add_field = lambda do |key, value|
|
38
41
|
unless value.nil? || (value.respond_to?(:empty?) && value.empty?)
|
39
42
|
span.add_field(key, value)
|
@@ -45,11 +48,12 @@ module Honeycomb
|
|
45
48
|
span.add_field("request.secure", req.ssl?)
|
46
49
|
span.add_field("request.xhr", req.xhr?)
|
47
50
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
51
|
+
begin
|
52
|
+
status, headers, body = call_with_hook(env, span, &add_field)
|
53
|
+
ensure
|
54
|
+
add_package_information(env, &add_field)
|
55
|
+
extract_user_information(env, &add_field)
|
56
|
+
end
|
53
57
|
|
54
58
|
span.add_field("response.status_code", status)
|
55
59
|
span.add_field("response.content_type", headers["Content-Type"])
|
@@ -69,6 +73,12 @@ module Honeycomb
|
|
69
73
|
end
|
70
74
|
end
|
71
75
|
|
76
|
+
private
|
77
|
+
|
78
|
+
def call_with_hook(env, _span, &_add_field)
|
79
|
+
app.call(env)
|
80
|
+
end
|
81
|
+
|
72
82
|
# Rack middleware
|
73
83
|
class Middleware
|
74
84
|
include Rack
|
@@ -89,6 +89,16 @@ module Honeycomb
|
|
89
89
|
include Rack
|
90
90
|
include Warden
|
91
91
|
include Rails
|
92
|
+
|
93
|
+
def call_with_hook(env, span, &_add_field)
|
94
|
+
super
|
95
|
+
rescue StandardError => e
|
96
|
+
wrapped = ActionDispatch::ExceptionWrapper.new(nil, e)
|
97
|
+
|
98
|
+
span.add_field "response.status_code", wrapped.status_code
|
99
|
+
|
100
|
+
raise e
|
101
|
+
end
|
92
102
|
end
|
93
103
|
end
|
94
104
|
end
|
@@ -159,7 +159,17 @@ module Honeycomb
|
|
159
159
|
# * :logger - just some Ruby object, not useful
|
160
160
|
# * :_parsed - implementation detail
|
161
161
|
def ignore?(option)
|
162
|
-
|
162
|
+
# Redis options may be symbol or string keys.
|
163
|
+
#
|
164
|
+
# This normalizes `option` using `to_sym` as benchmarking on Ruby MRI
|
165
|
+
# v2.6.6 and v2.7.3 has shown that was faster compared to `to_s`.
|
166
|
+
# However, `nil` does not support `to_sym`. This uses a guard clause to
|
167
|
+
# handle the `nil` case because this is still faster than safe
|
168
|
+
# navigation. Also this lib still supports Ruby 2.2.0; which does not
|
169
|
+
# include safe navigation.
|
170
|
+
return true unless option
|
171
|
+
|
172
|
+
%i[url password logger _parsed].include?(option.to_sym)
|
163
173
|
end
|
164
174
|
|
165
175
|
def format(cmd)
|
@@ -177,16 +187,6 @@ module Honeycomb
|
|
177
187
|
args.map! { "[sanitized]" }
|
178
188
|
end
|
179
189
|
|
180
|
-
def prettify(arg)
|
181
|
-
quotes = false
|
182
|
-
pretty = "".dup
|
183
|
-
arg.to_s.each_char do |c|
|
184
|
-
quotes ||= needs_quotes?(c)
|
185
|
-
pretty << escape(c)
|
186
|
-
end
|
187
|
-
quotes ? "\"#{pretty}\"" : pretty
|
188
|
-
end
|
189
|
-
|
190
190
|
# This aims to replicate the algorithms used by redis-cli.
|
191
191
|
#
|
192
192
|
# @see https://github.com/antirez/redis/blob/0f026af185e918a9773148f6ceaa1b084662be88/src/sds.c#L940-L1067
|
@@ -194,54 +194,15 @@ module Honeycomb
|
|
194
194
|
#
|
195
195
|
# @see https://github.com/antirez/redis/blob/0f026af185e918a9773148f6ceaa1b084662be88/src/sds.c#L878-L907
|
196
196
|
# The redis-cli printing algorithm
|
197
|
-
def
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
# A lookup table for backslash-escaped characters.
|
205
|
-
#
|
206
|
-
# This is used by {#escape_with_backslash?} and {#escape_with_backslash}
|
207
|
-
# to replicate the hard-coded `case` statements in redis-cli. As of this
|
208
|
-
# writing, Redis recognizes a handful of standard C escape sequences,
|
209
|
-
# like "\n" for newlines.
|
210
|
-
#
|
211
|
-
# Because {#prettify} will output double quoted strings if any escaping
|
212
|
-
# is needed, this table must additionally consider the double-quote to be
|
213
|
-
# a backslash-escaped character. For example, instead of generating
|
214
|
-
#
|
215
|
-
# '"hello"'
|
216
|
-
#
|
217
|
-
# we'll generate
|
218
|
-
#
|
219
|
-
# "\"hello\""
|
220
|
-
#
|
221
|
-
# even though redis-cli would technically recognize the single-quoted
|
222
|
-
# version.
|
223
|
-
#
|
224
|
-
# @see https://github.com/antirez/redis/blob/0f026af185e918a9773148f6ceaa1b084662be88/src/sds.c#L888-L896
|
225
|
-
# The redis-cli algorithm for outputting standard escape sequences
|
226
|
-
BACKSLASHES = {
|
227
|
-
"\\" => "\\\\",
|
228
|
-
'"' => '\\"',
|
229
|
-
"\n" => "\\n",
|
230
|
-
"\r" => "\\r",
|
231
|
-
"\t" => "\\t",
|
232
|
-
"\a" => "\\a",
|
233
|
-
"\b" => "\\b",
|
234
|
-
}.freeze
|
235
|
-
|
236
|
-
def escape_with_backslash?(char)
|
237
|
-
BACKSLASHES.key?(char)
|
238
|
-
end
|
239
|
-
|
240
|
-
def escape_with_backslash(char)
|
241
|
-
BACKSLASHES.fetch(char, char)
|
197
|
+
def prettify(arg)
|
198
|
+
pretty = arg.to_s.dup
|
199
|
+
pretty.encode!("UTF-8", "binary", fallback: ->(c) { hex(c) })
|
200
|
+
pretty.gsub!(NEEDS_BACKSLASH, BACKSLASH)
|
201
|
+
pretty.gsub!(NEEDS_HEX) { |c| hex(c) }
|
202
|
+
pretty =~ NEEDS_QUOTES ? "\"#{pretty}\"" : pretty
|
242
203
|
end
|
243
204
|
|
244
|
-
#
|
205
|
+
# A regular expression matching characters that need to be hex-encoded.
|
245
206
|
#
|
246
207
|
# This replicates the C isprint() function that redis-cli uses to decide
|
247
208
|
# whether to escape a character in hexadecimal notation, "\xhh". Any
|
@@ -277,18 +238,95 @@ module Honeycomb
|
|
277
238
|
# escape it.
|
278
239
|
#
|
279
240
|
# What's more, Ruby's Regexp#=~ method will blow up if the string does
|
280
|
-
# not have a valid encoding (e.g., in UTF-8).
|
281
|
-
#
|
282
|
-
# invalid
|
283
|
-
# invalidly-encoded characters before testing the above match.
|
241
|
+
# not have a valid encoding (e.g., in UTF-8). We handle this case
|
242
|
+
# separately, though, using String#encode! with a :fallback option to
|
243
|
+
# hex-encode invalid UTF-8 byte sequences with {#hex}.
|
284
244
|
#
|
285
245
|
# @see https://ruby-doc.org/core-2.6.5/Regexp.html
|
286
246
|
# @see https://github.com/antirez/redis/blob/0f026af185e918a9773148f6ceaa1b084662be88/src/sds.c#L878-L880
|
287
247
|
# @see https://github.com/antirez/redis/blob/0f026af185e918a9773148f6ceaa1b084662be88/src/sds.c#L898-L901
|
288
248
|
# @see https://www.justinweiss.com/articles/3-steps-to-fix-encoding-problems-in-ruby/
|
289
|
-
|
290
|
-
|
291
|
-
|
249
|
+
NEEDS_HEX = /[^[:print:]&&[:ascii:]]/.freeze
|
250
|
+
|
251
|
+
# A regular expression for characters that need to be backslash-escaped.
|
252
|
+
#
|
253
|
+
# Any match of this regexp will be substituted according to the
|
254
|
+
# {BACKSLASH} table. This includes standard C escape sequences (newlines,
|
255
|
+
# tabs, etc) as well as a couple special considerations:
|
256
|
+
#
|
257
|
+
# 1. Because {#prettify} will output double quoted strings if any
|
258
|
+
# escaping is needed, we must match double quotes (") so they'll be
|
259
|
+
# replaced by escaped quotes (\").
|
260
|
+
#
|
261
|
+
# 2. Backslashes themselves get backslash-escaped, so \ becomes \\.
|
262
|
+
# However, strings with invalid UTF-8 encoding will blow up when we
|
263
|
+
# try to use String#gsub!, so {#prettify} must first use
|
264
|
+
# String#encode! to scrub out invalid characters. It does this by
|
265
|
+
# replacing invalid bytes with hex-encoded escape sequences using
|
266
|
+
# {#hex}. This will insert sequences like \xhh, which contains a
|
267
|
+
# backslash that we *don't* want to escape.
|
268
|
+
#
|
269
|
+
# Unfortunately, this regexp can't really distinguish between
|
270
|
+
# backslashes in the original input vs backslashes resulting from the
|
271
|
+
# UTF-8 fallback. We make an effort by using a negative lookahead.
|
272
|
+
# That way, only backslashes that *aren't* followed by x + hex digit +
|
273
|
+
# hex digit will be escaped.
|
274
|
+
NEEDS_BACKSLASH = /["\n\r\t\a\b]|\\(?!x\h\h)/.freeze
|
275
|
+
|
276
|
+
# A lookup table for backslash-escaped characters.
|
277
|
+
#
|
278
|
+
# This is used by {#prettify} to replicate the hard-coded `case`
|
279
|
+
# statements in redis-cli. As of this writing, Redis recognizes a handful
|
280
|
+
# of standard C escape sequences, like "\n" for newlines.
|
281
|
+
#
|
282
|
+
# Because {#prettify} will output double quoted strings if any escaping
|
283
|
+
# is needed, this table must additionally consider the double-quote to be
|
284
|
+
# a backslash-escaped character. For example, instead of generating
|
285
|
+
#
|
286
|
+
# '"hello"'
|
287
|
+
#
|
288
|
+
# we'll generate
|
289
|
+
#
|
290
|
+
# "\"hello\""
|
291
|
+
#
|
292
|
+
# even though redis-cli would technically recognize the single-quoted
|
293
|
+
# version.
|
294
|
+
#
|
295
|
+
# @see https://github.com/antirez/redis/blob/0f026af185e918a9773148f6ceaa1b084662be88/src/sds.c#L888-L896
|
296
|
+
# The redis-cli algorithm for outputting standard escape sequences
|
297
|
+
BACKSLASH = {
|
298
|
+
"\\" => "\\\\",
|
299
|
+
'"' => '\\"',
|
300
|
+
"\n" => "\\n",
|
301
|
+
"\r" => "\\r",
|
302
|
+
"\t" => "\\t",
|
303
|
+
"\a" => "\\a",
|
304
|
+
"\b" => "\\b",
|
305
|
+
}.freeze
|
306
|
+
|
307
|
+
# If the final escaped string needs quotes, it will match this regexp.
|
308
|
+
#
|
309
|
+
# The overall string returned by {#prettify} should only be quoted if at
|
310
|
+
# least one of the following holds:
|
311
|
+
#
|
312
|
+
# 1. The string contains an escape sequence, broadly demarcated by a
|
313
|
+
# backslash. This includes standard escape sequences like "\n" and
|
314
|
+
# "\t" as well as hex-encoded bytes using the "\x" escape sequence.
|
315
|
+
# Since {#prettify} uses double quotes on its output string, we must
|
316
|
+
# also force quotes if the string itself contains a literal
|
317
|
+
# double quote. This double quote behavior is handled tacitly by the
|
318
|
+
# {NEEDS_BACKSLASH} + {BACKSLASH} replacement.
|
319
|
+
#
|
320
|
+
# 2. The string contains a single quote. Since redis-cli recognizes
|
321
|
+
# single-quoted strings, we want to wrap the {#prettify} output in
|
322
|
+
# double quotes so that the literal single quote character isn't
|
323
|
+
# mistaken as the delimiter of a new string.
|
324
|
+
#
|
325
|
+
# 3. The string contains any whitespace characters. If the {#prettify}
|
326
|
+
# output weren't wrapped in quotes, whitespace would act as a
|
327
|
+
# separator between arguments to the Redis command. To group things
|
328
|
+
# together, we need to quote the string.
|
329
|
+
NEEDS_QUOTES = /[\\'\s]/.freeze
|
292
330
|
|
293
331
|
# Hex-encodes a (presumably non-printable or non-ASCII) character.
|
294
332
|
#
|
@@ -316,38 +354,9 @@ module Honeycomb
|
|
316
354
|
# @see https://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap07.html
|
317
355
|
# @see https://github.com/antirez/redis/blob/0f026af185e918a9773148f6ceaa1b084662be88/src/sds.c#L878-L880
|
318
356
|
# @see https://github.com/antirez/redis/blob/0f026af185e918a9773148f6ceaa1b084662be88/src/sds.c#L898-L901
|
319
|
-
def
|
357
|
+
def hex(char)
|
320
358
|
char.bytes.map { |b| Kernel.format("\\x%02x", b) }.join
|
321
359
|
end
|
322
|
-
|
323
|
-
def escape?(char)
|
324
|
-
escape_with_backslash?(char) || escape_with_hex_codes?(char)
|
325
|
-
end
|
326
|
-
|
327
|
-
# Should this character cause {#prettify} to wrap its output in quotes?
|
328
|
-
#
|
329
|
-
# The overall string returned by {#prettify} should only be quoted if at
|
330
|
-
# least one of the following holds:
|
331
|
-
#
|
332
|
-
# 1. The string contains a character that needs to be escaped. This
|
333
|
-
# includes standard backslash escape sequences (like "\n" and "\t") as
|
334
|
-
# well as hex-encoded bytes using the "\x" escape sequence. Since
|
335
|
-
# {#prettify} uses double quotes on its output string, we must also
|
336
|
-
# force quotes if the string itself contains a literal double quote.
|
337
|
-
# This double quote behavior is handled tacitly by {BACKSLASHES}.
|
338
|
-
#
|
339
|
-
# 2. The string contains a single quote. Since redis-cli recognizes
|
340
|
-
# single-quoted strings, we want to wrap the {#prettify} output in
|
341
|
-
# double quotes so that the literal single quote character isn't
|
342
|
-
# mistaken as the delimiter of a new string.
|
343
|
-
#
|
344
|
-
# 3. The string contains any whitespace characters. If the {#prettify}
|
345
|
-
# output weren't wrapped in quotes, whitespace would act as a
|
346
|
-
# separator between arguments to the Redis command. To group things
|
347
|
-
# together, we need to quote the string.
|
348
|
-
def needs_quotes?(char)
|
349
|
-
escape?(char) || char == "'" || char =~ /\s/
|
350
|
-
end
|
351
360
|
end
|
352
361
|
end
|
353
362
|
end
|