Module: Stasher

Defined in:
lib/stasher.rb,
lib/stasher/logger.rb,
lib/stasher/railtie.rb,
lib/stasher/version.rb,
lib/stasher/current_scope.rb,
lib/stasher/log_subscriber.rb

Defined Under Namespace

Modules: CurrentScope Classes: LogSubscriber, Logger, Railtie

Constant Summary collapse

VERSION =
"0.1.0"

Class Method Summary collapse

Class Method Details

.add_custom_fields(&block) ⇒ Object



41
42
43
# File 'lib/stasher.rb', line 41

def self.add_custom_fields(&block)
  ActionController::Metal.send(:define_method, :stasher_add_custom_fields_to_scope, &block)
end

.add_default_fields_to_scope(scope, request) ⇒ Object



37
38
39
# File 'lib/stasher.rb', line 37

def self.add_default_fields_to_scope(scope, request)
  scope[:uuid] = request.uuid
end

.format_exception(type_name, message, backtrace) ⇒ Object



80
81
82
83
84
85
86
87
88
# File 'lib/stasher.rb', line 80

def self.format_exception(type_name, message, backtrace)
  {
    :exception => { 
      :name => type_name,
      :message => message,
      :backtrace => backtrace
    }
  }
end

.hostnameObject



120
121
122
123
124
# File 'lib/stasher.rb', line 120

def self.hostname
  require 'socket'

  Socket.gethostname
end

.log(severity, msg) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/stasher.rb', line 90

def self.log(severity, msg)
  if self.logger && self.logger.send("#{severity.to_s.downcase}?")
    data = {
      :severity => severity.upcase
    }
    tags = ['log']

    if msg.is_a? Exception
      data.merge! self.format_exception(msg.class.name, msg.message, msg.backtrace.join("\n"))
      msg = "#{msg.class.name}: #{msg.message}"
      tags << 'exception'
    else        
      # Strip ANSI codes from the message
      msg.gsub!(/\u001B\[[0-9;]+m/, '')
    end

    return true if msg.empty?
    data.merge! CurrentScope.fields

    tags << severity.downcase

    event = LogStash::Event.new(
      '@fields' => data, 
      '@tags' => tags,
      '@message' => msg,
      '@source' => Stasher.source)
    self.logger << event.to_json + "\n"
  end
end

.remove_existing_log_subscriptionsObject



13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/stasher.rb', line 13

def self.remove_existing_log_subscriptions
  ActiveSupport::LogSubscriber.log_subscribers.each do |subscriber|
    case subscriber
      when ActionView::LogSubscriber
        unsubscribe(:action_view, subscriber)
      when ActiveRecord::LogSubscriber
        unsubscribe(:active_record, subscriber)
      when ActionController::LogSubscriber
        unsubscribe(:action_controller, subscriber)
    end
  end
end

.setup(app) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/stasher.rb', line 45

def self.setup(app)
  app.config.action_dispatch.rack_cache[:verbose] = false if app.config.action_dispatch.rack_cache

  # Compose source
  self.source = "rails://#{hostname}/#{app.class.name.deconstantize.underscore}"

  # Initialize & set up instrumentation
  require 'stasher/rails_ext/action_controller/metal/instrumentation'
  require 'logstash/event'      
  self.suppress_app_logs(app) if app.config.stasher.suppress_app_log

  # Redirect Rails' logger if requested
  Rails.logger = Stasher::Logger.new  if app.config.stasher.redirect_logger

  # Subscribe to configured events
  app.config.stasher.attach_to.each do |target|
    Stasher::LogSubscriber.attach_to target
  end

  # Initialize internal logger
  self.logger = app.config.stasher.logger || Logger.new("#{Rails.root}/log/logstash_#{Rails.env}.log")
  level = ::Logger.const_get(app.config.stasher.log_level.to_s.upcase) if app.config.stasher.log_level
  self.logger.level = level || Logger::WARN

  self.enabled = true
end

.suppress_app_logs(app) ⇒ Object



72
73
74
75
76
77
78
# File 'lib/stasher.rb', line 72

def self.suppress_app_logs(app)   
  require 'stasher/rails_ext/rack/logger'
  Stasher.remove_existing_log_subscriptions

  # Disable ANSI colorization
  app.config.colorize_logging = false
end

.unsubscribe(component, subscriber) ⇒ Object



26
27
28
29
30
31
32
33
34
35
# File 'lib/stasher.rb', line 26

def self.unsubscribe(component, subscriber)
  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