sawmill-sawyer 13.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 +7 -0
- data/.gitignore +9 -0
- data/Gemfile +17 -0
- data/LICENSE +13 -0
- data/Rakefile +29 -0
- data/Readme.md +3 -0
- data/VERSION +1 -0
- data/bin/sawyer +56 -0
- data/lib/sawyer.rb +13 -0
- data/lib/sawyer/actions.rb +99 -0
- data/lib/sawyer/actions_raw.rb +69 -0
- data/lib/sawyer/logger.rb +12 -0
- data/sawmill-sawyer.gemspec +20 -0
- metadata +98 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 55137b531ea6620f6a0f27a0fe51569e8240118f
|
4
|
+
data.tar.gz: 1bc7ceaf34cd708a76dc75974d0e77a4e0df3443
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bd78951fbe1e60bacf54c7ef8a4419a587bdcb9aca0b0e57ef9366f40b3eaf3104f44bf81ef38bf8fdb5064555fa72bb8a2fe5bd13b2a962a8739c939b93223e
|
7
|
+
data.tar.gz: 4234a4d8e3c6a1f26b346f28e161de5cc9801fe9ea6e23071eb4c9fb9bcb652e405dc26c6fde05b0d747dc9b94e812b9cbfef41546e33fb2f47547b5b331ce31
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright (c) 2014 Sean Clemmer and Blue Jeans Network
|
2
|
+
|
3
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
4
|
+
purpose with or without fee is hereby granted, provided that the above
|
5
|
+
copyright notice and this permission notice appear in all copies.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
8
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
9
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
10
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
11
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
12
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
13
|
+
PERFORMANCE OF THIS SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
require 'rake'
|
4
|
+
|
5
|
+
require 'rake/testtask'
|
6
|
+
Rake::TestTask.new(:test) do |test|
|
7
|
+
test.libs << 'lib' << 'test'
|
8
|
+
test.test_files = FileList['test/test*.rb']
|
9
|
+
test.verbose = true
|
10
|
+
end
|
11
|
+
|
12
|
+
task default: :test
|
13
|
+
|
14
|
+
|
15
|
+
require 'yard'
|
16
|
+
YARD::Rake::YardocTask.new do |t|
|
17
|
+
t.files = %w[ --readme Readme.md lib/**/*.rb - VERSION ]
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
require 'rubygems/tasks'
|
22
|
+
Gem::Tasks.new push: true, sign: {} do |tasks|
|
23
|
+
tasks.console.command = 'pry'
|
24
|
+
end
|
25
|
+
Gem::Tasks::Sign::Checksum.new sha2: true
|
26
|
+
|
27
|
+
|
28
|
+
require 'rake/version_task'
|
29
|
+
Rake::VersionTask.new
|
data/Readme.md
ADDED
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
13.0.2
|
data/bin/sawyer
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require_relative '../lib/sawyer'
|
3
|
+
|
4
|
+
BIN_DIR = File.dirname(File.expand_path(__FILE__))
|
5
|
+
VERSION = File.read(File.join(BIN_DIR, '..', 'VERSION')).strip
|
6
|
+
ABOUT = "sawyer v#{VERSION} - Sean Clemmer (sclemmer@bluejeans.com) / Blue Jeans Network"
|
7
|
+
ACTIONS = [
|
8
|
+
"logs QUERY_STRING -- Find all logs matching the query string within an interval",
|
9
|
+
"events QUERY_STRING [LOGS] -- Find all events matching the query string within the given logs and interval"
|
10
|
+
]
|
11
|
+
|
12
|
+
argv = ARGV.empty? ? %w[ --help ] : ARGV
|
13
|
+
|
14
|
+
opts = Trollop::options(argv) do
|
15
|
+
version ABOUT
|
16
|
+
|
17
|
+
ART = <<-'EOART' % VERSION
|
18
|
+
.---. __ ,-.
|
19
|
+
.--.--. /. ./| ,' ,'/ /|
|
20
|
+
/ / ' ,--.--. .-'-. ' | .--, ,---. ' | |' |
|
21
|
+
| : /`./ / \ /___/ \: | /_ ./| / \ | | ,'
|
22
|
+
| : ;_ .--. .-. | .-'.. ' ' . , ' , ' : / / |' : /
|
23
|
+
\ \ `. \__\/: . ./___/ \: '/___/ \: |. ' / || | '
|
24
|
+
`----. \ ," .--.; |. \ ' .\ . \ ' |' ; /|; : |
|
25
|
+
/ /`--' // / ,. | \ \ ' \ | \ ; :' | / || , ;
|
26
|
+
'--'. /; : .' \ \ \ |--" \ \ ;| : | ---'
|
27
|
+
`--'---' | , .-./ \ \ | : \ \\ \ /
|
28
|
+
`--`---' '---" \ ' ; `----'
|
29
|
+
`--` v%s
|
30
|
+
EOART
|
31
|
+
|
32
|
+
USAGE = <<-EOS.gsub(/^ /, '')
|
33
|
+
Usage: sawyer [OPTIONS] ACTION [ARGS]
|
34
|
+
|
35
|
+
Actions:
|
36
|
+
\t#{ACTIONS.join("\n\t")}
|
37
|
+
|
38
|
+
Options:
|
39
|
+
EOS
|
40
|
+
|
41
|
+
banner "\n\n" + ART + "\n" + USAGE
|
42
|
+
opt :from, 'Match events after this', default: '15 minutes ago'
|
43
|
+
opt :to, 'Match events before this', default: 'now'
|
44
|
+
opt :environment, 'Match events in this environment', default: 'prod'
|
45
|
+
opt :prefix, 'Match events with this index prefix', default: 'logs'
|
46
|
+
opt :limit, 'Limit search result size', default: 25
|
47
|
+
opt :debug, 'Enable debug output', default: false
|
48
|
+
end
|
49
|
+
|
50
|
+
level = ::Logger::INFO
|
51
|
+
level = ::Logger::DEBUG if opts[:debug]
|
52
|
+
logger = Sawyer::Logger.new STDERR, level
|
53
|
+
action = argv.shift.to_sym rescue nil
|
54
|
+
|
55
|
+
Trollop::die 'No action provided' if action.nil?
|
56
|
+
exit Sawyer::Actions.new(opts, action, argv, logger).status
|
data/lib/sawyer.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
require_relative 'actions_raw'
|
2
|
+
|
3
|
+
class Fixnum
|
4
|
+
def hours
|
5
|
+
self * 60 * 60 # [hr] * [min/hr] * [s/min] => [s]
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
module Sawyer
|
11
|
+
ENVIRONMENTS = {
|
12
|
+
prod: 'http://10.100.0.146:8080/es',
|
13
|
+
stage: 'http://10.100.200.12:8080/es'
|
14
|
+
}
|
15
|
+
|
16
|
+
class Actions
|
17
|
+
include RawActions
|
18
|
+
|
19
|
+
attr_reader :logger, :status
|
20
|
+
|
21
|
+
def initialize opts, action, args, logger
|
22
|
+
environment = opts[:environment].to_sym
|
23
|
+
from = Chronic.parse(opts[:from])
|
24
|
+
to = Chronic.parse(opts[:to])
|
25
|
+
|
26
|
+
@prefix = opts[:prefix]
|
27
|
+
@limit = opts[:limit]
|
28
|
+
@action = action
|
29
|
+
@args = args
|
30
|
+
@logger = logger
|
31
|
+
@status = 0
|
32
|
+
|
33
|
+
@elasticsearch = ENVIRONMENTS[environment.to_sym]
|
34
|
+
|
35
|
+
@status = send action, from, to, args
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def search from, to, request
|
40
|
+
indexes = []
|
41
|
+
|
42
|
+
# INF-4114: Limit searches to 24h max
|
43
|
+
max = 24
|
44
|
+
limit = from + max.hours
|
45
|
+
if to > limit
|
46
|
+
@logger.warn "Truncating search to first #{max} hours"
|
47
|
+
to = limit
|
48
|
+
end
|
49
|
+
|
50
|
+
date_from = from.getutc.to_date
|
51
|
+
date_to = to.getutc.to_date
|
52
|
+
|
53
|
+
until date_from > date_to
|
54
|
+
indexes << date_from.strftime("#{@prefix}-%Y.%m.%d")
|
55
|
+
date_from += 1 # day
|
56
|
+
end
|
57
|
+
|
58
|
+
unless request.has_key?(:size) and request[:size] == 0
|
59
|
+
request[:size] = @limit
|
60
|
+
end
|
61
|
+
|
62
|
+
if request.has_key? :aggregations
|
63
|
+
request[:aggregations].each do |name, agg|
|
64
|
+
agg.keys.each do |k|
|
65
|
+
request[:aggregations][name][k].merge!({ size: @limit })
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
request[:query] = {
|
71
|
+
filtered: {
|
72
|
+
query: request[:query],
|
73
|
+
filter: {
|
74
|
+
bool: {
|
75
|
+
must: {
|
76
|
+
range: {
|
77
|
+
'@timestamp' => {
|
78
|
+
gte: from.iso8601,
|
79
|
+
lte: to.iso8601
|
80
|
+
}
|
81
|
+
}
|
82
|
+
}
|
83
|
+
}
|
84
|
+
}
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
url = "#{@elasticsearch}/#{indexes * ','}/_search?ignore_unavailable=true&timeout=10000"
|
89
|
+
@logger.debug url
|
90
|
+
@logger.debug request.to_json
|
91
|
+
curl_request = Curl::Easy.http_post(url, request.to_json) do |curl|
|
92
|
+
curl.headers['Accept'] = 'application/json'
|
93
|
+
curl.headers['Content-Type'] = 'application/json'
|
94
|
+
curl.verbose = @logger.debug?
|
95
|
+
end
|
96
|
+
JSON::parse curl_request.body_str
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module RawActions
|
2
|
+
def logs from, to, args
|
3
|
+
qs = args.shift
|
4
|
+
request = {
|
5
|
+
size: 0,
|
6
|
+
query: {
|
7
|
+
query_string: {
|
8
|
+
query: qs
|
9
|
+
}
|
10
|
+
},
|
11
|
+
aggregations: {
|
12
|
+
logs: {
|
13
|
+
terms: {
|
14
|
+
script: "_source.host + _source.path"
|
15
|
+
}
|
16
|
+
}
|
17
|
+
}
|
18
|
+
}
|
19
|
+
|
20
|
+
response = search from, to, request
|
21
|
+
buckets = []
|
22
|
+
if response.has_key? 'aggregations'
|
23
|
+
buckets = response['aggregations']['logs']['buckets']
|
24
|
+
end
|
25
|
+
logs = buckets.map { |log| "%d\t%s" % [ log['doc_count'], log['key'] ] }
|
26
|
+
puts logs.reverse
|
27
|
+
return 0
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
def events from, to, args
|
33
|
+
qs = args.shift
|
34
|
+
logs = args
|
35
|
+
|
36
|
+
$stdin.read.split("\n").each do |l|
|
37
|
+
logs << l.split(' ', 2).last
|
38
|
+
end unless $stdin.tty?
|
39
|
+
|
40
|
+
unless logs.empty?
|
41
|
+
logs = logs.map do |log|
|
42
|
+
host, path = log.split('/', 2)
|
43
|
+
if path.nil? || path.empty?
|
44
|
+
'host:"%s"' % host
|
45
|
+
else
|
46
|
+
'(host:"%s" AND path:"/%s")' % [ host, path ]
|
47
|
+
end
|
48
|
+
end.join(' OR ')
|
49
|
+
logs = " AND (#{logs})"
|
50
|
+
else
|
51
|
+
logs = ''
|
52
|
+
end
|
53
|
+
|
54
|
+
request = {
|
55
|
+
query: {
|
56
|
+
query_string: {
|
57
|
+
query: qs + logs
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
response = search from, to, request
|
63
|
+
if response.has_key?('hits')
|
64
|
+
puts JSON::pretty_generate(response['hits']['hits'].map { |e| e['_source'] })
|
65
|
+
return 0
|
66
|
+
end
|
67
|
+
return 1
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Sawyer
|
2
|
+
module Logger
|
3
|
+
def self.new file=STDOUT, level=::Logger::INFO
|
4
|
+
logger = ::Logger.new file
|
5
|
+
logger.level = level
|
6
|
+
logger.formatter = proc { |severity, datetime, _, msg|
|
7
|
+
"#{severity} [#{datetime.iso8601(6)}] #{File::basename caller[4]} -- #{msg}\n"
|
8
|
+
}
|
9
|
+
return logger
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'sawmill-sawyer'
|
3
|
+
s.version = File.read('VERSION').strip
|
4
|
+
s.platform = Gem::Platform::RUBY
|
5
|
+
s.author = 'Sean Clemmer'
|
6
|
+
s.email = 'sclemmer@bluejeans.com'
|
7
|
+
s.homepage = 'http://wiki.bluejeansnet.com/operations/sawyer'
|
8
|
+
s.summary = 'Sawyer is a command-line companion to Sawmill'
|
9
|
+
s.description = 'Sawyer is a command-line companion to Sawmill.'
|
10
|
+
s.license = 'ISC'
|
11
|
+
|
12
|
+
s.add_runtime_dependency 'curb', '~> 0'
|
13
|
+
s.add_runtime_dependency 'chronic', '~> 0'
|
14
|
+
s.add_runtime_dependency 'trollop', '~> 2'
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ['lib']
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sawmill-sawyer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 13.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sean Clemmer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-12-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: curb
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: chronic
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
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: trollop
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2'
|
55
|
+
description: Sawyer is a command-line companion to Sawmill.
|
56
|
+
email: sclemmer@bluejeans.com
|
57
|
+
executables:
|
58
|
+
- sawyer
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- Gemfile
|
64
|
+
- LICENSE
|
65
|
+
- Rakefile
|
66
|
+
- Readme.md
|
67
|
+
- VERSION
|
68
|
+
- bin/sawyer
|
69
|
+
- lib/sawyer.rb
|
70
|
+
- lib/sawyer/actions.rb
|
71
|
+
- lib/sawyer/actions_raw.rb
|
72
|
+
- lib/sawyer/logger.rb
|
73
|
+
- sawmill-sawyer.gemspec
|
74
|
+
homepage: http://wiki.bluejeansnet.com/operations/sawyer
|
75
|
+
licenses:
|
76
|
+
- ISC
|
77
|
+
metadata: {}
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options: []
|
80
|
+
require_paths:
|
81
|
+
- lib
|
82
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
requirements: []
|
93
|
+
rubyforge_project:
|
94
|
+
rubygems_version: 2.2.2
|
95
|
+
signing_key:
|
96
|
+
specification_version: 4
|
97
|
+
summary: Sawyer is a command-line companion to Sawmill
|
98
|
+
test_files: []
|