You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

88 lines
3.1 KiB

2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
  1. module Semantic
  2. module Subscribers
  3. # LogSubscriber for event_group :active_record
  4. class ActiveRecord < LogSubscriber
  5. include AnsiColors
  6. IGNORE_PAYLOAD_NAMES = %w[SCHEMA EXPLAIN].freeze
  7. TRANSACTION_TAINT = AnsiColors::DARK_TEXT_CYAN
  8. def sql(event)
  9. name = event.payload[:name]
  10. return if IGNORE_PAYLOAD_NAMES.include?(name)
  11. category, model, *remaining = name.split.reverse
  12. return if category == 'TRANSACTION'
  13. statement_taint = AnsiColors::TEXT_GRAY_300
  14. case category
  15. when 'Count'
  16. name = "#{category} #{model}"
  17. when 'Load'
  18. if event.payload[:cached]
  19. name = "Cache #{model}"
  20. no_stats = true
  21. else
  22. statement_taint = TEXT_BLUE
  23. row_count = event.payload[:row_count]
  24. name = "#{category} #{row_count} #{model.pluralize(row_count)}"
  25. end
  26. when 'Update', 'Create', 'Destroy'
  27. statement_taint = TEXT__PINK
  28. name = "#{category} #{model}"
  29. category_taint = TRANSACTION_TAINT
  30. increment_transaction_local(event.payload[:transaction].uuid, category.downcase.to_sym, event.duration)
  31. else raise "unknown sql category: <#{category}>"
  32. end
  33. name = "#{name} #{stats_event(event.duration)}" unless no_stats
  34. name = "#{name} #{remaining.join(' ')}" if remaining.any?
  35. name = colorize(name, category_taint) if category_taint
  36. statement = colorize(event.payload[:sql], statement_taint)
  37. logger.debug("#{name} #{statement}")
  38. end
  39. def start_transaction(_event)
  40. logger.info(colorize('Begin', TRANSACTION_TAINT))
  41. end
  42. def transaction(event)
  43. outcome = colorize(event.payload[:outcome].capitalize, TRANSACTION_TAINT)
  44. transaction = event.payload[:transaction]
  45. summary = transaction_summary(transaction)
  46. stats = stats_event(event.duration - transaction_internal_duration(transaction))
  47. logger.info("#{outcome} #{summary} #{stats}")
  48. end
  49. def instantiation(event); end
  50. def strict_loading_violation(event) = any_hook event
  51. private
  52. def stats_event(duration)= colorize("(#{number_to_ms(duration)})", TEXT_GRAY_400)
  53. def number_to_ms(number) = "#{::ActionController::Base.helpers.number_with_precision(number, precision: 1)}ms"
  54. def transaction_internal_duration(transaction) = transaction_local(transaction.uuid)[:total_duration]
  55. def transaction_summary(transaction)
  56. transaction_local(transaction.uuid)
  57. .except(:total_duration)
  58. .select { |_, value| value.positive? }
  59. .map { |k, v| "#{v} #{k.to_s.pluralize(v)}" }
  60. .join(',')
  61. end
  62. def increment_transaction_local(transaction_id, sql_command, duration)
  63. transaction_local(transaction_id)[sql_command] += 1
  64. transaction_local(transaction_id)[:total_duration] += duration
  65. end
  66. def thread_local = Thread.current[self.class.to_s] ||= {}
  67. def transaction_local(transaction_id)
  68. thread_local[transaction_id] ||= { update: 0, create: 0, destroy: 0, total_duration: 0 }
  69. end
  70. end
  71. end
  72. end