lstash 0.0.6
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/.autotest +2 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +37 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +154 -0
- data/Rakefile +6 -0
- data/bin/lstash +5 -0
- data/lib/lstash/cli.rb +77 -0
- data/lib/lstash/client.rb +94 -0
- data/lib/lstash/query.rb +159 -0
- data/lib/lstash/version.rb +3 -0
- data/lib/lstash.rb +8 -0
- data/lstash.gemspec +35 -0
- data/spec/lstash/cli_spec.rb +107 -0
- data/spec/lstash/client_spec.rb +60 -0
- data/spec/lstash/query_spec.rb +145 -0
- data/spec/lstash_spec.rb +8 -0
- data/spec/spec_helper.rb +33 -0
- metadata +245 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MWVmNzk3MjRlYTIxNjRkMzNiYjliODg1ZTEzZmNkOTJlMDE4ZDA5Ng==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZDRiNGE0ZmZhZTViOGI0YjFmNjU3ZTJjYTAxNWY1Y2Y0MTdhODZkZg==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
N2QyNTU3ZTBiNDRiZDgxMTViNWRhM2RjNTZkZTM5ZmI0M2NiNjkyZTE3YTEy
|
10
|
+
ZjJlNmIxM2YzMTVlM2MxY2JmNDMwNTgyZjcxODRiMGNiNGE0YzI0ZDk5Yjkw
|
11
|
+
NmRlMDA3YWUyOGRlYmNhMjc5NTNlYWEwNDIxOGEyZGVjMzFhNTc=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NTU0ZDk2MTkyMzk4ODgzZjk1YzI3YTIyYTQ5ZmExMGFiYWIxY2JjZWVjNDI0
|
14
|
+
ZjcwMTZlNWMxOTY1NTcyMDhiNWQ2NzhiYmI0YWRjMGY3MTgxM2YwMjZmNDE2
|
15
|
+
ZGI3NDFmMTM4OWI5MmM1ZWZmMGNhZTJkOTg1NDFlMzg5NzYyOTY=
|
data/.autotest
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
lstash
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-1.9.3
|
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
### v0.0.6 / 2014-09-01
|
2
|
+
|
3
|
+
Bug Fixes
|
4
|
+
|
5
|
+
* Pushing version 0.0.5 failed and it was yanked from rubygems.org. Need to push new version 0.0.6.
|
6
|
+
|
7
|
+
### 0.0.5 / 2014-09-01
|
8
|
+
|
9
|
+
Bug Fixes
|
10
|
+
|
11
|
+
* Running as binary didn't load HTTP client properly. Add 'patron' dependency
|
12
|
+
to force loading an appropriate HTTP client.
|
13
|
+
|
14
|
+
### 0.0.4 / 2014-08-29
|
15
|
+
|
16
|
+
Bug Fixes
|
17
|
+
|
18
|
+
* Use .ruby-[version|gemset] to support any ruby environment manager.
|
19
|
+
|
20
|
+
### 0.0.3 / 2014-08-28
|
21
|
+
|
22
|
+
Bug Fixes
|
23
|
+
|
24
|
+
* Run CI on travis-ci.org.
|
25
|
+
* Fixate timezone to assumed timezone for specs.
|
26
|
+
* Run Ruby 2.1.1 instead of 2.1.0.
|
27
|
+
|
28
|
+
### 0.0.2 / 2014-08-28
|
29
|
+
|
30
|
+
Enhancements
|
31
|
+
|
32
|
+
* Updated documentation.
|
33
|
+
* Rename debug option (-v) to (-d).
|
34
|
+
|
35
|
+
### 0.0.1 / 2014-08-28
|
36
|
+
|
37
|
+
Initial release.
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Klaas Jan Wierenga
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
# lstash
|
2
|
+
|
3
|
+
[](https://travis-ci.org/kjwierenga/lstash)
|
4
|
+
|
5
|
+
Lstash is a gem and command line utility to count or grep log messages in a certain time frame from a Logstash Elasticsearch server.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Or install it yourself as:
|
10
|
+
|
11
|
+
$ gem install lstash
|
12
|
+
|
13
|
+
## Running lstash from the command line
|
14
|
+
|
15
|
+
$ lstash
|
16
|
+
Commands:
|
17
|
+
lstash count QUERY # count number of log messages matching the QUERY
|
18
|
+
lstash grep QUERY # grep log messages from Logstash
|
19
|
+
lstash help [COMMAND] # Describe available commands or one specific command
|
20
|
+
|
21
|
+
## The `count` command
|
22
|
+
|
23
|
+
Usage:
|
24
|
+
lstash count QUERY
|
25
|
+
|
26
|
+
Description:
|
27
|
+
Count log messages matching the QUERY from Logstash and output this count to stdout. QUERY can use Apache Lucene query
|
28
|
+
parser syntax.
|
29
|
+
|
30
|
+
Example to count the number of HAProxy log messages in yesterdays month.
|
31
|
+
|
32
|
+
lstash count 'program:haproxy' --from firstday --to today --anchor yesterday
|
33
|
+
|
34
|
+
## The `grep` command
|
35
|
+
|
36
|
+
Usage:
|
37
|
+
lstash grep QUERY
|
38
|
+
|
39
|
+
Description:
|
40
|
+
Grep log messages matching the QUERY from Logstash in ascending timestamp order and output to stdout. QUERY can use Apache Lucene query parser syntax.
|
41
|
+
|
42
|
+
Example to grep HAProxy log messages from the beginning of this month upto now
|
43
|
+
|
44
|
+
lstash grep 'program:haproxy' --from firstday --to now
|
45
|
+
|
46
|
+
## Command line options
|
47
|
+
|
48
|
+
Options:
|
49
|
+
-f, [--from=start of time range] # date/time, 'now', 'today', 'yesterday', or 'firstday'
|
50
|
+
-t, [--to=end of time range] # date/time, 'now', 'today', 'yesterday', or 'firstday'
|
51
|
+
-a, [--anchor=anchor date/time] # used as reference date for firstday
|
52
|
+
-e, [--es-url=Elasticsearch endpoint for Logstash] # or ES_URL environment variable
|
53
|
+
|
54
|
+
All times will be relative to the timezone of the machine on which you are running lstash.
|
55
|
+
|
56
|
+
## Elasticsearch configuration
|
57
|
+
|
58
|
+
By default `lstash` will connnect to Elasticsearch on your localhost as `http://localhost:9200`. To connect
|
59
|
+
to a different server you can set the `ES_URL` environment variable. URL scheme `http` and port `9200` are default
|
60
|
+
and may be omitted.
|
61
|
+
|
62
|
+
Example
|
63
|
+
|
64
|
+
export ES_URL=log.mydomain.com
|
65
|
+
lstash count program:haproxy
|
66
|
+
|
67
|
+
Or
|
68
|
+
|
69
|
+
lstash count program:haproxy --es-url log.mydomain.com
|
70
|
+
|
71
|
+
## Examples
|
72
|
+
|
73
|
+
Count the number of haproxy log messages matching QUERY from Aug 1 at midnight (0:00 am) upto (not including) Aug 2 at midnight (0:00 am).
|
74
|
+
|
75
|
+
lstash count program:haproxy --from "Aug 1" --to "Aug 2"
|
76
|
+
|
77
|
+
Grep all haproxy log messages using for one day (Aug 24 1 0:00 am upto and including Aug 2 23:59).
|
78
|
+
|
79
|
+
lstash grep program:haproxy --from "Aug 1" --to "Aug 2"
|
80
|
+
|
81
|
+
Assuming today is Sep 1 2014. Count all haproxy log messages in the previous month.
|
82
|
+
|
83
|
+
lstash count program:haproxy --anchor yesterday --from firstday --to today -d
|
84
|
+
time range: [2014-08-01 00:00:00 +0200..2014-09-01 00:00:00 +0200]
|
85
|
+
logstash-2014.07.31: 1
|
86
|
+
logstash-2014.08.01: 13
|
87
|
+
logstash-2014.08.02: 14
|
88
|
+
logstash-2014.08.03: 1654
|
89
|
+
logstash-2014.08.04: 6
|
90
|
+
logstash-2014.08.05: 20
|
91
|
+
logstash-2014.08.06: 219
|
92
|
+
logstash-2014.08.07: 32
|
93
|
+
logstash-2014.08.08: 14
|
94
|
+
logstash-2014.08.09: 28
|
95
|
+
logstash-2014.08.10: 799
|
96
|
+
logstash-2014.08.11: 18
|
97
|
+
logstash-2014.08.12: 8
|
98
|
+
logstash-2014.08.13: 23
|
99
|
+
logstash-2014.08.14: 25
|
100
|
+
logstash-2014.08.15: 69
|
101
|
+
logstash-2014.08.16: 19
|
102
|
+
logstash-2014.08.17: 1160
|
103
|
+
logstash-2014.08.18: 284
|
104
|
+
logstash-2014.08.19: 61
|
105
|
+
logstash-2014.08.20: 26
|
106
|
+
logstash-2014.08.21: 16
|
107
|
+
logstash-2014.08.22: 145
|
108
|
+
logstash-2014.08.23: 72
|
109
|
+
logstash-2014.08.24: 792
|
110
|
+
logstash-2014.08.25: 31
|
111
|
+
logstash-2014.08.26: 33
|
112
|
+
logstash-2014.08.27: 51
|
113
|
+
logstash-2014.08.28: 8
|
114
|
+
logstash-2014.08.29: 23
|
115
|
+
logstash-2014.08.30: 25
|
116
|
+
logstash-2014.08.31: 69
|
117
|
+
5633
|
118
|
+
|
119
|
+
## Using lstash as a gem in your project
|
120
|
+
|
121
|
+
Add this line to your application's Gemfile:
|
122
|
+
|
123
|
+
gem 'lstash'
|
124
|
+
|
125
|
+
And then execute:
|
126
|
+
|
127
|
+
$ bundle
|
128
|
+
|
129
|
+
Usage:
|
130
|
+
|
131
|
+
$ bundle console
|
132
|
+
|
133
|
+
# connect to elasticsearch and create the Lstash client
|
134
|
+
elasticsearch = Elasticsearch::Client.new(url: 'log.mydomain.com')
|
135
|
+
client = Lstash::Client.new(elasticsearch)
|
136
|
+
|
137
|
+
# create the query
|
138
|
+
query = Lstash::Query.new('program:haproxy', from: 'today', to: 'now')
|
139
|
+
|
140
|
+
# count
|
141
|
+
client.count(query)
|
142
|
+
|
143
|
+
# grep
|
144
|
+
client.grep(query) do |message|
|
145
|
+
puts message
|
146
|
+
end
|
147
|
+
|
148
|
+
## Contributing
|
149
|
+
|
150
|
+
1. Fork it
|
151
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
152
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
153
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
154
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/lstash
ADDED
data/lib/lstash/cli.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# external dependencies
|
2
|
+
require 'thor'
|
3
|
+
require 'patron' # use Patron HTTP library for optimal performance
|
4
|
+
require 'elasticsearch'
|
5
|
+
|
6
|
+
# local files we need
|
7
|
+
require 'lstash/query'
|
8
|
+
require 'lstash/client'
|
9
|
+
|
10
|
+
module Lstash
|
11
|
+
|
12
|
+
class CLI < Thor
|
13
|
+
|
14
|
+
class_option :from, :banner => 'start of time range', :aliases => '-f', :desc => "date/time, 'now', 'today', 'yesterday', or 'firstday'"
|
15
|
+
class_option :to, :banner => 'end of time range', :aliases => '-t', :desc => "date/time, 'now', 'today', 'yesterday', or 'firstday'"
|
16
|
+
class_option :anchor, :banner => 'anchor date/time', :aliases => '-a', :desc => "used as reference date for firstday"
|
17
|
+
class_option :es_url, :banner => 'Elasticsearch endpoint for Logstash', :aliases => '-e', :desc => "or ES_URL environment variable"
|
18
|
+
class_option :debug, :banner => 'debug log to stderr', :aliases => '-d', :type => :boolean
|
19
|
+
|
20
|
+
long_desc <<-LONGDESC
|
21
|
+
Grep log messages matching the QUERY from Logstash in ascending timestamp order
|
22
|
+
and output to stdout. QUERY can use Apache Lucene query parser syntax.
|
23
|
+
|
24
|
+
Example to grep HAProxy log messages from the beginning of this month upto now
|
25
|
+
|
26
|
+
lstash grep 'program:haproxy' --from firstday --to now
|
27
|
+
LONGDESC
|
28
|
+
desc "grep QUERY", "grep log messages from Logstash"
|
29
|
+
def grep(query_string)
|
30
|
+
run_command(query_string) do |es_client, query|
|
31
|
+
Lstash::Client.new(es_client, options).grep(query) do |message|
|
32
|
+
puts message
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
long_desc <<-LONGDESC
|
38
|
+
Count log messages matching the QUERY from Logstash and output this count to stdout.
|
39
|
+
QUERY can use Apache Lucene query parser syntax.
|
40
|
+
|
41
|
+
Example to count the number of HAProxy log messages in yesterdays month.
|
42
|
+
|
43
|
+
lstash count 'program:haproxy' --from firstday --to today --anchor yesterday
|
44
|
+
LONGDESC
|
45
|
+
desc "count QUERY", "count number of log messages matching the QUERY"
|
46
|
+
def count(query_string)
|
47
|
+
run_command(query_string) do |es_client, query|
|
48
|
+
count = Lstash::Client.new(es_client, options).count(query)
|
49
|
+
puts count
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def run_command(query_string)
|
56
|
+
es_client = ::Elasticsearch::Client.new(
|
57
|
+
url: options[:es_url] || ENV['ES_URL'] || 'localhost',
|
58
|
+
log: !!ENV['DEBUG']
|
59
|
+
)
|
60
|
+
query = Lstash::Query.new(query_string, options)
|
61
|
+
|
62
|
+
yield es_client, query
|
63
|
+
|
64
|
+
rescue Exception => e
|
65
|
+
raise Thor::Error.new(e.message)
|
66
|
+
end
|
67
|
+
|
68
|
+
protected
|
69
|
+
|
70
|
+
# Make sure we exit on failure with an error code
|
71
|
+
def self.exit_on_failure?
|
72
|
+
true
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'date'
|
3
|
+
require 'hashie'
|
4
|
+
|
5
|
+
class NullLogger < Logger
|
6
|
+
def initialize(*args); end
|
7
|
+
def add(*args, &block); end
|
8
|
+
end
|
9
|
+
|
10
|
+
module Lstash
|
11
|
+
|
12
|
+
class Client
|
13
|
+
|
14
|
+
class ConnectionError < StandardError; end
|
15
|
+
|
16
|
+
PER_PAGE = 5000 # best time, lowest resource usage
|
17
|
+
|
18
|
+
def initialize(es_client, options = {})
|
19
|
+
raise ConnectionError, "No elasticsearch client specified" if es_client.nil?
|
20
|
+
|
21
|
+
@es_client = es_client
|
22
|
+
@logger = options[:logger] || (options[:debug] ? debug_logger : NullLogger.new)
|
23
|
+
end
|
24
|
+
|
25
|
+
def count(query)
|
26
|
+
@logger.debug "time range: [%s..%s]" % [query.time_range.from, query.time_range.to]
|
27
|
+
|
28
|
+
count = 0
|
29
|
+
query.indices.each do |index|
|
30
|
+
count += count_messages(index, query)
|
31
|
+
end
|
32
|
+
|
33
|
+
count
|
34
|
+
end
|
35
|
+
|
36
|
+
def grep(query)
|
37
|
+
@logger.debug "time range: [%s..%s]" % [query.time_range.from, query.time_range.to]
|
38
|
+
|
39
|
+
query.indices.each do |index|
|
40
|
+
grep_messages(index, query) do |message|
|
41
|
+
yield message if block_given?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def count_messages(index, query)
|
49
|
+
result = Hashie::Mash.new @es_client.send(:count,
|
50
|
+
index: index,
|
51
|
+
body: query.body[:query]
|
52
|
+
)
|
53
|
+
@logger.debug "count #{index}: #{result['count']} "
|
54
|
+
result['count']
|
55
|
+
end
|
56
|
+
|
57
|
+
def grep_messages(index, query)
|
58
|
+
messages = nil
|
59
|
+
scroll_params = {}
|
60
|
+
offset = 0
|
61
|
+
method = :search
|
62
|
+
while (messages.nil? || messages.count > 0) do
|
63
|
+
result = Hashie::Mash.new @es_client.send(method, {
|
64
|
+
index: index,
|
65
|
+
scroll: '10m',
|
66
|
+
body: query.body.merge(from: offset, size: PER_PAGE),
|
67
|
+
}.merge(scroll_params))
|
68
|
+
|
69
|
+
messages = result.hits.hits
|
70
|
+
|
71
|
+
offset += messages.count
|
72
|
+
scroll_params = {scroll_id: result._scroll_id}
|
73
|
+
|
74
|
+
messages.each do |h|
|
75
|
+
yield h._source.message if block_given?
|
76
|
+
end
|
77
|
+
|
78
|
+
method = :scroll
|
79
|
+
end
|
80
|
+
@logger.debug "grep #{index}: #{offset}"
|
81
|
+
Hashie::Mash.new @es_client.clear_scroll(scroll_params)
|
82
|
+
end
|
83
|
+
|
84
|
+
def debug_logger
|
85
|
+
logger = Logger.new(STDERR)
|
86
|
+
logger.formatter = proc do |severity, datetime, progname, msg|
|
87
|
+
"#{msg}\n"
|
88
|
+
end
|
89
|
+
logger
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
data/lib/lstash/query.rb
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'date'
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
module Lstash
|
6
|
+
|
7
|
+
class Query
|
8
|
+
|
9
|
+
class FormatError < StandardError; end
|
10
|
+
class QueryMissing < StandardError; end
|
11
|
+
|
12
|
+
LOGSTASH_PREFIX = 'logstash-'
|
13
|
+
WILDCARD_QUERY = '*'
|
14
|
+
|
15
|
+
def initialize(query = nil, arguments = {})
|
16
|
+
@query = query
|
17
|
+
|
18
|
+
@anchor = time_parse(arguments[:anchor], 'today')
|
19
|
+
@from = time_parse(arguments[:from], 'today')
|
20
|
+
@to = time_parse(arguments[:to], 'now')
|
21
|
+
|
22
|
+
@to = Time.now if @to > Time.now # prevent accessing non-existing times / indices
|
23
|
+
end
|
24
|
+
|
25
|
+
def time_range
|
26
|
+
OpenStruct.new(from: @from, to: @to)
|
27
|
+
end
|
28
|
+
|
29
|
+
def date_range
|
30
|
+
(@from.utc.to_date .. @to.utc.to_date)
|
31
|
+
end
|
32
|
+
|
33
|
+
def indices
|
34
|
+
date_range.map { |d| "#{LOGSTASH_PREFIX}#{d.strftime('%Y.%m.%d')}" }
|
35
|
+
end
|
36
|
+
|
37
|
+
def body
|
38
|
+
{
|
39
|
+
sort: sort_order,
|
40
|
+
|
41
|
+
# return in order of ascending timestamp
|
42
|
+
query: {
|
43
|
+
filtered: {
|
44
|
+
query: es_query,
|
45
|
+
filter: es_filter
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def time_parse(time_string, default)
|
54
|
+
time_string = time_string.strip rescue nil
|
55
|
+
time_string ||= default
|
56
|
+
case time_string
|
57
|
+
when 'firstday'
|
58
|
+
midnight_at_beginning_of_month
|
59
|
+
when 'now'
|
60
|
+
Time.now
|
61
|
+
when 'today'
|
62
|
+
midnight_today
|
63
|
+
when 'yesterday'
|
64
|
+
midnight_yesterday
|
65
|
+
else
|
66
|
+
Time.parse(time_string)
|
67
|
+
end
|
68
|
+
rescue ArgumentError
|
69
|
+
raise FormatError, "Invalid time format: #{time_string}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def query
|
73
|
+
q = @query.dup.strip rescue ''
|
74
|
+
q = WILDCARD_QUERY if q.empty?
|
75
|
+
q
|
76
|
+
end
|
77
|
+
|
78
|
+
def sort_order
|
79
|
+
[ { '@timestamp' => { order: 'asc' } } ]
|
80
|
+
end
|
81
|
+
|
82
|
+
def es_query
|
83
|
+
{
|
84
|
+
bool: {
|
85
|
+
should: [
|
86
|
+
{
|
87
|
+
query_string: {
|
88
|
+
query: query
|
89
|
+
}
|
90
|
+
}
|
91
|
+
]
|
92
|
+
}
|
93
|
+
}
|
94
|
+
end
|
95
|
+
|
96
|
+
def es_filter
|
97
|
+
{
|
98
|
+
bool: {
|
99
|
+
must: [
|
100
|
+
range: {
|
101
|
+
'@timestamp' => {
|
102
|
+
from: to_msec(time_range.from),
|
103
|
+
to: to_msec(time_range.to)
|
104
|
+
}
|
105
|
+
},
|
106
|
+
# fquery: {
|
107
|
+
# query: {
|
108
|
+
# query_string: {
|
109
|
+
# query: query
|
110
|
+
# }
|
111
|
+
# }
|
112
|
+
# }
|
113
|
+
],
|
114
|
+
# must_not: [
|
115
|
+
# fquery: {
|
116
|
+
# query: {
|
117
|
+
# query_string: {
|
118
|
+
# query: query
|
119
|
+
# }
|
120
|
+
# }
|
121
|
+
# }
|
122
|
+
# ],
|
123
|
+
# should: [
|
124
|
+
# fquery: {
|
125
|
+
# query: {
|
126
|
+
# query_string: {
|
127
|
+
# query: query
|
128
|
+
# }
|
129
|
+
# }
|
130
|
+
# }
|
131
|
+
# ]
|
132
|
+
}
|
133
|
+
}
|
134
|
+
end
|
135
|
+
|
136
|
+
# Return the date of the first day of date's month
|
137
|
+
def midnight_at_beginning_of_month
|
138
|
+
Date.new(anchor_time.year, anchor_time.month, 1).to_time
|
139
|
+
end
|
140
|
+
|
141
|
+
def midnight_today
|
142
|
+
Date.today.to_time
|
143
|
+
end
|
144
|
+
|
145
|
+
def midnight_yesterday
|
146
|
+
(Date.today-1).to_time
|
147
|
+
end
|
148
|
+
|
149
|
+
def anchor_time
|
150
|
+
@anchor
|
151
|
+
end
|
152
|
+
|
153
|
+
def to_msec(time)
|
154
|
+
time.to_i * 1000
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
data/lib/lstash.rb
ADDED
data/lstash.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'lstash/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "lstash"
|
8
|
+
spec.version = Lstash::VERSION
|
9
|
+
spec.authors = ["Klaas Jan Wierenga"]
|
10
|
+
spec.email = ["k.j.wierenga@gmail.com"]
|
11
|
+
spec.description = %q{Count or grep log messages in a specified time range from a Logstash Elasticsearch server.}
|
12
|
+
spec.summary = %q{The lstash gem allows you to count or grep log messages in a specific time range from a Logstash Elasticsearch server. }
|
13
|
+
spec.homepage = "http://bitbucket.org/kjwierenga/lstash"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
spec.extra_rdoc_files = [ 'LICENSE.txt', 'README.md' ]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
spec.add_development_dependency "rspec"
|
25
|
+
spec.add_development_dependency "rspec-its"
|
26
|
+
spec.add_development_dependency "rspec-autotest"
|
27
|
+
spec.add_development_dependency "autotest-standalone"
|
28
|
+
spec.add_development_dependency "autotest-fsevent"
|
29
|
+
spec.add_development_dependency "timecop"
|
30
|
+
|
31
|
+
spec.add_dependency "patron"
|
32
|
+
spec.add_dependency "elasticsearch", "~> 0.4"
|
33
|
+
spec.add_dependency "hashie"
|
34
|
+
spec.add_dependency "thor"
|
35
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'lstash/cli'
|
3
|
+
|
4
|
+
class Lstash::CLI < Thor
|
5
|
+
def self.exit_on_failure?
|
6
|
+
false
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe Lstash::CLI do
|
11
|
+
|
12
|
+
context "options" do
|
13
|
+
subject { Lstash::CLI.options(args) }
|
14
|
+
|
15
|
+
let(:args) { %w(extract --time from --to to --one --two --three --four) }
|
16
|
+
|
17
|
+
its(:keys) { should eq args }
|
18
|
+
end
|
19
|
+
|
20
|
+
context "count" do
|
21
|
+
|
22
|
+
context "with valid arguments" do
|
23
|
+
let(:args) { %w(count "program:haproxy" --es-url localhost) }
|
24
|
+
|
25
|
+
it "should succeed" do
|
26
|
+
client = double('client')
|
27
|
+
|
28
|
+
allow(Lstash::Client).to receive(:new).and_return(client)
|
29
|
+
allow(client).to receive(:count).and_return(100)
|
30
|
+
|
31
|
+
output = capture_stdout { Lstash::CLI.start(args) }
|
32
|
+
|
33
|
+
expect(output).to eq "100\n"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "with invalid --es-url" do
|
38
|
+
let(:args) { %w(count "program:haproxy" --es-url '') }
|
39
|
+
|
40
|
+
it "should print error message" do
|
41
|
+
output = capture_stderr { Lstash::CLI.start(args) }
|
42
|
+
|
43
|
+
expect(output).to eq "the scheme http does not accept registry part: '':9200 (or bad hostname?)\n"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "without query" do
|
48
|
+
let(:args) { %w() }
|
49
|
+
it "should print help message" do
|
50
|
+
output = capture_stdout { Lstash::CLI.start(args) }
|
51
|
+
|
52
|
+
expect(output).to match("Commands:\n rspec count QUERY")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "with anchor date" do
|
57
|
+
let(:args) { %w(count program:haproxy --from firstday --to today --anchor yesterday) }
|
58
|
+
|
59
|
+
it "should succeed" do
|
60
|
+
Timecop.freeze('2014-08-01 14:58') do
|
61
|
+
es_client = double('es_client')
|
62
|
+
|
63
|
+
allow(Elasticsearch::Client).to receive(:new) { es_client }
|
64
|
+
|
65
|
+
expect(es_client).to receive(:count).with(satisfy { |args|
|
66
|
+
expect_time_range(args, [
|
67
|
+
Time.parse('2014-07-01').to_i*1000,
|
68
|
+
Time.parse('2014-08-01').to_i*1000
|
69
|
+
])
|
70
|
+
})
|
71
|
+
|
72
|
+
Lstash::CLI.start(args)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context "without anchor date" do
|
78
|
+
let(:args) { %w(count program:haproxy --from yesterday --to today) }
|
79
|
+
|
80
|
+
it "should succeed" do
|
81
|
+
Timecop.freeze('2014-08-01 14:58') do
|
82
|
+
es_client = double('es_client')
|
83
|
+
|
84
|
+
allow(Elasticsearch::Client).to receive(:new) { es_client }
|
85
|
+
|
86
|
+
expect(es_client).to receive(:count).with(satisfy { |args|
|
87
|
+
expect_time_range(args, [
|
88
|
+
Time.parse('2014-07-31').to_i*1000,
|
89
|
+
Time.parse('2014-08-01').to_i*1000
|
90
|
+
])
|
91
|
+
}).and_return([{count:1}])
|
92
|
+
|
93
|
+
Lstash::CLI.start(args)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def expect_time_range(args, time_range)
|
103
|
+
expect(args[:body][:filtered][:filter][:bool][:must].first[:range]['@timestamp'][:from]).to eq time_range.first
|
104
|
+
expect(args[:body][:filtered][:filter][:bool][:must].first[:range]['@timestamp'][:to]).to eq time_range.last
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'lstash/client'
|
3
|
+
|
4
|
+
describe Lstash::Client do
|
5
|
+
|
6
|
+
let(:es_client) { double('es_client') }
|
7
|
+
subject { Lstash::Client.new(es_client) }
|
8
|
+
|
9
|
+
it "should initialize properly" do
|
10
|
+
expect(subject).not_to be nil
|
11
|
+
end
|
12
|
+
|
13
|
+
context "with query" do
|
14
|
+
|
15
|
+
let(:query) { double('query', time_range: OpenStruct.new) }
|
16
|
+
|
17
|
+
context "count" do
|
18
|
+
it "should return number of messages matching query" do
|
19
|
+
allow(query).to receive(:indices).and_return (['logstash-2014-08-01', 'logstash-2014-08-02'])
|
20
|
+
allow(query).to receive(:body).and_return ({})
|
21
|
+
|
22
|
+
allow(es_client).to receive(:count).and_return({'count' => 100},{'count' => 100})
|
23
|
+
|
24
|
+
expect(subject.count(query)).to eq 200
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "grep" do
|
29
|
+
let(:query) { double('query', time_range: OpenStruct.new) }
|
30
|
+
|
31
|
+
it "should return the messages matching the query" do
|
32
|
+
allow(query).to receive(:indices).and_return (['logstash-2014-08-01', 'logstash-2014-08-02'])
|
33
|
+
allow(query).to receive(:body).and_return ({})
|
34
|
+
|
35
|
+
allow(es_client).to receive(:search).and_return(
|
36
|
+
hits([
|
37
|
+
'this is the first log line',
|
38
|
+
'this is the second log line'
|
39
|
+
])
|
40
|
+
)
|
41
|
+
|
42
|
+
allow(es_client).to receive(:scroll).and_return(hits([]))
|
43
|
+
|
44
|
+
allow(es_client).to receive(:clear_scroll)
|
45
|
+
|
46
|
+
subject.grep(query)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
def hits(messages)
|
53
|
+
{
|
54
|
+
hits: {
|
55
|
+
hits: messages.map { |m| { _source: { message: m }}}
|
56
|
+
}
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'lstash/query'
|
3
|
+
|
4
|
+
describe Lstash::Query do
|
5
|
+
|
6
|
+
context "running on 2014-08-03" do
|
7
|
+
let(:time) { '2014-08-03 15:54:33' }
|
8
|
+
let(:query) { nil }
|
9
|
+
let(:options) { {} }
|
10
|
+
|
11
|
+
subject { Lstash::Query.new(query, options) }
|
12
|
+
|
13
|
+
before { Timecop.freeze(Time.parse(time)) }
|
14
|
+
after { Timecop.return }
|
15
|
+
|
16
|
+
it { should_not be nil }
|
17
|
+
# it "should initialize properly" do
|
18
|
+
# expect(subject).not_to be nil
|
19
|
+
# end
|
20
|
+
|
21
|
+
its('time_range.from') { should eq Time.parse('2014-08-03 00:00:00.000000000 +0200') }
|
22
|
+
its('time_range.to') { should eq Time.parse('2014-08-03 15:54:33.000000000 +0200') }
|
23
|
+
|
24
|
+
its(:date_range) { should eq (Date.parse('2014-08-02')..Date.parse('2014-08-03')) }
|
25
|
+
|
26
|
+
its(:indices) { should eq [ "logstash-2014.08.02", "logstash-2014.08.03" ] }
|
27
|
+
|
28
|
+
context "with specific query" do
|
29
|
+
let(:query) { 'program:haproxy' }
|
30
|
+
its(:query) { should eq query }
|
31
|
+
end
|
32
|
+
|
33
|
+
context "without query" do
|
34
|
+
let(:query) { nil }
|
35
|
+
its(:query) { should eql '*' }
|
36
|
+
end
|
37
|
+
|
38
|
+
context "from 'yesterday'" do
|
39
|
+
let(:options) { { from: 'yesterday' }}
|
40
|
+
its('time_range.from') { should eq Time.parse('2014-08-02 00:00:00.000000000 +0200') }
|
41
|
+
end
|
42
|
+
|
43
|
+
context "from 'today'" do
|
44
|
+
let(:options) { { from: 'today' }}
|
45
|
+
its('time_range.from') { should eq Time.parse('2014-08-03 00:00:00.000000000 +0200') }
|
46
|
+
end
|
47
|
+
|
48
|
+
context "from 'now'" do
|
49
|
+
let(:options) { { from: 'now' }}
|
50
|
+
its('time_range.from') { should eq Time.parse('2014-08-03 15:54:33.000000000 +0200') }
|
51
|
+
end
|
52
|
+
|
53
|
+
context "to 'yesterday'" do
|
54
|
+
let(:options) { { to: 'yesterday' }}
|
55
|
+
its('time_range.to') { should eq Time.parse('2014-08-02 00:00:00.000000000 +0200') }
|
56
|
+
end
|
57
|
+
|
58
|
+
context "to 'today'" do
|
59
|
+
let(:options) { { to: 'today' }}
|
60
|
+
its('time_range.to') { should eq Time.parse('2014-08-03 00:00:00.000000000 +0200') }
|
61
|
+
end
|
62
|
+
|
63
|
+
context "to 'now'" do
|
64
|
+
let(:options) { { to: 'now' }}
|
65
|
+
its('time_range.to') { should eq Time.parse('2014-08-03 15:54:33.000000000 +0200') }
|
66
|
+
end
|
67
|
+
|
68
|
+
context "from 'firstday'" do
|
69
|
+
|
70
|
+
let(:options) { { from: 'firstday' } }
|
71
|
+
its('time_range.from') { should eq Time.parse('2014-08-01 00:00:00.000000000 +0200') }
|
72
|
+
|
73
|
+
context "anchor 'yesterday'" do
|
74
|
+
let(:anchor) { 'yesterday' }
|
75
|
+
its('time_range.from') { should eq Time.parse('2014-08-01 00:00:00.000000000 +0200') }
|
76
|
+
end
|
77
|
+
|
78
|
+
context "anchor 'today'" do
|
79
|
+
let(:anchor) { 'today' }
|
80
|
+
its('time_range.from') { should eq Time.parse('2014-08-01 00:00:00.000000000 +0200') }
|
81
|
+
end
|
82
|
+
|
83
|
+
context "anchor '2014-07-17'" do
|
84
|
+
let(:options) { { from: 'firstday', anchor: '2014-07-17' } }
|
85
|
+
its('time_range.from') { should eq Time.parse('2014-07-01 00:00:00.000000000 +0200') }
|
86
|
+
end
|
87
|
+
|
88
|
+
context "date range" do
|
89
|
+
let(:options) { { from: 'firstday', anchor: 'yesterday' } }
|
90
|
+
its(:date_range) { should eq (Date.parse('2014-07-31')..Date.parse('2014-08-03')) }
|
91
|
+
end
|
92
|
+
|
93
|
+
context "indices" do
|
94
|
+
let(:options) { { from: 'firstday', anchor: 'yesterday' } }
|
95
|
+
its(:indices) {
|
96
|
+
should eq [
|
97
|
+
"logstash-2014.07.31",
|
98
|
+
"logstash-2014.08.01",
|
99
|
+
"logstash-2014.08.02",
|
100
|
+
"logstash-2014.08.03",
|
101
|
+
]
|
102
|
+
}
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
context "body" do
|
108
|
+
its(:body) { should eq ({
|
109
|
+
:sort => [{"@timestamp"=>{:order=>"asc"}}],
|
110
|
+
:query => {:filtered=>{
|
111
|
+
:query => { :bool => { :should => [ { :query_string => { :query=>"*" }}]}},
|
112
|
+
:filter=> { :bool => { :must => [ { :range => { "@timestamp" => { :from => 1407016800000, :to => 1407074073000}}}]}}}}
|
113
|
+
})}
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
context "running on 2014-08-01" do
|
119
|
+
let(:time) { '2014-08-01 12:53:03' }
|
120
|
+
let(:query) { nil }
|
121
|
+
let(:options) { {} }
|
122
|
+
|
123
|
+
subject { Lstash::Query.new(query, options) }
|
124
|
+
|
125
|
+
before { Timecop.freeze(Time.parse(time)) }
|
126
|
+
after { Timecop.return }
|
127
|
+
|
128
|
+
context "from 'firstday' with 'yesterday' anchor" do
|
129
|
+
let(:options) { { anchor: 'yesterday', from: 'firstday' } }
|
130
|
+
|
131
|
+
its('time_range.from') { should eq Time.parse('2014-07-01 00:00:00.000000000 +0200') }
|
132
|
+
its('time_range.to') { should eq Time.parse('2014-08-01 12:53:03.000000000 +0200') }
|
133
|
+
end
|
134
|
+
|
135
|
+
context "from 'firstday' with default 'today' anchor" do
|
136
|
+
let(:options) { { from: 'firstday', to: 'now' } }
|
137
|
+
|
138
|
+
its('time_range.from') { should eq Time.parse('2014-08-01 00:00:00.000000000 +0200') }
|
139
|
+
its('time_range.to') { should eq Time.parse('2014-08-01 12:53:03.000000000 +0200') }
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
data/spec/lstash_spec.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'lstash'
|
3
|
+
|
4
|
+
require 'rspec/its'
|
5
|
+
|
6
|
+
require 'timecop'
|
7
|
+
|
8
|
+
ENV['ES_URL'] = nil
|
9
|
+
ENV['TZ'] = 'Europe/Amsterdam' # Test in a specific timezone.
|
10
|
+
|
11
|
+
RSpec.configure do |config|
|
12
|
+
config.order = 'random'
|
13
|
+
end
|
14
|
+
|
15
|
+
require 'stringio'
|
16
|
+
|
17
|
+
def capture_stdout(&blk)
|
18
|
+
old = $stdout
|
19
|
+
$stdout = fake = StringIO.new
|
20
|
+
blk.call
|
21
|
+
fake.string
|
22
|
+
ensure
|
23
|
+
$stdout = old
|
24
|
+
end
|
25
|
+
|
26
|
+
def capture_stderr(&blk)
|
27
|
+
old = $stderr
|
28
|
+
$stderr = fake = StringIO.new
|
29
|
+
blk.call
|
30
|
+
fake.string
|
31
|
+
ensure
|
32
|
+
$stderr = old
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,245 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lstash
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.6
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Klaas Jan Wierenga
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-09-01 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.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec-its
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec-autotest
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ! '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ! '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: autotest-standalone
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ! '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ! '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: autotest-fsevent
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ! '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: timecop
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ! '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: patron
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ! '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ! '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: elasticsearch
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ~>
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0.4'
|
146
|
+
type: :runtime
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ~>
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0.4'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: hashie
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ! '>='
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :runtime
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ! '>='
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: thor
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ! '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :runtime
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ! '>='
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
181
|
+
description: Count or grep log messages in a specified time range from a Logstash
|
182
|
+
Elasticsearch server.
|
183
|
+
email:
|
184
|
+
- k.j.wierenga@gmail.com
|
185
|
+
executables:
|
186
|
+
- lstash
|
187
|
+
extensions: []
|
188
|
+
extra_rdoc_files:
|
189
|
+
- LICENSE.txt
|
190
|
+
- README.md
|
191
|
+
files:
|
192
|
+
- .autotest
|
193
|
+
- .gitignore
|
194
|
+
- .rspec
|
195
|
+
- .ruby-gemset
|
196
|
+
- .ruby-version
|
197
|
+
- .travis.yml
|
198
|
+
- CHANGELOG.md
|
199
|
+
- Gemfile
|
200
|
+
- LICENSE.txt
|
201
|
+
- README.md
|
202
|
+
- Rakefile
|
203
|
+
- bin/lstash
|
204
|
+
- lib/lstash.rb
|
205
|
+
- lib/lstash/cli.rb
|
206
|
+
- lib/lstash/client.rb
|
207
|
+
- lib/lstash/query.rb
|
208
|
+
- lib/lstash/version.rb
|
209
|
+
- lstash.gemspec
|
210
|
+
- spec/lstash/cli_spec.rb
|
211
|
+
- spec/lstash/client_spec.rb
|
212
|
+
- spec/lstash/query_spec.rb
|
213
|
+
- spec/lstash_spec.rb
|
214
|
+
- spec/spec_helper.rb
|
215
|
+
homepage: http://bitbucket.org/kjwierenga/lstash
|
216
|
+
licenses:
|
217
|
+
- MIT
|
218
|
+
metadata: {}
|
219
|
+
post_install_message:
|
220
|
+
rdoc_options: []
|
221
|
+
require_paths:
|
222
|
+
- lib
|
223
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
224
|
+
requirements:
|
225
|
+
- - ! '>='
|
226
|
+
- !ruby/object:Gem::Version
|
227
|
+
version: '0'
|
228
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
229
|
+
requirements:
|
230
|
+
- - ! '>='
|
231
|
+
- !ruby/object:Gem::Version
|
232
|
+
version: '0'
|
233
|
+
requirements: []
|
234
|
+
rubyforge_project:
|
235
|
+
rubygems_version: 2.4.1
|
236
|
+
signing_key:
|
237
|
+
specification_version: 4
|
238
|
+
summary: The lstash gem allows you to count or grep log messages in a specific time
|
239
|
+
range from a Logstash Elasticsearch server.
|
240
|
+
test_files:
|
241
|
+
- spec/lstash/cli_spec.rb
|
242
|
+
- spec/lstash/client_spec.rb
|
243
|
+
- spec/lstash/query_spec.rb
|
244
|
+
- spec/lstash_spec.rb
|
245
|
+
- spec/spec_helper.rb
|