pvincent
2 months ago
4 changed files with 159 additions and 141 deletions
-
27lib/semantic/dev_loader.rb
-
124lib/semantic/log_subscriber.rb
-
130lib/semantic/subscribers/action_controller.rb
-
19lib/semantic/subscribers/action_view.rb
@ -1,124 +0,0 @@ |
|||
module Semantic |
|||
class LogSubscriber < ActiveSupport::LogSubscriber |
|||
include SemanticLogger::Loggable |
|||
include AnsiColors |
|||
def logger = SemanticLogger['Rails'] |
|||
|
|||
INTERNAL_PARAMS = %i[controller action format _method only_path].freeze |
|||
DEFAULT_DEV_HOSTS = ['127.0.0.1', 'localhost'].freeze |
|||
TERMINUS_STRING = '╙─╜'.freeze |
|||
|
|||
def initialize(session_key) |
|||
@session_key = session_key |
|||
@transactions = {} |
|||
super() |
|||
end |
|||
|
|||
def start_processing(event) |
|||
session_value = session_value(event) |
|||
@transactions[event.transaction_id] = session_value # preserve session_value to help finish_processing |
|||
|
|||
SemanticLogger.tagged(session_value) do |
|||
request = event.payload[:request] |
|||
path = colorize(request.filtered_path, BOLD) |
|||
|
|||
dimensions = Semantic::AnsiDimensions.new(rails: '╓─╖', before: 1) |
|||
if defined?(@previously_redirect) && @previously_redirect |
|||
dimensions = Semantic::AnsiDimensions.new(rails: '╓║╖', before: 0) |
|||
@previously_redirect = false |
|||
end |
|||
logger.info("Started #{request.raw_request_method} #{path}", dimensions:) |
|||
|
|||
format = event.payload[:format] |
|||
format = format.to_s.upcase if format.is_a?(Symbol) |
|||
format = '*/*' if format.nil? |
|||
format = colorize(format, BOLD) |
|||
logger.debug("Processing by #{event.payload[:controller]}##{event.payload[:action]} as #{format}") |
|||
|
|||
params = event.payload[:params].deep_symbolize_keys.except(*INTERNAL_PARAMS) |
|||
unless params.empty? |
|||
params = params.ai(ruby19_syntax: true, plain: true, multiline: false) |
|||
params.gsub!(/(\w+):/, "#{TEXT_CYAN}\\1#{CLEAR}:") |
|||
params.gsub!(/"(.*?)"/, "\"#{TEXT_YELLOW}\\1#{CLEAR}\"") |
|||
end |
|||
logger.debug("Parameters: #{params}") unless params.empty? |
|||
end |
|||
end |
|||
|
|||
def finish_processing(event) |
|||
session_value = @transactions.delete(event.transaction_id) # delete previous session_value from start_processing |
|||
SemanticLogger.tagged(session_value) do |
|||
payload = event.payload |
|||
additions = ActionController::Base.log_process_action(payload) |
|||
status = payload[:status] |
|||
|
|||
if status.nil? && (exception_class_name = payload[:exception]&.first) |
|||
status = ActionDispatch::ExceptionWrapper.status_code_for_exception(exception_class_name) |
|||
end |
|||
|
|||
additions << "GC: #{event.gc_time.round(1)}ms" |
|||
if event.duration >= 1200 |
|||
logger.error process_duration(event, additions) |
|||
elsif event.duration >= 600 |
|||
logger.warn process_duration(event, additions) |
|||
elsif event.duration >= 300 |
|||
logger.info process_duration(event, additions) |
|||
elsif event.duration >= 100 |
|||
logger.debug process_duration(event, additions) |
|||
end |
|||
|
|||
status_family = status / 100 |
|||
|
|||
dimensions = case status_family |
|||
when 2 |
|||
Semantic::AnsiDimensions.new(rails: TERMINUS_STRING) |
|||
when 3 |
|||
Semantic::AnsiDimensions.new(rails: '╙║╜') |
|||
when 4 |
|||
Semantic::AnsiDimensions.new(rails: '╙╨╜') |
|||
when 5 |
|||
Semantic::AnsiDimensions.new(rails: '╙║╜') |
|||
end |
|||
logger.info("Completed #{colorize(status, BOLD)} #{Rack::Utils::HTTP_STATUS_CODES[status]}", dimensions:) |
|||
logger.info(' ', dimensions: Semantic::AnsiDimensions.new(rails: ' ║ ')) if status_family == 3 |
|||
logger.info(' ', dimensions: Semantic::AnsiDimensions.new(rails: '╓║╖')) if status_family == 5 |
|||
end |
|||
end |
|||
|
|||
def redirect_to(event) |
|||
SemanticLogger.tagged(@transactions[event.transaction_id]) do |
|||
location = capture_path(event.payload[:location]) |
|||
logger.debug("Redirected to #{colorize(location, BOLD)}") |
|||
end |
|||
@previously_redirect = true |
|||
end |
|||
|
|||
def any_hook(event) |
|||
SemanticLogger.tagged(@transactions[event.transaction_id]) do |
|||
logger.warn("action_controller hook=<#{event.name.split('.')[0]}> needs a proper message handling!", |
|||
event.payload.keys) |
|||
end |
|||
end |
|||
|
|||
private |
|||
|
|||
def redirect_regex |
|||
return @redirect_regex if defined?(@redirect_regex) |
|||
|
|||
options = Rails.application.routes.default_url_options |
|||
dev_hosts = DEFAULT_DEV_HOSTS + Array.wrap(options[:host]) |
|||
dev_hosts_or = dev_hosts.uniq.join('|') |
|||
dev_from = "http://(?:#{dev_hosts_or}):#{options[:port]}(.*)" |
|||
|
|||
@redirect_regex = /^#{dev_from}/ |
|||
end |
|||
|
|||
def capture_path(url) |
|||
m = redirect_regex.match(url) |
|||
m.nil? ? url : m[1] |
|||
end |
|||
|
|||
def session_value(event) = event.payload[:headers]['rack.session'].fetch(@session_key, nil) |
|||
def process_duration(event, additions) = "Processed in #{event.duration.round}ms (#{additions.join(' | ')})" |
|||
end |
|||
end |
@ -0,0 +1,130 @@ |
|||
module Semantic |
|||
module Subscribers |
|||
class ActionController < ActiveSupport::LogSubscriber |
|||
include AnsiColors |
|||
|
|||
INTERNAL_PARAMS = %i[controller action format _method only_path].freeze |
|||
DEFAULT_DEV_HOSTS = ['127.0.0.1', 'localhost'].freeze |
|||
TERMINUS_STRING = '╙─╜'.freeze |
|||
|
|||
attr_reader :logger |
|||
|
|||
def initialize(session_key) |
|||
@session_key = session_key |
|||
@transactions = {} |
|||
|
|||
short_name = self.class.to_s.split('::').last |
|||
@logger = SemanticLogger[short_name] |
|||
|
|||
super() |
|||
end |
|||
|
|||
def start_processing(event) |
|||
session_value = session_value(event) |
|||
@transactions[event.transaction_id] = session_value # preserve session_value to help finish_processing |
|||
|
|||
SemanticLogger.tagged(session_value) do |
|||
request = event.payload[:request] |
|||
path = colorize(request.filtered_path, BOLD) |
|||
|
|||
dimensions = Semantic::AnsiDimensions.new(rails: '╓─╖', before: 1) |
|||
if defined?(@previously_redirect) && @previously_redirect |
|||
dimensions = Semantic::AnsiDimensions.new(rails: '╓║╖', before: 0) |
|||
@previously_redirect = false |
|||
end |
|||
logger.info("Started #{request.raw_request_method} #{path}", dimensions:) |
|||
|
|||
format = event.payload[:format] |
|||
format = format.to_s.upcase if format.is_a?(Symbol) |
|||
format = '*/*' if format.nil? |
|||
format = colorize(format, BOLD) |
|||
logger.debug("Processing by #{event.payload[:controller]}##{event.payload[:action]} as #{format}") |
|||
|
|||
params = event.payload[:params].deep_symbolize_keys.except(*INTERNAL_PARAMS) |
|||
unless params.empty? |
|||
params = params.ai(ruby19_syntax: true, plain: true, multiline: false) |
|||
params.gsub!(/(\w+):/, "#{TEXT_CYAN}\\1#{CLEAR}:") |
|||
params.gsub!(/"(.*?)"/, "\"#{TEXT_YELLOW}\\1#{CLEAR}\"") |
|||
end |
|||
logger.debug("Parameters: #{params}") unless params.empty? |
|||
end |
|||
end |
|||
|
|||
def finish_processing(event) |
|||
session_value = @transactions.delete(event.transaction_id) # delete previous session_value from start_processing |
|||
SemanticLogger.tagged(session_value) do |
|||
payload = event.payload |
|||
additions = ::ActionController::Base.log_process_action(payload) |
|||
status = payload[:status] |
|||
|
|||
if status.nil? && (exception_class_name = payload[:exception]&.first) |
|||
status = ::ActionDispatch::ExceptionWrapper.status_code_for_exception(exception_class_name) |
|||
end |
|||
|
|||
additions << "GC: #{event.gc_time.round(1)}ms" |
|||
if event.duration >= 1200 |
|||
logger.error process_duration(event, additions) |
|||
elsif event.duration >= 600 |
|||
logger.warn process_duration(event, additions) |
|||
elsif event.duration >= 300 |
|||
logger.info process_duration(event, additions) |
|||
elsif event.duration >= 100 |
|||
logger.debug process_duration(event, additions) |
|||
end |
|||
|
|||
status_family = status / 100 |
|||
|
|||
dimensions = case status_family |
|||
when 2 |
|||
Semantic::AnsiDimensions.new(rails: TERMINUS_STRING) |
|||
when 3 |
|||
Semantic::AnsiDimensions.new(rails: '╙║╜') |
|||
when 4 |
|||
Semantic::AnsiDimensions.new(rails: '╙╨╜') |
|||
when 5 |
|||
Semantic::AnsiDimensions.new(rails: '╙║╜') |
|||
end |
|||
logger.info("Completed #{colorize(status, BOLD)} #{Rack::Utils::HTTP_STATUS_CODES[status]}", dimensions:) |
|||
logger.info(' ', dimensions: Semantic::AnsiDimensions.new(rails: ' ║ ')) if status_family == 3 |
|||
logger.info(' ', dimensions: Semantic::AnsiDimensions.new(rails: '╓║╖')) if status_family == 5 |
|||
end |
|||
end |
|||
|
|||
def redirect_to(event) |
|||
SemanticLogger.tagged(@transactions[event.transaction_id]) do |
|||
location = capture_path(event.payload[:location]) |
|||
logger.debug("Redirected to #{colorize(location, BOLD)}") |
|||
end |
|||
@previously_redirect = true |
|||
end |
|||
|
|||
def any_hook(event) |
|||
SemanticLogger.tagged(@transactions[event.transaction_id]) do |
|||
logger.warn("action_controller hook=<#{event.name.split('.')[0]}> needs a proper message handling!", |
|||
event.payload.keys) |
|||
end |
|||
end |
|||
|
|||
private |
|||
|
|||
def redirect_regex |
|||
return @redirect_regex if defined?(@redirect_regex) |
|||
|
|||
options = Rails.application.routes.default_url_options |
|||
dev_hosts = DEFAULT_DEV_HOSTS + Array.wrap(options[:host]) |
|||
dev_hosts_or = dev_hosts.uniq.join('|') |
|||
dev_from = "http://(?:#{dev_hosts_or}):#{options[:port]}(.*)" |
|||
|
|||
@redirect_regex = /^#{dev_from}/ |
|||
end |
|||
|
|||
def capture_path(url) |
|||
m = redirect_regex.match(url) |
|||
m.nil? ? url : m[1] |
|||
end |
|||
|
|||
def session_value(event) = event.payload[:headers]['rack.session'].fetch(@session_key, nil) |
|||
def process_duration(event, additions) = "Processed in #{event.duration.round}ms (#{additions.join(' | ')})" |
|||
end |
|||
end |
|||
end |
@ -0,0 +1,19 @@ |
|||
module Semantic |
|||
module Subscribers |
|||
class ActionView < ActiveSupport::LogSubscriber |
|||
include AnsiColors |
|||
|
|||
attr_reader :logger |
|||
|
|||
def initialize |
|||
short_name = self.class.to_s.split('::').last |
|||
@logger = SemanticLogger[short_name] |
|||
super |
|||
end |
|||
|
|||
def render_partial(event) |
|||
logger.info('Rendered partial', event) |
|||
end |
|||
end |
|||
end |
|||
end |
Write
Preview
Loading…
Cancel
Save
Reference in new issue