lugg 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 269ec3ed7cc8b001cb923289fcc45a991f1d6fbb
4
+ data.tar.gz: 9f34b5919963cfc7f972887ab416d6d1e21abf92
5
+ SHA512:
6
+ metadata.gz: 4c2a1b31b30905a76ce343f57510fa5373dfbe06c499b9819d57e7e40e90cf11eb3ea6f858eeb3390f3fabe8a92d466984b39e7bf5f6b9fbe3584d35678efbef
7
+ data.tar.gz: c673f9f5112bb7233ec78c882d913bbecbb7a5f425043ae5053eae42183d0930397469b0d411ef621ea6d47082b76143ed20f7f99a6ddba40c89526889b3ed0b
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --order rand
3
+ -I lib
4
+ --require lugg
data/.rubocop.yml ADDED
@@ -0,0 +1,36 @@
1
+ AllCops:
2
+ Includes:
3
+ - '**/*.gemspec'
4
+ - '**/Rakefile'
5
+ Excludes:
6
+ - 'bin/*'
7
+
8
+ SignalException:
9
+ EnforcedStyle: only_raise
10
+
11
+ SymbolArray:
12
+ Enabled: true
13
+
14
+ Documentation:
15
+ Exclude:
16
+ - spec/**/*.rb
17
+ - lib/lugg/version.rb
18
+
19
+ LineLength:
20
+ Exclude:
21
+ - spec/**/*.rb
22
+ - lib/lugg.rb
23
+
24
+ AndOr:
25
+ Enabled: false
26
+
27
+ ClassLength:
28
+ Exclude:
29
+ - lib/lugg/runner.rb
30
+
31
+ MethodLength:
32
+ Exclude:
33
+ - lib/lugg/runner.rb
34
+
35
+ DoubleNegation:
36
+ Enabled: false
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.1
4
+ - 2.1.0
5
+ - 2.0.0
data/.yardopts ADDED
@@ -0,0 +1,9 @@
1
+ --no-private
2
+ --title "Lugg, Query Rails log files from the command line."
3
+ --readme README.md
4
+ --markup markdown
5
+ --markup-provider kramdown
6
+ --output-dir doc/api
7
+ -
8
+ HISTORY.md
9
+ LICENSE
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in lugg.gemspec
4
+ gemspec
data/HISTORY.md ADDED
File without changes
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Arjan van der Gaag
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,89 @@
1
+ # Lugg — query Rails log files [![Build Status](https://secure.travis-ci.org/avdgaag/lugg.png?branch=master)](http://travis-ci.org/avdgaag/lugg) [![Code Climate](https://codeclimate.com/github/avdgaag/lugg.png)](https://codeclimate.com/github/avdgaag/lugg)
2
+
3
+ A tiny command line utility to search through Rails server log files and display
4
+ requests that meet certain criteria.
5
+
6
+ ## Installation
7
+
8
+ Lugg is distributed as a Ruby gem, which should be installed on most Macs and
9
+ Linux systems. Once you have ensured you have a working installation of Ruby
10
+ and Ruby gems, install the gem as follows from the command line:
11
+
12
+ $ gem install lugg
13
+
14
+ You can verify the gem has installed correctly by checking its version number:
15
+
16
+ $ lugg -v
17
+
18
+ If this generates an error, something has gone wrong. You should see something
19
+ along the lines of `lugg 1.0.0`.
20
+
21
+ ## Usage
22
+
23
+ Lugg takes one or more files as arguments or input on STDIN and redirects that
24
+ content to STDOUT -- but not before applying some filters. Content will be
25
+ parsed as Rails server log files and only the entire log entries matching your
26
+ criteria are displayed.
27
+
28
+ You supply criteria by passing in command line options. You can see a full list
29
+ of accepted options by running `lugg -h`:
30
+
31
+ ```
32
+ --and Combine previous and next clause with AND instead of OR
33
+ --get Limit to GET requests
34
+ --post Limit to POST requests
35
+ --put Limit to PUT requests
36
+ --delete Limit to DELETE requests
37
+ --head Limit to HEAD requests
38
+ --patch Limit to PATCH requests
39
+ -c, --controller CONTROLLER Limit to requests handled by CONTROLLER
40
+ -a, --action CONTROLLER_ACTION Limit to requests handled by CONTROLLER_ACTION
41
+ --json Limit to json requests
42
+ --html Limit to html requests
43
+ --xml Limit to xml requests
44
+ --csv Limit to csv requests
45
+ --pdf Limit to pdf requests
46
+ --js Limit to js requests
47
+ -f, --format FORMAT Limit to FORMAT requests
48
+ -s, --status CODE Limit requests with status code CODE
49
+ --since TIME Limit to requests made after TIME
50
+ --until TIME Limit to requests made before TIME
51
+ -d, --duration N Limit to requests longer than N ms
52
+ -u, --uri URI Limit to requests matching URI
53
+ -p, --param KEY=VAL Limit to requests with param KEY => VAL
54
+
55
+ -v, --version Display version number
56
+ -h, --help Display this message
57
+ ```
58
+
59
+ Note that all conditions are combined with OR, but you can combine two
60
+ conditions with the `--and` flag.
61
+
62
+ ### Documentation
63
+
64
+ See the inline [API docs](http://rubydoc.info/github/avdgaag/lugg/master/frames) for more information.
65
+
66
+ ## Contributing
67
+
68
+ 1. Fork it ( https://github.com/avdgaag/lugg/fork )
69
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
70
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
71
+ 4. Push to the branch (`git push origin my-new-feature`)
72
+ 5. Create new Pull Request
73
+
74
+ ### Issues
75
+
76
+ Please report any issues, defects or suggestions in the [Github issue
77
+ tracker](https://github.com/avdgaag/lugg/issues).
78
+
79
+ ### What has changed?
80
+
81
+ See the [HISTORY](https://github.com/avdgaag/lugg/blob/master/HISTORY.md) file for a detailed changelog.
82
+
83
+ ### Credits
84
+
85
+ Created by: Arjan van der Gaag
86
+ URL: [http://arjanvandergaag.nl](http://arjanvandergaag.nl)
87
+ Project homepage: [http://avdgaag.github.io/lugg](http://avdgaag.github.io/lugg)
88
+ Date: march 2014
89
+ License: [MIT-license](https://github.com/avdgaag/lugg/LICENSE) (same as Ruby)
data/Rakefile ADDED
@@ -0,0 +1,25 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ desc 'Default: run specs.'
4
+ task default: %i[spec rubocop doc]
5
+
6
+ require 'rspec/core/rake_task'
7
+ desc 'Run specs'
8
+ RSpec::Core::RakeTask.new
9
+
10
+ require 'yard'
11
+ desc 'Generate API docs'
12
+ YARD::Rake::YardocTask.new :doc
13
+
14
+ require 'rubocop/rake_task'
15
+ desc 'Check source code against Ruby style guide'
16
+ Rubocop::RakeTask.new
17
+
18
+ desc 'Start Irb with Lugg pre-loaded'
19
+ task :console do
20
+ require 'irb'
21
+ require 'irb/completion'
22
+ require 'lugg'
23
+ ARGV.clear
24
+ IRB.start
25
+ end
data/bin/lugg ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby -w
2
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
3
+ require 'lugg'
4
+ Lugg::Runner.new(ARGV).run(ARGF)
@@ -0,0 +1,60 @@
1
+ module Lugg
2
+ # Apply a list of filters to an Enumerable object or an enumerator.
3
+ #
4
+ # This class is used to combine all the search queries into a single filter
5
+ # to process a collection with. Its input is expected to be a
6
+ # `Lugg::Streamer` enumerator, but it could be anything.
7
+ #
8
+ # By default, the collection will be passed through as-is, but you can add
9
+ # more conditions to limit the results with either callable objects (such as
10
+ # Procs) or with blocks.
11
+ #
12
+ # @example Using a proc
13
+ # filter = Filter.new
14
+ # filter.use ->(record) { record.method == 'GET' }
15
+ #
16
+ # @example Using a block
17
+ # filter = Filter.new
18
+ # filter.use { |record| record.code == 404 }
19
+ class Filter
20
+ def initialize
21
+ @conditions = []
22
+ end
23
+
24
+ # Apply all known conditions to `records`.
25
+ #
26
+ # @param [Enumerable] records
27
+ # @return [Enumerable] filtered records
28
+ def call(records)
29
+ return records unless @conditions.any?
30
+ records.select do |record|
31
+ matches?(record)
32
+ end
33
+ end
34
+
35
+ # Store a new condition to be used on the next invocation of {#call}.
36
+ #
37
+ # @param [#call] callable
38
+ # @raise ArgumentError when both a callable or block are given
39
+ # @raise ArgumentError when the given callable does not respond to #call
40
+ def use(callable = nil, &block)
41
+ unless block_given? ^ callable
42
+ raise ArgumentError, 'Supply either an argument or a block'
43
+ end
44
+
45
+ unless block_given? || callable.respond_to?(:call)
46
+ raise ArgumentError, 'Supply either a callable argument or a block'
47
+ end
48
+
49
+ @conditions << (block_given? ? block : callable)
50
+ end
51
+
52
+ private
53
+
54
+ def matches?(record)
55
+ @conditions.any? do |condition|
56
+ condition.call(record)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,81 @@
1
+ require 'time'
2
+
3
+ module Lugg
4
+ # Request is a value object representing a single log entry from start to
5
+ # finish. Its value is the original source text from the log file, but it
6
+ # defines various reader methods to extract useful information from it.
7
+ #
8
+ # Note that a request is frozen once created. Two {Request} objects with
9
+ # the same source are considered equal.
10
+ #
11
+ # @todo optimise performance
12
+ class Request
13
+ attr_reader :source, :hash
14
+
15
+ def initialize(source)
16
+ @source = source
17
+ @hash = self.class.hash ^ source.hash
18
+ freeze
19
+ end
20
+
21
+ def eql?(other)
22
+ self.class == other.class && source == other.source
23
+ end
24
+ alias_method :==, :eql?
25
+
26
+ def method
27
+ source[/^Started ([A-Z]+)/, 1]
28
+ end
29
+
30
+ def controller
31
+ source[/^Processing by (\w+)#(\w+) as (\w+)$/, 1]
32
+ end
33
+
34
+ def action
35
+ source[/^Processing by (\w+)#(\w+) as (\w+)$/, 1] + '#' +
36
+ source[/^Processing by (\w+)#(\w+) as (\w+)$/, 2]
37
+ end
38
+
39
+ def format
40
+ source[/^Processing by (\w+)#(\w+) as (\w+)$/, 3]
41
+ end
42
+
43
+ def status
44
+ source[/^Completed (\d+) (\w+)/, 2]
45
+ end
46
+
47
+ def code
48
+ source[/^Completed (\d+) (\w+)/, 1].to_i
49
+ end
50
+
51
+ def ip
52
+ source[/^Started .* for ([0-9\.]+)/, 1]
53
+ end
54
+
55
+ def timestamp
56
+ Time.parse(source[/^Started .* at (.+)$/, 1])
57
+ end
58
+
59
+ def uri
60
+ source[/^Started \w+ "([^"]+)"/, 1]
61
+ end
62
+
63
+ def path
64
+ uri.split('?').first
65
+ end
66
+
67
+ def query
68
+ uri.split('?', 2).last
69
+ end
70
+
71
+ def duration
72
+ source[/^Completed .* in (\d+)ms/, 1].to_i
73
+ end
74
+
75
+ def params
76
+ params_string = source[/^ Parameters: (.+)$/, 1]
77
+ return {} unless params_string
78
+ eval(params_string) rescue {} # rubocop:disable Eval, RescueModifier
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,32 @@
1
+ module Lugg
2
+ # RequestMatcher is a flip-flop conditional, that becomes true when compared
3
+ # to one condition, and then stays true until a new condition. It is used to
4
+ # match log entries in a log file, starting to match when encountering a line
5
+ # with `Starting...` and stopping to match when encountering a line with
6
+ # `Completed...`.
7
+ class RequestMatcher
8
+ def initialize
9
+ @active = false
10
+ @finished = false
11
+ end
12
+
13
+ def active?
14
+ !!@active
15
+ end
16
+
17
+ def finished?
18
+ !!@finished
19
+ end
20
+
21
+ def =~(line) # rubocop:disable OpMethod
22
+ if line =~ /^Started/
23
+ @active = true
24
+ elsif line =~ /^Completed/
25
+ @active = false
26
+ @finished = true
27
+ else
28
+ @active
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,150 @@
1
+ require 'lugg/version'
2
+ require 'lugg/filter'
3
+ require 'lugg/streamer'
4
+ require 'optparse'
5
+ require 'optparse/time'
6
+
7
+ module Lugg
8
+ # The runner defines the command line interface for Lugg, using the other
9
+ # components and defining command line options and their implementations.
10
+ #
11
+ # When creating a Runner object, you pass it your option flags (typically
12
+ # `ARGV`). You can then apply its conditions to an IO object (typically
13
+ # `ARGF`).
14
+ #
15
+ # @todo extract conditions into individual objects.
16
+ class Runner
17
+ attr_reader :filter
18
+ private :filter
19
+
20
+ def initialize(flags = [], filter = Filter.new)
21
+ @filter = filter
22
+ reset
23
+ options.parse!(flags)
24
+ end
25
+
26
+ def run(io)
27
+ filter.call(Streamer.new(io).records).each do |request|
28
+ puts request.source
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def reset
35
+ @combine = false
36
+ @last_block = nil
37
+ end
38
+
39
+ def combine_clauses?
40
+ @combine && @last_block
41
+ end
42
+
43
+ def add_clause(&block)
44
+ if combine_clauses?
45
+ prev_block = @last_block
46
+ filter.use { |r| prev_block.call(r) && block.call(r) }
47
+ reset
48
+ else
49
+ filter.use(&block)
50
+ @last_block = block
51
+ end
52
+ end
53
+
54
+ def options
55
+ @options ||= OptionParser.new do |o|
56
+ o.banner = <<-EOS
57
+ Usage: lugg [options] FILE
58
+
59
+ Parses log entries from FILE or STDIN and uses [options] to control what is
60
+ sent STDOUT.
61
+ EOS
62
+ o.separator ''
63
+
64
+ o.on '--and',
65
+ 'Combine previous and next clause with AND instead of OR' do
66
+ @combine = true
67
+ end
68
+
69
+ %w(get post put delete head patch).each do |verb|
70
+ o.on "--#{verb}", "Limit to #{verb.upcase} requests" do
71
+ add_clause { |r| r.method == verb.upcase }
72
+ end
73
+ end
74
+
75
+ o.on '-c',
76
+ '--controller CONTROLLER',
77
+ 'Limit to requests handled by CONTROLLER' do |controller|
78
+ add_clause { |r| r.controller == controller }
79
+ end
80
+
81
+ o.on '-a',
82
+ '--action CONTROLLER_ACTION',
83
+ 'Limit to requests handled by CONTROLLER_ACTION' do |ca|
84
+ add_clause { |r| r.action == ca }
85
+ end
86
+
87
+ %w(json html xml csv pdf js).each do |format|
88
+ o.on "--#{format}", "Limit to #{format} requests" do
89
+ add_clause { |r| r.format.downcase == format }
90
+ end
91
+ end
92
+
93
+ o.on '-f', '--format FORMAT', 'Limit to FORMAT requests' do |format|
94
+ add_clause { |r| r.format.downcase == format.downcase }
95
+ end
96
+
97
+ o.on '-s',
98
+ '--status CODE',
99
+ 'Limit requests with status code CODE' do |code|
100
+ add_clause { |r| r.code == code }
101
+ end
102
+
103
+ o.on '--since TIME',
104
+ Time,
105
+ 'Limit to requests made after TIME' do |time|
106
+ add_clause { |r| r.timestamp > time }
107
+ end
108
+
109
+ o.on '--until TIME',
110
+ Time,
111
+ 'Limit to requests made before TIME' do |time|
112
+ add_clause { |r| r.timestamp < time }
113
+ end
114
+
115
+ o.on '-d',
116
+ '--duration N',
117
+ Integer,
118
+ 'Limit to requests longer than N ms' do |n|
119
+ add_clause { |r| r.duration > n }
120
+ end
121
+
122
+ o.on '-u',
123
+ '--uri URI',
124
+ Regexp,
125
+ 'Limit to requests matching URI' do |uri|
126
+ add_clause { |r| r.uri =~ uri }
127
+ end
128
+
129
+ o.on '-p',
130
+ '--param KEY=VAL',
131
+ 'Limit to requests with param KEY => VAL' do |param|
132
+ key, value = param.split('=', 2)
133
+ add_clause { |r| r.params[key] == value }
134
+ end
135
+
136
+ o.separator ''
137
+
138
+ o.on_tail '-v', '--version', 'Display version number' do
139
+ puts Lugg::VERSION
140
+ exit
141
+ end
142
+
143
+ o.on_tail '-h', '--help', 'Display this message' do
144
+ puts o
145
+ exit
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,31 @@
1
+ require 'lugg/request'
2
+ require 'lugg/request_matcher'
3
+
4
+ module Lugg
5
+ # The Streamer reads in content from an IO object and returns an Enumerator
6
+ # yielding {Request} objects.
7
+ class Streamer
8
+ attr_reader :io
9
+ private :io
10
+
11
+ def initialize(io)
12
+ @io = io
13
+ end
14
+
15
+ # @return [Enumerator]
16
+ def records # rubocop:disable MethodLength
17
+ Enumerator.new do |yielder|
18
+ buffer = ''
19
+ matcher = RequestMatcher.new
20
+ io.each do |line|
21
+ buffer << line if matcher =~ line
22
+ if matcher.finished?
23
+ yielder << Request.new(buffer)
24
+ matcher = RequestMatcher.new
25
+ buffer = ''
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,3 @@
1
+ module Lugg
2
+ VERSION = '0.0.1'
3
+ end
data/lib/lugg.rb ADDED
@@ -0,0 +1,44 @@
1
+ require 'lugg/version'
2
+ require 'lugg/runner'
3
+
4
+ # A tiny command line utility to search through Rails server log files and
5
+ # display requests that meet certain criteria.
6
+ #
7
+ # Lugg takes one or more files as arguments or input on STDIN and redirects
8
+ # that content to STDOUT -- but not before applying some filters. Content will
9
+ # be parsed as Rails server log files and only the entire log entries matching
10
+ # your criteria are displayed.
11
+ #
12
+ # You supply criteria by passing in command line options. You can see a full
13
+ # list of accepted options by running `lugg -h`:
14
+ #
15
+ # --and Combine previous and next clause with AND instead of OR
16
+ # --get Limit to GET requests
17
+ # --post Limit to POST requests
18
+ # --put Limit to PUT requests
19
+ # --delete Limit to DELETE requests
20
+ # --head Limit to HEAD requests
21
+ # --patch Limit to PATCH requests
22
+ # -c, --controller CONTROLLER Limit to requests handled by CONTROLLER
23
+ # -a, --action CONTROLLER_ACTION Limit to requests handled by CONTROLLER_ACTION
24
+ # --json Limit to json requests
25
+ # --html Limit to html requests
26
+ # --xml Limit to xml requests
27
+ # --csv Limit to csv requests
28
+ # --pdf Limit to pdf requests
29
+ # --js Limit to js requests
30
+ # -f, --format FORMAT Limit to FORMAT requests
31
+ # -s, --status CODE Limit requests with status code CODE
32
+ # --since TIME Limit to requests made after TIME
33
+ # --until TIME Limit to requests made before TIME
34
+ # -d, --duration N Limit to requests longer than N ms
35
+ # -u, --uri URI Limit to requests matching URI
36
+ # -p, --param KEY=VAL Limit to requests with param KEY => VAL
37
+ #
38
+ # -v, --version Display version number
39
+ # -h, --help Display this message
40
+ #
41
+ # Note that all conditions are combined with OR, but you can combine two
42
+ # conditions with the `--and` flag.
43
+ module Lugg
44
+ end
data/lugg.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'lugg/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'lugg'
8
+ spec.version = Lugg::VERSION
9
+ spec.authors = ['Arjan van der Gaag']
10
+ spec.email = ['arjan@kabisa.nl']
11
+ spec.summary = %q{Query Rails log files from the command line.}
12
+ spec.description = <<-EOS
13
+ A tiny command line utility to search through Rails server log files and
14
+ display requests that meet certain criteria.
15
+ EOS
16
+ spec.homepage = 'http://avdgaa.github.io/lugg'
17
+ spec.license = 'MIT'
18
+
19
+ spec.files = `git ls-files -z`.split("\x0")
20
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
21
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
+ spec.require_paths = ['lib']
23
+
24
+ spec.add_development_dependency 'bundler', '~> 1.5'
25
+ spec.add_development_dependency 'rake'
26
+ spec.add_development_dependency 'rspec'
27
+ spec.add_development_dependency 'yard'
28
+ spec.add_development_dependency 'rubocop'
29
+ end