logstash-codec-protobuf 1.0.0 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -2
- data/Gemfile +10 -2
- data/docs/index.asciidoc +106 -0
- data/lib/logstash/codecs/protobuf.rb +29 -53
- data/logstash-codec-protobuf.gemspec +2 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 826cf27e43ea66cbabc39b226b229d179fd275d6
|
4
|
+
data.tar.gz: 0e2888f0622344cc8dddf20b03b9c89974d0613f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8f49b8820a8a70a686a42c7561621946a426e74f839f18476c84a1e59dc06e2b71cbb2045c8281fb36d6cd432ee22ea896900dbbacf01686b46530b8008a8726
|
7
|
+
data.tar.gz: a162df9db2fed47938ef1cdd2901c28230a6f127351f464288582561b2d0fd5baef1fa59da91af503e2cd1b36e598932af827f0492e8becd5b9e122c19494828
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
@@ -1,3 +1,11 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
|
-
|
3
|
-
gemspec
|
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/docs/index.asciidoc
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
:plugin: protobuf
|
2
|
+
:type: codec
|
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
|
+
=== Protobuf codec plugin
|
18
|
+
|
19
|
+
include::{include_path}/plugin_header.asciidoc[]
|
20
|
+
|
21
|
+
==== Description
|
22
|
+
|
23
|
+
This codec converts protobuf encoded messages into logstash events and vice versa.
|
24
|
+
|
25
|
+
Requires the protobuf definitions as ruby files. You can create those using the [ruby-protoc compiler](https://github.com/codekitchen/ruby-protocol-buffers).
|
26
|
+
|
27
|
+
The following shows a usage example for decoding events from a kafka stream:
|
28
|
+
[source,ruby]
|
29
|
+
kafka
|
30
|
+
{
|
31
|
+
zk_connect => "127.0.0.1"
|
32
|
+
topic_id => "your_topic_goes_here"
|
33
|
+
codec => protobuf
|
34
|
+
{
|
35
|
+
class_name => "Animal::Unicorn"
|
36
|
+
include_path => ['/path/to/protobuf/definitions/UnicornProtobuf.pb.rb']
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
|
41
|
+
[id="plugins-{type}s-{plugin}-options"]
|
42
|
+
==== Protobuf Codec Configuration Options
|
43
|
+
|
44
|
+
[cols="<,<,<",options="header",]
|
45
|
+
|=======================================================================
|
46
|
+
|Setting |Input type|Required
|
47
|
+
| <<plugins-{type}s-{plugin}-class_name>> |<<string,string>>|Yes
|
48
|
+
| <<plugins-{type}s-{plugin}-include_path>> |<<array,array>>|Yes
|
49
|
+
|=======================================================================
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
[id="plugins-{type}s-{plugin}-class_name"]
|
54
|
+
===== `class_name`
|
55
|
+
|
56
|
+
* This is a required setting.
|
57
|
+
* Value type is <<string,string>>
|
58
|
+
* There is no default value for this setting.
|
59
|
+
|
60
|
+
Name of the class to decode.
|
61
|
+
If your protobuf definition contains modules, prepend them to the class name with double colons like so:
|
62
|
+
[source,ruby]
|
63
|
+
class_name => "Foods::Dairy::Cheese"
|
64
|
+
|
65
|
+
This corresponds to a protobuf definition starting as follows:
|
66
|
+
[source,ruby]
|
67
|
+
module Foods
|
68
|
+
module Dairy
|
69
|
+
class Cheese
|
70
|
+
# here are your field definitions.
|
71
|
+
|
72
|
+
If your class references other definitions: you only have to add the main class here.
|
73
|
+
|
74
|
+
[id="plugins-{type}s-{plugin}-include_path"]
|
75
|
+
===== `include_path`
|
76
|
+
|
77
|
+
* This is a required setting.
|
78
|
+
* Value type is <<array,array>>
|
79
|
+
* There is no default value for this setting.
|
80
|
+
|
81
|
+
List of absolute pathes to files with protobuf definitions.
|
82
|
+
When using more than one file, make sure to arrange the files in reverse order of dependency so that each class is loaded before it is
|
83
|
+
refered to by another.
|
84
|
+
|
85
|
+
Example: a class _Cheese_ referencing another protobuf class _Milk_
|
86
|
+
[source,ruby]
|
87
|
+
module Foods
|
88
|
+
module Dairy
|
89
|
+
class Cheese
|
90
|
+
set_fully_qualified_name "Foods.Dairy.Cheese"
|
91
|
+
optional ::Foods::Cheese::Milk, :milk, 1
|
92
|
+
optional :int64, :unique_id, 2
|
93
|
+
# here be more field definitions
|
94
|
+
|
95
|
+
would be configured as
|
96
|
+
[source,ruby]
|
97
|
+
include_path => ['/path/to/protobuf/definitions/Milk.pb.rb','/path/to/protobuf/definitions/Cheese.pb.rb']
|
98
|
+
|
99
|
+
When using the codec in an output plugin:
|
100
|
+
* make sure to include all the desired fields in the protobuf definition, including timestamp.
|
101
|
+
Remove fields that are not part of the protobuf definition from the event by using the mutate filter.
|
102
|
+
* the @ symbol is currently not supported in field names when loading the protobuf definitions for encoding. Make sure to call the timestamp field "timestamp"
|
103
|
+
instead of "@timestamp" in the protobuf file. Logstash event fields will be stripped of the leading @ before conversion.
|
104
|
+
|
105
|
+
|
106
|
+
|
@@ -66,32 +66,23 @@ class LogStash::Codecs::Protobuf < LogStash::Codecs::Base
|
|
66
66
|
config :include_path, :validate => :array, :required => true
|
67
67
|
|
68
68
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
69
|
def register
|
73
70
|
@pb_metainfo = {}
|
74
71
|
include_path.each { |path| require_pb_path(path) }
|
75
72
|
@obj = create_object_from_name(class_name)
|
76
73
|
@logger.debug("Protobuf files successfully loaded.")
|
77
|
-
|
78
74
|
end
|
79
75
|
|
80
|
-
def decode(data)
|
81
|
-
decoded = @obj.parse(data.to_s)
|
82
|
-
results = keys2strings(decoded.to_hash)
|
83
|
-
yield LogStash::Event.new(results) if block_given?
|
84
|
-
end # def decode
|
85
76
|
|
86
|
-
def
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
77
|
+
def decode(data)
|
78
|
+
begin
|
79
|
+
decoded = @obj.parse(data.to_s)
|
80
|
+
yield LogStash::Event.new(decoded.to_hash) if block_given?
|
81
|
+
rescue => e
|
82
|
+
@logger.warn("Couldn't decode protobuf: #{e.inspect}.")
|
83
|
+
# raise e
|
93
84
|
end
|
94
|
-
end
|
85
|
+
end # def decode
|
95
86
|
|
96
87
|
|
97
88
|
def encode(event)
|
@@ -99,68 +90,53 @@ class LogStash::Codecs::Protobuf < LogStash::Codecs::Base
|
|
99
90
|
@on_event.call(event, protobytes)
|
100
91
|
end # def encode
|
101
92
|
|
93
|
+
|
102
94
|
private
|
103
|
-
def generate_protobuf(event)
|
104
|
-
meth = self.method("encoder_strategy_1")
|
105
|
-
data = meth.call(event, @class_name)
|
95
|
+
def generate_protobuf(event)
|
106
96
|
begin
|
97
|
+
data = _encode(event, @class_name)
|
107
98
|
msg = @obj.new(data)
|
108
99
|
msg.serialize_to_string
|
109
100
|
rescue NoMethodError
|
110
101
|
@logger.debug("error 2: NoMethodError. Maybe mismatching protobuf definition. Required fields are: " + event.to_hash.keys.join(", "))
|
102
|
+
rescue => e
|
103
|
+
@logger.debug("Couldn't generate protobuf: ${e}")
|
111
104
|
end
|
112
105
|
end
|
113
106
|
|
114
|
-
def encoder_strategy_1(event, class_name)
|
115
|
-
_encoder_strategy_1(event.to_hash, class_name)
|
116
107
|
|
117
|
-
|
118
|
-
|
119
|
-
def _encoder_strategy_1(datahash, class_name)
|
120
|
-
fields = clean_hash_keys(datahash)
|
121
|
-
fields = flatten_hash_values(fields) # TODO we could merge this and the above method back into one to save one iteration, but how are we going to name it?
|
108
|
+
def _encode(datahash, class_name)
|
109
|
+
fields = prepare_for_encoding(datahash)
|
122
110
|
meta = get_complex_types(class_name) # returns a hash with member names and their protobuf class names
|
123
111
|
meta.map do | (k,typeinfo) |
|
124
112
|
if fields.include?(k)
|
125
113
|
original_value = fields[k]
|
126
114
|
proto_obj = create_object_from_name(typeinfo)
|
127
115
|
fields[k] =
|
128
|
-
if original_value.is_a?(::Array)
|
129
|
-
|
130
|
-
|
116
|
+
if original_value.is_a?(::Array)
|
117
|
+
# make this field an array/list of protobuf objects
|
118
|
+
# value is a list of hashed complex objects, each of which needs to be protobuffed and
|
119
|
+
# put back into the list.
|
120
|
+
original_value.map { |x| _encode(x, typeinfo) }
|
121
|
+
original_value
|
131
122
|
else
|
132
|
-
recursive_fix =
|
123
|
+
recursive_fix = _encode(original_value, class_name)
|
133
124
|
proto_obj.new(recursive_fix)
|
134
125
|
end # if is array
|
135
126
|
end
|
136
|
-
|
137
|
-
end
|
138
|
-
|
127
|
+
end
|
139
128
|
fields
|
140
129
|
end
|
141
130
|
|
142
|
-
def ecs1_list_helper(value, proto_obj, class_name)
|
143
|
-
# make this field an array/list of protobuf objects
|
144
|
-
# value is a list of hashed complex objects, each of which needs to be protobuffed and
|
145
|
-
# put back into the list.
|
146
|
-
next unless value.is_a?(::Array)
|
147
|
-
value.map { |x| _encoder_strategy_1(x, class_name) }
|
148
|
-
value
|
149
|
-
end
|
150
131
|
|
151
|
-
def
|
132
|
+
def prepare_for_encoding(datahash)
|
133
|
+
# the data cannot be encoded until certain criteria are met:
|
134
|
+
# 1) remove @ signs from keys
|
152
135
|
# 2) convert timestamps and other objects to strings
|
153
|
-
next unless datahash.is_a?(::Hash)
|
154
|
-
|
155
|
-
::Hash[datahash.map{|(k,v)| [k, (convert_to_string?(v) ? v.to_s : v)] }]
|
136
|
+
next unless datahash.is_a?(::Hash)
|
137
|
+
::Hash[datahash.map{|(k,v)| [remove_atchar(k.to_s), (convert_to_string?(v) ? v.to_s : v)] }]
|
156
138
|
end
|
157
139
|
|
158
|
-
def clean_hash_keys(datahash)
|
159
|
-
# 1) remove @ signs from keys
|
160
|
-
next unless datahash.is_a?(::Hash)
|
161
|
-
|
162
|
-
::Hash[datahash.map{|(k,v)| [remove_atchar(k.to_s), v] }]
|
163
|
-
end #clean_hash_keys
|
164
140
|
|
165
141
|
def convert_to_string?(v)
|
166
142
|
!(v.is_a?(Fixnum) || v.is_a?(::Hash) || v.is_a?(::Array) || [true, false].include?(v))
|
@@ -171,7 +147,7 @@ class LogStash::Codecs::Protobuf < LogStash::Codecs::Base
|
|
171
147
|
key.dup.gsub(/@/,'')
|
172
148
|
end
|
173
149
|
|
174
|
-
|
150
|
+
|
175
151
|
def create_object_from_name(name)
|
176
152
|
begin
|
177
153
|
@logger.debug("Creating instance of " + name)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
|
3
3
|
s.name = 'logstash-codec-protobuf'
|
4
|
-
s.version = '1.0.
|
4
|
+
s.version = '1.0.2'
|
5
5
|
s.licenses = ['Apache License (2.0)']
|
6
6
|
s.summary = "This codec may be used to decode (via inputs) and encode (via outputs) protobuf messages"
|
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"
|
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.require_paths = ["lib"]
|
11
11
|
|
12
12
|
# Files
|
13
|
-
s.files = Dir[
|
13
|
+
s.files = Dir["lib/**/*","spec/**/*","*.gemspec","*.md","CONTRIBUTORS","Gemfile","LICENSE","NOTICE.TXT", "vendor/jar-dependencies/**/*.jar", "vendor/jar-dependencies/**/*.rb", "VERSION", "docs/**/*"]
|
14
14
|
|
15
15
|
# Tests
|
16
16
|
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-codec-protobuf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Inga Feick
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-06-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -71,6 +71,7 @@ files:
|
|
71
71
|
- LICENSE
|
72
72
|
- NOTICE.TXT
|
73
73
|
- README.md
|
74
|
+
- docs/index.asciidoc
|
74
75
|
- lib/logstash/codecs/protobuf.rb
|
75
76
|
- logstash-codec-protobuf.gemspec
|
76
77
|
- spec/codecs/protobuf_spec.rb
|