logstash-codec-avro_header 3.2.4-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5849d46bfeead73b272c3069757384876a4c8798
4
+ data.tar.gz: d5ae1267322c8aaa8ae09728f77300531ef5d615
5
+ SHA512:
6
+ metadata.gz: 860422ba2bb509831d70c54041ec4100c6a9372a2be7cc373afacd9291f9c020427327a978290c049569a04f2343c6e05d344d898e526e4d084d73cd8f5f1ba7
7
+ data.tar.gz: 3a7cf8f4ab4784c4786097b0fe879865f4191ca16513087752003a8aa0da3d5f1bbb73e910753ab7f45ce97114b7ba4982861c64ca25f1d6d27b83b43d2db35a
data/CHANGELOG.md ADDED
@@ -0,0 +1,28 @@
1
+ ## 3.2.4
2
+ - Add support for decoding Kafka events with schema header
3
+
4
+ ## 3.2.3
5
+ - Update gemspec summary
6
+
7
+ ## 3.2.2
8
+ - Fix some documentation issues
9
+
10
+ ## 3.2.0
11
+ - Fixed an issue with the encoding that prevented certain fields from being serialized in a way compatible with the Kafka plugins
12
+
13
+ ## 3.1.0
14
+ - Introduce `tag_on_failure` option to tag events with `_avroparsefailure` instead of throwing an exception when decoding
15
+
16
+ ## 3.0.0
17
+ - breaking: Update to new Event API
18
+
19
+ ## 2.0.4
20
+ - Depend on logstash-core-plugin-api instead of logstash-core, removing the need to mass update plugins on major releases of logstash
21
+
22
+ ## 2.0.3
23
+ - New dependency requirements for logstash-core for the 5.0 release
24
+
25
+ ## 2.0.0
26
+ - Plugins were updated to follow the new shutdown semantic, this mainly allows Logstash to instruct input plugins to terminate gracefully,
27
+ instead of using Thread.raise on the plugins' threads. Ref: https://github.com/elastic/logstash/pull/3895
28
+ - Dependency on logstash-core update to 2.0
data/CONTRIBUTORS ADDED
@@ -0,0 +1,12 @@
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
+ * Pier-Hugues Pellerin (ph)
6
+ * Tal Levy (talevy)
7
+ * Jake Morrison (reachfh)
8
+
9
+ Note: If you've sent us patches, bug reports, or otherwise contributed to
10
+ Logstash, and you aren't on the list above and want to be, please let us know
11
+ and we'll make sure you're here. Contributions from folks like you are what make
12
+ open source awesome.
data/DEVELOPER.md ADDED
@@ -0,0 +1,67 @@
1
+ Logstash Avro Codec
2
+ ===================
3
+
4
+ How to Install
5
+ --------------
6
+
7
+ ```
8
+ bin/plugin install logstash-avro-codec_header
9
+ ```
10
+
11
+ How to Use
12
+ ----------
13
+ You can use this codec to decode avro messages
14
+ in a Kafka topic input.
15
+
16
+ Here is an example schema for tweets.
17
+
18
+ ### tweet.avsc
19
+ ```
20
+ {
21
+ "type" : "record",
22
+ "name" : "twitter_schema",
23
+ "namespace" : "com.miguno.avro",
24
+ "fields" : [ {
25
+ "name" : "username",
26
+ "type" : "string",
27
+ "doc" : "Name of the user account on Twitter.com"
28
+ }, {
29
+ "name" : "tweet",
30
+ "type" : "string",
31
+ "doc" : "The content of the user's Twitter message"
32
+ }, {
33
+ "name" : "timestamp",
34
+ "type" : "long",
35
+ "doc" : "Unix epoch time in seconds"
36
+ } ],
37
+ "doc:" : "A basic schema for storing Twitter messages"
38
+ }
39
+ ```
40
+
41
+ Along with the logstash config for reading in messages of this
42
+ type using the avro codec with the logstash-input-kafka plugin.
43
+
44
+ ### logstash.conf
45
+
46
+ ```
47
+ input {
48
+ kafka {
49
+ topic_id => 'test_topic'
50
+ codec => avro_header {
51
+ schema_uri => 'tweet.avsc'
52
+ header_length => 10
53
+ }
54
+ }
55
+ }
56
+
57
+ output {
58
+ stdout {
59
+ codec => rubydebug
60
+ }
61
+ }
62
+ ```
63
+
64
+ ### Running the setup
65
+ ```
66
+ bin/logstash -f logstash.conf
67
+ ```
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
@@ -0,0 +1,5 @@
1
+ Elasticsearch
2
+ Copyright 2012-2015 Elasticsearch
3
+
4
+ This product includes software developed by The Apache Software
5
+ Foundation (http://www.apache.org/).
data/README.md ADDED
@@ -0,0 +1,109 @@
1
+ # Logstash Plugin
2
+
3
+ This is a plugin for [Logstash](https://github.com/elastic/logstash).
4
+
5
+ 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.
6
+
7
+ ## Documentation
8
+
9
+ 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/).
10
+
11
+ - For formatting code or config example, you can use the asciidoc `[source,ruby]` directive
12
+ - For more asciidoc formatting tips, see the excellent reference here https://github.com/elastic/docs#asciidoc-guide
13
+
14
+ ## Need Help?
15
+
16
+ Need help? Try #logstash on freenode IRC or the https://discuss.elastic.co/c/logstash discussion forum.
17
+
18
+ ## Developing
19
+
20
+ ### 1. Plugin Developement and Testing
21
+
22
+ #### Code
23
+ - To get started, you'll need JRuby with the Bundler gem installed.
24
+
25
+ - 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).
26
+
27
+ - Install dependencies
28
+ ```sh
29
+ bundle install
30
+ ```
31
+
32
+ #### Test
33
+
34
+ - Update your dependencies
35
+
36
+ ```sh
37
+ bundle install
38
+ ```
39
+
40
+ - Run tests
41
+
42
+ ```sh
43
+ bundle exec rspec
44
+ ```
45
+
46
+ - Build gem
47
+ ```sh
48
+ jruby -S gem build logstash-codec-avro_header.gemspec
49
+ ```
50
+
51
+ ### 2. Running your unpublished Plugin in Logstash
52
+
53
+ #### 2.1 Run in a local Logstash clone
54
+
55
+ - Edit Logstash `Gemfile` and add the local plugin path, for example:
56
+ ```ruby
57
+ gem "logstash-codec-avro_header", :path => "/your/local/logstash-codec-avro_header"
58
+ ```
59
+ - Install plugin
60
+ ```sh
61
+ # Logstash 2.3 and higher
62
+ bin/logstash-plugin install --no-verify
63
+
64
+ # Prior to Logstash 2.3
65
+ bin/plugin install --no-verify
66
+
67
+ ```
68
+ - Run Logstash with your plugin
69
+ ```sh
70
+ bin/logstash -e 'codec {avro_header {}}'
71
+ ```
72
+ At this point any modifications to the plugin code will be applied to this local Logstash setup. After modifying the plugin, simply rerun Logstash.
73
+
74
+ #### 2.2 Run in an installed Logstash
75
+
76
+ 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:
77
+
78
+ - Build your plugin gem
79
+ ```sh
80
+ gem build logstash-codec-avro_header.gemspec
81
+ ```
82
+
83
+ - Install the plugin from a local gem
84
+ ```sh
85
+ bin/logstash-plugin install /your/local/plugin/logstash-codec-avro_header.gem
86
+ ```
87
+
88
+ or
89
+
90
+ - Install the plugin from the Logstash home
91
+ ```sh
92
+ # Logstash 2.3 and higher
93
+ bin/logstash-plugin install --no-verify
94
+
95
+ # Prior to Logstash 2.3
96
+ bin/plugin install --no-verify
97
+
98
+ ```
99
+ - Start Logstash and proceed to test the plugin
100
+
101
+ ## Contributing
102
+
103
+ All contributions are welcome: ideas, patches, documentation, bug reports, complaints, and even something you drew up on a napkin.
104
+
105
+ 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.
106
+
107
+ It is more important to the community that you are able to contribute.
108
+
109
+ For more information about contributing, see the [CONTRIBUTING](https://github.com/elastic/logstash/blob/master/CONTRIBUTING.md) file.
@@ -0,0 +1,104 @@
1
+ :plugin: avro_header
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}s-{plugin}"]
16
+
17
+ === Avro codec plugin
18
+
19
+ include::{include_path}/plugin_header.asciidoc[]
20
+
21
+ ==== Description
22
+
23
+ Read serialized Avro records as Logstash events
24
+
25
+ This plugin is used to serialize Logstash events as
26
+ Avro datums, as well as deserializing Avro datums into
27
+ Logstash events.
28
+
29
+ ==== Encoding
30
+
31
+ This codec is for serializing individual Logstash events
32
+ as Avro datums that are Avro binary blobs. It does not encode
33
+ Logstash events into an Avro file.
34
+
35
+
36
+ ==== Decoding
37
+
38
+ This codec is for deserializing individual Avro records. It is not for reading
39
+ Avro files. Avro files have a unique format that must be handled upon input.
40
+
41
+
42
+ ==== Usage
43
+ Example usage with Kafka input.
44
+
45
+ [source,ruby]
46
+ ----------------------------------
47
+ input {
48
+ kafka {
49
+ codec => avro {
50
+ schema_uri => "/tmp/schema.avsc"
51
+ header_length => 10
52
+ }
53
+ }
54
+ }
55
+ filter {
56
+ ...
57
+ }
58
+ output {
59
+ ...
60
+ }
61
+ ----------------------------------
62
+
63
+ [id="plugins-{type}s-{plugin}-options"]
64
+ ==== Avro Codec Configuration Options
65
+
66
+ [cols="<,<,<",options="header",]
67
+ |=======================================================================
68
+ |Setting |Input type|Required
69
+ | <<plugins-{type}s-{plugin}-schema_uri>> |<<string,string>>|Yes
70
+ | <<plugins-{type}s-{plugin}-header_length>> |<<integer,integer>>|No
71
+ | <<plugins-{type}s-{plugin}-tag_on_failure>> |<<boolean,boolean>>|No
72
+ |=======================================================================
73
+
74
+ &nbsp;
75
+
76
+ [id="plugins-{type}s-{plugin}-schema_uri"]
77
+ ===== `schema_uri`
78
+
79
+ * This is a required setting.
80
+ * Value type is <<string,string>>
81
+ * There is no default value for this setting.
82
+
83
+ schema path to fetch the schema from.
84
+ This can be a 'http' or 'file' scheme URI
85
+ example:
86
+
87
+ * http - `http://example.com/schema.avsc`
88
+ * file - `/path/to/schema.avsc`
89
+
90
+ [id="plugins-{type}s-{plugin}-header_length"]
91
+ ===== `header_length`
92
+
93
+ * Value type is <<integer,integer>>
94
+ * Default value is 0
95
+
96
+ Number of bytes in header before Avro data.
97
+
98
+ [id="plugins-{type}s-{plugin}-tag_on_failure"]
99
+ ===== `tag_on_failure`
100
+
101
+ * Value type is <<boolean,boolean>>
102
+ * Default value is `false`
103
+
104
+ tag events with `_avroparsefailure` when decode fails
@@ -0,0 +1,181 @@
1
+ # encoding: utf-8
2
+ require "open-uri"
3
+ require "avro"
4
+ require "base64"
5
+ require "logstash/codecs/base"
6
+ require "logstash/event"
7
+ require "logstash/timestamp"
8
+ require "logstash/util"
9
+
10
+ # Read serialized Avro records as Logstash events
11
+ #
12
+ # This plugin is used to serialize Logstash events as
13
+ # Avro datums, as well as deserializing Avro datums into
14
+ # Logstash events.
15
+ #
16
+ # ==== Encoding
17
+ #
18
+ # This codec is for serializing individual Logstash events
19
+ # as Avro datums that are Avro binary blobs. It does not encode
20
+ # Logstash events into an Avro file.
21
+ #
22
+ #
23
+ # ==== Decoding
24
+ #
25
+ # This codec is for deserializing individual Avro records. It is not for reading
26
+ # Avro files. Avro files have a unique format that must be handled upon input.
27
+ #
28
+ #
29
+ # ==== Usage
30
+ # To read messages from Kafka input:
31
+ #
32
+ # [source,ruby]
33
+ # ----------------------------------
34
+ # input {
35
+ # kafka {
36
+ # codec => avro {
37
+ # schema_uri => "/tmp/schema.avsc"
38
+ # }
39
+ # }
40
+ # }
41
+ # filter {
42
+ # ...
43
+ # }
44
+ # output {
45
+ # ...
46
+ # }
47
+ # ----------------------------------
48
+ #
49
+ # Avro messages may have a header before the binary data indicating the schema,
50
+ # as described in the https://avro.apache.org/docs/1.8.2/spec.html#single_object_encoding[the Avro
51
+ # spec].
52
+ #
53
+ # The length of the header depends on how many bytes are used for a marker and
54
+ # the https://avro.apache.org/docs/1.8.2/spec.html#schema_fingerprints[fingerprint
55
+ # algorithm]. The fingerprint might be 8 bytes for CRC-64-AVRO, 16 bytes for
56
+ # MD5, or 32 bytes for SHA-256.
57
+ #
58
+ # Another option is the
59
+ # https://docs.confluent.io/current/schema-registry/docs/intro.html[Confluent
60
+ # Schema Registry], which uses a server to assign ids to different versions of
61
+ # schemas and look them up. That's supported by other logstash plugins, e.g.
62
+ # https://github.com/revpoint/logstash-codec-avro_schema_registry.
63
+ #
64
+ # At a minimum, specify the header length, and the plugin will skip those bytes
65
+ # before passing the input to the Avro parser.
66
+ #
67
+ # [source,ruby]
68
+ # ----------------------------------
69
+ # input {
70
+ # kafka {
71
+ # codec => avro {
72
+ # schema_uri => "/tmp/schema.avsc"
73
+ # header_length => 10
74
+ # }
75
+ # }
76
+ # }
77
+ # ----------------------------------
78
+ #
79
+ # If you specify the header marker, the plugin will attempt to match those
80
+ # bytes at the beginning of the data. If they match, it will skip the header
81
+ # bytes, otherwise it will pass all the data to the Avro parser.
82
+ #
83
+ # [source,ruby]
84
+ # ----------------------------------
85
+ # input {
86
+ # kafka {
87
+ # codec => avro {
88
+ # schema_uri => "/tmp/schema.avsc"
89
+ # header_length => 10
90
+ # # Marker bytes, specified as integer
91
+ # header_marker => [195, 1] # 0xC3, 0x01
92
+ # }
93
+ # }
94
+ # }
95
+ # ----------------------------------
96
+ class LogStash::Codecs::AvroHeader < LogStash::Codecs::Base
97
+ config_name "avro_header"
98
+
99
+ # schema path to fetch the schema from.
100
+ # This can be a 'http' or 'file' scheme URI
101
+ # example:
102
+ #
103
+ # * http - `http://example.com/schema.avsc`
104
+ # * file - `/path/to/schema.avsc`
105
+ config :schema_uri, :validate => :string, :required => true
106
+
107
+ # number of header bytes to skip before the Avro data
108
+ config :header_length, :validate => :number, :default => 0
109
+
110
+ # marker bytes at beginning of header, specified as integers
111
+ config :header_marker, :validate => :number, :list => true, :default => []
112
+
113
+ # tag events with `_avroparsefailure` when decode fails
114
+ config :tag_on_failure, :validate => :boolean, :default => false
115
+
116
+ def open_and_read(uri_string)
117
+ open(uri_string).read
118
+ end
119
+
120
+ public
121
+ def register
122
+ @schema = Avro::Schema.parse(open_and_read(schema_uri))
123
+ end
124
+
125
+ public
126
+ def decode(data)
127
+ begin
128
+ binary_data = Base64.strict_decode64(data)
129
+ rescue
130
+ binary_data = data
131
+ end
132
+
133
+ datum = StringIO.new(binary_data)
134
+ if header_length > 0
135
+ if binary_data.length < header_length
136
+ @logger.error('message is too small to decode header')
137
+ # Ignore header and try to parse as Avro
138
+ else
139
+ if header_marker and header_marker.length > 0
140
+ marker_length = header_marker.length
141
+ marker = datum.read(marker_length)
142
+ marker_bytes = marker.unpack("C" * marker_length)
143
+ if marker_bytes == header_marker
144
+ hash_length = header_length - marker_length
145
+ if hash_length > 0
146
+ datum.read(hash_length)
147
+ # TODO: look up schema using hash
148
+ end
149
+ else
150
+ @logger.error('header marker mismatch')
151
+ # Assume that there is no header and try to parse as Avro
152
+ datum.rewind
153
+ end
154
+ else
155
+ # No marker, just read header and ignore it
156
+ datum.read(header_length)
157
+ end
158
+ end
159
+ end
160
+ decoder = Avro::IO::BinaryDecoder.new(datum)
161
+ datum_reader = Avro::IO::DatumReader.new(@schema)
162
+ yield LogStash::Event.new(datum_reader.read(decoder))
163
+ rescue => e
164
+ if tag_on_failure
165
+ @logger.error("Avro parse error, original data now in message field", :error => e)
166
+ yield LogStash::Event.new("message" => data, "tags" => ["_avroparsefailure"])
167
+ else
168
+ raise e
169
+ end
170
+ end
171
+
172
+ public
173
+ def encode(event)
174
+ dw = Avro::IO::DatumWriter.new(@schema)
175
+ buffer = StringIO.new
176
+ encoder = Avro::IO::BinaryEncoder.new(buffer)
177
+ dw.write(event.to_hash, encoder)
178
+ @on_event.call(event, Base64.strict_encode64(buffer.string))
179
+ end
180
+
181
+ end
@@ -0,0 +1,29 @@
1
+ Gem::Specification.new do |s|
2
+
3
+ s.name = 'logstash-codec-avro_header'
4
+ s.version = '3.2.4'
5
+ s.platform = 'java'
6
+ s.licenses = ['Apache-2.0']
7
+ s.summary = "Reads serialized Avro records as Logstash events, with a header identifying the schema"
8
+ 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"
9
+ s.authors = ["Elastic"]
10
+ s.email = 'info@elastic.co'
11
+ s.homepage = "http://www.elastic.co/guide/en/logstash/current/index.html"
12
+ s.require_paths = ["lib"]
13
+
14
+ # Files
15
+ s.files = Dir["lib/**/*","spec/**/*","*.gemspec","*.md","CONTRIBUTORS","Gemfile","LICENSE","NOTICE.TXT", "vendor/jar-dependencies/**/*.jar", "vendor/jar-dependencies/**/*.rb", "VERSION", "docs/**/*"]
16
+
17
+ # Tests
18
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
19
+
20
+ # Special flag to let us know this is actually a logstash plugin
21
+ s.metadata = { "logstash_plugin" => "true", "logstash_group" => "codec" }
22
+
23
+ # Gem dependencies
24
+ s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
25
+
26
+ s.add_runtime_dependency "avro" #(Apache 2.0 license)
27
+
28
+ s.add_development_dependency 'logstash-devutils'
29
+ end
@@ -0,0 +1,193 @@
1
+ # encoding: utf-8
2
+ require 'logstash/devutils/rspec/spec_helper'
3
+ require 'avro'
4
+ require 'base64'
5
+ require 'logstash/codecs/avro_header'
6
+ require 'logstash/event'
7
+
8
+ describe LogStash::Codecs::AvroHeader do
9
+
10
+ context "non binary data" do
11
+ let (:avro_config) {{ 'schema_uri' => '
12
+ {"type": "record", "name": "Test",
13
+ "fields": [{"name": "foo", "type": ["null", "string"]},
14
+ {"name": "bar", "type": "int"}]}' }}
15
+ let (:test_event) {LogStash::Event.new({ "foo" => "hello", "bar" => 10 })}
16
+
17
+ subject do
18
+ allow_any_instance_of(LogStash::Codecs::AvroHeader).to \
19
+ receive(:open_and_read).and_return(avro_config['schema_uri'])
20
+ next LogStash::Codecs::AvroHeader.new(avro_config)
21
+ end
22
+
23
+ context "#decode" do
24
+ it "should return an LogStash::Event from raw and base64 encoded avro data" do
25
+ schema = Avro::Schema.parse(avro_config['schema_uri'])
26
+ dw = Avro::IO::DatumWriter.new(schema)
27
+ buffer = StringIO.new
28
+ encoder = Avro::IO::BinaryEncoder.new(buffer)
29
+ dw.write(test_event.to_hash, encoder)
30
+
31
+ subject.decode(Base64.strict_encode64(buffer.string)) do |event|
32
+ insist {event.is_a? LogStash::Event}
33
+ insist {event.get("foo")} == test_event.get("foo")
34
+ insist {event.get("bar")} == test_event.get("bar")
35
+ end
36
+ subject.decode(buffer.string) do |event|
37
+ insist {event.is_a? LogStash::Event}
38
+ insist {event.get("foo")} == test_event.get("foo")
39
+ insist {event.get("bar")} == test_event.get("bar")
40
+ end
41
+ end
42
+
43
+ it "should throw exception if decoding fails" do
44
+ expect {subject.decode("not avro") {|_| }}.to raise_error NoMethodError
45
+ end
46
+ end
47
+
48
+ context "#decode with tag_on_failure" do
49
+ let (:avro_config) {super.merge("tag_on_failure" => true)}
50
+
51
+ it "should tag event on failure" do
52
+ subject.decode("not avro") do |event|
53
+ insist {event.is_a? LogStash::Event}
54
+ insist {event.get("tags")} == ["_avroparsefailure"]
55
+ end
56
+ end
57
+ end
58
+
59
+ context "#decode binary data with header" do
60
+ let (:avro_config) {{ 'header_length' => 10,
61
+ 'schema_uri' => '
62
+ {"type": "record", "name": "Test",
63
+ "fields": [{"name": "foo", "type": ["null", "string"]},
64
+ {"name": "bar", "type": "int"}]}' }}
65
+
66
+ it "should return an LogStash::Event from raw and base64 encoded avro data with a header" do
67
+ schema = Avro::Schema.parse(avro_config['schema_uri'])
68
+ dw = Avro::IO::DatumWriter.new(schema)
69
+ buffer = StringIO.new
70
+ header = [0xC3, 0x01, 0xDEADBEEF00000001].pack('CCQ<')
71
+ buffer.write(header)
72
+
73
+ encoder = Avro::IO::BinaryEncoder.new(buffer)
74
+ dw.write(test_event.to_hash, encoder)
75
+
76
+ subject.decode(Base64.strict_encode64(buffer.string)) do |event|
77
+ insist {event.is_a? LogStash::Event}
78
+ insist {event.get("foo")} == test_event.get("foo")
79
+ insist {event.get("bar")} == test_event.get("bar")
80
+ end
81
+ subject.decode(buffer.string) do |event|
82
+ insist {event.is_a? LogStash::Event}
83
+ insist {event.get("foo")} == test_event.get("foo")
84
+ insist {event.get("bar")} == test_event.get("bar")
85
+ end
86
+ end
87
+
88
+ it "should throw exception if decoding fails" do
89
+ expect {subject.decode("not avro") {|_| }}.to raise_error NoMethodError
90
+ end
91
+ end
92
+
93
+ context "#decode binary data with header and marker" do
94
+ let (:avro_config) {{ 'header_length' => 10,
95
+ 'header_marker' => [0xC3, 0x01],
96
+ 'schema_uri' => '
97
+ {"type": "record", "name": "Test",
98
+ "fields": [{"name": "foo", "type": ["null", "string"]},
99
+ {"name": "bar", "type": "int"}]}' }}
100
+
101
+ it "should return an LogStash::Event when the marker matches" do
102
+ schema = Avro::Schema.parse(avro_config['schema_uri'])
103
+ dw = Avro::IO::DatumWriter.new(schema)
104
+ buffer = StringIO.new
105
+ header = [0xC3, 0x01, 0xDEADBEEF00000001].pack('CCQ<')
106
+ buffer.write(header)
107
+
108
+ encoder = Avro::IO::BinaryEncoder.new(buffer)
109
+ dw.write(test_event.to_hash, encoder)
110
+
111
+ subject.decode(Base64.strict_encode64(buffer.string)) do |event|
112
+ insist {event.is_a? LogStash::Event}
113
+ insist {event.get("foo")} == test_event.get("foo")
114
+ insist {event.get("bar")} == test_event.get("bar")
115
+ end
116
+ end
117
+
118
+ it "should return an LogStash::Event when the marker doesn't match" do
119
+ schema = Avro::Schema.parse(avro_config['schema_uri'])
120
+ dw = Avro::IO::DatumWriter.new(schema)
121
+ buffer = StringIO.new
122
+ encoder = Avro::IO::BinaryEncoder.new(buffer)
123
+ dw.write(test_event.to_hash, encoder)
124
+
125
+ subject.decode(Base64.strict_encode64(buffer.string)) do |event|
126
+ insist {event.is_a? LogStash::Event}
127
+ insist {event.get("foo")} == test_event.get("foo")
128
+ insist {event.get("bar")} == test_event.get("bar")
129
+ end
130
+ end
131
+
132
+ it "should throw exception if decoding fails" do
133
+ expect {subject.decode("not avro") {|_| }}.to raise_error NoMethodError
134
+ end
135
+ end
136
+
137
+
138
+ context "#encode" do
139
+ it "should return avro data from a LogStash::Event" do
140
+ got_event = false
141
+ subject.on_event do |event, data|
142
+ schema = Avro::Schema.parse(avro_config['schema_uri'])
143
+ datum = StringIO.new(Base64.strict_decode64(data))
144
+ decoder = Avro::IO::BinaryDecoder.new(datum)
145
+ datum_reader = Avro::IO::DatumReader.new(schema)
146
+ record = datum_reader.read(decoder)
147
+
148
+ insist {record["foo"]} == test_event.get("foo")
149
+ insist {record["bar"]} == test_event.get("bar")
150
+ insist {event.is_a? LogStash::Event}
151
+ got_event = true
152
+ end
153
+ subject.encode(test_event)
154
+ insist {got_event}
155
+ end
156
+
157
+ context "binary data" do
158
+
159
+ let (:avro_config) {{ 'schema_uri' => '{"namespace": "com.systems.test.data",
160
+ "type": "record",
161
+ "name": "TestRecord",
162
+ "fields": [
163
+ {"name": "name", "type": ["string", "null"]},
164
+ {"name": "longitude", "type": ["double", "null"]},
165
+ {"name": "latitude", "type": ["double", "null"]}
166
+ ]
167
+ }' }}
168
+ let (:test_event) {LogStash::Event.new({ "name" => "foo", "longitude" => 21.01234.to_f, "latitude" => 111.0123.to_f })}
169
+
170
+ subject do
171
+ allow_any_instance_of(LogStash::Codecs::AvroHeader).to \
172
+ receive(:open_and_read).and_return(avro_config['schema_uri'])
173
+ next LogStash::Codecs::AvroHeader.new(avro_config)
174
+ end
175
+
176
+ it "should correctly encode binary data" do
177
+ schema = Avro::Schema.parse(avro_config['schema_uri'])
178
+ dw = Avro::IO::DatumWriter.new(schema)
179
+ buffer = StringIO.new
180
+ encoder = Avro::IO::BinaryEncoder.new(buffer)
181
+ dw.write(test_event.to_hash, encoder)
182
+
183
+ subject.decode(Base64.strict_encode64(buffer.string)) do |event|
184
+ insist {event.is_a? LogStash::Event}
185
+ insist {event.get("name")} == test_event.get("name")
186
+ insist {event.get("longitude")} == test_event.get("longitude")
187
+ insist {event.get("latitude")} == test_event.get("latitude")
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,2 @@
1
+ # encoding: utf-8
2
+ require "logstash/devutils/rspec/spec_helper"
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: logstash-codec-avro_header
3
+ version: !ruby/object:Gem::Version
4
+ version: 3.2.4
5
+ platform: java
6
+ authors:
7
+ - Elastic
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-12-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '1.60'
19
+ - - "<="
20
+ - !ruby/object:Gem::Version
21
+ version: '2.99'
22
+ name: logstash-core-plugin-api
23
+ prerelease: false
24
+ type: :runtime
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
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ name: avro
40
+ prerelease: false
41
+ type: :runtime
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ requirement: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ name: logstash-devutils
54
+ prerelease: false
55
+ type: :development
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ description: This gem is a Logstash plugin required to be installed on top of the
62
+ Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This
63
+ gem is not a stand-alone program
64
+ email: info@elastic.co
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - CHANGELOG.md
70
+ - CONTRIBUTORS
71
+ - DEVELOPER.md
72
+ - Gemfile
73
+ - LICENSE
74
+ - NOTICE.TXT
75
+ - README.md
76
+ - docs/index.asciidoc
77
+ - lib/logstash/codecs/avro_header.rb
78
+ - logstash-codec-avro_header.gemspec
79
+ - spec/codecs/avro_header_spec.rb
80
+ - spec/spec_helper.rb
81
+ homepage: http://www.elastic.co/guide/en/logstash/current/index.html
82
+ licenses:
83
+ - Apache-2.0
84
+ metadata:
85
+ logstash_plugin: 'true'
86
+ logstash_group: codec
87
+ post_install_message:
88
+ rdoc_options: []
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ requirements: []
102
+ rubyforge_project:
103
+ rubygems_version: 2.6.14
104
+ signing_key:
105
+ specification_version: 4
106
+ summary: Reads serialized Avro records as Logstash events, with a header identifying
107
+ the schema
108
+ test_files:
109
+ - spec/codecs/avro_header_spec.rb
110
+ - spec/spec_helper.rb