logstash-patterns-core 4.0.2 → 4.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +149 -8
  3. data/CONTRIBUTORS +1 -0
  4. data/Gemfile +11 -1
  5. data/LICENSE +199 -10
  6. data/README.md +12 -19
  7. data/lib/logstash/patterns/core.rb +11 -3
  8. data/logstash-patterns-core.gemspec +1 -1
  9. data/patterns/ecs-v1/aws +28 -0
  10. data/patterns/ecs-v1/bacula +53 -0
  11. data/patterns/ecs-v1/bind +13 -0
  12. data/patterns/ecs-v1/bro +30 -0
  13. data/patterns/ecs-v1/exim +26 -0
  14. data/patterns/ecs-v1/firewalls +111 -0
  15. data/patterns/ecs-v1/grok-patterns +95 -0
  16. data/patterns/ecs-v1/haproxy +40 -0
  17. data/patterns/ecs-v1/httpd +17 -0
  18. data/patterns/ecs-v1/java +34 -0
  19. data/patterns/ecs-v1/junos +13 -0
  20. data/patterns/ecs-v1/linux-syslog +16 -0
  21. data/patterns/ecs-v1/maven +1 -0
  22. data/patterns/ecs-v1/mcollective +4 -0
  23. data/patterns/ecs-v1/mongodb +7 -0
  24. data/patterns/ecs-v1/nagios +124 -0
  25. data/patterns/ecs-v1/postgresql +2 -0
  26. data/patterns/ecs-v1/rails +13 -0
  27. data/patterns/ecs-v1/redis +3 -0
  28. data/patterns/ecs-v1/ruby +2 -0
  29. data/patterns/ecs-v1/squid +6 -0
  30. data/patterns/ecs-v1/zeek +33 -0
  31. data/patterns/legacy/aws +14 -0
  32. data/patterns/{bacula → legacy/bacula} +5 -5
  33. data/patterns/legacy/bind +3 -0
  34. data/patterns/{bro → legacy/bro} +0 -0
  35. data/patterns/{exim → legacy/exim} +8 -2
  36. data/patterns/{firewalls → legacy/firewalls} +7 -2
  37. data/patterns/{grok-patterns → legacy/grok-patterns} +5 -13
  38. data/patterns/{haproxy → legacy/haproxy} +1 -1
  39. data/patterns/legacy/httpd +15 -0
  40. data/patterns/{java → legacy/java} +1 -4
  41. data/patterns/{junos → legacy/junos} +0 -0
  42. data/patterns/{linux-syslog → legacy/linux-syslog} +1 -1
  43. data/patterns/legacy/maven +1 -0
  44. data/patterns/{mcollective → legacy/mcollective} +0 -0
  45. data/patterns/{mcollective-patterns → legacy/mcollective-patterns} +0 -0
  46. data/patterns/{mongodb → legacy/mongodb} +0 -0
  47. data/patterns/{nagios → legacy/nagios} +1 -1
  48. data/patterns/{postgresql → legacy/postgresql} +0 -0
  49. data/patterns/{rails → legacy/rails} +0 -0
  50. data/patterns/legacy/redis +3 -0
  51. data/patterns/{ruby → legacy/ruby} +0 -0
  52. data/patterns/legacy/squid +4 -0
  53. data/spec/patterns/aws_spec.rb +395 -0
  54. data/spec/patterns/bacula_spec.rb +367 -0
  55. data/spec/patterns/bind_spec.rb +78 -0
  56. data/spec/patterns/bro_spec.rb +613 -0
  57. data/spec/patterns/core_spec.rb +271 -16
  58. data/spec/patterns/exim_spec.rb +201 -0
  59. data/spec/patterns/firewalls_spec.rb +683 -49
  60. data/spec/patterns/haproxy_spec.rb +253 -28
  61. data/spec/patterns/httpd_spec.rb +291 -10
  62. data/spec/patterns/java_spec.rb +375 -0
  63. data/spec/patterns/junos_spec.rb +101 -0
  64. data/spec/patterns/maven_spec.rb +61 -0
  65. data/spec/patterns/mcollective_spec.rb +35 -0
  66. data/spec/patterns/mongodb_spec.rb +170 -33
  67. data/spec/patterns/nagios_spec.rb +299 -78
  68. data/spec/patterns/netscreen_spec.rb +123 -0
  69. data/spec/patterns/rails3_spec.rb +87 -29
  70. data/spec/patterns/redis_spec.rb +207 -0
  71. data/spec/patterns/shorewall_spec.rb +85 -74
  72. data/spec/patterns/squid_spec.rb +139 -0
  73. data/spec/patterns/syslog_spec.rb +266 -8
  74. data/spec/spec_helper.rb +83 -5
  75. metadata +74 -26
  76. data/patterns/aws +0 -11
  77. data/patterns/redis +0 -3
  78. data/spec/patterns/bro.rb +0 -126
  79. data/spec/patterns/s3_spec.rb +0 -132
