logstash_writer 0.0.7 → 0.0.12

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: 9254bae4e4a6f114fd683a3509b576d272256e162ecc5722c8d1c7a78a3e25e3
4
- data.tar.gz: 9e61badc96a9bc3028a15311117eb95b6d3f37c7c59d950d66fe76d223160363
3
+ metadata.gz: b4f17ecaf181fbd3bf0160ecbd3a0a1fb156b5965be340e4bda05713edafa8fa
4
+ data.tar.gz: c279de10eb157ab271e88117b78d46fe345b8612648c9a5a945fe01c808752d3
5
5
  SHA512:
6
- metadata.gz: 97ebc1f452ecc063b81e534ffb87e62ac4f225101454494ad8058abc18cef6427986b93a8643bc87631fdbde9d629dbebb35a51936f403a20e2d84b5517086b5
7
- data.tar.gz: 01f8be94cee73a68b228e69f55f4f2d8e6448f8d37d885427a741cb8786f4c8fc37e1a99567ee92c8133f27e3faded0f6b3b1ca19cfe0bc382696682b281b6c7
6
+ metadata.gz: f3de8d9133af36ed73dcf965db8d8004d2cd92df054d23a59930a2ea444711d579f6877740924860d265fdb30eb2289ca6b5506331685cac8606d1e6ff13f170
7
+ data.tar.gz: 9d40ca34dd0622593b48ef73c613d278a3f6ab7241abb0f5596e19745094a9791a15e5b9a163167d48b7bb3cd8256d8b5f80616a9b695d7b178d9f3f65cd74e1
@@ -0,0 +1,7 @@
1
+ [*.rb]
2
+ indent_style = space
3
+ indent_size = 2
4
+ end_of_line = lf
5
+ insert_final_newline = true
6
+ charset = utf-8
7
+ trim_trailing_whitespace = true
data/README.md CHANGED
@@ -186,7 +186,7 @@ conduct](CODE_OF_CONDUCT.md).
186
186
  Unless otherwise stated, everything in this repo is covered by the following
187
187
  copyright notice:
188
188
 
189
- Copyright (C) 2015 Civilized Discourse Construction Kit, Inc.
189
+ Copyright (C) 2016,2017,2018 Civilized Discourse Construction Kit, Inc.
190
190
 
191
191
  This program is free software: you can redistribute it and/or modify it
192
192
  under the terms of the GNU General Public License version 3, as
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'ipaddr'
2
4
  require 'json'
3
5
  require 'resolv'
@@ -8,8 +10,8 @@ require 'prometheus/client'
8
10
  #
9
11
  # Flings events, represented as JSON objects, to logstash using the
10
12
  # `json_lines` codec (over TCP). Doesn't do any munging or modification of
11
- # the event data given to it, other than adding `@timestamp` and
12
- # `[@metadata][_id]` fields if they do not already exist.
13
+ # the event data given to it, other than adding a `@timestamp` field if
14
+ # it doesn't already exist.
13
15
  #
14
16
  # We support highly-available logstash installations by means of multiple
15
17
  # address records, or via SRV records. See the docs for .new for details
@@ -74,27 +76,29 @@ class LogstashWriter
74
76
  @server_name, @logger, @backlog = server_name, logger, backlog
75
77
 
