log_query 0.1.1 → 0.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1cefdd467431992b29c7feb20907d6c0f7a5f8f5
4
- data.tar.gz: 523ca2c9fb0133d2a932aa42ad3adcafb785bf1b
3
+ metadata.gz: b6a5eace67508a8f9b304887399b8850934c394e
4
+ data.tar.gz: 40b0398eed248d957935748636fb9cbdb1b6b1a9
5
5
  SHA512:
6
- metadata.gz: d63f2f6f56815c31facb0179102e8e9041cdf2d265065cb545a18c955438c0e6eb214bf891bab89fd7af71a71f62425ed34ded6e93ea4b90ee2fc4aed2e69aaf
7
- data.tar.gz: c49ff3dcedd003d37e63e962d07093281531821711a37643633d3eedf3966452121bc0710e03382e53b3d5379c9367817cf447c2269126bd190e68c8b6f31950
6
+ metadata.gz: 1fea3044667c84a0d59691382da0216465d3738480cbd87bb5ab4929e238528e499d8fe378baaea9b4391f29edaa1790e0399a0bac08703249a465ef0c9cc276
7
+ data.tar.gz: 66ca2acebdd27e20842e861848dc2da2eb08fe5eb27d795d6a6513d29b9de801e9d57693f2c79cb5a706850fb14d21d8e791fa2a5d74211190e31cdfe250a816
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # LogQuery
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/log_query`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
3
+ TODO: Add description
6
4
 
7
5
  ## Installation
8
6
 
@@ -16,13 +14,15 @@ And then execute:
16
14
 
17
15
  $ bundle
18
16
 
19
- Or install it yourself as:
17
+ Or install the binary as:
20
18
 
21
19
  $ gem install log_query
22
20
 
23
21
  ## Usage
24
22
 
25
- TODO: Write usage instructions here
23
+ `heroku logs --tail -n 1500 | lq --group_by path --measure service --average --varience --percentile 99`
24
+
25
+ ![log_query usage](/log_query.gif?raw=true)
26
26
 
27
27
  ## Development
28
28
 
data/bin/lq CHANGED
@@ -16,6 +16,7 @@ global_option('-g', '--group_by ATTRIBUTE', 'Attribute to group by')
16
16
  global_option('-m', '--measure ATTRIBUTE', 'Attribute to measure')
17
17
  global_option('-a', '--average', 'Perform average')
18
18
  global_option('-p', '--percentile NUMBER', Integer,'Find nth percentile')
19
+ global_option('-c', '--count', 'Count instances of attribute')
19
20
  global_option('--variance', 'Perform variance')
20
21
 
21
22
  default_command :run
@@ -26,16 +27,35 @@ command :run do |c|
26
27
  screen = Screen.new
27
28
  ARGF.each_line do |line|
28
29
  entry = LogEntry.from_heroku_log_line(line)
29
- entries << entry if entry.message.is_a?(Messages::HerokuRouter)
30
+ message = entry.message
30
31
 
31
- screen.reset
32
- entries.group_by { |e| e.message.send(options.group_by) }.
33
- map { |k, es| [k, DescriptiveStatistics::Stats.new(es.map { |e| e.message.send(options.measure) })] }.
32
+ # check which type group_by is in
33
+ if options.group_by
34
+ unless Messages.class_from_attribute(options.group_by).detect { |klass| message.is_a?(klass) }
35
+ #screen.line("#{options.group_by} is not in #{message.class} with attributes #{message.class&.attributes}")
36
+ next
37
+ end
38
+ end
39
+
40
+ # check which type measure is in
41
+ unless Messages.class_from_attribute(options.measure).detect { |klass| message.is_a?(klass) }
42
+ #screen.line("#{options.measure} is not in #{message.class} with attributes #{message.class&.attributes}")
43
+ next
44
+ end
45
+
46
+ entries << entry
47
+
48
+ data = entries.group_by { |e| e.message.send(options.group_by) } if options.group_by
49
+ data ||= { all: entries }
50
+
51
+ data.
52
+ map { |k, es| [k, DescriptiveStatistics::Stats.new(es.map { |e| e.message.send(options.measure) } )] }.
34
53
  map do |k, stats|
35
54
  line = "#{k}: "
36
55
  line += "mean: #{stats.mean.round(2)} " if options.average
37
56
  line += "variance: #{stats.variance.round(2)} " if options.variance
38
57
  line += "#{options.percentile}th: #{stats.percentile(options.percentile).round(2)} " if options.percentile
58
+ line += "count: #{stats.number} " if options.count
39
59
  screen.line(line)
40
60
  end
41
61
 
@@ -1,12 +1,28 @@
1
1
  require_relative './messages/heroku_router'
2
+ require_relative './messages/heroku_web/rails'
2
3
 
3
4
  module Messages
5
+ def self.class_from_attribute(attr)
6
+ [HerokuRouter, HerokuWeb::Rails].select do |klass|
7
+ klass.attributes.include?(attr.to_sym)
8
+ end
9
+ end
10
+
4
11
  def self.resolve_message(source, dyno)
5
12
  case [source, dyno]
13
+ when HerokuWeb::Rails
14
+ HerokuWeb::Rails
6
15
  when HerokuRouter
7
16
  HerokuRouter
8
17
  else
9
18
  String
10
19
  end
11
20
  end
21
+
22
+ # A wrapper for native string class
23
+ class String < String
24
+ def self.attributes
25
+ []
26
+ end
27
+ end
12
28
  end
@@ -9,6 +9,10 @@ module Messages
9
9
  ATTRIBUTES = [:sock, :at, :code, :desc, :method, :path, :host, :request_id, :fwd, :dyno, :connect, :service, :status, :bytes]
10
10
  attr_accessor *ATTRIBUTES
11
11
 
12
+ def self.attributes
13
+ ATTRIBUTES
14
+ end
15
+
12
16
  def initialize(message)
13
17
  ATTRIBUTES.
14
18
  select { |attr| message.include?(" #{attr}=") }.
@@ -22,6 +26,7 @@ module Messages
22
26
  end
23
27
  end
24
28
 
29
+
25
30
  def parse_value(value, attribute)
26
31
  case attribute
27
32
  when :sock, :at, :code, :desc, :method, :host, :request_id, :fwd, :dyno, :status
@@ -0,0 +1,44 @@
1
+ module Messages
2
+ module HerokuWeb
3
+ # 2016-10-20T17:19:51.396574+00:00 app[web.1]: Started HEAD "/" for 127.0.0.1 at 2016-10-20 17:19:51 +0000
4
+ # 2016-10-20T17:19:51.508781+00:00 app[web.1]: Processing by HomeController#index as HTML
5
+ # 2016-10-20T17:19:51.575265+00:00 app[web.1]: Rendered home/index.html.erb (53.0ms)
6
+ # 2016-10-20T17:19:51.575470+00:00 app[web.1]: Completed 500 Internal Server Error in 67ms (ActiveRecord: 0.0ms)
7
+ class Rails < MessageTypeMatcher
8
+ source 'app'
9
+ dyno 'web.*'
10
+
11
+ ATTRIBUTES = {
12
+ method: /Started ([^\s]+)/,
13
+ route: /"([^"]+)"/,
14
+ ip_address: /for (([0-9]{1,3}\.){4})/,
15
+ timestamp: /at (.*)$/,
16
+ controller: /Processing by ([^\s]+)/,
17
+ format: /as (.*)$/,
18
+ template: /Rendered ([^\s]+)/,
19
+ render_time: /\(([0-9\.]+?)ms\)/,
20
+ status: /Completed ([^\s]+)/,
21
+ total_time: /in ([0-9\.]+)ms/,
22
+ active_record_time: /ActiveRecord: ([0-9\.])ms/
23
+ }
24
+
25
+ attr_accessor *(ATTRIBUTES.keys)
26
+
27
+ def self.attributes
28
+ ATTRIBUTES.keys
29
+ end
30
+
31
+ def initialize(message)
32
+ ATTRIBUTES.
33
+ select { |attr, regexp| message.match(regexp) }.
34
+ map do |attr, regexp|
35
+ value = message.match(regexp)[0]
36
+ value = Integer(value) rescue value
37
+ [attr, value]
38
+ end.each do |(key, value)|
39
+ instance_variable_set("@#{key}", value)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -13,7 +13,7 @@ module Messages
13
13
  end
14
14
 
15
15
  def self.===((source, dyno))
16
- @source == source and @dyno == dyno
16
+ source.match("^#{@source}$") and dyno.match("^#{dyno}$")
17
17
  end
18
18
  end
19
19
  end
@@ -1,20 +1,53 @@
1
1
  class Screen
2
2
  def initialize
3
- @buffer = ""
4
- @lines = 0
3
+ @old_lines = []
4
+ @new_lines = []
5
+ @current_line = 0
5
6
  end
6
7
 
7
8
  def line(value)
8
- @buffer += "#{value}\n"
9
- @lines += 1
9
+ @new_lines << value
10
+ end
11
+
12
+ def move_to(row)
13
+ #puts "moving to #{row}"
14
+ #puts "current line #{@current_line}"
15
+ diff = row - @current_line
16
+ if diff > 0
17
+ #puts "moving down #{diff.abs}"
18
+ @buffer += "\e[#{diff.abs}B"
19
+ elsif diff < 0
20
+ #puts "moving up #{diff.abs}"
21
+ @buffer += "\e[#{diff.abs}A"
22
+ end
23
+ @current_line += diff
10
24
  end
11
25
 
12
- def reset
13
- @buffer = "\e[K\e[1A" * [0, @lines].max
14
- @lines = 0
26
+ def delete_current_line
27
+ @buffer += "\e[2K"
28
+ end
29
+
30
+ def print_line(line)
31
+ @buffer += "#{line}\n"
32
+ @current_line += 1
15
33
  end
16
34
 
17
35
  def draw
36
+ @buffer = ""
37
+ # pad line buffers
38
+ line_count = [@old_lines.size, @new_lines.size].max
39
+ @old_lines.fill(nil, @old_lines.size, line_count) if @old_lines.size < line_count
40
+ @new_lines.fill(nil, @new_lines.size, line_count) if @new_lines.size < line_count
41
+
42
+ @old_lines.zip(@new_lines).each_with_index do |(old, new), index|
43
+ if old != new
44
+ move_to(index)
45
+ delete_current_line
46
+ print_line(new)
47
+ end
48
+ end
49
+ @old_lines = @new_lines
50
+ @new_lines = []
18
51
  print @buffer
19
52
  end
20
53
  end
@@ -1,3 +1,3 @@
1
1
  module LogQuery
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
Binary file
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: log_query
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jasper Lyons
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-10-20 00:00:00.000000000 Z
11
+ date: 2016-10-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: descriptive_statistics
@@ -74,10 +74,12 @@ files:
74
74
  - lib/log_query/log_entry.rb
75
75
  - lib/log_query/messages.rb
76
76
  - lib/log_query/messages/heroku_router.rb
77
+ - lib/log_query/messages/heroku_web/rails.rb
77
78
  - lib/log_query/messages/message_type_matcher.rb
78
79
  - lib/log_query/screen.rb
79
80
  - lib/log_query/version.rb
80
81
  - log_query.gemspec
82
+ - log_query.gif
81
83
  homepage: https://github.com/releaseplatform/log_query
82
84
  licenses:
83
85
  - MIT