roqua-support 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 +7 -0
- data/.gitignore +16 -0
- data/.rspec +1 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +33 -0
- data/LICENSE.txt +22 -0
- data/README.md +54 -0
- data/Rakefile +24 -0
- data/lib/roqua-support.rb +2 -0
- data/lib/roqua-support/version.rb +5 -0
- data/lib/roqua/core_ext/array/stable_sort_by.rb +37 -0
- data/lib/roqua/core_ext/enumerable/sort_by_alphanum.rb +49 -0
- data/lib/roqua/core_ext/fabrication/singleton.rb +8 -0
- data/lib/roqua/core_ext/fixnum/clamp.rb +8 -0
- data/lib/roqua/support.rb +14 -0
- data/lib/roqua/support/command_runner.rb +24 -0
- data/lib/roqua/support/log_wrapper.rb +34 -0
- data/lib/roqua/support/logging.rb +26 -0
- data/lib/roqua/support/request_logger.rb +108 -0
- data/roqua-support.gemspec +26 -0
- data/spec/roqua/core_ext/array/stable_sort_by_spec.rb +40 -0
- data/spec/roqua/core_ext/enumerable/sort_by_alphanum_spec.rb +21 -0
- data/spec/roqua/core_ext/fabrication/singleton_spec.rb +16 -0
- data/spec/roqua/core_ext/fixnum/clamp_spec.rb +23 -0
- data/spec/roqua/support/logging_spec.rb +86 -0
- data/spec/roqua/support/request_logger_spec.rb +147 -0
- data/spec/roqua/support_spec.rb +19 -0
- metadata +133 -0
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            SHA1:
         | 
| 3 | 
            +
              metadata.gz: 4aa0d44014dfb644f0d1c89f6d1fc7bf161bd69d
         | 
| 4 | 
            +
              data.tar.gz: 480bec91ad5b3b5687c365c82c642302a2fe8064
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: 45cdd38e1b846d5456efe2eb76d9cb5757ed6f0d25badb43e74bcb7db2e0626118986077cda6e588a48e416c76fd2e0b56002f70a97c58e09c55e4f81cab963f
         | 
| 7 | 
            +
              data.tar.gz: 87bbbd4f07f04b89f9f07674ee2253d3de81ab078c445c7d34d167869e74b999f200f83c62ca02cb39f356e66fe2c3aabb171f9eb22192b8131e68c32b9f7922
         | 
    
        data/.gitignore
    ADDED
    
    
    
        data/.rspec
    ADDED
    
    | @@ -0,0 +1 @@ | |
| 1 | 
            +
            --color
         | 
    
        data/.travis.yml
    ADDED
    
    
    
        data/Gemfile
    ADDED
    
    
    
        data/Gemfile.lock
    ADDED
    
    | @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            PATH
         | 
| 2 | 
            +
              remote: .
         | 
| 3 | 
            +
              specs:
         | 
| 4 | 
            +
                roqua-support (0.1.0)
         | 
| 5 | 
            +
                  activesupport (~> 3.2)
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            GEM
         | 
| 8 | 
            +
              remote: https://rubygems.org/
         | 
| 9 | 
            +
              specs:
         | 
| 10 | 
            +
                activesupport (3.2.16)
         | 
| 11 | 
            +
                  i18n (~> 0.6, >= 0.6.4)
         | 
| 12 | 
            +
                  multi_json (~> 1.0)
         | 
| 13 | 
            +
                diff-lcs (1.1.3)
         | 
| 14 | 
            +
                i18n (0.6.8)
         | 
| 15 | 
            +
                multi_json (1.8.2)
         | 
| 16 | 
            +
                rake (10.0.3)
         | 
| 17 | 
            +
                rspec (2.12.0)
         | 
| 18 | 
            +
                  rspec-core (~> 2.12.0)
         | 
| 19 | 
            +
                  rspec-expectations (~> 2.12.0)
         | 
| 20 | 
            +
                  rspec-mocks (~> 2.12.0)
         | 
| 21 | 
            +
                rspec-core (2.12.0)
         | 
| 22 | 
            +
                rspec-expectations (2.12.0)
         | 
| 23 | 
            +
                  diff-lcs (~> 1.1.3)
         | 
| 24 | 
            +
                rspec-mocks (2.12.0)
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            PLATFORMS
         | 
| 27 | 
            +
              ruby
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            DEPENDENCIES
         | 
| 30 | 
            +
              bundler (~> 1.0)
         | 
| 31 | 
            +
              rake
         | 
| 32 | 
            +
              roqua-support!
         | 
| 33 | 
            +
              rspec (~> 2.12.0)
         | 
    
        data/LICENSE.txt
    ADDED
    
    | @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            Copyright (c) 2012 RoQua
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            MIT License
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Permission is hereby granted, free of charge, to any person obtaining
         | 
| 6 | 
            +
            a copy of this software and associated documentation files (the
         | 
| 7 | 
            +
            "Software"), to deal in the Software without restriction, including
         | 
| 8 | 
            +
            without limitation the rights to use, copy, modify, merge, publish,
         | 
| 9 | 
            +
            distribute, sublicense, and/or sell copies of the Software, and to
         | 
| 10 | 
            +
            permit persons to whom the Software is furnished to do so, subject to
         | 
| 11 | 
            +
            the following conditions:
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            The above copyright notice and this permission notice shall be
         | 
| 14 | 
            +
            included in all copies or substantial portions of the Software.
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         | 
| 17 | 
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         | 
| 18 | 
            +
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         | 
| 19 | 
            +
            NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         | 
| 20 | 
            +
            LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         | 
| 21 | 
            +
            OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         | 
| 22 | 
            +
            WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         | 
    
        data/README.md
    ADDED
    
    | @@ -0,0 +1,54 @@ | |
| 1 | 
            +
            # Roqua::Support
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            This gem contains all sorts of support utilities and helper methods that are
         | 
| 4 | 
            +
            useful to have in RoQua's applications, but have nothing to with the domain.
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            ## Usage
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            ### Logging
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            ```ruby
         | 
| 11 | 
            +
            class Example
         | 
| 12 | 
            +
              include Roqua::Logging
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              def methodname
         | 
| 15 | 
            +
                # This writes a single line to the event log with
         | 
| 16 | 
            +
                # the given event name and parameters as key=value format.
         | 
| 17 | 
            +
                eventlog.info 'example.eventname', optional: 'extra parameters'
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              def another
         | 
| 21 | 
            +
                # This automatically emits two lines, one for when the
         | 
| 22 | 
            +
                # block begins, one for when the block ends. ':started',
         | 
| 23 | 
            +
                # ':finished', ':failed' are appended to the event name
         | 
| 24 | 
            +
                # given, and the duration of the block is logged with
         | 
| 25 | 
            +
                # the :finished log line.
         | 
| 26 | 
            +
                eventlog.lifecycle 'example.lifecycle', optional: 'params' do
         | 
| 27 | 
            +
                  sleep 5
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
              def third
         | 
| 32 | 
            +
                # This example is the same as the `another` example.
         | 
| 33 | 
            +
                sleep 5
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
              log :third, 'example.lifecycle', optional: 'params'
         | 
| 36 | 
            +
            end
         | 
| 37 | 
            +
            ```
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            ### Rails logger
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            You can also add an additional request logger by adding this to `config/initializers/request_logger.rb`:
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            ```ruby
         | 
| 44 | 
            +
            require 'roqua/support/request_logger'
         | 
| 45 | 
            +
            Roqua::Support::RequestLogger.attach_to :action_controller
         | 
| 46 | 
            +
            ```
         | 
| 47 | 
            +
             | 
| 48 | 
            +
            ## Contributing
         | 
| 49 | 
            +
             | 
| 50 | 
            +
            1. Fork it
         | 
| 51 | 
            +
            2. Create your feature branch (`git checkout -b my-new-feature`)
         | 
| 52 | 
            +
            3. Commit your changes (`git commit -am 'Add some feature'`)
         | 
| 53 | 
            +
            4. Push to the branch (`git push origin my-new-feature`)
         | 
| 54 | 
            +
            5. Create new Pull Request
         | 
    
        data/Rakefile
    ADDED
    
    | @@ -0,0 +1,24 @@ | |
| 1 | 
            +
            require 'rubygems'
         | 
| 2 | 
            +
            require 'rake'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            begin
         | 
| 5 | 
            +
              require 'bundler'
         | 
| 6 | 
            +
            rescue LoadError => e
         | 
| 7 | 
            +
              warn e.message
         | 
| 8 | 
            +
              warn "Run `gem install bundler` to install Bundler."
         | 
| 9 | 
            +
              exit -1
         | 
| 10 | 
            +
            end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            begin
         | 
| 13 | 
            +
              Bundler.setup(:development)
         | 
| 14 | 
            +
            rescue Bundler::BundlerError => e
         | 
| 15 | 
            +
              warn e.message
         | 
| 16 | 
            +
              warn "Run `bundle install` to install missing gems."
         | 
| 17 | 
            +
              exit e.status_code
         | 
| 18 | 
            +
            end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            require "bundler/gem_tasks"
         | 
| 21 | 
            +
            require 'rspec/core/rake_task'
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            RSpec::Core::RakeTask.new(:spec)
         | 
| 24 | 
            +
            task :default => :spec
         | 
| @@ -0,0 +1,37 @@ | |
| 1 | 
            +
            class Array
         | 
| 2 | 
            +
              # Method for stably sorting elements in an array on multiple attributes.
         | 
| 3 | 
            +
              #
         | 
| 4 | 
            +
              # * Pass the method a block with two arrays containing the attributes for which the
         | 
| 5 | 
            +
              #   elements should be subsequently sorted. The first attribute is applied last.
         | 
| 6 | 
            +
              #   If for some attribute the sort order should be reversed, the parameters x and y can
         | 
| 7 | 
            +
              #   be exchanged between the arrays.
         | 
| 8 | 
            +
              #
         | 
| 9 | 
            +
              # ==== Example
         | 
| 10 | 
            +
              #   my_array.stable_sort_by{|x, y| [
         | 
| 11 | 
            +
              #                            x.attribute1,
         | 
| 12 | 
            +
              #                            y.attribute2,
         | 
| 13 | 
            +
              #                            y.attribute3,
         | 
| 14 | 
            +
              #                            y.attribute4
         | 
| 15 | 
            +
              #                          ] <=> [
         | 
| 16 | 
            +
              #                            y.attribute1,
         | 
| 17 | 
            +
              #                            x.attribute2,
         | 
| 18 | 
            +
              #                            x.attribute3,
         | 
| 19 | 
            +
              #                            x.attribute4
         | 
| 20 | 
            +
              #                          ]}
         | 
| 21 | 
            +
              #
         | 
| 22 | 
            +
              def stable_sort_by
         | 
| 23 | 
            +
                sort do |x, y|
         | 
| 24 | 
            +
                  if not x
         | 
| 25 | 
            +
                    -1
         | 
| 26 | 
            +
                  elsif not y
         | 
| 27 | 
            +
                    1
         | 
| 28 | 
            +
                  else
         | 
| 29 | 
            +
                    if block_given?
         | 
| 30 | 
            +
                      yield x, y
         | 
| 31 | 
            +
                    else
         | 
| 32 | 
            +
                      x <=> y
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
            end
         | 
| @@ -0,0 +1,49 @@ | |
| 1 | 
            +
            module Enumerable
         | 
| 2 | 
            +
              def sort_by_alphanum
         | 
| 3 | 
            +
                sort do |a, b|
         | 
| 4 | 
            +
                  if block_given?
         | 
| 5 | 
            +
                    grouped_compare(yield(a), yield(b))
         | 
| 6 | 
            +
                  else
         | 
| 7 | 
            +
                    grouped_compare(a, b)
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              def sort_by_alphanum!
         | 