76
78
  @metrics = {
77
- received: metrics_registry.counter(:"#{metrics_prefix}_events_received_total", "The number of logstash events which have been submitted for delivery"),
78
- sent: metrics_registry.counter(:"#{metrics_prefix}_events_written_total", "The number of logstash events which have been delivered to the logstash server"),
79
- queue_size: metrics_registry.gauge(:"#{metrics_prefix}_queue_size", "The number of events currently in the queue to be sent"),
80
- dropped: metrics_registry.counter(:"#{metrics_prefix}_events_dropped_total", "The number of events which have been dropped from the queue"),
79
+ received: metrics_registry.counter(:"#{metrics_prefix}_events_received_total", docstring: "The number of logstash events which have been submitted for delivery"),
80
+ sent: metrics_registry.counter(:"#{metrics_prefix}_events_written_total", docstring: "The number of logstash events which have been delivered to the logstash server", labels: %i{server}),
81
+ queue_size: metrics_registry.gauge(:"#{metrics_prefix}_queue_size", docstring: "The number of events currently in the queue to be sent"),
82
+ dropped: metrics_registry.counter(:"#{metrics_prefix}_events_dropped_total", docstring: "The number of events which have been dropped from the queue"),
81
83
 
82
- lag: metrics_registry.gauge(:"#{metrics_prefix}_last_sent_event_time_seconds", "When the last event successfully sent to logstash was originally received"),
84
+ lag: metrics_registry.gauge(:"#{metrics_prefix}_last_sent_event_time_seconds", docstring: "When the last event successfully sent to logstash was originally received"),
83
85
 
84
- connected: metrics_registry.gauge(:"#{metrics_prefix}_connected_to_server", "Boolean flag indicating whether we are currently connected to a logstash server"),
85
- connect_exception: metrics_registry.counter(:"#{metrics_prefix}_connect_exceptions_total", "The number of exceptions that have occurred whilst attempting to connect to a logstash server"),
86
- write_exception: metrics_registry.counter(:"#{metrics_prefix}_write_exceptions_total", "The number of exceptions that have occurred whilst attempting to write an event to a logstash server"),
86
+ connected: metrics_registry.gauge(:"#{metrics_prefix}_connected_to_server", docstring: "Boolean flag indicating whether we are currently connected to a logstash server", labels: %i{server}),
87
+ connect_exception: metrics_registry.counter(:"#{metrics_prefix}_connect_exceptions_total", docstring: "The number of exceptions that have occurred whilst attempting to connect to a logstash server", labels: %i{server class}),
88
+ write_exception: metrics_registry.counter(:"#{metrics_prefix}_write_exceptions_total", docstring: "The number of exceptions that have occurred whilst attempting to write an event to a logstash server", labels: %i{server class}),
87
89
 
88
- write_loop_exception: metrics_registry.counter(:"#{metrics_prefix}_write_loop_exceptions_total", "The number of exceptions that have occurred in the writing loop"),
89
- write_loop_ok: metrics_registry.gauge(:"#{metrics_prefix}_write_loop_ok", "Boolean flag indicating whether the writing loop is currently operating correctly, or is in a post-apocalyptic hellscape of never-ending exceptions"),
90
+ write_loop_exception: metrics_registry.counter(:"#{metrics_prefix}_write_loop_exceptions_total", docstring: "The number of exceptions that have occurred in the writing loop", labels: %i{class}),
91
+ write_loop_ok: metrics_registry.gauge(:"#{metrics_prefix}_write_loop_ok", docstring: "Boolean flag indicating whether the writing loop is currently operating correctly, or is in a post-apocalyptic hellscape of never-ending exceptions"),
90
92
  }
91
93
 
92
- @metrics[:lag].set({}, 0)
93
- @metrics[:queue_size].set({}, 0)
94
+ @metrics[:lag].set(0)
95
+ @metrics[:queue_size].set(0)
94
96
 
95
- metrics_registry.gauge(:"#{metrics_prefix}_queue_max", "The maximum size of the event queue").set({}, backlog)
97
+ metrics_registry.gauge(:"#{metrics_prefix}_queue_max", docstring: "The maximum size of the event queue").set(backlog)
96
98
 
97
- @queue = []
99
+ # We can't use a stdlib Queue object because we need to re-push items
100
+ # onto the front of the queue in case of error
101
+ @queue = []
98
102
  @queue_mutex = Mutex.new
99
103
  @queue_cv = ConditionVariable.new
100
104
 
@@ -104,8 +108,8 @@ class LogstashWriter
104
108
 
105
109
  # Add an event to the queue, to be sent to logstash. Actual event
106
110
  # delivery will happen in a worker thread that is started with
107
- # #run. If the event does not have a `@timestamp` or `[@metadata][_id]`
108
- # element, they will be added with appropriate values.
111
+ # #run. If the event does not have a `@timestamp` field, it will
112
+ # be added set to the current time.
109
113
  #
110
114
  # @param e [Hash] the event data to be sent.
111
115
  #