@@ -0,0 +1,61 @@
1
+ # encoding: utf-8
2
+ require "spec_helper"
3
+ require "logstash/patterns/core"
4
+
5
+ describe "MAVEN_VERSION" do
6
+
7
+ let(:pattern) { 'MAVEN_VERSION' }
8
+
9
+ context "when maven version is simple" do
10
+ let(:value) { '1.1.0' }
11
+
12
+ it "should match the version" do
13
+ expect(grok_match(pattern,value)).to pass
14
+ end
15
+ end
16
+
17
+ context "when maven version is a bit more complex" do
18
+ let(:value) { '2.35.128' }
19
+
20
+ it "should match the version" do
21
+ expect(grok_match(pattern,value)).to pass
22
+ end
23
+ end
24
+
25
+ context "when maven version contains release" do
26
+ let(:value) { '1.1.0.RELEASE' }
27
+
28
+ it "should match the version" do
29
+ expect(grok_match(pattern,value)).to pass
30
+ end
31
+ end
32
+
33
+ context "when maven version contains shapshot" do
34
+ let(:value) { '1.1.0.SNAPSHOT' }
35
+
36
+ it "should match the version" do
37
+ expect(grok_match(pattern,value)).to pass
38
+ end
39
+ end
40
+
41
+ context "when maven version contains release" do
42
+ context "and the version contains a dash" do
43
+ let(:value) { '1.1.0-RELEASE' }
44
+
45
+ it "should match the version" do
46
+ expect(grok_match(pattern,value)).to pass
47
+ end
48
+ end
49
+ end
50
+
51
+ context "when maven version contains shapshot" do
52
+ context "and the version contains a dash" do
53
+ let(:value) { '1.1.0-SNAPSHOT' }
54
+
55
+ it "should match the version" do
56
+ expect(grok_match(pattern,value)).to pass
57
+ end
58
+ end
59
+ end
60
+
61
+ end
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+ require "spec_helper"
3
+ require "logstash/patterns/core"
4
+
5
+ describe_pattern "MCOLLECTIVE", ['legacy', 'ecs-v1'] do
6
+
7
+ let(:message) { "I, [2010-12-29T11:15:32.321744 #11479] INFO -- : mcollectived:33 The Marionette Collective 1.1.0 started logging at info level" }
8
+
9
+ it do
10
+ should include("timestamp" => "2010-12-29T11:15:32.321744")
11
+ end
12
+
13
+ it do
14
+ if ecs_compatibility?
15
+ should include("process" => { "pid" => 11479 })
16
+ else
17
+ should include("pid" => "11479")
18
+ end
19
+ end
20
+
21
+ it do
22
+ if ecs_compatibility?
23
+ should include("log" => hash_including("level" => "INFO"))
24
+ else
25
+ should include("event_level" => "INFO")
26
+ end
27
+ end
28
+
29
+ # NOTE: pattern seems unfinished - missing match of remaining message
30
+ it 'should have extracted message' do
31
+ # but did not :
32
+ expect( subject['message'] ).to eql message
33
+ end
34
+
35
+ end
@@ -2,83 +2,220 @@
2
2
  require "spec_helper"
3
3
  require "logstash/patterns/core"
4
4
 
5
- describe "MONGO3_LOG" do
6
-
7
- let(:pattern) { "MONGO3_LOG" }
5
+ describe_pattern "MONGO3_LOG", ['legacy', 'ecs-v1'] do
8
6
 
9
7
  context "parsing an standard/basic message" do
10
8
 
11
- let(:value) { "2014-11-03T18:28:32.450-0500 I NETWORK [initandlisten] waiting for connections on port 27017" }
12
-
13
- subject { grok_match(pattern, value) }
9
+ let(:message) { "2014-11-03T18:28:32.450-0500 I NETWORK [initandlisten] waiting for connections on port 27017" }
14
10
 
15
11
  it { should include("timestamp" => "2014-11-03T18:28:32.450-0500") }
16
12
 
17
- it { should include("severity" => "I") }
13
+ it do
14
+ if ecs_compatibility?
15
+ should include("log" => { 'level' => "I" })
16
+ else
17
+ should include("severity" => "I")
18
+ end
19
+ end
18
20
 
19
- it { should include("component" => "NETWORK") }
21
+ it do
22
+ if ecs_compatibility?
23
+ should include("mongodb" => hash_including("component" => "NETWORK"))
24
+ else
25
+ should include("component" => "NETWORK")
26
+ end
27
+ end
20
28
 
21
- it { should include("context" => "initandlisten") }
29
+ it do
30
+ if ecs_compatibility?
31
+ should include("mongodb" => hash_including("context" => "initandlisten"))
32
+ else
33
+ should include("context" => "initandlisten")
34
+ end
35
+ end
22
36
 
23
37
  it "generates a message field" do
24
- expect(subject["message"]).to include("waiting for connections on port 27017")
38
+ expect(subject["message"]).to eql [ message, "waiting for connections on port 27017" ]
25
39
  end
26
40
  end
27
41
 
28
42
  context "parsing a message with a missing component" do
29
43
 
30
- let(:value) { "2015-02-24T18:17:47.148+0000 F - [conn11] Got signal: 11 (Segmentation fault)." }
44
+ let(:message) { "2015-02-24T18:17:47.148+0000 F - [conn11] Got signal: 11 (Segmentation fault)." }
31
45
 
32
- subject { grok_match(pattern, value) }
46
+ it 'matches' do
47
+ should include("timestamp" => "2015-02-24T18:17:47.148+0000")
33
48
 
34
- it { should include("timestamp" => "2015-02-24T18:17:47.148+0000") }
49
+ if ecs_compatibility?
50
+ expect( grok_result['mongodb'].keys ).to_not include("component")
51
+ else
52
+ should include("component" => "-")
53
+ end
35
54
 
36
- it { should include("severity" => "F") }
55
+ if ecs_compatibility?
56
+ should include("log" => { 'level' => "F" })
57
+ else
58
+ should include("severity" => "F")
59
+ end
37
60
 