| 13 | 
            +
                sort! do |a, b|
         | 
| 14 | 
            +
                  if block_given?
         | 
| 15 | 
            +
                    grouped_compare(yield(a), yield(b))
         | 
| 16 | 
            +
                  else
         | 
| 17 | 
            +
                    grouped_compare(a, b)
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              private
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              def grouped_compare(a, b)
         | 
| 25 | 
            +
                loop {
         | 
| 26 | 
            +
                  a_chunk, a = extract_alpha_or_number_group(a)
         | 
| 27 | 
            +
                  b_chunk, b = extract_alpha_or_number_group(b)
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  ret = if a_chunk =~ /\d/ and b_chunk =~ /\d/
         | 
| 30 | 
            +
                          a_chunk.to_i <=> b_chunk.to_i
         | 
| 31 | 
            +
                        else
         | 
| 32 | 
            +
                          a_chunk <=> b_chunk
         | 
| 33 | 
            +
                        end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  return -1 if a_chunk == ''
         | 
| 36 | 
            +
                  return ret if ret != 0
         | 
| 37 | 
            +
                }
         | 
| 38 | 
            +
              end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              def extract_alpha_or_number_group(item)
         | 
| 41 | 
            +
                matchdata = /([A-Za-z]+|[\d]+)/.match(item)
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                if matchdata.nil?
         | 
| 44 | 
            +
                  ["", ""]
         | 
| 45 | 
            +
                else
         | 
| 46 | 
            +
                  [matchdata[0], item = item[matchdata.offset(0)[1] .. -1]]
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
              end
         | 
| 49 | 
            +
            end
         | 
| @@ -0,0 +1,24 @@ | |
| 1 | 
            +
            require 'pty'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module CommandRunner
         | 
| 4 | 
            +
              def self.run_command_and_print(cmd, output)
         | 
| 5 | 
            +
                output.puts "[1mExecuting #{cmd}[0m\n\n"
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                PTY.spawn(cmd) do |read_stream, write_stream, pid|
         | 
| 8 | 
            +
                  begin
         | 
| 9 | 
            +
                    while chars = read_stream.read(1)
         | 
| 10 | 
            +
                      output.print chars
         | 
| 11 | 
            +
                    end
         | 
| 12 | 
            +
                  rescue Errno::EIO
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
                  Process.wait(pid)
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
                output.puts "\n\n\n"
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                if $?
         | 
| 19 | 
            +
                  exit 1 if $?.exitstatus > 0
         | 
| 20 | 
            +
                else
         | 
| 21 | 
            +
                  raise "Huh?! We didn't get an exit status from that last one: #{cmd}"
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
            end
         | 
| @@ -0,0 +1,34 @@ | |
| 1 | 
            +
            require 'json'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Roqua
         | 
| 4 | 
            +
              class LogWrapper
         | 
| 5 | 
            +
                attr_reader :logger
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def initialize(logger)
         | 
| 8 | 
            +
                  @logger = logger
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def add(level, message, options = {})
         | 
| 12 | 
            +
                  logger.send(level, "#{message} #{options.to_json}".strip)
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                [:fatal, :error, :warn, :info, :debug].each do |level|
         | 
| 16 | 
            +
                  define_method(level) do |*args|
         | 
| 17 | 
            +
                    add(level, *args)
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def lifecycle(message, options = {})
         | 
| 22 | 
            +
                  started_at = Time.now.to_f
         | 
| 23 | 
            +
                  info("#{message}:started", options)
         | 
| 24 | 
            +
                  value = yield
         | 
| 25 | 
            +
                  finished_at = Time.now.to_f
         | 
| 26 | 
            +
                  duration = finished_at - started_at
         | 
| 27 | 
            +
                  info("#{message}:finished", {duration: duration}.merge(options))
         | 
| 28 | 
            +
                  value
         | 
| 29 | 
            +
                rescue => e
         | 
| 30 | 
            +
                  error("#{message}:failed", {exception: e.class, message: e.message}.merge(options))
         | 
| 31 | 
            +
                  raise
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
            end
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            require 'active_support/core_ext/module/aliasing'
         | 
| 2 | 
            +
            require 'roqua/support/log_wrapper'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Roqua
         | 
| 5 | 
            +
              module Logging
         | 
| 6 | 
            +
                def self.included(base)
         | 
| 7 | 
            +
                  base.extend ClassMethods
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                module ClassMethods
         | 
| 11 | 
            +
                  def log(method_name, message, options = {})
         | 
| 12 | 
            +
                    define_method(:"#{method_name}_with_log") do |*args, &block|
         | 
| 13 | 
            +
                      eventlog.lifecycle(message, options) do
         | 
| 14 | 
            +
                        send(:"#{method_name}_without_log", *args, &block)
         | 
| 15 | 
            +
                      end
         | 
| 16 | 
            +
                    end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                    alias_method_chain method_name, 'log'
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def eventlog
         | 
| 23 | 
            +
                  Roqua.logger
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         | 
| @@ -0,0 +1,108 @@ | |
| 1 | 
            +
            require 'roqua/support'
         | 
| 2 | 
            +
            require 'active_support/log_subscriber'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Roqua
         | 
| 5 | 
            +
              module Support
         | 
| 6 | 
            +
                module RequestLogging
         | 
| 7 | 
            +
                  def add_log_information(key, value)
         | 
| 8 | 
            +
                    Thread.current[:roqua_request_log] ||= {}
         | 
| 9 | 
            +
                    Thread.current[:roqua_request_log][key] = value
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                class RequestLogger < ActiveSupport::LogSubscriber
         | 
| 14 | 
            +
                  include Roqua::Logging
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def process_action(event)
         | 
| 17 | 
            +
                    payload = event.payload
         | 
| 18 | 
            +
                    extra_logged_information = Thread.current[:roqua_request_log] || {}
         | 
| 19 | 
            +
                    Thread.current[:roqua_request_log] = {}
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                    data      = extract_request_id(event)
         | 
| 22 | 
            +
                    data.merge! extract_request(payload)
         | 
| 23 | 
            +
                    data.merge! extract_status(payload)
         | 
| 24 | 
            +
                    data.merge! extract_parameters(payload)
         | 
| 25 | 
            +
                    data.merge! redirect_information
         | 
| 26 | 
            +
                    data.merge! extra_logged_information
         | 
| 27 | 
            +
                    data.merge! runtimes(event)
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                    #eventlog.info event.inspect
         | 
| 30 | 
            +
                    eventlog.info 'roqua.web', data
         | 
| 31 | 
            +
                  rescue Exception => e
         | 
| 32 | 
            +
                    eventlog.info 'roqua.web:logerror', {class: e.class, message: e.message}
         | 
| 33 | 
            +
                    raise
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  def redirect_to(event)
         | 
| 37 | 
            +
                    # Unfortunately, when a redirect is triggered by your application's code,
         | 
| 38 | 
            +
                    # ActionController fires two events. One for the redirect itself, and
         | 
| 39 | 
            +
                    # another one when the request is finished. Unfortunately the final event
         | 
| 40 | 
            +
                    # doesn't include the redirect, so we store the redirect URL as a
         | 
| 41 | 
            +
                    # thread-local attribute and refers to it in process_action.
         | 
| 42 | 
            +
                    Thread.current[:roqua_request_log_redirect] = event.payload[:location]
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  private
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                  def extract_request_id(event)
         | 
| 48 | 
            +
                    {uuid: event.transaction_id}
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  def extract_request(payload)
         | 
| 52 | 
            +
                    {
         | 
| 53 | 
            +
                      :method     => payload[:method],
         | 
| 54 | 
            +
                      :path       => extract_path(payload),
         | 
| 55 | 
            +
                      :format     => extract_format(payload),
         | 
| 56 | 
            +
                      :controller => payload[:params]['controller'],
         | 
| 57 | 
            +
                      :action     => payload[:params]['action']
         | 
| 58 | 
            +
                    }
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  def extract_path(payload)
         | 
| 62 | 
            +
                    payload[:path].split("?").first
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                  def extract_format(payload)
         | 
| 66 | 
            +
                    payload[:format]
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                  def extract_status(payload)
         | 
| 70 | 
            +
                    if payload[:status]
         | 
| 71 | 
            +
                      { :status => payload[:status].to_i }
         | 
| 72 | 
            +
                    elsif payload[:exception]
         | 
| 73 | 
            +
                      exception, message = payload[:exception]
         | 
| 74 | 
            +
                      { :status => 500, :error => "#{exception}:#{message}" }
         | 
| 75 | 
            +
                    else
         | 
| 76 | 
            +
                      { :status => 0 }
         | 
| 77 | 
            +
                    end
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                  def redirect_information
         | 
| 81 | 
            +
                    if location = Thread.current[:roqua_request_log_redirect]
         | 
| 82 | 
            +
                      Thread.current[:roqua_request_log_redirect] = nil
         | 
| 83 | 
            +
                      {location: location}
         | 
| 84 | 
            +
                    else
         | 
| 85 | 
            +
                      {}
         | 
| 86 | 
            +
                    end
         | 
| 87 | 
            +
                  end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                  def extract_parameters(payload)
         | 
| 90 | 
            +
                    filtered_params = payload[:params].reject do |key, value|
         | 
| 91 | 
            +
                      key == 'controller' or key == 'action'
         | 
| 92 | 
            +
                    end
         | 
| 93 | 
            +
                    {params: filtered_params}
         | 
| 94 | 
            +
                  end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                  def runtimes(event)
         | 
| 97 | 
            +
                    {
         | 
| 98 | 
            +
                      :duration => event.duration,
         | 
| 99 | 
            +
                      :view => event.payload[:view_runtime],
         | 
| 100 | 
            +
                      :db => event.payload[:db_runtime]
         | 
| 101 | 
            +
                    }.inject({}) do |runtimes, (name, runtime)|
         | 
| 102 | 
            +
                      runtimes[name] = runtime.to_f.round(2) if runtime
         | 
| 103 | 
            +
                      runtimes
         | 
| 104 | 
            +
                    end
         | 
| 105 | 
            +
                  end
         | 
| 106 | 
            +
                end
         | 
| 107 | 
            +
              end
         | 
| 108 | 
            +
            end
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            # -*- encoding: utf-8 -*-
         | 
| 2 | 
            +
            lib = File.expand_path('../lib', __FILE__)
         | 
| 3 | 
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         | 
| 4 | 
            +
            require 'roqua-support/version'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            Gem::Specification.new do |gem|
         | 
| 7 | 
            +
              gem.name          = "roqua-support"
         | 
| 8 | 
            +
              gem.version       = Roqua::Support::VERSION
         | 
| 9 | 
            +
              gem.summary       = %q{Helper objects and proxies used by a lot of RoQua applications}
         | 
| 10 | 
            +
              gem.description   = %q{Logging backend, freedom patches, }
         | 
| 11 | 
            +
              gem.license       = "MIT"
         | 
| 12 | 
            +
              gem.authors       = ["Marten Veldthuis"]
         | 
| 13 | 
            +
              gem.email         = "marten@roqua.nl"
         | 
| 14 | 
            +
              gem.homepage      = "https://github.com/roqua/healthy"
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              gem.files         = `git ls-files`.split($/)
         | 
| 17 | 
            +
              gem.executables   = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
         | 
| 18 | 
            +
              gem.test_files    = gem.files.grep(%r{^(test|spec|features)/})
         | 
| 19 | 
            +
              gem.require_paths = ["lib"]
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              gem.add_dependency 'activesupport', '~> 3.2'
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              gem.add_development_dependency 'bundler', '~> 1.0'
         | 
| 24 | 
            +
              gem.add_development_dependency 'rake'
         | 
| 25 | 
            +
              gem.add_development_dependency 'rspec', '~> 2.12.0'
         | 
| 26 | 
            +
            end
         | 