@@ -120,22 +124,6 @@ class LogstashWriter
120
124
  e[:@timestamp] = Time.now.utc.strftime("%FT%T.%NZ")
121
125
  end
122
126
 
123
- if e.has_key?("@metadata")
124
- e[:@metadata] = (e[:@metadata] || {}).merge(e.delete("@metadata"))
125
- end
126
-
127
- unless e.has_key?(:@metadata)
128
- e[:@metadata] = {}
129
- end
130
-
131
- unless e[:@metadata].has_key?(:_id) || e.has_key?("_id")
132
- # This is the quickest way I've found to get a long, random string.
133
- # We don't need any sort of cryptographic or unpredictability
134
- # guarantees for what we're doing here, so SecureRandom is unnecessary
135
- # overhead.
136
- e[:@metadata][:_id] = rand(0x1000_0000_0000_0000_0000_0000_0000_0000).to_s(36)
137
- end
138
-
139
127
  @queue_mutex.synchronize do
140
128
  @queue << { content: e, arrival_timestamp: Time.now }
141
129
  while @queue.length > @backlog
@@ -150,6 +138,33 @@ class LogstashWriter
150
138
  nil
151
139
  end
152
140
 
141
+ # Send events.
142
+ #
143
+ # Does not return until `#shutdown` is called (in another thread).
144
+ #
145
+ def run
146
+ @queue_mutex.synchronize do
147
+ @terminate = false
148
+ end
149
+
150
+ write_loop
151
+ end
152
+
153
+ # Tell the LogstashWriter to flush its queue and terminate operation.
154
+ #
155
+ # Returns immediately.
156
+ #
157
+ def shutdown
158
+ #:nocov:
159
+ @worker_mutex.synchronize do
160
+ @queue_mutex.synchronize do
161
+ @terminate = true
162
+ @queue_cv.signal
163
+ end
164
+ end
165
+ #:nocov:
166
+ end
167
+
153
168
  # Start sending events.
154
169
  #
155
170
  # This method will return almost immediately, and actual event
@@ -157,15 +172,16 @@ class LogstashWriter
157
172
  #
158
173
  # @return [NilClass]
159
174
  #
160
- def run
175
+ def start!
161
176
  @worker_mutex.synchronize do
162
177
  if @worker_thread.nil?
163
- m, cv = Mutex.new, ConditionVariable.new
164
-
165
- @worker_thread = Thread.new { cv.signal; write_loop }
178
+ @queue_mutex.synchronize do
179
+ @terminate = false
180
+ end
166
181
 
167
- # Don't return until the thread has *actually* started
168
- m.synchronize { cv.wait(m) }
182
+ @worker_thread = Thread.new do
183
+ write_loop
184
+ end
169
185
  end
170
186
  end
171
187
 
@@ -180,18 +196,19 @@ class LogstashWriter
180
196
  #
181
197
  # @return [NilClass]
182
198
  #
183
- def stop
199
+ def stop!
184
200
  @worker_mutex.synchronize do
185
201
  if @worker_thread
186
- @terminate = true
187
- @queue_cv.signal
202
+ @queue_mutex.synchronize do
203
+ @terminate = true
204
+ @queue_cv.signal
205
+ end
188
206
  begin
189
- @worker_thread.join
207
+ @worker_thread.join unless @worker_thread == Thread.current
190
208
  rescue Exception => ex
191
209
  @logger.error("LogstashWriter") { (["Worker thread terminated with exception: #{ex.message} (#{ex.class})"] + ex.backtrace).join("\n ") }
192
210
  end
193
211
  @worker_thread = nil
194
- @socket_mutex.synchronize { (@current_target.close; @current_target = nil) if @current_target }
195
212
  end
196
213
  end
197
214
 
@@ -226,45 +243,43 @@ class LogstashWriter
226
243
  #
227
244
  def write_loop
228
245
  error_wait = INITIAL_RETRY_WAIT
246
+ Thread.current.name = "LogstashWriter"
229
247
 
230
- catch :terminate do
231
- loop do
232
- event = nil
248
+ until @terminate do
249
+ event = nil
233
250
 
