rack_lineprof 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bf63ce2f01c5dbfed1f2bd3dde124c0eb81a95b1
4
+ data.tar.gz: 61800a817dff047d6fa44a752c2166080c4ea3fa
5
+ SHA512:
6
+ metadata.gz: b87932598add64d4d7c97e4d423a92e0e23fe8a8681caa6121bf77a658c37b9d5be0afce778c34b002d5cf96ac70f84bec8f18e45d3692046354dbeb7c22fe2a
7
+ data.tar.gz: 98fb360d03fe208d0d9741ed17239d21e5dba750a970308a6fc1395d223e4c4a558977aad61f7a7fcfff5c1b54b99e9c726cedd5a50e3c764e6fede97ed11b50
@@ -0,0 +1,54 @@
1
+ require 'rblineprof'
2
+ require 'logger'
3
+ require 'term/ansicolor'
4
+
5
+ module Rack
6
+ class Lineprof
7
+ autoload :Sample, 'rack/lineprof/sample'
8
+ autoload :Source, 'rack/lineprof/source'
9
+
10
+ CONTEXT = 0
11
+ NOMINAL = 1
12
+ WARNING = 2
13
+ CRITICAL = 3
14
+
15
+ DEFAULT_LOGGER = if defined?(::Rails)
16
+ if ::Rails.env.development?
17
+ ::Logger.new(STDOUT)
18
+ else
19
+ ::Logger.new(::Rails.root.join('log/profiler.log'))
20
+ end
21
+ else
22
+ ::Logger.new(STDOUT)
23
+ end
24
+
25
+ attr_reader :app, :options
26
+
27
+ def initialize(app, options = {})
28
+ @app, @options = app, options
29
+ end
30
+
31
+ def call(env)
32
+ request = Rack::Request.new(env)
33
+ matcher = request.params['lineprof'] || options[:profile]
34
+ logger = options[:logger] || DEFAULT_LOGGER
35
+
36
+ return @app.call(env) unless matcher
37
+
38
+ response = nil
39
+ profile = lineprof(%r{#{matcher}}) { response = @app.call(env) }
40
+
41
+ logger.error Term::ANSIColor.blue("\n[Rack::Lineprof] #{'=' * 63}") + "\n\n" + format_profile(profile) + "\n"
42
+
43
+ response
44
+ end
45
+
46
+ def format_profile(profile)
47
+ sources = profile.map do |filename, samples|
48
+ Source.new(filename, samples, options)
49
+ end
50
+
51
+ sources.map(&:format).compact.join "\n"
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,32 @@
1
+ module Rack
2
+ class Lineprof
3
+ class Sample < Struct.new :ms, :calls, :line, :code, :level
4
+ def format(colorize = true)
5
+ formatted = if level == CONTEXT
6
+ sprintf " | % 3i %s", line, code
7
+ else
8
+ sprintf "% 6.1fms %5i | % 3i %s", ms, calls, line, code
9
+ end
10
+
11
+ return formatted unless colorize
12
+
13
+ case level
14
+ when CRITICAL
15
+ color.red formatted
16
+ when WARNING
17
+ color.yellow formatted
18
+ when NOMINAL
19
+ color.white formatted
20
+ else # CONTEXT
21
+ color.intense_black formatted
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def color
28
+ Term::ANSIColor
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,81 @@
1
+ module Rack
2
+ class Lineprof
3
+ class Source
4
+ attr_reader :file_name, :raw_samples, :options
5
+
6
+ def initialize(file_name, raw_samples, options = {})
7
+ @file_name, @raw_samples, @options = file_name, raw_samples, options
8
+ end
9
+
10
+ def format
11
+ return nil if samples.empty?
12
+
13
+ formatted = file_name.sub(Dir.pwd + '/', '') + "\n"
14
+
15
+ prev_line = samples.first.line - 1
16
+ samples.each do |sample|
17
+ if sample.line != prev_line + 1
18
+ formatted << color.intense_black(' ' * 14 + '.' * 7) + "\n"
19
+ end
20
+ prev_line = sample.line
21
+
22
+ formatted << sample.format
23
+ end
24
+
25
+ formatted
26
+ end
27
+
28
+ def samples
29
+ @samples ||= begin
30
+ parsed = []
31
+
32
+ raw_samples.each_with_index do |sample, line|
33
+ next if line == 0 # drop file info
34
+
35
+ ms = sample[0] / 1000.0
36
+ calls = sample[2]
37
+
38
+ abnormal = ms >= thresholds[NOMINAL]
39
+ near_abnormal = (line-context..line+context).any? do |near|
40
+ near = [1, near].max
41
+ next unless raw_samples[near]
42
+ (raw_samples[near][0] / 1000.0) >= thresholds[NOMINAL]
43
+ end
44
+
45
+ next unless abnormal or near_abnormal
46
+
47
+ threshold = thresholds.invert.detect { |th, _| ms > th }
48
+ level = threshold ? threshold.last : CONTEXT
49
+
50
+ next unless code = source_lines[line - 1]
51
+ parsed << Sample.new(ms, calls, line, code, level)
52
+ end
53
+
54
+ parsed
55
+ end
56
+ end
57
+
58
+ def source_lines
59
+ @source_lines ||= ::File.open(file_name, 'r').to_a
60
+ end
61
+
62
+ private
63
+
64
+ def color
65
+ Term::ANSIColor
66
+ end
67
+
68
+ def context
69
+ options.fetch :context, 2
70
+ end
71
+
72
+ def thresholds
73
+ @thresholds ||= {
74
+ CRITICAL => 50,
75
+ WARNING => 5,
76
+ NOMINAL => 0.2
77
+ }.merge(options.fetch :thresholds, {})
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,5 @@
1
+ require 'rack'
2
+
3
+ module Rack
4
+ autoload :Lineprof, 'rack/lineprof'
5
+ end
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack_lineprof
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Evan Owen
8
+ - Patrice Lebel
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2017-04-04 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rack
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '1.5'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '1.5'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rblineprof
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: 0.3.7
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: 0.3.7
42
+ - !ruby/object:Gem::Dependency
43
+ name: term-ansicolor
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '1.3'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '1.3'
56
+ description: Rack middleware for rblineprof (github.com/tmm1/rblineprof)
57
+ email:
58
+ - kainosnoema@gmail.com
59
+ - patleb@users.noreply.github.com
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - lib/rack/lineprof.rb
65
+ - lib/rack/lineprof/sample.rb
66
+ - lib/rack/lineprof/source.rb
67
+ - lib/rack_lineprof.rb
68
+ homepage: https://github.com/patleb/rack_lineprof
69
+ licenses:
70
+ - MIT
71
+ metadata: {}
72
+ post_install_message:
73
+ rdoc_options: []
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ requirements: []
87
+ rubyforge_project:
88
+ rubygems_version: 2.5.2
89
+ signing_key:
90
+ specification_version: 4
91
+ summary: Makes line-by-line source code profiling easy.
92
+ test_files: []