fluent-plugin-querycombiner 0.0.1 → 0.0.2
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 +4 -4
- data/README.md +49 -6
- data/fluent-plugin-querycombiner.gemspec +1 -1
- data/lib/fluent/plugin/out_query_combiner.rb +38 -2
- data/test/plugin/test_out_query_combiner.rb +93 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1124703306d418f033d3ff5127b918532e8b3930
|
4
|
+
data.tar.gz: df04cbd16f7465ec26fe3acadffa687163da88b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 82d7aef42eacf95e1f3282205e872523d9f00f742c606820e51358d3710966a76e5a640223a707facea22d18d24bb7e384c7e4c2b9dc9b701d2931b412ab9af2
|
7
|
+
data.tar.gz: 26a39c63fb7b00e9e143485ed820739417b27fa99b7f424e6f40f95251d710622228cf2c0afe68c58dd465c1affa3115b4d0835c27484ebe0746484738b7a4dc
|
data/README.md
CHANGED
@@ -78,7 +78,7 @@ Combined results will be:
|
|
78
78
|
|
79
79
|
### Replace some field names
|
80
80
|
|
81
|
-
If messages has the same fields, these are overwritten in the combination process. You can use `replace` sentence in `<catch>` and `<dump>` blocks to avoid
|
81
|
+
If messages has the same fields, these are overwritten in the combination process. You can use `replace` sentence in `<catch>` and `<dump>` blocks to avoid overwriting such fields.
|
82
82
|
|
83
83
|
For example, you have some event messages like:
|
84
84
|
|
@@ -113,7 +113,6 @@ You can keep `time` fields which defined both `event-start` and `event-finish` b
|
|
113
113
|
<catch>
|
114
114
|
condition status == 'event-start'
|
115
115
|
replace time => time_start
|
116
|
-
|
117
116
|
</catch>
|
118
117
|
|
119
118
|
<dump>
|
@@ -135,6 +134,15 @@ Combined results will be:
|
|
135
134
|
}
|
136
135
|
```
|
137
136
|
|
137
|
+
You can also replace multiple fields joined by comma(`,`):
|
138
|
+
|
139
|
+
```
|
140
|
+
<catch>
|
141
|
+
condition status == 'event-start'
|
142
|
+
replace time => time_start, condition => condition_start
|
143
|
+
</catch>
|
144
|
+
```
|
145
|
+
|
138
146
|
### \<release\> block
|
139
147
|
|
140
148
|
In previous examples, messages with `"status": "event-start"` will be watched by plugin immediately.
|
@@ -166,7 +174,7 @@ You cannot use `replace` sentence in the `<release>` block.
|
|
166
174
|
|
167
175
|
### \<prolong\> block
|
168
176
|
|
169
|
-
Suppose your `query_ttl` is **600** (10 minutes) and almost events are finished within **10 minutes**. But occasionally very-long events occur which finish about **1
|
177
|
+
Suppose your `query_ttl` is **600** (10 minutes) and almost events are finished within **10 minutes**. But occasionally very-long events occur which finish about **1 hour**. These very-long events send `status: 'event-continue'` messages every 5 minutes for keep-alive.
|
170
178
|
|
171
179
|
In this case you can use `<prolong>` block to reset expired time.
|
172
180
|
|
@@ -180,6 +188,34 @@ You cannot use `replace` sentence in the `<prolong>` block.
|
|
180
188
|
|
181
189
|
Also you cannot combine messages which defined `<prolong>` blocks.
|
182
190
|
|
191
|
+
### Record time of the event
|
192
|
+
|
193
|
+
If you combine events, time of the events will be lost except defined in `<dump>` block.
|
194
|
+
|
195
|
+
If you want record time of the event, you can define `time` sentence in `<catch>` and `<dump>` blocks.
|
196
|
+
|
197
|
+
For example, if you configure your fluentd configuration like below,
|
198
|
+
|
199
|
+
```
|
200
|
+
<catch>
|
201
|
+
condition status == 'event-start'
|
202
|
+
replace time => time_start, condition => condition_start
|
203
|
+
time time-catch
|
204
|
+
</catch>
|
205
|
+
```
|
206
|
+
|
207
|
+
you can record time in `time-catch` field in the result.
|
208
|
+
|
209
|
+
```
|
210
|
+
{
|
211
|
+
"event_id": "01234567",
|
212
|
+
"status": "event-finish",
|
213
|
+
"time-catch": 1414715801.112015,
|
214
|
+
}
|
215
|
+
```
|
216
|
+
|
217
|
+
You can set time formats by `time_format` configuration.
|
218
|
+
|
183
219
|
|
184
220
|
## Configuration
|
185
221
|
|
@@ -193,7 +229,7 @@ The basic information for connecting to Redis. By default it's **redis://127.0.0
|
|
193
229
|
How many times should the plugin retry when performing a redis operation before raising a error.
|
194
230
|
By default it's 3.
|
195
231
|
|
196
|
-
###
|
232
|
+
### query_ttl
|
197
233
|
The inactive expire time in seconds. By default it's **1800** (30 minutes).
|
198
234
|
|
199
235
|
### buffer_size
|
@@ -202,7 +238,6 @@ The max queries to store in redis. By default it's **1000**.
|
|
202
238
|
### remove_interval
|
203
239
|
The interval time to delete expired or overflowed queries which configured by `query_ttl` and `buffer_size`. By default it's 10 [sec].
|
204
240
|
|
205
|
-
|
206
241
|
### redis_key_prefix
|
207
242
|
|
208
243
|
The key prefix for data stored in Redis. By default it's `query_combiner:`.
|
@@ -212,11 +247,19 @@ The key prefix for data stored in Redis. By default it's `query_combiner:`.
|
|
212
247
|
Indicates how to extract the query identity from event record.
|
213
248
|
It can be set as a single field name or multiple field names join by comma (`,`).
|
214
249
|
|
250
|
+
### time_format
|
251
|
+
|
252
|
+
The time format for recording time of the events. Default is `$time` which holds event time. You can also use [Ruby's Time module](http://www.ruby-doc.org/core/Time.html).
|
253
|
+
If you want write ISO8601 format (e.g. `2014-10-31T09:32:57+09:00`), you can configure like below.
|
254
|
+
|
255
|
+
```
|
256
|
+
time_format Time.at($time).iso8601
|
257
|
+
```
|
258
|
+
|
215
259
|
|
216
260
|
## TODO
|
217
261
|
|
218
262
|
- Multi-query combination
|
219
|
-
- Support hyphen `-` and dollar `$` contained field names
|
220
263
|
|
221
264
|
|
222
265
|
## Copyright
|
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |spec|
|
5
5
|
spec.name = "fluent-plugin-querycombiner"
|
6
|
-
spec.version = "0.0.
|
6
|
+
spec.version = "0.0.2"
|
7
7
|
spec.authors = ["Takahiro Kamatani"]
|
8
8
|
spec.email = ["buhii314@gmail.com"]
|
9
9
|
spec.description = %q{Fluent plugin to combine multiple queries.}
|
@@ -14,6 +14,8 @@ module Fluent
|
|
14
14
|
config_param :query_ttl, :integer, :default => 1800
|
15
15
|
config_param :buffer_size, :integer, :default => 1000
|
16
16
|
|
17
|
+
config_param :time_format, :string, :default => '$time'
|
18
|
+
|
17
19
|
config_param :flush_interval, :integer, :default => 60
|
18
20
|
config_param :remove_interval, :integer, :default => 10
|
19
21
|
config_param :tag, :string, :default => "query_combiner"
|
@@ -24,6 +26,7 @@ module Fluent
|
|
24
26
|
require 'msgpack'
|
25
27
|
require 'json'
|
26
28
|
require 'rubygems'
|
29
|
+
require 'time'
|
27
30
|
end
|
28
31
|
|
29
32
|
def configure(conf)
|
@@ -34,6 +37,19 @@ module Fluent
|
|
34
37
|
|
35
38
|
@query_identify = @query_identify.split(',').map { |qid| qid.strip }
|
36
39
|
|
40
|
+
# functions for time format
|
41
|
+
def create_time_formatter(expr)
|
42
|
+
begin
|
43
|
+
f = eval('lambda {|__arg_time__| ' + expr.gsub("$time", "__arg_time__") + '}')
|
44
|
+
return f
|
45
|
+
rescue SyntaxError
|
46
|
+
raise Fluent::ConfigError, "SyntaxError at time_format `#{expr}`"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
@_time_formatter = create_time_formatter(@time_format)
|
50
|
+
|
51
|
+
@_time_keys = {}
|
52
|
+
|
37
53
|
# Create functions for each conditions
|
38
54
|
@_cond_funcs = {}
|
39
55
|
@_replace_keys = {
|
@@ -88,6 +104,16 @@ module Fluent
|
|
88
104
|
else
|
89
105
|
raise Fluent::ConfigError, "`replace` configuration in #{element.name}: only allowed in `catch` and `dump`"
|
90
106
|
end
|
107
|
+
|
108
|
+
elsif var == 'time'
|
109
|
+
if %w{catch dump}.include? element.name
|
110
|
+
@_time_keys[element.name] = expr
|
111
|
+
else
|
112
|
+
raise Fluent::ConfigError, "`time` configuration in #{element.name}: only allowed in `catch` and `dump`"
|
113
|
+
end
|
114
|
+
|
115
|
+
else
|
116
|
+
raise Fluent::ConfigError, "Unknown configuration `#{var}` in #{element.name}"
|
91
117
|
end
|
92
118
|
}
|
93
119
|
}
|
@@ -164,6 +190,11 @@ module Fluent
|
|
164
190
|
record[after] = record[before]
|
165
191
|
record.delete(before)
|
166
192
|
}
|
193
|
+
# add time key if configured
|
194
|
+
if @_time_keys.has_key? 'catch'
|
195
|
+
record[@_time_keys['catch']] = @_time_formatter.call(time)
|
196
|
+
end
|
197
|
+
|
167
198
|
# save record
|
168
199
|
tryOnRedis 'set', @redis_key_prefix + qid, JSON.dump(record)
|
169
200
|
# update qid's timestamp
|
@@ -179,7 +210,7 @@ module Fluent
|
|
179
210
|
end
|
180
211
|
end
|
181
212
|
|
182
|
-
def do_dump(qid, record)
|
213
|
+
def do_dump(qid, record, time)
|
183
214
|
if (tryOnRedis 'exists', @redis_key_prefix + qid)
|
184
215
|
# replace record keys
|
185
216
|
@_replace_keys['dump'].each_pair { |before, after|
|
@@ -187,6 +218,11 @@ module Fluent
|
|
187
218
|
record.delete(before)
|
188
219
|
}
|
189
220
|
|
221
|
+
# add time key if configured
|
222
|
+
if @_time_keys.has_key? 'dump'
|
223
|
+
record[@_time_keys['dump']] = @_time_formatter.call(time)
|
224
|
+
end
|
225
|
+
|
190
226
|
# emit
|
191
227
|
catched_record = JSON.load(tryOnRedis('get', @redis_key_prefix + qid))
|
192
228
|
combined_record = catched_record.merge(record)
|
@@ -229,7 +265,7 @@ module Fluent
|
|
229
265
|
when "prolong"
|
230
266
|
do_prolong(qid, time)
|
231
267
|
when "dump"
|
232
|
-
do_dump(qid, record)
|
268
|
+
do_dump(qid, record, time)
|
233
269
|
when "release"
|
234
270
|
do_release(qid)
|
235
271
|
end
|
@@ -81,6 +81,27 @@ class QueryCombinerOutputTest < Test::Unit::TestCase
|
|
81
81
|
]
|
82
82
|
}
|
83
83
|
|
84
|
+
# `time` configuration only allowed in <catch> and <dump>
|
85
|
+
assert_raise(Fluent::ConfigError) {
|
86
|
+
d = create_driver %[
|
87
|
+
query_identify event_id
|
88
|
+
<catch>
|
89
|
+
condition status == 'start'
|
90
|
+
replace hoge => hoge_start
|
91
|
+
time time_catch
|
92
|
+
</catch>
|
93
|
+
<release>
|
94
|
+
condition status == 'error'
|
95
|
+
time time_release
|
96
|
+
</release>
|
97
|
+
<dump>
|
98
|
+
condition status == 'finish'
|
99
|
+
replace hoge => hoge_finish
|
100
|
+
time time_dump
|
101
|
+
</dump>
|
102
|
+
]
|
103
|
+
}
|
104
|
+
|
84
105
|
end
|
85
106
|
|
86
107
|
def test_readme_sample_basic_example
|
@@ -137,6 +158,36 @@ class QueryCombinerOutputTest < Test::Unit::TestCase
|
|
137
158
|
"time_finish"=>"2001-02-03T04:15:11Z"}
|
138
159
|
end
|
139
160
|
|
161
|
+
def test_readme_sample_replace_multiple_fields
|
162
|
+
d = create_driver %[
|
163
|
+
query_identify event_id
|
164
|
+
query_ttl 3600 # time to live[sec]
|
165
|
+
buffer_size 1000 # queries
|
166
|
+
|
167
|
+
<catch>
|
168
|
+
condition status == 'event-start'
|
169
|
+
replace time => time_start, condition => condition_start
|
170
|
+
</catch>
|
171
|
+
|
172
|
+
<dump>
|
173
|
+
condition status == 'event-finish'
|
174
|
+
replace time => time_finish, condition => condition_end
|
175
|
+
</dump>
|
176
|
+
]
|
177
|
+
time = Time.now.to_i
|
178
|
+
d.emit({"event_id"=>"01234567", "status"=>"event-start", "time"=>"2001-02-03T04:05:06Z", "condition"=>"bad"}, time)
|
179
|
+
d.emit({"event_id"=>"01234567", "status"=>"event-finish", "time"=>"2001-02-03T04:15:11Z", "condition"=>"excellent"}, time)
|
180
|
+
d.run
|
181
|
+
assert_equal d.emits.length, 1
|
182
|
+
assert_equal d.emits[0][2], {
|
183
|
+
"event_id"=>"01234567",
|
184
|
+
"status"=>"event-finish",
|
185
|
+
"time_start"=>"2001-02-03T04:05:06Z",
|
186
|
+
"condition_start"=>"bad",
|
187
|
+
"time_finish"=>"2001-02-03T04:15:11Z",
|
188
|
+
"condition_end"=>"excellent"}
|
189
|
+
end
|
190
|
+
|
140
191
|
def test_readme_sample_release
|
141
192
|
d = create_driver %[
|
142
193
|
query_identify event_id
|
@@ -317,6 +368,48 @@ class QueryCombinerOutputTest < Test::Unit::TestCase
|
|
317
368
|
assert_equal d.emits.size, finish_list.size
|
318
369
|
end
|
319
370
|
|
371
|
+
def test_time_format_and_configuration
|
372
|
+
d = create_driver %[
|
373
|
+
query_identify event_id
|
374
|
+
query_ttl 3600 # time to live[sec]
|
375
|
+
buffer_size 1000 # queries
|
376
|
+
time_format Time.at($time).iso8601(3)
|
377
|
+
|
378
|
+
<catch>
|
379
|
+
condition status == 'event-start'
|
380
|
+
time time-catch
|
381
|
+
</catch>
|
382
|
+
|
383
|
+
<dump>
|
384
|
+
condition status == 'event-finish'
|
385
|
+
time time-dump
|
386
|
+
</dump>
|
387
|
+
|
388
|
+
<prolong>
|
389
|
+
condition status == 'event-continue'
|
390
|
+
</prolong>
|
391
|
+
|
392
|
+
<release>
|
393
|
+
condition status == 'event-error'
|
394
|
+
</release>
|
395
|
+
]
|
396
|
+
def emit(d, status)
|
397
|
+
d.emit({"event_id"=>"01234567", "status"=>status}, Time.now.to_f)
|
398
|
+
end
|
399
|
+
|
400
|
+
emit(d, "event-start")
|
401
|
+
emit(d, "event-continue")
|
402
|
+
emit(d, "event-continue")
|
403
|
+
emit(d, "event-continue")
|
404
|
+
emit(d, "event-finish")
|
405
|
+
d.run
|
406
|
+
|
407
|
+
assert_equal d.emits.length, 1
|
408
|
+
assert_not_nil d.emits[0][2]['time-catch']
|
409
|
+
assert_not_nil d.emits[0][2]['time-dump']
|
410
|
+
|
411
|
+
end
|
412
|
+
|
320
413
|
def test_buffer_size
|
321
414
|
|
322
415
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-querycombiner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Takahiro Kamatani
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-10-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|