log_query 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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