logstash-input-syslog 3.4.3 → 3.6.0

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: 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