streamlog 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +15 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +47 -0
  4. data/Rakefile +34 -0
  5. data/app/assets/javascripts/streamlog/application.js +14 -0
  6. data/app/assets/javascripts/streamlog/logs.js +34 -0
  7. data/app/assets/stylesheets/streamlog/application.css +14 -0
  8. data/app/assets/stylesheets/streamlog/logs.css +130 -0
  9. data/app/controllers/streamlog/application_controller.rb +4 -0
  10. data/app/controllers/streamlog/logs_controller.rb +28 -0
  11. data/app/helpers/streamlog/application_helper.rb +4 -0
  12. data/app/helpers/streamlog/logs_helper.rb +4 -0
  13. data/app/views/layouts/streamlog/application.html.erb +14 -0
  14. data/app/views/streamlog/logs/index.html.erb +11 -0
  15. data/config/routes.rb +4 -0
  16. data/lib/streamlog.rb +9 -0
  17. data/lib/streamlog/content_length_with_exclusions.rb +17 -0
  18. data/lib/streamlog/engine.rb +13 -0
  19. data/lib/streamlog/log_colorize.rb +97 -0
  20. data/lib/streamlog/sse.rb +20 -0
  21. data/lib/streamlog/version.rb +3 -0
  22. data/lib/tasks/streamlog_tasks.rake +4 -0
  23. data/test/controllers/streamlog/logs_controller_test.rb +16 -0
  24. data/test/dummy/README.rdoc +28 -0
  25. data/test/dummy/Rakefile +6 -0
  26. data/test/dummy/app/assets/javascripts/application.js +13 -0
  27. data/test/dummy/app/assets/stylesheets/application.css +14 -0
  28. data/test/dummy/app/controllers/application_controller.rb +5 -0
  29. data/test/dummy/app/helpers/application_helper.rb +2 -0
  30. data/test/dummy/app/views/layouts/application.html.erb +15 -0
  31. data/test/dummy/bin/bundle +3 -0
  32. data/test/dummy/bin/rails +4 -0
  33. data/test/dummy/bin/rake +4 -0
  34. data/test/dummy/config.ru +4 -0
  35. data/test/dummy/config/application.rb +23 -0
  36. data/test/dummy/config/boot.rb +5 -0
  37. data/test/dummy/config/database.yml +25 -0
  38. data/test/dummy/config/environment.rb +5 -0
  39. data/test/dummy/config/environments/development.rb +37 -0
  40. data/test/dummy/config/environments/production.rb +83 -0
  41. data/test/dummy/config/environments/test.rb +39 -0
  42. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  43. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  44. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  45. data/test/dummy/config/initializers/inflections.rb +16 -0
  46. data/test/dummy/config/initializers/mime_types.rb +4 -0
  47. data/test/dummy/config/initializers/session_store.rb +3 -0
  48. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  49. data/test/dummy/config/locales/en.yml +23 -0
  50. data/test/dummy/config/routes.rb +4 -0
  51. data/test/dummy/config/secrets.yml +22 -0
  52. data/test/dummy/db/development.sqlite3 +0 -0
  53. data/test/dummy/log/development.log +12713 -0
  54. data/test/dummy/public/404.html +67 -0
  55. data/test/dummy/public/422.html +67 -0
  56. data/test/dummy/public/500.html +66 -0
  57. data/test/dummy/public/favicon.ico +0 -0
  58. data/test/dummy/tmp/cache/assets/development/sprockets/08566920d369f24fb0e0fab666d6533f +0 -0
  59. data/test/dummy/tmp/cache/assets/development/sprockets/0cc19a2b1a79905d88a44c841f3905a7 +0 -0
  60. data/test/dummy/tmp/cache/assets/development/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
  61. data/test/dummy/tmp/cache/assets/development/sprockets/15077dcfc2991f4d53efb227afb355d8 +0 -0
  62. data/test/dummy/tmp/cache/assets/development/sprockets/1e0370339d0fe37d611e41d1753b64a7 +0 -0
  63. data/test/dummy/tmp/cache/assets/development/sprockets/2672f8bcb16682edfcec89e54222e43e +0 -0
  64. data/test/dummy/tmp/cache/assets/development/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
  65. data/test/dummy/tmp/cache/assets/development/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
  66. data/test/dummy/tmp/cache/assets/development/sprockets/3a5e2b558fc8fd85e97118737d640cc8 +0 -0
  67. data/test/dummy/tmp/cache/assets/development/sprockets/55bd36192b21d16d1da18eb7dfc63115 +0 -0
  68. data/test/dummy/tmp/cache/assets/development/sprockets/62ae17f9de91b7ce7f9d5389a82a4af5 +0 -0
  69. data/test/dummy/tmp/cache/assets/development/sprockets/737cb2e025a1ed703455f8b0b6c50705 +0 -0
  70. data/test/dummy/tmp/cache/assets/development/sprockets/a607af0389defa27633daba46cbc840a +0 -0
  71. data/test/dummy/tmp/cache/assets/development/sprockets/a6e7eb2dba0d23cc46af96364c4f3594 +0 -0
  72. data/test/dummy/tmp/cache/assets/development/sprockets/b5eaa04d91d85a3b0ee804a3b8496517 +0 -0
  73. data/test/dummy/tmp/cache/assets/development/sprockets/c1767bfa4fed465c13b09ac150b937b1 +0 -0
  74. data/test/dummy/tmp/cache/assets/development/sprockets/cc93a764cc1ad7c2772f18342be2a007 +0 -0
  75. data/test/dummy/tmp/cache/assets/development/sprockets/cd4fa3bc740d41192a3777a88b7205b5 +0 -0
  76. data/test/dummy/tmp/cache/assets/development/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
  77. data/test/dummy/tmp/cache/assets/development/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
  78. data/test/dummy/tmp/cache/assets/development/sprockets/e3be3a6ce6847d32e038498a4fc2a773 +0 -0
  79. data/test/dummy/tmp/cache/assets/development/sprockets/e75d188293b55f22a5579aba994b4dba +0 -0
  80. data/test/dummy/tmp/cache/assets/development/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
  81. data/test/dummy/tmp/cache/assets/development/sprockets/fc993b8ba5edeca52d799d32cb4cf088 +0 -0
  82. data/test/dummy/tmp/restart.txt +0 -0
  83. data/test/helpers/streamlog/logs_helper_test.rb +6 -0
  84. data/test/integration/navigation_test.rb +10 -0
  85. data/test/streamlog_test.rb +7 -0
  86. data/test/test_helper.rb +15 -0
  87. metadata +249 -0
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YTk1NzM4M2VkZDg4YTFkM2NjNzk2NGVjNGZhOTRhNTI4NTQ3OGNjMg==
5
+ data.tar.gz: !binary |-
6
+ Mzk4NmVhODNmMDNiNDQ5MzcxOGY0Zjc4MWFjYTk4ZTA0ZTI1MzFiNw==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MGY0NmFiNmQ5NWFhNzliNmM4ZDgyMTRhZjE3NzJiYTAwZWFkOWM4Njc3NDgw
10
+ NTM2N2FjZDYxODQ5NjIxZDE1NGVhZTVmZjA2Y2M3OWUyNzZkYzM2M2I3NDY1
11
+ ZDFjMTExZjhjYWQxMzY5MzYxMzQ3YzAxOTdjNTllYzJhZDczN2E=
12
+ data.tar.gz: !binary |-
13
+ OWRmOTY4NmQ3YjUyZDg2MjVmNWY2ZTc4M2MzOWZlMmM4ODRiNzQxMTkyZWUz
14
+ YjM0NmE5MDUzYTkxMDE5OWQ2MDEzMjBkMDVhMTcwOWE3ZWI3YjBmZWM0ZWQ5
15
+ ZmZkNmI4Mzg3YjQwNDhlNGY1YWQ2YjM2MTNjOTdmNjJiNzZmOTE=
@@ -0,0 +1,20 @@
1
+ Copyright 2014 Salman Siddiqui
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,47 @@
1
+ # Streamlog
2
+
3
+ Streamlog is a Rails Mountable Engine. It streams rails application log to the browser. It is an alternative to [Browserlog](https://coveralls.io/r/dieb/browserlog).
4
+ Browserlog is based on polling while streamlog streams the log.
5
+
6
+ ## Installation
7
+
8
+ Simply add it to your `Gemfile`
9
+
10
+ ```ruby
11
+ gem 'streamlog'
12
+ ```
13
+
14
+ And then mount this rails engine on `config/routes.rb`
15
+
16
+ ```ruby
17
+ Rails.application.routes.draw do
18
+ mount Streamlog::Engine => '/streamlog'
19
+ end
20
+ ```
21
+
22
+ This will make the log available at ``domain/streamlog``. Make sure to authenticate this route.
23
+
24
+ ### Using your app layout
25
+
26
+ Create ``streamlog.rb`` in ``config/initializers``, and add the following line in it.
27
+
28
+ ```ruby
29
+ Streamlog.engine_layout = false
30
+ ```
31
+
32
+ Then add the following line in your layout ``head`` tag
33
+
34
+ ```ruby
35
+ <% yield :head %>
36
+ ```
37
+
38
+ This will use your application layout to load streamlog view.
39
+
40
+ ## Note
41
+
42
+ You will need to install passenger with nginx/apache on your local machine to achieve concurrency and be able to test streamlog.
43
+ [GoRails](https://gorails.com/deploy/ubuntu/14.04) is a guide to setup Passenger with nginx.
44
+
45
+ ## Supported Rails Version
46
+
47
+ * Rails >= 4.1
@@ -0,0 +1,34 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Streamlog'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path('../test/dummy/Rakefile', __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+
22
+ Bundler::GemHelper.install_tasks
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'lib'
28
+ t.libs << 'test'
29
+ t.pattern = 'test/**/*_test.rb'
30
+ t.verbose = false
31
+ end
32
+
33
+
34
+ task default: :test
@@ -0,0 +1,14 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require jquery
14
+ //= require_tree .
@@ -0,0 +1,34 @@
1
+ $(document).ready(function () {
2
+ var autoScroll = true;
3
+
4
+ function startAutoScroll() {
5
+ $("#streamlog-resume").addClass('streamlog-hidden');
6
+ autoScroll = true;
7
+ }
8
+
9
+ function stopAutoScroll() {
10
+ $("#streamlog-resume").removeClass('streamlog-hidden');
11
+ autoScroll = false;
12
+ }
13
+
14
+ function scrollToBottom() {
15
+ window.scrollTo(0, document.body.scrollHeight);
16
+ }
17
+
18
+ var source = new EventSource('/streamlog/stream');
19
+
20
+ source.addEventListener('message', function (e) {
21
+ $("<p>" + JSON.parse(e.data) + "</p>").insertBefore(".streamlog-cursor");
22
+ if (autoScroll)
23
+ scrollToBottom();
24
+ });
25
+
26
+ $("#streamlog-resume").click(scrollToBottom);
27
+
28
+ window.onscroll = function () {
29
+ if ($(window).scrollTop() + $(window).height() == $(document).height())
30
+ startAutoScroll();
31
+ else
32
+ stopAutoScroll();
33
+ };
34
+ });
@@ -0,0 +1,14 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_tree .
14
+ */
@@ -0,0 +1,130 @@
1
+ .streamlog {
2
+ min-width: 500px;
3
+ min-height: 430px;
4
+ background: #272822;
5
+ border-radius: 5px;
6
+ overflow: hidden;
7
+ font-size: 13px;
8
+ }
9
+
10
+ .streamlog-body {
11
+ font-family: Andale Mono, monospace;
12
+ padding: 10px;
13
+ }
14
+
15
+ .streamlog-body p {
16
+ color: #fff;
17
+ padding: 1px 0;
18
+ }
19
+
20
+ @keyframes blink {
21
+ 0% {
22
+ background: rgba(225, 225, 225, 100);
23
+ }
24
+ 100% {
25
+ background: rgba(225, 225, 225, 0);
26
+ }
27
+ }
28
+
29
+ @-webkit-keyframes blink {
30
+ 0% {
31
+ background: rgba(225, 225, 225, 100);
32
+ }
33
+ 100% {
34
+ background: rgba(225, 225, 225, 0);
35
+ }
36
+ }
37
+
38
+ @-moz-keyframes blink {
39
+ 0% {
40
+ background: rgba(225, 225, 225, 100);
41
+ }
42
+ 100% {
43
+ background: rgba(225, 225, 225, 0);
44
+ }
45
+ }
46
+
47
+ .streamlog-cursor {
48
+ background: #63de00;
49
+ display: inline-block;
50
+ width: 11px;
51
+ height: 19px;
52
+ margin-bottom: -3px;
53
+ -webkit-animation-name: blink;
54
+ -webkit-animation-duration: 1.2s;
55
+ -webkit-animation-iteration-count: infinite;
56
+ -moz-animation-name: blink;
57
+ -moz-animation-duration: 1.2s;
58
+ -moz-animation-iteration-count: infinite;
59
+ }
60
+
61
+ .streamlog-hidden {
62
+ display: none !important;
63
+ visibility: hidden !important;
64
+ }
65
+
66
+ #streamlog-resume {
67
+ position: fixed;
68
+ right: 40px;
69
+ bottom: 40px;
70
+ }
71
+
72
+ .log-method {
73
+ color: #C285FF;
74
+ }
75
+
76
+ .log-path {
77
+ color: #85D6FF;
78
+ }
79
+
80
+ .log-ip {
81
+ color: #585856;
82
+ }
83
+
84
+ .log-date {
85
+ color: #585856;
86
+ }
87
+
88
+ .log-controller {
89
+ color: #FF0066;
90
+ }
91
+
92
+ .log-action {
93
+ color: #FF0066;
94
+ }
95
+
96
+ .log-format {
97
+ color: #C285FF;
98
+ }
99
+
100
+ .log-template-name {
101
+ color: #FFFF66;
102
+ }
103
+
104
+ .log-layout-name {
105
+ color: #C285FF;
106
+ }
107
+
108
+ .log-rendering-time {
109
+ color: #85D6FF;
110
+ }
111
+
112
+ .log-model-load {
113
+ color: #da564a;
114
+ }
115
+
116
+ .log-sql-query {
117
+ color: #585856;
118
+ }
119
+
120
+ .log-total-time {
121
+ color: #85D6FF;
122
+ }
123
+
124
+ .log-status.success {
125
+ color: #33D633;
126
+ }
127
+
128
+ .log-status.error {
129
+ color: red;
130
+ }
@@ -0,0 +1,4 @@
1
+ module Streamlog
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,28 @@
1
+ require_dependency 'streamlog/application_controller'
2
+
3
+ module Streamlog
4
+ class LogsController < ApplicationController
5
+ include ActionController::Live
6
+ layout 'application' unless Streamlog.engine_layout
7
+
8
+ def index
9
+ end
10
+
11
+ def stream
12
+ response.headers['Content-Type'] = 'text/event-stream'
13
+
14
+ sse = Streamlog::SSE.new(response.stream)
15
+ colorizer = Streamlog::LogColorize.new
16
+
17
+ begin
18
+ File::Tail::Logfile.tail(Rails.root.join('log', Rails.env+'.log').to_s, backward: 1) do |line|
19
+ sse.write colorizer.colorize_line line
20
+ end
21
+ rescue IOError
22
+ # When the client disconnects, we'll get an IOError on write
23
+ ensure
24
+ sse.close
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,4 @@
1
+ module Streamlog
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Streamlog
2
+ module LogsHelper
3
+ end
4
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Streamlog</title>
5
+ <%= stylesheet_link_tag 'streamlog/application', media: 'all' %>
6
+ <%= javascript_include_tag 'streamlog/application' %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
@@ -0,0 +1,11 @@
1
+ <%= h content_for(:title, 'Server Logs') %>
2
+ <% content_for :head do %>
3
+ <%= javascript_include_tag 'streamlog/application' %>
4
+ <%= stylesheet_link_tag 'streamlog/application' %>
5
+ <% end %>
6
+ <div class="streamlog">
7
+ <div class="streamlog-body">
8
+ <div class="streamlog-cursor"></div>
9
+ </div>
10
+ </div>
11
+ <button class="streamlog-hidden" id="streamlog-resume">Resume</button>
@@ -0,0 +1,4 @@
1
+ Streamlog::Engine.routes.draw do
2
+ get '/' => 'logs#index'
3
+ get '/stream' => 'logs#stream'
4
+ end
@@ -0,0 +1,9 @@
1
+ require 'streamlog/engine'
2
+
3
+ module Streamlog
4
+ autoload :SSE, 'streamlog/sse'
5
+ autoload :LogColorize, 'streamlog/log_colorize'
6
+
7
+ mattr_accessor :engine_layout
8
+ @@engine_layout = true
9
+ end
@@ -0,0 +1,17 @@
1
+ module Rack
2
+ class ContentLengthWithExclusions < ContentLength
3
+ def initialize(app, options = {})
4
+ @app = app
5
+
6
+ @exclude = options[:exclude]
7
+ end
8
+
9
+ def call(env)
10
+ if @exclude && @exclude.call(env)
11
+ @app.call(env)
12
+ else
13
+ super(env)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ require 'streamlog/content_length_with_exclusions'
2
+
3
+ module Streamlog
4
+ class Engine < ::Rails::Engine
5
+ isolate_namespace Streamlog
6
+
7
+ config.middleware.use Rack::ContentLengthWithExclusions, exclude: proc { |env|
8
+ env['PATH_INFO'] == 'streamlog/stream'
9
+ }
10
+ config.preload_frameworks = true
11
+ config.allow_concurrency = true
12
+ end
13
+ end
@@ -0,0 +1,97 @@
1
+ module Streamlog
2
+ class LogColorize
3
+ REXP_REQUEST = /^Started (?<method>\w+) "(?<path>[\w\/\?\&\=\.]+)" for (?<ip>[\d\.]+) at (?<date>[\w:\-\+\s]+)$/
4
+ REXP_CONTROLLER = /^Processing by (?<controller>[\w\:]+)#(?<action>\w+) as (?<format>[\w\/\-\.]+)$/
5
+ REXP_RENDER = /^\s*Rendered (?<path>.*\/)(?<template_name>\w+\.html\.\w+) \((?<rendering_time>[\d+\.]+ms)\)$/
6
+ REXP_RENDER_WITHIN = /^\s*Rendered (?<path>.*\/)(?<template_name>\w+\.html\.\w+) within (?<layout_name>[\w\d\/]+) ?\((?<rendering_time>[\d+\.]+ms)\)$/
7
+ REXP_COMPLETE = /^Completed (?<status>\d+\s\w+) in (?<total_time>[\d+\.]+ms) (?<last_bit>.*)$/
8
+ REXP_SQL_QUERY = /^\s*(?<model_load>[\w:]+ Load) \((?<rendering_time>[\d+\.]+ms)\) \s*(?<sql_query>.*)$/
9
+
10
+ def colorize_line(line)
11
+ line = strip_ansi_colors(line)
12
+ line = colorize(line)
13
+ rescue => e
14
+ puts "Could not colorize: #{e.message}"
15
+ line
16
+ end
17
+
18
+ private
19
+
20
+ def strip_ansi_colors(line)
21
+ line.gsub(/\e\[(\d+)m/, '')
22
+ end
23
+
24
+ def colorize(line)
25
+ case line
26
+ when REXP_REQUEST then colorize_request(line)
27
+ when REXP_CONTROLLER then colorize_controller(line)
28
+ when REXP_RENDER then colorize_render(line)
29
+ when REXP_RENDER_WITHIN then colorize_render_within(line)
30
+ when REXP_COMPLETE then colorize_complete(line)
31
+ when REXP_SQL_QUERY then colorize_sql_query(line)
32
+ else line
33
+ end
34
+ end
35
+
36
+ def span(item, classname)
37
+ "<span class='#{classname}'>#{item}</span>"
38
+ end
39
+
40
+ def space
41
+ '&nbsp;&nbsp;'
42
+ end
43
+
44
+ def colorize_request(line)
45
+ data = regex_parse(line.match(REXP_REQUEST))
46
+ method = span(data[:method], 'log-method')
47
+ path = span(data[:path], 'log-path')
48
+ ip = span(data[:ip], 'log-ip')
49
+ date = span(data[:date], 'log-date')
50
+ "Started #{method} \"#{path}\" for #{ip} at #{date}"
51
+ end
52
+
53
+ def colorize_controller(line)
54
+ data = regex_parse(line.match(REXP_CONTROLLER))
55
+ controller = span(data[:controller], 'log-controller')
56
+ action = span(data[:action], 'log-action')
57
+ format = span(data[:format], 'log-format')
58
+ "Processing by #{controller}##{action} as #{format}"
59
+ end
60
+
61
+ def colorize_render(line)
62
+ data = regex_parse(line.match(REXP_RENDER))
63
+ path = data[:path]
64
+ template_name = span(data[:template_name], 'log-template-name')
65
+ rendering_time = span(data[:rendering_time], 'log-rendering-time')
66
+ "#{space}Rendered #{path}#{template_name} (#{rendering_time})"
67
+ end
68
+
69
+ def colorize_render_within(line)
70
+ data = regex_parse(line.match(REXP_RENDER_WITHIN))
71
+ path = data[:path]
72
+ layout_name = span(data[:layout_name], 'log-layout-name')
73
+ template_name = span(data[:template_name], 'log-template-name')
74
+ rendering_time = span(data[:rendering_time], 'log-rendering-time')
75
+ "#{space}Rendered #{path}#{template_name} within #{layout_name} (#{rendering_time})"
76
+ end
77
+
78
+ def colorize_sql_query(line)
79
+ data = regex_parse(line.match(REXP_SQL_QUERY))
80
+ model_load = span(data[:model_load], 'log-model-load')
81
+ rendering_time = span(data[:rendering_time], 'log-rendering-time')
82
+ sql_query = data[:sql_query]
83
+ "#{space}#{model_load} (#{rendering_time}) #{sql_query}"
84
+ end
85
+
86
+ def colorize_complete(line)
87
+ data = regex_parse(line.match(REXP_COMPLETE))
88
+ status = span(data[:status], data[:status] =~ /^2/ ? 'log-status success' : 'log-status failure')
89
+ total_time = span(data[:total_time], 'log-total-time')
90
+ "Completed #{status} in #{total_time} #{data[:last_bit]}"
91
+ end
92
+
93
+ def regex_parse(match)
94
+ Hash[match.names.collect { |k| k.to_sym }.zip(match.captures)]
95
+ end
96
+ end
97
+ end