logstash-output-graphite-mavlyutov 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +32 -0
- data/CONTRIBUTORS +22 -0
- data/Gemfile +11 -0
- data/LICENSE +13 -0
- data/NOTICE.TXT +5 -0
- data/README.md +98 -0
- data/docs/index.asciidoc +172 -0
- data/lib/logstash/outputs/graphite.rb +226 -0
- data/logstash-output-graphite.gemspec +30 -0
- data/spec/outputs/graphite_spec.rb +199 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/support/server.rb +29 -0
- metadata +138 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 136822ceb4a9a17016f9d77316efa454d78d1409
|
4
|
+
data.tar.gz: 74637f2414cfe17add60878e2806b3210915af42
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9327d6ba1e419f985ec0cc4f21ec99f963f43b1a3434b6785f780edabe56b257494b0eb2b6792db2d1f3fbe8195cc90f9567d3f1c68f87d0dbfbe8fb190640b8
|
7
|
+
data.tar.gz: 014ddb627b0fe85dc74ec4849710c39ee2c4d8f56bbe68d95af394b849dd6cd3dc02a5a2499281ce29ec1ae702784b8be294fd2a771905e91fb67eaa5eb18563
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
## 3.1.1
|
2
|
+
- Relax constraint on logstash-core-plugin-api to >= 1.60 <= 2.99
|
3
|
+
|
4
|
+
## 3.1.0
|
5
|
+
- breaking,config: Remove deprecated config `debug`.
|
6
|
+
|
7
|
+
## 3.0.1
|
8
|
+
- Republish all the gems under jruby.
|
9
|
+
|
10
|
+
## 3.0.0
|
11
|
+
- Update the plugin to the version 2.0 of the plugin api, this change is required for Logstash 5.0 compatibility. See https://github.com/elastic/logstash/issues/5141
|
12
|
+
|
13
|
+
## 2.0.5
|
14
|
+
- Depend on logstash-core-plugin-api instead of logstash-core, removing the need to mass update plugins on major releases of logstash
|
15
|
+
|
16
|
+
## 2.0.4
|
17
|
+
- New dependency requirements for logstash-core for the 5.0 release
|
18
|
+
|
19
|
+
## 2.0.3
|
20
|
+
- Fixed empty/nil messages handling
|
21
|
+
|
22
|
+
## 2.0.0
|
23
|
+
- Plugins were updated to follow the new shutdown semantic, this mainly allows Logstash to instruct input plugins to terminate gracefully,
|
24
|
+
instead of using Thread.raise on the plugins' threads. Ref: https://github.com/elastic/logstash/pull/3895
|
25
|
+
- Dependency on logstash-core update to 2.0
|
26
|
+
|
27
|
+
## 1.0.2
|
28
|
+
- Added support for sprintf in field formatting
|
29
|
+
|
30
|
+
## 1.0.1
|
31
|
+
- Added support for nested hashes as values
|
32
|
+
|
data/CONTRIBUTORS
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The following is a list of people who have contributed ideas, code, bug
|
2
|
+
reports, or in general have helped logstash along its way.
|
3
|
+
|
4
|
+
Contributors:
|
5
|
+
* Colin Surprenant (colinsurprenant)
|
6
|
+
* Dave Snigier (LambdaDriver)
|
7
|
+
* John E. Vincent (lusis)
|
8
|
+
* Jordan Sissel (jordansissel)
|
9
|
+
* Kurt Hurtado (kurtado)
|
10
|
+
* Michael Leinartas (mleinart)
|
11
|
+
* Pere Urbón (purbon)
|
12
|
+
* Pete Fritchman (fetep)
|
13
|
+
* Pier-Hugues Pellerin (ph)
|
14
|
+
* Rene Lengwinat (invadersmustdie)
|
15
|
+
* Richard Pijnenburg (electrical)
|
16
|
+
* eravenelle
|
17
|
+
* piavlo
|
18
|
+
|
19
|
+
Note: If you've sent us patches, bug reports, or otherwise contributed to
|
20
|
+
Logstash, and you aren't on the list above and want to be, please let us know
|
21
|
+
and we'll make sure you're here. Contributions from folks like you are what make
|
22
|
+
open source awesome.
|
data/Gemfile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
logstash_path = ENV["LOGSTASH_PATH"] || "../../logstash"
|
6
|
+
use_logstash_source = ENV["LOGSTASH_SOURCE"] && ENV["LOGSTASH_SOURCE"].to_s == "1"
|
7
|
+
|
8
|
+
if Dir.exist?(logstash_path) && use_logstash_source
|
9
|
+
gem 'logstash-core', :path => "#{logstash_path}/logstash-core"
|
10
|
+
gem 'logstash-core-plugin-api', :path => "#{logstash_path}/logstash-core-plugin-api"
|
11
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright (c) 2012–2016 Elasticsearch <http://www.elastic.co>
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
data/NOTICE.TXT
ADDED
data/README.md
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
# Logstash Plugin
|
2
|
+
|
3
|
+
[![Travis Build Status](https://travis-ci.org/logstash-plugins/logstash-output-graphite.svg)](https://travis-ci.org/logstash-plugins/logstash-output-graphite)
|
4
|
+
|
5
|
+
This is a plugin for [Logstash](https://github.com/elastic/logstash).
|
6
|
+
|
7
|
+
It is fully free and fully open source. The license is Apache 2.0, meaning you are pretty much free to use it however you want in whatever way.
|
8
|
+
|
9
|
+
## Documentation
|
10
|
+
|
11
|
+
Logstash provides infrastructure to automatically generate documentation for this plugin. We use the asciidoc format to write documentation so any comments in the source code will be first converted into asciidoc and then into html. All plugin documentation are placed under one [central location](http://www.elastic.co/guide/en/logstash/current/).
|
12
|
+
|
13
|
+
- For formatting code or config example, you can use the asciidoc `[source,ruby]` directive
|
14
|
+
- For more asciidoc formatting tips, see the excellent reference here https://github.com/elastic/docs#asciidoc-guide
|
15
|
+
|
16
|
+
## Need Help?
|
17
|
+
|
18
|
+
Need help? Try #logstash on freenode IRC or the https://discuss.elastic.co/c/logstash discussion forum.
|
19
|
+
|
20
|
+
## Developing
|
21
|
+
|
22
|
+
### 1. Plugin Developement and Testing
|
23
|
+
|
24
|
+
#### Code
|
25
|
+
- To get started, you'll need JRuby with the Bundler gem installed.
|
26
|
+
|
27
|
+
- Create a new plugin or clone and existing from the GitHub [logstash-plugins](https://github.com/logstash-plugins) organization. We also provide [example plugins](https://github.com/logstash-plugins?query=example).
|
28
|
+
|
29
|
+
- Install dependencies
|
30
|
+
```sh
|
31
|
+
bundle install
|
32
|
+
```
|
33
|
+
|
34
|
+
#### Test
|
35
|
+
|
36
|
+
- Update your dependencies
|
37
|
+
|
38
|
+
```sh
|
39
|
+
bundle install
|
40
|
+
```
|
41
|
+
|
42
|
+
- Run tests
|
43
|
+
|
44
|
+
```sh
|
45
|
+
bundle exec rspec
|
46
|
+
```
|
47
|
+
|
48
|
+
### 2. Running your unpublished Plugin in Logstash
|
49
|
+
|
50
|
+
#### 2.1 Run in a local Logstash clone
|
51
|
+
|
52
|
+
- Edit Logstash `Gemfile` and add the local plugin path, for example:
|
53
|
+
```ruby
|
54
|
+
gem "logstash-filter-awesome", :path => "/your/local/logstash-filter-awesome"
|
55
|
+
```
|
56
|
+
- Install plugin
|
57
|
+
```sh
|
58
|
+
# Logstash 2.3 and higher
|
59
|
+
bin/logstash-plugin install --no-verify
|
60
|
+
|
61
|
+
# Prior to Logstash 2.3
|
62
|
+
bin/plugin install --no-verify
|
63
|
+
|
64
|
+
```
|
65
|
+
- Run Logstash with your plugin
|
66
|
+
```sh
|
67
|
+
bin/logstash -e 'filter {awesome {}}'
|
68
|
+
```
|
69
|
+
At this point any modifications to the plugin code will be applied to this local Logstash setup. After modifying the plugin, simply rerun Logstash.
|
70
|
+
|
71
|
+
#### 2.2 Run in an installed Logstash
|
72
|
+
|
73
|
+
You can use the same **2.1** method to run your plugin in an installed Logstash by editing its `Gemfile` and pointing the `:path` to your local plugin development directory or you can build the gem and install it using:
|
74
|
+
|
75
|
+
- Build your plugin gem
|
76
|
+
```sh
|
77
|
+
gem build logstash-filter-awesome.gemspec
|
78
|
+
```
|
79
|
+
- Install the plugin from the Logstash home
|
80
|
+
```sh
|
81
|
+
# Logstash 2.3 and higher
|
82
|
+
bin/logstash-plugin install --no-verify
|
83
|
+
|
84
|
+
# Prior to Logstash 2.3
|
85
|
+
bin/plugin install --no-verify
|
86
|
+
|
87
|
+
```
|
88
|
+
- Start Logstash and proceed to test the plugin
|
89
|
+
|
90
|
+
## Contributing
|
91
|
+
|
92
|
+
All contributions are welcome: ideas, patches, documentation, bug reports, complaints, and even something you drew up on a napkin.
|
93
|
+
|
94
|
+
Programming is not a required skill. Whatever you've seen about open source and maintainers or community members saying "send patches or die" - you will not see that here.
|
95
|
+
|
96
|
+
It is more important to the community that you are able to contribute.
|
97
|
+
|
98
|
+
For more information about contributing, see the [CONTRIBUTING](https://github.com/elastic/logstash/blob/master/CONTRIBUTING.md) file.
|
data/docs/index.asciidoc
ADDED
@@ -0,0 +1,172 @@
|
|
1
|
+
:plugin: graphite
|
2
|
+
:type: output
|
3
|
+
|
4
|
+
///////////////////////////////////////////
|
5
|
+
START - GENERATED VARIABLES, DO NOT EDIT!
|
6
|
+
///////////////////////////////////////////
|
7
|
+
:version: %VERSION%
|
8
|
+
:release_date: %RELEASE_DATE%
|
9
|
+
:changelog_url: %CHANGELOG_URL%
|
10
|
+
:include_path: ../../../logstash/docs/include
|
11
|
+
///////////////////////////////////////////
|
12
|
+
END - GENERATED VARIABLES, DO NOT EDIT!
|
13
|
+
///////////////////////////////////////////
|
14
|
+
|
15
|
+
[id="plugins-{type}-{plugin}"]
|
16
|
+
|
17
|
+
=== Graphite
|
18
|
+
|
19
|
+
include::{include_path}/plugin_header.asciidoc[]
|
20
|
+
|
21
|
+
==== Description
|
22
|
+
|
23
|
+
This output allows you to pull metrics from your logs and ship them to
|
24
|
+
Graphite. Graphite is an open source tool for storing and graphing metrics.
|
25
|
+
|
26
|
+
An example use case: Some applications emit aggregated stats in the logs
|
27
|
+
every 10 seconds. Using the grok filter and this output, it is possible to
|
28
|
+
capture the metric values from the logs and emit them to Graphite.
|
29
|
+
|
30
|
+
[id="plugins-{type}s-{plugin}-options"]
|
31
|
+
==== Graphite Output Configuration Options
|
32
|
+
|
33
|
+
This plugin supports the following configuration options plus the <<plugins-{type}s-common-options>> described later.
|
34
|
+
|
35
|
+
[cols="<,<,<",options="header",]
|
36
|
+
|=======================================================================
|
37
|
+
|Setting |Input type|Required
|
38
|
+
| <<plugins-{type}s-{plugin}-exclude_metrics>> |<<array,array>>|No
|
39
|
+
| <<plugins-{type}s-{plugin}-fields_are_metrics>> |<<boolean,boolean>>|No
|
40
|
+
| <<plugins-{type}s-{plugin}-host>> |<<string,string>>|No
|
41
|
+
| <<plugins-{type}s-{plugin}-include_metrics>> |<<array,array>>|No
|
42
|
+
| <<plugins-{type}s-{plugin}-metrics>> |<<hash,hash>>|No
|
43
|
+
| <<plugins-{type}s-{plugin}-metrics_format>> |<<string,string>>|No
|
44
|
+
| <<plugins-{type}s-{plugin}-nested_object_separator>> |<<string,string>>|No
|
45
|
+
| <<plugins-{type}s-{plugin}-port>> |<<number,number>>|No
|
46
|
+
| <<plugins-{type}s-{plugin}-reconnect_interval>> |<<number,number>>|No
|
47
|
+
| <<plugins-{type}s-{plugin}-resend_on_failure>> |<<boolean,boolean>>|No
|
48
|
+
| <<plugins-{type}s-{plugin}-timestamp_field>> |<<string,string>>|No
|
49
|
+
|=======================================================================
|
50
|
+
|
51
|
+
Also see <<plugins-{type}s-common-options>> for a list of options supported by all
|
52
|
+
output plugins.
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
[id="plugins-{type}s-{plugin}-exclude_metrics"]
|
57
|
+
===== `exclude_metrics`
|
58
|
+
|
59
|
+
* Value type is <<array,array>>
|
60
|
+
* Default value is `["%{[^}]+}"]`
|
61
|
+
|
62
|
+
Exclude regex matched metric names, by default exclude unresolved %{field} strings.
|
63
|
+
|
64
|
+
[id="plugins-{type}s-{plugin}-fields_are_metrics"]
|
65
|
+
===== `fields_are_metrics`
|
66
|
+
|
67
|
+
* Value type is <<boolean,boolean>>
|
68
|
+
* Default value is `false`
|
69
|
+
|
70
|
+
An array indicating that these event fields should be treated as metrics
|
71
|
+
and will be sent verbatim to Graphite. You may use either `fields_are_metrics`
|
72
|
+
or `metrics`, but not both.
|
73
|
+
|
74
|
+
[id="plugins-{type}s-{plugin}-host"]
|
75
|
+
===== `host`
|
76
|
+
|
77
|
+
* Value type is <<string,string>>
|
78
|
+
* Default value is `"localhost"`
|
79
|
+
|
80
|
+
The hostname or IP address of the Graphite server.
|
81
|
+
|
82
|
+
[id="plugins-{type}s-{plugin}-include_metrics"]
|
83
|
+
===== `include_metrics`
|
84
|
+
|
85
|
+
* Value type is <<array,array>>
|
86
|
+
* Default value is `[".*"]`
|
87
|
+
|
88
|
+
Include only regex matched metric names.
|
89
|
+
|
90
|
+
[id="plugins-{type}s-{plugin}-metrics"]
|
91
|
+
===== `metrics`
|
92
|
+
|
93
|
+
* Value type is <<hash,hash>>
|
94
|
+
* Default value is `{}`
|
95
|
+
|
96
|
+
The metric(s) to use. This supports dynamic strings like %{host}
|
97
|
+
for metric names and also for values. This is a hash field with key
|
98
|
+
being the metric name, value being the metric value. Example:
|
99
|
+
[source,ruby]
|
100
|
+
metrics => { "%{host}/uptime" => "%{uptime_1m}" }
|
101
|
+
|
102
|
+
The value will be coerced to a floating point value. Values which cannot be
|
103
|
+
coerced will be set to zero (0). You may use either `metrics` or `fields_are_metrics`,
|
104
|
+
but not both.
|
105
|
+
|
106
|
+
[id="plugins-{type}s-{plugin}-metrics_format"]
|
107
|
+
===== `metrics_format`
|
108
|
+
|
109
|
+
* Value type is <<string,string>>
|
110
|
+
* Default value is `"*"`
|
111
|
+
|
112
|
+
Defines the format of the metric string. The placeholder '*' will be
|
113
|
+
replaced with the name of the actual metric.
|
114
|
+
[source,ruby]
|
115
|
+
metrics_format => "foo.bar.*.sum"
|
116
|
+
|
117
|
+
NOTE: If no metrics_format is defined, the name of the metric will be used as fallback.
|
118
|
+
|
119
|
+
[id="plugins-{type}s-{plugin}-nested_object_separator"]
|
120
|
+
===== `nested_object_separator`
|
121
|
+
|
122
|
+
* Value type is <<string,string>>
|
123
|
+
* Default value is `"."`
|
124
|
+
|
125
|
+
When hashes are passed in as values they are broken out into a dotted notation
|
126
|
+
For instance if you configure this plugin with
|
127
|
+
# [source,ruby]
|
128
|
+
metrics => "mymetrics"
|
129
|
+
|
130
|
+
and "mymetrics" is a nested hash of '{a => 1, b => { c => 2 }}'
|
131
|
+
this plugin will generate two metrics: a => 1, and b.c => 2 .
|
132
|
+
If you've specified a 'metrics_format' it will respect that,
|
133
|
+
but you still may want control over the separator within these nested key names.
|
134
|
+
This config setting changes the separator from the '.' default.
|
135
|
+
|
136
|
+
[id="plugins-{type}s-{plugin}-port"]
|
137
|
+
===== `port`
|
138
|
+
|
139
|
+
* Value type is <<number,number>>
|
140
|
+
* Default value is `2003`
|
141
|
+
|
142
|
+
The port to connect to on the Graphite server.
|
143
|
+
|
144
|
+
[id="plugins-{type}s-{plugin}-reconnect_interval"]
|
145
|
+
===== `reconnect_interval`
|
146
|
+
|
147
|
+
* Value type is <<number,number>>
|
148
|
+
* Default value is `2`
|
149
|
+
|
150
|
+
Interval between reconnect attempts to Carbon.
|
151
|
+
|
152
|
+
[id="plugins-{type}s-{plugin}-resend_on_failure"]
|
153
|
+
===== `resend_on_failure`
|
154
|
+
|
155
|
+
* Value type is <<boolean,boolean>>
|
156
|
+
* Default value is `false`
|
157
|
+
|
158
|
+
Should metrics be resent on failure?
|
159
|
+
|
160
|
+
[id="plugins-{type}s-{plugin}-timestamp_field"]
|
161
|
+
===== `timestamp_field`
|
162
|
+
|
163
|
+
* Value type is <<string,string>>
|
164
|
+
* Default value is `"@timestamp"`
|
165
|
+
|
166
|
+
Use this field for the timestamp instead of '@timestamp' which is the
|
167
|
+
default. Useful when backfilling or just getting more accurate data into
|
168
|
+
graphite since you probably have a cache layer infront of Logstash.
|
169
|
+
|
170
|
+
|
171
|
+
|
172
|
+
include::{include_path}/{type}.asciidoc[]
|
@@ -0,0 +1,226 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "logstash/outputs/base"
|
3
|
+
require "logstash/namespace"
|
4
|
+
require "socket"
|
5
|
+
|
6
|
+
# This output allows you to pull metrics from your logs and ship them to
|
7
|
+
# Graphite. Graphite is an open source tool for storing and graphing metrics.
|
8
|
+
#
|
9
|
+
# An example use case: Some applications emit aggregated stats in the logs
|
10
|
+
# every 10 seconds. Using the grok filter and this output, it is possible to
|
11
|
+
# capture the metric values from the logs and emit them to Graphite.
|
12
|
+
class LogStash::Outputs::Graphite < LogStash::Outputs::Base
|
13
|
+
config_name "graphite"
|
14
|
+
|
15
|
+
EXCLUDE_ALWAYS = [ "@timestamp", "@version" ]
|
16
|
+
|
17
|
+
DEFAULT_METRICS_FORMAT = "*"
|
18
|
+
METRIC_PLACEHOLDER = "*"
|
19
|
+
|
20
|
+
# The hostname or IP address of the Graphite server.
|
21
|
+
config :host, :validate => :string, :default => "localhost", :deprecated => "This setting is being deprecated, use :hosts instead."
|
22
|
+
|
23
|
+
# The port to connect to the Graphite server.
|
24
|
+
config :port, :validate => :number, :default => 2003, :deprecated => "This setting is being deprecated, use :hosts instead."
|
25
|
+
|
26
|
+
# The list of known Graphite servers to connect to. One host is selected randomly (there is no precedence). If one host becomes unreachable, another one is selected randomly.
|
27
|
+
# All entries in this list can contain a port number. If no port number is given, the default value of 2003 is used.
|
28
|
+
config :hosts, :validate => :string, :list => true, :default => ["localhost:2003"]
|
29
|
+
|
30
|
+
# Interval between reconnect attempts to Graphite server, seconds.
|
31
|
+
config :reconnect_interval, :validate => :number, :default => 2
|
32
|
+
|
33
|
+
# Should metrics be resent on failure?
|
34
|
+
config :resend_on_failure, :validate => :boolean, :default => false
|
35
|
+
|
36
|
+
# Number of attempts to be made resending metrics before abandoning
|
37
|
+
config :resend_attempts, :validate => :number, :default => 3
|
38
|
+
|
39
|
+
# The metric(s) to use. This supports dynamic strings like %{host}
|
40
|
+
# for metric names and also for values. This is a hash field with key
|
41
|
+
# being the metric name, value being the metric value. Example:
|
42
|
+
# [source,ruby]
|
43
|
+
# metrics => { "%{host}/uptime" => "%{uptime_1m}" }
|
44
|
+
#
|
45
|
+
# The value will be coerced to a floating point value. Values which cannot be
|
46
|
+
# coerced will be set to zero (0). You may use either `metrics` or `fields_are_metrics`,
|
47
|
+
# but not both.
|
48
|
+
config :metrics, :validate => :hash, :default => {}
|
49
|
+
|
50
|
+
# An array indicating that these event fields should be treated as metrics
|
51
|
+
# and will be sent verbatim to Graphite. You may use either `fields_are_metrics`
|
52
|
+
# or `metrics`, but not both.
|
53
|
+
config :fields_are_metrics, :validate => :boolean, :default => false
|
54
|
+
|
55
|
+
# Include only regex matched metric names.
|
56
|
+
config :include_metrics, :validate => :array, :default => [ ".*" ]
|
57
|
+
|
58
|
+
# Exclude regex matched metric names, by default exclude unresolved %{field} strings.
|
59
|
+
config :exclude_metrics, :validate => :array, :default => [ "%\{[^}]+\}" ]
|
60
|
+
|
61
|
+
# Use this field for the timestamp instead of '@timestamp' which is the
|
62
|
+
# default. Useful when backfilling or just getting more accurate data into
|
63
|
+
# graphite since you probably have a cache layer infront of Logstash.
|
64
|
+
config :timestamp_field, :validate => :string, :default => '@timestamp'
|
65
|
+
|
66
|
+
# Defines the format of the metric string. The placeholder '*' will be
|
67
|
+
# replaced with the name of the actual metric.
|
68
|
+
# [source,ruby]
|
69
|
+
# metrics_format => "foo.bar.*.sum"
|
70
|
+
#
|
71
|
+
# NOTE: If no metrics_format is defined, the name of the metric will be used as fallback.
|
72
|
+
config :metrics_format, :validate => :string, :default => DEFAULT_METRICS_FORMAT
|
73
|
+
|
74
|
+
# When hashes are passed in as values they are broken out into a dotted notation
|
75
|
+
# For instance if you configure this plugin with
|
76
|
+
# # [source,ruby]
|
77
|
+
# metrics => "mymetrics"
|
78
|
+
#
|
79
|
+
# and "mymetrics" is a nested hash of '{a => 1, b => { c => 2 }}'
|
80
|
+
# this plugin will generate two metrics: a => 1, and b.c => 2 .
|
81
|
+
# If you've specified a 'metrics_format' it will respect that,
|
82
|
+
# but you still may want control over the separator within these nested key names.
|
83
|
+
# This config setting changes the separator from the '.' default.
|
84
|
+
config :nested_object_separator, :validate => :string, :default => "."
|
85
|
+
|
86
|
+
def register
|
87
|
+
@include_metrics.collect!{|regexp| Regexp.new(regexp)}
|
88
|
+
@exclude_metrics.collect!{|regexp| Regexp.new(regexp)}
|
89
|
+
|
90
|
+
if @metrics_format && !@metrics_format.include?(METRIC_PLACEHOLDER)
|
91
|
+
@logger.warn("metrics_format does not include placeholder #{METRIC_PLACEHOLDER} .. falling back to default format: #{DEFAULT_METRICS_FORMAT.inspect}")
|
92
|
+
|
93
|
+
@metrics_format = DEFAULT_METRICS_FORMAT
|
94
|
+
end
|
95
|
+
|
96
|
+
setup_hosts
|
97
|
+
end
|
98
|
+
|
99
|
+
def setup_hosts
|
100
|
+
if @hosts && @hosts.size == 1 && @hosts[0] == "localhost:2003"
|
101
|
+
@hosts.replace(["%s:%s" % [@host, @port]])
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def send(message)
|
106
|
+
numattempts = 0
|
107
|
+
hosts_to_try = @hosts
|
108
|
+
host = hosts_to_try.sample
|
109
|
+
hosts_to_try.delete(host)
|
110
|
+
|
111
|
+
begin
|
112
|
+
address, _, port = host.rpartition(":")
|
113
|
+
TCPSocket.new(address, port).puts(message)
|
114
|
+
rescue Errno::ECOPNNREFUSED, Errno::EPIPE, Errno::ECONNRESET, IOError
|
115
|
+
if hosts_to_try.size > 0
|
116
|
+
host = hosts_to_try.sample
|
117
|
+
hosts_to_try.delete(host)
|
118
|
+
retry
|
119
|
+
elsif @resend_on_failure && numattempts < @resend_attempts
|
120
|
+
sleep(@reconnect_interval)
|
121
|
+
hosts_to_try = @hosts
|
122
|
+
host = hosts_to_try.sample
|
123
|
+
hosts_to_try.delete(host)
|
124
|
+
numattempts += 1
|
125
|
+
retry
|
126
|
+
else
|
127
|
+
@logger.warn("No more hosts to try, skip sending...")
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
def construct_metric_name(event, metric)
|
134
|
+
if @metrics_format
|
135
|
+
sprinted = event.sprintf(@metrics_format)
|
136
|
+
return sprinted.gsub(METRIC_PLACEHOLDER, metric)
|
137
|
+
end
|
138
|
+
|
139
|
+
metric
|
140
|
+
end
|
141
|
+
|
142
|
+
def receive(event)
|
143
|
+
# Graphite message format: metric value timestamp\n
|
144
|
+
|
145
|
+
# compact to remove nil messages which produces useless \n
|
146
|
+
messages = (
|
147
|
+
@fields_are_metrics \
|
148
|
+
? messages_from_event_fields(event, @include_metrics, @exclude_metrics)
|
149
|
+
: messages_from_event_metrics(event, @metrics)
|
150
|
+
).compact
|
151
|
+
|
152
|
+
if messages.empty?
|
153
|
+
@logger.debug? && @logger.debug("Message is empty, not sending anything to Graphite", :messages => messages)
|
154
|
+
else
|
155
|
+
message = messages.join("\n")
|
156
|
+
@logger.debug? && @logger.debug("Sending carbon messages", :messages => messages)
|
157
|
+
|
158
|
+
send(message)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
private
|
163
|
+
|
164
|
+
def messages_from_event_fields(event, include_metrics, exclude_metrics)
|
165
|
+
@logger.debug? && @logger.debug("got metrics event", :metrics => event.to_hash)
|
166
|
+
|
167
|
+
timestamp = event_timestamp(event)
|
168
|
+
event.to_hash.flat_map do |metric,value|
|
169
|
+
next if EXCLUDE_ALWAYS.include?(metric)
|
170
|
+
next unless include_metrics.empty? || include_metrics.any? { |regexp| metric.match(regexp) }
|
171
|
+
next if exclude_metrics.any? {|regexp| metric.match(regexp)}
|
172
|
+
|
173
|
+
metrics_lines_for_event(event, metric, value, timestamp)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def messages_from_event_metrics(event, metrics)
|
178
|
+
timestamp = event_timestamp(event)
|
179
|
+
metrics.flat_map do |metric, value|
|
180
|
+
@logger.debug? && @logger.debug("processing", :metric => metric, :value => value)
|
181
|
+
|
182
|
+
metric = event.sprintf(metric)
|
183
|
+
next unless @include_metrics.any? {|regexp| metric.match(regexp)}
|
184
|
+
next if @exclude_metrics.any? {|regexp| metric.match(regexp)}
|
185
|
+
|
186
|
+
metrics_lines_for_event(event, metric, value, timestamp)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def event_timestamp(event)
|
191
|
+
event.get(@timestamp_field).to_i
|
192
|
+
end
|
193
|
+
|
194
|
+
def metrics_lines_for_event(event, metric, value, timestamp)
|
195
|
+
if event.get(metric).is_a?(Hash)
|
196
|
+
dotify(event.get(metric), metric).map do |k, v|
|
197
|
+
metrics_line(event, k, v, timestamp)
|
198
|
+
end
|
199
|
+
else
|
200
|
+
metrics_line(event, event.sprintf(metric), event.sprintf(value).to_f, timestamp)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def metrics_line(event, name, value, timestamp)
|
205
|
+
"#{construct_metric_name(event, name)} #{value} #{timestamp}"
|
206
|
+
end
|
207
|
+
|
208
|
+
# Take a nested ruby hash of the form {:a => {:b => 2}, c: => 3} and
|
209
|
+
# turn it into a hash of the form
|
210
|
+
# { "a.b" => 2, "c" => 3}
|
211
|
+
def dotify(hash, prefix = nil)
|
212
|
+
hash.reduce({}) do |acc, kv|
|
213
|
+
k, v = kv
|
214
|
+
pk = prefix ? "#{prefix}#{@nested_object_separator}#{k}" : k.to_s
|
215
|
+
if v.is_a?(Hash)
|
216
|
+
acc.merge!(dotify(v, pk))
|
217
|
+
elsif v.is_a?(Array)
|
218
|
+
# There's no right answer here, so we do nothing
|
219
|
+
@logger.warn("Array values not supported for graphite metrics! Ignoring #{hash} @ #{prefix}")
|
220
|
+
else
|
221
|
+
acc[pk] = v
|
222
|
+
end
|
223
|
+
acc
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
|
3
|
+
s.name = 'logstash-output-graphite-mavlyutov'
|
4
|
+
s.version = '3.2.0'
|
5
|
+
s.licenses = ['Apache License (2.0)']
|
6
|
+
s.summary = "This output allows you to pull metrics from your logs and ship them to Graphite"
|
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"
|
8
|
+
s.authors = ["Elastic"]
|
9
|
+
s.email = 'info@elastic.co'
|
10
|
+
s.homepage = "http://www.elastic.co/guide/en/logstash/current/index.html"
|
11
|
+
s.require_paths = ["lib"]
|
12
|
+
|
13
|
+
# Files
|
14
|
+
s.files = Dir["lib/**/*","spec/**/*","*.gemspec","*.md","CONTRIBUTORS","Gemfile","LICENSE","NOTICE.TXT", "vendor/jar-dependencies/**/*.jar", "vendor/jar-dependencies/**/*.rb", "VERSION", "docs/**/*"]
|
15
|
+
|
16
|
+
# Tests
|
17
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
18
|
+
|
19
|
+
# Special flag to let us know this is actually a logstash plugin
|
20
|
+
s.metadata = { "logstash_plugin" => "true", "logstash_group" => "output" }
|
21
|
+
|
22
|
+
# Gem dependencies
|
23
|
+
s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
|
24
|
+
|
25
|
+
s.add_development_dependency 'logstash-devutils'
|
26
|
+
s.add_development_dependency 'logstash-input-generator'
|
27
|
+
s.add_development_dependency 'logstash-filter-kv'
|
28
|
+
s.add_development_dependency 'logstash-filter-ruby'
|
29
|
+
end
|
30
|
+
|
@@ -0,0 +1,199 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require_relative '../spec_helper'
|
4
|
+
|
5
|
+
describe LogStash::Outputs::Graphite do
|
6
|
+
|
7
|
+
let(:port) { 4939 }
|
8
|
+
let(:server) { subject.socket }
|
9
|
+
|
10
|
+
before :each do
|
11
|
+
subject.register
|
12
|
+
subject.receive(event)
|
13
|
+
end
|
14
|
+
|
15
|
+
context "with a default run" do
|
16
|
+
|
17
|
+
subject { LogStash::Outputs::Graphite.new("host" => "localhost", "port" => port, "metrics" => [ "hurray.%{foo}", "%{bar}" ]) }
|
18
|
+
let(:event) { LogStash::Event.new("foo" => "fancy", "bar" => 42) }
|
19
|
+
|
20
|
+
it "generate one element" do
|
21
|
+
expect(server.size).to eq(1)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "include all metrics" do
|
25
|
+
line = server.pop
|
26
|
+
expect(line).to match(/^hurray.fancy 42.0 \d{10,}\n$/)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "if fields_are_metrics => true" do
|
31
|
+
context "when metrics_format => ..." do
|
32
|
+
subject { LogStash::Outputs::Graphite.new("host" => "localhost",
|
33
|
+
"port" => port,
|
34
|
+
"fields_are_metrics" => true,
|
35
|
+
"include_metrics" => ["foo"],
|
36
|
+
"metrics_format" => "foo.%{@host}.sys.data.*") }
|
37
|
+
|
38
|
+
let(:event) { LogStash::Event.new("foo" => "123", "@host" => "testhost") }
|
39
|
+
let(:expected_metric_prefix) { "foo.#{event.get('@host')}.sys.data" }
|
40
|
+
|
41
|
+
context "match one key" do
|
42
|
+
it "should generate one element" do
|
43
|
+
expect(server.size).to eq(1)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should match the generated key" do
|
47
|
+
line = server.pop
|
48
|
+
expect(line).to match(/^#{expected_metric_prefix}.foo 123.0 \d{10,}\n$/)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "when matching a nested hash" do
|
53
|
+
let(:event) { LogStash::Event.new("foo" => {"a" => 3, "c" => {"d" => 2}}, "@host" => "myhost") }
|
54
|
+
|
55
|
+
it "should create the proper formatted lines" do
|
56
|
+
lines = [server.pop, server.pop].sort # Put key 'a' first
|
57
|
+
expect(lines[0]).to match(/^#{expected_metric_prefix}.foo.a 3 \d{10,}\n$/)
|
58
|
+
expect(lines[1]).to match(/^#{expected_metric_prefix}.foo.c.d 2 \d{10,}\n$/)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "match all keys" do
|
64
|
+
|
65
|
+
subject { LogStash::Outputs::Graphite.new("host" => "localhost",
|
66
|
+
"port" => port,
|
67
|
+
"fields_are_metrics" => true,
|
68
|
+
"include_metrics" => [".*"],
|
69
|
+
"metrics_format" => "foo.bar.sys.data.*") }
|
70
|
+
|
71
|
+
let(:event) { LogStash::Event.new("foo" => "123", "bar" => "42") }
|
72
|
+
|
73
|
+
let(:lines) do
|
74
|
+
dict = {}
|
75
|
+
while(!server.empty?)
|
76
|
+
line = server.pop
|
77
|
+
key = line.split(' ')[0]
|
78
|
+
dict[key] = line
|
79
|
+
end
|
80
|
+
dict
|
81
|
+
end
|
82
|
+
|
83
|
+
it "match the generated foo key" do
|
84
|
+
expect(lines['foo.bar.sys.data.foo']).to match(/^foo.bar.sys.data.foo 123.0 \d{10,}\n$/)
|
85
|
+
end
|
86
|
+
|
87
|
+
it "match the generated bar key" do
|
88
|
+
expect(lines['foo.bar.sys.data.bar']).to match(/^foo.bar.sys.data.bar 42.0 \d{10,}\n$/)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "no match" do
|
93
|
+
|
94
|
+
subject { LogStash::Outputs::Graphite.new("host" => "localhost",
|
95
|
+
"port" => port,
|
96
|
+
"fields_are_metrics" => true,
|
97
|
+
"include_metrics" => ["notmatchinganything"],
|
98
|
+
"metrics_format" => "foo.bar.sys.data.*") }
|
99
|
+
|
100
|
+
let(:event) { LogStash::Event.new("foo" => "123", "bar" => "42") }
|
101
|
+
|
102
|
+
it "generate no event" do
|
103
|
+
expect(server.empty?).to eq(true)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context "match a key with invalid metric_format" do
|
108
|
+
|
109
|
+
subject { LogStash::Outputs::Graphite.new("host" => "localhost",
|
110
|
+
"port" => port,
|
111
|
+
"fields_are_metrics" => true,
|
112
|
+
"include_metrics" => ["foo"],
|
113
|
+
"metrics_format" => "invalidformat") }
|
114
|
+
|
115
|
+
let(:event) { LogStash::Event.new("foo" => "123") }
|
116
|
+
|
117
|
+
it "match the foo key" do
|
118
|
+
line = server.pop
|
119
|
+
expect(line).to match(/^foo 123.0 \d{10,}\n$/)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "fields are metrics = false" do
|
125
|
+
context "metrics_format not set" do
|
126
|
+
context "match one key with metrics list" do
|
127
|
+
|
128
|
+
subject { LogStash::Outputs::Graphite.new("host" => "localhost",
|
129
|
+
"port" => port,
|
130
|
+
"fields_are_metrics" => false,
|
131
|
+
"include_metrics" => ["foo"],
|
132
|
+
"metrics" => [ "custom.foo", "%{foo}" ]) }
|
133
|
+
|
134
|
+
let(:event) { LogStash::Event.new("foo" => "123") }
|
135
|
+
|
136
|
+
it "match the custom.foo key" do
|
137
|
+
line = server.pop
|
138
|
+
expect(line).to match(/^custom.foo 123.0 \d{10,}\n$/)
|
139
|
+
end
|
140
|
+
|
141
|
+
context "when matching a nested hash" do
|
142
|
+
let(:event) { LogStash::Event.new("custom.foo" => {"a" => 3, "c" => {"d" => 2}}) }
|
143
|
+
|
144
|
+
it "should create the proper formatted lines" do
|
145
|
+
lines = [server.pop, server.pop].sort # Put key 'a' first
|
146
|
+
expect(lines[0]).to match(/^custom.foo.a 3 \d{10,}\n$/)
|
147
|
+
expect(lines[1]).to match(/^custom.foo.c.d 2 \d{10,}\n$/)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context "timestamp_field used is timestamp_new" do
|
155
|
+
|
156
|
+
let(:timestamp_new) { (Time.now + 3).to_i }
|
157
|
+
|
158
|
+
subject { LogStash::Outputs::Graphite.new("host" => "localhost",
|
159
|
+
"port" => port,
|
160
|
+
"timestamp_field" => "timestamp_new",
|
161
|
+
"metrics" => ["foo", "1"]) }
|
162
|
+
|
163
|
+
let(:event) { LogStash::Event.new("foo" => "123", "timestamp_new" => timestamp_new) }
|
164
|
+
|
165
|
+
it "timestamp matches timestamp_new" do
|
166
|
+
line = server.pop
|
167
|
+
expect(line).to match(/^foo 1.0 #{timestamp_new}\n$/)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
describe "dotifying a hash" do
|
172
|
+
let(:event) { LogStash::Event.new( "metrics" => hash) }
|
173
|
+
let(:dotified) { LogStash::Outputs::Graphite.new().send(:dotify, hash) }
|
174
|
+
|
175
|
+
context "with a complex hash" do
|
176
|
+
let(:hash) { {:a => 2, :b => {:c => 3, :d => 4, :e => {:f => 5}}} }
|
177
|
+
|
178
|
+
it "should dottify correctly" do
|
179
|
+
expect(dotified).to eql({"a" => 2, "b.c" => 3, "b.d" => 4, "b.e.f" => 5})
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
context "with a simple hash" do
|
184
|
+
let(:hash) { {:a => 2, 5 => 4} }
|
185
|
+
|
186
|
+
it "should do nothing more than stringify the keys" do
|
187
|
+
expect(dotified).to eql("a" => 2, "5" => 4)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
context "with an array value" do
|
192
|
+
let(:hash) { {:a => 2, 5 => 4, :c => [1,2,3]} }
|
193
|
+
|
194
|
+
it "should ignore array values" do
|
195
|
+
expect(dotified).to eql("a" => 2, "5" => 4)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module Mocks
|
2
|
+
class Server
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@queue = Array.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def size
|
9
|
+
@queue.length
|
10
|
+
end
|
11
|
+
|
12
|
+
def pop
|
13
|
+
@queue.pop
|
14
|
+
end
|
15
|
+
|
16
|
+
def stop
|
17
|
+
end
|
18
|
+
|
19
|
+
def empty?
|
20
|
+
@queue.empty?
|
21
|
+
end
|
22
|
+
|
23
|
+
def puts(data)
|
24
|
+
data.split("\n").each do |line|
|
25
|
+
@queue << "#{line}\n"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: logstash-output-graphite-mavlyutov
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 3.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Elastic
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-06-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: logstash-core-plugin-api
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.60'
|
20
|
+
- - <=
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '2.99'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.60'
|
30
|
+
- - <=
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2.99'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: logstash-devutils
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
type: :development
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: logstash-input-generator
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - '>='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: logstash-filter-kv
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - '>='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - '>='
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: logstash-filter-ruby
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - '>='
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
description: This gem is a Logstash plugin required to be installed on top of the
|
90
|
+
Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This
|
91
|
+
gem is not a stand-alone program
|
92
|
+
email: info@elastic.co
|
93
|
+
executables: []
|
94
|
+
extensions: []
|
95
|
+
extra_rdoc_files: []
|
96
|
+
files:
|
97
|
+
- lib/logstash/outputs/graphite.rb
|
98
|
+
- spec/outputs/graphite_spec.rb
|
99
|
+
- spec/spec_helper.rb
|
100
|
+
- spec/support/server.rb
|
101
|
+
- logstash-output-graphite.gemspec
|
102
|
+
- CHANGELOG.md
|
103
|
+
- README.md
|
104
|
+
- CONTRIBUTORS
|
105
|
+
- Gemfile
|
106
|
+
- LICENSE
|
107
|
+
- NOTICE.TXT
|
108
|
+
- docs/index.asciidoc
|
109
|
+
homepage: http://www.elastic.co/guide/en/logstash/current/index.html
|
110
|
+
licenses:
|
111
|
+
- Apache License (2.0)
|
112
|
+
metadata:
|
113
|
+
logstash_plugin: 'true'
|
114
|
+
logstash_group: output
|
115
|
+
post_install_message:
|
116
|
+
rdoc_options: []
|
117
|
+
require_paths:
|
118
|
+
- lib
|
119
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - '>='
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
125
|
+
requirements:
|
126
|
+
- - '>='
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: '0'
|
129
|
+
requirements: []
|
130
|
+
rubyforge_project:
|
131
|
+
rubygems_version: 2.0.14.1
|
132
|
+
signing_key:
|
133
|
+
specification_version: 4
|
134
|
+
summary: This output allows you to pull metrics from your logs and ship them to Graphite
|
135
|
+
test_files:
|
136
|
+
- spec/outputs/graphite_spec.rb
|
137
|
+
- spec/spec_helper.rb
|
138
|
+
- spec/support/server.rb
|