38
- it { should include("component" => "-") }
39
-
40
- it { should include("context" => "conn11") }
61
+ if ecs_compatibility?
62
+ should include("mongodb" => hash_including("context" => "conn11"))
63
+ else
64
+ should include("context" => "conn11")
65
+ end
66
+ end
41
67
 
42
68
  it "generates a message field" do
43
- expect(subject["message"]).to include("Got signal: 11 (Segmentation fault).")
69
+ expect(subject["message"]).to eql [ message, "Got signal: 11 (Segmentation fault)." ]
44
70
  end
45
71
  end
46
72
 
47
73
  context "parsing a message with a multiwords context" do
48
74
 
49
- let(:value) { "2015-04-23T06:57:28.256+0200 I JOURNAL [journal writer] Journal writer thread started" }
50
-
51
- subject { grok_match(pattern, value) }
75
+ let(:message) { "2015-04-23T06:57:28.256+0200 I JOURNAL [journal writer] Journal writer thread started" }
52
76
 
53
- it { should include("timestamp" => "2015-04-23T06:57:28.256+0200") }
77
+ it 'matches' do
78
+ should include("timestamp" => "2015-04-23T06:57:28.256+0200")
54
79
 
55
- it { should include("severity" => "I") }
80
+ if ecs_compatibility?
81
+ should include("log" => { 'level' => "I" })
82
+ else
83
+ should include("severity" => "I")
84
+ end
56
85
 
57
- it { should include("component" => "JOURNAL") }
86
+ if ecs_compatibility?
87
+ should include("mongodb" => hash_including("component" => "JOURNAL"))
88
+ else
89
+ should include("component" => "JOURNAL")
90
+ end
58
91
 
59
- it { should include("context" => "journal writer") }
92
+ if ecs_compatibility?
93
+ should include("mongodb" => hash_including("context" => "journal writer"))
94
+ else
95
+ should include("context" => "journal writer")
96
+ end
97
+ end
60
98
 
61
99
  it "generates a message field" do
62
100
  expect(subject["message"]).to include("Journal writer thread started")
63
101
  end
102
+
103
+ context '3.6 simple log line' do
104
+
105
+ let(:message) do
106
+ '2020-08-13T11:58:09.672+0200 I NETWORK [conn2] end connection 127.0.0.1:41258 (1 connection now open)'
107
+ end
108
+
109
+ it 'matches' do
110
+ should include("timestamp" => "2020-08-13T11:58:09.672+0200")
111
+
112
+ if ecs_compatibility?
113
+ should include("mongodb" => hash_including("component" => "NETWORK"))
114
+ else
115
+ should include("component" => "NETWORK")
116
+ end
117
+
118
+ if ecs_compatibility?
119
+ should include("mongodb" => hash_including("context" => "conn2"))
120
+ else
121
+ should include("context" => "conn2")
122
+ end
123
+
124
+ expect(subject["message"]).to include("end connection 127.0.0.1:41258 (1 connection now open)")
125
+ end
126
+
127
+ end
128
+
129
+ context '3.6 long log line' do
130
+
131
+ let(:command) do
132
+ 'command config.$cmd command: createIndexes { createIndexes: "system.sessions", ' +
133
+ 'indexes: [ { key: { lastUse: 1 }, name: "lsidTTLIndex", expireAfterSeconds: 1800 } ], $db: "config" } ' +
134
+ 'numYields:0 reslen:101 locks:{ Global: { acquireCount: { r: 2, w: 2 } }, Database: { acquireCount: { w: 2 } }, ' +
135
+ 'Collection: { acquireCount: { w: 1 } } } protocol:op_msg 0ms'
136
+ end
137
+
138
+ let(:message) do
139
+ '2020-08-13T11:57:45.259+0200 I COMMAND [LogicalSessionCacheRefresh] ' + command
140
+ end
141
+
142
+ it 'matches' do
143
+ should include("timestamp" => "2020-08-13T11:57:45.259+0200")
144
+
145
+ if ecs_compatibility?
146
+ should include("mongodb" => hash_including("component" => "COMMAND"))
147
+ else
148
+ should include("component" => "COMMAND")
149
+ end
150
+
151
+ if ecs_compatibility?
152
+ should include("mongodb" => hash_including("context" => "LogicalSessionCacheRefresh"))
153
+ else
154
+ should include("context" => "LogicalSessionCacheRefresh")
155
+ end
156
+
157
+ expect(subject["message"]).to eql [message, command]
158
+ end
159
+
160
+ end
161
+
64
162
  end
65
163
 
66
164
  context "parsing a message without context" do
67
165
 
68
- let(:value) { "2015-04-23T07:00:13.864+0200 I CONTROL Ctrl-C signal" }
69
-
70
- subject { grok_match(pattern, value) }
166
+ let(:message) { "2015-04-23T07:00:13.864+0200 I CONTROL Ctrl-C signal" }
71
167
 
72
- it { should include("timestamp" => "2015-04-23T07:00:13.864+0200") }
168
+ it 'matches' do
169
+ should include("timestamp" => "2015-04-23T07:00:13.864+0200")
73
170
 
74
- it { should include("severity" => "I") }
171
+ if ecs_compatibility?
172
+ should include("log" => { 'level' => "I" })
173
+ else
174
+ should include("severity" => "I")
175
+ end
75
176
 
76
- it { should include("component" => "CONTROL") }
177
+ if ecs_compatibility?
178
+ should include("mongodb" => hash_including("component" => "CONTROL"))
179
+ else
180
+ should include("component" => "CONTROL")
181
+ end
77
182
 
