browserlog 0.0.1

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.
Files changed (67) hide show
  1. checksums.yaml +15 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +30 -0
  4. data/app/assets/javascripts/browserlog/application.js +14 -0
  5. data/app/assets/javascripts/browserlog/logs.js.coffee +94 -0
  6. data/app/assets/stylesheets/browserlog/application.css +15 -0
  7. data/app/assets/stylesheets/browserlog/dark-theme.css.scss +100 -0
  8. data/app/assets/stylesheets/browserlog/light-theme.css.scss +99 -0
  9. data/app/assets/stylesheets/browserlog/log.css.scss +38 -0
  10. data/app/controllers/browserlog/application_controller.rb +4 -0
  11. data/app/controllers/browserlog/logs_controller.rb +44 -0
  12. data/app/helpers/browserlog/application_helper.rb +4 -0
  13. data/app/helpers/browserlog/logs_helper.rb +4 -0
  14. data/app/views/browserlog/logs/_form.html.erb +17 -0
  15. data/app/views/browserlog/logs/edit.html.erb +6 -0
  16. data/app/views/browserlog/logs/index.html.erb +1 -0
  17. data/app/views/browserlog/logs/new.html.erb +5 -0
  18. data/app/views/browserlog/logs/show.html.erb +4 -0
  19. data/app/views/browserlog/logs/unauthorized.html.erb +0 -0
  20. data/app/views/layouts/browserlog/application.html.erb +21 -0
  21. data/config/routes.rb +4 -0
  22. data/lib/browserlog.rb +12 -0
  23. data/lib/browserlog/config.rb +13 -0
  24. data/lib/browserlog/engine.rb +37 -0
  25. data/lib/browserlog/log_colorize.rb +97 -0
  26. data/lib/browserlog/log_reader.rb +35 -0
  27. data/lib/browserlog/selective_logger.rb +63 -0
  28. data/lib/browserlog/version.rb +3 -0
  29. data/lib/tasks/browserlog_tasks.rake +4 -0
  30. data/spec/dummy/README.rdoc +28 -0
  31. data/spec/dummy/Rakefile +7 -0
  32. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  33. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  34. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  35. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  36. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  37. data/spec/dummy/bin/bundle +3 -0
  38. data/spec/dummy/bin/rails +4 -0
  39. data/spec/dummy/bin/rake +4 -0
  40. data/spec/dummy/config.ru +4 -0
  41. data/spec/dummy/config/application.rb +27 -0
  42. data/spec/dummy/config/boot.rb +5 -0
  43. data/spec/dummy/config/database.yml +19 -0
  44. data/spec/dummy/config/environment.rb +5 -0
  45. data/spec/dummy/config/environments/development.rb +38 -0
  46. data/spec/dummy/config/environments/production.rb +89 -0
  47. data/spec/dummy/config/environments/test.rb +40 -0
  48. data/spec/dummy/config/initializers/backtrace_silencers.rb +9 -0
  49. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  50. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  51. data/spec/dummy/config/initializers/inflections.rb +16 -0
  52. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  53. data/spec/dummy/config/initializers/session_store.rb +3 -0
  54. data/spec/dummy/config/initializers/wrap_parameters.rb +15 -0
  55. data/spec/dummy/config/locales/en.yml +23 -0
  56. data/spec/dummy/config/routes.rb +3 -0
  57. data/spec/dummy/config/secrets.yml +22 -0
  58. data/spec/dummy/db/development.sqlite3 +0 -0
  59. data/spec/dummy/db/schema.rb +16 -0
  60. data/spec/dummy/db/test.sqlite3 +0 -0
  61. data/spec/dummy/log/test.log +40 -0
  62. data/spec/dummy/public/404.html +67 -0
  63. data/spec/dummy/public/422.html +67 -0
  64. data/spec/dummy/public/500.html +66 -0
  65. data/spec/dummy/public/favicon.ico +0 -0
  66. data/spec/spec_helper.rb +19 -0
  67. metadata +188 -0
@@ -0,0 +1,4 @@
1
+ module Browserlog
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Browserlog
2
+ module LogsHelper
3
+ end
4
+ end
@@ -0,0 +1,17 @@
1
+ <%= form_for(@browserlog_log) do |f| %>
2
+ <% if @browserlog_log.errors.any? %>
3
+ <div id="error_explanation">
4
+ <h2><%= pluralize(@browserlog_log.errors.count, "error") %> prohibited this browserlog_log from being saved:</h2>
5
+
6
+ <ul>
7
+ <% @browserlog_log.errors.full_messages.each do |message| %>
8
+ <li><%= message %></li>
9
+ <% end %>
10
+ </ul>
11
+ </div>
12
+ <% end %>
13
+
14
+ <div class="actions">
15
+ <%= f.submit %>
16
+ </div>
17
+ <% end %>
@@ -0,0 +1,6 @@
1
+ <h1>Editing browserlog_log</h1>
2
+
3
+ <%= render 'form' %>
4
+
5
+ <%= link_to 'Show', @browserlog_log %> |
6
+ <%= link_to 'Back', browserlog_logs_path %>
@@ -0,0 +1 @@
1
+ <ul id="lines"></ul>
@@ -0,0 +1,5 @@
1
+ <h1>New browserlog_log</h1>
2
+
3
+ <%= render 'form' %>
4
+
5
+ <%= link_to 'Back', browserlog_logs_path %>
@@ -0,0 +1,4 @@
1
+ <p id="notice"><%= notice %></p>
2
+
3
+ <%= link_to 'Edit', edit_browserlog_log_path(@browserlog_log) %> |
4
+ <%= link_to 'Back', browserlog_logs_path %>
File without changes
@@ -0,0 +1,21 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title><%= @filename %></title>
5
+ <%= stylesheet_link_tag "browserlog/application", media: "all" %>
6
+ <%= javascript_include_tag "browserlog/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body data-theme="light">
10
+
11
+ <%= yield %>
12
+
13
+ <button class="resume-scroll-btn hidden">Resume</button>
14
+
15
+ <select class="theme-switch">
16
+ <option value="dark">Dark</option>
17
+ <option value="light">Light</option>
18
+ </select>
19
+
20
+ </body>
21
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,4 @@
1
+ Browserlog::Engine.routes.draw do
2
+ get ':env', to: 'logs#index'
3
+ get ':env/changes', to: 'logs#changes'
4
+ end
data/lib/browserlog.rb ADDED
@@ -0,0 +1,12 @@
1
+ require 'browserlog/engine'
2
+
3
+ module Browserlog
4
+ autoload :LogReader, 'browserlog/log_reader'
5
+ autoload :LogColorize, 'browserlog/log_colorize'
6
+ autoload :SelectiveLogger, 'browserlog/selective_logger'
7
+ autoload :Config, 'browserlog/config'
8
+
9
+ def self.config
10
+ Config.instance
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ require 'singleton'
2
+
3
+ module Browserlog
4
+ class Config
5
+ include Singleton
6
+
7
+ attr_accessor :allow_production_logs
8
+
9
+ def initialize
10
+ @allow_production_logs = false
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,37 @@
1
+ module Browserlog
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Browserlog
4
+
5
+ config.generators do |g|
6
+ g.test_framework :rspec, fixture: false
7
+ g.assets false
8
+ g.helper false
9
+ end
10
+
11
+ initializer 'browserlog.swap_logger' do |app|
12
+ app.middleware.swap Rails::Rack::Logger, SelectiveLogger
13
+ end
14
+
15
+ def call(env)
16
+ case Rails.version
17
+ when /\A3/
18
+ if SKIP_PATHS.any? { |path| env['PATH_INFO'].include?(path) } ||
19
+ env['SCRIPT_NAME'] =~ /logs/
20
+ silence { super }
21
+ else
22
+ super
23
+ end
24
+ when /\A4/
25
+ Rails.logger.silence { super }
26
+ end
27
+ end
28
+
29
+ def silence(&block)
30
+ prev = Rails.logger.level
31
+ Rails.logger.level = 4
32
+ ret = block.call
33
+ Rails.logger.level = prev
34
+ ret
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,97 @@
1
+ module Browserlog
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], 'method')
47
+ path = span(data[:path], 'path')
48
+ ip = span(data[:ip], 'ip')
49
+ date = span(data[:date], '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], 'controller')
56
+ action = span(data[:action], 'action')
57
+ format = span(data[:format], '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], 'template-name')
65
+ rendering_time = span(data[:rendering_time], '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], 'layout-name')
73
+ template_name = span(data[:template_name], 'template-name')
74
+ rendering_time = span(data[:rendering_time], '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], 'model-load')
81
+ rendering_time = span(data[:rendering_time], '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/ ? 'status success' : 'status failure')
89
+ total_time = span(data[:total_time], '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
@@ -0,0 +1,35 @@
1
+ module Browserlog
2
+ class LogReader
3
+ def read(options = {})
4
+ offset = options[:offset] || -1
5
+ limit = options[:limit] || 25
6
+ amount = [limit, remaining_lines(offset)].min
7
+
8
+ if offset == -1
9
+ line_index = num_lines
10
+ [readlines(amount), line_index]
11
+ else
12
+ line_index = offset + amount
13
+ [readlines(amount), line_index]
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def remaining_lines(offset)
20
+ (offset == -1) ? num_lines : (num_lines - offset)
21
+ end
22
+
23
+ def log_path
24
+ Rails.root.join("log/#{Rails.env}.log")
25
+ end
26
+
27
+ def num_lines
28
+ `wc -l #{log_path}`.split.first.to_i
29
+ end
30
+
31
+ def readlines(amount)
32
+ `tail -n #{amount} #{log_path}`.split(/\n/)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,63 @@
1
+ module Browserlog
2
+ SKIP_PATHS = %w(/changes.json /browserlog/ jquery /logs/).freeze
3
+
4
+ module SelectiveLogger3
5
+ def call_app(request, env)
6
+ if SKIP_PATHS.any? { |path| env['PATH_INFO'].include?(path) }
7
+ @app.call(env)
8
+ else
9
+ # Put some space between requests in development logs.
10
+ if Rails.env.development?
11
+ Rails.logger.info ''
12
+ Rails.logger.info ''
13
+ end
14
+
15
+ Rails.logger.info started_request_message(request)
16
+ @app.call(env)
17
+ end
18
+ ensure
19
+ ActiveSupport::LogSubscriber.flush_all!
20
+ end
21
+ end
22
+
23
+ module SelectiveLogger4
24
+ def call_app(request, env)
25
+ # Put some space between requests in development logs.
26
+ if SKIP_PATHS.any? { |path| env['PATH_INFO'].include?(path) }
27
+ @app.call(env)
28
+ else
29
+ default_behaviour(request, env)
30
+ end
31
+ rescue Exception
32
+ finish(request)
33
+ raise
34
+ ensure
35
+ ActiveSupport::LogSubscriber.flush_all!
36
+ end
37
+
38
+ private
39
+
40
+ def default_behaviour(request, env)
41
+ if development?
42
+ logger.debug ''
43
+ logger.debug ''
44
+ end
45
+
46
+ instrumenter = ActiveSupport::Notifications.instrumenter
47
+ instrumenter.start 'request.action_dispatch', request: request
48
+ logger.info started_request_message(request)
49
+ resp = @app.call(env)
50
+ resp[2] = ::Rack::BodyProxy.new(resp[2]) { finish(request) }
51
+ resp
52
+ end
53
+ end
54
+
55
+ class SelectiveLogger < Rails::Rack::Logger
56
+ case Rails.version
57
+ when /\A3/
58
+ include SelectiveLogger3
59
+ when /\A4/
60
+ include SelectiveLogger4
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,3 @@
1
+ module Browserlog
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :browserlog do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,28 @@
1
+ == README
2
+
3
+ This README would normally document whatever steps are necessary to get the
4
+ application up and running.
5
+
6
+ Things you may want to cover:
7
+
8
+ * Ruby version
9
+
10
+ * System dependencies
11
+
12
+ * Configuration
13
+
14
+ * Database creation
15
+
16
+ * Database initialization
17
+
18
+ * How to run the test suite
19
+
20
+ * Services (job queues, cache servers, search engines, etc.)
21
+
22
+ * Deployment instructions
23
+
24
+ * ...
25
+
26
+
27
+ Please feel free to use a different markup language if you do not plan to run
28
+ <tt>rake doc:app</tt>.
@@ -0,0 +1,7 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically
3
+ # be available to Rake.
4
+
5
+ require File.expand_path('../config/application', __FILE__)
6
+
7
+ Rails.application.load_tasks
@@ -0,0 +1,13 @@
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_tree .
@@ -0,0 +1,15 @@
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
+ *= require_self
15
+ */
@@ -0,0 +1,5 @@
1
+ class ApplicationController < ActionController::Base
2
+ # Prevent CSRF attacks by raising an exception.
3
+ # For APIs, you may want to use :null_session instead.
4
+ protect_from_forgery with: :exception
5
+ end