franz 2.0.2 → 2.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 +4 -4
- data/VERSION +1 -1
- data/lib/franz/metadata.rb +5 -0
- metadata +17 -22
- data/.gitignore +0 -14
- data/Gemfile +0 -15
- data/History.md +0 -287
- data/Rakefile +0 -32
- data/franz.gemspec +0 -29
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bdc8e2f8a34ec53cc121ba4c3208bcff7c52b496
|
|
4
|
+
data.tar.gz: 8f70dbf552fa97e18f0c435ecf2f05b96bdfdf0d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: aeff8102b0d4635749bfc9751ee01e5dcddb1674635c5130d997800d561c6f955a55575deb015590d2be6586d3bec7ce7d5414504eeb469ec0b251887bffc9d7
|
|
7
|
+
data.tar.gz: 9d9dba062334ea71d64a2be833a061911d3215738e7ff762695e69369f12071600f0a16619f77fffd2472bf51e2d0ba875d28a0a37b2f0bcd4a05b81f53a3206
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.0
|
|
1
|
+
2.1.0
|
data/lib/franz/metadata.rb
CHANGED
|
@@ -20,6 +20,11 @@ module Franz
|
|
|
20
20
|
# Turn here to strangle your dictator
|
|
21
21
|
EMAIL = 'sclemmer@bluejeans.com'
|
|
22
22
|
|
|
23
|
+
# Bundled extensions
|
|
24
|
+
TRAVELING_RUBY_VERSION = '20150210-2.1.5'
|
|
25
|
+
SNAPPY_VERSION = '0.0.11'
|
|
26
|
+
EM_VERSION = '1.0.5'
|
|
27
|
+
|
|
23
28
|
# Every project deserves its own ASCII art
|
|
24
29
|
ART = <<-'EOART' % VERSION
|
|
25
30
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: franz
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.0
|
|
4
|
+
version: 2.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sean Clemmer
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2015-03-
|
|
11
|
+
date: 2015-03-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: slog
|
|
@@ -81,47 +81,47 @@ dependencies:
|
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
82
|
version: 1.0.0
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
|
-
name:
|
|
84
|
+
name: poseidon
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
86
86
|
requirements:
|
|
87
|
-
- -
|
|
87
|
+
- - "~>"
|
|
88
88
|
- !ruby/object:Gem::Version
|
|
89
|
-
version:
|
|
89
|
+
version: 0.0.5
|
|
90
90
|
type: :runtime
|
|
91
91
|
prerelease: false
|
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
93
|
requirements:
|
|
94
|
-
- -
|
|
94
|
+
- - "~>"
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
|
-
version:
|
|
96
|
+
version: 0.0.5
|
|
97
97
|
- !ruby/object:Gem::Dependency
|
|
98
|
-
name:
|
|
98
|
+
name: snappy
|
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
|
100
100
|
requirements:
|
|
101
|
-
- -
|
|
101
|
+
- - '='
|
|
102
102
|
- !ruby/object:Gem::Version
|
|
103
|
-
version: 0.0.
|
|
103
|
+
version: 0.0.11
|
|
104
104
|
type: :runtime
|
|
105
105
|
prerelease: false
|
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
107
|
requirements:
|
|
108
|
-
- -
|
|
108
|
+
- - '='
|
|
109
109
|
- !ruby/object:Gem::Version
|
|
110
|
-
version: 0.0.
|
|
110
|
+
version: 0.0.11
|
|
111
111
|
- !ruby/object:Gem::Dependency
|
|
112
|
-
name:
|
|
112
|
+
name: eventmachine
|
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
|
114
114
|
requirements:
|
|
115
|
-
- -
|
|
115
|
+
- - '='
|
|
116
116
|
- !ruby/object:Gem::Version
|
|
117
|
-
version:
|
|
117
|
+
version: 1.0.5
|
|
118
118
|
type: :runtime
|
|
119
119
|
prerelease: false
|
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
|
121
121
|
requirements:
|
|
122
|
-
- -
|
|
122
|
+
- - '='
|
|
123
123
|
- !ruby/object:Gem::Version
|
|
124
|
-
version:
|
|
124
|
+
version: 1.0.5
|
|
125
125
|
description: Aggregate log file events and send them elsewhere.
|
|
126
126
|
email: sclemmer@bluejeans.com
|
|
127
127
|
executables:
|
|
@@ -129,15 +129,10 @@ executables:
|
|
|
129
129
|
extensions: []
|
|
130
130
|
extra_rdoc_files: []
|
|
131
131
|
files:
|
|
132
|
-
- ".gitignore"
|
|
133
|
-
- Gemfile
|
|
134
|
-
- History.md
|
|
135
132
|
- LICENSE
|
|
136
|
-
- Rakefile
|
|
137
133
|
- Readme.md
|
|
138
134
|
- VERSION
|
|
139
135
|
- bin/franz
|
|
140
|
-
- franz.gemspec
|
|
141
136
|
- lib/franz.rb
|
|
142
137
|
- lib/franz/agg.rb
|
|
143
138
|
- lib/franz/config.rb
|
data/.gitignore
DELETED
data/Gemfile
DELETED
data/History.md
DELETED
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
# Franz
|
|
2
|
-
|
|
3
|
-
Hi there, your old pal Sean Clemmer here. Imma talk quite a lot, so we might as
|
|
4
|
-
well get acquainted. I work on the Operations team at Blue Jeans Network, an
|
|
5
|
-
enterprise videoconferencing provider based in Mountain View, CA. Our team
|
|
6
|
-
provides infrastructure, tools, and support to the Engineering team, including,
|
|
7
|
-
most importantly for our purposes, log storage and processing.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
## A lil History
|
|
11
|
-
|
|
12
|
-
Before the latest rearchitecture, logs at Blue Jeans were basically `rsync`ed
|
|
13
|
-
from every host to a central log server. Once on the box, a few processes came
|
|
14
|
-
afterwards to compress the files and scan for meeting identifiers. Our reporting
|
|
15
|
-
tools queried the log server with a meeting ID, and it replied with a list of
|
|
16
|
-
files and their location.
|
|
17
|
-
|
|
18
|
-
Compression saved a lot of space, and the search index was fairly small, since
|
|
19
|
-
we only needed to store a map of meeting IDs to file paths. If you wanted to
|
|
20
|
-
search the text, you need to log into the log server itself and `grep`.
|
|
21
|
-
|
|
22
|
-
And all of that worked for everyone until a point. At a certain number of files,
|
|
23
|
-
`grep` just wasn't fast enough, and worse, it was stealing resources necessary
|
|
24
|
-
for processing logs. At a certain volume, we just couldn't scan the logs fast
|
|
25
|
-
enough. Our scripts were getting harder to maintain, and we were looking for
|
|
26
|
-
answers sooner rather than later.
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
### Exploring our options
|
|
30
|
-
|
|
31
|
-
We did a fair amount of research and fiddling before deciding anything. We
|
|
32
|
-
looked especially hard at the Elasticsearch-Logstash-Kibana (ELK) stack,
|
|
33
|
-
Graylog2, and rearchitecting our scripts as a distributed system. In the end,
|
|
34
|
-
we decided we weren't smart enough and there wasn't enough time to design our
|
|
35
|
-
own system from the ground up. We also found Graylog2 to be a bit immature and
|
|
36
|
-
lacking in features compared to the ELK stack.
|
|
37
|
-
|
|
38
|
-
In the end, we appreciated the ELK stack had a lot of community and corporate
|
|
39
|
-
support, it was easy to get started, and everything was fairly well-documented.
|
|
40
|
-
Elasticsearch in particular seemed like a well-architected and professional
|
|
41
|
-
software project. Logstash had an active development community, and the author
|
|
42
|
-
Jordan Sissel soon joined Elasticsearch, Inc. as an employee.
|
|
43
|
-
|
|
44
|
-
There was a lot of hype around ELK, and I thought we could make it work.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
### Our requirements
|
|
48
|
-
|
|
49
|
-
If you'll recall, the old system was really geared to look up log files based
|
|
50
|
-
on a special meeting ID. Quick, but no real search.
|
|
51
|
-
|
|
52
|
-
To emulate this with Elasticsearch we might store the whole file in a document
|
|
53
|
-
along with the meeting ID, which would make queries straightforward. A more
|
|
54
|
-
common approach in the ELK community is to store individual lines of a log file
|
|
55
|
-
in Elasticsearch documents. I figured we could get the file back by asking the
|
|
56
|
-
Elasticsearch cluster for an aggregation of documents corresponding to a given
|
|
57
|
-
file path on a given host.
|
|
58
|
-
|
|
59
|
-
To prove it to I slapped a couple scripts together, although the initial
|
|
60
|
-
implementation actually used *facets* and not *aggregations*. If we could get
|
|
61
|
-
the file back, that was everything we needed; we got advanced query support with
|
|
62
|
-
Elasticsearch and visualization with Kibana for free. Logstash was making it
|
|
63
|
-
easy for me to play around. Fun, even.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
### Moving forward with ELK
|
|
67
|
-
|
|
68
|
-
I got to reading about the pipelines, and I realized pretty quick we were't
|
|
69
|
-
just gonna be able to hook Logstash right into Elasticsearch. You should put
|
|
70
|
-
a kind of buffer inbetween, and both RabbitMQ and Redis were popular at the
|
|
71
|
-
time. While I was developing our solution, alternative "forwarders" like
|
|
72
|
-
Lumberjack were just being introduced. After evaluating our options, I decided
|
|
73
|
-
on RabbitMQ based on team experience and the native Logstash support.
|
|
74
|
-
|
|
75
|
-
So the initial pipeline looked like this:
|
|
76
|
-
|
|
77
|
-
Logstash -> RabbitMQ -> Logstash -> Elasticsearch <- Kibana
|
|
78
|
-
|
|
79
|
-
The first Logstash stage picked up logs with the `file` input and shipped them
|
|
80
|
-
out with the `rabbitmq` output. These log *events* sat in RabbitMQ until a
|
|
81
|
-
second, dedicated Logstash agent came along to parse it and shove it into
|
|
82
|
-
Elasticsearch for long-term storage and search. I slapped Kibana on top to
|
|
83
|
-
provide our users a usable window into the cluster.
|
|
84
|
-
|
|
85
|
-
And it all *kinda* worked. It wasn't very fast, and outages were fairly common,
|
|
86
|
-
but the all pieces were on the board. Over a few weeks I tuned and expanded the
|
|
87
|
-
RabbitMQ and Elasticsearch clusters, but still we were missing chunks of files,
|
|
88
|
-
missing whole files, and Logstash would die regularly with all kinds of strange
|
|
89
|
-
issues. Encoding issues, buffer issues, timeout issues, heap size issues.
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
### Fighting with Logstash
|
|
93
|
-
|
|
94
|
-
Surely we weren't the only people running into issues with this very popular
|
|
95
|
-
piece of open source software? Logstash has a GitHub project, a JIRA account,
|
|
96
|
-
and an active mailing list. I scoured issues, source code, pull requests, and
|
|
97
|
-
e-mail archives. These seemed like huge bugs:
|
|
98
|
-
|
|
99
|
-
1. *Multiline:* Both the multiline codec and filter had their issues. The codec
|
|
100
|
-
is generally preffered, but even still you might miss the last line of your
|
|
101
|
-
file, because Logstash does not implement *multiline flush*. Logstash will
|
|
102
|
-
buffer the last line of a file indefinitely, thinking you may come back and
|
|
103
|
-
write to the log.
|
|
104
|
-
2. *File handling:* Because Logstash keeps files open indefinitely, it can soak
|
|
105
|
-
up file handles after running a while. We had tens of thousands of log files
|
|
106
|
-
on some hosts, and Logstash just wasn't having it.
|
|
107
|
-
3. *Reconstruction:* Despite my initial proofs, we were having a lot of trouble
|
|
108
|
-
reconstructing log files from individual events. Lines were often missing,
|
|
109
|
-
truncated, and shuffled.
|
|
110
|
-
|
|
111
|
-
The multiline issue was actually fixed by the community, so I forked Logstash,
|
|
112
|
-
applied some patches, and did a little hacking to get it working right.
|
|
113
|
-
|
|
114
|
-
Fixing the second issue required delving deep into the depths of Logstash, the
|
|
115
|
-
`file` input, and Jordan Sissel's FileWatch project. FileWatch provides most of
|
|
116
|
-
the implementation for the `file` input, but it was riddled with bugs. I forked
|
|
117
|
-
the project and went through a major refactor to simplify and sanitize the code.
|
|
118
|
-
Eventually I was able to make it so Logstash would relinquish a file handle
|
|
119
|
-
some short interval after reading the file had ceased.
|
|
120
|
-
|
|
121
|
-
The third issue was rather more difficult. Subtle bugs at play. Rather than
|
|
122
|
-
relying on the `@timestamp` field, which we found did not have enough
|
|
123
|
-
resolution, I added a new field called `@seq`, just a simple counter, which
|
|
124
|
-
enabled us to put the events back in order. Still we were missing chunks, and
|
|
125
|
-
some lines appeared to be interleaved. Just weird stuff.
|
|
126
|
-
|
|
127
|
-
After hacking Logstash half to death we decided the first stage of the pipeline
|
|
128
|
-
would have to change. We'd still use Logstash to move events from RabbitMQ into
|
|
129
|
-
Elasticsearch, but we couldn't trust it to collect files.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
### And so Franz was born
|
|
133
|
-
|
|
134
|
-
I researched Logstash alternatives, but there weren't many at the time. Fluentd
|
|
135
|
-
looked promising, but early testing revealed the multiline facility wasn't quite
|
|
136
|
-
there yet. Lumberjack was just gaining some popularity, but it was still too
|
|
137
|
-
immature. In the end, I decided I had a pretty good handle on our requirements
|
|
138
|
-
and I would take a stab at implementing a solution.
|
|
139
|
-
|
|
140
|
-
It would be risky, but Logstash and the community just weren't moving fast
|
|
141
|
-
enough for our needs. Engineering was justly upset with our logging "solution",
|
|
142
|
-
and I was pretty frantic after weeks of hacking and debugging. How hard could
|
|
143
|
-
it really be to tail a file and send the lines out to a queue?
|
|
144
|
-
|
|
145
|
-
After a few prototypes and a couple false starts, we had our boy Franz.
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
## Design and Implementation
|
|
150
|
-
|
|
151
|
-
From 10,000 feet Franz and Logstash are pretty similar; you can imagine Franz is
|
|
152
|
-
basically a Logstash agent configured with a `file` input and `rabbitmq` output.
|
|
153
|
-
Franz accepts a single configuration file that tells the process which files to
|
|
154
|
-
tail, how to handle them, and where to send the output. Besides solving the
|
|
155
|
-
three issues we discussed earlier, Franz provides a kind of `json` codec and
|
|
156
|
-
`drop` filter (in Logstash parlance).
|
|
157
|
-
|
|
158
|
-
I decided early on to implement Franz in Ruby, like Logstash. Unlike Logstash,
|
|
159
|
-
which is typically executed by JRuby, I decided to stick with Mat'z Ruby for
|
|
160
|
-
Franz in order to obtain a lower resource footprint at the expense of true
|
|
161
|
-
concurrency (MRI has a GIL).
|
|
162
|
-
|
|
163
|
-
Implementation-wise, Franz bears little resemblance to Logstash. Logstash has
|
|
164
|
-
a clever system which "compiles" the inputs, filters, and outputs into a single
|
|
165
|
-
block of code. Franz is a fairly straightward Ruby program with only a handful
|
|
166
|
-
of classes and a simple execution path.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
### The Twelve-Factor App
|
|
170
|
-
|
|
171
|
-
I was heavily influenced by [the Twelve-Factor App](http://12factor.net):
|
|
172
|
-
|
|
173
|
-
1. *Codebase:* Franz is contained in a single repo on [GitHub](https://github.com/sczizzo/franz).
|
|
174
|
-
2. *Dependencies:* Franz provides a `Gemfile` to isolate dependencies.
|
|
175
|
-
3. *Config:* Franz separates code from configuration (no env vars, though).
|
|
176
|
-
4. *Backing Services:* Franz is agnostic to the connected RabbitMQ server.
|
|
177
|
-
5. *Build, release, run:* Franz is versioned and released as a [RubyGem](https://rubygems.org/gems/franz).
|
|
178
|
-
6. *Processes:* Franz provides mostly-stateless share-nothing executions.
|
|
179
|
-
7. *Port binding:* Franz isn't a Web service, so no worries here!
|
|
180
|
-
8. *Concurrency:* Franz is a single process and plays nice with Upstart.
|
|
181
|
-
9. *Disposability:* Franz uses a crash-only architecture, discussed below.
|
|
182
|
-
10. *Dev/prod parity:* We run the same configuration in every environment.
|
|
183
|
-
11. *Logs:* Franz provides structured logs which can be routed to file.
|
|
184
|
-
12. *Admin processes:* Franz is simple enough this isn't necessary.
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
### Crash-Only Architecture
|
|
188
|
-
|
|
189
|
-
Logstash assumes you might want to stop the process and restart it later, having
|
|
190
|
-
the new instance pick up where the last left off. To support this, Logstash (or
|
|
191
|
-
really, FileWatch) keeps a small "checkpoint" file, which is written whenever
|
|
192
|
-
Logstash is shut down.
|
|
193
|
-
|
|
194
|
-
Franz takes this one step further and implements a ["crash-only" design](http://lwn.net/Articles/191059).
|
|
195
|
-
The basic idea here the application does not distinguish between a crash and
|
|
196
|
-
a restart. In practical terms, Franz simply writes a checkpoint at regular
|
|
197
|
-
intervals; when asked to shut down, it aborts immediately.
|
|
198
|
-
|
|
199
|
-
Franz checkpoints are simple, too. It's just a `Hash` from log file paths to
|
|
200
|
-
the current `cursor` (byte offset) and `seq` (sequence number):
|
|
201
|
-
|
|
202
|
-
{
|
|
203
|
-
"/path/to/my.log": {
|
|
204
|
-
"cursor": 1234,
|
|
205
|
-
"seq": 99
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
The checkpoint file contains the `Marshal` representation of this `Hash`.
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
### Sash
|
|
213
|
-
|
|
214
|
-
The `Sash` is a data structure I discovered during the development of Franz,
|
|
215
|
-
which came out of the implementation of multiline flush. Here's a taste:
|
|
216
|
-
|
|
217
|
-
s = Sash.new # => #<Sash...>
|
|
218
|
-
s.keys # => []
|
|
219
|
-
s.insert :key, :value # => :value
|
|
220
|
-
s.get :key # => [ :value ]
|
|
221
|
-
s.insert :key, :crazy # => :crazy
|
|
222
|
-
s.mtime :key # => 2014-02-18 21:24:30 -0800
|
|
223
|
-
s.flush :key # => [ :value, :crazy ]
|
|
224
|
-
|
|
225
|
-
For multilining, what you do is create a `Sash` keyed by each path, and insert
|
|
226
|
-
each line in the appropriate key as they come in from upstream. Before you
|
|
227
|
-
insert it, though, you check if the line in question matches the multiline
|
|
228
|
-
pattern for the key: If so, you flush the `Sash` key and write the result out as
|
|
229
|
-
an event. Now the `Sash` key will buffer the next event.
|
|
230
|
-
|
|
231
|
-
In fact, a `Sash` key will only ever contain lines for at most one event, and
|
|
232
|
-
the `mtime` method allows us to know how recently that key was modified. To
|
|
233
|
-
implement multiline flush correctly, we periodically check the `Sash` for old
|
|
234
|
-
keys and flush them according to configuration. `Sash` methods are threadsafe,
|
|
235
|
-
so we can do this on the side without interrupting the main thread.
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
### Slog
|
|
239
|
-
|
|
240
|
-
[Slog](https://github.com/sczizzo/slog) was also factored out of Franz, but
|
|
241
|
-
it's heavily inspired by Logstash. By default, output is pretty and colored (I
|
|
242
|
-
swear):
|
|
243
|
-
|
|
244
|
-
Slog.new.info 'example'
|
|
245
|
-
#
|
|
246
|
-
# {
|
|
247
|
-
# "level": "info",
|
|
248
|
-
# "@timestamp": "2014-12-25T06:22:43.459-08:00",
|
|
249
|
-
# "message": "example"
|
|
250
|
-
# }
|
|
251
|
-
#
|
|
252
|
-
|
|
253
|
-
`Slog` works perfectly with Logstash or Franz when configured to treat the log
|
|
254
|
-
file as JSON; they'll add the other fields necessary for reconstruction.
|
|
255
|
-
|
|
256
|
-
More than anything, structured logging has changed how I approach logs. Instead
|
|
257
|
-
of writing *everything* to file, Franz strives to log useful events that contain
|
|
258
|
-
metadata. Instead of every request, an occasional digest. Instead of a paragraph
|
|
259
|
-
of text, a simple summary. Franz uses different log levels appropriately,
|
|
260
|
-
allowing end users to control verbosity.
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
### Execution Path
|
|
264
|
-
|
|
265
|
-
Franz is implemented as a series of stages connected via bounded queues:
|
|
266
|
-
|
|
267
|
-
Input -> Discover -> Watch -> Tail -> Agg -> Output
|
|
268
|
-
|
|
269
|
-
Each of these stages is a class under the `Franz` namespace, and they run up
|
|
270
|
-
to a couple `Thread`s, typically a worker and maybe a helper (e.g. multiline
|
|
271
|
-
flush). Communicating via `SizedQueue`s helps ensure correctness and constrain
|
|
272
|
-
memory usage under high load.
|
|
273
|
-
|
|
274
|
-
0. `Input`: Actually wires together `Discover`, `Watch`, `Tail`, and `Agg`.
|
|
275
|
-
1. `Discover`: Performs half of file existence detection by expanding globs and
|
|
276
|
-
keeping track of files known to Franz.
|
|
277
|
-
2. `Watch`: Works in tandem with `Discover` to maintain a list of known files and
|
|
278
|
-
their status. Events are generated when a file is created, destroyed, or
|
|
279
|
-
modified (including appended, truncated, and replaced).
|
|
280
|
-
3. `Tail`: Receives low-level file events from a `Watch` and handles the actual
|
|
281
|
-
reading of files, providing a stream of lines.
|
|
282
|
-
4. `Agg`: Mostly aggregates `Tail` events by applying the multiline filter, but it
|
|
283
|
-
also applies the `host` and `type` fields. Basically, it does all the post
|
|
284
|
-
processing after we've retreived a line from a file.
|
|
285
|
-
5. `Output`: RabbitMQ output for Franz, based on the really-very-good [Bunny](https://github.com/ruby-amqp/bunny)
|
|
286
|
-
client. You must declare an `x-consistent-hash` exchange, as we generate a
|
|
287
|
-
random `Integer` for routing. Such is life.
|
data/Rakefile
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
require 'rubygems'
|
|
2
|
-
require 'bundler'
|
|
3
|
-
require 'rake'
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
require 'rake/testtask'
|
|
7
|
-
Rake::TestTask.new(:test) do |test|
|
|
8
|
-
test.libs << 'lib' << 'test'
|
|
9
|
-
test.test_files = FileList['test/test*.rb']
|
|
10
|
-
test.verbose = true
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
task :default => :test
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
require 'yard'
|
|
17
|
-
YARD::Rake::YardocTask.new do |t|
|
|
18
|
-
t.files = %w[ --readme Readme.md lib/**/*.rb - VERSION ]
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
require 'rubygems/tasks'
|
|
23
|
-
Gem::Tasks.new({
|
|
24
|
-
sign: {}
|
|
25
|
-
}) do |tasks|
|
|
26
|
-
tasks.console.command = 'pry'
|
|
27
|
-
end
|
|
28
|
-
Gem::Tasks::Sign::Checksum.new sha2: true
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
require 'rake/version_task'
|
|
32
|
-
Rake::VersionTask.new
|
data/franz.gemspec
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
|
-
$:.push File.expand_path(File.join('..', 'lib'), __FILE__)
|
|
3
|
-
require 'franz/metadata'
|
|
4
|
-
|
|
5
|
-
Gem::Specification.new do |s|
|
|
6
|
-
s.name = 'franz'
|
|
7
|
-
s.version = Franz::VERSION
|
|
8
|
-
s.platform = Gem::Platform::RUBY
|
|
9
|
-
s.license = Franz::LICENSE
|
|
10
|
-
s.homepage = Franz::HOMEPAGE
|
|
11
|
-
s.author = Franz::AUTHOR
|
|
12
|
-
s.email = Franz::EMAIL
|
|
13
|
-
s.summary = Franz::SUMMARY
|
|
14
|
-
s.description = Franz::SUMMARY + '.'
|
|
15
|
-
|
|
16
|
-
s.add_runtime_dependency 'slog', '~> 1.1.0'
|
|
17
|
-
s.add_runtime_dependency 'bunny', '~> 1.6.0'
|
|
18
|
-
s.add_runtime_dependency 'trollop', '~> 2.1.0'
|
|
19
|
-
s.add_runtime_dependency 'colorize', '~> 0.7.0'
|
|
20
|
-
s.add_runtime_dependency 'deep_merge', '~> 1.0.0'
|
|
21
|
-
s.add_runtime_dependency 'eventmachine', '= 1.0.5'
|
|
22
|
-
s.add_runtime_dependency 'poseidon', '~> 0.0.5'
|
|
23
|
-
s.add_runtime_dependency 'snappy', '~> 0.0.11'
|
|
24
|
-
|
|
25
|
-
s.files = `git ls-files`.split("\n")
|
|
26
|
-
s.test_files = `git ls-files -- test/*`.split("\n")
|
|
27
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File::basename(f) }
|
|
28
|
-
s.require_paths = %w[ lib ]
|
|
29
|
-
end
|