78
- it { should_not have_key("context") }
183
+ if ecs_compatibility?
184
+ expect( grok_result['mongodb'].keys ).to_not include("context")
185
+ else
186
+ should_not have_key("context")
187
+ end
188
+ end
79
189
 
80
190
  it "generates a message field" do
81
- expect(subject["message"]).to include("Ctrl-C signal")
191
+ expect(subject["message"]).to eql [ message, "Ctrl-C signal" ]
82
192
  end
83
193
  end
84
194
  end
195
+
196
+ describe_pattern "MONGO_SLOWQUERY", ['legacy', 'ecs-v1'] do
197
+
198
+ let(:message) do
199
+ "[conn11485496] query sample.User query: { clientId: 12345 } ntoreturn:0 ntoskip:0 nscanned:287011 keyUpdates:0 numYields: 2 locks(micros) r:4187700 nreturned:18 reslen:14019 2340ms"
200
+ end
201
+
202
+ it do
203
+ if ecs_compatibility?
204
+ should include("mongodb" => {
205
+ "database" => "sample", "collection" => "User",
206
+ "query" => { "original"=>"{ clientId: 12345 }" },
207
+ "profile" => {
208
+ "op" => "query",
209
+ "ntoreturn" => 0, "ntoskip" => 0, "nscanned" => 287011, "nreturned" => 18,
210
+ "duration" => 2340
211
+ }
212
+ })
213
+ else
214
+ should include("database" => "sample", "collection" => "User")
215
+ should include("ntoreturn" => '0', "ntoskip" => '0', "nscanned" => "287011", "nreturned" => "18")
216
+ should include("query" => "{ clientId: 12345 }")
217
+ should include("duration" => "2340")
218
+ end
219
+ end
220
+
221
+ end
@@ -2,242 +2,463 @@
2
2
  require "spec_helper"
3
3
  require "logstash/patterns/core"
4
4
 
5
- describe "NAGIOSLOGLINE - CURRENT HOST STATE" do
5
+ describe_pattern "NAGIOSLOGLINE - CURRENT HOST STATE", [ 'legacy', 'ecs-v1' ] do
6
6
 
7
- let(:value) { "[1427925600] CURRENT HOST STATE: nagioshost;UP;HARD;1;PING OK - Packet loss = 0%, RTA = 2.24 ms" }
8
- let(:grok) { grok_match(subject, value) }
7
+ let(:message) { "[1427925600] CURRENT HOST STATE: nagioshost;UP;HARD;1;PING OK - Packet loss = 0%, RTA = 2.24 ms" }
9
8
 
10
9
  it "a pattern pass the grok expression" do
11
10
  expect(grok).to pass
12
11
  end
13
12
 
14
13
  it "matches a simple message" do
15
- expect(subject).to match(value)
14
+ expect(pattern).to match(message)
16
15
  end
17
16
 
18
17
  it "generates the nagios_epoch field" do
19
- expect(grok).to include("nagios_epoch" => "1427925600")
18
+ if ecs_compatibility?
19
+ expect(grok).to include("timestamp" => "1427925600")
20
+ else
21
+ expect(grok).to include("nagios_epoch" => "1427925600")
22
+ end
20
23
  end
21
24
 
22
25
  it "generates the nagios_message field" do
23
- expect(grok).to include("nagios_message" => "PING OK - Packet loss = 0%, RTA = 2.24 ms")
26
+ if ecs_compatibility?
27
+ expect(grok).to include("message" => [message, "PING OK - Packet loss = 0%, RTA = 2.24 ms"])
28
+ else
29
+ expect(grok).to include("nagios_message" => "PING OK - Packet loss = 0%, RTA = 2.24 ms")
30
+ end
24
31
  end
25
32
 
26
33
  it "generates the nagios_hostname field" do
27
- expect(grok).to include("nagios_hostname" => "nagioshost")
34
+ if ecs_compatibility?
35
+ expect(grok).to include("host" => { "hostname" => "nagioshost" })
36
+ else
37
+ expect(grok).to include("nagios_hostname" => "nagioshost")
38
+ end
28
39
  end
29
40
 
30
41
  it "generates the nagios_state field" do
31
- expect(grok).to include("nagios_state" => "UP")
42
+ if ecs_compatibility?
43
+ expect(grok).to include("service" => hash_including("state" => "UP"))
44
+ else
45
+ expect(grok).to include("nagios_state" => "UP")
46
+ end
32
47
  end
33
48
 
34
49
  it "generates the nagios_statetype field" do
35
- expect(grok).to include("nagios_statetype" => "HARD")
50
+ if ecs_compatibility?
51
+ expect(grok).to include("nagios" => hash_including("log" => hash_including("state_type" => "HARD")))
52
+ else
53
+ expect(grok).to include("nagios_statetype" => "HARD")
54
+ end
36
55
  end
37
56
 
38
57
  end
39
58
 
40
- describe "NAGIOSLOGLINE - CURRENT SERVICE STATE" do
59
+ describe_pattern "NAGIOSLOGLINE - CURRENT SERVICE STATE", [ 'legacy', 'ecs-v1' ] do
41
60
 
42
- let(:value) { "[1427925600] CURRENT SERVICE STATE: nagioshost;nagiosservice;OK;HARD;1;nagiosmessage" }
43
- let(:grok) { grok_match(subject, value) }
61
+ let(:message) { "[1427925600] CURRENT SERVICE STATE: nagioshost;SSH;OK;HARD;1;nagiosmessage" }
44
62
 
45
63
  it "a pattern pass the grok expression" do
46
64
  expect(grok).to pass
47
65
  end
48
66
 
