[deploy] Refactor:Remove No Longer Needed Timber Logging (#9555)

This commit is contained in:
Molly Struve 2020-07-28 14:00:38 -05:00 committed by GitHub
parent a589529269
commit e2e034b910
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
83 changed files with 1 additions and 2242 deletions

View file

@ -167,11 +167,6 @@ variable :STACK_EXCHANGE_APP_KEY, :String, default: ""
group :production do
variable :SECRET_KEY_BASE, :String
# Timber
# (https://docs.timber.io/)
variable :SEND_LOGS_TO_TIMBER, :String # Defaults to true in production, false in development
variable :TIMBER, :String # Only required if above is "true" or unset
# Sendgrid
# (https://sendgrid.com/docs/API_Reference/api_v3.html)
variable :SENDGRID_USERNAME_ACCEL, :String

View file

@ -100,8 +100,6 @@ gem "staccato", "~> 0.5" # Ruby Google Analytics Measurement
gem "storext", "~> 3.1" # Add type-casting and other features on top of ActiveRecord::Store.store_accessor
gem "stripe", "~> 5.22" # Ruby library for the Stripe API
gem "strong_migrations", "~> 0.7" # Catch unsafe migrations
gem "timber", "~> 3.0" # Great Ruby logging made easy
gem "timber-rails", github: "timberio/timber-ruby-rails", branch: "master" # Timber integration for Rails
gem "twilio-ruby", "~> 5.39" # The official library for communicating with the Twilio REST API
gem "twitter", "~> 7.0" # A Ruby interface to the Twitter API
gem "uglifier", "~> 4.2" # Uglifier minifies JavaScript files

View file

@ -6,16 +6,6 @@ GIT
acts_as_follower (0.2.1)
activerecord (>= 4.0)
GIT
remote: https://github.com/timberio/timber-ruby-rails.git
revision: 250326b0926d33207f0e1147a594dd8fe4487466
branch: master
specs:
timber-rails (1.0.2)
rails (>= 3.0.0)
timber (~> 3.0)
timber-rack (~> 1.0)
GEM
remote: https://rubygems.org/
specs:
@ -775,11 +765,6 @@ GEM
thor (0.20.3)
thread_safe (0.3.6)
tilt (2.0.10)
timber (3.0.1)
msgpack (~> 1.0)
timber-rack (1.0.1)
rack (>= 1.2, < 3.0)
timber (~> 3.0)
timecop (0.9.1)
twilio-ruby (5.39.2)
faraday (>= 0.9, < 2.0)
@ -990,8 +975,6 @@ DEPENDENCIES
stripe-ruby-mock (~> 3.0)
strong_migrations (~> 0.7)
test-prof (~> 0.12)
timber (~> 3.0)
timber-rails!
timecop (~> 0.9)
twilio-ruby (~> 5.39)
twitter (~> 7.0)

View file

@ -12,7 +12,7 @@ module Metrics
model.estimated_count
end
Rails.logger.info("db_table_size", table_info: { table_name: model.table_name, table_size: db_count })
Rails.logger.info(message: "db_table_size", table_info: { table_name: model.table_name, table_size: db_count })
DatadogStatsClient.gauge("postgres.db_table_size", db_count, tags: ["table_name:#{model.table_name}"])
next unless model.const_defined?(:SEARCH_CLASS)

View file

@ -107,14 +107,6 @@ Rails.application.configure do
config.logger = ActiveSupport::TaggedLogging.new(logger)
end
if (ENV["SEND_LOGS_TO_TIMBER"] || "true") == "true"
# Timber.io logger
log_device = Timber::LogDevices::HTTP.new(ENV["TIMBER"])
logger = Timber::Logger.new(log_device)
logger.level = config.log_level
config.logger = ActiveSupport::TaggedLogging.new(logger)
end
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false

View file

@ -1,33 +0,0 @@
# Timber.io Ruby Configuration - Simple Structured Logging
#
# ^ ^ ^ ^ ___I_ ^ ^ ^ ^ ^ ^ ^
# /|\/|\/|\ /|\ /\-_--\ /|\/|\ /|\/|\/|\ /|\/|\
# /|\/|\/|\ /|\ / \_-__\ /|\/|\ /|\/|\/|\ /|\/|\
# /|\/|\/|\ /|\ |[]| [] | /|\/|\ /|\/|\/|\ /|\/|\
# -------------------------------------------------------------------
# Website: https://timber.io
# Documentation: https://timber.io/docs
# Support: support@timber.io
# -------------------------------------------------------------------
config = Timber::Config.instance
config.integrations.action_view.silence = true
config.integrations.active_record.silence = !Rails.env.development?
config.integrations.rack.http_events.collapse_into_single_event = true
config.integrations.rack.http_events.silence_request = lambda do |_rack_env, rack_request|
rack_request.path.match?(%r{^/page_views/\d{1,9}})
end
config.integrations.rack.user_context.custom_user_hash = lambda do |rack_env|
session_user_id = rack_env["rack.session"].to_h["warden.user.user.key"]&.first&.first
if session_user_id
{
id: session_user_id
}
end
end
# Add additional configuration here.
# For a full list of configuration options and their explanations see:
# http://www.rubydoc.info/github/timberio/timber-ruby/Timber/Config

View file

@ -1,19 +1,9 @@
require "rails_helper"
RSpec.describe Metrics::RecordDataCountsWorker, type: :worker do
default_logger = Rails.logger
include_examples "#enqueues_on_correct_queue", "low_priority", 1
describe "#perform" do
# Override the default Rails logger as these tests require the Timber logger.
before do
timber_logger = Timber::Logger.new(nil)
Rails.logger = ActiveSupport::TaggedLogging.new(timber_logger)
end
after { Rails.logger = default_logger }
it "calls count on each model" do
allow(User).to receive(:count)
allow(User).to receive(:estimated_count)

Binary file not shown.

Binary file not shown.

View file

@ -1,14 +0,0 @@
/.bundle/
/.yardoc
/_yardoc/
/coverage/
/doc/
/pkg/
/spec/reports/
/tmp/
# rspec failure tracking
.rspec_status
# Ignore gemset
/.gem

View file

@ -1,3 +0,0 @@
--format documentation
--color
--require spec_helper

View file

@ -1,68 +0,0 @@
sudo: false
language: ruby
cache: bundler
rvm:
- 1.9.3
- 2.2.10
- 2.3.8
- 2.4.7
- 2.5.6
- 2.6.4
- jruby-9.2.8.0
before_install: gem install bundler -v 1.17.3
gemfile:
- gemfiles/rails-3.2.gemfile
- gemfiles/rails-4.0.gemfile
- gemfiles/rails-4.1.gemfile
- gemfiles/rails-4.2.gemfile
- gemfiles/rails-5.0.gemfile
- gemfiles/rails-5.1.gemfile
- gemfiles/rails-5.2.gemfile
- gemfiles/rails-6.0.gemfile
- gemfiles/rails-edge.gemfile
env:
global: RAILS_ENV=test
before_script:
- echo $BUNDLE_GEMFILE
- bundle install
script:
- bundle exec rspec --format documentation
matrix:
fast_finish: true
exclude:
- rvm: 1.9.3
- gemfile: gemfiles/rails-edge.gemfile
- rvm: 2.2.10
gemfile: gemfiles/rails-6.0.gemfile
- rvm: 2.3.8
gemfile: gemfiles/rails-6.0.gemfile
- rvm: 2.4.7
gemfile: gemfiles/rails-4.0.gemfile
- rvm: 2.4.7
gemfile: gemfiles/rails-4.1.gemfile
- rvm: 2.4.7
gemfile: gemfiles/rails-6.0.gemfile
- rvm: 2.5.6
gemfile: gemfiles/rails-3.2.gemfile
- rvm: 2.5.6
gemfile: gemfiles/rails-4.0.gemfile
- rvm: 2.5.6
gemfile: gemfiles/rails-4.1.gemfile
- rvm: 2.6.4
gemfile: gemfiles/rails-4.0.gemfile
- rvm: 2.6.4
gemfile: gemfiles/rails-4.1.gemfile
include:
- rvm: 2.5.6
gemfile: gemfiles/rails-edge.gemfile
- rvm: 1.9.3
gemfile: gemfiles/rails-3.2.gemfile
allow_failures:
- rvm: 1.9.3 # bundler wont install the gems
- gemfile: gemfiles/rails-edge.gemfile
- rvm: jruby-9.2.8.0
notifications:
email: false
slack:
rooms:
secure: F4BGVLUnaDqJ3YXfuIwx+m6047E8YstCUXs33Tfcs7SUlSuOSChuXqvCfVtnfNy2muF7xgB6VRL3xpFIRm7qNStqGUWCQJXmKq2OEgq1DYGkhAVle4d/LBtVcfBgeLelsoi+1TI9MrUtpZDHPl0li3PLoC+dq7rzSuhrxQ9EOhZlZGVn6LTeVcgNw6cLNzHSWJJ8zpYWLjBWUXgJ75MQvo5qaNbQxyfzm7GzEgRNfSzabFBwpKwB1Tog9X9TKTtPrn30O9Ur9+wmTu6EnwaDWZjaTK6I+AbxE8huIfUGvSrq1aV2JaDIra6zHEQ+d4j0oRYutgFM4YfyN9124MbPE2yH/5lXNQHMpUOsP0bl2U+KGDzq/V5APyrZ6irsvwGYpo3fSXrW8nDIAK4Mh8KB+Ta0zN5H8PmIRK76wJ+wG2zAtrfl+ailxMrdpK6J04fl3pCBuO6eW+AKEJ7Wfi5GiE7a9lk/YewAeDHyyLSnUNFIP0/iFAbTtRh5denCk0ZUS1XyfZNQuFoku7jk5lpe41SNItqOO0jv/jXPF+wensNa2UgMBIP0XkRw55LKn9eY0MKm9P+zp9ePaXs0T0Ttv4e0T4Jxrgf5QBynefgHwAsOI1nHr7GhlPaFQ6u8iNmjNYLB9v1JZMlO08LkytzZFpUuJoHbYYoBaRtUtEosBHg=

View file

@ -1,3 +0,0 @@
source "https://rubygems.org"
gemspec

View file

@ -1,15 +0,0 @@
# License
Copyright (c) 2019, Timber Technologies, Inc.
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.

View file

@ -1,14 +0,0 @@
# 🌲 Timber Integration For Rails
[![ISC License](https://img.shields.io/badge/license-ISC-ff69b4.svg)](LICENSE.md)
[![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://www.rubydoc.info/github/timberio/timber-ruby-rails)
[![Build Status](https://travis-ci.org/timberio/timber-ruby-rails.svg?branch=master)](https://travis-ci.org/timberio/timber-ruby-rails)
This library integrates the
[`timber` Ruby library](https://github.com/timberio/timber-ruby) with the
[rails](https://github.com/rails/rails) framework, turning your rails logs into
rich structured events.
- **Sign-up: [https://app.timber.io](https://app.timber.io)**
- **Documentation:
[https://docs.timber.io/setup/languages/ruby/integrations/rails](https://docs.timber.io/setup/languages/ruby/integrations/rails)**

View file

@ -1,6 +0,0 @@
require "bundler/gem_tasks"
require "rspec/core/rake_task"
RSpec::Core::RakeTask.new(:spec)
task :default => :spec

View file

@ -1,14 +0,0 @@
#!/usr/bin/env ruby
require "bundler/setup"
require "timber-rails"
# You can add fixtures and/or initialization code here to make experimenting
# with your gem easier. You can also use a different console, if you like.
# (If you use this, don't forget to add pry to your Gemfile!)
# require "pry"
# Pry.start
require "irb"
IRB.start(__FILE__)

View file

@ -1,8 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
set -vx
bundle install
# Do any other automated setup that you need to do here

View file

@ -1,8 +0,0 @@
source 'https://rubygems.org'
gem 'rails', '~> 3.0.0'
gem 'timber',
gem 'timber-rack'
gemspec :path => '../'

View file

@ -1,8 +0,0 @@
source 'https://rubygems.org'
gem 'rails', '~> 3.1.0'
gem 'timber'
gem 'timber-rack'
gemspec :path => '../'

View file

@ -1,8 +0,0 @@
source 'https://rubygems.org'
gem 'rails', '~> 3.2.0'
gem 'timber'
gem 'timber-rack'
gemspec :path => '../'

View file

@ -1,12 +0,0 @@
source 'https://rubygems.org'
gem 'rails', '~> 4.0.0'
gem 'timber'
gem 'timber-rack'
if RUBY_PLATFORM == "java"
gem 'mime-types', '2.6.2'
end
gemspec :path => '../'

View file

@ -1,12 +0,0 @@
source 'https://rubygems.org'
gem 'rails', '~> 4.1.0'
gem 'timber'
gem 'timber-rack'
if RUBY_PLATFORM == "java"
gem 'mime-types', '2.6.2'
end
gemspec :path => '../'

View file

@ -1,12 +0,0 @@
source 'https://rubygems.org'
gem 'rails', '~> 4.2.0'
gem 'timber'
gem 'timber-rack'
if RUBY_PLATFORM == "java"
gem 'mime-types', '2.6.2'
end
gemspec :path => '../'

View file

@ -1,12 +0,0 @@
source 'https://rubygems.org'
gem 'rails', '~> 5.0.0'
gem 'timber'
gem 'timber-rack'
if RUBY_PLATFORM == "java"
gem 'mime-types', '2.6.2'
end
gemspec :path => '../'

View file

@ -1,12 +0,0 @@
source 'https://rubygems.org'
gem 'rails', '~> 5.1.0'
gem 'timber'
gem 'timber-rack'
if RUBY_PLATFORM == "java"
gem 'mime-types', '2.6.2'
end
gemspec :path => '../'

View file

@ -1,12 +0,0 @@
source 'https://rubygems.org'
gem 'rails', '~> 5.2.0'
gem 'timber'
gem 'timber-rack'
if RUBY_PLATFORM == "java"
gem 'mime-types', '2.6.2'
end
gemspec :path => '../'

View file

@ -1,12 +0,0 @@
source 'https://rubygems.org'
gem 'rails', '~> 6.0.0'
gem 'timber'
gem 'timber-rack'
if RUBY_PLATFORM == "java"
gem 'mime-types', '2.6.2'
end
gemspec :path => '../'

View file

@ -1,10 +0,0 @@
source 'https://rubygems.org'
gem 'rack', git: 'https://github.com/rack/rack', branch: 'master'
gem 'arel', git: 'https://github.com/rails/arel', branch: 'master'
gem 'rails', git: 'https://github.com/rails/rails', branch: 'master'
gem 'timber'
gem 'timber-rack'
gemspec :path => '../'

View file

@ -1,65 +0,0 @@
require "timber-rails/overrides"
require "timber"
require "rails"
require "timber-rails/active_support_log_subscriber"
require "timber-rails/config"
require "timber-rails/railtie"
require "timber-rack/http_context"
require "timber-rack/http_events"
require "timber-rack/user_context"
require "timber-rails/session_context"
require "timber-rails/rack_logger"
require "timber-rails/error_event"
require "timber-rails/action_controller"
require "timber-rails/action_dispatch"
require "timber-rails/action_view"
require "timber-rails/active_record"
require "timber-rails/logger"
module Timber
module Integrations
# Module for holding *all* Rails integrations. This module does *not*
# extend {Integration} because it's dependent on {Rack::HTTPEvents}. This
# module simply disables the default HTTP request logging.
module Rails
def self.enabled?
Timber::Integrations::Rack::HTTPEvents.enabled?
end
def self.integrate!
return false if !enabled?
ActionController.integrate!
ActionDispatch.integrate!
ActionView.integrate!
ActiveRecord.integrate!
RackLogger.integrate!
end
def self.enabled=(value)
Timber::Integrations::Rails::ErrorEvent.enabled = value
Timber::Integrations::Rack::HTTPContext.enabled = value
Timber::Integrations::Rack::HTTPEvents.enabled = value
Timber::Integrations::Rack::UserContext.enabled = value
SessionContext.enabled = value
ActionController.enabled = value
ActionView.enabled = value
ActiveRecord.enabled = value
end
# All enabled middlewares. The order is relevant. Middlewares that set
# context are added first so that context is included in subsequent log lines.
def self.middlewares
@middlewares ||= [Timber::Integrations::Rack::HTTPContext, SessionContext, Timber::Integrations::Rack::UserContext,
Timber::Integrations::Rack::HTTPEvents, Timber::Integrations::Rails::ErrorEvent].select(&:enabled?)
end
end
end
end

View file

@ -1,17 +0,0 @@
require "timber-rails/action_controller/log_subscriber"
module Timber
module Integrations
# Module for holding *all* ActionController integrations. See {Integration} for
# configuration details for all integrations.
module ActionController
extend Integration
def self.integrate!
return false if !enabled?
LogSubscriber.integrate!
end
end
end
end

View file

@ -1,25 +0,0 @@
module Timber
module Integrations
module ActionController
# Responsible for removing the default ActionController::LogSubscriber and installing
# the TimberLogSubscriber
#
# @private
class LogSubscriber < Integrator
def initialize
require "action_controller/log_subscriber"
require "timber-rails/action_controller/log_subscriber/timber_log_subscriber"
rescue LoadError => e
raise RequirementNotMetError.new(e.message)
end
def integrate!
return true if Timber::Integrations::Rails::ActiveSupportLogSubscriber.subscribed?(:action_controller, TimberLogSubscriber)
Timber::Integrations::Rails::ActiveSupportLogSubscriber.unsubscribe!(:action_controller, ::ActionController::LogSubscriber)
TimberLogSubscriber.attach_to(:action_controller)
end
end
end
end
end

View file

@ -1,46 +0,0 @@
module Timber
module Integrations
module ActionController
class LogSubscriber < Integrator
# The log subscriber that replaces the default `ActionController::LogSubscriber`.
# The intent of this subscriber is to, as transparently as possible, properly
# track events that are being logged here. This LogSubscriber will never change
# default behavior / log messages.
#
# @private
class TimberLogSubscriber < ::ActionController::LogSubscriber
def start_processing(event)
return true if silence?
info do
payload = event.payload
params = payload[:params].except(*INTERNAL_PARAMS)
format = extract_format(payload)
format = format.to_s.upcase if format.is_a?(Symbol)
Events::ControllerCall.new(
controller: payload[:controller],
action: payload[:action],
format: format,
params: params
)
end
end
private
def extract_format(payload)
if payload.key?(:format)
payload[:format] # rails > 4.X
elsif payload.key?(:formats)
payload[:formats].first # rails 3.X
end
end
def silence?
ActionController.silence?
end
end
end
end
end
end

View file

@ -1,20 +0,0 @@
require "timber-rails/action_dispatch/debug_exceptions"
module Timber
module Integrations
# Module for holding *all* ActionDispatch integrations. This
# module simply disables the exception tracking middleware so that our middleware
# works as expected.
module ActionDispatch
def self.enabled?
Rails::ErrorEvent.enabled?
end
def self.integrate!
return false if !enabled?
DebugExceptions.integrate!
end
end
end
end

View file

@ -1,51 +0,0 @@
module Timber
module Integrations
module ActionDispatch
# Reponsible for disabled logging in the ActionDispatch::DebugExceptions
# Rack middleware. We cannot simply remove the middleware because it is
# coupled with displaying an exception debug screen if debug exceptions is enabled.
#
# @private
class DebugExceptions < Integrator
# Patch for disabling logging
#
# @private
module InstanceMethods
def self.included(klass)
klass.class_eval do
private
def logger(*args)
nil
end
end
end
end
def initialize
begin
# Rails >= 3.1
require "action_dispatch/middleware/debug_exceptions"
rescue LoadError
# Rails < 3.1
require "action_dispatch/middleware/show_exceptions"
end
rescue LoadError => e
raise RequirementNotMetError.new(e.message)
end
def integrate!
if defined?(::ActionDispatch::DebugExceptions) && !::ActionDispatch::DebugExceptions.include?(InstanceMethods)
::ActionDispatch::DebugExceptions.send(:include, InstanceMethods)
end
if defined?(::ActionDispatch::ShowExceptions) && !::ActionDispatch::ShowExceptions.include?(InstanceMethods)
::ActionDispatch::ShowExceptions.send(:include, InstanceMethods)
end
true
end
end
end
end
end

View file

@ -1,17 +0,0 @@
require "timber-rails/action_view/log_subscriber"
module Timber
module Integrations
# Module for holding *all* ActionView integrations. See {Integration} for
# configuration details for all integrations.
module ActionView
extend Integration
def self.integrate!
return false if !enabled?
LogSubscriber.integrate!
end
end
end
end

View file

@ -1,25 +0,0 @@
module Timber
module Integrations
module ActionView
# Reponsible for uninstalling the default `ActionView::LogSubscriber` and installing
# the TimberLogSubscriber.
#
# @private
class LogSubscriber < Integrator
def initialize
require "action_view/log_subscriber"
require "timber-rails/action_view/log_subscriber/timber_log_subscriber"
rescue LoadError => e
raise RequirementNotMetError.new(e.message)
end
def integrate!
return true if Timber::Integrations::Rails::ActiveSupportLogSubscriber.subscribed?(:action_view, TimberLogSubscriber)
Timber::Integrations::Rails::ActiveSupportLogSubscriber.unsubscribe!(:action_view, ::ActionView::LogSubscriber)
TimberLogSubscriber.attach_to(:action_view)
end
end
end
end
end

View file

@ -1,83 +0,0 @@
module Timber
module Integrations
module ActionView
class LogSubscriber < Integrator
# The log subscriber that replaces the default `ActionView::LogSubscriber`.
# The intent of this subscriber is to, as transparently as possible, properly
# track events that are being logged here.
#
# @private
class TimberLogSubscriber < ::ActionView::LogSubscriber
def render_template(event)
return true if silence?
info do
full_name = from_rails_root(event.payload[:identifier])
message = " Rendered #{full_name}"
message << " within #{from_rails_root(event.payload[:layout])}" if event.payload[:layout]
message << " (#{event.duration.round(1)}ms)"
Events::TemplateRender.new(
name: full_name,
duration_ms: event.duration,
message: message
)
end
end
def render_partial(event)
return true if silence?
info do
full_name = from_rails_root(event.payload[:identifier])
message = " Rendered #{full_name}"
message << " within #{from_rails_root(event.payload[:layout])}" if event.payload[:layout]
message << " (#{event.duration.round(1)}ms)"
message << " #{cache_message(event.payload)}" if event.payload.key?(:cache_hit)
Events::TemplateRender.new(
name: full_name,
duration_ms: event.duration,
message: message
)
end
end
def render_collection(event)
return true if silence?
if respond_to?(:render_count, true)
info do
identifier = event.payload[:identifier] || "templates"
full_name = from_rails_root(identifier)
message = " Rendered collection of #{full_name}" \
" #{render_count(event.payload)} (#{event.duration.round(1)}ms)"
Events::TemplateRender.new(
name: full_name,
duration_ms: event.duration,
message: message
)
end
else
# Older versions of rails delegate this method to #render_template
render_template(event)
end
end
private
def log_rendering_start(payload)
# Consolidates 2 template rendering events into 1. We don't need 2 events for
# rendering a template. If you disagree, please feel free to open a PR and we
# can make this an option.
end
def silence?
ActionView.silence?
end
end
end
end
end
end

View file

@ -1,17 +0,0 @@
require "timber-rails/active_record/log_subscriber"
module Timber
module Integrations
# Module for holding *all* ActiveRecord integrations. See {Integration} for
# configuration details for all integrations.
module ActiveRecord
extend Integration
def self.integrate!
return false if !enabled?
LogSubscriber.integrate!
end
end
end
end

View file

@ -1,20 +0,0 @@
require "timber-rails/active_record/log_subscriber/timber_log_subscriber"
module Timber
module Integrations
module ActiveRecord
# Reponsible for uninstalling the default `ActiveRecord::LogSubscriber` and replacing it
# with the `TimberLogSubscriber`.
#
# @private
class LogSubscriber < Integrator
def integrate!
return true if Timber::Integrations::Rails::ActiveSupportLogSubscriber.subscribed?(:active_record, TimberLogSubscriber)
Timber::Integrations::Rails::ActiveSupportLogSubscriber.unsubscribe!(:active_record, ::ActiveRecord::LogSubscriber)
TimberLogSubscriber.attach_to(:active_record)
end
end
end
end
end

View file

@ -1,52 +0,0 @@
# We require all of ActiveRecord because the #logger method in ::ActiveRecord::LogSubscriber
# uses ActiveRecord::Base. We can't require active_record/base directly because ActiveRecord
# does not require files properly and we receive unintialized constant errors.
require "active_record"
require "active_record/log_subscriber"
module Timber
module Integrations
module ActiveRecord
class LogSubscriber < Integrator
# The log subscriber that replaces the default `ActiveRecord::LogSubscriber`.
# The intent of this subscriber is to, as transparently as possible, properly
# track events that are being logged here. This LogSubscriber will never change
# default behavior / log messages.
#
# @private
class TimberLogSubscriber < ::ActiveRecord::LogSubscriber
def sql(event)
return true if silence?
r = super(event)
if @message
payload = event.payload
sql_event = Events::SQLQuery.new(
sql: payload[:sql],
duration_ms: event.duration,
message: @message,
)
logger.debug sql_event
@message = nil
end
r
end
private
def debug(message)
@message = message
end
def silence?
ActiveRecord.silence?
end
end
end
end
end
end

View file

@ -1,39 +0,0 @@
module Timber
module Integrations
module Rails
# @private
module ActiveSupportLogSubscriber
extend self
def find(component, type)
::ActiveSupport::LogSubscriber.log_subscribers.find do |subscriber|
subscriber.class == type
end
end
def subscribed?(component, type)
!find(component, type).nil?
end
# I don't know why this has to be so complicated, but it is. This code was taken from
# lograge :/
def unsubscribe!(component, type)
subscriber = find(component, type)
if !subscriber
raise "We could not find a log subscriber for #{component.inspect} of type #{type.inspect}"
end
events = subscriber.public_methods(false).reject { |method| method.to_s == 'call' }
events.each do |event|
::ActiveSupport::Notifications.notifier.listeners_for("#{event}.#{component}").each do |listener|
if listener.instance_variable_get('@delegate') == subscriber
::ActiveSupport::Notifications.unsubscribe listener
end
end
end
end
end
end
end
end

View file

@ -1,12 +0,0 @@
require 'timber/config'
require 'timber-rack/config'
require 'timber-rails/config/action_view'
require 'timber-rails/config/active_record'
require 'timber-rails/config/action_controller'
Timber::Config.instance.define_singleton_method(:logrageify!) do
integrations.action_controller.silence = true
integrations.action_view.silence = true
integrations.active_record.silence = true
integrations.rack.http_events.collapse_into_single_event = true
end

View file

@ -1,29 +0,0 @@
require "timber-rails/action_controller"
module Timber
class Config
# Convenience module for accessing the various `Timber::Integrations::*` classes
# through the {Timber::Config} object. Timber couples configuration with the class
# responsible for implementing it. This provides for a tighter design, but also
# requires the user to understand and access the various classes. This module aims
# to provide a simple ruby-like configuration interface for internal Timber classes.
#
# For example:
#
# config = Timber::Config.instance
# config.integrations.active_record.silence = true
module Integrations
extend self
# Convenience method for accessing the {Timber::Integrations::ActionController} class
# specific configuration.
#
# @example
# config = Timber::Config.instance
# config.integrations.action_controller.silence = true
def action_controller
Timber::Integrations::ActionController
end
end
end
end

View file

@ -1,29 +0,0 @@
require "timber-rails/action_view"
module Timber
class Config
# Convenience module for accessing the various `Timber::Integrations::*` classes
# through the {Timber::Config} object. Timber couples configuration with the class
# responsible for implementing it. This provides for a tighter design, but also
# requires the user to understand and access the various classes. This module aims
# to provide a simple ruby-like configuration interface for internal Timber classes.
#
# For example:
#
# config = Timber::Config.instance
# config.integrations.active_record.silence = true
module Integrations
extend self
# Convenience method for accessing the {Timber::Integrations::ActionView} class
# specific configuration.
#
# @example
# config = Timber::Config.instance
# config.integrations.action_view.silence = true
def action_view
Timber::Integrations::ActionView
end
end
end
end

View file

@ -1,29 +0,0 @@
require "timber-rails/active_record"
module Timber
class Config
# Convenience module for accessing the various `Timber::Integrations::*` classes
# through the {Timber::Config} object. Timber couples configuration with the class
# responsible for implementing it. This provides for a tighter design, but also
# requires the user to understand and access the various classes. This module aims
# to provide a simple ruby-like configuration interface for internal Timber classes.
#
# For example:
#
# config = Timber::Config.instance
# config.integrations.active_record.silence = true
module Integrations
extend self
# Convenience method for accessing the {Timber::Integrations::ActiveRecord} class
# specific configuration.
#
# @example
# config = Timber::Config.instance
# config.integrations.active_record.silence = true
def active_record
Timber::Integrations::ActiveRecord
end
end
end
end

View file

@ -1,61 +0,0 @@
begin
# Rails 3.2 requires you to require all of Rails before requiring
# the exception wrapper.
require "action_dispatch/middleware/exception_wrapper"
rescue Exception
end
require "timber/events/error"
require "timber-rack/middleware"
require "timber/util"
module Timber
module Integrations
module Rails
# A Rack middleware that is reponsible for capturing exception and error events
# {Timber::Events::Error}.
class ErrorEvent < Timber::Integrations::Rack::Middleware
# We determine this when the app loads to avoid the overhead on a per request basis.
EXCEPTION_WRAPPER_TAKES_CLEANER = defined?(::ActionDispatch::ExceptionWrapper) &&
!::ActionDispatch::ExceptionWrapper.instance_methods.include?(:env)
def call(env)
begin
status, headers, body = @app.call(env)
rescue Exception => exception
Config.instance.logger.fatal do
backtrace = extract_backtrace(env, exception)
Events::Error.new(
name: exception.class.name,
error_message: exception.message,
backtrace: backtrace
)
end
raise exception
end
end
private
# Rails provides a backtrace cleaner, so we use it here.
def extract_backtrace(env, exception)
if defined?(::ActionDispatch::ExceptionWrapper)
wrapper = if EXCEPTION_WRAPPER_TAKES_CLEANER
request = Util::Request.new(env)
backtrace_cleaner = request.get_header("action_dispatch.backtrace_cleaner")
::ActionDispatch::ExceptionWrapper.new(backtrace_cleaner, exception)
else
::ActionDispatch::ExceptionWrapper.new(env, exception)
end
trace = wrapper.application_trace
trace = wrapper.framework_trace if trace.empty?
trace
else
exception.backtrace
end
end
end
end
end
end

View file

@ -1,20 +0,0 @@
module Timber
# The Timber Logger behaves exactly like the standard Ruby `::Logger`, except that it supports a
# transparent API for logging structured data and events.
#
# @example Basic logging
# logger.info "Payment rejected for customer #{customer_id}"
#
# @example Logging an event
# logger.info "Payment rejected", payment_rejected: {customer_id: customer_id, amount: 100}
class Logger < ::Logger
include ::ActiveSupport::LoggerThreadSafeLevel if defined?(::ActiveSupport::LoggerThreadSafeLevel)
if defined?(::ActiveSupport::LoggerSilence)
include ::ActiveSupport::LoggerSilence
elsif defined?(::LoggerSilence)
include ::LoggerSilence
end
end
end

View file

@ -1,12 +0,0 @@
# The order is relevant
require "timber-rails/overrides/active_support_3_tagged_logging"
require "timber-rails/overrides/active_support_tagged_logging"
require "timber-rails/overrides/active_support_buffered_logger"
require "timber-rails/overrides/lograge"
require "timber-rails/overrides/rails_stdout_logging"
module Timber
# @private
module Overrides
end
end

View file

@ -1,111 +0,0 @@
# Please note, this patch is merely an upgrade, backporting improved tagged logging code
# from newer versions of Rails:
# https://github.com/rails/rails/blob/5-1-stable/activesupport/lib/active_support/tagged_logging.rb
# The behavior of tagged logging will not change in any way.
#
# This patch is specifically for Rails 3. The legacy approach to wrapping the logger in
# ActiveSupport::TaggedLogging is rather poor, hence the reason it was changed entirely
# for Rails 4 and 5. The problem is that ActiveSupport::TaggedLogging is a wrapping
# class that entirely redefines the public API for the logger. As a result, any deviations
# from this API in the logger are not exposed (such as accepting event data as a second argument).
# This is assuming, so we're fixing it here.
begin
require "active_support/tagged_logging"
# Instead of patching the class we're pulling the code from Rails master. This brings in
# a number of improvements while also addressing the issue above.
if ActiveSupport::TaggedLogging.instance_of?(Class)
ActiveSupport.send(:remove_const, :TaggedLogging)
require "active_support/core_ext/module/delegation"
require "active_support/core_ext/object/blank"
require "logger"
module ActiveSupport
# Wraps any standard Logger object to provide tagging capabilities.
#
# logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
# logger.tagged('BCX') { logger.info 'Stuff' } # Logs "[BCX] Stuff"
# logger.tagged('BCX', "Jason") { logger.info 'Stuff' } # Logs "[BCX] [Jason] Stuff"
# logger.tagged('BCX') { logger.tagged('Jason') { logger.info 'Stuff' } } # Logs "[BCX] [Jason] Stuff"
#
# This is used by the default Rails.logger as configured by Railties to make
# it easy to stamp log lines with subdomains, request ids, and anything else
# to aid debugging of multi-user production applications.
module TaggedLogging
module Formatter # :nodoc:
# This method is invoked when a log event occurs.
def call(severity, timestamp, progname, msg)
super(severity, timestamp, progname, "#{tags_text}#{msg}")
end
def tagged(*tags)
new_tags = push_tags(*tags)
yield self
ensure
pop_tags(new_tags.size)
end
def push_tags(*tags)
tags.flatten.reject(&:blank?).tap do |new_tags|
current_tags.concat new_tags
end
end
def pop_tags(size = 1)
current_tags.pop size
end
def clear_tags!
current_tags.clear
end
def current_tags
# We use our object ID here to avoid conflicting with other instances
thread_key = @thread_key ||= "activesupport_tagged_logging_tags:#{object_id}".freeze
Thread.current[thread_key] ||= []
end
def tags_text
tags = current_tags
if tags.any?
tags.collect { |tag| "[#{tag}] " }.join
end
end
end
# Simple formatter which only displays the message.
class SimpleFormatter < ::Logger::Formatter
# This method is invoked when a log event occurs
def call(severity, timestamp, progname, msg)
"#{String === msg ? msg : msg.inspect}\n"
end
end
def self.new(logger)
if logger.respond_to?(:formatter=) && logger.respond_to?(:formatter)
# Ensure we set a default formatter so we aren't extending nil!
logger.formatter ||= SimpleFormatter.new
logger.formatter.extend Formatter
end
logger.extend(self)
end
delegate :push_tags, :pop_tags, :clear_tags!, to: :formatter
def tagged(*tags)
formatter.tagged(*tags) { yield self }
end
def flush
clear_tags!
super if defined?(super)
end
end
end
end
rescue Exception
end

View file

@ -1,22 +0,0 @@
# This adds a #formatter and #formatter= method to the legacy ActiveSupport::BufferedLogger
# class. This bug was never resolved due to it being phased out past Rails >= 4.
begin
require "active_support/buffered_logger"
class ActiveSupport::BufferedLogger
def formatter
if @log.respond_to?(:formatter)
@log.formatter
end
end
def formatter=(value)
if @log.respond_to?(:formatter=)
@log.formatter = value
end
end
end
rescue Exception
end

View file

@ -1,66 +0,0 @@
# This is an override instead of an integration because without this Timber would not
# work properly if ActiveSupport::TaggedLogging is used.
#
# This is called after 'active_support_3_tagged_logging' where the constant is loaded and
# replaced. I want to make sure we don't attempt to load it again undoing the patches
# applied there.
if defined?(ActiveSupport::TaggedLogging)
module Timber
module Overrides
# @private
module ActiveSupportTaggedLogging
# @private
module FormatterMethods
def self.included(mod)
mod.module_eval do
alias_method :_timber_original_push_tags, :push_tags
alias_method :_timber_original_pop_tags, :pop_tags
def call(severity, timestamp, progname, msg)
if is_a?(Timber::Logger::Formatter)
# Don't convert the message into a string
super(severity, timestamp, progname, msg)
else
super(severity, timestamp, progname, "#{tags_text}#{msg}")
end
end
end
end
end
# @private
module LoggerMethods
def self.included(klass)
klass.class_eval do
def add(severity, message = nil, progname = nil, &block)
if message.nil?
if block_given?
message = block.call
else
message = progname
progname = nil #No instance variable for this like Logger
end
end
if @logger.is_a?(Timber::Logger)
@logger.add(severity, message, progname)
else
@logger.add(severity, "#{tags_text}#{message}", progname)
end
end
end
end
end
if defined?(::ActiveSupport::TaggedLogging::Formatter)
if !::ActiveSupport::TaggedLogging::Formatter.include?(FormatterMethods)
::ActiveSupport::TaggedLogging::Formatter.send(:include, FormatterMethods)
end
else
if !::ActiveSupport::TaggedLogging.include?(LoggerMethods)
::ActiveSupport::TaggedLogging.send(:include, LoggerMethods)
end
end
end
end
end
end

View file

@ -1,18 +0,0 @@
# Timber and lograge are not compatible installed together. Using lograge
# with the Timber.io *service* is perfectly fine, but not with the Timber *gem*.
#
# Timber does ship with a {Timber::Config#logrageify!} option that configures
# Timber to behave similarly to Lograge (silencing various logs). Check out
# the aforementioned method or the README for info.
begin
require "lograge"
module Lograge
module_function
def setup(app)
return true
end
end
rescue Exception
end

View file

@ -1,21 +0,0 @@
# See https://github.com/heroku/rails_stdout_logging
# I have no idea why this library was created, but most Heroku / Rails apps use it.
# This library completely obliterates any logger configuration you set.
# So this patch fixes that.
begin
require "rails_stdout_logging"
module RailsStdoutLogging
class Rails2 < Rails
def self.set_logger
end
end
class Rails3 < Rails
def self.set_logger(config)
end
end
end
rescue Exception
end

View file

@ -1,58 +0,0 @@
module Timber
module Integrations
module Rails
# Disables the default rail's rack logging. Note, we cannot simply uninstall this rack
# middleware because rails couples this with ActiveSupport instrumentation. As such,
# we simply disable the logger and let our Rack middleware handle the logging.
#
# See: https://github.com/rails/rails/blob/80e66cc4d90bf8c15d1a5f6e3152e90147f00772/railties/lib/rails/rack/logger.rb#L34
#
# @private
class RackLogger < Integrator
# @private
module InstanceMethods
LOGGER = ::Logger.new(nil)
def self.included(klass)
klass.class_eval do
private
if ::Rails::VERSION::MAJOR == 3
# Rails 3.2 calls Rails.logger directly in call_app, so we
# will just replace it with a version that doesn't
def call_app(_, env)
# Put some space between requests in development logs.
if ::Rails.env.development?
::Rails.logger.info ''
::Rails.logger.info ''
end
@app.call(env)
ensure
ActiveSupport::LogSubscriber.flush_all!
end
end
# Rails > 3.2 uses a logger method. Muting logs is accomplished by
# passing a dummy logger instance with a nil log device.
def logger
LOGGER
end
end
end
end
def initialize
require "rails/rack/logger"
rescue LoadError => e
raise RequirementNotMetError.new(e.message)
end
def integrate!
return true if ::Rails::Rack::Logger.include?(InstanceMethods)
::Rails::Rack::Logger.send(:include, InstanceMethods)
end
end
end
end
end

View file

@ -1,27 +0,0 @@
module Timber
module Frameworks
# Module for Rails specific code, such as the Railtie and any methods that assist
# with Rails setup.
module Rails
# Installs Timber into your Rails app automatically.
class Railtie < ::Rails::Railtie
config.timber = Config.instance
config.before_initialize do
Timber::Config.instance.logger = Proc.new { ::Rails.logger }
end
# Must be loaded after initializers so that we respect any Timber configuration set
initializer(:timber, before: :build_middleware_stack, after: :load_config_initializers) do
Integrations::Rails.integrate!
# Install the Rack middlewares so that we capture structured data instead of
# raw text logs.
Integrations::Rails.middlewares.collect do |middleware_class|
config.app_middleware.use middleware_class
end
end
end
end
end
end

View file

@ -1,37 +0,0 @@
require "timber/contexts/session"
require "timber-rack/middleware"
module Timber
module Integrations
module Rails
# A Rack middleware that is responsible for adding the Session context
# {Timber::Contexts::Session}.
class SessionContext < Timber::Integrations::Rack::Middleware
def call(env)
id = get_session_id(env)
if id
context = Contexts::Session.new(id: id)
CurrentContext.add(context.to_hash)
end
@app.call(env)
end
private
def get_session_id(env)
session_key = ::Rails.application.config.session_options[:key]
request = ::ActionDispatch::Request.new(env)
extract_from_cookie(request, session_key)
rescue Exception => e
nil
end
def extract_from_cookie(request, session_key)
data = request
.cookie_jar
.signed_or_encrypted[session_key] || {}
data["session_id"]
end
end
end
end
end

View file

@ -1,7 +0,0 @@
module Timber
module Integrations
module Rails
VERSION = "1.0.2"
end
end
end

View file

@ -1,19 +0,0 @@
# Testing
To get started:
```shell
bundle install
```
Be sure to install specific Gemfile dependencies:
```
BUNDLE_GEMFILE=gemfiles/rails-4.2.gemfile bundle install
```
You can run tests like this:
```shell
BUNDLE_GEMFILE=gemfiles/rails-4.2.gemfile bundle exec rspec
```

View file

@ -1,39 +0,0 @@
# Base
# require 'rubygems'
require 'bundler/setup'
# Testing
require 'rspec'
require 'rspec/its'
require 'rspec/mocks'
# Support files, order is relevant
require File.join(File.dirname(__FILE__), 'support', 'socket_hostname')
require File.join(File.dirname(__FILE__), 'support', 'timecop')
require File.join(File.dirname(__FILE__), 'support', 'webmock')
require File.join(File.dirname(__FILE__), 'support', 'timber')
# Load framework files after we've setup everything
if !ENV["RAILS_23"]
require File.join(File.dirname(__FILE__), 'support', 'rails')
require File.join(File.dirname(__FILE__), 'support', 'action_controller')
require File.join(File.dirname(__FILE__), 'support', 'active_record')
end
RSpec::Support::ObjectFormatter.default_instance.max_formatted_output_length = 5_000
RSpec.configure do |config|
config.color = true
config.order = :random
config.warnings = false
# Enable flags like --only-failures and --next-failure
config.example_status_persistence_file_path = ".rspec_status"
# Disable RSpec exposing methods globally on `Module` and `main`
config.disable_monkey_patching!
config.expect_with :rspec do |c|
c.syntax = :expect
end
end

View file

@ -1,2 +0,0 @@
require "action_controller"
::ActionController::Base.prepend_view_path("#{File.dirname(__FILE__)}/rails/templates")

View file

@ -1,26 +0,0 @@
require 'active_record'
ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
ActiveRecord::Schema.define do
self.verbose = false
create_table :organizations, :force => true do |t|
t.string :name
t.timestamps :null => false
end
create_table :users, :force => true do |t|
t.integer :age
t.string :email
t.string :first_name
t.timestamps :null => false
end
end
class Organization < ::ActiveRecord::Base
end
class User < ::ActiveRecord::Base
end

View file

@ -1,77 +0,0 @@
require "rails"
require "timber-rails/railtie"
# Defualt the rails logger to nothing, each test shoould be
# responsible for setting up the logger
logger = Timber::Logger.new(nil) # change to STDOUT to see rails logs
Rails.logger = logger
class RailsApp < Rails::Application
if ::Rails.version =~ /^3\./
config.secret_token = '1e05af2b349457936a41427e63450937'
else
config.secret_key_base = '1e05af2b349457936a41427e63450937'
end
# This ensures our tests fail, otherwise exceptions get swallowed by ActionDispatch::DebugExceptions
config.action_dispatch.show_exceptions = false
config.active_support.deprecation = :stderr
config.eager_load = false
end
RailsApp.initialize!
module Support
module Rails
def dispatch_rails_request(path, additional_env_options = {})
application = ::Rails.application
env = application.respond_to?(:env_config) ? application.env_config.clone : application.env_defaults.clone
env["rack.request.cookie_hash"] = {}.with_indifferent_access
env["CONTENT_LENGTH"] = 100
env["REMOTE_ADDR"] = "123.456.789.10"
env["HTTP_X_REQUEST_ID"] = "unique-request-id-1234"
env["action_dispatch.request_id"] = env["HTTP_X_REQUEST_ID"]
env = env.merge(additional_env_options)
::Rack::MockRequest.new(application).get(path, env)
end
def with_rails_logger(logger)
old_logger = ::Rails.logger
# We have to set these again because rails set's these after initialization.
# Since we've already booted the rails app we need to update them all as we
# change the logger.
#
# You can see here that they use simple class attribute, hence the reason we need
# to update all of them: https://github.com/rails/rails/blob/700ec897f97c60016ad748236bf3a49ef15a20de/actionview/lib/action_view/base.rb#L157
::ActionCable::Server::Base.logger = logger if defined?(::ActionCable::Server::Base) && ::ActionCable::Server::Base.respond_to?(:logger=)
::ActionController::Base.logger = logger if defined?(::ActionController::Base) && ::ActionController::Base.respond_to?(:logger=)
::ActionMailer::Base.logger = logger if defined?(::ActionMailer::Base) && ::ActionMailer::Base.respond_to?(:logger=)
::ActionView::Base.logger = logger if defined?(::ActionView::Base) && ::ActionView::Base.respond_to?(:logger=)
::ActiveRecord::Base.logger = logger if defined?(::ActiveRecord::Base) && ::ActiveRecord::Base.respond_to?(:logger=)
::Rails.logger = logger
yield
::Rails.logger = old_logger
end
end
end
# This is necessary as tests use Timber::Config.send(:new) to create
# an instance of the Config class instead of the Timber::Config
# singleton.
module Timber
class Config
def logrageify!
integrations.action_controller.silence = true
integrations.action_view.silence = true
integrations.active_record.silence = true
integrations.rack.http_events.collapse_into_single_event = true
end
end
end
RSpec.configure do |config|
config.include Support::Rails
end

View file

@ -1,12 +0,0 @@
require "socket"
# Stub out the hostname for tests only. This can't use a normal stub in the
# test life cycle since our test rails app is loaded once upon initialization.
# In other words, the rails app gets loaded with the server context inserted
# before any tests are run.
class ::Socket
def self.gethostname
"computer-name.domain.com"
end
end

View file

@ -1,6 +0,0 @@
require "timber-rails"
require "timber"
require "timber/config"
config = Timber::Config.instance
config.environment = "production"

View file

@ -1,3 +0,0 @@
require 'timecop'
Timecop.safe_mode = true

View file

@ -1,3 +0,0 @@
require 'webmock/rspec'
WebMock.disable_net_connect!

View file

@ -1,53 +0,0 @@
require "spec_helper"
RSpec.describe Timber::Integrations::ActionController::LogSubscriber do
let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
let(:io) { StringIO.new }
let(:logger) do
logger = Timber::Logger.new(io)
logger.level = ::Logger::INFO
logger
end
describe "#insert!" do
around(:each) do |example|
class LogSubscriberController < ActionController::Base
layout nil
def index
render json: {}
end
def method_for_action(action_name)
action_name
end
end
::RailsApp.routes.draw do
get 'log_subscriber' => 'log_subscriber#index'
end
with_rails_logger(logger) do
Timecop.freeze(time) { example.run }
end
Object.send(:remove_const, :LogSubscriberController)
end
it "should log a controller_call event once" do
# Rails uses this to calculate the view runtime below
allow(Benchmark).to receive(:ms).and_return(1).and_yield
dispatch_rails_request("/log_subscriber?query=value")
lines = clean_lines(io.string.split("\n"))
expect(lines.length).to eq(3)
expect(lines[1]).to include("Processing by LogSubscriberController#index as HTML")
expect(lines[1]).to include('"controller_called":{"controller":"LogSubscriberController","action":"index","params_json"')
end
# Remove blank lines since Rails does this to space out requests in the logs
def clean_lines(lines)
lines.select { |line| !line.start_with?(" @metadat") }
end
end
end

View file

@ -1,52 +0,0 @@
require "spec_helper"
RSpec.describe Timber::Integrations::ActionDispatch::DebugExceptions do
let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
let(:io) { StringIO.new }
let(:logger) do
logger = Timber::Logger.new(io)
logger.level = ::Logger::DEBUG
logger
end
describe "#insert!" do
around(:each) do |example|
class ExceptionController < ActionController::Base
layout nil
def index
raise "boom"
end
def method_for_action(action_name)
action_name
end
end
::RailsApp.routes.draw do
get 'exception' => 'exception#index'
end
with_rails_logger(logger) do
Timecop.freeze(time) { example.run }
end
Object.send(:remove_const, :ExceptionController)
end
it "should log an exception event once" do
expect { dispatch_rails_request("/exception") }.to raise_error(RuntimeError)
lines = clean_lines(io.string.split("\n"))
expect(lines.length).to eq(3)
expect(lines[2]).to include('RuntimeError (boom)')
expect(lines[2]).to include('fatal')
expect(lines[2]).to include("\"error\":{\"name\":\"RuntimeError\",\"message\":\"boom\",\"backtrace_json\":\"[")
end
# Remove blank lines since Rails does this to space out requests in the logs
def clean_lines(lines)
lines.select { |line| !line.start_with?(" @metadat") }
end
end
end

View file

@ -1,113 +0,0 @@
require "spec_helper"
RSpec.describe Timber::Integrations::ActionView::LogSubscriber do
let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
let(:io) { StringIO.new }
let(:logger) do
logger = Timber::Logger.new(io)
logger.level = ::Logger::WARN
logger
end
describe "insert!" do
around(:each) do |example|
class ActionViewLogSubscriberController < ActionController::Base
layout nil
def index
render template: "template"
end
def method_for_action(action_name)
action_name
end
end
::RailsApp.routes.draw do
get 'action_view_log_subscriber' => 'action_view_log_subscriber#index'
end
with_rails_logger(logger) do
Timecop.freeze(time) { example.run }
end
Object.send(:remove_const, :ActionViewLogSubscriberController)
end
describe "#render_template" do
it "should not log if the level is not sufficient" do
dispatch_rails_request("/action_view_log_subscriber")
expect(io.string).to eq("")
end
context "with an info level" do
around(:each) do |example|
old_level = logger.level
logger.level = ::Logger::INFO
example.run
logger.level = old_level
end
it "should log a template render event once" do
dispatch_rails_request("/action_view_log_subscriber")
lines = clean_lines(io.string.split("\n"))
expect(lines[2].strip).to match(/Rendered spec\/support\/rails\/templates\/template.html \(\d+\.\d+ms\)/)
expect(lines[2]).to include("\"template_rendered\":{\"name\":\"spec/support/rails/templates/template.html\"")
end
end
end
end
if defined?(described_class::TimberLogSubscriber)
describe described_class::TimberLogSubscriber do
let(:event) do
event = Struct.new(:duration, :payload)
event.new(2.0, identifier: "path/to/template.html")
end
around(:each) do |example|
old_level = logger.level
logger.level = ::Logger::INFO
example.run
logger.level = old_level
end
describe "#render_template" do
it "should render the collection" do
log_subscriber = described_class.new
allow(log_subscriber).to receive(:logger).and_return(logger)
log_subscriber.render_template(event)
expect(io.string.strip).to include("Rendered path/to/template.html (2.0ms)")
end
end
describe "#render_partial" do
it "should render the collection" do
log_subscriber = described_class.new
allow(log_subscriber).to receive(:logger).and_return(logger)
log_subscriber.render_partial(event)
expect(io.string.strip).to include("Rendered path/to/template.html (2.0ms)")
end
end
describe "#render_collection" do
it "should render the collection" do
log_subscriber = described_class.new
allow(log_subscriber).to receive(:logger).and_return(logger)
log_subscriber.render_collection(event)
if log_subscriber.respond_to?(:render_count, true)
expect(io.string.strip).to include("Rendered collection of path/to/template.html [ times] (2.0ms)")
else
expect(io.string.strip).to include("Rendered path/to/template.html (2.0ms)")
end
end
end
end
end
# Remove blank lines since Rails does this to space out requests in the logs
def clean_lines(lines)
lines.select { |line| !line.start_with?(" @metadata") }
end
end

View file

@ -1,44 +0,0 @@
require "spec_helper"
RSpec.describe Timber::Integrations::ActiveRecord::LogSubscriber do
let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
let(:io) { StringIO.new }
let(:logger) do
logger = Timber::Logger.new(io)
logger.level = ::Logger::INFO
logger
end
describe "#insert!" do
around(:each) do |example|
with_rails_logger(logger) do
Timecop.freeze(time) { example.run }
end
end
it "should not log if the level is not sufficient" do
ActiveRecord::Base.connection.execute("select * from users")
expect(io.string).to eq("")
end
context "with an info level" do
around(:each) do |example|
old_level = logger.level
logger.level = ::Logger::DEBUG
example.run
logger.level = old_level
end
it "should log the sql query" do
ActiveRecord::Base.connection.execute("select * from users")
# Rails 4.X adds random spaces :/
string = io.string.gsub(" ORDER BY", " ORDER BY")
string = string.gsub(" ORDER BY", " ORDER BY")
expect(string).to include("select * from users")
expect(string).to include("duration_ms")
expect(string).to include("\"level\":\"debug\"")
expect(string).to include("\"sql_query_executed\":")
end
end
end
end

View file

@ -1,30 +0,0 @@
require "singleton"
require "spec_helper"
RSpec.describe Timber::Config, :rails_23 => true do
let(:config) { Timber::Config.send(:new) }
describe ".logrageify!" do
it "should logrageify!" do
expect(Timber::Integrations::ActionController.silence?).to eq(false)
expect(Timber::Integrations::ActionView.silence?).to eq(false)
expect(Timber::Integrations::ActiveRecord.silence?).to eq(false)
expect(Timber::Integrations::Rack::HTTPEvents.collapse_into_single_event?).to eq(false)
config.logrageify!
expect(Timber::Integrations::ActionController.silence?).to eq(true)
expect(Timber::Integrations::ActionView.silence?).to eq(true)
expect(Timber::Integrations::ActiveRecord.silence?).to eq(true)
expect(Timber::Integrations::Rack::HTTPEvents.collapse_into_single_event?).to eq(true)
# Reset
Timber::Integrations::ActionController.silence = false
Timber::Integrations::ActionView.silence = false
Timber::Integrations::ActiveRecord.silence = false
Timber::Integrations::Rack::HTTPEvents.collapse_into_single_event = false
end
end
end

View file

@ -1,62 +0,0 @@
require "spec_helper"
RSpec.describe Timber::Integrations::Rails::ErrorEvent do
let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
let(:io) { StringIO.new }
let(:logger) do
logger = Timber::Logger.new(io)
logger.level = ::Logger::INFO
logger
end
around(:each) do |example|
class RackErrorController < ActionController::Base
layout nil
hook_name = respond_to?(:before_action) ? "before_action" : "before_filter"
send(hook_name) do
raise "Boom!"
end
def index
Thread.current[:_timber_context_snapshot] = Timber::CurrentContext.instance.snapshot
render json: {}
end
def method_for_action(action_name)
action_name
end
end
::RailsApp.routes.draw do
get '/rack_error' => 'rack_error#index'
end
with_rails_logger(logger) do
Timecop.freeze(time) { example.run }
end
Object.send(:remove_const, :RackErrorController)
end
describe "#process" do
it "should log the exception" do
allow(Benchmark).to receive(:ms).and_return(1).and_yield
expect { dispatch_rails_request("/rack_error") }.to raise_error(RuntimeError)
lines = clean_lines(io.string.split("\n"))
expect(lines.length).to eq(3)
expect(lines[0]).to include("Started GET \\\"/rack_error\\\"")
expect(lines[1]).to include("Processing by RackErrorController#index as HTML")
expect(lines[2]).to include("RuntimeError (Boom!)")
end
end
# Remove blank lines since Rails does this to space out requests in the logs
def clean_lines(lines)
lines.select { |line| !line.start_with?(" @metadat") }
end
end

View file

@ -1,58 +0,0 @@
require "spec_helper"
RSpec.describe Timber::Integrations::Rack::HTTPContext do
let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
let(:io) { StringIO.new }
let(:logger) do
logger = Timber::Logger.new(io)
logger.level = ::Logger::INFO
logger
end
around(:each) do |example|
class RackHttpController < ActionController::Base
layout nil
def index
Thread.current[:_timber_context_snapshot] = Timber::CurrentContext.instance.snapshot
render json: {}
end
def method_for_action(action_name)
action_name
end
end
::RailsApp.routes.draw do
get '/rack_http' => 'rack_http#index'
end
with_rails_logger(logger) do
Timecop.freeze(time) { example.run }
end
Object.send(:remove_const, :RackHttpController)
end
describe "#process" do
it "should set the context" do
allow(Benchmark).to receive(:ms).and_return(1).and_yield
dispatch_rails_request("/rack_http")
http_context = Thread.current[:_timber_context_snapshot][:http]
expect(http_context).to eq({:host => "example.org", :method=>"GET", :path=>"/rack_http", :remote_addr=>"123.456.789.10", :request_id=>"unique-request-id-1234"})
lines = clean_lines(io.string.split("\n"))
expect(lines.length).to eq(3)
lines.each do |line|
expect(line).to include("\"http\":{\"host\":\"example.org\",\"method\":\"GET\",\"path\":\"/rack_http\",\"remote_addr\":\"123.456.789.10\",\"request_id\":\"unique-request-id-1234\"}")
end
end
end
# Remove blank lines since Rails does this to space out requests in the logs
def clean_lines(lines)
lines.select { |line| !line.start_with?(" @metadat") }
end
end

View file

@ -1,99 +0,0 @@
require "spec_helper"
RSpec.describe Timber::Integrations::Rack::HTTPEvents do
let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
let(:io) { StringIO.new }
let(:logger) do
logger = Timber::Logger.new(io)
logger.level = ::Logger::INFO
logger
end
around(:each) do |example|
class RackHttpController < ActionController::Base
layout nil
def index
Thread.current[:_timber_context_snapshot] = Timber::CurrentContext.instance.snapshot
render json: {}
end
def method_for_action(action_name)
action_name
end
end
::RailsApp.routes.draw do
get '/rack_http' => 'rack_http#index'
end
with_rails_logger(logger) do
Timecop.freeze(time) { example.run }
end
Object.send(:remove_const, :RackHttpController)
end
describe "#process" do
it "should log the events" do
allow(Benchmark).to receive(:ms).and_return(1).and_yield
dispatch_rails_request("/rack_http")
lines = clean_lines(io.string.split("\n"))
expect(lines.length).to eq(3)
expect(lines[0]).to include("Started GET \\\"/rack_http\\\"")
expect(lines[1]).to include("Processing by RackHttpController#index as HTML")
expect(lines[2]).to include("Completed 200 OK in 0.0ms")
end
context "with the route silenced" do
around(:each) do |example|
described_class.silence_request = lambda do |rack_env, rack_request|
rack_request.path == "/rack_http"
end
example.run
described_class.silence_request = nil
end
it "should silence the logs" do
allow(Benchmark).to receive(:ms).and_return(1).and_yield
dispatch_rails_request("/rack_http")
lines = clean_lines(io.string.split("\n"))
expect(lines.length).to eq(0)
end
end
context "collapsed into a single event" do
around(:each) do |example|
described_class.collapse_into_single_event = true
example.run
described_class.collapse_into_single_event = nil
end
it "should silence the logs" do
allow(Benchmark).to receive(:ms).and_return(1).and_yield
dispatch_rails_request("/rack_http")
lines = clean_lines(io.string.split("\n"))
expect(lines.length).to eq(2)
expect(lines[0]).to include("Processing by RackHttpController#index as HTML")
expect(lines[1]).to include("GET /rack_http completed with 200 OK in 0.0ms")
end
end
end
# Remove blank lines since Rails does this to space out requests in the logs
def clean_lines(lines)
lines.select { |line| !line.start_with?(" @metadat") }
end
end

View file

@ -1,16 +0,0 @@
require "spec_helper"
RSpec.describe Timber::Logger, :rails_23 => true do
describe "#silence" do
let(:io) { StringIO.new }
let(:logger) { Timber::Logger.new(io) }
it "should silence the logs" do
logger.silence do
logger.info("test")
end
expect(io.string).to eq("")
end
end
end

View file

@ -1,56 +0,0 @@
require "spec_helper"
RSpec.describe Timber::Integrations::Rails::RackLogger do
describe described_class::InstanceMethods do
let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
let(:io) { StringIO.new }
let(:logger) do
logger = Timber::Logger.new(io)
logger.level = ::Logger::INFO
logger
end
around(:each) do |example|
class RailsRackLoggerController < ActionController::Base
layout nil
def index
render json: {}
end
def method_for_action(action_name)
action_name
end
end
::RailsApp.routes.draw do
get '/rails_rack_logger' => 'rails_rack_logger#index'
end
with_rails_logger(logger) do
Timecop.freeze(time) { example.run }
end
Object.send(:remove_const, :RailsRackLoggerController)
end
describe "#started_request_message" do
it "should mute the default rails logs" do
allow(::Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new("production")) # Rails 3.2.X
dispatch_rails_request("/rails_rack_logger")
lines = clean_lines(io.string.split("\n"))
expect(lines.length).to eq(3)
expect(lines[0]).to include("Started GET \\\"/rails_rack_logger\\\"")
expect(lines[1]).to include("Processing by RailsRackLoggerController#index as HTML")
expect(lines[2]).to include("Completed 200 OK in 0.0ms")
end
end
end
# Remove blank lines since Rails does this to space out requests in the logs
def clean_lines(lines)
lines.select { |line| !line.start_with?(" @metadat") }
end
end

View file

@ -1,11 +0,0 @@
require "spec_helper"
RSpec.describe Timber::Integrations::Rails::SessionContext do
let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
let(:io) { StringIO.new }
let(:logger) do
logger = Timber::Logger.new(io)
logger.level = ::Logger::INFO
logger
end
end

View file

@ -1,29 +0,0 @@
require "spec_helper"
RSpec.describe ActiveSupport::TaggedLogging, :rails_23 => true do
describe "#new" do
let(:io) { StringIO.new }
it "should instantiate for Timber::Logger object" do
ActiveSupport::TaggedLogging.new(Timber::Logger.new(io))
end
if defined?(ActiveSupport::BufferedLogger)
it "should instantiate for a ActiveSupport::BufferedLogger object" do
ActiveSupport::TaggedLogging.new(ActiveSupport::BufferedLogger.new(io))
end
end
end
describe "#info" do
let(:time) { Time.utc(2016, 9, 1, 12, 0, 0) }
let(:io) { StringIO.new }
let(:logger) { ActiveSupport::TaggedLogging.new(Timber::Logger.new(io)) }
it "should accept events as the second argument" do
logger.info("SQL query", payment_rejected: {customer_id: "abcd1234", amount: 100, reason: "Card expired"})
expect(io.string).to include("SQL query")
expect(io.string).to include("\"payment_rejected\":")
end
end
end

View file

@ -1,55 +0,0 @@
# -*- encoding: utf-8 -*-
# stub: timber-rails 1.0.2 ruby lib
Gem::Specification.new do |s|
s.name = "timber-rails".freeze
s.version = "1.0.2"
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
s.metadata = { "changelog_uri" => "https://github.com/timberio/timber-ruby-rails/blob/master/README.md", "homepage_uri" => "https://docs.timber.io/languages/ruby/", "source_code_uri" => "https://github.com/timberio/timber-ruby-rails" } if s.respond_to? :metadata=
s.require_paths = ["lib".freeze]
s.authors = ["Timber Technologies, Inc.".freeze]
s.bindir = "exe".freeze
s.date = "2020-06-01"
s.email = ["hi@timber.io".freeze]
s.files = [".gitignore".freeze, ".rspec".freeze, ".travis.yml".freeze, "Gemfile".freeze, "LICENSE.md".freeze, "README.md".freeze, "Rakefile".freeze, "bin/console".freeze, "bin/setup".freeze, "gemfiles/rails-3.0.gemfile".freeze, "gemfiles/rails-3.1.gemfile".freeze, "gemfiles/rails-3.2.gemfile".freeze, "gemfiles/rails-4.0.gemfile".freeze, "gemfiles/rails-4.1.gemfile".freeze, "gemfiles/rails-4.2.gemfile".freeze, "gemfiles/rails-5.0.gemfile".freeze, "gemfiles/rails-5.1.gemfile".freeze, "gemfiles/rails-5.2.gemfile".freeze, "gemfiles/rails-6.0.gemfile".freeze, "gemfiles/rails-edge.gemfile".freeze, "lib/timber-rails.rb".freeze, "lib/timber-rails/action_controller.rb".freeze, "lib/timber-rails/action_controller/log_subscriber.rb".freeze, "lib/timber-rails/action_controller/log_subscriber/timber_log_subscriber.rb".freeze, "lib/timber-rails/action_dispatch.rb".freeze, "lib/timber-rails/action_dispatch/debug_exceptions.rb".freeze, "lib/timber-rails/action_view.rb".freeze, "lib/timber-rails/action_view/log_subscriber.rb".freeze, "lib/timber-rails/action_view/log_subscriber/timber_log_subscriber.rb".freeze, "lib/timber-rails/active_record.rb".freeze, "lib/timber-rails/active_record/log_subscriber.rb".freeze, "lib/timber-rails/active_record/log_subscriber/timber_log_subscriber.rb".freeze, "lib/timber-rails/active_support_log_subscriber.rb".freeze, "lib/timber-rails/config.rb".freeze, "lib/timber-rails/config/action_controller.rb".freeze, "lib/timber-rails/config/action_view.rb".freeze, "lib/timber-rails/config/active_record.rb".freeze, "lib/timber-rails/error_event.rb".freeze, "lib/timber-rails/logger.rb".freeze, "lib/timber-rails/overrides.rb".freeze, "lib/timber-rails/overrides/active_support_3_tagged_logging.rb".freeze, "lib/timber-rails/overrides/active_support_buffered_logger.rb".freeze, "lib/timber-rails/overrides/active_support_tagged_logging.rb".freeze, "lib/timber-rails/overrides/lograge.rb".freeze, "lib/timber-rails/overrides/rails_stdout_logging.rb".freeze, "lib/timber-rails/rack_logger.rb".freeze, "lib/timber-rails/railtie.rb".freeze, "lib/timber-rails/session_context.rb".freeze, "lib/timber-rails/version.rb".freeze, "timber-rails.gemspec".freeze]
s.homepage = "https://docs.timber.io/languages/ruby/".freeze
s.licenses = ["ISC".freeze]
s.required_ruby_version = Gem::Requirement.new(">= 1.9.0".freeze)
s.rubygems_version = "3.1.2".freeze
s.summary = "Timber.io Rails integration".freeze
s.installed_by_version = "3.1.2" if s.respond_to? :installed_by_version
if s.respond_to? :specification_version then
s.specification_version = 4
end
if s.respond_to? :add_runtime_dependency then
s.add_runtime_dependency(%q<rails>.freeze, [">= 3.0.0"])
s.add_runtime_dependency(%q<timber>.freeze, ["~> 3.0"])
s.add_runtime_dependency(%q<timber-rack>.freeze, ["~> 1.0"])
s.add_development_dependency(%q<bundler>.freeze, [">= 0.0"])
s.add_development_dependency(%q<rake>.freeze, [">= 0.8"])
s.add_development_dependency(%q<rspec>.freeze, ["~> 3.0"])
s.add_development_dependency(%q<bundler-audit>.freeze, [">= 0"])
s.add_development_dependency(%q<rails_stdout_logging>.freeze, [">= 0"])
s.add_development_dependency(%q<rspec-its>.freeze, [">= 0"])
s.add_development_dependency(%q<timecop>.freeze, [">= 0"])
s.add_development_dependency(%q<sqlite3>.freeze, ["= 1.3.13"])
s.add_development_dependency(%q<webmock>.freeze, ["~> 2.3"])
else
s.add_dependency(%q<rails>.freeze, [">= 3.0.0"])
s.add_dependency(%q<timber>.freeze, ["~> 3.0"])
s.add_dependency(%q<timber-rack>.freeze, ["~> 1.0"])
s.add_dependency(%q<bundler>.freeze, [">= 0.0"])
s.add_dependency(%q<rake>.freeze, [">= 0.8"])
s.add_dependency(%q<rspec>.freeze, ["~> 3.0"])
s.add_dependency(%q<bundler-audit>.freeze, [">= 0"])
s.add_dependency(%q<rails_stdout_logging>.freeze, [">= 0"])
s.add_dependency(%q<rspec-its>.freeze, [">= 0"])
s.add_dependency(%q<timecop>.freeze, [">= 0"])
s.add_dependency(%q<sqlite3>.freeze, ["= 1.3.13"])
s.add_dependency(%q<webmock>.freeze, ["~> 2.3"])
end
end