234
- begin
235
- @queue_mutex.synchronize do
236
- while @queue.empty? && !@terminate
237
- @queue_cv.wait(@queue_mutex)
238
- end
239
-
240
- if @queue.empty? && @terminate
241
- @terminate = false
242
- throw :terminate
243
- end
244
-
245
- event = @queue.shift
251
+ begin
252
+ @queue_mutex.synchronize do
253
+ while @queue.empty? && !@terminate
254
+ @queue_cv.wait(@queue_mutex)
246
255
  end
247
256
 
257
+ event = @queue.shift
258
+ end
259
+
260
+ if event
248
261
  current_target do |t|
249
262
  t.socket.puts event[:content].to_json
250
263
  stat_sent(t.to_s, event[:arrival_timestamp])
251
- @metrics[:write_loop_ok].set({}, 1)
264
+ @metrics[:write_loop_ok].set(1)
252
265
  error_wait = INITIAL_RETRY_WAIT
253
266
  end
254
- rescue StandardError => ex
255
- @logger.error("LogstashWriter") { (["Exception in write_loop: #{ex.message} (#{ex.class})"] + ex.backtrace).join("\n ") }
256
- @queue_mutex.synchronize { @queue.unshift(event) if event }
257
- @metrics[:write_loop_exception].increment(class: ex.class.to_s)
258
- @metrics[:write_loop_ok].set({}, 0)
259
- sleep error_wait
260
- # Increase the error wait timeout for next time, up to a maximum
261
- # interval of about 60 seconds
262
- error_wait *= 1.1
263
- error_wait = 60 if error_wait > 60
264
- error_wait += rand / 0.5
265
267
  end
268
+ rescue StandardError => ex
269
+ @logger.error("LogstashWriter") { (["Exception in write_loop: #{ex.message} (#{ex.class})"] + ex.backtrace).join("\n ") }
270
+ @queue_mutex.synchronize { @queue.unshift(event) if event }
271
+ @metrics[:write_loop_exception].increment(labels: { class: ex.class.to_s })
272
+ @metrics[:write_loop_ok].set(0)
273
+ sleep error_wait
274
+ # Increase the error wait timeout for next time, up to a maximum
275
+ # interval of about 60 seconds
276
+ error_wait *= 1.1
277
+ error_wait = 60 if error_wait > 60
278
+ error_wait += rand / 0.5
266
279
  end
267
280
  end
281
+
282
+ force_disconnect!
268
283
  end
269
284
 
270
285
  # Yield a Target connected to the server we currently believe to be
@@ -296,14 +311,14 @@ class LogstashWriter
296
311
  raise Errno::ENOTCONN unless IO.select([@current_target.socket], [], [], 0).nil?
297
312
 
298
313
  yield @current_target
299
- @metrics[:connected].set({ server: @current_target.describe_peer }, 1)
314
+ @metrics[:connected].set(1, labels: { server: @current_target.describe_peer })
300
315
  done = true
301
316
  rescue SystemCallError => ex
302
317
  # Something went wrong during the send; disconnect from this
303
318
  # server and recycle
304
- @metrics[:write_exception].increment(server: @current_target.describe_peer, class: ex.class.to_s)
305
- @metrics[:connected].set({ server: @current_target.describe_peer }, 0)
306
- @logger.info("LogstashWriter") { "Error while writing to current server #{@current_target.describe_peer}: #{ex.message} (#{ex.class})" }
319
+ @metrics[:write_exception].increment(labels: { server: @current_target.describe_peer, class: ex.class.to_s })
320
+ @metrics[:connected].set(0, labels: { server: @current_target.describe_peer })
321
+ @logger.error("LogstashWriter") { "Error while writing to current server #{@current_target.describe_peer}: #{ex.message} (#{ex.class})" }
307
322
  @current_target.close
308
323
  @current_target = nil
309
324
 
@@ -328,6 +343,7 @@ class LogstashWriter
328
343
  @current_target = next_server
329
344
  # Trigger a connection attempt
330
345
  @current_target.socket
346
+ @logger.info("LogstashWriter") { "Connected to #{@current_target.describe_peer}" }
331
347
  else
332
348
  @logger.debug("LogstashWriter") { "Could not connect to any server; pausing before trying again" }
333
349
  @current_target = nil