49
67
  it "matches a simple message" do
50
- expect(subject).to match(value)
68
+ expect(pattern).to match(message)
51
69
  end
52
70
 
53
71
  it "generates the nagios_type field" do
54
- expect(grok).to include("nagios_type" => "CURRENT SERVICE STATE")
72
+ if ecs_compatibility?
73
+ expect(grok).to include("nagios" => hash_including("log" => hash_including("type" => "CURRENT SERVICE STATE")))
74
+ else
75
+ expect(grok).to include("nagios_type" => "CURRENT SERVICE STATE")
76
+ end
55
77
  end
56
78
 
57
79
  it "generates the nagios_epoch field" do
58
- expect(grok).to include("nagios_epoch" => "1427925600")
80
+ if ecs_compatibility?
81
+ expect(grok).to include("timestamp" => "1427925600")
82
+ else
83
+ expect(grok).to include("nagios_epoch" => "1427925600")
84
+ end
59
85
  end
60
86
 
61
87
  it "generates the nagios_message field" do
62
- expect(grok).to include("nagios_message" => "nagiosmessage")
88
+ if ecs_compatibility?
89
+ expect(grok).to include("message" => [message, "nagiosmessage"])
90
+ else
91
+ expect(grok).to include("nagios_message" => "nagiosmessage")
92
+ end
63
93
  end
64
94
 
65
- it "generates the nagios_hostname field" do
66
- expect(grok).to include("nagios_hostname" => "nagioshost")
95
+ it "generates the hostname field" do
96
+ if ecs_compatibility?
97
+ expect(grok).to include("host" => { "hostname" => "nagioshost" })
98
+ else
99
+ expect(grok).to include("nagios_hostname" => "nagioshost")
100
+ end
67
101
  end
68
102
 
69
- it "generates the nagios_service field" do
70
- expect(grok).to include("nagios_service" => "nagiosservice")
103
+ it "generates the service field" do
104
+ if ecs_compatibility?
105
+ expect(grok).to include("service" => hash_including("name" => "SSH"))
106
+ else
107
+ expect(grok).to include("nagios_service" => "SSH")
108
+ end
71
109
  end
72
110
 
73
111
  it "generates the nagios_state field" do
74
- expect(grok).to include("nagios_state" => "OK")
112
+ if ecs_compatibility?
113
+ expect(grok).to include("service" => hash_including("state" => "OK"))
114
+ else
115
+ expect(grok).to include("nagios_state" => "OK")
116
+ end
75
117
  end
76
118
 
77
119
  it "generates the nagios_statetype field" do
78
- expect(grok).to include("nagios_statetype" => "HARD")
79
- end
120
+ if ecs_compatibility?
121
+ expect(grok).to include("nagios" => hash_including("log" => hash_including("state_type" => "HARD")))
122
+ else
123
+ expect(grok).to include("nagios_statetype" => "HARD")
124
+ end
125
+ end
126
+
127
+ it "generates the nagios_statecode field" do
128
+ if ecs_compatibility?
129
+ expect(grok).to include("nagios" => hash_including("log" => hash_including("attempt" => 1)))
130
+ else
131
+ # NOTE: (legacy) nagios_statecode corresponds to current_attempt (according to Nagios' source)
132
+ expect(grok).to include("nagios_statecode" => "1")
133
+ end
134
+ end
135
+
136
+ context 'real-world example' do
137
+
138
+ let(:message) do
139
+ '[1427956600] CURRENT SERVICE STATE: prod-virtual-ESz06;check_vmfs_prod-PvDC2;CRITICAL;HARD;3;CRITICAL - /vmfs/volumes/prod-vsRoot - total: 8191.75 Gb - used: 7859.84 Gb (95%)- free: 331.90 Gb (5%)'
140
+ end
141
+
142
+ it 'matches' do
143
+ if ecs_compatibility?
144
+ expect(grok).to include(
145
+ "host" => { "hostname" => "prod-virtual-ESz06" },
146
+ "service" => { "name" => "check_vmfs_prod-PvDC2", "state" => 'CRITICAL' },
147
+ "nagios" => { "log" => {
148
+ "type" => "CURRENT SERVICE STATE",
149
+ "state_type" => "HARD",
150
+ "attempt" => 3
151
+ }},
152
+ "message" => [message, "CRITICAL - /vmfs/volumes/prod-vsRoot - total: 8191.75 Gb - used: 7859.84 Gb (95%)- free: 331.90 Gb (5%)"]
153
+ )
154
+ else
155
+ expect(grok).to include(
156
+ "nagios_type"=>"CURRENT SERVICE STATE",
157
+ "nagios_state"=>"CRITICAL",
158
+ "nagios_statetype"=>"HARD",
159
+ "nagios_hostname"=>"prod-virtual-ESz06",
160
+ "nagios_statecode"=>"3", # NOTE: "incorrect" - corresponds to current_attempt (according to Nagios' source)
161
+ "nagios_message"=>"CRITICAL - /vmfs/volumes/prod-vsRoot - total: 8191.75 Gb - used: 7859.84 Gb (95%)- free: 331.90 Gb (5%)"
162
+ )
163
+ end
164
+ end
80
165
 
166
+ end
81
167
  end
82
168
 
83
- describe "NAGIOSLOGLINE - TIMEPERIOD TRANSITION" do
169
+ describe_pattern "NAGIOSLOGLINE - TIMEPERIOD TRANSITION", [ 'legacy', 'ecs-v1' ] do
84
170
 