| @@ -0,0 +1,40 @@ | |
| 1 | 
            +
            require 'roqua/core_ext/array/stable_sort_by'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe Array do
         | 
| 4 | 
            +
              describe "#stable_sort_by" do
         | 
| 5 | 
            +
                it "wraps #sort" do
         | 
| 6 | 
            +
                  array = []
         | 
| 7 | 
            +
                  array.should_receive(:sort)
         | 
| 8 | 
            +
                  array.stable_sort_by
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                it "sorts nil values before all others" do
         | 
| 12 | 
            +
                  [1, nil, 3].stable_sort_by.should == [nil, 1, 3]
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                it "defaults to regular comparison" do
         | 
| 16 | 
            +
                  [1, 3, 2].stable_sort_by.should == [1, 2, 3]
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                it "accepts a block to do complex comparison" do
         | 
| 20 | 
            +
                  [{a: 2, b: 2, c: 3},
         | 
| 21 | 
            +
                   {a: 2, b: 2, c: 4},
         | 
| 22 | 
            +
                   {a: 1, b: 1, c: 6}].stable_sort_by do |x, y|
         | 
| 23 | 
            +
                    [x[:a], x[:b], x[:c]] <=> [y[:a], y[:b], y[:c]]
         | 
| 24 | 
            +
                   end.should == [{a: 1, b: 1, c: 6},
         | 
| 25 | 
            +
                                  {a: 2, b: 2, c: 3},
         | 
| 26 | 
            +
                                  {a: 2, b: 2, c: 4}]
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                it "leaves items in original order if they are the same" do
         | 
| 30 | 
            +
                  [{a: 2, b: 2, c: 4},
         | 
| 31 | 
            +
                   {a: 2, b: 1, c: 3},
         | 
| 32 | 
            +
                   {a: 1, b: 3, c: 6}].sort do |x, y|
         | 
| 33 | 
            +
                    [x[:a], x[:b]] <=> [y[:a], y[:b]]
         | 
| 34 | 
            +
                   end.should == [{a: 1, b: 3, c: 6},
         | 
| 35 | 
            +
                                  {a: 2, b: 1, c: 3},
         | 
| 36 | 
            +
                                  {a: 2, b: 2, c: 4}]
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
            end
         | 
| @@ -0,0 +1,21 @@ | |
| 1 | 
            +
            require 'roqua/core_ext/enumerable/sort_by_alphanum'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe Enumerable do
         | 
| 4 | 
            +
              describe '#sort_by_alphanum' do
         | 
| 5 | 
            +
                it 'sorts by chunks' do
         | 
| 6 | 
            +
                  ["004some11thing",
         | 
| 7 | 
            +
                   "004some10thing",
         | 
| 8 | 
            +
                   "3another"].sort_by_alphanum.should == ["3another", "004some10thing", "004some11thing"]
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                it 'can take a block which can transform values before comparison' do
         | 
| 12 | 
            +
                  ["004some11thing",
         | 
| 13 | 
            +
                   "004some10thing",
         | 
| 14 | 
            +
                   "3another"].sort_by_alphanum(&:reverse).should == ["004some10thing", "004some11thing", "3another"]
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                it 'compares number chunks as integers' do
         | 
| 18 | 
            +
                  %w(004 3).sort_by_alphanum.should == %w(3 004)
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
            end
         | 
| @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            require 'roqua/core_ext/fabrication/singleton'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            def Fabricate(name, overrides={}, &block)
         | 
| 4 | 
            +
              rand
         | 
| 5 | 
            +
            end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            describe Fabricate do
         | 
| 8 | 
            +
              it "returns singleton objects" do
         | 
| 9 | 
            +
                Fabricate.singleton(:one).should == Fabricate.singleton(:one)
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              it 'maintains multiple singletons' do
         | 
| 13 | 
            +
                Fabricate.singleton(:one).should_not == Fabricate.singleton(:two)
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| 16 | 
            +
             | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            require 'roqua/core_ext/fixnum/clamp'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe Fixnum do
         | 
| 4 | 
            +
              describe '#clamp' do
         | 
| 5 | 
            +
                it "returns self if within bounds" do
         | 
| 6 | 
            +
                  5.clamp(1,10).should == 5
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                it "returns the lower bound if self < low" do
         | 
| 10 | 
            +
                  5.clamp(8,10).should == 8
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                it "returns the upper bound if self > high" do
         | 
| 14 | 
            +
                  5.clamp(1,3).should == 3
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                it "should raise an exception if the lower bound is greater than the upper bound" do
         | 
| 18 | 
            +
                  expect {
         | 
| 19 | 
            +
                    5.clamp(10,1)
         | 
| 20 | 
            +
                  }.to raise_error
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            end
         | 
| @@ -0,0 +1,86 @@ | |
| 1 | 
            +
            require 'roqua/support/logging'
         | 
| 2 | 
            +
            require 'logger'
         | 
| 3 | 
            +
            require 'stringio'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Roqua
         | 
| 6 | 
            +
              describe LogWrapper do
         | 
| 7 | 
            +
                let(:logstream)  { StringIO.new }
         | 
| 8 | 
            +
                let(:logger)     { Logger.new(logstream) }
         | 
| 9 | 
            +
                let(:logwrapper) { LogWrapper.new(logger) }
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def log
         | 
| 12 | 
            +
                  logstream.string
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                describe '#add' do
         | 
| 16 | 
            +
                  it 'writes event name to log' do
         | 
| 17 | 
            +
                    logwrapper.add :info, "testevent"
         | 
| 18 | 
            +
                    log.should include("testevent {}\n")
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  it 'writes given parameters as json hash' do
         | 
| 22 | 
            +
                    logwrapper.add :info, "testevent", extra: 'params', go: 'here'
         | 
| 23 | 
            +
                    log.should include('testevent {"extra":"params","go":"here"}' + "\n")
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  it 'escapes newline characters in params' do
         | 
| 27 | 
            +
                    logwrapper.add :info, "testevent", param: "this\nshould not have newlines"
         | 
