fluent-output-router 0.9.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 +15 -0
- data/lib/fluent/plugin/out_router.rb +152 -0
- metadata +62 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
N2I3MzMzMDk2OWQ0MjIwZGQxZTFhOTcwNDE0YmJlZTA4ZjZkNjczZQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MDUzODc1NjM2MTEzMTA5MTM3OTQ0NzRlY2UxZjY3ZjVlN2ZhMDE1Zg==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NTQ5NGM1YTU0ODYxNDJiMmQ2YjU1MDM4NWM5ODQxNTBiYWUzYTNhNTU1MDZm
|
10
|
+
ODZlYjdkOWU2MTVmZWMxZjBkMDhhZTUwYmQ0ZGJkNzEzMTQxNmExOTMwMDBl
|
11
|
+
YTQwYTYxODhkNDgyYTg5OWFlZWFhNWM2NzNmZWMzNWNlMDA5YjA=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MDg1OTVhZDA1YTg0Zjk1OWExZWNhNGQyODEwOGFhYjlkZTYxYmZkMjhlZTdh
|
14
|
+
YjFlZjFjNzJlNjYwZjE2MDgyNmVlMWMxMmFmY2NkOGY4ZWZhYzc1MjYzYTBl
|
15
|
+
MWViNDJiMGUzZGZiOGYwNzVhYzkyZGE4YTU1M2NmZDNjOTYyMWY=
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Fluent
|
6
|
+
class RouterOutput < Fluent::Output
|
7
|
+
|
8
|
+
Fluent::Plugin.register_output('router', self)
|
9
|
+
MIN_REAPER_INTERVAL = 5 #sec
|
10
|
+
ROUTER_STATE_FILE = "router_state.json"
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
super
|
14
|
+
@outputs = {}
|
15
|
+
@last_used_time = {}
|
16
|
+
@last_reaper_run = Time.now
|
17
|
+
end
|
18
|
+
|
19
|
+
def configure(conf)
|
20
|
+
super
|
21
|
+
log "Starting the out_router plugin"
|
22
|
+
@inactivity_timeout = conf['inactivity_timeout'].to_i
|
23
|
+
@output_config = conf.elements.select { |e| e.name == 'config' }.first
|
24
|
+
mark_used @output_config
|
25
|
+
filename = File.join(File.dirname(Fluent::DEFAULT_CONFIG_PATH),
|
26
|
+
ROUTER_STATE_FILE)
|
27
|
+
@state_serializer = ConsistentArrayStorage.new(filename)
|
28
|
+
output_keys = @state_serializer.load
|
29
|
+
|
30
|
+
# Restarts all output plugins for each stored key after a crash
|
31
|
+
# or a stop.
|
32
|
+
# This way we ensure every needed buffered output plugin, like
|
33
|
+
# the s3 plugin, will start after a crash and flush its buffer
|
34
|
+
# files to s3.
|
35
|
+
log "Reading file " + filename +
|
36
|
+
" and found output keys: " + output_keys.to_json
|
37
|
+
output_keys.each do |key|
|
38
|
+
start_output(key)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def emit(tag, es, chain)
|
43
|
+
# This is the router logic. Splitting tag on character '.'
|
44
|
+
# uses the value after '.' as the router key.
|
45
|
+
key = tag.split(/\./)[1]
|
46
|
+
out = @outputs[key]
|
47
|
+
unless out
|
48
|
+
out = start_output(key)
|
49
|
+
end
|
50
|
+
out.emit tag, es, chain
|
51
|
+
now = Time.now
|
52
|
+
@last_used_time[key] = now
|
53
|
+
run_reaper(now)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def start_output(key)
|
59
|
+
log "Starting a new output of type " + @output_config['type'] +
|
60
|
+
" for key #{key}"
|
61
|
+
@outputs[key] = Fluent::Plugin.new_output @output_config['type']
|
62
|
+
@last_used_time[key] = Time.now
|
63
|
+
config = @output_config.clone
|
64
|
+
template! config, :key => key
|
65
|
+
out = @outputs[key]
|
66
|
+
out.configure config
|
67
|
+
out.start
|
68
|
+
@state_serializer.store(@outputs.keys)
|
69
|
+
out
|
70
|
+
end
|
71
|
+
|
72
|
+
def stop_output(key)
|
73
|
+
log "Stopping output of type " + @output_config['type'] +
|
74
|
+
" for key #{key} due to inactivity (no data comming in)"
|
75
|
+
out = @outputs.delete(key)
|
76
|
+
@last_used_time.delete(key)
|
77
|
+
out.shutdown
|
78
|
+
@state_serializer.store(@outputs.keys)
|
79
|
+
end
|
80
|
+
|
81
|
+
def mark_used(conf)
|
82
|
+
conf.used = conf.keys
|
83
|
+
conf.elements.each { |e| mark_used e }
|
84
|
+
end
|
85
|
+
|
86
|
+
# MUTABLE. WHICH ALSO MEANS IT IS TERRIBLE.
|
87
|
+
def template!(conf, keys)
|
88
|
+
conf.each do |k,v|
|
89
|
+
case v
|
90
|
+
when Hash
|
91
|
+
conf[k] = template v, keys
|
92
|
+
when String
|
93
|
+
conf[k] = ERB.new(v).result(binding)
|
94
|
+
else
|
95
|
+
$log.error "Template error #{v.inspect}"
|
96
|
+
$log.error_backtrace
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def log(string)
|
102
|
+
$log.info "out_router: " + string
|
103
|
+
end
|
104
|
+
|
105
|
+
# This is the reaper that is used to avoids resource leaks
|
106
|
+
# It will stop any active output plugin that does not get any input
|
107
|
+
def run_reaper(now)
|
108
|
+
if now - @last_reaper_run > MIN_REAPER_INTERVAL then
|
109
|
+
@last_used_time.each {|key, stored_time|
|
110
|
+
if now - stored_time > @inactivity_timeout then
|
111
|
+
stop_output(key)
|
112
|
+
end }
|
113
|
+
@last_reaper_run = now
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# ConsistentArrayStorage serializes/deserializes an array to disc.
|
119
|
+
# It uses two files.
|
120
|
+
# First it writes the serialized array into a tmp file and then renames
|
121
|
+
# the tmp file to the correct filename.
|
122
|
+
# The rename action is fast and Linux gives a guarantee that
|
123
|
+
# the rename operation is atomic (on local discs). This removes the risk
|
124
|
+
# of any kind of crash leaving the @store_file file in a bad state.
|
125
|
+
class ConsistentArrayStorage
|
126
|
+
def initialize(filename)
|
127
|
+
@store_file = filename
|
128
|
+
@temp_file = filename + ".tmp"
|
129
|
+
end
|
130
|
+
|
131
|
+
def store(array)
|
132
|
+
file = File.open(@temp_file, 'w')
|
133
|
+
file << array.to_json
|
134
|
+
file.close
|
135
|
+
File.rename(@temp_file, @store_file)
|
136
|
+
end
|
137
|
+
|
138
|
+
#Returns the array stored on disc.
|
139
|
+
#Returns an empty array if the file does not exist
|
140
|
+
def load
|
141
|
+
if File.exists?(@store_file) then
|
142
|
+
file = File.open(@store_file, 'r')
|
143
|
+
json_string = file.read
|
144
|
+
file.close
|
145
|
+
JSON.parse(json_string)
|
146
|
+
else
|
147
|
+
[]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fluent-output-router
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- David Almroth
|
8
|
+
- Torbjörn Norinder
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-08-16 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: fluentd
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ~>
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 0.10.0
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ~>
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 0.10.0
|
28
|
+
description: Depending on the message tag, this fluent plugin can start new instances
|
29
|
+
of any other available output plugins for fluent (for example the fluent-plugin-s3).
|
30
|
+
This way it is possible to have one fluent input get split into separate (s3) output
|
31
|
+
instances. The output instances will be shut down individually when there is no
|
32
|
+
traffic to an instance.
|
33
|
+
email: david@campanja.com
|
34
|
+
executables: []
|
35
|
+
extensions: []
|
36
|
+
extra_rdoc_files: []
|
37
|
+
files:
|
38
|
+
- lib/fluent/plugin/out_router.rb
|
39
|
+
homepage: https://github.com/campanja/fluent-output-router
|
40
|
+
licenses: []
|
41
|
+
metadata: {}
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options: []
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ! '>='
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0'
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
requirements: []
|
57
|
+
rubyforge_project:
|
58
|
+
rubygems_version: 2.0.7
|
59
|
+
signing_key:
|
60
|
+
specification_version: 4
|
61
|
+
summary: Can dynamically route fluentd messages based on the tag content
|
62
|
+
test_files: []
|