class Logster::Middleware::Viewer

Constants

PATH_INFO
REQUEST_METHOD
SCRIPT_NAME

Public Class Methods

new(app) click to toggle source
# File lib/logster/middleware/viewer.rb, line 11
def initialize(app)
  @app = app

  @logs_path = Logster.config.subdirectory || "/logs"
  @path_regex = Regexp.new("^(#{@logs_path}$)|^(#{@logs_path}(/.*))$")
  @store = Logster.store or raise ArgumentError.new("store")

  @assets_path = File.expand_path("../../../../assets", __FILE__)
  @fileserver = Rack::File.new(@assets_path)
end

Public Instance Methods

call(env) click to toggle source
# File lib/logster/middleware/viewer.rb, line 22
def call(env)
  path = env[PATH_INFO]
  script_name = env[SCRIPT_NAME]

  if script_name && script_name.length > 0
    path = script_name + path
  end

  if resource = resolve_path(path)

    if resource =~ /\.js$|\.handlebars$|\.css$/
      env[PATH_INFO] = resource
      # accl redirect is going to be trouble, ensure its bypassed
      env['sendfile.type'] = ''
      @fileserver.call(env)

    elsif resource.start_with?("/messages.json")
      serve_messages(Rack::Request.new(env))

    elsif resource =~ /\/(un)?protect\/([0-9a-f]+)$/
      off = $1 == "un"
      key = $2

      message = Logster.store.get(key)
      unless message
        return [404, {}, ["Message not found"]]
      end

      if off
        if Logster.store.unprotect(key)
          return [301, {"Location" => "#{@logs_path}/show/#{key}?protected=false"}, []]
        else
          return [500, {}, ["Failed"]]
        end
      else
        if Logster.store.protect(key)
          return [301, {"Location" => "#{@logs_path}/show/#{key}?protected=true"}, []]
        else
          return [500, {}, ["Failed"]]
        end
      end

    elsif resource =~ /\/clear$/
      if env[REQUEST_METHOD] != "POST"
        return [405, {}, ["GET not allowed for /clear"]]
      end
      Logster.store.clear
      return [200, {}, ["Messages cleared"]]

    elsif resource =~ /\/show\/([0-9a-f]+)(\.json)?$/
      key = $1
      json = $2 == ".json"

      message = Logster.store.get(key)
      unless message
        return [404, {}, ["Message not found"]]
      end

      if json
        [200, {"Content-Type" => "application/json; charset=utf-8"}, [message.to_json]]
      else
        preload = preload_json({"/show/#{key}.json" => message})
        [200, {"Content-Type" => "text/html; charset=utf-8"}, [body(preload)]]
      end

    elsif resource == "/"
      [200, {"Content-Type" => "text/html; charset=utf-8"}, [body(preload_json)]]

    else
      [404, {}, ["Not found"]]
    end
  else
    @app.call(env)
  end
end

Protected Instance Methods

body(preload) click to toggle source
# File lib/logster/middleware/viewer.rb, line 174
      def body(preload)
<<HTML
<html>
<head>
  #{css("app.css")}
  #{script("external/moment.min.js")}
  #{script("external/jquery.min.js")}
  #{script("external/handlebars.min.js")}
  #{script("external/lodash.min.js")}
  #{script("external/ember.min.js", "external/ember.js")}
  #{handlebars("application")}
  #{handlebars("index")}
  #{handlebars("message")}
  #{handlebars("show")}
  #{component("message-info")}
  #{component("tabbed-section")}
  #{component("tab-contents")}
  #{component("tab-link")}
  <script>
    window.Logger = {
       rootPath: "#{@logs_path}",
       preload: #{JSON.fast_generate(preload)}
    };
  </script>
</head>
<body>
  #{script("app.js")}
  <script>
    App.Router.reopen({
      rootURL: Logger.rootPath,
      location: 'history'
    });
  </script>
</body>
</html>
HTML
      end
component(name) click to toggle source
# File lib/logster/middleware/viewer.rb, line 157
def component(name)
  ember_template("components/#{name}", "components/" << name)
end
css(name, attrs={}) click to toggle source
# File lib/logster/middleware/viewer.rb, line 144
def css(name, attrs={})
  attrs = attrs.map do |k,v|
    "#{k}='#{v}'"
  end.join(" ")

  "<link rel='stylesheet' type='text/css' href='#{@logs_path}/stylesheets/#{name}' #{attrs}>"
end
ember_template(location, name) click to toggle source
# File lib/logster/middleware/viewer.rb, line 165
      def ember_template(location, name)
        val = File.read("#{@assets_path}/javascript/#{location}.handlebars")
<<JS
      <script>
        Ember.TEMPLATES[#{name.inspect}] = Ember.Handlebars.compile(#{val.inspect});
      </script>
JS
      end
handlebars(name) click to toggle source
# File lib/logster/middleware/viewer.rb, line 161
def handlebars(name)
  ember_template("templates/#{name}", name)
end
parse_regex(string) click to toggle source
# File lib/logster/middleware/viewer.rb, line 125
def parse_regex(string)
  if string =~ /\/(.+)\/(.*)/
    s = $1
    flags = Regexp::IGNORECASE if $2 && $2.include?("i")
    Regexp.new(s, flags) rescue nil
  end
end
preload_json(extra={}) click to toggle source
# File lib/logster/middleware/viewer.rb, line 139
def preload_json(extra={})
  values = {}
  values.merge!(extra)
end
resolve_path(path) click to toggle source
# File lib/logster/middleware/viewer.rb, line 133
def resolve_path(path)
  if path =~ @path_regex
    $3 || "/"
  end
end
script(prod, dev=nil) click to toggle source
# File lib/logster/middleware/viewer.rb, line 152
def script(prod, dev=nil)
  name = ENV['DEBUG_JS'] == "1" && dev ? dev : prod
  "<script src='#{@logs_path}/javascript/#{name}'></script>"
end
serve_messages(req) click to toggle source
# File lib/logster/middleware/viewer.rb, line 100
def serve_messages(req)
  opts = {
    before: req["before"],
    after: req["after"]
  }

  if(filter = req["filter"])
    filter = filter.split("_").map{|s| s.to_i}
    opts[:severity] = filter
  end

  if search = req["search"]
    search = (parse_regex(search) || search) if req["regex_search"] == "true"
    opts[:search] = search
  end

  payload = {
    messages: @store.latest(opts),
    total: @store.count
  }

  json = JSON.generate(payload)
  [200, {"Content-Type" => "application/json"}, [json]]
end