Skip to content

Commit 5ce9c34

Browse files
authored
Feat: added target configuration + event-factory support (#31)
+ Refactor: nest plugin specific errors + Refactor: log a debug msg on decode failure
1 parent 950ab09 commit 5ce9c34

File tree

5 files changed

+87
-18
lines changed

5 files changed

+87
-18
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
## 3.1.0
2+
- Feat: added target configuration + event-factory support [#31](https://github.com/logstash-plugins/logstash-codec-collectd/pull/31)
3+
14
## 3.0.8
25
- Update gemspec summary
36

docs/index.asciidoc

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ Be sure to replace `10.0.0.1` with the IP of your Logstash instance.
5252

5353

5454
[id="plugins-{type}s-{plugin}-options"]
55-
==== Collectd Codec Configuration Options
55+
==== Collectd Codec configuration options
5656

5757
[cols="<,<,<",options="header",]
5858
|=======================================================================
@@ -63,6 +63,7 @@ Be sure to replace `10.0.0.1` with the IP of your Logstash instance.
6363
| <<plugins-{type}s-{plugin}-nan_value>> |<<number,number>>|No
6464
| <<plugins-{type}s-{plugin}-prune_intervals>> |<<boolean,boolean>>|No
6565
| <<plugins-{type}s-{plugin}-security_level>> |<<string,string>>, one of `["None", "Sign", "Encrypt"]`|No
66+
| <<plugins-{type}s-{plugin}-target>> |<<string,string>>|No
6667
| <<plugins-{type}s-{plugin}-typesdb>> |<<array,array>>|No
6768
|=======================================================================
6869

@@ -126,6 +127,26 @@ Prune interval records. Defaults to `true`.
126127
Security Level. Default is `None`. This setting mirrors the setting from the
127128
collectd https://collectd.org/wiki/index.php/Plugin:Network[Network plugin]
128129

130+
[id="plugins-{type}s-{plugin}-target"]
131+
===== `target`
132+
133+
* Value type is <<string,string>>
134+
* There is no default value for this setting.
135+
136+
Define the target field for placing the decoded values. If this setting is not
137+
set, data will be stored at the root (top level) of the event.
138+
139+
For example, if you want data to be put under the `document` field:
140+
[source,ruby]
141+
input {
142+
udp {
143+
port => 12345
144+
codec => collectd {
145+
target => "[document]"
146+
}
147+
}
148+
}
149+
129150
[id="plugins-{type}s-{plugin}-typesdb"]
130151
===== `typesdb`
131152

lib/logstash/codecs/collectd.rb

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,8 @@
66
require "tempfile"
77
require "time"
88

9-
import "javax.crypto.Mac"
10-
11-
class ProtocolError < LogStash::Error; end
12-
class HeaderError < LogStash::Error; end
13-
class EncryptionError < LogStash::Error; end
14-
class NaNError < LogStash::Error; end
9+
require 'logstash/plugin_mixins/event_support/event_factory_adapter'
10+
require 'logstash/plugin_mixins/validator_support/field_reference_validation_adapter'
1511

1612
# Read events from the collectd binary protocol over the network via udp.
1713
# See https://collectd.org/wiki/index.php/Binary_protocol
@@ -38,15 +34,24 @@ class NaNError < LogStash::Error; end
3834
# IgnoreSelected false
3935
# </Plugin>
4036
# <Plugin network>
41-
# <Server "10.0.0.1" "25826">
42-
# </Server>
37+
# Server "10.0.0.1" "25826"
4338
# </Plugin>
4439
#
4540
# Be sure to replace `10.0.0.1` with the IP of your Logstash instance.
4641
#
4742
class LogStash::Codecs::Collectd < LogStash::Codecs::Base
43+
44+
extend LogStash::PluginMixins::ValidatorSupport::FieldReferenceValidationAdapter
45+
46+
include LogStash::PluginMixins::EventSupport::EventFactoryAdapter
47+
4848
config_name "collectd"
4949

50+
class ProtocolError < LogStash::Error; end
51+
class HeaderError < LogStash::Error; end
52+
class EncryptionError < LogStash::Error; end
53+
class NaNError < LogStash::Error; end
54+
5055
@@openssl_mutex = Mutex.new
5156

5257
AUTHFILEREGEX = /([^:]+): (.+)/
@@ -108,8 +113,7 @@ class LogStash::Codecs::Collectd < LogStash::Codecs::Base
108113

109114
# Security Level. Default is `None`. This setting mirrors the setting from the
110115
# collectd https://collectd.org/wiki/index.php/Plugin:Network[Network plugin]
111-
config :security_level, :validate => [SECURITY_NONE, SECURITY_SIGN, SECURITY_ENCR],
112-
:default => "None"
116+
config :security_level, :validate => [SECURITY_NONE, SECURITY_SIGN, SECURITY_ENCR], :default => "None"
113117

114118
# What to do when a value in the event is `NaN` (Not a Number)
115119
#
@@ -132,6 +136,12 @@ class LogStash::Codecs::Collectd < LogStash::Codecs::Base
132136
# `Sign` or `Encrypt`
133137
config :authfile, :validate => :string
134138

139+
# Defines a target field for placing decoded fields.
140+
# If this setting is omitted, data gets stored at the root (top level) of the event.
141+
#
142+
# NOTE: the target is only relevant while decoding data into a new event.
143+
config :target, :validate => :field_reference
144+
135145
public
136146
def register
137147
@logger.trace("Starting Collectd codec...")
@@ -467,14 +477,10 @@ def decode(payload)
467477
# This is better than looping over all keys every time.
468478
collectd.delete('type_instance') if collectd['type_instance'] == ""
469479
collectd.delete('plugin_instance') if collectd['plugin_instance'] == ""
470-
if add_nan_tag
471-
collectd['tags'] ||= []
472-
collectd['tags'] << @nan_tag
473-
end
474480
# This ugly little shallow-copy hack keeps the new event from getting munged by the cleanup
475481
# With pass-by-reference we get hosed (if we pass collectd, then clean it up rapidly, values can disappear)
476482
if !drop # Drop the event if it's flagged true
477-
yield LogStash::Event.new(collectd.dup)
483+
yield generate_event(collectd.dup, add_nan_tag)
478484
else
479485
raise(NaNError)
480486
end
@@ -485,8 +491,15 @@ def decode(payload)
485491
end
486492
end
487493
end # while payload.length > 0 do
488-
rescue EncryptionError, ProtocolError, HeaderError, NaNError
494+
rescue EncryptionError, ProtocolError, HeaderError, NaNError => e
489495
# basically do nothing, we just want out
496+
@logger.debug("Decode failure", payload: payload, message: e.message)
490497
end # def decode
491498

499+
def generate_event(payload, add_nan_tag)
500+
event = targeted_event_factory.new_event(payload)
501+
event.tag @nan_tag if add_nan_tag
502+
event
503+
end
504+
492505
end # class LogStash::Codecs::Collectd

logstash-codec-collectd.gemspec

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Gem::Specification.new do |s|
22
s.name = 'logstash-codec-collectd'
3-
s.version = '3.0.8'
3+
s.version = '3.1.0'
44
s.licenses = ['Apache License (2.0)']
55
s.summary = "Reads events from the `collectd` binary protocol using UDP."
66
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"
@@ -20,6 +20,8 @@ Gem::Specification.new do |s|
2020

2121
# Gem dependencies
2222
s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
23+
s.add_runtime_dependency 'logstash-mixin-event_support', '~> 1.0'
24+
s.add_runtime_dependency 'logstash-mixin-validator_support', '~> 1.0'
2325

2426
s.add_development_dependency 'logstash-devutils'
2527
s.add_development_dependency 'insist'

spec/codecs/collectd_spec.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,36 @@
9494
end
9595
expect(counter).to eq(1)
9696
end # it "should replace a NaN with a zero and add tag '_collectdNaN' by default"
97+
98+
context 'with target' do
99+
100+
subject do
101+
LogStash::Codecs::Collectd.new("target" => "[foo]")
102+
end
103+
104+
it "decodes with data into target field" do
105+
payload = ["00000015746573742e6578616d706c652e636f6d000008000c14dc4c81831ef78b0009000c00000000400000000002000970696e67000004000970696e67000005001c70696e672d7461726765742e6578616d706c652e636f6d000006000f000101000000000000f87f"].pack('H*')
106+
counter = 0
107+
subject.decode(payload) do |event|
108+
case counter
109+
when 0
110+
expect(event.include?("host")).to be false
111+
expect(event.include?("plugin")).to be false
112+
113+
expect(event.get("[foo][host]")).to eq("test.example.com")
114+
expect(event.get("[foo][plugin]")).to eq("ping")
115+
expect(event.get("[foo][type_instance]")).to eq("ping-target.example.com")
116+
expect(event.get("[foo][collectd_type]")).to eq("ping")
117+
expect(event.get("[foo][value]")).to eq(0)
118+
expect(event.get("tags")).to eq(["_collectdNaN"])
119+
end
120+
counter += 1
121+
end
122+
expect(counter).to eq(1)
123+
end
124+
125+
end
126+
97127
end # context "None"
98128

99129
context "Replace nan_value and nan_tag with non-default values" do

0 commit comments

Comments
 (0)