| 28 | 
            +
                    log.should include('testevent {"param":"this\nshould not have newlines"')
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                describe '#lifecycle' do
         | 
| 33 | 
            +
                  it 'logs the start and finish lifecycle of a block' do
         | 
| 34 | 
            +
                    logwrapper.lifecycle 'testevent', extra: 'params' do
         | 
| 35 | 
            +
                      1 + 1
         | 
| 36 | 
            +
                    end
         | 
| 37 | 
            +
                    log.should include('testevent:started {"extra":"params"}')
         | 
| 38 | 
            +
                    log.should match(/testevent:finished.*"extra":"params"/)
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  it 'logs the duration of the block with the finished event' do
         | 
| 42 | 
            +
                    logwrapper.lifecycle('testevent') { 1 + 1 }
         | 
| 43 | 
            +
                    log.should match(/testevent:finished.*"duration":/)
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  it 'returns the value returned by the block' do
         | 
| 47 | 
            +
                    logwrapper.lifecycle('testevent') { 1 + 1 }.should == 2
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  it 'logs the start and failure of a block if it raises' do
         | 
| 51 | 
            +
                    logwrapper.lifecycle 'testevent' do
         | 
| 52 | 
            +
                      raise StandardError, "Foo"
         | 
| 53 | 
            +
                    end rescue nil
         | 
| 54 | 
            +
                    log.should include('testevent:started')
         | 
| 55 | 
            +
                    log.should include('testevent:failed {"exception":"StandardError","message":"Foo"}')
         | 
| 56 | 
            +
                  end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                  it 'reraises the exception' do
         | 
| 59 | 
            +
                    expect {
         | 
| 60 | 
            +
                      logwrapper.lifecycle 'testevent' do
         | 
| 61 | 
            +
                        raise "Foo"
         | 
| 62 | 
            +
                      end
         | 
| 63 | 
            +
                    }.to raise_error('Foo')
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
                end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                describe '.lifecycle' do
         | 
| 68 | 
            +
                  it 'wraps given method' do
         | 
| 69 | 
            +
                    ::Roqua.stub(:logger => logwrapper)
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                    test = Class.new do
         | 
| 72 | 
            +
                      include Logging
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                      def foo
         | 
| 75 | 
            +
                        'bar'
         | 
| 76 | 
            +
                      end
         | 
| 77 | 
            +
                      log :foo, 'roqua.testevent.foo'
         | 
| 78 | 
            +
                    end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                    test.new.foo.should == 'bar'
         | 
| 81 | 
            +
                    log.should include('roqua.testevent.foo:started')
         | 
| 82 | 
            +
                    log.should include('roqua.testevent.foo:finished')
         | 
| 83 | 
            +
                  end
         | 
| 84 | 
            +
                end
         | 
| 85 | 
            +
              end
         | 
| 86 | 
            +
            end
         | 
| @@ -0,0 +1,147 @@ | |
| 1 | 
            +
            require 'roqua/support/logging'
         | 
| 2 | 
            +
            require 'roqua/support/request_logger'
         | 
| 3 | 
            +
            require 'active_support/notifications'
         | 
| 4 | 
            +
            require 'active_support/core_ext/string'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            describe Roqua::Support::RequestLogger do
         | 
| 7 | 
            +
              let(:logstream)  { StringIO.new }
         | 
| 8 | 
            +
              let(:logger)     { Logger.new(logstream) }
         | 
| 9 | 
            +
              let(:logwrapper) { Roqua::LogWrapper.new(logger) }
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              before { Roqua.stub(logger: logwrapper) }
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              def log
         | 
| 14 | 
            +
                logstream.string
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              let(:subscriber) { Roqua::Support::RequestLogger.new }
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              context 'when processing a request' do
         | 
| 20 | 
            +
                let(:event) do
         | 
| 21 | 
            +
                  ActiveSupport::Notifications::Event.new('process_action.action_controller',
         | 
| 22 | 
            +
                                                          Time.new(2013, 02, 28, 12, 34, 56),
         | 
| 23 | 
            +
                                                          Time.new(2013, 02, 28, 12, 34, 57), 2,
         | 
| 24 | 
            +
                      status: 200, format: 'application/json', method: 'GET', path: '/home?foo=bar',
         | 
| 25 | 
            +
                      params: {'controller' => 'home', 'action' => 'index', 'foo' => 'bar'},
         | 
| 26 | 
            +
                      db_runtime: 0.02, view_runtime: 0.01
         | 
| 27 | 
            +
                  )
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                it "logs the URL" do
         | 
| 31 | 
            +
                  subscriber.process_action(event)
         | 
| 32 | 
            +
                  logstream.string.should include('/home')
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                it "does not log the query string" do
         | 
| 36 | 
            +
                  subscriber.process_action(event)
         | 
| 37 | 
            +
                  logstream.string.should_not include('?foo=bar')
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                it "logs the HTTP method" do
         | 
| 41 | 
            +
                  subscriber.process_action(event)
         | 
| 42 | 
            +
                  logstream.string.should include('"method":"GET"')
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                it "logs the status code returned" do
         | 
| 46 | 
            +
                  subscriber.process_action(event)
         | 
| 47 | 
            +
                  logstream.string.should include('"status":200')
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                it "logs the controller and action" do
         | 
| 51 | 
            +
                  subscriber.process_action(event)
         | 
| 52 | 
            +
                  logstream.string.should include('"controller":"home","action":"index"')
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                it 'logs request parameters' do
         | 
| 56 | 
            +
                  subscriber.process_action(event)
         | 
| 57 | 
            +
                  logstream.string.should include('"params":{"foo":"bar"}')
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                it "logs how long the request took" do
         | 
| 61 | 
            +
                  subscriber.process_action(event)
         | 
| 62 | 
            +
                  logstream.string.should =~ /"duration":1000.0/
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                it "logs the view rendering time" do
         | 
| 66 | 
            +
                  subscriber.process_action(event)
         | 
