Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
skylight / lib / skylight / helpers.rb
Size: Mime:
module Skylight
  # Instrumenting a specific method will cause an event to be created every time that method is called.
  # The event will be inserted at the appropriate place in the Skylight trace.
  #
  # To instrument a method, the first thing to do is include {Skylight::Helpers Skylight::Helpers}
  # into the class that you will be instrumenting. Then, annotate each method that
  # you wish to instrument with {Skylight::Helpers::ClassMethods#instrument_method instrument_method}.
  module Helpers

    # @see Skylight::Helpers
    module ClassMethods
      # @api private
      def method_added(name)
        super

        if opts = @__sk_instrument_next_method
          @__sk_instrument_next_method = nil
          title = "#{to_s}##{name}"
          __sk_instrument_method_on(self, name, title, opts)
        end
      end

      # @api private
      def singleton_method_added(name)
        super

        if opts = @__sk_instrument_next_method
          @__sk_instrument_next_method = nil
          title = "#{to_s}.#{name}"
          __sk_instrument_method_on(__sk_singleton_class, name, title, opts)
        end
      end

      # @overload instrument_method
      #   Instruments the following method
      #
      #   @example
      #     class MyClass
      #       include Skylight::Helpers
      #
      #       instrument_method
      #       def my_method
      #         do_expensive_stuff
      #       end
      #
      #     end
      #
      # @overload instrument_method([name], opts={})
      #   @param [Symbol|String] [name]
      #   @param [Hash] opts
      #   @option opts [String] :category ('app.method')
      #   @option opts [String] :title (ClassName#method_name)
      #   @option opts [String] :description
      #
      #   You may also declare the methods to instrument at any time by passing the name
      #   of the method as the first argument to `instrument_method`.
      #
      #   @example With name
      #     class MyClass
      #       include Skylight::Helpers
      #
      #       def my_method
      #         do_expensive_stuff
      #       end
      #
      #       instrument_method :my_method
      #
      #     end
      #
      #   By default, the event will be titled using the name of the class and the
      #   method. For example, in our previous example, the event name will be:
      #   +MyClass#my_method+. You can customize this by passing using the *:title* option.
      #
      #   @example Without name
      #     class MyClass
      #       include Skylight::Helpers
      #
      #       instrument_method title: 'Expensive work'
      #       def my_method
      #         do_expensive_stuff
      #       end
      #     end
      def instrument_method(*args)
        opts = args.pop if Hash === args.last

        if name = args.pop
          title = "#{to_s}##{name}"
          __sk_instrument_method_on(self, name, title, opts || {})
        else
          @__sk_instrument_next_method = opts || {}
        end
      end

    private

      def __sk_instrument_method_on(klass, name, title, opts)
        category = (opts[:category] || "app.method").to_s
        title    = (opts[:title] || title).to_s
        desc     = opts[:description].to_s if opts[:description]

        klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
          alias_method :"before_instrument_#{name}", :"#{name}"

          def #{name}(*args, &blk)
            span = Skylight.instrument(
              category:  :"#{category}",
              title:       #{title.inspect},
              description: #{desc.inspect})

            begin
              before_instrument_#{name}(*args, &blk)
            ensure
              Skylight.done(span) if span
            end
          end
        RUBY
      end

      if respond_to?(:singleton_class)
        alias :__sk_singleton_class :singleton_class
      else
        def __sk_singleton_class
          class << self; self; end
        end
      end
    end

    # @api private
    def self.included(base)
      base.class_eval do
        @__sk_instrument_next_method = nil
        extend ClassMethods
      end
    end

  end
end