85
- let(:value) { "[1427925600] TIMEPERIOD TRANSITION: 24X7;1;1" }
86
- let(:grok) { grok_match(subject, value) }
171
+ let(:message) { "[1427925600] TIMEPERIOD TRANSITION: 24X7;-1;1" }
87
172
 
88
- it "a pattern pass the grok expression" do
89
- expect(grok).to pass
90
- end
91
-
92
- it "matches a simple message" do
93
- expect(subject).to match(value)
173
+ it "matches the message" do
174
+ expect(pattern).to match(message)
94
175
  end
95
176
 
96
177
  it "generates the nagios_type field" do
97
- expect(grok).to include("nagios_type" => "TIMEPERIOD TRANSITION")
178
+ if ecs_compatibility?
179
+ expect(grok).to include("nagios" => hash_including("log" => hash_including("type" => 'TIMEPERIOD TRANSITION')))
180
+ else
181
+ expect(grok).to include("nagios_type" => "TIMEPERIOD TRANSITION")
182
+ end
98
183
  end
99
184
 
100
185
  it "generates the nagios_epoch field" do
101
- expect(grok).to include("nagios_epoch" => "1427925600")
186
+ expect(grok).to include("nagios_epoch" => "1427925600") unless ecs_compatibility?
102
187
  end
103
188
 
104
- it "generates the nagios_esrvice field" do
105
- expect(grok).to include("nagios_service" => "24X7")
189
+ it "generates the service field" do
190
+ if ecs_compatibility?
191
+ expect(grok).to include("service" => hash_including("name" => '24X7'))
192
+ else
193
+ expect(grok).to include("nagios_service" => "24X7")
194
+ end
195
+ end
196
+
197
+ it "generates the period from/to fields" do
198
+ if ecs_compatibility?
199
+ expect(grok).to include("nagios" => hash_including("log" => hash_including("period_from" => -1, "period_to" => 1)))
200
+ else
201
+ expect(grok).to include("nagios_unknown1" => "-1", "nagios_unknown2" => "1")
202
+ end
106
203
  end
107
204
 
108
205
  # Regression test for but fixed in Nagios patterns #30
109
206
  it "doesn't end in a semi-colon" do
110
- expect(grok['message']).to_not end_with(";")
207
+ message = grok['message']
208
+ message = message.last if message.is_a?(Array)
209
+ expect(message).to_not end_with(";")
111
210
  end
112
211
 
113
212
  end
114
213
 
115
- describe "NAGIOSLOGLINE - SERVICE ALERT" do
214
+ describe_pattern "NAGIOSLOGLINE - SERVICE ALERT", [ 'legacy', 'ecs-v1' ] do
116
215
 
117
- let(:value) { "[1427925689] SERVICE ALERT: varnish;Varnish Backend Connections;CRITICAL;SOFT;1;Current value: 154.0, warn threshold: 10.0, crit threshold: 20.0" }
118
- let(:grok) { grok_match(subject, value) }
216
+ let(:message) { "[1427925689] SERVICE ALERT: varnish;Varnish Backend Connections;CRITICAL;SOFT;1;Current value: 154.0, warn threshold: 10.0, crit threshold: 20.0" }
119
217
 
120
218
  it "a pattern pass the grok expression" do
121
219
  expect(grok).to pass
122
220
  end
123
221
 
124
222
  it "matches a simple message" do
125
- expect(subject).to match(value)
223
+ expect(pattern).to match(message)
126
224
  end
127
225
 
128
226
  it "generates the nagios_type field" do
129
- expect(grok).to include("nagios_type" => "SERVICE ALERT")
227
+ if ecs_compatibility?
228
+ expect(grok).to include("nagios" => hash_including("log" => hash_including("type" => 'SERVICE ALERT')))
229
+ else
230
+ expect(grok).to include("nagios_type" => "SERVICE ALERT")
231
+ end
130
232
  end
131
233
 
132
234
  it "generates the nagios_epoch field" do
133
- expect(grok).to include("nagios_epoch" => "1427925689")
235
+ if ecs_compatibility?
236
+ expect(grok).to include("timestamp" => "1427925689")
237
+ else
238
+ expect(grok).to include("nagios_epoch" => "1427925689")
239
+ end
134
240
  end
135
241
 
136
- it "generates the nagios_hostname field" do
137
- expect(grok).to include("nagios_hostname" => "varnish")
242
+ it "generates the hostname field" do
243
+ if ecs_compatibility?
244
+ expect(grok).to include("host" => { "hostname" => "varnish" })
245
+ else
246
+ expect(grok).to include("nagios_hostname" => "varnish")
247
+ end
138
248
  end
139
249
 
140
- it "generates the nagios_service field" do
141
- expect(grok).to include("nagios_service" => "Varnish Backend Connections")
250
+ it "generates the service field" do
251
+ if ecs_compatibility?
252
+ expect(grok).to include("service" => hash_including("name" => 'Varnish Backend Connections'))
253
+ else
254
+ expect(grok).to include("nagios_service" => "Varnish Backend Connections")
255
+ end
142
256
  end
143
257
 
144
258
  it "generates the nagios_state field" do
145
- expect(grok).to include("nagios_state" => "CRITICAL")
259
+ if ecs_compatibility?
260
+ expect(grok).to include("service" => hash_including("state" => "CRITICAL"))
261
+ else
262
+ expect(grok).to include("nagios_state" => "CRITICAL")
263
+ end
146
264
  end
147
265
 
148
266
  it "generates the nagios_statelevel field" do
