sensu-plugins-outlyer 0.3.0 → 0.4.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 +4 -4
- data/CHANGELOG.md +7 -4
- data/README.md +24 -90
- data/bin/outlyer-metrics.rb +88 -17
- data/lib/sensu-plugins-outlyer/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 06fefcec9b4ad9d5c308b13f85f547b0bd4b8b53
|
4
|
+
data.tar.gz: e2b9db23d1252b2eeb1874eb3fd13a5c5290af91
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2219ff7def5ba400bac2ed178d395ce94d786b95b3dc2102a5a86f5ae7c4c440fc0bfa7476ae663597425cea75f46ddd0d852b3c46804fa13555f8063be44da4
|
7
|
+
data.tar.gz: 680a766582636eaf7b826bc8b7eccee35967b66c99ac98804cd9da1a5d039d6c247c740d67eb29e50cd7956a52419a4a75095fbefb9d31ac6f77bce001917113
|
data/CHANGELOG.md
CHANGED
@@ -3,10 +3,13 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
3
3
|
|
4
4
|
This CHANGELOG follows the format listed at [Keep A Changelog](http://keepachangelog.com/)
|
5
5
|
|
6
|
-
## 0.
|
7
|
-
|
6
|
+
## [0.4.0] - 2018-07-13
|
7
|
+
- Added handling for client environments set as array of values
|
8
|
+
- Added schemas so graphite metric names can be parsed into dimensional metrics
|
9
|
+
- Added debug option
|
10
|
+
|
11
|
+
## [0.3.0] - 2018-07-13
|
8
12
|
- Better logging
|
9
13
|
|
10
|
-
## 0.1.0 - 2018-07-12
|
11
|
-
### Added
|
14
|
+
## [0.1.0] - 2018-07-12
|
12
15
|
- initial release
|
data/README.md
CHANGED
@@ -1,113 +1,47 @@
|
|
1
|
-
|
2
|
-
=================================
|
1
|
+
# Sensu Outlyer Handler Plugin
|
3
2
|
|
4
|
-
|
3
|
+
This readme includes development instructions for building, packaging and testing the Sensu plugin in Ruby.
|
5
4
|
|
6
|
-
|
7
|
-
to push all your check event metrics and check status's from Sensu checks into Outlyer. It supports
|
8
|
-
both Nagios checks and Graphite Metric check outputs from Sensu.
|
5
|
+
## Packaging and Publishing
|
9
6
|
|
10
|
-
|
11
|
-
use on custom dashboards and alerts.
|
12
|
-
|
13
|
-
== Metrics Collected ==
|
14
|
-
|
15
|
-
The Sensu integration will push any metric collected by your Sensu checks with metric
|
16
|
-
names namespaced to the check name as follows:
|
7
|
+
First build the gem:
|
17
8
|
|
18
9
|
```
|
19
|
-
|
10
|
+
gem build sensu-plugins-outlyer.gemspec
|
20
11
|
```
|
21
12
|
|
22
|
-
|
23
|
-
|
24
|
-
metric to configure dashboad status widgets and service check alerts in Outlyer.
|
25
|
-
|
26
|
-
For Nagios checks, the timestamp of when the check was executed is used for all the
|
27
|
-
metric data points. For Graphite metric checks the timestamp of each metric data
|
28
|
-
point is used, apart from the service.status which uses the check execution time
|
29
|
-
like Nagios checks.
|
30
|
-
|
31
|
-
== Installation ==
|
32
|
-
|
33
|
-
Firstly install the Outlyer Sensu plugin on your Sensu machine(s) using the following
|
34
|
-
command:
|
13
|
+
Then publish the sensu-plugins-outlyer gem to the Outlyer account on the RubyGems server
|
14
|
+
using the following command:
|
35
15
|
|
36
16
|
```bash
|
37
|
-
sensu-
|
17
|
+
gem push sensu-plugins-outlyer-<version_number>.gem
|
38
18
|
```
|
39
19
|
|
40
|
-
|
41
|
-
|
42
|
-
```json
|
43
|
-
{
|
44
|
-
"handlers": {
|
45
|
-
"outlyer-graphite": {
|
46
|
-
"type": "pipe",
|
47
|
-
"command": "/opt/sensu/embedded/bin/outlyer-metrics.rb"
|
48
|
-
},
|
49
|
-
"outlyer-nagios": {
|
50
|
-
"type": "pipe",
|
51
|
-
"command": "/opt/sensu/embedded/bin/outlyer-metrics.rb -f nagios"
|
52
|
-
}
|
53
|
-
}
|
54
|
-
}
|
55
|
-
```
|
56
|
-
|
57
|
-
Two handlers have been configured, one for your Nagios checks `outlyer-nagios` and
|
58
|
-
one for your Graphite metric checks `outlyer-graphite`. You can refer to these handlers
|
59
|
-
in your check configurations to ensure they are handled by the Outlyer handler with
|
60
|
-
the correct check output parsing.
|
61
|
-
|
62
|
-
You can also add the optional `-t` parameter to the handler command to change the default
|
63
|
-
timeout for Outlyer API requests from 5 seconds. This is useful if you notice the handler
|
64
|
-
timing out as your checks send more metrics creating larger payloads.
|
20
|
+
## Testing
|
65
21
|
|
66
|
-
|
22
|
+
First copy the example config file under `test/test-config.json` to a path outside your
|
23
|
+
project and set the account and your API key in the new file. Then set the path to your
|
24
|
+
handler configuration file with your API details as an environment variable:
|
67
25
|
|
68
|
-
```
|
69
|
-
|
70
|
-
"outlyer": {
|
71
|
-
"api_key": "<API_KEY>",
|
72
|
-
"account": "<ACCOUNT_NAME>"
|
73
|
-
}
|
74
|
-
}
|
26
|
+
```bash
|
27
|
+
export SENSU_CONFIG_FILES='/Users/dgildeh/Development/Outlyer/sensu-config.json'
|
75
28
|
```
|
76
29
|
|
77
|
-
|
78
|
-
|
79
|
-
* **api_key**: Your user's API key generated under user settings
|
80
|
-
* **account**: The unique account name of the account you want to push metrics too (you will see this in the URL when using the app)
|
81
|
-
|
82
|
-
Finally restart your Sensu server so the new handler is enabled:
|
30
|
+
Then you can use the following command to test the handler with example Nagios
|
31
|
+
output data using the following command:
|
83
32
|
|
84
33
|
```bash
|
85
|
-
|
34
|
+
cat ./test/test-nagios-data.json | ruby ./bin/outlyer-metrics.rb -f nagios
|
86
35
|
```
|
87
|
-
|
88
|
-
You will need to add the handler to all the checks you want metrics sent to Outlyer for by adding
|
89
|
-
`outlyer-nagios` or `outlyer-graphite` to your check handlers configuration as appropriate. Once
|
90
|
-
your checks have been configured to use the Outlyer handler you should start seeing all your
|
91
|
-
metrics from your configured Sensu checks appearing in Outlyer shortly afterwards.
|
92
|
-
|
93
|
-
Also ensure any Sensu checks that send metrics have type `metric` otherwise the output will not
|
94
|
-
be processed everytime the check runs.
|
95
|
-
|
96
|
-
Please read the Metrics Collected section of this guide to understand how your check metrics
|
97
|
-
are sent to Outlyer.
|
98
|
-
|
99
|
-
## Troubleshooting
|
100
|
-
|
101
|
-
If you don't see metrics appearing in Outlyer after enabling the handlers and checks
|
102
|
-
you should use the following command to view the Sensu server logs to see if any
|
103
|
-
errors are being output by the hander:
|
36
|
+
For Graphite metric test:
|
104
37
|
|
105
38
|
```bash
|
106
|
-
|
39
|
+
cat ./test/test-graphite-data.json | ruby ./bin/outlyer-metrics.rb
|
107
40
|
```
|
108
41
|
|
109
|
-
|
42
|
+
Note you will have to override the check timestamp to the current time so your
|
43
|
+
metrics will appear in Outlyer using the test above:
|
110
44
|
|
111
|
-
|
112
|
-
|
113
|
-
|
45
|
+
```ruby
|
46
|
+
timestamp = Time.now.to_i * 1000
|
47
|
+
```
|
data/bin/outlyer-metrics.rb
CHANGED
@@ -51,6 +51,12 @@ class OutlyerMetrics < Sensu::Handler
|
|
51
51
|
short: '-t TIMEOUT',
|
52
52
|
long: '--timeout TIMEOUT',
|
53
53
|
default: '5'
|
54
|
+
|
55
|
+
option :debug,
|
56
|
+
description: 'Enable debug for more verbose output',
|
57
|
+
short: '-d DEBUG',
|
58
|
+
long: '--debug DEBUG',
|
59
|
+
default: 'false'
|
54
60
|
|
55
61
|
# Override filters from Sensu::Handler.
|
56
62
|
# They are not appropriate for metric handlers
|
@@ -62,16 +68,22 @@ class OutlyerMetrics < Sensu::Handler
|
|
62
68
|
#
|
63
69
|
def handle
|
64
70
|
|
71
|
+
@debug = false
|
72
|
+
if config[:debug] == 'true'
|
73
|
+
@debug = true
|
74
|
+
end
|
75
|
+
|
65
76
|
output = @event['check']['output']
|
66
77
|
check_status = @event['check']['status'].to_f
|
67
78
|
@check_name = @event['check']['name']
|
68
|
-
@host = @event['client']['name']
|
79
|
+
@host = @event['client']['name'].strip.to_s
|
69
80
|
@environment = @event['client']['environment']
|
81
|
+
if @environment.kind_of?(Array)
|
82
|
+
# environment can be an array, so merge values with hyphens
|
83
|
+
@environment = @environment.join("-")
|
84
|
+
end
|
70
85
|
timestamp = @event['check']['executed'].to_i * 1000
|
71
86
|
|
72
|
-
# Uncomment this line for local testing outside Sensu
|
73
|
-
#@settings = { "outlyer" => {"account" => "", "api_key" => ""}}
|
74
|
-
|
75
87
|
# Parse output for metric data
|
76
88
|
metrics = if config[:output_format] == 'nagios' then
|
77
89
|
parse_nagios_output(output, timestamp)
|
@@ -80,7 +92,7 @@ class OutlyerMetrics < Sensu::Handler
|
|
80
92
|
end
|
81
93
|
|
82
94
|
# Add a service status metric
|
83
|
-
metrics.push(create_datapoint('service.status', check_status, timestamp, {service: "sensu.#{@check_name}"}))
|
95
|
+
metrics.push(create_datapoint('service.status', check_status, timestamp, {service: "sensu.#{sanitize_value(@check_name)}"}))
|
84
96
|
# Post metrics to Outlyer
|
85
97
|
push_metrics(metrics)
|
86
98
|
end
|
@@ -127,10 +139,11 @@ class OutlyerMetrics < Sensu::Handler
|
|
127
139
|
begin
|
128
140
|
name = metric_parts[0]
|
129
141
|
value = metric_parts[1].split(";")[0].to_f
|
130
|
-
|
142
|
+
labels = {service: "sensu.#{sanitize_value(@check_name)}"}
|
143
|
+
data.push(create_datapoint(name, value, timestamp, labels))
|
131
144
|
rescue => error
|
132
145
|
# Raised when any metrics could not be parsed
|
133
|
-
puts "
|
146
|
+
puts "The Nagios metric '#{metric}' could not be parsed: #{error.message}"
|
134
147
|
end
|
135
148
|
end
|
136
149
|
data
|
@@ -145,17 +158,71 @@ class OutlyerMetrics < Sensu::Handler
|
|
145
158
|
#
|
146
159
|
def parse_graphite_output(output)
|
147
160
|
data = []
|
161
|
+
|
162
|
+
# Get Scheme to parse Graphite metrics if exists
|
163
|
+
scheme = nil
|
164
|
+
if settings['outlyer'].key?('schemes') && settings['outlyer']['schemes'] != nil
|
165
|
+
if settings['outlyer']['schemes'].key?(@check_name)
|
166
|
+
scheme = settings['outlyer']['schemes'][@check_name]
|
167
|
+
else
|
168
|
+
# Get default scheme if check specific scheme not defined
|
169
|
+
scheme = settings['outlyer']['schemes']['default']
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# Parse the metric on each line in graphite format
|
148
174
|
output.split("\n").each do |metric|
|
149
175
|
m = metric.split
|
150
176
|
next unless m.count == 3
|
151
|
-
name
|
177
|
+
# Get name and extract labels - we remove hostname if in metric name
|
178
|
+
# as it contains dots and breaks parsing
|
179
|
+
metric_parts = m[0].gsub("#{@host}", 'host').split('.')
|
180
|
+
labels = {service: "sensu.#{sanitize_value(@check_name)}"}
|
181
|
+
if scheme
|
182
|
+
metric_name = metric_parts.last(scheme['metric_name_length'].to_i).join('.')
|
183
|
+
# Get dimensions from metric name
|
184
|
+
schema_parts = scheme['scheme'].split('.')
|
185
|
+
if (metric_parts.length - scheme['metric_name_length'].to_i) != schema_parts.length
|
186
|
+
puts "Schema Parsing Error: metric parts (#{metric_parts.length - scheme['metric_name_length'].to_i}) is not same length as schema (#{schema_parts.length})"
|
187
|
+
puts "Example metric: m[0]"
|
188
|
+
return []
|
189
|
+
end
|
190
|
+
schema_parts.each_with_index do |val,index|
|
191
|
+
if val != 'host' && val != 'hostname' && val != 'name'
|
192
|
+
labels.merge!(Hash[sanitize_value(val, 40),sanitize_value(metric_parts[index])])
|
193
|
+
end
|
194
|
+
end
|
195
|
+
else
|
196
|
+
metric_name = sanitize_value(metric_parts.join('.'))
|
197
|
+
end
|
152
198
|
value = m[1].to_f
|
153
|
-
time =
|
154
|
-
point = create_datapoint(
|
199
|
+
time = Time.now.to_i * 1000
|
200
|
+
point = create_datapoint(metric_name, value, time, labels)
|
155
201
|
data.push(point)
|
156
202
|
end
|
157
203
|
data
|
158
204
|
end
|
205
|
+
|
206
|
+
# Ensures all label values conform to Outlyer's data format requirements:
|
207
|
+
#
|
208
|
+
# * values can only contain the characters `-._A-Za-z0-9`, other characters
|
209
|
+
# will be replaced by underscore including spaces
|
210
|
+
# * values can only be 80 characters or less
|
211
|
+
#
|
212
|
+
# @param value [String] The value to sanitize
|
213
|
+
# @param max_length [Integer] The maximum length of string, default 80
|
214
|
+
#
|
215
|
+
def sanitize_value(value, max_length = 80)
|
216
|
+
if !value
|
217
|
+
return ''
|
218
|
+
end
|
219
|
+
value = value.gsub(/[^-._A-Za-z0-9]/i, '_').downcase
|
220
|
+
if value.length > max_length
|
221
|
+
puts "Warning: value '#{value}' is greater than 80 characters and will be truncated to last 80 characters"
|
222
|
+
value = value.split(//).last(max_length).join
|
223
|
+
end
|
224
|
+
value
|
225
|
+
end
|
159
226
|
|
160
227
|
# Post check metrics to Outlyer's Series API:
|
161
228
|
#
|
@@ -166,7 +233,7 @@ class OutlyerMetrics < Sensu::Handler
|
|
166
233
|
def push_metrics(datapoints)
|
167
234
|
Timeout.timeout(config[:api_timeout].to_i) do
|
168
235
|
uri = URI.parse("https://api2.outlyer.com/v2/accounts/#{settings['outlyer']['account']}/series")
|
169
|
-
|
236
|
+
|
170
237
|
# Create the HTTP objects
|
171
238
|
http = Net::HTTP.new(uri.host, uri.port)
|
172
239
|
http.use_ssl = true
|
@@ -176,13 +243,17 @@ class OutlyerMetrics < Sensu::Handler
|
|
176
243
|
request.add_field("accept", "application/json")
|
177
244
|
request.add_field("Content-Type", "application/json")
|
178
245
|
request.body = {samples: datapoints}.to_json
|
179
|
-
|
246
|
+
|
247
|
+
if @debug
|
248
|
+
puts "DEBUG: Outlyer API Payload: #{request.body}"
|
249
|
+
end
|
250
|
+
|
180
251
|
# Send the request
|
181
252
|
response = http.request(request)
|
182
253
|
if response.code.to_i != 200
|
183
|
-
puts "
|
184
|
-
puts "
|
185
|
-
puts "
|
254
|
+
puts "Outlyer API Error -- API responded with status code #{response.code}"
|
255
|
+
puts "Outlyer API Response: #{response.body}"
|
256
|
+
puts "Outlyer API Request Body: #{request.body}"
|
186
257
|
return
|
187
258
|
end
|
188
259
|
puts "Successfully pushed #{datapoints.length} metrics to Outlyer"
|
@@ -190,9 +261,9 @@ class OutlyerMetrics < Sensu::Handler
|
|
190
261
|
# Raised when any metrics could not be sent
|
191
262
|
#
|
192
263
|
rescue Timeout::Error
|
193
|
-
puts '
|
264
|
+
puts 'Outlyer API Error -- timed out while sending metrics'
|
194
265
|
rescue => error
|
195
|
-
puts "
|
266
|
+
puts "Outlyer API Error -- failed to send metrics: #{error.message}"
|
196
267
|
puts " #{error.backtrace.join("\n\t")}"
|
197
268
|
end
|
198
269
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sensu-plugins-outlyer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dataloop Software, INC. Trading as Outlyer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-07-
|
11
|
+
date: 2018-07-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sensu-plugin
|