@@ -344,7 +360,7 @@ class LogstashWriter
344
360
  end
345
361
  rescue SystemCallError => ex
346
362
  # Connection failed for any number of reasons; try the next one in the list
347
- @metrics[:connect_exception].increment(server: next_server.to_s, class: ex.class.to_s)
363
+ @metrics[:connect_exception].increment(labels: { server: next_server.to_s, class: ex.class.to_s })
348
364
  @logger.error("LogstashWriter") { "Failed to connect to #{next_server.to_s}: #{ex.message} (#{ex.class})" }
349
365
  sleep INITIAL_RETRY_WAIT
350
366
  retry
@@ -436,19 +452,19 @@ class LogstashWriter
436
452
  end
437
453
 
438
454
  def stat_received
439
- @metrics[:received].increment({})
440
- @metrics[:queue_size].increment({})
455
+ @metrics[:received].increment
456
+ @metrics[:queue_size].increment
441
457
  end
442
458
 
443
459
  def stat_sent(peer, arrived_time)
444
- @metrics[:sent].increment(server: peer)
445
- @metrics[:queue_size].decrement({})
446
- @metrics[:lag].set({}, arrived_time.to_f)
460
+ @metrics[:sent].increment(labels: { server: peer })
461
+ @metrics[:queue_size].decrement
462
+ @metrics[:lag].set(arrived_time.to_f)
447
463
  end
448
464
 
449
465
  def stat_dropped
450
- @metrics[:queue_size].decrement({})
451
- @metrics[:dropped].increment({})
466
+ @metrics[:queue_size].decrement
467
+ @metrics[:dropped].increment
452
468
  end
453
469
 
454
470
  # An individual target for logstash messages
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require 'git-version-bump'
3
5
  rescue LoadError
@@ -27,21 +29,16 @@ Gem::Specification.new do |s|
27
29
 
28
30
  s.required_ruby_version = ">= 2.3.0"
29
31
 
30
- # prometheus-client provides no guaranteed backwards compatibility,
31
- # and in fact happily breaks things with no notice, so we're stuck
32
- # with hard-coding a specific version to avoid unexpected disaster.
33
- s.add_runtime_dependency "prometheus-client", "0.8.0"
32
+ s.add_runtime_dependency "prometheus-client", "~> 2.0"
34
33
 
35
34
  s.add_development_dependency 'bundler'
36
35
  s.add_development_dependency 'github-release'
37
36
  s.add_development_dependency 'git-version-bump'
38
37
  s.add_development_dependency 'guard-rspec'
39
- s.add_development_dependency 'guard-rubocop'
40
38
  s.add_development_dependency 'rack-test'
41
39
  s.add_development_dependency 'rake', "~> 12.0"
42
40
  s.add_development_dependency 'redcarpet'
43
41
  s.add_development_dependency 'rspec'
44
- s.add_development_dependency 'rubocop'
45
42
  s.add_development_dependency 'simplecov'
46
43
  s.add_development_dependency 'yard'
47
44
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash_writer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Palmer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-04 00:00:00.000000000 Z
11
+ date: 2020-05-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: prometheus-client
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '='
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.8.0
19
+ version: '2.0'
20
20
  type: :runtime
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: 0.8.0
26
+ version: '2.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -80,20 +80,6 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: guard-rubocop
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
83
  - !ruby/object:Gem::Dependency
98
84
  name: rack-test
99
85
  requirement: !ruby/object:Gem::Requirement
@@ -150,20 +136,6 @@ dependencies:
150
136
  - - ">="
151
137
  - !ruby/object:Gem::Version
152
138
  version: '0'
153
- - !ruby/object:Gem::Dependency
154
- name: rubocop
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - ">="
158
- - !ruby/object:Gem::Version
159
- version: '0'
160
- type: :development
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - ">="
165
- - !ruby/object:Gem::Version
166
- version: '0'
167
139
  - !ruby/object:Gem::Dependency
168
140
  name: simplecov
169
141
  requirement: !ruby/object:Gem::Requirement
@@ -202,8 +174,8 @@ executables: []
202
174
  extensions: []
203
175
  extra_rdoc_files: []
204
176
  files:
177
+ - ".editorconfig"
205
178
  - ".gitignore"
206
- - ".rubocop.yml"
207
179
  - ".travis.yml"
208
180
  - ".yardopts"
209
181
  - CODE_OF_CONDUCT.md
@@ -230,8 +202,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
230
202
  - !ruby/object:Gem::Version
231
203
  version: '0'
232
204
  requirements: []
233
- rubyforge_project:
234
- rubygems_version: 2.7.7
205
+ rubygems_version: 3.0.3
235
206
  signing_key:
236
207
  specification_version: 4
237
208
  summary: Opinionated logstash event pump
@@ -1,116 +0,0 @@
1
- AllCops:
2
- TargetRubyVersion: 2.4
3
- DisabledByDefault: true
4
- Exclude:
5
- - 'db/schema.rb'
6
- - 'bundle/**/*'
7
- - 'vendor/**/*'
8
- - 'node_modules/**/*'
9
- - 'public/**/*'
10
-
11
- # Prefer &&/|| over and/or.
12
- Style/AndOr:
13
- Enabled: true
14
-
15
- # Do not use braces for hash literals when they are the last argument of a
16
- # method call.
17
- Style/BracesAroundHashParameters:
18
- Enabled: true
19
-
20
- # Align `when` with `case`.
21
- Layout/CaseIndentation:
22
- Enabled: true
23
-
24
- # Align comments with method definitions.
25
- Layout/CommentIndentation:
26
- Enabled: true
27
-
28
- # No extra empty lines.
29
- Layout/EmptyLines:
30
- Enabled: true
31
-
32
- # Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }.
33
- Style/HashSyntax:
34
- Enabled: true
35
-
36
- # Two spaces, no tabs (for indentation).
37
- Layout/IndentationWidth:
38
- Enabled: true
39
-
40
- Layout/SpaceAfterColon:
41
- Enabled: true
42
-
43
- Layout/SpaceAfterComma:
44
- Enabled: true
45
-
46
- Layout/SpaceAroundEqualsInParameterDefault:
47
- Enabled: true
48
-
49
- Layout/SpaceAroundKeyword:
50
- Enabled: true
51
-
52
- Layout/SpaceAroundOperators:
53
- Enabled: true
54
-
55
- Layout/SpaceBeforeFirstArg:
56
- Enabled: true
57
-
58
- # Defining a method with parameters needs parentheses.
59
- Style/MethodDefParentheses:
60
- Enabled: true
61
-
62
- # Use `foo {}` not `foo{}`.
63
- Layout/SpaceBeforeBlockBraces:
64
- Enabled: true
65
-
66
- # Use `foo { bar }` not `foo {bar}`.
67
- Layout/SpaceInsideBlockBraces:
68
- Enabled: true
69
-
70
- # Use `{ a: 1 }` not `{a:1}`.
71
- Layout/SpaceInsideHashLiteralBraces:
72
- Enabled: true
73
-
74
- Layout/SpaceInsideParens:
75
- Enabled: true
76
-
77
- # Detect hard tabs, no hard tabs.
78
- Layout/Tab:
79
- Enabled: true
80
-
81
- # Blank lines should not have any spaces.
82
- Layout/TrailingBlankLines:
83
- Enabled: true
84
-
85
- # No trailing whitespace.
86
- Layout/TrailingWhitespace:
87
- Enabled: true
88
-
89
- Lint/Debugger:
90
- Enabled: true
91
-
92
- Layout/BlockAlignment:
93
- Enabled: true
94
-
95
- # Align `end` with the matching keyword or starting expression except for
96
- # assignments, where it should be aligned with the LHS.
97
- Layout/EndAlignment:
98
- Enabled: true
99
- EnforcedStyleAlignWith: variable
100
-
101
- # Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
102
- Lint/RequireParentheses:
103
- Enabled: true
104
-
105
- Lint/ShadowingOuterLocalVariable:
106
- Enabled: true
107
-
108
- Layout/MultilineMethodCallIndentation:
109
- Enabled: true
110
- EnforcedStyle: indented
111
-
112
- Layout/AlignHash:
113
- Enabled: true
114
-
115
- Bundler/OrderedGems:
116
- Enabled: false