149
- expect(grok).to include("nagios_statelevel" => "SOFT")
267
+ if ecs_compatibility?
268
+ expect(grok).to include("nagios" => hash_including("log" => hash_including("state_type" => "SOFT")))
269
+ else
270
+ expect(grok).to include("nagios_statelevel" => "SOFT")
271
+ end
272
+ end
273
+
274
+ it "generates the nagios_attempt field" do
275
+ if ecs_compatibility?
276
+ pending "TODO: are we hitting a grok bug here ?!?"
277
+ # [nagios][log][attempt]:int is clearly there (changing to :float gets this passing)
278
+ # ... but in this particular case we still get the raw "1" string back
279
+ expect(grok).to include("nagios" => hash_including("log" => hash_including("attempt" => 1)))
280
+ else
281
+ expect(grok).to include("nagios_attempt" => "1")
282
+ end
150
283
  end
151
284
 
152
285
  it "generates the nagios_message field" do
153
- expect(grok).to include("nagios_message" => "Current value: 154.0, warn threshold: 10.0, crit threshold: 20.0")
286
+ if ecs_compatibility?
287
+ expect(grok['message'].last).to eql "Current value: 154.0, warn threshold: 10.0, crit threshold: 20.0"
288
+ else
289
+ expect(grok).to include("nagios_message" => "Current value: 154.0, warn threshold: 10.0, crit threshold: 20.0")
290
+ end
154
291
  end
155
292
 
156
293
  end
157
294
 
158
- describe "NAGIOSLOGLINE - SERVICE NOTIFICATION" do
295
+ describe_pattern "NAGIOSLOGLINE - SERVICE NOTIFICATION", [ 'legacy', 'ecs-v1' ] do
159
296
 
160
- let(:value) { "[1427950229] SERVICE NOTIFICATION: nagiosadmin;varnish;Varnish Backend Connections;CRITICAL;notify-service-by-email;Current value: 337.0, warn threshold: 10.0, crit threshold: 20.0" }
161
- let(:grok) { grok_match(subject, value) }
297
+ let(:message) { "[1427950229] SERVICE NOTIFICATION: nagiosadmin;varnish;Varnish Backend Connections;CRITICAL;notify-service-by-email;Current value: 337.0, warn threshold: 10.0, crit threshold: 20.0" }
162
298
 
163
299
  it "a pattern pass the grok expression" do
164
300
  expect(grok).to pass
165
301
  end
166
302
 
167
303
  it "matches a simple message" do
168
- expect(subject).to match(value)
304
+ expect(pattern).to match(message)
169
305
  end
170
306
 
171
307
  it "generates the nagios_type field" do
172
- expect(grok).to include("nagios_type" => "SERVICE NOTIFICATION")
308
+ if ecs_compatibility?
309
+ expect(grok).to include("nagios" => hash_including("log" => hash_including("type" => 'SERVICE NOTIFICATION')))
310
+ else
311
+ expect(grok).to include("nagios_type" => "SERVICE NOTIFICATION")
312
+ end
173
313
  end
174
314
 
175
315
  it "generates the nagios_epoch field" do
176
- expect(grok).to include("nagios_epoch" => "1427950229")
316
+ if ecs_compatibility?
317
+ expect(grok).to include("timestamp" => "1427950229")
318
+ else
319
+ expect(grok).to include("nagios_epoch" => "1427950229")
320
+ end
177
321
  end
178
322
 
179
323
  it "generates the nagios_notifyname field" do
180
- expect(grok).to include("nagios_notifyname" => "nagiosadmin")
324
+ if ecs_compatibility?
325
+ expect(grok).to include("user" => { "name" => "nagiosadmin" }) # Nagios contact's contact_name
326
+ else
327
+ expect(grok).to include("nagios_notifyname" => "nagiosadmin")
328
+ end
181
329
  end
182
330
 
183
- it "generates the nagios_hostname field" do
184
- expect(grok).to include("nagios_hostname" => "varnish")
331
+ it "generates the hostname field" do
332
+ if ecs_compatibility?
333
+ expect(grok).to include("host" => { "hostname" => "varnish" })
334
+ else
335
+ expect(grok).to include("nagios_hostname" => "varnish")
336
+ end
185
337
  end
186
338
 
187
- it "generates the nagios_service field" do
188
- expect(grok).to include("nagios_service" => "Varnish Backend Connections")
339
+ it "generates the service field" do
340
+ if ecs_compatibility?
341
+ expect(grok).to include("service" => hash_including("name" => 'Varnish Backend Connections'))
342
+ else
343
+ expect(grok).to include("nagios_service" => "Varnish Backend Connections")
344
+ end
189
345
  end
190
346
 
191
347
  it "generates the nagios_state field" do
192
- expect(grok).to include("nagios_state" => "CRITICAL")
348
+ if ecs_compatibility?
349
+ expect(grok).to include("service" => hash_including("state" => "CRITICAL"))
350
+ else
351
+ expect(grok).to include("nagios_state" => "CRITICAL")
352
+ end
193
353
  end
194
354
 
195
355
  it "generates the nagios_contact field" do
196
- expect(grok).to include("nagios_contact" => "notify-service-by-email")
356
+ if ecs_compatibility?
357
+ expect(grok).to include("nagios" => hash_including("log" => hash_including("notification_command" => "notify-service-by-email")))
358
+ else
359
+ expect(grok).to include("nagios_contact" => "notify-service-by-email")
360
+ end
197
361
  end
198
362
 
199
363
  it "generates the nagios_message field" do