| 67 | 
            +
                  logstream.string.should =~ /"view":0.01/
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                it "logs the database rendering time" do
         | 
| 71 | 
            +
                  subscriber.process_action(event)
         | 
| 72 | 
            +
                  logstream.string.should =~ /"db":0.02/
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                it 'logs extra information added in the controller' do
         | 
| 76 | 
            +
                  controller = Class.new do
         | 
| 77 | 
            +
                    include Roqua::Support::RequestLogging
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                    def index
         | 
| 80 | 
            +
                      add_log_information 'current_user', 'johndoe'
         | 
| 81 | 
            +
                    end
         | 
| 82 | 
            +
                  end
         | 
| 83 | 
            +
                  controller.new.index
         | 
| 84 | 
            +
                  subscriber.process_action(event)
         | 
| 85 | 
            +
                  logstream.string.should include('"current_user":"johndoe"')
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                  # next request should not still maintain this data
         | 
| 88 | 
            +
                  logstream.truncate 0
         | 
| 89 | 
            +
                  subscriber.process_action(event)
         | 
| 90 | 
            +
                  logstream.string.should_not include('current_user')
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
              end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
              context 'when an exception occured processing the request' do
         | 
| 95 | 
            +
                let(:event) do
         | 
| 96 | 
            +
                  ActiveSupport::Notifications::Event.new('process_action.action_controller',
         | 
| 97 | 
            +
                                                          Time.now, Time.now, 2,
         | 
| 98 | 
            +
                      status: nil, format: 'application/json', method: 'GET', path: '/home?foo=bar',
         | 
| 99 | 
            +
                      exception: ['AbstractController::ActionNotFound', 'Route not found'],
         | 
| 100 | 
            +
                      params: {'controller' => 'home', 'action' => 'index', 'foo' => 'bar'},
         | 
| 101 | 
            +
                      db_runtime: 0.02, view_runtime: 0.01
         | 
| 102 | 
            +
                  )
         | 
| 103 | 
            +
                end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                it "logs the 500 status when an exception occurred" do
         | 
| 106 | 
            +
                  subscriber.process_action(event)
         | 
| 107 | 
            +
                  logstream.string.should =~ /"status":500/
         | 
| 108 | 
            +
                  logstream.string.should =~ /"error":"AbstractController::ActionNotFound:Route not found"/
         | 
| 109 | 
            +
                end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                it "should return an unknown status when no status or exception is found" do
         | 
| 112 | 
            +
                  event.payload[:status] = nil
         | 
| 113 | 
            +
                  event.payload[:exception] = nil
         | 
| 114 | 
            +
                  subscriber.process_action(event)
         | 
| 115 | 
            +
                  logstream.string.should =~ /"status":0/
         | 
| 116 | 
            +
                end
         | 
| 117 | 
            +
              end
         | 
| 118 | 
            +
             | 
| 119 | 
            +
              context 'when the request redirected' do
         | 
| 120 | 
            +
                let(:event) do
         | 
| 121 | 
            +
                  ActiveSupport::Notifications::Event.new('process_action.action_controller',
         | 
| 122 | 
            +
                                                          Time.new(2013, 02, 28, 12, 34, 56),
         | 
| 123 | 
            +
                                                          Time.new(2013, 02, 28, 12, 34, 57), 2,
         | 
| 124 | 
            +
                      status: 200, format: 'application/json', method: 'GET', path: '/home?foo=bar',
         | 
| 125 | 
            +
                      params: {'controller' => 'home', 'action' => 'index', 'foo' => 'bar'},
         | 
| 126 | 
            +
                      db_runtime: 0.02, view_runtime: 0.01
         | 
| 127 | 
            +
                  )
         | 
| 128 | 
            +
                end
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                let(:redirect) {
         | 
| 131 | 
            +
                  ActiveSupport::Notifications::Event.new(
         | 
| 132 | 
            +
                    'redirect_to.action_controller', Time.now, Time.now, 1, location: 'http://example.com', status: 302
         | 
| 133 | 
            +
                  )
         | 
| 134 | 
            +
                }
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                it 'logs the redirect' do
         | 
| 137 | 
            +
                  subscriber.redirect_to(redirect)
         | 
| 138 | 
            +
                  subscriber.process_action(event)
         | 
| 139 | 
            +
                  log.should include('"location":"http://example.com"')
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                  # next request should no longer get location
         | 
| 142 | 
            +
                  logstream.truncate 0
         | 
| 143 | 
            +
                  subscriber.process_action(event)
         | 
| 144 | 
            +
                  log.should_not include('location')
         | 
| 145 | 
            +
                end
         | 
| 146 | 
            +
              end
         | 
| 147 | 
            +
            end
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            require 'roqua/support'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe Roqua do
         | 
| 4 | 
            +
              describe '#logger' do
         | 
| 5 | 
            +
                it 'has a default' do
         | 
| 6 | 
            +
                  Roqua.logger.should be_an_instance_of(Roqua::LogWrapper)
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              describe '#logger=' do
         | 
| 11 | 
            +
                let(:logger) { stub }
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                it 'wraps a given logger' do
         | 
| 14 | 
            +
                  Roqua.logger = logger
         | 
| 15 | 
            +
                  Roqua.logger.should be_an_instance_of(Roqua::LogWrapper)
         | 
| 16 | 
            +
                  Roqua.logger.logger.should == logger
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,133 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: roqua-support
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.1.0
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - Marten Veldthuis
         | 
| 8 | 
            +
            autorequire: 
         | 
| 9 | 
            +
            bindir: bin
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2013-12-05 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: activesupport
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - ~>
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: '3.2'
         | 
| 20 | 
            +
              type: :runtime
         | 
| 21 | 
            +
              prerelease: false
         | 
| 22 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 | 
            +
                requirements:
         | 
| 24 | 
            +
                - - ~>
         | 
| 25 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            +
                    version: '3.2'
         | 
| 27 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 28 | 
            +
              name: bundler
         | 
| 29 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 | 
            +
                requirements:
         | 
| 31 | 
            +
                - - ~>
         | 
