hq-log-monitor-server 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/features/event-page.feature +45 -2
- data/features/overview-page.feature +4 -4
- data/features/service-host-page.feature +47 -2
- data/features/support/steps.rb +8 -0
- data/features/support/ui-steps.rb +12 -0
- data/lib/hq/log-monitor-server/do-checks.rb +4 -9
- data/lib/hq/log-monitor-server/event-page.rb +27 -1
- data/lib/hq/log-monitor-server/logic.rb +133 -1
- data/lib/hq/log-monitor-server/misc.rb +135 -0
- data/lib/hq/log-monitor-server/overview-page.rb +14 -14
- data/lib/hq/log-monitor-server/script.rb +1 -0
- data/lib/hq/log-monitor-server/service-host-page.rb +21 -1
- data/lib/hq/log-monitor-server/service-page.rb +12 -12
- data/spec/hq/log-monitor-server/misc-spec.rb +198 -0
- metadata +35 -60
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6c802a656d6c2c2f5cee3eed1f4c866b812fc5ba
|
4
|
+
data.tar.gz: e234c43d9f6be7a9879c5192b7d0ab0a1b15e33f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a2db019440cc38fe7319b32cb4d357f6b35eed61f7fdbedcdd651c12110a36c49751bb9c3ec47116660f8d230e2569ec6a9aed44cb4438bdd54215a34b570e7e
|
7
|
+
data.tar.gz: 4f6b25e91c08a504f272615a4f34a6f03a3ad75532bd621a34fe9c728787bbefa55057e8a4abb963eecd62ab10730161729fae253c553e5ab2f880538038c34d
|
data/features/event-page.feature
CHANGED
@@ -68,7 +68,6 @@ Scenario: Mark as seen
|
|
68
68
|
|
69
69
|
And icinga should receive:
|
70
70
|
"""
|
71
|
-
[10] PROCESS_SERVICE_CHECK_RESULT;host;service;0;OK no new events
|
72
71
|
[10] PROCESS_SERVICE_CHECK_RESULT;host;service;1;WARNING 1 warning
|
73
72
|
[20] PROCESS_SERVICE_CHECK_RESULT;host;service;0;OK no new events
|
74
73
|
"""
|
@@ -94,8 +93,52 @@ Scenario: Mark as unseen
|
|
94
93
|
|
95
94
|
And icinga should receive:
|
96
95
|
"""
|
97
|
-
[10] PROCESS_SERVICE_CHECK_RESULT;host;service;0;OK no new events
|
98
96
|
[10] PROCESS_SERVICE_CHECK_RESULT;host;service;1;WARNING 1 warning
|
99
97
|
[20] PROCESS_SERVICE_CHECK_RESULT;host;service;0;OK no new events
|
100
98
|
[20] PROCESS_SERVICE_CHECK_RESULT;host;service;1;WARNING 1 warning
|
101
99
|
"""
|
100
|
+
|
101
|
+
Scenario: Delete unseen
|
102
|
+
|
103
|
+
Given the time is 20
|
104
|
+
|
105
|
+
When I visit /event/${event-id}
|
106
|
+
And I click "delete"
|
107
|
+
|
108
|
+
Then I should be sent to /service-host/service/class/host
|
109
|
+
|
110
|
+
And the event should be deleted
|
111
|
+
|
112
|
+
And the summary new should be 0
|
113
|
+
And the summary total should be 0
|
114
|
+
And the summary new for type "warning" should be 0
|
115
|
+
And the summary total for type "warning" should be 0
|
116
|
+
|
117
|
+
And icinga should receive:
|
118
|
+
"""
|
119
|
+
[10] PROCESS_SERVICE_CHECK_RESULT;host;service;1;WARNING 1 warning
|
120
|
+
[20] PROCESS_SERVICE_CHECK_RESULT;host;service;0;OK no new events
|
121
|
+
"""
|
122
|
+
|
123
|
+
Scenario: Delete seen
|
124
|
+
|
125
|
+
Given the time is 20
|
126
|
+
|
127
|
+
When I visit /event/${event-id}
|
128
|
+
And I click "mark as seen"
|
129
|
+
And I click "delete"
|
130
|
+
|
131
|
+
Then I should be sent to /service-host/service/class/host
|
132
|
+
|
133
|
+
And the event should be deleted
|
134
|
+
|
135
|
+
And the summary new should be 0
|
136
|
+
And the summary total should be 0
|
137
|
+
And the summary new for type "warning" should be 0
|
138
|
+
And the summary total for type "warning" should be 0
|
139
|
+
|
140
|
+
And icinga should receive:
|
141
|
+
"""
|
142
|
+
[10] PROCESS_SERVICE_CHECK_RESULT;host;service;1;WARNING 1 warning
|
143
|
+
[20] PROCESS_SERVICE_CHECK_RESULT;host;service;0;OK no new events
|
144
|
+
"""
|
@@ -41,7 +41,7 @@ Feature: Log monitor server overview
|
|
41
41
|
|
42
42
|
Then I should see 1 summary
|
43
43
|
And the 1st summary should be:
|
44
|
-
| name | value
|
45
|
-
| service | service
|
46
|
-
|
|
47
|
-
|
|
44
|
+
| name | value |
|
45
|
+
| service | service |
|
46
|
+
| new | 2 (1 warning, 1 critical) |
|
47
|
+
| total | 2 (1 warning, 1 critical) |
|
@@ -49,6 +49,7 @@ Feature: View and manipulate all events for a service/host combo
|
|
49
49
|
|
50
50
|
Then I should see 2 events
|
51
51
|
And I should see a button "mark all as seen"
|
52
|
+
And I should see a button "delete all"
|
52
53
|
|
53
54
|
And the summary new should be 2
|
54
55
|
And the summary total should be 2
|
@@ -57,7 +58,6 @@ Feature: View and manipulate all events for a service/host combo
|
|
57
58
|
|
58
59
|
And icinga should receive:
|
59
60
|
"""
|
60
|
-
[10] PROCESS_SERVICE_CHECK_RESULT;host;service;0;OK no new events
|
61
61
|
[10] PROCESS_SERVICE_CHECK_RESULT;host;service;1;WARNING 1 warning
|
62
62
|
[10] PROCESS_SERVICE_CHECK_RESULT;host;service;1;WARNING 2 warning
|
63
63
|
"""
|
@@ -71,6 +71,7 @@ Feature: View and manipulate all events for a service/host combo
|
|
71
71
|
|
72
72
|
Then I should see 2 events
|
73
73
|
And I should not see a button "mark all as unseen"
|
74
|
+
And I should see a button "delete all"
|
74
75
|
|
75
76
|
And the summary new should be 0
|
76
77
|
And the summary total should be 2
|
@@ -79,10 +80,54 @@ Feature: View and manipulate all events for a service/host combo
|
|
79
80
|
|
80
81
|
And icinga should receive:
|
81
82
|
"""
|
82
|
-
[10] PROCESS_SERVICE_CHECK_RESULT;host;service;0;OK no new events
|
83
83
|
[10] PROCESS_SERVICE_CHECK_RESULT;host;service;1;WARNING 1 warning
|
84
84
|
[10] PROCESS_SERVICE_CHECK_RESULT;host;service;1;WARNING 2 warning
|
85
85
|
[20] PROCESS_SERVICE_CHECK_RESULT;host;service;0;OK no new events
|
86
86
|
"""
|
87
87
|
|
88
|
+
Scenario: Delete all unseen
|
88
89
|
|
90
|
+
Given the time is 20
|
91
|
+
|
92
|
+
When I visit /service-host/service/class/host
|
93
|
+
And I click "delete all"
|
94
|
+
|
95
|
+
Then I should not see any events
|
96
|
+
And I should not see a button "mark all as seen"
|
97
|
+
And I should not see a button "delete all"
|
98
|
+
|
99
|
+
And the summary new should be 0
|
100
|
+
And the summary total should be 0
|
101
|
+
And the summary new for type "warning" should be 0
|
102
|
+
And the summary total for type "warning" should be 0
|
103
|
+
|
104
|
+
And icinga should receive:
|
105
|
+
"""
|
106
|
+
[10] PROCESS_SERVICE_CHECK_RESULT;host;service;1;WARNING 1 warning
|
107
|
+
[10] PROCESS_SERVICE_CHECK_RESULT;host;service;1;WARNING 2 warning
|
108
|
+
[20] PROCESS_SERVICE_CHECK_RESULT;host;service;0;OK no new events
|
109
|
+
"""
|
110
|
+
|
111
|
+
Scenario: Delete all seen
|
112
|
+
|
113
|
+
Given the time is 20
|
114
|
+
|
115
|
+
When I visit /service-host/service/class/host
|
116
|
+
And I click "mark all as seen"
|
117
|
+
And I click "delete all"
|
118
|
+
|
119
|
+
Then I should not see any events
|
120
|
+
And I should not see a button "mark all as unseen"
|
121
|
+
And I should not see a button "delete all"
|
122
|
+
|
123
|
+
And the summary new should be 0
|
124
|
+
And the summary total should be 0
|
125
|
+
And the summary new for type "warning" should be 0
|
126
|
+
And the summary total for type "warning" should be 0
|
127
|
+
|
128
|
+
And icinga should receive:
|
129
|
+
"""
|
130
|
+
[10] PROCESS_SERVICE_CHECK_RESULT;host;service;1;WARNING 1 warning
|
131
|
+
[10] PROCESS_SERVICE_CHECK_RESULT;host;service;1;WARNING 2 warning
|
132
|
+
[20] PROCESS_SERVICE_CHECK_RESULT;host;service;0;OK no new events
|
133
|
+
"""
|
data/features/support/steps.rb
CHANGED
@@ -129,6 +129,14 @@ Then /^the event status should be "(.*?)"$/ do
|
|
129
129
|
|
130
130
|
end
|
131
131
|
|
132
|
+
Then /^the event should be deleted$/ do
|
133
|
+
|
134
|
+
event = get_event @event_id
|
135
|
+
|
136
|
+
event.should be_nil
|
137
|
+
|
138
|
+
end
|
139
|
+
|
132
140
|
Then /^the summary new should be (\d+)$/ do
|
133
141
|
|count_str|
|
134
142
|
|
@@ -17,6 +17,13 @@ When /^I click "(.*?)"$/ do
|
|
17
17
|
|
18
18
|
end
|
19
19
|
|
20
|
+
Then /^I should be sent to (\/.*)$/ do
|
21
|
+
|expected_url|
|
22
|
+
|
23
|
+
current_path.should == expected_url
|
24
|
+
|
25
|
+
end
|
26
|
+
|
20
27
|
Then /^I should see no summaries$/ do
|
21
28
|
page.should have_content "No events have been logged"
|
22
29
|
end
|
@@ -56,6 +63,11 @@ Then /^I should see (\d+) events$/ do
|
|
56
63
|
|
57
64
|
end
|
58
65
|
|
66
|
+
Then /^I should not see any events$/ do
|
67
|
+
all("#events")
|
68
|
+
# TODO
|
69
|
+
end
|
70
|
+
|
59
71
|
Then /^I should see a button "(.*?)"$/ do
|
60
72
|
|label|
|
61
73
|
|
@@ -28,20 +28,15 @@ class Script
|
|
28
28
|
summaries["types"].each do
|
29
29
|
|type_name, type_info|
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
type [@name = #{esc_xp type_name}]
|
34
|
-
")
|
35
|
-
|
36
|
-
if ! type_elem
|
37
|
-
unknown_count += type_info["new"]
|
38
|
-
elsif type_elem["level"] == "critical"
|
31
|
+
case level_for_type service_name, type_name
|
32
|
+
when "critical"
|
39
33
|
critical_count += type_info["new"]
|
40
|
-
|
34
|
+
when "warning"
|
41
35
|
warning_count += type_info["new"]
|
42
36
|
else
|
43
37
|
unknown_count += type_info["new"]
|
44
38
|
end
|
39
|
+
|
45
40
|
end
|
46
41
|
end
|
47
42
|
|
@@ -23,6 +23,25 @@ class Script
|
|
23
23
|
|
24
24
|
end
|
25
25
|
|
26
|
+
if req.request_method == "POST" \
|
27
|
+
&& req.params["delete"]
|
28
|
+
|
29
|
+
event =
|
30
|
+
delete_event context[:event_id]
|
31
|
+
|
32
|
+
resp =
|
33
|
+
Rack::Response.new
|
34
|
+
|
35
|
+
resp.redirect "/service-host/%s/%s/%s" % [
|
36
|
+
event["source"]["service"],
|
37
|
+
event["source"]["class"],
|
38
|
+
event["source"]["host"],
|
39
|
+
]
|
40
|
+
|
41
|
+
return resp
|
42
|
+
|
43
|
+
end
|
44
|
+
|
26
45
|
# read from database
|
27
46
|
|
28
47
|
event =
|
@@ -80,8 +99,9 @@ class Script
|
|
80
99
|
]),
|
81
100
|
]
|
82
101
|
html << "<li><a href=\"%s\">Host</a></li>\n" % [
|
83
|
-
esc_ht("/service/%s
|
102
|
+
esc_ht("/service-host/%s/%s/%s" % [
|
84
103
|
event["source"]["service"],
|
104
|
+
event["source"]["class"],
|
85
105
|
event["source"]["host"],
|
86
106
|
])
|
87
107
|
]
|
@@ -234,6 +254,12 @@ class Script
|
|
234
254
|
|
235
255
|
end
|
236
256
|
|
257
|
+
html <<
|
258
|
+
"<input " +
|
259
|
+
"type=\"submit\" " +
|
260
|
+
"name=\"delete\" " +
|
261
|
+
"value=\"delete\">\n"
|
262
|
+
|
237
263
|
html << "</p>\n"
|
238
264
|
|
239
265
|
html << "</form>\n"
|
@@ -124,6 +124,136 @@ class Script
|
|
124
124
|
|
125
125
|
end
|
126
126
|
|
127
|
+
def delete_event event_id
|
128
|
+
|
129
|
+
# fetch it
|
130
|
+
|
131
|
+
event = get_event event_id
|
132
|
+
|
133
|
+
return nil unless event
|
134
|
+
|
135
|
+
# delete it
|
136
|
+
|
137
|
+
@db["events"].remove({
|
138
|
+
"_id" => event["_id"],
|
139
|
+
})
|
140
|
+
|
141
|
+
event_count =
|
142
|
+
@db.get_last_error["n"]
|
143
|
+
|
144
|
+
return event unless event_count > 0
|
145
|
+
|
146
|
+
# update summary
|
147
|
+
|
148
|
+
case event["status"]
|
149
|
+
|
150
|
+
when "unseen"
|
151
|
+
|
152
|
+
@db["summaries"].update(
|
153
|
+
{ "_id" => event["source"] },
|
154
|
+
{ "$inc" => {
|
155
|
+
"combined.new" => -1,
|
156
|
+
"combined.total" => -1,
|
157
|
+
"types.#{event["type"]}.new" => -1,
|
158
|
+
"types.#{event["type"]}.total" => -1,
|
159
|
+
} }
|
160
|
+
)
|
161
|
+
|
162
|
+
when "seen"
|
163
|
+
|
164
|
+
@db["summaries"].update(
|
165
|
+
{ "_id" => event["source"] },
|
166
|
+
{ "$inc" => {
|
167
|
+
"combined.total" => -1,
|
168
|
+
"types.#{event["type"]}.total" => -1,
|
169
|
+
} }
|
170
|
+
)
|
171
|
+
|
172
|
+
else
|
173
|
+
|
174
|
+
raise "Error 3084789190"
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
# notify icinga checks
|
179
|
+
|
180
|
+
do_checks
|
181
|
+
|
182
|
+
# and return
|
183
|
+
|
184
|
+
return event
|
185
|
+
|
186
|
+
end
|
187
|
+
|
188
|
+
def delete_all source
|
189
|
+
|
190
|
+
# get types
|
191
|
+
|
192
|
+
query = {
|
193
|
+
"source.service" => source["service"],
|
194
|
+
"source.class" => source["class"],
|
195
|
+
"source.host" => source["host"],
|
196
|
+
}
|
197
|
+
|
198
|
+
types =
|
199
|
+
@db["events"].distinct "type", query
|
200
|
+
|
201
|
+
types.each do
|
202
|
+
|type|
|
203
|
+
|
204
|
+
# delete events
|
205
|
+
|
206
|
+
query = {
|
207
|
+
"source.service" => source["service"],
|
208
|
+
"source.class" => source["class"],
|
209
|
+
"source.host" => source["host"],
|
210
|
+
"status" => "unseen",
|
211
|
+
"type" => type,
|
212
|
+
}
|
213
|
+
|
214
|
+
@db["events"].remove query
|
215
|
+
|
216
|
+
unseen_count =
|
217
|
+
@db.get_last_error["n"]
|
218
|
+
|
219
|
+
query = {
|
220
|
+
"source.service" => source["service"],
|
221
|
+
"source.class" => source["class"],
|
222
|
+
"source.host" => source["host"],
|
223
|
+
"status" => "seen",
|
224
|
+
"type" => type,
|
225
|
+
}
|
226
|
+
|
227
|
+
@db["events"].remove query
|
228
|
+
|
229
|
+
seen_count =
|
230
|
+
@db.get_last_error["n"]
|
231
|
+
|
232
|
+
# update summaries
|
233
|
+
|
234
|
+
@db["summaries"].update(
|
235
|
+
{
|
236
|
+
"_id.service" => source["service"],
|
237
|
+
"_id.class" => source["class"],
|
238
|
+
"_id.host" => source["host"],
|
239
|
+
}, {
|
240
|
+
"$inc" => {
|
241
|
+
"combined.new" => - unseen_count,
|
242
|
+
"combined.total" => - unseen_count - seen_count,
|
243
|
+
"types.#{type}.new" => - unseen_count,
|
244
|
+
"types.#{type}.total" => - unseen_count - seen_count,
|
245
|
+
}
|
246
|
+
}
|
247
|
+
)
|
248
|
+
|
249
|
+
end
|
250
|
+
|
251
|
+
# notify icinga checks
|
252
|
+
|
253
|
+
do_checks
|
254
|
+
|
255
|
+
end
|
256
|
+
|
127
257
|
def get_summaries_by_service
|
128
258
|
|
129
259
|
summaries_by_service = {}
|
@@ -136,7 +266,9 @@ class Script
|
|
136
266
|
|
137
267
|
summary_by_service =
|
138
268
|
summaries_by_service[service] ||= {
|
139
|
-
"
|
269
|
+
"_id" => {
|
270
|
+
"service" => service,
|
271
|
+
},
|
140
272
|
"combined" => { "new" => 0, "total" => 0 },
|
141
273
|
"types" => {},
|
142
274
|
}
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require "hq/tools/escape"
|
2
|
+
|
3
|
+
module HQ
|
4
|
+
module LogMonitorServer
|
5
|
+
|
6
|
+
class Script
|
7
|
+
|
8
|
+
include Tools::Escape
|
9
|
+
|
10
|
+
def status_breakdown summary, status
|
11
|
+
|
12
|
+
if summary["combined"][status] == 0
|
13
|
+
|
14
|
+
return "0"
|
15
|
+
|
16
|
+
else
|
17
|
+
|
18
|
+
return "%s (%s)" % [
|
19
|
+
|
20
|
+
summary["combined"][status].to_s,
|
21
|
+
|
22
|
+
summary["types"]
|
23
|
+
.select {
|
24
|
+
|type, counts|
|
25
|
+
counts[status] > 0
|
26
|
+
}
|
27
|
+
.map {
|
28
|
+
|type, counts|
|
29
|
+
"%s %s" % [ counts[status], type ]
|
30
|
+
}
|
31
|
+
.join(", ")
|
32
|
+
|
33
|
+
]
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
def level_for_type service_name, type_name
|
40
|
+
|
41
|
+
service_elem =
|
42
|
+
@icinga_elem.find_first("
|
43
|
+
service [@name = #{esc_xp service_name}]
|
44
|
+
")
|
45
|
+
|
46
|
+
return nil unless service_elem
|
47
|
+
|
48
|
+
type_elem =
|
49
|
+
service_elem.find_first("
|
50
|
+
type [@name = #{esc_xp type_name}]
|
51
|
+
")
|
52
|
+
|
53
|
+
return nil unless type_elem
|
54
|
+
|
55
|
+
level = type_elem["level"]
|
56
|
+
|
57
|
+
return level == "" ? nil : level
|
58
|
+
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
def class_for_level level
|
63
|
+
|
64
|
+
case level
|
65
|
+
|
66
|
+
when "critical"
|
67
|
+
return "error"
|
68
|
+
|
69
|
+
when "warning"
|
70
|
+
return "warning"
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
def class_for_type service, type
|
77
|
+
|
78
|
+
level = level_for_type service, type
|
79
|
+
|
80
|
+
return class_for_level level
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
def class_for_event event
|
85
|
+
|
86
|
+
return nil \
|
87
|
+
unless event["status"] == "unseen"
|
88
|
+
|
89
|
+
return class_for_type \
|
90
|
+
event["source"]["service"],
|
91
|
+
event["type"]
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
def level_for_summary summary
|
96
|
+
|
97
|
+
critical = false
|
98
|
+
warning = false
|
99
|
+
|
100
|
+
summary["types"].each do
|
101
|
+
|type_name, type_info|
|
102
|
+
|
103
|
+
next unless type_info["new"] > 0
|
104
|
+
|
105
|
+
case level_for_type summary["_id"]["service"], type_name
|
106
|
+
|
107
|
+
when "critical"
|
108
|
+
critical = true
|
109
|
+
|
110
|
+
when "warning"
|
111
|
+
warning = true
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
return "critical" if critical
|
118
|
+
return "warning" if warning
|
119
|
+
|
120
|
+
return nil
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
def class_for_summary summary
|
125
|
+
|
126
|
+
level = level_for_summary summary
|
127
|
+
|
128
|
+
return class_for_level level
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
@@ -66,8 +66,8 @@ class Script
|
|
66
66
|
|
67
67
|
html << "<tr>\n"
|
68
68
|
html << "<th>Service</th>\n"
|
69
|
-
html << "<th>
|
70
|
-
html << "<th>
|
69
|
+
html << "<th>New</th>\n"
|
70
|
+
html << "<th>Total</th>\n"
|
71
71
|
html << "<th>View</th>\n"
|
72
72
|
html << "</tr>\n"
|
73
73
|
|
@@ -77,29 +77,29 @@ class Script
|
|
77
77
|
summaries_by_service.each do
|
78
78
|
|service, summary|
|
79
79
|
|
80
|
-
html << "<tr class=\"
|
80
|
+
html << "<tr class=\"%s\">\n" % [
|
81
|
+
esc_ht([
|
82
|
+
"summary",
|
83
|
+
class_for_summary(summary),
|
84
|
+
].compact.join(" "))
|
85
|
+
]
|
81
86
|
|
82
87
|
html << "<td class=\"service\">%s</td>\n" % [
|
83
|
-
esc_ht(summary["service"]),
|
88
|
+
esc_ht(summary["_id"]["service"]),
|
84
89
|
]
|
85
90
|
|
86
|
-
html << "<td class=\"
|
87
|
-
esc_ht(summary
|
91
|
+
html << "<td class=\"new\">%s</td>\n" % [
|
92
|
+
esc_ht(status_breakdown(summary, "new")),
|
88
93
|
]
|
89
94
|
|
90
|
-
html << "<td class=\"
|
91
|
-
esc_ht(
|
92
|
-
summary["types"].map {
|
93
|
-
|type, counts|
|
94
|
-
"%s %s" % [ counts["new"], type ]
|
95
|
-
}.join ", "
|
96
|
-
),
|
95
|
+
html << "<td class=\"total\">%s</td>\n" % [
|
96
|
+
esc_ht(status_breakdown(summary, "total")),
|
97
97
|
]
|
98
98
|
|
99
99
|
html << "<td class=\"view\">%s</td>\n" % [
|
100
100
|
"<a href=\"%s\">view</a>" % [
|
101
101
|
"/service/%s" % [
|
102
|
-
esc_ue(summary["service"]),
|
102
|
+
esc_ue(summary["_id"]["service"]),
|
103
103
|
],
|
104
104
|
],
|
105
105
|
]
|
@@ -210,6 +210,7 @@ end
|
|
210
210
|
require "hq/log-monitor-server/do-checks"
|
211
211
|
require "hq/log-monitor-server/event-page"
|
212
212
|
require "hq/log-monitor-server/logic"
|
213
|
+
require "hq/log-monitor-server/misc"
|
213
214
|
require "hq/log-monitor-server/overview-page"
|
214
215
|
require "hq/log-monitor-server/service-host-page"
|
215
216
|
require "hq/log-monitor-server/service-page"
|
@@ -22,6 +22,13 @@ class Script
|
|
22
22
|
|
23
23
|
end
|
24
24
|
|
25
|
+
if req.request_method == "POST" \
|
26
|
+
&& req.params["delete-all"]
|
27
|
+
|
28
|
+
delete_all source
|
29
|
+
|
30
|
+
end
|
31
|
+
|
25
32
|
# read from database
|
26
33
|
|
27
34
|
events =
|
@@ -97,8 +104,10 @@ class Script
|
|
97
104
|
]
|
98
105
|
|
99
106
|
if events.empty?
|
107
|
+
|
100
108
|
html << "<p>No events have been logged for this service on this " +
|
101
109
|
"host</p>\n"
|
110
|
+
|
102
111
|
else
|
103
112
|
|
104
113
|
html << "<table id=\"events\" class=\"table table-striped\">\n"
|
@@ -121,7 +130,12 @@ class Script
|
|
121
130
|
events.each do
|
122
131
|
|event|
|
123
132
|
|
124
|
-
html << "<tr class=\"
|
133
|
+
html << "<tr class=\"%s\">\n" % [
|
134
|
+
[
|
135
|
+
"event",
|
136
|
+
class_for_event(event),
|
137
|
+
].compact.join(" "),
|
138
|
+
]
|
125
139
|
|
126
140
|
html << "<td class=\"timestamp\">%s</td>\n" % [
|
127
141
|
esc_ht(event["timestamp"].to_s),
|
@@ -175,6 +189,12 @@ class Script
|
|
175
189
|
|
176
190
|
end
|
177
191
|
|
192
|
+
html <<
|
193
|
+
"<input " +
|
194
|
+
"type=\"submit\" " +
|
195
|
+
"name=\"delete-all\" " +
|
196
|
+
"value=\"delete all\">\n"
|
197
|
+
|
178
198
|
html << "</p>\n"
|
179
199
|
|
180
200
|
html << "</form>\n"
|
@@ -76,8 +76,8 @@ class Script
|
|
76
76
|
html << "<tr>\n"
|
77
77
|
html << "<th>Host</th>\n"
|
78
78
|
html << "<th>Class</th>\n"
|
79
|
-
html << "<th>
|
80
|
-
html << "<th>
|
79
|
+
html << "<th>New</th>\n"
|
80
|
+
html << "<th>Total</th>\n"
|
81
81
|
html << "<th>View</th>\n"
|
82
82
|
html << "</tr>\n"
|
83
83
|
|
@@ -87,7 +87,12 @@ class Script
|
|
87
87
|
summaries.each do
|
88
88
|
|summary|
|
89
89
|
|
90
|
-
html << "<tr class=\"
|
90
|
+
html << "<tr class=\"%s\">\n" % [
|
91
|
+
esc_ht([
|
92
|
+
"summary",
|
93
|
+
class_for_summary(summary),
|
94
|
+
].compact.join(" "))
|
95
|
+
]
|
91
96
|
|
92
97
|
html << "<td class=\"host\">%s</td>\n" % [
|
93
98
|
esc_ht(summary["_id"]["host"]),
|
@@ -97,17 +102,12 @@ class Script
|
|
97
102
|
esc_ht(summary["_id"]["class"]),
|
98
103
|
]
|
99
104
|
|
100
|
-
html << "<td class=\"
|
101
|
-
esc_ht(summary
|
105
|
+
html << "<td class=\"new\">%s</td>\n" % [
|
106
|
+
esc_ht(status_breakdown(summary, "new")),
|
102
107
|
]
|
103
108
|
|
104
|
-
html << "<td class=\"
|
105
|
-
esc_ht(
|
106
|
-
summary["types"].map {
|
107
|
-
|type, counts|
|
108
|
-
"%s %s" % [ counts["new"], type ]
|
109
|
-
}.join ", "
|
110
|
-
),
|
109
|
+
html << "<td class=\"total\">%s</td>\n" % [
|
110
|
+
esc_ht(status_breakdown(summary, "total")),
|
111
111
|
]
|
112
112
|
|
113
113
|
html << "<td class=\"view\">%s</td>\n" % [
|
@@ -0,0 +1,198 @@
|
|
1
|
+
require "hq/log-monitor-server/misc"
|
2
|
+
|
3
|
+
module HQ
|
4
|
+
module LogMonitorServer
|
5
|
+
|
6
|
+
describe Script do
|
7
|
+
|
8
|
+
context "#status_breakdown" do
|
9
|
+
|
10
|
+
it "shows 0 if the combined amount is 0" do
|
11
|
+
summary = {
|
12
|
+
"combined" => { "new" => 0 },
|
13
|
+
}
|
14
|
+
ret = subject.status_breakdown summary, "new"
|
15
|
+
ret.should == "0"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "shows a breakdown if the combined amount is greater than 0" do
|
19
|
+
summary = {
|
20
|
+
"combined" => { "new" => 3 },
|
21
|
+
"types" => {
|
22
|
+
"type1" => { "new" => 1 },
|
23
|
+
"type2" => { "new" => 2 },
|
24
|
+
},
|
25
|
+
}
|
26
|
+
ret = subject.status_breakdown summary, "new"
|
27
|
+
ret.should == "3 (1 type1, 2 type2)"
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
context "#level_for_type" do
|
33
|
+
|
34
|
+
before do
|
35
|
+
require "xml"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "returns nil if the service does not exist" do
|
39
|
+
|
40
|
+
subject.instance_variable_set \
|
41
|
+
"@icinga_elem",
|
42
|
+
XML::Document.string("<icinga/>")
|
43
|
+
|
44
|
+
ret = subject.level_for_type "service", "type"
|
45
|
+
|
46
|
+
ret.should == nil
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
it "returns nil if the type does not exist" do
|
51
|
+
|
52
|
+
subject.instance_variable_set \
|
53
|
+
"@icinga_elem",
|
54
|
+
XML::Document.string("
|
55
|
+
<icinga>
|
56
|
+
<service name=\"service\"/>
|
57
|
+
</icinga>
|
58
|
+
")
|
59
|
+
|
60
|
+
ret = subject.level_for_type "service", "type"
|
61
|
+
|
62
|
+
ret.should == nil
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
it "returns nil if the type has no level" do
|
67
|
+
|
68
|
+
subject.instance_variable_set \
|
69
|
+
"@icinga_elem",
|
70
|
+
XML::Document.string("
|
71
|
+
<icinga>
|
72
|
+
<service name=\"service\">
|
73
|
+
<type name=\"type\"/>
|
74
|
+
</service>
|
75
|
+
</icinga>
|
76
|
+
")
|
77
|
+
|
78
|
+
ret = subject.level_for_type "service", "type"
|
79
|
+
|
80
|
+
ret.should == nil
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
it "returns nil if the type has an empty level" do
|
85
|
+
|
86
|
+
subject.instance_variable_set \
|
87
|
+
"@icinga_elem",
|
88
|
+
XML::Document.string("
|
89
|
+
<icinga>
|
90
|
+
<service name=\"service\">
|
91
|
+
<type name=\"type\" level=\"\"/>
|
92
|
+
</service>
|
93
|
+
</icinga>
|
94
|
+
")
|
95
|
+
|
96
|
+
ret = subject.level_for_type "service", "type"
|
97
|
+
|
98
|
+
ret.should == nil
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
it "returns the appropriate level if all is well" do
|
103
|
+
|
104
|
+
subject.instance_variable_set \
|
105
|
+
"@icinga_elem",
|
106
|
+
XML::Document.string("
|
107
|
+
<icinga>
|
108
|
+
<service name=\"service\">
|
109
|
+
<type name=\"type\" level=\"level\"/>
|
110
|
+
</service>
|
111
|
+
</icinga>
|
112
|
+
")
|
113
|
+
|
114
|
+
ret = subject.level_for_type "service", "type"
|
115
|
+
|
116
|
+
ret.should == "level"
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
context "#level_for_summary" do
|
123
|
+
|
124
|
+
before do
|
125
|
+
|
126
|
+
subject.instance_variable_set \
|
127
|
+
"@icinga_elem",
|
128
|
+
XML::Document.string("
|
129
|
+
<icinga>
|
130
|
+
<service name=\"service\">
|
131
|
+
<type name=\"critical\" level=\"critical\"/>
|
132
|
+
<type name=\"warning\" level=\"warning\"/>
|
133
|
+
</service>
|
134
|
+
</icinga>
|
135
|
+
")
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
it "returns critical if any are critical" do
|
140
|
+
|
141
|
+
summary = {
|
142
|
+
"_id" => {
|
143
|
+
"service" => "service",
|
144
|
+
},
|
145
|
+
"types" => {
|
146
|
+
"critical" => { "new" => 1 },
|
147
|
+
"warning" => { "new" => 1 },
|
148
|
+
"other" => { "new" => 1 },
|
149
|
+
},
|
150
|
+
}
|
151
|
+
|
152
|
+
ret = subject.level_for_summary summary
|
153
|
+
|
154
|
+
ret.should == "critical"
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
it "returns warning if any are warning but none are critical" do
|
159
|
+
|
160
|
+
summary = {
|
161
|
+
"_id" => {
|
162
|
+
"service" => "service",
|
163
|
+
},
|
164
|
+
"types" => {
|
165
|
+
"warning" => { "new" => 1 },
|
166
|
+
"other" => { "new" => 1 },
|
167
|
+
},
|
168
|
+
}
|
169
|
+
|
170
|
+
ret = subject.level_for_summary summary
|
171
|
+
|
172
|
+
ret.should == "warning"
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
it "returns nil if there none are warning or critical" do
|
177
|
+
|
178
|
+
summary = {
|
179
|
+
"_id" => {
|
180
|
+
"service" => "service",
|
181
|
+
},
|
182
|
+
"types" => {
|
183
|
+
"other" => { "new" => 1 },
|
184
|
+
},
|
185
|
+
}
|
186
|
+
|
187
|
+
ret = subject.level_for_summary summary
|
188
|
+
|
189
|
+
ret.should be_nil
|
190
|
+
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
198
|
+
end
|
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hq-log-monitor-server
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.7.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- James Pharaoh
|
@@ -14,209 +13,183 @@ dependencies:
|
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: bson_ext
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - '>='
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: 1.8.2
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - '>='
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: 1.8.2
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: hq-tools
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - '>='
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: 0.2.0
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - '>='
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: 0.2.0
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: libxml-ruby
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - '>='
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: 2.6.0
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - '>='
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: 2.6.0
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: mongo
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
|
-
- -
|
59
|
+
- - '>='
|
68
60
|
- !ruby/object:Gem::Version
|
69
61
|
version: 1.8.2
|
70
62
|
type: :runtime
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
|
-
- -
|
66
|
+
- - '>='
|
76
67
|
- !ruby/object:Gem::Version
|
77
68
|
version: 1.8.2
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: multi_json
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
|
-
- -
|
73
|
+
- - '>='
|
84
74
|
- !ruby/object:Gem::Version
|
85
75
|
version: 1.6.1
|
86
76
|
type: :runtime
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
|
-
- -
|
80
|
+
- - '>='
|
92
81
|
- !ruby/object:Gem::Version
|
93
82
|
version: 1.6.1
|
94
83
|
- !ruby/object:Gem::Dependency
|
95
84
|
name: rack
|
96
85
|
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
86
|
requirements:
|
99
|
-
- -
|
87
|
+
- - '>='
|
100
88
|
- !ruby/object:Gem::Version
|
101
89
|
version: 1.5.1
|
102
90
|
type: :runtime
|
103
91
|
prerelease: false
|
104
92
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
93
|
requirements:
|
107
|
-
- -
|
94
|
+
- - '>='
|
108
95
|
- !ruby/object:Gem::Version
|
109
96
|
version: 1.5.1
|
110
97
|
- !ruby/object:Gem::Dependency
|
111
98
|
name: capybara
|
112
99
|
requirement: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
100
|
requirements:
|
115
|
-
- -
|
101
|
+
- - '>='
|
116
102
|
- !ruby/object:Gem::Version
|
117
103
|
version: 2.0.2
|
118
104
|
type: :development
|
119
105
|
prerelease: false
|
120
106
|
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
none: false
|
122
107
|
requirements:
|
123
|
-
- -
|
108
|
+
- - '>='
|
124
109
|
- !ruby/object:Gem::Version
|
125
110
|
version: 2.0.2
|
126
111
|
- !ruby/object:Gem::Dependency
|
127
112
|
name: cucumber
|
128
113
|
requirement: !ruby/object:Gem::Requirement
|
129
|
-
none: false
|
130
114
|
requirements:
|
131
|
-
- -
|
115
|
+
- - '>='
|
132
116
|
- !ruby/object:Gem::Version
|
133
117
|
version: 1.2.1
|
134
118
|
type: :development
|
135
119
|
prerelease: false
|
136
120
|
version_requirements: !ruby/object:Gem::Requirement
|
137
|
-
none: false
|
138
121
|
requirements:
|
139
|
-
- -
|
122
|
+
- - '>='
|
140
123
|
- !ruby/object:Gem::Version
|
141
124
|
version: 1.2.1
|
142
125
|
- !ruby/object:Gem::Dependency
|
143
126
|
name: json
|
144
127
|
requirement: !ruby/object:Gem::Requirement
|
145
|
-
none: false
|
146
128
|
requirements:
|
147
|
-
- -
|
129
|
+
- - '>='
|
148
130
|
- !ruby/object:Gem::Version
|
149
131
|
version: 1.7.7
|
150
132
|
type: :development
|
151
133
|
prerelease: false
|
152
134
|
version_requirements: !ruby/object:Gem::Requirement
|
153
|
-
none: false
|
154
135
|
requirements:
|
155
|
-
- -
|
136
|
+
- - '>='
|
156
137
|
- !ruby/object:Gem::Version
|
157
138
|
version: 1.7.7
|
158
139
|
- !ruby/object:Gem::Dependency
|
159
140
|
name: rake
|
160
141
|
requirement: !ruby/object:Gem::Requirement
|
161
|
-
none: false
|
162
142
|
requirements:
|
163
|
-
- -
|
143
|
+
- - '>='
|
164
144
|
- !ruby/object:Gem::Version
|
165
145
|
version: 10.0.3
|
166
146
|
type: :development
|
167
147
|
prerelease: false
|
168
148
|
version_requirements: !ruby/object:Gem::Requirement
|
169
|
-
none: false
|
170
149
|
requirements:
|
171
|
-
- -
|
150
|
+
- - '>='
|
172
151
|
- !ruby/object:Gem::Version
|
173
152
|
version: 10.0.3
|
174
153
|
- !ruby/object:Gem::Dependency
|
175
154
|
name: rspec
|
176
155
|
requirement: !ruby/object:Gem::Requirement
|
177
|
-
none: false
|
178
156
|
requirements:
|
179
|
-
- -
|
157
|
+
- - '>='
|
180
158
|
- !ruby/object:Gem::Version
|
181
159
|
version: 2.12.0
|
182
160
|
type: :development
|
183
161
|
prerelease: false
|
184
162
|
version_requirements: !ruby/object:Gem::Requirement
|
185
|
-
none: false
|
186
163
|
requirements:
|
187
|
-
- -
|
164
|
+
- - '>='
|
188
165
|
- !ruby/object:Gem::Version
|
189
166
|
version: 2.12.0
|
190
167
|
- !ruby/object:Gem::Dependency
|
191
168
|
name: rspec_junit_formatter
|
192
169
|
requirement: !ruby/object:Gem::Requirement
|
193
|
-
none: false
|
194
170
|
requirements:
|
195
|
-
- -
|
171
|
+
- - '>='
|
196
172
|
- !ruby/object:Gem::Version
|
197
173
|
version: '0'
|
198
174
|
type: :development
|
199
175
|
prerelease: false
|
200
176
|
version_requirements: !ruby/object:Gem::Requirement
|
201
|
-
none: false
|
202
177
|
requirements:
|
203
|
-
- -
|
178
|
+
- - '>='
|
204
179
|
- !ruby/object:Gem::Version
|
205
180
|
version: '0'
|
206
181
|
- !ruby/object:Gem::Dependency
|
207
182
|
name: simplecov
|
208
183
|
requirement: !ruby/object:Gem::Requirement
|
209
|
-
none: false
|
210
184
|
requirements:
|
211
|
-
- -
|
185
|
+
- - '>='
|
212
186
|
- !ruby/object:Gem::Version
|
213
187
|
version: '0'
|
214
188
|
type: :development
|
215
189
|
prerelease: false
|
216
190
|
version_requirements: !ruby/object:Gem::Requirement
|
217
|
-
none: false
|
218
191
|
requirements:
|
219
|
-
- -
|
192
|
+
- - '>='
|
220
193
|
- !ruby/object:Gem::Version
|
221
194
|
version: '0'
|
222
195
|
description: HQ log monitor system, central component
|
@@ -231,6 +204,7 @@ files:
|
|
231
204
|
- lib/hq/log-monitor-server/do-checks.rb
|
232
205
|
- lib/hq/log-monitor-server/submit-log-event.rb
|
233
206
|
- lib/hq/log-monitor-server/script.rb
|
207
|
+
- lib/hq/log-monitor-server/misc.rb
|
234
208
|
- lib/hq/log-monitor-server/service-host-page.rb
|
235
209
|
- lib/hq/log-monitor-server/service-page.rb
|
236
210
|
- lib/hq/log-monitor-server/event-page.rb
|
@@ -242,30 +216,30 @@ files:
|
|
242
216
|
- features/support/steps.rb
|
243
217
|
- features/support/env.rb
|
244
218
|
- features/support/ui-steps.rb
|
219
|
+
- spec/hq/log-monitor-server/misc-spec.rb
|
245
220
|
- bin/hq-log-monitor-server
|
246
221
|
homepage: https://github.com/jamespharaoh/hq-log-monitor-server
|
247
222
|
licenses: []
|
223
|
+
metadata: {}
|
248
224
|
post_install_message:
|
249
225
|
rdoc_options: []
|
250
226
|
require_paths:
|
251
227
|
- lib
|
252
228
|
required_ruby_version: !ruby/object:Gem::Requirement
|
253
|
-
none: false
|
254
229
|
requirements:
|
255
|
-
- -
|
230
|
+
- - '>='
|
256
231
|
- !ruby/object:Gem::Version
|
257
232
|
version: '0'
|
258
233
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
259
|
-
none: false
|
260
234
|
requirements:
|
261
|
-
- -
|
235
|
+
- - '>='
|
262
236
|
- !ruby/object:Gem::Version
|
263
237
|
version: 1.3.6
|
264
238
|
requirements: []
|
265
239
|
rubyforge_project: hq-log-monitor-server
|
266
|
-
rubygems_version:
|
240
|
+
rubygems_version: 2.0.3
|
267
241
|
signing_key:
|
268
|
-
specification_version:
|
242
|
+
specification_version: 4
|
269
243
|
summary: HQ log monitor server
|
270
244
|
test_files:
|
271
245
|
- features/event-page.feature
|
@@ -275,3 +249,4 @@ test_files:
|
|
275
249
|
- features/support/steps.rb
|
276
250
|
- features/support/env.rb
|
277
251
|
- features/support/ui-steps.rb
|
252
|
+
- spec/hq/log-monitor-server/misc-spec.rb
|