logstash-output-graphite 1.0.0 → 1.0.1
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 +2 -0
- data/lib/logstash/outputs/graphite.rb +79 -21
- data/logstash-output-graphite.gemspec +1 -1
- data/spec/outputs/graphite_spec.rb +52 -2
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aaa1548ced5cd4e3cc3f3724c078a13e9c507fe5
|
4
|
+
data.tar.gz: 9c2309ed86b7c371bd35ad4d21ed7bb96536b48d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 26aedf2dae122c104225a6297484edd858457e553b340113d2458c2c4ec963a80133e8505f52cc0e348135db0ab5eb6ee654e8b15419906a1ba7a3f2f62dc7f4
|
7
|
+
data.tar.gz: dd176d82e9c199bb713dc8c8e3ecdda2b30117692994b9beef372d6531c125a6ff1056ae13d6bec070fc62d33f80b4637f8b567dd9404fef663d843a2f9a7571
|
data/CHANGELOG.md
CHANGED
@@ -67,6 +67,18 @@ class LogStash::Outputs::Graphite < LogStash::Outputs::Base
|
|
67
67
|
# NOTE: If no metrics_format is defined, the name of the metric will be used as fallback.
|
68
68
|
config :metrics_format, :validate => :string, :default => DEFAULT_METRICS_FORMAT
|
69
69
|
|
70
|
+
# When hashes are passed in as values they are broken out into a dotted notation
|
71
|
+
# For instance if you configure this plugin with
|
72
|
+
# # [source,ruby]
|
73
|
+
# metrics => "mymetrics"
|
74
|
+
#
|
75
|
+
# and "mymetrics" is a nested hash of '{a => 1, b => { c => 2 }}'
|
76
|
+
# this plugin will generate two metrics: a => 1, and b.c => 2 .
|
77
|
+
# If you've specified a 'metrics_format' it will respect that,
|
78
|
+
# but you still may want control over the separator within these nested key names.
|
79
|
+
# This config setting changes the separator from the '.' default.
|
80
|
+
config :nested_object_separator, :validate => :string, :default => "."
|
81
|
+
|
70
82
|
def register
|
71
83
|
@include_metrics.collect!{|regexp| Regexp.new(regexp)}
|
72
84
|
@exclude_metrics.collect!{|regexp| Regexp.new(regexp)}
|
@@ -106,26 +118,9 @@ class LogStash::Outputs::Graphite < LogStash::Outputs::Base
|
|
106
118
|
|
107
119
|
# Graphite message format: metric value timestamp\n
|
108
120
|
|
109
|
-
messages =
|
110
|
-
|
111
|
-
|
112
|
-
if @fields_are_metrics
|
113
|
-
@logger.debug("got metrics event", :metrics => event.to_hash)
|
114
|
-
event.to_hash.each do |metric,value|
|
115
|
-
next if EXCLUDE_ALWAYS.include?(metric)
|
116
|
-
next unless @include_metrics.empty? || @include_metrics.any? { |regexp| metric.match(regexp) }
|
117
|
-
next if @exclude_metrics.any? {|regexp| metric.match(regexp)}
|
118
|
-
messages << "#{construct_metric_name(metric)} #{event.sprintf(value.to_s).to_f} #{timestamp}"
|
119
|
-
end
|
120
|
-
else
|
121
|
-
@metrics.each do |metric, value|
|
122
|
-
@logger.debug("processing", :metric => metric, :value => value)
|
123
|
-
metric = event.sprintf(metric)
|
124
|
-
next unless @include_metrics.any? {|regexp| metric.match(regexp)}
|
125
|
-
next if @exclude_metrics.any? {|regexp| metric.match(regexp)}
|
126
|
-
messages << "#{construct_metric_name(event.sprintf(metric))} #{event.sprintf(value).to_f} #{timestamp}"
|
127
|
-
end
|
128
|
-
end
|
121
|
+
messages = @fields_are_metrics ?
|
122
|
+
messages_from_event_fields(event, @include_metrics, @exclude_metrics) :
|
123
|
+
messages_from_event_metrics(event, @metrics)
|
129
124
|
|
130
125
|
if messages.empty?
|
131
126
|
@logger.debug("Message is empty, not sending anything to Graphite", :messages => messages, :host => @host, :port => @port)
|
@@ -145,6 +140,69 @@ class LogStash::Outputs::Graphite < LogStash::Outputs::Base
|
|
145
140
|
retry if @resend_on_failure
|
146
141
|
end
|
147
142
|
end
|
148
|
-
|
149
143
|
end # def receive
|
144
|
+
|
145
|
+
private
|
146
|
+
|
147
|
+
def messages_from_event_fields(event, include_metrics, exclude_metrics)
|
148
|
+
timestamp = event_timestamp(event)
|
149
|
+
@logger.debug? && @logger.debug("got metrics event", :metrics => event.to_hash)
|
150
|
+
event.to_hash.flat_map do |metric,value|
|
151
|
+
next if EXCLUDE_ALWAYS.include?(metric)
|
152
|
+
next unless include_metrics.empty? || include_metrics.any? { |regexp| metric.match(regexp) }
|
153
|
+
next if exclude_metrics.any? {|regexp| metric.match(regexp)}
|
154
|
+
|
155
|
+
metrics_lines_for_event(event, metric, value, timestamp)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def messages_from_event_metrics(event, metrics)
|
160
|
+
timestamp = event_timestamp(event)
|
161
|
+
metrics.flat_map do |metric, value|
|
162
|
+
@logger.debug("processing", :metric => metric, :value => value)
|
163
|
+
metric = event.sprintf(metric)
|
164
|
+
next unless @include_metrics.any? {|regexp| metric.match(regexp)}
|
165
|
+
next if @exclude_metrics.any? {|regexp| metric.match(regexp)}
|
166
|
+
|
167
|
+
metrics_lines_for_event(event, metric, value, timestamp)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def event_timestamp(event)
|
172
|
+
event[@timestamp_field].to_i
|
173
|
+
end
|
174
|
+
|
175
|
+
def metrics_lines_for_event(event, metric, value, timestamp)
|
176
|
+
if event[metric].is_a?(Hash)
|
177
|
+
dotify(event[metric], metric).map do |k,v|
|
178
|
+
metrics_line(k, v, timestamp)
|
179
|
+
end
|
180
|
+
else
|
181
|
+
metrics_line(event.sprintf(metric), event.sprintf(value).to_f, timestamp)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def metrics_line(name, value, timestamp)
|
186
|
+
"#{construct_metric_name(name)} #{value} #{timestamp}"
|
187
|
+
end
|
188
|
+
|
189
|
+
# Take a nested ruby hash of the form {:a => {:b => 2}, c: => 3} and
|
190
|
+
# turn it into a hash of the form
|
191
|
+
# { "a.b" => 2, "c" => 3}
|
192
|
+
def dotify(hash,prefix=nil)
|
193
|
+
hash.reduce({}) do |acc,kv|
|
194
|
+
k,v = kv
|
195
|
+
pk = prefix ? "#{prefix}#{@nested_object_separator}#{k}" : k.to_s
|
196
|
+
if v.is_a?(Hash)
|
197
|
+
acc.merge!(dotify(v, pk))
|
198
|
+
elsif v.is_a?(Array)
|
199
|
+
# There's no right answer here, so we do nothing
|
200
|
+
@logger.warn("Array values not supported for graphite metrics! Ignoring #{hash} @ #{prefix}")
|
201
|
+
else
|
202
|
+
acc[pk] = v
|
203
|
+
end
|
204
|
+
acc
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
150
208
|
end # class LogStash::Outputs::Graphite
|
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
|
3
3
|
s.name = 'logstash-output-graphite'
|
4
|
-
s.version = '1.0.
|
4
|
+
s.version = '1.0.1'
|
5
5
|
s.licenses = ['Apache License (2.0)']
|
6
6
|
s.summary = "This output allows you to pull metrics from your logs and ship them to Graphite"
|
7
7
|
s.description = "This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program"
|
@@ -36,15 +36,25 @@ describe LogStash::Outputs::Graphite do
|
|
36
36
|
let(:event) { LogStash::Event.new("foo" => "123") }
|
37
37
|
|
38
38
|
context "match one key" do
|
39
|
-
it "generate one element" do
|
39
|
+
it "should generate one element" do
|
40
40
|
expect(server.size).to eq(1)
|
41
41
|
end
|
42
42
|
|
43
|
-
it "match the generated key" do
|
43
|
+
it "should match the generated key" do
|
44
44
|
line = server.pop
|
45
45
|
expect(line).to match(/^foo.bar.sys.data.foo 123.0 \d{10,}\n$/)
|
46
46
|
end
|
47
47
|
end
|
48
|
+
|
49
|
+
context "when matching a nested hash" do
|
50
|
+
let(:event) { LogStash::Event.new("foo" => {"a" => 3, "c" => {"d" => 2}}) }
|
51
|
+
|
52
|
+
it "should create the proper formatted lines" do
|
53
|
+
lines = [server.pop, server.pop].sort # Put key 'a' first
|
54
|
+
expect(lines[0]).to match(/^foo.bar.sys.data.foo.a 3 \d{10,}\n$/)
|
55
|
+
expect(lines[1]).to match(/^foo.bar.sys.data.foo.c.d 2 \d{10,}\n$/)
|
56
|
+
end
|
57
|
+
end
|
48
58
|
end
|
49
59
|
|
50
60
|
context "match all keys" do
|
@@ -124,6 +134,16 @@ describe LogStash::Outputs::Graphite do
|
|
124
134
|
line = server.pop
|
125
135
|
expect(line).to match(/^custom.foo 123.0 \d{10,}\n$/)
|
126
136
|
end
|
137
|
+
|
138
|
+
context "when matching a nested hash" do
|
139
|
+
let(:event) { LogStash::Event.new("custom.foo" => {"a" => 3, "c" => {"d" => 2}}) }
|
140
|
+
|
141
|
+
it "should create the proper formatted lines" do
|
142
|
+
lines = [server.pop, server.pop].sort # Put key 'a' first
|
143
|
+
expect(lines[0]).to match(/^custom.foo.a 3 \d{10,}\n$/)
|
144
|
+
expect(lines[1]).to match(/^custom.foo.c.d 2 \d{10,}\n$/)
|
145
|
+
end
|
146
|
+
end
|
127
147
|
end
|
128
148
|
end
|
129
149
|
end
|
@@ -144,4 +164,34 @@ describe LogStash::Outputs::Graphite do
|
|
144
164
|
expect(line).to match(/^foo 1.0 #{timestamp_new}\n$/)
|
145
165
|
end
|
146
166
|
end
|
167
|
+
|
168
|
+
describe "dotifying a hash" do
|
169
|
+
let(:event) { LogStash::Event.new( "metrics" => hash) }
|
170
|
+
let(:dotified) { LogStash::Outputs::Graphite.new().send(:dotify, hash) }
|
171
|
+
|
172
|
+
context "with a complex hash" do
|
173
|
+
let(:hash) { {:a => 2, :b => {:c => 3, :d => 4, :e => {:f => 5}}} }
|
174
|
+
|
175
|
+
it "should dottify correctly" do
|
176
|
+
expect(dotified).to eql({"a" => 2, "b.c" => 3, "b.d" => 4, "b.e.f" => 5})
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context "with a simple hash" do
|
181
|
+
let(:hash) { {:a => 2, 5 => 4} }
|
182
|
+
|
183
|
+
it "should do nothing more than stringify the keys" do
|
184
|
+
expect(dotified).to eql("a" => 2, "5" => 4)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
context "with an array value" do
|
189
|
+
let(:hash) { {:a => 2, 5 => 4, :c => [1,2,3]} }
|
190
|
+
|
191
|
+
it "should ignore array values" do
|
192
|
+
expect(dotified).to eql("a" => 2, "5" => 4)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
147
197
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-output-graphite
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Elastic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-06
|
11
|
+
date: 2015-08-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: logstash-core
|
@@ -127,7 +127,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
127
127
|
version: '0'
|
128
128
|
requirements: []
|
129
129
|
rubyforge_project:
|
130
|
-
rubygems_version: 2.
|
130
|
+
rubygems_version: 2.1.9
|
131
131
|
signing_key:
|
132
132
|
specification_version: 4
|
133
133
|
summary: This output allows you to pull metrics from your logs and ship them to Graphite
|