200
- expect(grok).to include("nagios_message" => "Current value: 337.0, warn threshold: 10.0, crit threshold: 20.0")
364
+ if ecs_compatibility?
365
+ expect(grok['message'].last).to eql "Current value: 337.0, warn threshold: 10.0, crit threshold: 20.0"
366
+ else
367
+ expect(grok).to include("nagios_message" => "Current value: 337.0, warn threshold: 10.0, crit threshold: 20.0")
368
+ end
201
369
  end
202
370
 
203
371
  end
204
372
 
205
373
 
206
- describe "NAGIOSLOGLINE - HOST NOTIFICATION" do
374
+ describe_pattern "NAGIOSLOGLINE - HOST NOTIFICATION", [ 'legacy', 'ecs-v1' ] do
207
375
 
208
- let(:value) { "[1429878690] HOST NOTIFICATION: nagiosadmin;nagioshost;DOWN;notify-host-by-email;CRITICAL - Socket timeout after 10 seconds" }
209
- let(:grok) { grok_match(subject, value) }
210
-
211
- it "a pattern pass the grok expression" do
212
- expect(grok).to pass
213
- end
376
+ let(:message) { "[1429878690] HOST NOTIFICATION: nagiosadmin;127.0.0.1;DOWN;host-notify-by-email;CRITICAL - Socket timeout after 10 seconds" }
214
377
 
215
378
  it "matches a simple message" do
216
- expect(subject).to match(value)
379
+ expect(pattern).to match(message)
217
380
  end
218
381
 
219
382
  it "generates the nagios_type field" do
220
- expect(grok).to include("nagios_type" => "HOST NOTIFICATION")
383
+ if ecs_compatibility?
384
+ expect(grok).to include("nagios" => hash_including("log" => hash_including("type" => "HOST NOTIFICATION")))
385
+ else
386
+ expect(grok).to include("nagios_type" => "HOST NOTIFICATION")
387
+ end
221
388
  end
222
389
 
223
390
  it "generates the nagios_epoch field" do
224
- expect(grok).to include("nagios_epoch" => "1429878690")
391
+ expect(grok).to include("nagios_epoch" => "1429878690") unless ecs_compatibility?
225
392
  end
226
393
 
227
394
  it "generates the nagios_notifyname field" do
228
- expect(grok).to include("nagios_notifyname" => "nagiosadmin")
395
+ if ecs_compatibility?
396
+ expect(grok).to include("user" => { "name" => "nagiosadmin" }) # Nagios contact's contact_name
397
+ else
398
+ expect(grok).to include("nagios_notifyname" => "nagiosadmin")
399
+ end
229
400
  end
230
401
 
231
402
  it "generates the nagios_hostname field" do
232
- expect(grok).to include("nagios_hostname" => "nagioshost")
403
+ if ecs_compatibility?
404
+ expect(grok).to include("host" => { "hostname" => "127.0.0.1" })
405
+ else
406
+ expect(grok).to include("nagios_hostname" => "127.0.0.1")
407
+ end
233
408
  end
234
409
 
235
410
  it "generates the nagios_contact field" do
236
- expect(grok).to include("nagios_contact" => "notify-host-by-email")
411
+ if ecs_compatibility?
412
+ expect(grok).to include("nagios" => hash_including("log" => hash_including("notification_command" => "host-notify-by-email")))
413
+ else
414
+ expect(grok).to include("nagios_contact" => "host-notify-by-email")
415
+ end
237
416
  end
238
417
 
239
418
  it "generates the nagios_message field" do
240
- expect(grok).to include("nagios_message" => "CRITICAL - Socket timeout after 10 seconds")
419
+ if ecs_compatibility?
420
+ expect(grok['message'].last).to eql "CRITICAL - Socket timeout after 10 seconds"
421
+ else
422
+ expect(grok).to include("nagios_message" => "CRITICAL - Socket timeout after 10 seconds")
423
+ end
241
424
  end
242
425
 
243
426
  end
427
+
428
+ describe_pattern "NAGIOSLOGLINE - SCHEDULE_HOST_DOWNTIME", [ 'legacy', 'ecs-v1' ] do
429
+
430
+ let(:message) { "[1334609999] EXTERNAL COMMAND: SCHEDULE_HOST_DOWNTIME;sputnik;1334665800;1334553600;1;0;120;nagiosadmin;test;" }
431
+
432
+ it "matches" do
433
+ if ecs_compatibility?
434
+ expect(grok).to include(
435
+ "host" => { "hostname" => "sputnik" },
436
+ "nagios" => { "log" => {
437
+ "type" => "EXTERNAL COMMAND",
438
+ "command" => "SCHEDULE_HOST_DOWNTIME",
439
+ "start_time" => "1334665800",
440
+ "end_time" => "1334553600",
441
+ "fixed" => '1',
442
+ "trigger_id" => '0',
443
+ "duration" => 120,
444
+
445
+ }},
446
+ "user" => { "name" => 'nagiosadmin' },
447
+ "message" => message
448
+ )
449
+ else
450
+ expect(grok).to include(
451
+ "nagios_epoch"=>"1334609999",
452
+ "nagios_type"=>"EXTERNAL COMMAND",
453
+ "nagios_command"=>"SCHEDULE_HOST_DOWNTIME",
454
+ "nagios_hostname"=>"sputnik",
455
+ "nagios_duration"=>"120",
456
+ "nagios_fixed"=>"1",
457
+ "nagios_trigger_id"=>"0",
458
+ "nagios_start_time"=>"1334665800",
459
+ "nagios_end_time"=>"1334553600",
460
+ "author"=>"nagiosadmin"
461
+ )
462
+ end
463
+ end
464
+ end