rack_lineprof 0.1.0

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: 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: []