File: event_prof.rb

package info (click to toggle)
ruby-test-prof 0.12.2%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 508 kB
  • sloc: ruby: 4,075; makefile: 4
file content (107 lines) | stat: -rw-r--r-- 3,048 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# frozen_string_literal: true

require "test_prof/rspec_stamp"
require "test_prof/event_prof/profiler"
require "test_prof/event_prof/instrumentations/active_support"
require "test_prof/event_prof/monitor"
require "test_prof/utils/sized_ordered_set"

module TestProf
  # EventProf profiles your tests and suites against custom events,
  # such as ActiveSupport::Notifacations.
  #
  # It works very similar to `rspec --profile` but can track arbitrary events.
  #
  # Example:
  #
  #   # Collect SQL queries stats for every suite and example
  #   EVENT_PROF='sql.active_record' rspec ...
  #
  # By default it collects information only about top-level groups (aka suites),
  # but you can also profile individual examples. Just set the configuration option:
  #
  #  TestProf::EventProf.configure do |config|
  #    config.per_example = true
  #  end
  #
  # Or provide the EVENT_PROF_EXAMPLES=1 env variable.
  module EventProf
    # EventProf configuration
    class Configuration
      # Map of supported instrumenters
      INSTRUMENTERS = {
        active_support: "ActiveSupport"
      }.freeze

      attr_accessor :instrumenter, :top_count, :per_example,
        :rank_by, :event

      def initialize
        @event = ENV["EVENT_PROF"]
        @instrumenter = :active_support
        @top_count = (ENV["EVENT_PROF_TOP"] || 5).to_i
        @per_example = ENV["EVENT_PROF_EXAMPLES"] == "1"
        @rank_by = (ENV["EVENT_PROF_RANK"] || :time).to_sym
        @stamp = ENV["EVENT_PROF_STAMP"]

        RSpecStamp.config.tags = @stamp if stamp?
      end

      def stamp?
        !@stamp.nil?
      end

      def per_example?
        per_example == true
      end

      def resolve_instrumenter
        return instrumenter if instrumenter.is_a?(Module)

        raise ArgumentError, "Unknown instrumenter: #{instrumenter}" unless
          INSTRUMENTERS.key?(instrumenter)

        Instrumentations.const_get(INSTRUMENTERS[instrumenter])
      end
    end

    class << self
      def config
        @config ||= Configuration.new
      end

      def configure
        yield config
      end

      # Returns new configured instance of profilers group
      def build(event = config.event)
        ProfilersGroup.new(
          event: event,
          instrumenter: instrumenter,
          rank_by: config.rank_by,
          top_count: config.top_count,
          per_example: config.per_example?
        )
      end

      def instrumenter
        @instrumenter ||= config.resolve_instrumenter
      end

      # Instrument specified module methods.
      # Wraps them with `instrumenter.instrument(event) { ... }`.
      #
      # Use it to profile arbitrary methods:
      #
      #   TestProf::EventProf.monitor(MyModule, "my_module.call", :call)
      def monitor(mod, event, *mids, **kwargs)
        Monitor.call(mod, event, *mids, **kwargs)
      end
    end
  end
end

require "test_prof/event_prof/custom_events"
require "test_prof/event_prof/rspec" if TestProf.rspec?
require "test_prof/event_prof/minitest" if TestProf.minitest?