| 32 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            +
                    version: '1.0'
         | 
| 34 | 
            +
              type: :development
         | 
| 35 | 
            +
              prerelease: false
         | 
| 36 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 | 
            +
                requirements:
         | 
| 38 | 
            +
                - - ~>
         | 
| 39 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            +
                    version: '1.0'
         | 
| 41 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 42 | 
            +
              name: rake
         | 
| 43 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 | 
            +
                requirements:
         | 
| 45 | 
            +
                - - '>='
         | 
| 46 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            +
                    version: '0'
         | 
| 48 | 
            +
              type: :development
         | 
| 49 | 
            +
              prerelease: false
         | 
| 50 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 | 
            +
                requirements:
         | 
| 52 | 
            +
                - - '>='
         | 
| 53 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            +
                    version: '0'
         | 
| 55 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 56 | 
            +
              name: rspec
         | 
| 57 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 58 | 
            +
                requirements:
         | 
| 59 | 
            +
                - - ~>
         | 
| 60 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            +
                    version: 2.12.0
         | 
| 62 | 
            +
              type: :development
         | 
| 63 | 
            +
              prerelease: false
         | 
| 64 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 65 | 
            +
                requirements:
         | 
| 66 | 
            +
                - - ~>
         | 
| 67 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 68 | 
            +
                    version: 2.12.0
         | 
| 69 | 
            +
            description: 'Logging backend, freedom patches, '
         | 
| 70 | 
            +
            email: marten@roqua.nl
         | 
| 71 | 
            +
            executables: []
         | 
| 72 | 
            +
            extensions: []
         | 
| 73 | 
            +
            extra_rdoc_files: []
         | 
| 74 | 
            +
            files:
         | 
| 75 | 
            +
            - .gitignore
         | 
| 76 | 
            +
            - .rspec
         | 
| 77 | 
            +
            - .travis.yml
         | 
| 78 | 
            +
            - Gemfile
         | 
| 79 | 
            +
            - Gemfile.lock
         | 
| 80 | 
            +
            - LICENSE.txt
         | 
| 81 | 
            +
            - README.md
         | 
| 82 | 
            +
            - Rakefile
         | 
| 83 | 
            +
            - lib/roqua-support.rb
         | 
| 84 | 
            +
            - lib/roqua-support/version.rb
         | 
| 85 | 
            +
            - lib/roqua/core_ext/array/stable_sort_by.rb
         | 
| 86 | 
            +
            - lib/roqua/core_ext/enumerable/sort_by_alphanum.rb
         | 
| 87 | 
            +
            - lib/roqua/core_ext/fabrication/singleton.rb
         | 
| 88 | 
            +
            - lib/roqua/core_ext/fixnum/clamp.rb
         | 
| 89 | 
            +
            - lib/roqua/support.rb
         | 
| 90 | 
            +
            - lib/roqua/support/command_runner.rb
         | 
| 91 | 
            +
            - lib/roqua/support/log_wrapper.rb
         | 
| 92 | 
            +
            - lib/roqua/support/logging.rb
         | 
| 93 | 
            +
            - lib/roqua/support/request_logger.rb
         | 
| 94 | 
            +
            - roqua-support.gemspec
         | 
| 95 | 
            +
            - spec/roqua/core_ext/array/stable_sort_by_spec.rb
         | 
| 96 | 
            +
            - spec/roqua/core_ext/enumerable/sort_by_alphanum_spec.rb
         | 
| 97 | 
            +
            - spec/roqua/core_ext/fabrication/singleton_spec.rb
         | 
| 98 | 
            +
            - spec/roqua/core_ext/fixnum/clamp_spec.rb
         | 
| 99 | 
            +
            - spec/roqua/support/logging_spec.rb
         | 
| 100 | 
            +
            - spec/roqua/support/request_logger_spec.rb
         | 
| 101 | 
            +
            - spec/roqua/support_spec.rb
         | 
| 102 | 
            +
            homepage: https://github.com/roqua/healthy
         | 
| 103 | 
            +
            licenses:
         | 
| 104 | 
            +
            - MIT
         | 
| 105 | 
            +
            metadata: {}
         | 
| 106 | 
            +
            post_install_message: 
         | 
| 107 | 
            +
            rdoc_options: []
         | 
| 108 | 
            +
            require_paths:
         | 
| 109 | 
            +
            - lib
         | 
| 110 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 111 | 
            +
              requirements:
         | 
| 112 | 
            +
              - - '>='
         | 
| 113 | 
            +
                - !ruby/object:Gem::Version
         | 
| 114 | 
            +
                  version: '0'
         | 
| 115 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 116 | 
            +
              requirements:
         | 
| 117 | 
            +
              - - '>='
         | 
| 118 | 
            +
                - !ruby/object:Gem::Version
         | 
| 119 | 
            +
                  version: '0'
         | 
| 120 | 
            +
            requirements: []
         | 
| 121 | 
            +
            rubyforge_project: 
         | 
| 122 | 
            +
            rubygems_version: 2.0.6
         | 
| 123 | 
            +
            signing_key: 
         | 
| 124 | 
            +
            specification_version: 4
         | 
| 125 | 
            +
            summary: Helper objects and proxies used by a lot of RoQua applications
         | 
| 126 | 
            +
            test_files:
         | 
| 127 | 
            +
            - spec/roqua/core_ext/array/stable_sort_by_spec.rb
         | 
| 128 | 
            +
            - spec/roqua/core_ext/enumerable/sort_by_alphanum_spec.rb
         | 
| 129 | 
            +
            - spec/roqua/core_ext/fabrication/singleton_spec.rb
         | 
| 130 | 
            +
            - spec/roqua/core_ext/fixnum/clamp_spec.rb
         | 
| 131 | 
            +
            - spec/roqua/support/logging_spec.rb
         | 
| 132 | 
            +
            - spec/roqua/support/request_logger_spec.rb
         | 
| 133 | 
            +
            - spec/roqua/support_spec.rb
         |