honeycomb-beeline 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +72 -0
- data/Appraisals +8 -0
- data/Gemfile.lock +2 -2
- data/README.md +1 -0
- data/lib/honeycomb-beeline.rb +1 -0
- data/lib/honeycomb/beeline/version.rb +1 -1
- data/lib/honeycomb/integrations/redis.rb +354 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ddd03586fceabfcdb1d51f914e4a61cae2c87bbe295341036969a9fca40b3484
|
4
|
+
data.tar.gz: cc72f4183017b81d07ee227a4a5aa48c7e933b24f551b61328575fe5d3cb880b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 93c1a6e138fb39c9a83591c3c10b7427ff28b4f397c2844f631e22d241976e4d3d4f26bb63bdf2380fb35bfe2ae016ff3e659611808608ffeba36c7e10dd6f6c
|
7
|
+
data.tar.gz: ba29c324e453cb42180134008cd8586dba0c1b34ad71a3efc2b4a9165ad380a116d2fd533a9c06cdd7ea2e2fc033a9cf09b9d98f8e68a6ebd242631dba1c4c61
|
data/.circleci/config.yml
CHANGED
@@ -97,6 +97,14 @@ gemfiles:
|
|
97
97
|
steps:
|
98
98
|
- ruby:
|
99
99
|
gemfile: gemfiles/rails_6.gemfile
|
100
|
+
redis-three: &redis-three
|
101
|
+
steps:
|
102
|
+
- ruby:
|
103
|
+
gemfile: gemfiles/redis_3.gemfile
|
104
|
+
redis-four: &redis-four
|
105
|
+
steps:
|
106
|
+
- ruby:
|
107
|
+
gemfile: gemfiles/redis_4.gemfile
|
100
108
|
|
101
109
|
jobs:
|
102
110
|
publish:
|
@@ -269,6 +277,30 @@ jobs:
|
|
269
277
|
rails-six-ruby-two-six:
|
270
278
|
<<: *rails-six
|
271
279
|
executor: ruby-two-six
|
280
|
+
redis-three-ruby-two-three:
|
281
|
+
<<: *redis-three
|
282
|
+
executor: ruby-two-three
|
283
|
+
redis-three-ruby-two-four:
|
284
|
+
<<: *redis-three
|
285
|
+
executor: ruby-two-four
|
286
|
+
redis-three-ruby-two-five:
|
287
|
+
<<: *redis-three
|
288
|
+
executor: ruby-two-five
|
289
|
+
redis-three-ruby-two-six:
|
290
|
+
<<: *redis-three
|
291
|
+
executor: ruby-two-six
|
292
|
+
redis-four-ruby-two-three:
|
293
|
+
<<: *redis-four
|
294
|
+
executor: ruby-two-three
|
295
|
+
redis-four-ruby-two-four:
|
296
|
+
<<: *redis-four
|
297
|
+
executor: ruby-two-four
|
298
|
+
redis-four-ruby-two-five:
|
299
|
+
<<: *redis-four
|
300
|
+
executor: ruby-two-five
|
301
|
+
redis-four-ruby-two-six:
|
302
|
+
<<: *redis-four
|
303
|
+
executor: ruby-two-six
|
272
304
|
|
273
305
|
workflows:
|
274
306
|
version: 2
|
@@ -463,6 +495,38 @@ workflows:
|
|
463
495
|
<<: *tag_filters
|
464
496
|
requires:
|
465
497
|
- lint
|
498
|
+
- redis-three-ruby-two-three:
|
499
|
+
<<: *tag_filters
|
500
|
+
requires:
|
501
|
+
- lint
|
502
|
+
- redis-three-ruby-two-four:
|
503
|
+
<<: *tag_filters
|
504
|
+
requires:
|
505
|
+
- lint
|
506
|
+
- redis-three-ruby-two-five:
|
507
|
+
<<: *tag_filters
|
508
|
+
requires:
|
509
|
+
- lint
|
510
|
+
- redis-three-ruby-two-six:
|
511
|
+
<<: *tag_filters
|
512
|
+
requires:
|
513
|
+
- lint
|
514
|
+
- redis-four-ruby-two-three:
|
515
|
+
<<: *tag_filters
|
516
|
+
requires:
|
517
|
+
- lint
|
518
|
+
- redis-four-ruby-two-four:
|
519
|
+
<<: *tag_filters
|
520
|
+
requires:
|
521
|
+
- lint
|
522
|
+
- redis-four-ruby-two-five:
|
523
|
+
<<: *tag_filters
|
524
|
+
requires:
|
525
|
+
- lint
|
526
|
+
- redis-four-ruby-two-six:
|
527
|
+
<<: *tag_filters
|
528
|
+
requires:
|
529
|
+
- lint
|
466
530
|
- publish:
|
467
531
|
filters:
|
468
532
|
tags:
|
@@ -518,3 +582,11 @@ workflows:
|
|
518
582
|
- rails-five-two-ruby-two-six
|
519
583
|
- rails-six-ruby-two-five
|
520
584
|
- rails-six-ruby-two-six
|
585
|
+
- redis-three-ruby-two-three
|
586
|
+
- redis-three-ruby-two-four
|
587
|
+
- redis-three-ruby-two-five
|
588
|
+
- redis-three-ruby-two-six
|
589
|
+
- redis-four-ruby-two-three
|
590
|
+
- redis-four-ruby-two-four
|
591
|
+
- redis-four-ruby-two-five
|
592
|
+
- redis-four-ruby-two-six
|
data/Appraisals
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
honeycomb-beeline (1.
|
4
|
+
honeycomb-beeline (1.3.0)
|
5
5
|
libhoney (~> 1.8)
|
6
6
|
|
7
7
|
GEM
|
@@ -44,7 +44,7 @@ GEM
|
|
44
44
|
iniparse (1.4.4)
|
45
45
|
jaro_winkler (1.5.3)
|
46
46
|
json (2.2.0)
|
47
|
-
libhoney (1.14.
|
47
|
+
libhoney (1.14.1)
|
48
48
|
addressable (~> 2.0)
|
49
49
|
http (>= 2.0, < 5.0)
|
50
50
|
method_source (0.9.2)
|
data/README.md
CHANGED
data/lib/honeycomb-beeline.rb
CHANGED
@@ -0,0 +1,354 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "redis"
|
4
|
+
|
5
|
+
module Honeycomb
|
6
|
+
module Redis
|
7
|
+
# Patches Redis with the option to configure the Honeycomb client.
|
8
|
+
#
|
9
|
+
# When you load this integration, each Redis call will be wrapped in a span
|
10
|
+
# containing information about the command being invoked.
|
11
|
+
#
|
12
|
+
# This module automatically gets mixed into the Redis class so you can
|
13
|
+
# change the underlying {Honeycomb::Client}. By default, we use the global
|
14
|
+
# {Honeycomb.client} to send events. A nil client will disable the
|
15
|
+
# integration altogether.
|
16
|
+
#
|
17
|
+
# @example Custom client
|
18
|
+
# Redis.honeycomb_client = Honeycomb::Client.new(...)
|
19
|
+
#
|
20
|
+
# @example Disabling instrumentation
|
21
|
+
# Redis.honeycomb_client = nil
|
22
|
+
module Configuration
|
23
|
+
attr_writer :honeycomb_client
|
24
|
+
|
25
|
+
def honeycomb_client
|
26
|
+
@honeycomb_client || Honeycomb.client
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Patches Redis::Client with Honeycomb instrumentation.
|
31
|
+
#
|
32
|
+
# Circa versions 3.x and 4.x of their gem, the Redis class is backed by an
|
33
|
+
# underlying Redis::Client object. The methods used to send commands to the
|
34
|
+
# Redis server - namely Redis::Client#call, Redis::Client#call_loop,
|
35
|
+
# Redis::Client#call_pipeline, Redis::Client#call_pipelined,
|
36
|
+
# Redis::Client#call_with_timeout, and Redis::Client#call_without_timeout -
|
37
|
+
# all eventually wind up calling the Redis::Client#process method to do the
|
38
|
+
# "dirty work" of writing commands out to an underlying connection. So this
|
39
|
+
# gives us a single point of entry that's ideal for introducing the
|
40
|
+
# Honeycomb span.
|
41
|
+
#
|
42
|
+
# An alternative interface provided since at least version 3.0.0 is
|
43
|
+
# Redis::Distributed. Underneath, though, it maintains a collection of
|
44
|
+
# Redis objects, and each call is forwarded to one or more members of the
|
45
|
+
# collection. So patching Redis::Client still captures spans originating
|
46
|
+
# from Redis::Distributed. Typical commands (i.e., ones that aren't
|
47
|
+
# "global" like `QUIT` or `FLUSHALL`) forward to just a single node anyway,
|
48
|
+
# so there's not much use to wrapping everything up in a span for the
|
49
|
+
# Redis::Distributed method call.
|
50
|
+
#
|
51
|
+
# Another alternative interface provided since v4.0.3 is Redis::Cluster,
|
52
|
+
# which you can configure the Redis class to use instead of Redis::Client.
|
53
|
+
# Again, though, Redis::Cluster maintains a collection of Redis::Client
|
54
|
+
# instances underneath. The tracing needs wind up being pretty much the
|
55
|
+
# same as Redis::Distributed, even though the actual architecture is
|
56
|
+
# significantly different.
|
57
|
+
#
|
58
|
+
# An implementation detail of pub/sub commands since v2.0.0 (well below our
|
59
|
+
# supported version of the redis gem!) is Redis::SubscribedClient, but that
|
60
|
+
# still wraps an underlying Redis::Client or Redis::Cluster instance.
|
61
|
+
#
|
62
|
+
# @see https://github.com/redis/redis-rb/blob/2e8577ad71d0efc32f31fb034f341e1eb10abc18/lib/redis/client.rb#L77-L180
|
63
|
+
# Relevant Redis::Client methods circa v3.0.0
|
64
|
+
# @see https://github.com/redis/redis-rb/blob/a2c562c002bc8f86d1f47818d63db2da1c5c3d3f/lib/redis/client.rb#L124-L239
|
65
|
+
# Relevant Redis::Client methods circa v4.1.3
|
66
|
+
# @see https://github.com/redis/redis-rb/commits/master/lib/redis/client.rb
|
67
|
+
# History of Redis::Client
|
68
|
+
#
|
69
|
+
# @see https://redis.io/topics/partitioning
|
70
|
+
# Partitioning (the basis for Redis::Distributed)
|
71
|
+
# @see https://github.com/redis/redis-rb/blob/2e8577ad71d0efc32f31fb034f341e1eb10abc18/lib/redis/distributed.rb
|
72
|
+
# Redis::Distributed circa v3.0.0
|
73
|
+
# @see https://github.com/redis/redis-rb/blob/a2c562c002bc8f86d1f47818d63db2da1c5c3d3f/lib/redis/distributed.rb
|
74
|
+
# Redis::Distributed circa v4.1.3
|
75
|
+
# @see https://github.com/redis/redis-rb/commits/master/lib/redis/distributed.rb
|
76
|
+
# History of Redis::Distributed
|
77
|
+
#
|
78
|
+
# @see https://redis.io/topics/cluster-spec
|
79
|
+
# Clustering (the basis for Redis::Cluster)
|
80
|
+
# @see https://github.com/redis/redis-rb/commit/7f48c0b02fa89256167bc481a73ce2e0c8cca89a
|
81
|
+
# Initial implementation of Redis::Cluster released in v4.0.3
|
82
|
+
# @see https://github.com/redis/redis-rb/blob/a2c562c002bc8f86d1f47818d63db2da1c5c3d3f/lib/redis/cluster.rb
|
83
|
+
# Redis::Cluster circa v4.1.3
|
84
|
+
# @see https://github.com/redis/redis-rb/commits/master/lib/redis/cluster.rb
|
85
|
+
# History of Redis::Cluster
|
86
|
+
#
|
87
|
+
# @see https://redis.io/topics/pubsub
|
88
|
+
# Pub/Sub in Redis
|
89
|
+
# @see https://github.com/redis/redis-rb/blob/17d40d80388b536ec53a8f19bb1404e93a61650f/lib/redis/subscribe.rb
|
90
|
+
# Redis::SubscribedClient circa v2.0.0
|
91
|
+
# @see https://github.com/redis/redis-rb/blob/2e8577ad71d0efc32f31fb034f341e1eb10abc18/lib/redis/subscribe.rb
|
92
|
+
# Redis::SubscribedClient circa v3.0.0
|
93
|
+
# @see https://github.com/redis/redis-rb/blob/a2c562c002bc8f86d1f47818d63db2da1c5c3d3f/lib/redis/subscribe.rb
|
94
|
+
# Redis::SubscribedClient circa v4.1.3
|
95
|
+
module Client
|
96
|
+
def process(commands)
|
97
|
+
return super if ::Redis.honeycomb_client.nil?
|
98
|
+
|
99
|
+
span = ::Redis.honeycomb_client.start_span(name: "redis")
|
100
|
+
begin
|
101
|
+
fields = Fields.new(self)
|
102
|
+
fields.options = @options
|
103
|
+
fields.command = commands
|
104
|
+
span.add fields
|
105
|
+
super
|
106
|
+
rescue StandardError => e
|
107
|
+
span.add_field "redis.error", e.class.name
|
108
|
+
span.add_field "redis.error_detail", e.message
|
109
|
+
raise
|
110
|
+
ensure
|
111
|
+
span.send
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# This structure contains the fields we'll add to each Redis span.
|
117
|
+
#
|
118
|
+
# The logic is in this class to avoid monkey-patching extraneous APIs into
|
119
|
+
# the Redis::Client via {Client}.
|
120
|
+
#
|
121
|
+
# @private
|
122
|
+
class Fields
|
123
|
+
def initialize(client)
|
124
|
+
@client = client
|
125
|
+
end
|
126
|
+
|
127
|
+
def options=(options)
|
128
|
+
options.each do |option, value|
|
129
|
+
values["redis.#{option}"] ||= value unless ignore?(option)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def command=(commands)
|
134
|
+
commands = Array(commands)
|
135
|
+
values["redis.command"] = commands.map { |cmd| format(cmd) }.join("\n")
|
136
|
+
end
|
137
|
+
|
138
|
+
def to_hash
|
139
|
+
values
|
140
|
+
end
|
141
|
+
|
142
|
+
private
|
143
|
+
|
144
|
+
def values
|
145
|
+
@values ||= {
|
146
|
+
"meta.package" => "redis",
|
147
|
+
"meta.package_version" => ::Redis::VERSION,
|
148
|
+
"redis.id" => @client.id,
|
149
|
+
"redis.location" => @client.location,
|
150
|
+
}
|
151
|
+
end
|
152
|
+
|
153
|
+
# Do we ignore this Redis::Client option?
|
154
|
+
#
|
155
|
+
# * :url - unsafe because it might contain a password
|
156
|
+
# * :password - unsafe
|
157
|
+
# * :logger - just some Ruby object, not useful
|
158
|
+
# * :_parsed - implementation detail
|
159
|
+
def ignore?(option)
|
160
|
+
%i[url password logger _parsed].include?(option)
|
161
|
+
end
|
162
|
+
|
163
|
+
def format(cmd)
|
164
|
+
name, *args = cmd.flatten(1)
|
165
|
+
name = resolve(name)
|
166
|
+
sanitize(args) if name.casecmp("auth").zero?
|
167
|
+
[name.upcase, *args.map { |arg| prettify(arg) }].join(" ")
|
168
|
+
end
|
169
|
+
|
170
|
+
def resolve(name)
|
171
|
+
@client.command_map.fetch(name, name).to_s
|
172
|
+
end
|
173
|
+
|
174
|
+
def sanitize(args)
|
175
|
+
args.map! { "[sanitized]" }
|
176
|
+
end
|
177
|
+
|
178
|
+
def prettify(arg)
|
179
|
+
quotes = false
|
180
|
+
pretty = "".dup
|
181
|
+
arg.to_s.each_char do |c|
|
182
|
+
quotes ||= needs_quotes?(c)
|
183
|
+
pretty << escape(c)
|
184
|
+
end
|
185
|
+
quotes ? "\"#{pretty}\"" : pretty
|
186
|
+
end
|
187
|
+
|
188
|
+
# This aims to replicate the algorithms used by redis-cli.
|
189
|
+
#
|
190
|
+
# @see https://github.com/antirez/redis/blob/0f026af185e918a9773148f6ceaa1b084662be88/src/sds.c#L940-L1067
|
191
|
+
# The redis-cli parsing algorithm
|
192
|
+
#
|
193
|
+
# @see https://github.com/antirez/redis/blob/0f026af185e918a9773148f6ceaa1b084662be88/src/sds.c#L878-L907
|
194
|
+
# The redis-cli printing algorithm
|
195
|
+
def escape(char)
|
196
|
+
return escape_with_backslash(char) if escape_with_backslash?(char)
|
197
|
+
return escape_with_hex_codes(char) if escape_with_hex_codes?(char)
|
198
|
+
|
199
|
+
char
|
200
|
+
end
|
201
|
+
|
202
|
+
# A lookup table for backslash-escaped characters.
|
203
|
+
#
|
204
|
+
# This is used by {#escape_with_backslash?} and {#escape_with_backslash}
|
205
|
+
# to replicate the hard-coded `case` statements in redis-cli. As of this
|
206
|
+
# writing, Redis recognizes a handful of standard C escape sequences,
|
207
|
+
# like "\n" for newlines.
|
208
|
+
#
|
209
|
+
# Because {#prettify} will output double quoted strings if any escaping
|
210
|
+
# is needed, this table must additionally consider the double-quote to be
|
211
|
+
# a backslash-escaped character. For example, instead of generating
|
212
|
+
#
|
213
|
+
# '"hello"'
|
214
|
+
#
|
215
|
+
# we'll generate
|
216
|
+
#
|
217
|
+
# "\"hello\""
|
218
|
+
#
|
219
|
+
# even though redis-cli would technically recognize the single-quoted
|
220
|
+
# version.
|
221
|
+
#
|
222
|
+
# @see https://github.com/antirez/redis/blob/0f026af185e918a9773148f6ceaa1b084662be88/src/sds.c#L888-L896
|
223
|
+
# The redis-cli algorithm for outputting standard escape sequences
|
224
|
+
BACKSLASHES = {
|
225
|
+
"\\" => "\\\\",
|
226
|
+
'"' => '\\"',
|
227
|
+
"\n" => "\\n",
|
228
|
+
"\r" => "\\r",
|
229
|
+
"\t" => "\\t",
|
230
|
+
"\a" => "\\a",
|
231
|
+
"\b" => "\\b",
|
232
|
+
}.freeze
|
233
|
+
|
234
|
+
def escape_with_backslash?(char)
|
235
|
+
BACKSLASHES.key?(char)
|
236
|
+
end
|
237
|
+
|
238
|
+
def escape_with_backslash(char)
|
239
|
+
BACKSLASHES.fetch(char, char)
|
240
|
+
end
|
241
|
+
|
242
|
+
# Do we need to hex-encode this character?
|
243
|
+
#
|
244
|
+
# This replicates the C isprint() function that redis-cli uses to decide
|
245
|
+
# whether to escape a character in hexadecimal notation, "\xhh". Any
|
246
|
+
# non-printable character must be represented as a hex escape sequence.
|
247
|
+
#
|
248
|
+
# Normally, we could match this using a negated POSIX bracket expression:
|
249
|
+
#
|
250
|
+
# /[^[:print:]]/
|
251
|
+
#
|
252
|
+
# You can read that as "not printable".
|
253
|
+
#
|
254
|
+
# However, in Ruby, these character classes also encompass non-ASCII
|
255
|
+
# characters. In contrast, since most platforms have 8-bit `char` types,
|
256
|
+
# the C isprint() function generally does not recognize any Unicode code
|
257
|
+
# points. This effectively limits the redis-cli interpretation of the
|
258
|
+
# printable character range to just printable ASCII characters.
|
259
|
+
#
|
260
|
+
# Thus, we match using a combination of the previous regexp with a
|
261
|
+
# non-POSIX character class that Ruby defines:
|
262
|
+
#
|
263
|
+
# /[^[:print:]&&[:ascii:]]/
|
264
|
+
#
|
265
|
+
# You can read this like
|
266
|
+
#
|
267
|
+
# NOT (printable AND ascii)
|
268
|
+
#
|
269
|
+
# which by DeMorgan's Law is equivalent to
|
270
|
+
#
|
271
|
+
# (NOT printable) OR (NOT ascii)
|
272
|
+
#
|
273
|
+
# That is, if the character is not printable (even in Unicode), we'll
|
274
|
+
# escape it; if the character is printable but non-ASCII, we'll also
|
275
|
+
# escape it.
|
276
|
+
#
|
277
|
+
# What's more, Ruby's Regexp#=~ method will blow up if the string does
|
278
|
+
# not have a valid encoding (e.g., in UTF-8). In this case, though,
|
279
|
+
# {#escape_with_hex_codes} can still convert the bytes that make up the
|
280
|
+
# invalid character into a hex code. So we preemptively check for
|
281
|
+
# invalidly-encoded characters before testing the above match.
|
282
|
+
#
|
283
|
+
# @see https://ruby-doc.org/core-2.6.5/Regexp.html
|
284
|
+
# @see https://github.com/antirez/redis/blob/0f026af185e918a9773148f6ceaa1b084662be88/src/sds.c#L878-L880
|
285
|
+
# @see https://github.com/antirez/redis/blob/0f026af185e918a9773148f6ceaa1b084662be88/src/sds.c#L898-L901
|
286
|
+
# @see https://www.justinweiss.com/articles/3-steps-to-fix-encoding-problems-in-ruby/
|
287
|
+
def escape_with_hex_codes?(char)
|
288
|
+
!char.valid_encoding? || char =~ /[^[:print:]&&[:ascii:]]/
|
289
|
+
end
|
290
|
+
|
291
|
+
# Hex-encodes a (presumably non-printable or non-ASCII) character.
|
292
|
+
#
|
293
|
+
# Aside from standard backslash escape sequences, redis-cli also
|
294
|
+
# recognizes "\xhh" notation, where `hh` is a hexadecimal number.
|
295
|
+
#
|
296
|
+
# Of note is that redis-cli only recognizes *exactly* two-digit
|
297
|
+
# hexadecimal numbers. This is in accordance with IEEE Std 1003.1-2001,
|
298
|
+
# Chapter 7, Locale:
|
299
|
+
#
|
300
|
+
# > A character can be represented as a hexadecimal constant. A
|
301
|
+
# > hexadecimal constant shall be specified as the escape character
|
302
|
+
# > followed by an 'x' followed by two hexadecimal digits. Each constant
|
303
|
+
# > shall represent a byte value. Multi-byte values can be represented by
|
304
|
+
# > concatenated constants specified in byte order with the last constant
|
305
|
+
# > specifying the least significant byte of the character.
|
306
|
+
#
|
307
|
+
# Unlike the C `char` type, Ruby's conception of a character can span
|
308
|
+
# multiple bytes (and possibly bytes that aren't valid in Ruby's string
|
309
|
+
# encoding). So we take care to escape the input properly into the
|
310
|
+
# redis-cli compatible version by iterating through each byte and
|
311
|
+
# formatting it as a (zero-padded) 2-digit hexadecimal number prefixed by
|
312
|
+
# `\x`.
|
313
|
+
#
|
314
|
+
# @see https://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap07.html
|
315
|
+
# @see https://github.com/antirez/redis/blob/0f026af185e918a9773148f6ceaa1b084662be88/src/sds.c#L878-L880
|
316
|
+
# @see https://github.com/antirez/redis/blob/0f026af185e918a9773148f6ceaa1b084662be88/src/sds.c#L898-L901
|
317
|
+
def escape_with_hex_codes(char)
|
318
|
+
char.bytes.map { |b| Kernel.format("\\x%02x", b) }.join
|
319
|
+
end
|
320
|
+
|
321
|
+
def escape?(char)
|
322
|
+
escape_with_backslash?(char) || escape_with_hex_codes?(char)
|
323
|
+
end
|
324
|
+
|
325
|
+
# Should this character cause {#prettify} to wrap its output in quotes?
|
326
|
+
#
|
327
|
+
# The overall string returned by {#prettify} should only be quoted if at
|
328
|
+
# least one of the following holds:
|
329
|
+
#
|
330
|
+
# 1. The string contains a character that needs to be escaped. This
|
331
|
+
# includes standard backslash escape sequences (like "\n" and "\t") as
|
332
|
+
# well as hex-encoded bytes using the "\x" escape sequence. Since
|
333
|
+
# {#prettify} uses double quotes on its output string, we must also
|
334
|
+
# force quotes if the string itself contains a literal double quote.
|
335
|
+
# This double quote behavior is handled tacitly by {BACKSLASHES}.
|
336
|
+
#
|
337
|
+
# 2. The string contains a single quote. Since redis-cli recognizes
|
338
|
+
# single-quoted strings, we want to wrap the {#prettify} output in
|
339
|
+
# double quotes so that the literal single quote character isn't
|
340
|
+
# mistaken as the delimiter of a new string.
|
341
|
+
#
|
342
|
+
# 3. The string contains any whitespace characters. If the {#prettify}
|
343
|
+
# output weren't wrapped in quotes, whitespace would act as a
|
344
|
+
# separator between arguments to the Redis command. To group things
|
345
|
+
# together, we need to quote the string.
|
346
|
+
def needs_quotes?(char)
|
347
|
+
escape?(char) || char == "'" || char =~ /\s/
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
Redis.extend(Honeycomb::Redis::Configuration)
|
354
|
+
Redis::Client.prepend(Honeycomb::Redis::Client)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: honeycomb-beeline
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Holman
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-11-
|
11
|
+
date: 2019-11-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: libhoney
|
@@ -233,6 +233,7 @@ files:
|
|
233
233
|
- lib/honeycomb/integrations/rails.rb
|
234
234
|
- lib/honeycomb/integrations/railtie.rb
|
235
235
|
- lib/honeycomb/integrations/rake.rb
|
236
|
+
- lib/honeycomb/integrations/redis.rb
|
236
237
|
- lib/honeycomb/integrations/sequel.rb
|
237
238
|
- lib/honeycomb/integrations/sinatra.rb
|
238
239
|
- lib/honeycomb/integrations/warden.rb
|