logstash-input-syslog 3.4.5 → 3.5.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: 78d3ae407146832319799963b5ca4a436fda4936a75e1985261c8b4439acedec
4
- data.tar.gz: a59e5ea7f49ced6e7a9c75d4f30154733e4ad9413a1be01e309848e5802b7fac
3
+ metadata.gz: 6f54c37d7c50508f001a49df641a45df74cf61cf4c4a4fcebafef442e380df68
4
+ data.tar.gz: 8c269bbad63b3ee0b022e7e206fc0884ed213b38380b15bdda9ee421e7f8ebeb
5
5
  SHA512:
6
- metadata.gz: 3e9d73ad662d26e0a1a49b6700e8da99050982da9c36766473eb21742279e8117091fbfa1b6ab7d11958d6e015754eb7a4547c2795782fcd9081557510ca8097
7
- data.tar.gz: 2cf5e512229804e7dc0f99cded9070cf48d5f2d4ac73c107e60c242b453b55fce8832b6b71ee1766778d61719da39687806bd57c913d784556684c98f32a144f
6
+ metadata.gz: 8c886952d2095e9cefddeaaebbefa8495b78732b74350a6579849dd22da8f85f3065a35b411ce8952cd2cb12a80d49468cb44eeabfac4d93d8610663f7536366
7
+ data.tar.gz: a254785ecca431fc409bd2ebd031a14b2901295f2293913c6d7f92629327e8694e1ee2e13e7e04898cdc7c1939f29b1a6bb674e5dbc183b7c5c1487146d47284
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ ## 3.5.0
2
+ - Feat: ECS compatibility support [#63](https://github.com/logstash-plugins/logstash-input-syslog/pull/63)
3
+
1
4
  ## 3.4.5
2
5
  - Added support for listening on IPv6 addresses
3
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`: 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)
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
@@ -74,22 +77,67 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
74
77
  #
75
78
  config :locale, :validate => :string
76
79
 
77
- public
78
- def register
79
- @metric_errors = metric.namespace(:errors)
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)
87
+ super
88
+
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
+ ]
80
102
 
81
103
  @grok_filter = LogStash::Filters::Grok.new(
82
- "overwrite" => @syslog_field,
83
- "match" => { @syslog_field => @grok_pattern },
84
- "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
85
108
  )
86
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
+
87
119
  @date_filter = LogStash::Filters::Date.new(
88
- "match" => [ "timestamp", "MMM dd HH:mm:ss", "MMM d HH:mm:ss", "ISO8601"],
89
- "locale" => @locale,
90
- "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,
91
123
  )
92
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
+
93
141
  @grok_filter.register
94
142
  @date_filter.register
95
143
 
@@ -97,7 +145,8 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
97
145
  @tcp = @udp = nil
98
146
  end # def register
99
147
 
100
- public
148
+ private
149
+
101
150
  def run(output_queue)
102
151
  udp_thr = Thread.new(output_queue) do |output_queue|
103
152
  server(:udp, output_queue)
@@ -112,8 +161,8 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
112
161
  udp_thr.join
113
162
  tcp_thr.join
114
163
  end # def run
164
+ public :run
115
165
 
116
- private
117
166
  # server call the specified protocol listener and basically restarts on
118
167
  # any listener uncatched exception
119
168
  #
@@ -130,7 +179,6 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
130
179
  end
131
180
  end
132
181
 
133
- private
134
182
  # udp_listener creates the udp socket and continously read from it.
135
183
  # upon exception the socket will be closed and the exception bubbled
136
184
  # in the server which will restart the listener
@@ -151,7 +199,6 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
151
199
  close_udp
152
200
  end # def udp_listener
153
201
 
154
- private
155
202
  # tcp_listener accepts tcp connections and creates a new tcp_receiver thread
156
203
  # for each accepted socket.
157
204
  # upon exception all tcp sockets will be closed and the exception bubbled
@@ -177,11 +224,14 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
177
224
  # tcp_receiver is executed in a thread, any uncatched exception will be bubbled up to the
178
225
  # tcp server thread and all tcp connections will be closed and the listener restarted.
179
226
  def tcp_receiver(output_queue, socket)
180
- ip, port = socket.peeraddr[3], socket.peeraddr[1]
181
- first_read = true
227
+ peer_addr = socket.peeraddr
228
+ ip, port = peer_addr[3], peer_addr[1]
229
+
182
230
  @logger.info("new connection", :client => "#{ip}:#{port}")
183
231
  LogStash::Util::set_thread_name("input|syslog|tcp|#{ip}:#{port}}")
184
232
 
233
+ first_read = true
234
+
185
235
  socket.each do |line|
186
236
  metric.increment(:messages_received)
187
237
  if @proxy_protocol && first_read
@@ -189,10 +239,10 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
189
239
  pp_info = line.split(/\s/)
190
240
  # PROXY proto clientip proxyip clientport proxyport
191
241
  if pp_info[0] != "PROXY"
192
- @logger.error("invalid proxy protocol header label", :hdr => line)
242
+ @logger.error("invalid proxy protocol header label", header: line)
193
243
  raise IOError
194
244
  else
195
- # would be nice to log the proxy host and port data as well, but minimizing changes
245
+ @logger.debug("proxy protocol detected", header: line)
196
246
  ip = pp_info[2]
197
247
  port = pp_info[3]
198
248
  next
@@ -206,20 +256,19 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
206
256
  rescue Errno::EBADF
207
257
  # swallow connection closed exceptions to avoid bubling up the tcp_listener & server
208
258
  logger.info("connection closed", :client => "#{ip}:#{port}")
209
- rescue IOError => ioerror
259
+ rescue IOError => e
210
260
  # swallow connection closed exceptions to avoid bubling up the tcp_listener & server
211
- raise unless socket.closed? && ioerror.message.include?("closed")
212
- 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)
213
263
  ensure
214
264
  @tcp_sockets.delete(socket)
215
265
  socket.close rescue log_and_squash(:close_tcp_receiver_socket)
216
266
  end
217
267
 
218
- private
219
- def decode(host, output_queue, data)
268
+ def decode(ip, output_queue, data)
220
269
  @codec.decode(data) do |event|
221
270
  decorate(event)
222
- event.set("host", host)
271
+ event.set(@host_key, ip)
223
272
  syslog_relay(event)
224
273
  output_queue << event
225
274
  metric.increment(:events)
@@ -230,13 +279,13 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
230
279
  @metric_errors.increment(:decoding)
231
280
  end
232
281
 
233
- public
282
+ # @see LogStash::Plugin#close
234
283
  def stop
235
284
  close_udp
236
285
  close_tcp
237
286
  end
287
+ public :stop
238
288
 
239
- private
240
289
  def close_udp
241
290
  if @udp
242
291
  @udp.close_read rescue log_and_squash(:close_udp_read)
@@ -245,8 +294,6 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
245
294
  @udp = nil
246
295
  end
247
296
 
248
- private
249
-
250
297
  # Helper for inline rescues, which logs the exception at "DEBUG" level and returns nil.
251
298
  #
252
299
  # Instead of:
@@ -276,46 +323,54 @@ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
276
323
  # If the message cannot be recognized (see @grok_filter), we'll
277
324
  # treat it like the whole event["message"] is correct and try to fill
278
325
  # the missing pieces (host, priority, etc)
279
- public
280
326
  def syslog_relay(event)
281
- @grok_filter.filter(event)
327
+ @grok_filter_exec.(event)
282
328
 
283
329
  if event.get("tags").nil? || !event.get("tags").include?(@grok_filter.tag_on_failure)
284
330
  # Per RFC3164, priority = (facility * 8) + severity
285
331
  # = (facility << 3) & (severity)
286
- priority = event.get("priority").to_i rescue 13
287
- severity = priority & 7 # 7 is 111 (3 bits)
288
- facility = priority >> 3
289
- event.set("priority", priority)
290
- event.set("severity", severity)
291
- event.set("facility", facility)
292
-
293
- event.set("timestamp", event.get("timestamp8601")) if event.include?("timestamp8601")
294
- @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
+
295
337
  else
296
- @logger.debug? && @logger.debug("NOT SYSLOG", :message => event.get("message"))
338
+ @logger.debug? && @logger.debug("un-matched syslog message", :message => event.get("message"))
297
339
 
298
340
  # RFC3164 says unknown messages get pri=13
299
- priority = 13
300
- event.set("priority", 13)
301
- event.set("severity", 5) # 13 & 7 == 5
302
- event.set("facility", 1) # 13 >> 3 == 1
341
+ set_priority event, 13
303
342
  metric.increment(:unknown_messages)
304
343
  end
305
344
 
306
- # Apply severity and facility metadata if
307
- # use_labels => true
308
- if @use_labels
309
- facility_number = event.get("facility")
310
- 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
311
357
 
312
- if @facility_labels[facility_number]
313
- event.set("facility_label", @facility_labels[facility_number])
314
- end
358
+ def set_labels(event)
359
+ facility_number = event.get(@facility_key)
360
+ severity_number = event.get(@severity_key)
315
361
 
316
- if @severity_labels[severity_number]
317
- event.set("severity_label", @severity_labels[severity_number])
318
- 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]')
319
373
  end
320
- end # def syslog_relay
374
+ end
375
+
321
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.5'
4
+ s.version = '3.5.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,12 +21,13 @@ 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.1'
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.0'
30
31
  s.add_runtime_dependency 'logstash-filter-date'
31
32
 
32
33
  s.add_development_dependency 'logstash-devutils'
@@ -2,6 +2,8 @@
2
2
  require "logstash/devutils/rspec/spec_helper"
3
3
  require "logstash/devutils/rspec/shared_examples"
4
4
 
5
+ require 'logstash/plugin_mixins/ecs_compatibility_support/spec_helper'
6
+
5
7
  # running the grok code outside a logstash package means
6
8
  # LOGSTASH_HOME will not be defined, so let's set it here
7
9
  # before requiring the grok filter
@@ -32,7 +34,7 @@ describe LogStash::Inputs::Syslog do
32
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]"
33
35
 
34
36
  it "should properly handle priority, severity and facilities" do
35
- 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
36
38
  port = 5511
37
39
  event_count = 10
38
40
  conf = <<-CONFIG
@@ -63,7 +65,7 @@ describe LogStash::Inputs::Syslog do
63
65
  end
64
66
 
65
67
  it "should properly PROXY protocol v1" do
66
- 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
67
69
  port = 5511
68
70
  event_count = 10
69
71
  conf = <<-CONFIG
@@ -97,101 +99,190 @@ describe LogStash::Inputs::Syslog do
97
99
  end
98
100
  end
99
101
 
100
- it "should add unique tag when grok parsing fails with live syslog input" do
101
- skip 'elastic/logstash#11196 known LS 7.5 issue' if ENV['ELASTIC_STACK_VERSION'] && JRUBY_VERSION.eql?('9.2.8.0')
102
- port = 5511
103
- event_count = 10
104
- conf = <<-CONFIG
105
- input {
106
- syslog {
107
- type => "blah"
108
- port => #{port}
109
- }
110
- }
111
- CONFIG
102
+ context 'tag', :ecs_compatibility_support do
103
+ ecs_compatibility_matrix(:disabled, :v1) do
112
104
 
113
- events = input(conf) do |pipeline, queue|
114
- socket = Stud.try(5.times) { TCPSocket.new("127.0.0.1", port) }
115
- event_count.times do |i|
116
- 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)
117
107
  end
118
- socket.close
119
108
 
120
- event_count.times.collect { queue.pop }
121
- 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
122
137
 
123
- expect( events.length ).to eql event_count
124
- event_count.times do |i|
125
- expect( events[i].get("tags") ).to eql ["_grokparsefailure_sysloginput"]
126
138
  end
127
139
  end
128
140
 
129
- it "should properly handle locale and timezone" do
130
- port = 5511
131
- event_count = 10
141
+ context 'timestamp', :ecs_compatibility_support do
142
+ ecs_compatibility_matrix(:disabled, :v1) do
132
143
 
133
- conf = <<-CONFIG
134
- input {
135
- syslog {
136
- type => "blah"
137
- port => #{port}
138
- locale => "en"
139
- timezone => "UTC"
140
- }
141
- }
142
- CONFIG
144
+ before(:each) do
145
+ allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(ecs_compatibility)
146
+ end
143
147
 
144
- events = input(conf) do |pipeline, queue|
145
- socket = Stud.try(5.times) { TCPSocket.new("127.0.0.1", port) }
146
- event_count.times do |i|
147
- 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_iso8601 ).to eql "#{Time.now.year}-10-26T15:19:25.000Z"
176
+ end
148
177
  end
149
- socket.close
150
178
 
151
- event_count.times.collect { queue.pop }
152
- 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 ignore the hours
200
+ expect( event.get("@timestamp").to_iso8601 ).to match /#{Time.now.year}-10-26T\d\d:19:25.000Z/
201
+ end
202
+
203
+ it "should support non UTC timezone" do
204
+ input = LogStash::Inputs::Syslog.new({"timezone" => "-05:00"})
205
+ input.register
206
+
207
+ # event which is not syslog should have a new tag
208
+
209
+ 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" })
210
+ input.syslog_relay(syslog_event)
211
+
212
+ expect( syslog_event.get("@timestamp").to_iso8601 ).to eql "#{Time.now.year}-10-26T20:19:25.000Z"
213
+
214
+ input.close
215
+ end
153
216
 
154
- expect( events.length ).to eql event_count
155
- events.each do |event|
156
- expect( event.get("@timestamp").to_iso8601 ).to eql "#{Time.now.year}-10-26T15:19:25.000Z"
157
217
  end
158
218
  end
159
219
 
160
- it "should properly handle no locale and no timezone" do
161
- port = 5511
220
+ context 'ECS behavior', :ecs_compatibility_support do
162
221
 
163
- conf = <<-CONFIG
164
- input {
165
- syslog {
166
- type => "blah"
167
- port => #{port}
168
- }
169
- }
170
- CONFIG
222
+ ecs_compatibility_matrix(:v1) do
171
223
 
172
- event = input(conf) do |pipeline, queue|
173
- socket = Stud.try(5.times) { TCPSocket.new("127.0.0.1", port) }
174
- socket.puts(SYSLOG_LINE)
175
- socket.close
224
+ before(:each) do
225
+ allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(ecs_compatibility)
226
+ end
176
227
 
177
- queue.pop
178
- end
228
+ let(:event) do
229
+ LogStash::Event.new("message" => "<164>Oct 26 15:19:25 1.2.3.4 a sample message")
230
+ end
179
231
 
180
- # chances platform timezone is not UTC so ignore the hours
181
- expect( event.get("@timestamp").to_iso8601 ).to match /#{Time.now.year}-10-26T\d\d:19:25.000Z/
182
- end
232
+ subject { LogStash::Inputs::Syslog.new }
183
233
 
184
- it "should support non UTC timezone" do
185
- input = LogStash::Inputs::Syslog.new({"timezone" => "-05:00"})
186
- input.register
234
+ before { subject.register }
235
+ after { subject.close }
187
236
 
188
- # event which is not syslog should have a new tag
237
+ it "should not have a timestamp field" do
238
+ subject.syslog_relay(event)
189
239
 
190
- 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" })
191
- input.syslog_relay(syslog_event)
192
- expect( syslog_event.get("@timestamp").to_iso8601 ).to eql "#{Time.now.year}-10-26T20:19:25.000Z"
240
+ expect( event.to_hash.keys ).to_not include 'timestamp'
241
+ end
193
242
 
194
- input.close
243
+ it "overwrites message" do
244
+ subject.syslog_relay(event)
245
+
246
+ expect( event.get('message') ).to eql 'a sample message'
247
+ end
248
+
249
+ it "keep original log message" do
250
+ subject.syslog_relay(event)
251
+
252
+ expect( event.get('[event][original]') ).to eql '<164>Oct 26 15:19:25 1.2.3.4 a sample message'
253
+ end
254
+
255
+ it "sets syslog priority and severity" do
256
+ subject.syslog_relay(event)
257
+
258
+ expect( event.get('log') ).to include 'syslog' => hash_including('priority' => 164)
259
+ expect( event.get('log') ).to include 'syslog' => hash_including('severity' => { 'code' => 4, 'name' => 'Warning' })
260
+ end
261
+
262
+ it "sets service type" do
263
+ subject.syslog_relay(event)
264
+
265
+ expect( event.get('service') ).to include 'type' => 'system'
266
+ end
267
+
268
+ let(:queue) { Queue.new }
269
+
270
+ let(:socket) do
271
+ server = double('tcp-server')
272
+ allow( server ).to receive(:each).and_yield "<133>Mar 11 08:44:43 precision kernel: [765135.424096] mce: CPU6: Package temperature/speed normal\n"
273
+ allow( server ).to receive(:close)
274
+ server
275
+ end
276
+
277
+ it "sets host IP" do
278
+ expect( socket ).to receive(:peeraddr).and_return(["AF_INET", 514, "192.168.0.10", "192.168.0.10"])
279
+ subject.send :tcp_receiver, queue, socket
280
+
281
+ expect( queue.size ).to eql 1
282
+ event = queue.pop
283
+ expect( event.get('host') ).to eql 'hostname' => 'precision', 'ip' => '192.168.0.10'
284
+ end
285
+ end
195
286
  end
196
287
 
197
288
  it "should add unique tag when grok parsing fails" do
@@ -292,4 +383,10 @@ describe LogStash::Inputs::Syslog do
292
383
  expect( event.get("timestamp") ).to eql timestamp
293
384
  end
294
385
  end
386
+
387
+ private
388
+
389
+ def skip_if_stack_known_issue
390
+ skip 'elastic/logstash#11196 known LS 7.5 issue' if ENV['ELASTIC_STACK_VERSION'] && JRUBY_VERSION.eql?('9.2.8.0')
391
+ end
295
392
  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.5
4
+ version: 3.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-11 00:00:00.000000000 Z
11
+ date: 2021-03-22 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.1'
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.1'
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.0
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.0
95
109
  - !ruby/object:Gem::Dependency
96
110
  requirement: !ruby/object:Gem::Requirement
97
111
  requirements: