fluent-plugin-http_forward 0.1.0
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 +7 -0
- data/.gitignore +10 -0
- data/CHANGELOG.txt +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +11 -0
- data/README.md +43 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/examples/data.sh +6 -0
- data/examples/standalone.conf +36 -0
- data/flunt-plugin-http_forward.gemspec +22 -0
- data/lib/fluent/plugin/out_http_forward.rb +181 -0
- data/lib/fluent/plugin_mixin/chunk_json_streamer.rb +38 -0
- metadata +125 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d17721c462207dd57050c8f0549ca074ad1ca630
|
4
|
+
data.tar.gz: 2232c90bdb2fee35784415dcfa506c0707de10f2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9e31ea459957415c2f87a9097c5ca052b6fb21d558344e0384b861c53e05b297f54d261e8516a0b9dc8f7ac4e048e6205d91fd7f0c69e81e167fb0c71fe410fd
|
7
|
+
data.tar.gz: f42b9ea013bd072c3150f1f84f251d4cc69127c6ce5ca789f9ee5fc0f67973bc796788d4283bfe0d0b2c22372505fd0b70f92ad4813725d076133bd93f33399d
|
data/.gitignore
ADDED
data/CHANGELOG.txt
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
2
|
+
you may not use this file except in compliance with the License.
|
3
|
+
You may obtain a copy of the License at
|
4
|
+
|
5
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
6
|
+
|
7
|
+
Unless required by applicable law or agreed to in writing, software
|
8
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
9
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
10
|
+
See the License for the specific language governing permissions and
|
11
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# Fluent::Plugin::HttpForward
|
2
|
+
|
3
|
+
This gem provides a buffered HTTP output plugin for Fluentd which also optionally supports authentication.
|
4
|
+
|
5
|
+
## Requirements
|
6
|
+
|
7
|
+
* Fluetnd v0.14+
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'fluent-plugin-http_forward'
|
13
|
+
```
|
14
|
+
|
15
|
+
## Configuration Options
|
16
|
+
|
17
|
+
```
|
18
|
+
<match **>
|
19
|
+
@type http_forward
|
20
|
+
url http://remote.example.com/%{tag}
|
21
|
+
verb post
|
22
|
+
content_type application/json # optional override
|
23
|
+
<authentication>
|
24
|
+
method basic
|
25
|
+
username user
|
26
|
+
password pass
|
27
|
+
</authentication>
|
28
|
+
<format>
|
29
|
+
@type json
|
30
|
+
</format>
|
31
|
+
<buffer tag> # if buffering, specify tag for in_http compat
|
32
|
+
chunk_limit_size 8388608 # optional, maximum chunk size, default 8MB
|
33
|
+
total_limit_size 536760912 # optional, maximum buffer size, default 512M
|
34
|
+
chunk_records_limit 10 # optional, maximum records per chunk
|
35
|
+
flush_interval 60 # optional, maximum time between flush
|
36
|
+
flush_thread_count 1 # optional, async threads to flush buffer
|
37
|
+
</buffer>
|
38
|
+
```
|
39
|
+
|
40
|
+
## Status
|
41
|
+
|
42
|
+
At present, only the JSON format has been tested. There's an optional msgpack format available that is as of yet untested because in_http does not currently support it.
|
43
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "fluent/plugin/http_batch"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/examples/data.sh
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
<source>
|
2
|
+
@type redis_list_poller
|
3
|
+
tag redis.content
|
4
|
+
host 127.0.0.1
|
5
|
+
key test
|
6
|
+
batch_size 1
|
7
|
+
poll_interval 0.1
|
8
|
+
<parse>
|
9
|
+
@type json
|
10
|
+
</parse>
|
11
|
+
</source>
|
12
|
+
|
13
|
+
<source>
|
14
|
+
@type http
|
15
|
+
bind 127.0.0.1
|
16
|
+
format json
|
17
|
+
</source>
|
18
|
+
|
19
|
+
<match redis.content>
|
20
|
+
@type http_forward
|
21
|
+
url http://127.0.0.1:9880/dummy_tag
|
22
|
+
flush_thread_count 2
|
23
|
+
<format>
|
24
|
+
@type json
|
25
|
+
</format>
|
26
|
+
<buffer tag>
|
27
|
+
@type memory
|
28
|
+
chunk_records_limit 10
|
29
|
+
</buffer>
|
30
|
+
flush_interval 1
|
31
|
+
</match>
|
32
|
+
|
33
|
+
<match dummy_tag>
|
34
|
+
@type flowcounter_simple
|
35
|
+
unit second
|
36
|
+
</match>
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "fluent-plugin-http_forward"
|
5
|
+
spec.version = "0.1.0"
|
6
|
+
spec.authors = ["Jonathan Serafini"]
|
7
|
+
spec.email = ["jonathan@serafini.ca"]
|
8
|
+
|
9
|
+
spec.summary = %q{A buffered HTTP batching output for Fluentd}
|
10
|
+
spec.description = spec.summary
|
11
|
+
spec.homepage = "https://github.com/JonathanSerafini/fluent-plugin-http_forward"
|
12
|
+
|
13
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
14
|
+
spec.executables = []
|
15
|
+
spec.require_paths = ["lib"]
|
16
|
+
|
17
|
+
spec.add_development_dependency "bundler", "~> 1.11"
|
18
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
19
|
+
|
20
|
+
spec.add_runtime_dependency "fluentd", [">= 0.14.0", "< 2"]
|
21
|
+
spec.add_runtime_dependency "http", [">= 2.0.0", "< 3.0.0"]
|
22
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
require 'fluent/plugin/output'
|
2
|
+
require 'fluent/plugin_mixin/chunk_json_streamer'
|
3
|
+
|
4
|
+
module Fluent
|
5
|
+
module Plugin
|
6
|
+
class HttpForwardOutput < Output
|
7
|
+
Fluent::Plugin.register_output('http_forward', self)
|
8
|
+
helpers :timer
|
9
|
+
|
10
|
+
# http target parameters
|
11
|
+
# - url: the URL to upload to, ex.: http://iamateacup:8080/path/%{tag}
|
12
|
+
# the URI may contain the %{tag} pattern which will be replaced
|
13
|
+
# - verb: the HTTP verb to use
|
14
|
+
config_param :url, :string
|
15
|
+
config_param :verb, :string, :default => :post,
|
16
|
+
:list => %w(put post)
|
17
|
+
|
18
|
+
# an optional Content-Type header override, this may be unset and will be
|
19
|
+
# automatically detected based on the serializing format
|
20
|
+
config_param :content_type, :string, :default => nil
|
21
|
+
|
22
|
+
# http authentication parameters
|
23
|
+
config_section :authentication, :init => true, :multi => false do
|
24
|
+
config_param :method, :string, :default => nil, :list => %(basic)
|
25
|
+
config_param :username, :string, :default => nil
|
26
|
+
config_param :password, :string, :default => nil, :secret => true
|
27
|
+
end
|
28
|
+
|
29
|
+
# output serializing format
|
30
|
+
config_section :format, :init => true, :multi => false do
|
31
|
+
config_param :@type, :string, :default => "json",
|
32
|
+
:list => %w(msgpack json)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Initialize new output plugin
|
36
|
+
# @since 0.1.0
|
37
|
+
# @return [NilClass]
|
38
|
+
def initialize
|
39
|
+
super
|
40
|
+
require 'http'
|
41
|
+
end
|
42
|
+
|
43
|
+
# Initialize attributes and parameters
|
44
|
+
# @since 0.1.0
|
45
|
+
# @return [NilClass]
|
46
|
+
def configure(config)
|
47
|
+
super
|
48
|
+
|
49
|
+
configure_params(config)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Configure plugin parameters
|
53
|
+
# @since 0.1.0
|
54
|
+
# @return [NilClass]
|
55
|
+
def configure_params(config)
|
56
|
+
unless config.key?("content_type")
|
57
|
+
@content_type = case @format['@type']
|
58
|
+
when 'json' then 'application/json'
|
59
|
+
when 'msgpack' then 'application/x-msgpack'
|
60
|
+
else nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Prepare the plugin event loop
|
66
|
+
# @since 0.1.0
|
67
|
+
# @return [NilClass]
|
68
|
+
def start
|
69
|
+
super
|
70
|
+
start_connection
|
71
|
+
end
|
72
|
+
|
73
|
+
# Prepare the HTTP client object which provides a baseline for future
|
74
|
+
# request objects.
|
75
|
+
# @since 0.1.0
|
76
|
+
# @return [HTTP::Client]
|
77
|
+
def start_connection
|
78
|
+
@connection = HTTP::Client.new(
|
79
|
+
:headers => @headers
|
80
|
+
)
|
81
|
+
|
82
|
+
if @authentication['method']
|
83
|
+
@connection = @connection.basic_auth(
|
84
|
+
:user => @authentication['username'],
|
85
|
+
:pass => @authentication['password']
|
86
|
+
)
|
87
|
+
end
|
88
|
+
|
89
|
+
if @content_type
|
90
|
+
@connection = @connection.headers(
|
91
|
+
'Content-Type' => @content_type
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
95
|
+
@connection
|
96
|
+
end
|
97
|
+
|
98
|
+
# Tear down the plugin
|
99
|
+
# @since 0.1.0
|
100
|
+
# @return [NilClass]
|
101
|
+
def shutdown
|
102
|
+
@connection.close
|
103
|
+
super
|
104
|
+
end
|
105
|
+
|
106
|
+
# Enforce the usage of the MsgPack streaming method internally so as to
|
107
|
+
# ensure that we have a consistent buffering mechanism.
|
108
|
+
# @since 0.1.0
|
109
|
+
# @return [NilClass]
|
110
|
+
def execute_chunking(tag, es, enqueue: false)
|
111
|
+
return handle_stream_with_standard_format(tag, es, enqueue: enqueue)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Format the URL for a given request, and optionally replace the tag
|
115
|
+
# placerholder in the URI.
|
116
|
+
# @since 0.1.0
|
117
|
+
# @return [String] the url
|
118
|
+
def format_url(tag, time, data)
|
119
|
+
@url.sub(/%{tag}/, tag)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Format the Headers for a given request.
|
123
|
+
# @since 0.1.0
|
124
|
+
# @return [Hash] the header hash
|
125
|
+
def format_headers(tag, time, data)
|
126
|
+
@headers
|
127
|
+
end
|
128
|
+
|
129
|
+
# Format the Body for a given request depending on the Serializing
|
130
|
+
# format.
|
131
|
+
# @since 0.1.0
|
132
|
+
# @return [String] the request body
|
133
|
+
def format_body(tag, time, chunk)
|
134
|
+
case @format["@type"]
|
135
|
+
when "json"
|
136
|
+
chunk.extend Fluent::PluginMixin::ChunkJsonStreamer
|
137
|
+
serializer_proc = chunk.method(:to_json_stream)
|
138
|
+
else
|
139
|
+
serializer_proc = chunk.method(:to_msgpack_stream)
|
140
|
+
end
|
141
|
+
|
142
|
+
body = serializer_proc.call
|
143
|
+
end
|
144
|
+
|
145
|
+
# Upload the request body to the remote end point
|
146
|
+
# @since 0.1.0
|
147
|
+
# @return [Response] the HTTP response object
|
148
|
+
def upload(tag, time, content)
|
149
|
+
headers = format_headers(tag, nil, content)
|
150
|
+
url = format_url(tag, nil, content)
|
151
|
+
|
152
|
+
@connection.request(@verb, url, body: content, headers: headers)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Process a chunk of records synchronously, committing successful
|
156
|
+
# uploads and re-queueing failures.
|
157
|
+
# @since 0.1.0
|
158
|
+
# @return [Nil]
|
159
|
+
def write(chunk)
|
160
|
+
tag = chunk.metadata.tag
|
161
|
+
content = format_body(tag, nil, chunk)
|
162
|
+
|
163
|
+
response = upload(tag, nil, content)
|
164
|
+
|
165
|
+
if response.code <= 299
|
166
|
+
commit_write(chunk.unique_id)
|
167
|
+
else
|
168
|
+
@log.warn "failed to flush buffer", code: response.code
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# Process a chunk of records asynchronously, committing successful
|
173
|
+
# uploads and re-queueing failures.
|
174
|
+
# @since 0.1.0
|
175
|
+
# @return [Nil]
|
176
|
+
def try_write(chunk)
|
177
|
+
write(chunk)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Fluent
|
2
|
+
module PluginMixin
|
3
|
+
module ChunkJsonStreamer
|
4
|
+
# Iterate over records in chunk
|
5
|
+
# @since 0.1.0
|
6
|
+
# @returns [Array] an array of record objects
|
7
|
+
def records
|
8
|
+
records = []
|
9
|
+
each do |time, record|
|
10
|
+
records << record
|
11
|
+
end
|
12
|
+
records
|
13
|
+
end
|
14
|
+
|
15
|
+
# Serialize the chunk to a Json object
|
16
|
+
# @since 0.1.0
|
17
|
+
# @returns [String] the serialized object
|
18
|
+
def to_json_stream
|
19
|
+
json_serializer_proc.call(records)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# Load relevant Json modules and cache the serializing method
|
25
|
+
# @since 0.1.0
|
26
|
+
# @returns [Method] a proc which serializes to json
|
27
|
+
def json_serializer_proc
|
28
|
+
@json_packer ||= begin
|
29
|
+
require 'oj'
|
30
|
+
Oj.default_options = { mode: :compat }
|
31
|
+
Oj.method(:dump)
|
32
|
+
rescue LoadError
|
33
|
+
Yajl.method(:dump)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fluent-plugin-http_forward
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jonathan Serafini
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-06-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.11'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.11'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: fluentd
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.14.0
|
48
|
+
- - "<"
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '2'
|
51
|
+
type: :runtime
|
52
|
+
prerelease: false
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: 0.14.0
|
58
|
+
- - "<"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '2'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: http
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 2.0.0
|
68
|
+
- - "<"
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 3.0.0
|
71
|
+
type: :runtime
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 2.0.0
|
78
|
+
- - "<"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: 3.0.0
|
81
|
+
description: A buffered HTTP batching output for Fluentd
|
82
|
+
email:
|
83
|
+
- jonathan@serafini.ca
|
84
|
+
executables: []
|
85
|
+
extensions: []
|
86
|
+
extra_rdoc_files: []
|
87
|
+
files:
|
88
|
+
- ".gitignore"
|
89
|
+
- CHANGELOG.txt
|
90
|
+
- Gemfile
|
91
|
+
- LICENSE.txt
|
92
|
+
- README.md
|
93
|
+
- Rakefile
|
94
|
+
- bin/console
|
95
|
+
- bin/setup
|
96
|
+
- examples/data.sh
|
97
|
+
- examples/standalone.conf
|
98
|
+
- flunt-plugin-http_forward.gemspec
|
99
|
+
- lib/fluent/plugin/out_http_forward.rb
|
100
|
+
- lib/fluent/plugin_mixin/chunk_json_streamer.rb
|
101
|
+
homepage: https://github.com/JonathanSerafini/fluent-plugin-http_forward
|
102
|
+
licenses: []
|
103
|
+
metadata: {}
|
104
|
+
post_install_message:
|
105
|
+
rdoc_options: []
|
106
|
+
require_paths:
|
107
|
+
- lib
|
108
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
requirements: []
|
119
|
+
rubyforge_project:
|
120
|
+
rubygems_version: 2.5.2
|
121
|
+
signing_key:
|
122
|
+
specification_version: 4
|
123
|
+
summary: A buffered HTTP batching output for Fluentd
|
124
|
+
test_files: []
|
125
|
+
has_rdoc:
|