Module: Heavylog

Defined in:
lib/heavylog.rb,
lib/heavylog/railtie.rb,
lib/heavylog/version.rb,
lib/heavylog/middleware.rb,
lib/heavylog/proxy_logger.rb,
lib/heavylog/formatters/ecs.rb,
lib/heavylog/formatters/raw.rb,
lib/heavylog/log_subscriber.rb,
lib/heavylog/request_logger.rb,
lib/heavylog/formatters/json.rb,
lib/heavylog/ordered_options.rb,
lib/heavylog/sidekiq_exception_handler.rb

Defined Under Namespace

Modules: Formatters, RequestLogger Classes: LogSubscriber, Middleware, OrderedOptions, ProxyLogger, Railtie, SidekiqExceptionHandler

Constant Summary collapse

TRUNCATION =
"[TRUNCATED]"
ANSI_REGEX =
/\e\[(\d+)m/.freeze
VERSION =
"0.1.0"

Class Method Summary collapse

Class Method Details

.attach_to_action_controllerObject



56
57
58
# File 'lib/heavylog.rb', line 56

def attach_to_action_controller
  Heavylog::LogSubscriber.attach_to :action_controller
end

.attach_to_sidekiqObject



60
61
62
63
64
65
66
67
68
# File 'lib/heavylog.rb', line 60

def attach_to_sidekiq
  return unless config.log_sidekiq

  Sidekiq.configure_server do |config|
    config[:job_logger] = SidekiqLogger

    config.error_handlers << SidekiqExceptionHandler.new
  end
end

.configObject



159
160
161
162
163
# File 'lib/heavylog.rb', line 159

def config
  return OrderedOptions.new unless application

  application.config.heavylog
end

.extend_base_controller_class(klass) ⇒ Object



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

def extend_base_controller_class(klass)
  append_payload_method = klass.instance_method(:append_info_to_payload)
  custom_payload_method = config.custom_payload_method

  klass.send(:define_method, :append_info_to_payload) do |payload|
    append_payload_method.bind(self).call(payload)
    payload[:custom_payload] = custom_payload_method.call(self)
  end
end

.finishObject



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/heavylog.rb', line 135

def finish
  return unless config.enabled

  buffer = RequestStore.store[:heavylog_buffer]
  return unless buffer && Heavylog.logger

  request = {
    request_id:    RequestStore.store[:heavylog_request_id],
    request_start: RequestStore.store[:heavylog_request_start],
    ip:            RequestStore.store[:heavylog_request_ip],
    messages:      buffer.string.dup,
  }.merge(RequestStore.store[:heavylog_request_data] || {})

  formatted = Heavylog.formatter.call(request.transform_keys(&:to_s))
  Heavylog.logger.send(Heavylog.log_level, formatted)
rescue StandardError => e
  config.error_handler&.(e)
end

.finish_sidekiqObject



154
155
156
157
# File 'lib/heavylog.rb', line 154

def finish_sidekiq
  finish
  RequestStore.store[:heavylog_buffer] = nil
end

.log(_severity, message = nil, progname = nil) ⇒ Object



89
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
# File 'lib/heavylog.rb', line 89

def log(_severity, message=nil, progname=nil)
  return unless config.enabled
  return if !!RequestStore.store[:heavylog_truncated]

  uuid = RequestStore.store[:heavylog_request_id]
  return unless uuid

  if message.nil?
    message =
      if block_given?
        yield
      else
        progname
      end
  end

  message = message.gsub(ANSI_REGEX, "") if message.respond_to?(:gsub)
  message = message.map { |m| m.respond_to?(:gsub) ? m.gsub(ANSI_REGEX, "") : m } if message.is_a?(Array)

  RequestStore.store[:heavylog_buffer] ||= StringIO.new

  if RequestStore.store[:heavylog_buffer].length + message_size(message) > config.message_limit
    RequestStore.store[:heavylog_buffer].truncate(0)
    RequestStore.store[:heavylog_buffer].puts(TRUNCATION)
    RequestStore.store[:heavylog_truncated] = true
  else
    RequestStore.store[:heavylog_buffer].puts(message)
  end
end

.log_sidekiq(jid, klass, args) ⇒ Object



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/heavylog.rb', line 119

def log_sidekiq(jid, klass, args)
  return unless config.enabled

  RequestStore.store[:heavylog_request_id] = jid
  RequestStore.store[:heavylog_request_start] = Time.now.iso8601
  RequestStore.store[:heavylog_request_ip] = "127.0.0.1"

  RequestStore.store[:heavylog_request_data] = {
    controller: "SidekiqLogger",
    action:     klass,
    args:       args.to_s,
  }

  RequestStore.store[:heavylog_buffer] ||= StringIO.new
end

.message_size(message) ⇒ Object



165
166
167
168
169
170
# File 'lib/heavylog.rb', line 165

def message_size(message)
  return message.bytesize if message.respond_to?(:bytesize)
  return message.map(&:to_s).sum(&:bytesize) if message.is_a?(Array)

  message.to_s.length
end

.patch_loggersObject



32
33
34
35
36
37
38
39
40
# File 'lib/heavylog.rb', line 32

def patch_loggers
  return unless defined?(Rails)

  if Rails.logger.respond_to?(:broadcast_to)
    Rails.logger.broadcast_to(ProxyLogger.new)
  else
    Rails.logger.extend(RequestLogger)
  end
end

.set_optionsObject



42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/heavylog.rb', line 42

def set_options
  if config.path
    f = File.open(config.path, "a")
    f.binmode
    f.sync = true

    Heavylog.logger = ActiveSupport::Logger.new(f)
  end

  Heavylog.formatter = config.formatter || Heavylog::Formatters::Raw.new
  Heavylog.log_level = config.log_level || :info
  Heavylog.ignore_path = config.ignore_path || nil
end

.setup(app) ⇒ Object



23
24
25
26
27
28
29
30
# File 'lib/heavylog.rb', line 23

def setup(app)
  self.application = app
  patch_loggers
  attach_to_action_controller
  attach_to_sidekiq
  setup_custom_payload
  set_options
end

.setup_custom_payloadObject



70
71
72
73
74
75
76
77
# File 'lib/heavylog.rb', line 70

def setup_custom_payload
  return unless config.custom_payload_method.respond_to?(:call)

  klasses = Array(config.base_controller_class)
  klasses.map! { |klass| klass.try(:constantize) }
  klasses.push(ActionController::Base, ActionController::API) if klasses.empty?
  klasses.each { |klass| extend_base_controller_class(klass) }
end