logstash-input-syslog 3.4.3 → 3.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dc9057a2c876b1bdb746a10c07fcc32b66d265aeb5658e1116fb0435bd29ea76
4
- data.tar.gz: f33e03b2bb5cdad71d2152c6d563db6c2a1d7175e7cb24d6f5b872d707dbfc42
3
+ metadata.gz: ef06714d6d1b2383646d6ec53550171592e1dbcd97e3e7b1e847edcceba41d4a
4
+ data.tar.gz: acd1005f0b2db5ad66ff95c7d74027ead6841d97b4805c05ed19225fa5af3cf5
5
5
  SHA512:
6
- metadata.gz: 877bd6b44875b1b4318e08073d53caef55c90dbe636ab49a0e7c4e2af5d3c6f8a12527250e0988442aa12e884eee8902db89803cd0a517aa0506bb1127de4ea1
7
- data.tar.gz: 477cd68ad7aedb6125205b4c88d0ec2bdae3e5e58d82bc91c21317eef919f1047b7c9d4bbc2ccc7e381c447d1af2adda0ed8d69585544fd95d0a65884af91abb
6
+ metadata.gz: ea924072e2e8904864649a6be3706523dca20a01c1c7aef441fea1c643f93e78dcb12d869ffb1f4d16ee2ebbdcdf4a396f45d6b3fc77909ad247941a849f9e6d
7
+ data.tar.gz: d3d658703fa56537a9818f65b92ddba37e8f56e760beda02698b1782c5f89eb9dc6c279c18a0611ecf653f3c9b07894549edf5b750855fc0f42500862f7d6f4a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ ## 3.6.0
2
+ - Add support for ECS v8 as alias to v1 implementation [#68](https://github.com/logstash-plugins/logstash-input-syslog/pull/68)
3
+
4
+ ## 3.5.0
5
+ - Feat: ECS compatibility support [#63](https://github.com/logstash-plugins/logstash-input-syslog/pull/63)
6
+
7
+ ## 3.4.5
8
+ - Added support for listening on IPv6 addresses
9
+
10
+ ## 3.4.4
11
+ - Refactor: avoid global side-effect + cleanup [#62](https://github.com/logstash-plugins/logstash-input-syslog/pull/62)
12
+ * avoid setting `BasicSocket.do_not_reverse_lookup` as it has side effects for others
13
+
1
14
  ## 3.4.3
2
15
  - [DOC] Added expanded descriptions and requirements for facility_labels and severity_labels. [#52](https://github.com/logstash-plugins/logstash-input-syslog/pull/52)
3
16
 
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Logstash Plugin
2
2
 
3
- [![Travis Build Status](https://travis-ci.org/logstash-plugins/logstash-input-syslog.svg)](https://travis-ci.org/logstash-plugins/logstash-input-syslog)
3
+ [![Travis Build Status](https://travis-ci.com/logstash-plugins/logstash-input-syslog.svg)](https://travis-ci.com/logstash-plugins/logstash-input-syslog)
4
4
 
5
5
  This is a plugin for [Logstash](https://github.com/elastic/logstash).
6
6
 
data/docs/index.asciidoc CHANGED
@@ -47,6 +47,7 @@ This plugin supports the following configuration options plus the <<plugins-{typ
47
47
  [cols="<,<,<",options="header",]
48
48
  |=======================================================================
49
49
  |Setting |Input type|Required
50
+ | <<plugins-{type}s-{plugin}-ecs_compatibility>> | <<string,string>>|No
50
51
  | <<plugins-{type}s-{plugin}-facility_labels>> |<<array,array>>|No
51
52
  | <<plugins-{type}s-{plugin}-grok_pattern>> |<<string,string>>|No
52
53
  | <<plugins-{type}s-{plugin}-host>> |<<string,string>>|No
@@ -64,6 +65,20 @@ input plugins.
64
65
 
65
66
  &nbsp;
66
67
 
68
+ [id="plugins-{type}s-{plugin}-ecs_compatibility"]
69
+ ===== `ecs_compatibility`
70
+
71
+ * Value type is <<string,string>>
72
+ * Supported values are:
73
+ ** `disabled`: does not use ECS-compatible field names (for example, `priority` for syslog priority)
74
+ ** `v1`,`v8`: uses fields that are compatible with Elastic Common Schema (for example, `[log][syslog][priority]`)
75
+ * Default value depends on which version of Logstash is running:
76
+ ** When Logstash provides a `pipeline.ecs_compatibility` setting, its value is used as the default
77
+ ** Otherwise, the default value is `disabled`.
78
+
79
+ Controls this plugin's compatibility with the
80
+ {ecs-ref}[Elastic Common Schema (ECS)].
81
+
67
82
  [id="plugins-{type}s-{plugin}-facility_labels"]
68
83
  ===== `facility_labels`
69
84
 
@@ -84,6 +99,9 @@ the facility_label is not added to the event.
84
99
 
85
100
  * Value type is <<string,string>>
86
101
  * Default value is `"<%{POSINT:priority}>%{SYSLOGLINE}"`
102
+ * Default value depends on whether <<plugins-{type}s-{plugin}-ecs_compatibility>> is enabled:
103
+ ** ECS Compatibility disabled: `"<%{POSINT:priority}>%{SYSLOGLINE}"`
104
+ ** ECS Compatibility enabled: `"<%{POSINT:[log][syslog][priority]:int}>%{SYSLOGLINE}"`
87
105
 
88
106
  The default value should read and properly parse syslog lines which are
89
107
  fully compliant with http://www.ietf.org/rfc/rfc3164.txt[RFC3164].
@@ -6,6 +6,7 @@ require "logstash/filters/grok"
6
6
  require "logstash/filters/date"
7
7
  require "logstash/inputs/base"
8
8
  require "logstash/namespace"
9
+ require 'logstash/plugin_mixins/ecs_compatibility_support'
9
10
  require "stud/interval"
10
11
 
11
12
  # Read syslog messages as events over the network.
@@ -25,6 +26,8 @@ require "stud/interval"
25
26
  # Note: This input will start listeners on both TCP and UDP.
26
27
  #
27
28
  class LogStash::Inputs::Syslog < LogStash::Inputs::Base
29
+ include LogStash::PluginMixins::ECSCompatibilitySupport(:disabled, :v1, :v8 => :v1)
30
+
28
31
  config_name "syslog"
29
32
 
30
33
  default :codec, "plain"
@@ -42,7 +45,7 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
42
45
 
43
46
  # Set custom grok pattern to parse the syslog, in case the format differs
44
47
  # from the defined standard. This is common in security and other appliances
45
- config :grok_pattern, :validate => :string, :default => "<%{POSINT:priority}>%{SYSLOGLINE}"
48
+ config :grok_pattern, :validate => :string
46
49
 
47
50
  # Proxy protocol support, only v1 is supported at this time
48
51
  # http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt
@@ -59,8 +62,7 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
59
62
 
60
63
  # Specify a time zone canonical ID to be used for date parsing.
61
64
  # The valid IDs are listed on the [Joda.org available time zones page](http://joda-time.sourceforge.net/timezones.html).
62
- # This is useful in case the time zone cannot be extracted from the value,
63
- # and is not the platform default.
65
+ # This is useful in case the time zone cannot be extracted from the value, and is not the platform default.
64
66
  # If this is not specified the platform default will be used.
65
67
  # Canonical ID is good as it takes care of daylight saving time for you
66
68
  # For example, `America/Los_Angeles` or `Europe/France` are valid IDs.
@@ -75,28 +77,67 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
75
77
  #
76
78
  config :locale, :validate => :string
77
79
 
78
- public
79
- def initialize(params)
80
+ # ECS only option to configure [service][type] value in produced events.
81
+ #
82
+ # NOTE: for now, purposefully un-documented as there are other [service] fields we could support,
83
+ # assuming users would want that (they have specific use-case for LS as syslog server).
84
+ config :service_type, :validate => :string, :default => 'system'
85
+
86
+ def initialize(*params)
80
87
  super
81
- BasicSocket.do_not_reverse_lookup = true
82
- end # def initialize
83
88
 
84
- public
85
- def register
86
- @metric_errors = metric.namespace(:errors)
89
+ @priority_key = ecs_select[disabled:'priority', v1:'[log][syslog][priority]']
90
+ @facility_key = ecs_select[disabled:'facility', v1:'[log][syslog][facility][code]']
91
+ @severity_key = ecs_select[disabled:'severity', v1:'[log][syslog][severity][code]']
92
+
93
+ @facility_label_key = ecs_select[disabled:'facility_label', v1:'[log][syslog][facility][name]']
94
+ @severity_label_key = ecs_select[disabled:'severity_label', v1:'[log][syslog][severity][name]']
95
+
96
+ @host_key = ecs_select[disabled:'host', v1:'[host][ip]']
97
+
98
+ @grok_pattern ||= ecs_select[
99
+ disabled:"<%{POSINT:#{@priority_key}}>%{SYSLOGLINE}",
100
+ v1:"<%{POSINT:#{@priority_key}:int}>%{SYSLOGLINE}"
101
+ ]
87
102
 
88
103
  @grok_filter = LogStash::Filters::Grok.new(
89
- "overwrite" => @syslog_field,
90
- "match" => { @syslog_field => @grok_pattern },
91
- "tag_on_failure" => ["_grokparsefailure_sysloginput"],
104
+ "overwrite" => @syslog_field,
105
+ "match" => { @syslog_field => @grok_pattern },
106
+ "tag_on_failure" => ["_grokparsefailure_sysloginput"],
107
+ "ecs_compatibility" => ecs_compatibility # use ecs-compliant patterns
92
108
  )
93
109
 
110
+ @grok_filter_exec = ecs_select[
111
+ disabled: -> (event) { @grok_filter.filter(event) },
112
+ v1: -> (event) {
113
+ event.set('[event][original]', event.get(@syslog_field))
114
+ @grok_filter.filter(event)
115
+ set_service_fields(event)
116
+ }
117
+ ]
118
+
94
119
  @date_filter = LogStash::Filters::Date.new(
95
- "match" => [ "timestamp", "MMM dd HH:mm:ss", "MMM d HH:mm:ss", "ISO8601"],
96
- "locale" => @locale,
97
- "timezone" => @timezone,
120
+ "match" => [ "timestamp", "MMM dd HH:mm:ss", "MMM d HH:mm:ss", "MMM d HH:mm:ss", "ISO8601"],
121
+ "locale" => @locale,
122
+ "timezone" => @timezone,
98
123
  )
99
124
 
125
+ @date_filter_exec = ecs_select[
126
+ disabled: -> (event) {
127
+ # in legacy (non-ecs) mode we used to match (SYSLOGBASE2) timestamp into two fields
128
+ event.set("timestamp", event.get("timestamp8601")) if event.include?("timestamp8601")
129
+ @date_filter.filter(event)
130
+ },
131
+ v1: -> (event) {
132
+ @date_filter.filter(event)
133
+ event.remove('timestamp')
134
+ }
135
+ ]
136
+ end
137
+
138
+ def register
139
+ @metric_errors = metric.namespace(:errors)
140
+
100
141
  @grok_filter.register
101
142
  @date_filter.register
102
143
 
@@ -104,7 +145,8 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
104
145
  @tcp = @udp = nil
105
146
  end # def register
106
147
 
107
- public
148
+ private
149
+
108
150
  def run(output_queue)
109
151
  udp_thr = Thread.new(output_queue) do |output_queue|
110
152
  server(:udp, output_queue)
@@ -119,8 +161,8 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
119
161
  udp_thr.join
120
162
  tcp_thr.join
121
163
  end # def run
164
+ public :run
122
165
 
123
- private
124
166
  # server call the specified protocol listener and basically restarts on
125
167
  # any listener uncatched exception
126
168
  #
@@ -137,7 +179,6 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
137
179
  end
138
180
  end
139
181
 
140
- private
141
182
  # udp_listener creates the udp socket and continously read from it.
142
183
  # upon exception the socket will be closed and the exception bubbled
143
184
  # in the server which will restart the listener
@@ -145,7 +186,8 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
145
186
  @logger.info("Starting syslog udp listener", :address => "#{@host}:#{@port}")
146
187
 
147
188
  @udp.close if @udp
148
- @udp = UDPSocket.new(Socket::AF_INET)
189
+ @udp = UDPSocket.new (IPAddr.new(@host).ipv6? rescue nil) ? Socket::AF_INET6 : Socket::AF_INET
190
+ @udp.do_not_reverse_lookup = true
149
191
  @udp.bind(@host, @port)
150
192
 
151
193
  while !stop?
@@ -157,7 +199,6 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
157
199
  close_udp
158
200
  end # def udp_listener
159
201
 
160
- private
161
202
  # tcp_listener accepts tcp connections and creates a new tcp_receiver thread
162
203
  # for each accepted socket.
163
204
  # upon exception all tcp sockets will be closed and the exception bubbled
@@ -165,6 +206,7 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
165
206
  def tcp_listener(output_queue)
166
207
  @logger.info("Starting syslog tcp listener", :address => "#{@host}:#{@port}")
167
208
  @tcp = TCPServer.new(@host, @port)
209
+ @tcp.do_not_reverse_lookup = true
168
210
 
169
211
  while !stop?
170
212
  socket = @tcp.accept
@@ -182,11 +224,14 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
182
224
  # tcp_receiver is executed in a thread, any uncatched exception will be bubbled up to the
183
225
  # tcp server thread and all tcp connections will be closed and the listener restarted.
184
226
  def tcp_receiver(output_queue, socket)
185
- ip, port = socket.peeraddr[3], socket.peeraddr[1]
186
- first_read = true
227
+ peer_addr = socket.peeraddr
228
+ ip, port = peer_addr[3], peer_addr[1]
229
+
187
230
  @logger.info("new connection", :client => "#{ip}:#{port}")
188
231
  LogStash::Util::set_thread_name("input|syslog|tcp|#{ip}:#{port}}")
189
232
 
233
+ first_read = true
234
+
190
235
  socket.each do |line|
191
236
  metric.increment(:messages_received)
192
237
  if @proxy_protocol && first_read
@@ -194,10 +239,10 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
194
239
  pp_info = line.split(/\s/)
195
240
  # PROXY proto clientip proxyip clientport proxyport
196
241
  if pp_info[0] != "PROXY"
197
- @logger.error("invalid proxy protocol header label", :hdr => line)
242
+ @logger.error("invalid proxy protocol header label", header: line)
198
243
  raise IOError
199
244
  else
200
- # would be nice to log the proxy host and port data as well, but minimizing changes
245
+ @logger.debug("proxy protocol detected", header: line)
201
246
  ip = pp_info[2]
202
247
  port = pp_info[3]
203
248
  next
@@ -211,49 +256,45 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
211
256
  rescue Errno::EBADF
212
257
  # swallow connection closed exceptions to avoid bubling up the tcp_listener & server
213
258
  logger.info("connection closed", :client => "#{ip}:#{port}")
214
- rescue IOError => ioerror
259
+ rescue IOError => e
215
260
  # swallow connection closed exceptions to avoid bubling up the tcp_listener & server
216
- raise unless socket.closed? && ioerror.message.include?("closed")
217
- logger.info("connection error: #{ioerror.message}")
261
+ raise(e) unless socket.closed? && e.message.to_s.include?("closed")
262
+ logger.info("connection error:", :exception => e.class, :message => e.message)
218
263
  ensure
219
264
  @tcp_sockets.delete(socket)
220
- socket.close rescue log_and_squash
265
+ socket.close rescue log_and_squash(:close_tcp_receiver_socket)
221
266
  end
222
267
 
223
- private
224
- def decode(host, output_queue, data)
268
+ def decode(ip, output_queue, data)
225
269
  @codec.decode(data) do |event|
226
270
  decorate(event)
227
- event.set("host", host)
271
+ event.set(@host_key, ip)
228
272
  syslog_relay(event)
229
273
  output_queue << event
230
274
  metric.increment(:events)
231
275
  end
232
276
  rescue => e
233
277
  # swallow and log all decoding exceptions, these will never be socket related
234
- @logger.error("Error decoding data", :data => data.inspect, :exception => e, :backtrace => e.backtrace)
278
+ @logger.error("Error decoding data", :data => data.inspect, :exception => e.class, :message => e.message, :backtrace => e.backtrace)
235
279
  @metric_errors.increment(:decoding)
236
280
  end
237
281
 
238
- public
282
+ # @see LogStash::Plugin#close
239
283
  def stop
240
284
  close_udp
241
285
  close_tcp
242
286
  end
287
+ public :stop
243
288
 
244
- private
245
289
  def close_udp
246
290
  if @udp
247
- @udp.close_read rescue log_and_squash
248
- @udp.close_write rescue log_and_squash
291
+ @udp.close_read rescue log_and_squash(:close_udp_read)
292
+ @udp.close_write rescue log_and_squash(:close_udp_write)
249
293
  end
250
294
  @udp = nil
251
295
  end
252
296
 
253
- private
254
-
255
- # Helper for inline rescues, which logs the squashed exception at "TRACE" level
256
- # and returns nil.
297
+ # Helper for inline rescues, which logs the exception at "DEBUG" level and returns nil.
257
298
  #
258
299
  # Instead of:
259
300
  # ~~~ ruby
@@ -261,19 +302,19 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
261
302
  # ~~~
262
303
  # Do:
263
304
  # ~~~ ruby
264
- #. foo rescue log_and_squash
305
+ #. foo rescue log_and_squash(:foo)
265
306
  # ~~~
266
- def log_and_squash
267
- $! && logger.trace("SQUASHED EXCEPTION: `#{$!.message}` at (`#{caller.first}`)")
307
+ def log_and_squash(label)
308
+ $! && logger.debug("#{label} failed:", :exception => $!.class, :message => $!.message)
268
309
  nil
269
310
  end
270
311
 
271
312
  def close_tcp
272
313
  # If we somehow have this left open, close it.
273
314
  @tcp_sockets.each do |socket|
274
- socket.close rescue log_and_squash
315
+ socket.close rescue log_and_squash(:close_tcp_socket)
275
316
  end
276
- @tcp.close if @tcp rescue log_and_squash
317
+ @tcp.close if @tcp rescue log_and_squash(:close_tcp)
277
318
  @tcp = nil
278
319
  end
279
320
 
@@ -282,46 +323,54 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
282
323
  # If the message cannot be recognized (see @grok_filter), we'll
283
324
  # treat it like the whole event["message"] is correct and try to fill
284
325
  # the missing pieces (host, priority, etc)
285
- public
286
326
  def syslog_relay(event)
287
- @grok_filter.filter(event)
327
+ @grok_filter_exec.(event)
288
328
 
289
329
  if event.get("tags").nil? || !event.get("tags").include?(@grok_filter.tag_on_failure)
290
330
  # Per RFC3164, priority = (facility * 8) + severity
291
331
  # = (facility << 3) & (severity)
292
- priority = event.get("priority").to_i rescue 13
293
- severity = priority & 7 # 7 is 111 (3 bits)
294
- facility = priority >> 3
295
- event.set("priority", priority)
296
- event.set("severity", severity)
297
- event.set("facility", facility)
298
-
299
- event.set("timestamp", event.get("timestamp8601")) if event.include?("timestamp8601")
300
- @date_filter.filter(event)
332
+ priority = event.get(@priority_key).to_i rescue 13
333
+ set_priority event, priority
334
+
335
+ @date_filter_exec.(event)
336
+
301
337
  else
302
- @logger.debug? && @logger.debug("NOT SYSLOG", :message => event.get("message"))
338
+ @logger.debug? && @logger.debug("un-matched syslog message", :message => event.get("message"))
303
339
 
304
340
  # RFC3164 says unknown messages get pri=13
305
- priority = 13
306
- event.set("priority", 13)
307
- event.set("severity", 5) # 13 & 7 == 5
308
- event.set("facility", 1) # 13 >> 3 == 1
341
+ set_priority event, 13
309
342
  metric.increment(:unknown_messages)
310
343
  end
311
344
 
312
- # Apply severity and facility metadata if
313
- # use_labels => true
314
- if @use_labels
315
- facility_number = event.get("facility")
316
- severity_number = event.get("severity")
345
+ # Apply severity and facility metadata if use_labels => true
346
+ set_labels(event) if @use_labels
347
+ end # def syslog_relay
348
+ public :syslog_relay
349
+
350
+ def set_priority(event, priority)
351
+ severity = priority & 7 # 7 is 111 (3 bits)
352
+ facility = priority >> 3
353
+ event.set(@priority_key, priority)
354
+ event.set(@severity_key, severity)
355
+ event.set(@facility_key, facility)
356
+ end
317
357
 
318
- if @facility_labels[facility_number]
319
- event.set("facility_label", @facility_labels[facility_number])
320
- end
358
+ def set_labels(event)
359
+ facility_number = event.get(@facility_key)
360
+ severity_number = event.get(@severity_key)
321
361
 
322
- if @severity_labels[severity_number]
323
- event.set("severity_label", @severity_labels[severity_number])
324
- end
362
+ facility_label = @facility_labels[facility_number]
363
+ event.set(@facility_label_key, facility_label) if facility_label
364
+
365
+ severity_label = @severity_labels[severity_number]
366
+ event.set(@severity_label_key, severity_label) if severity_label
367
+ end
368
+
369
+ def set_service_fields(event)
370
+ service_type = @service_type
371
+ if service_type && !service_type.empty?
372
+ event.set('[service][type]', service_type) unless event.include?('[service][type]')
325
373
  end
326
- end # def syslog_relay
374
+ end
375
+
327
376
  end # class LogStash::Inputs::Syslog
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
 
3
3
  s.name = 'logstash-input-syslog'
4
- s.version = '3.4.3'
4
+ s.version = '3.6.0'
5
5
  s.licenses = ['Apache License (2.0)']
6
6
  s.summary = "Reads syslog messages as events"
7
7
  s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
@@ -21,16 +21,16 @@ Gem::Specification.new do |s|
21
21
 
22
22
  # Gem dependencies
23
23
  s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
24
+ s.add_runtime_dependency 'logstash-mixin-ecs_compatibility_support', '~> 1.2'
24
25
 
25
26
  s.add_runtime_dependency 'concurrent-ruby'
26
27
  s.add_runtime_dependency 'stud', '>= 0.0.22', '< 0.1.0'
27
28
 
28
29
  s.add_runtime_dependency 'logstash-codec-plain'
29
- s.add_runtime_dependency 'logstash-filter-grok'
30
+ s.add_runtime_dependency 'logstash-filter-grok', '>= 4.4.1'
30
31
  s.add_runtime_dependency 'logstash-filter-date'
31
32
 
32
- s.add_development_dependency 'logstash-devutils'
33
- s.add_development_dependency 'insist'
33
+ s.add_development_dependency 'logstash-devutils', '~> 2.3'
34
34
  s.add_development_dependency 'logstash-codec-cef'
35
35
  end
36
36
 
@@ -1,8 +1,9 @@
1
1
  # encoding: utf-8
2
2
  require "logstash/devutils/rspec/spec_helper"
3
- require "insist"
4
3
  require "logstash/devutils/rspec/shared_examples"
5
4
 
5
+ require 'logstash/plugin_mixins/ecs_compatibility_support/spec_helper'
6
+
6
7
  # running the grok code outside a logstash package means
7
8
  # LOGSTASH_HOME will not be defined, so let's set it here
8
9
  # before requiring the grok filter
@@ -33,7 +34,7 @@ describe LogStash::Inputs::Syslog do
33
34
  SYSLOG_LINE = "<164>Oct 26 15:19:25 1.2.3.4 %ASA-4-106023: Deny udp src DRAC:10.1.2.3/43434 dst outside:192.168.0.1/53 by access-group \"acl_drac\" [0x0, 0x0]"
34
35
 
35
36
  it "should properly handle priority, severity and facilities" do
36
- skip 'elastic/logstash#11196 known LS 7.5 issue' if ENV['ELASTIC_STACK_VERSION'] && JRUBY_VERSION.eql?('9.2.8.0')
37
+ skip_if_stack_known_issue
37
38
  port = 5511
38
39
  event_count = 10
39
40
  conf = <<-CONFIG
@@ -55,16 +56,16 @@ describe LogStash::Inputs::Syslog do
55
56
  event_count.times.collect { queue.pop }
56
57
  end
57
58
 
58
- insist { events.length } == event_count
59
+ expect( events.length ).to eql event_count
59
60
  events.each do |event|
60
- insist { event.get("priority") } == 164
61
- insist { event.get("severity") } == 4
62
- insist { event.get("facility") } == 20
61
+ expect( event.get("priority") ).to eql 164
62
+ expect( event.get("severity") ).to eql 4
63
+ expect( event.get("facility") ).to eql 20
63
64
  end
64
65
  end
65
66
 
66
67
  it "should properly PROXY protocol v1" do
67
- skip 'elastic/logstash#11196 known LS 7.5 issue' if ENV['ELASTIC_STACK_VERSION'] && JRUBY_VERSION.eql?('9.2.8.0')
68
+ skip_if_stack_known_issue
68
69
  port = 5511
69
70
  event_count = 10
70
71
  conf = <<-CONFIG
@@ -89,110 +90,200 @@ describe LogStash::Inputs::Syslog do
89
90
  event_count.times.collect { queue.pop }
90
91
  end
91
92
 
92
- insist { events.length } == event_count
93
+ expect( events.length ).to eql event_count
93
94
  events.each do |event|
94
- insist { event.get("priority") } == 164
95
- insist { event.get("severity") } == 4
96
- insist { event.get("facility") } == 20
97
- insist { event.get("host") } == "1.2.3.4"
95
+ expect( event.get("priority") ).to eql 164
96
+ expect( event.get("severity") ).to eql 4
97
+ expect( event.get("facility") ).to eql 20
98
+ expect( event.get("host") ).to eql "1.2.3.4"
98
99
  end
99
100
  end
100
101
 
101
- it "should add unique tag when grok parsing fails with live syslog input" do
102
- skip 'elastic/logstash#11196 known LS 7.5 issue' if ENV['ELASTIC_STACK_VERSION'] && JRUBY_VERSION.eql?('9.2.8.0')
103
- port = 5511
104
- event_count = 10
105
- conf = <<-CONFIG
106
- input {
107
- syslog {
108
- type => "blah"
109
- port => #{port}
110
- }
111
- }
112
- CONFIG
102
+ context 'tag', :ecs_compatibility_support do
103
+ ecs_compatibility_matrix(:disabled, :v1, :v8 => :v1) do
113
104
 
114
- events = input(conf) do |pipeline, queue|
115
- socket = Stud.try(5.times) { TCPSocket.new("127.0.0.1", port) }
116
- event_count.times do |i|
117
- socket.puts("message which causes the a grok parse failure")
105
+ before(:each) do
106
+ allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(ecs_compatibility)
118
107
  end
119
- socket.close
120
108
 
121
- event_count.times.collect { queue.pop }
122
- end
109
+ it "should add unique tag when grok parsing fails with live syslog input" do
110
+ skip_if_stack_known_issue
111
+ port = 5511
112
+ event_count = 10
113
+ conf = <<-CONFIG
114
+ input {
115
+ syslog {
116
+ type => "blah"
117
+ port => #{port}
118
+ }
119
+ }
120
+ CONFIG
121
+
122
+ events = input(conf) do |pipeline, queue|
123
+ socket = Stud.try(5.times) { TCPSocket.new("127.0.0.1", port) }
124
+ event_count.times do |i|
125
+ socket.puts("message which causes the a grok parse failure")
126
+ end
127
+ socket.close
128
+
129
+ event_count.times.collect { queue.pop }
130
+ end
131
+
132
+ expect( events.length ).to eql event_count
133
+ event_count.times do |i|
134
+ expect( events[i].get("tags") ).to eql ["_grokparsefailure_sysloginput"]
135
+ end
136
+ end
123
137
 
124
- insist { events.length } == event_count
125
- event_count.times do |i|
126
- insist { events[i].get("tags") } == ["_grokparsefailure_sysloginput"]
127
138
  end
128
139
  end
129
140
 
130
- it "should properly handle locale and timezone" do
131
- port = 5511
132
- event_count = 10
141
+ context 'timestamp', :ecs_compatibility_support do
142
+ ecs_compatibility_matrix(:disabled, :v1) do
133
143
 
134
- conf = <<-CONFIG
135
- input {
136
- syslog {
137
- type => "blah"
138
- port => #{port}
139
- locale => "en"
140
- timezone => "UTC"
141
- }
142
- }
143
- CONFIG
144
+ before(:each) do
145
+ allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(ecs_compatibility)
146
+ end
144
147
 
145
- events = input(conf) do |pipeline, queue|
146
- socket = Stud.try(5.times) { TCPSocket.new("127.0.0.1", port) }
147
- event_count.times do |i|
148
- socket.puts(SYSLOG_LINE)
148
+ it "should properly handle locale and timezone" do
149
+ port = 5511
150
+ event_count = 10
151
+
152
+ conf = <<-CONFIG
153
+ input {
154
+ syslog {
155
+ type => "blah"
156
+ port => #{port}
157
+ locale => "en"
158
+ timezone => "UTC"
159
+ }
160
+ }
161
+ CONFIG
162
+
163
+ events = input(conf) do |pipeline, queue|
164
+ socket = Stud.try(5.times) { TCPSocket.new("127.0.0.1", port) }
165
+ event_count.times do |i|
166
+ socket.puts(SYSLOG_LINE)
167
+ end
168
+ socket.close
169
+
170
+ event_count.times.collect { queue.pop }
171
+ end
172
+
173
+ expect( events.length ).to eql event_count
174
+ events.each do |event|
175
+ expect( event.get("@timestamp") ).to be_a_logstash_timestamp_equivalent_to("#{Time.now.year}-10-26T15:19:25Z")
176
+ end
149
177
  end
150
- socket.close
151
178
 
152
- event_count.times.collect { queue.pop }
153
- end
179
+ it "should properly handle no locale and no timezone" do
180
+ port = 5511
181
+
182
+ conf = <<-CONFIG
183
+ input {
184
+ syslog {
185
+ type => "blah"
186
+ port => #{port}
187
+ }
188
+ }
189
+ CONFIG
190
+
191
+ event = input(conf) do |pipeline, queue|
192
+ socket = Stud.try(5.times) { TCPSocket.new("127.0.0.1", port) }
193
+ socket.puts(SYSLOG_LINE)
194
+ socket.close
195
+
196
+ queue.pop
197
+ end
198
+
199
+ # chances platform timezone is not UTC, so parse without offset to create expectation
200
+ equivalent_time = Time.parse("#{Time.now.year}-10-26T15:19:25")
201
+ expect( event.get("@timestamp") ).to be_a_logstash_timestamp_equivalent_to(equivalent_time)
202
+ end
203
+
204
+ it "should support non UTC timezone" do
205
+ input = LogStash::Inputs::Syslog.new({"timezone" => "-05:00"})
206
+ input.register
207
+
208
+ # event which is not syslog should have a new tag
209
+
210
+ syslog_event = LogStash::Event.new({ "message" => "<164>Oct 26 15:19:25 1.2.3.4 %ASA-4-106023: Deny udp src DRAC:10.1.2.3/43434" })
211
+ input.syslog_relay(syslog_event)
212
+
213
+ expect( syslog_event.get("@timestamp") ).to be_a_logstash_timestamp_equivalent_to("#{Time.now.year}-10-26T20:19:25Z")
214
+
215
+ input.close
216
+ end
154
217
 
155
- insist { events.length } == event_count
156
- events.each do |event|
157
- insist { event.get("@timestamp").to_iso8601 } == "#{Time.now.year}-10-26T15:19:25.000Z"
158
218
  end
159
219
  end
160
220
 
161
- it "should properly handle no locale and no timezone" do
162
- port = 5511
221
+ context 'ECS behavior', :ecs_compatibility_support do
163
222
 
164
- conf = <<-CONFIG
165
- input {
166
- syslog {
167
- type => "blah"
168
- port => #{port}
169
- }
170
- }
171
- CONFIG
223
+ ecs_compatibility_matrix(:v1) do
172
224
 
173
- event = input(conf) do |pipeline, queue|
174
- socket = Stud.try(5.times) { TCPSocket.new("127.0.0.1", port) }
175
- socket.puts(SYSLOG_LINE)
176
- socket.close
225
+ before(:each) do
226
+ allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(ecs_compatibility)
227
+ end
177
228
 
178
- queue.pop
179
- end
229
+ let(:event) do
230
+ LogStash::Event.new("message" => "<164>Oct 26 15:19:25 1.2.3.4 a sample message")
231
+ end
180
232
 
181
- # chances platform timezone is not UTC so ignore the hours
182
- insist { event.get("@timestamp").to_iso8601 } =~ /#{Time.now.year}-10-26T\d\d:19:25.000Z/
183
- end
233
+ subject { LogStash::Inputs::Syslog.new }
184
234
 
185
- it "should support non UTC timezone" do
186
- input = LogStash::Inputs::Syslog.new({"timezone" => "-05:00"})
187
- input.register
235
+ before { subject.register }
236
+ after { subject.close }
188
237
 
189
- # event which is not syslog should have a new tag
238
+ it "should not have a timestamp field" do
239
+ subject.syslog_relay(event)
190
240
 
191
- syslog_event = LogStash::Event.new({ "message" => "<164>Oct 26 15:19:25 1.2.3.4 %ASA-4-106023: Deny udp src DRAC:10.1.2.3/43434" })
192
- input.syslog_relay(syslog_event)
193
- insist { syslog_event.get("@timestamp").to_iso8601 } == "#{Time.now.year}-10-26T20:19:25.000Z"
241
+ expect( event.to_hash.keys ).to_not include 'timestamp'
242
+ end
194
243
 
195
- input.close
244
+ it "overwrites message" do
245
+ subject.syslog_relay(event)
246
+
247
+ expect( event.get('message') ).to eql 'a sample message'
248
+ end
249
+
250
+ it "keep original log message" do
251
+ subject.syslog_relay(event)
252
+
253
+ expect( event.get('[event][original]') ).to eql '<164>Oct 26 15:19:25 1.2.3.4 a sample message'
254
+ end
255
+
256
+ it "sets syslog priority and severity" do
257
+ subject.syslog_relay(event)
258
+
259
+ expect( event.get('log') ).to include 'syslog' => hash_including('priority' => 164)
260
+ expect( event.get('log') ).to include 'syslog' => hash_including('severity' => { 'code' => 4, 'name' => 'Warning' })
261
+ end
262
+
263
+ it "sets service type" do
264
+ subject.syslog_relay(event)
265
+
266
+ expect( event.get('service') ).to include 'type' => 'system'
267
+ end
268
+
269
+ let(:queue) { Queue.new }
270
+
271
+ let(:socket) do
272
+ server = double('tcp-server')
273
+ allow( server ).to receive(:each).and_yield "<133>Mar 11 08:44:43 precision kernel: [765135.424096] mce: CPU6: Package temperature/speed normal\n"
274
+ allow( server ).to receive(:close)
275
+ server
276
+ end
277
+
278
+ it "sets host IP" do
279
+ expect( socket ).to receive(:peeraddr).and_return(["AF_INET", 514, "192.168.0.10", "192.168.0.10"])
280
+ subject.send :tcp_receiver, queue, socket
281
+
282
+ expect( queue.size ).to eql 1
283
+ event = queue.pop
284
+ expect( event.get('host') ).to eql 'hostname' => 'precision', 'ip' => '192.168.0.10'
285
+ end
286
+ end
196
287
  end
197
288
 
198
289
  it "should add unique tag when grok parsing fails" do
@@ -202,13 +293,13 @@ describe LogStash::Inputs::Syslog do
202
293
  # event which is not syslog should have a new tag
203
294
  event = LogStash::Event.new({ "message" => "hello world, this is not syslog RFC3164" })
204
295
  input.syslog_relay(event)
205
- insist { event.get("tags") } == ["_grokparsefailure_sysloginput"]
296
+ expect( event.get("tags") ).to eql ["_grokparsefailure_sysloginput"]
206
297
 
207
298
  syslog_event = LogStash::Event.new({ "message" => "<164>Oct 26 15:19:25 1.2.3.4 %ASA-4-106023: Deny udp src DRAC:10.1.2.3/43434" })
208
299
  input.syslog_relay(syslog_event)
209
- insist { syslog_event.get("priority") } == 164
210
- insist { syslog_event.get("severity") } == 4
211
- insist { syslog_event.get("tags") } == nil
300
+ expect( syslog_event.get("priority") ).to eql 164
301
+ expect( syslog_event.get("severity") ).to eql 4
302
+ expect( syslog_event.get("tags") ).to be nil
212
303
 
213
304
  input.close
214
305
  end
@@ -245,13 +336,13 @@ describe LogStash::Inputs::Syslog do
245
336
  event_count.times.collect { queue.pop }
246
337
  end
247
338
 
248
- insist { events.length } == event_count
339
+ expect( events.length ).to eql event_count
249
340
  events.each do |event|
250
- insist { event.get("priority") } == 164
251
- insist { event.get("severity") } == 4
252
- insist { event.get("facility") } == 20
253
- insist { event.get("message") } == "#{message_field}\n"
254
- insist { event.get("timestamp") } == timestamp
341
+ expect( event.get("priority") ).to eql 164
342
+ expect( event.get("severity") ).to eql 4
343
+ expect( event.get("facility") ).to eql 20
344
+ expect( event.get("message") ).to eql "#{message_field}\n"
345
+ expect( event.get("timestamp") ).to eql timestamp
255
346
  end
256
347
  end
257
348
 
@@ -284,13 +375,19 @@ describe LogStash::Inputs::Syslog do
284
375
  event_count.times.collect { queue.pop }
285
376
  end
286
377
 
287
- insist { events.length } == event_count
378
+ expect( events.length ).to eql event_count
288
379
  events.each do |event|
289
- insist { event.get("priority") } == 134
290
- insist { event.get("severity") } == 6
291
- insist { event.get("facility") } == 16
292
- insist { event.get("message") } == message_field
293
- insist { event.get("timestamp") } == timestamp
380
+ expect( event.get("priority") ).to eql 134
381
+ expect( event.get("severity") ).to eql 6
382
+ expect( event.get("facility") ).to eql 16
383
+ expect( event.get("message") ).to eql message_field
384
+ expect( event.get("timestamp") ).to eql timestamp
294
385
  end
295
386
  end
387
+
388
+ private
389
+
390
+ def skip_if_stack_known_issue
391
+ skip 'elastic/logstash#11196 known LS 7.5 issue' if ENV['ELASTIC_STACK_VERSION'] && JRUBY_VERSION.eql?('9.2.8.0')
392
+ end
296
393
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-input-syslog
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.3
4
+ version: 3.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-19 00:00:00.000000000 Z
11
+ date: 2021-11-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -30,6 +30,20 @@ dependencies:
30
30
  - - "<="
31
31
  - !ruby/object:Gem::Version
32
32
  version: '2.99'
33
+ - !ruby/object:Gem::Dependency
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - "~>"
37
+ - !ruby/object:Gem::Version
38
+ version: '1.2'
39
+ name: logstash-mixin-ecs_compatibility_support
40
+ prerelease: false
41
+ type: :runtime
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.2'
33
47
  - !ruby/object:Gem::Dependency
34
48
  requirement: !ruby/object:Gem::Requirement
35
49
  requirements:
@@ -83,7 +97,7 @@ dependencies:
83
97
  requirements:
84
98
  - - ">="
85
99
  - !ruby/object:Gem::Version
86
- version: '0'
100
+ version: 4.4.1
87
101
  name: logstash-filter-grok
88
102
  prerelease: false
89
103
  type: :runtime
@@ -91,7 +105,7 @@ dependencies:
91
105
  requirements:
92
106
  - - ">="
93
107
  - !ruby/object:Gem::Version
94
- version: '0'
108
+ version: 4.4.1
95
109
  - !ruby/object:Gem::Dependency
96
110
  requirement: !ruby/object:Gem::Requirement
97
111
  requirements:
@@ -109,31 +123,17 @@ dependencies:
109
123
  - !ruby/object:Gem::Dependency
110
124
  requirement: !ruby/object:Gem::Requirement
111
125
  requirements:
112
- - - ">="
126
+ - - "~>"
113
127
  - !ruby/object:Gem::Version
114
- version: '0'
128
+ version: '2.3'
115
129
  name: logstash-devutils
116
130
  prerelease: false
117
131
  type: :development
118
132
  version_requirements: !ruby/object:Gem::Requirement
119
133
  requirements:
120
- - - ">="
121
- - !ruby/object:Gem::Version
122
- version: '0'
123
- - !ruby/object:Gem::Dependency
124
- requirement: !ruby/object:Gem::Requirement
125
- requirements:
126
- - - ">="
127
- - !ruby/object:Gem::Version
128
- version: '0'
129
- name: insist
130
- prerelease: false
131
- type: :development
132
- version_requirements: !ruby/object:Gem::Requirement
133
- requirements:
134
- - - ">="
134
+ - - "~>"
135
135
  - !ruby/object:Gem::Version
136
- version: '0'
136
+ version: '2.3'
137
137
  - !ruby/object:Gem::Dependency
138
138
  requirement: !ruby/object:Gem::Requirement
139
139
  requirements:
@@ -187,8 +187,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
187
187
  - !ruby/object:Gem::Version
188
188
  version: '0'
189
189
  requirements: []
190
- rubyforge_project:
191
- rubygems_version: 2.6.13
190
+ rubygems_version: 3.1.6
192
191
  signing_key:
193
192
  specification_version: 4
194
193
  summary: Reads syslog messages as events