class GCareRubyMethodProfiler

pow.gs/mirror/discourse/blob/35d6fff69e86704081270333fbcb5248202a246a/lib/method_profiler.rb

Public Class Methods

clear() click to toggle source
# File lib/gcarerubymethodprofiler.rb, line 257
  def self.clear
  Thread.current[:_method_profiler] = nil
end
decorateForOneArgument(klass, methods, name) click to toggle source
# File lib/gcarerubymethodprofiler.rb, line 184
    def self.decorateForOneArgument(klass, methods, name)
    patches = methods.map do |method_name|
      <<~RUBY
      unless defined?(#{method_name}__mp_unpatched)
        alias_method :#{method_name}__mp_unpatched, :#{method_name}
        def #{method_name}(*args, &blk)
          unless prof = Thread.current[:_method_profiler]
                        puts 'test1'
            return #{method_name}__mp_unpatched(*args, &blk)
          end
          begin
            start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
                        puts 'test2'
                        a = __method__.to_s
                        argsdata =  args.to_s
                        puts a
                        puts argsdata
            #{method_name}__mp_unpatched(*args, &blk)
          ensure
            data = (prof[:#{name}] ||= {duration: 0.0, calls: 0})
            data[:duration] += Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
            data[:calls] += 1
          end
        end
      end
      RUBY
    end.join("\n")

    klass.class_eval patches
  end
decorateHttp(methods, name, iKey, gcareurl, no_recurse: false) click to toggle source
# File lib/gcarerubymethodprofiler.rb, line 10
  def self.decorateHttp(methods, name, iKey, gcareurl, no_recurse: false)
    patches = methods.map do |method_name|
        recurse_protection = ""
          if no_recurse
        recurse_protection = <<~RUBY
          return #{method_name}__mp_unpatched(*args, &blk) if @mp_recurse_protect_#{method_name}
          @mp_recurse_protect_#{method_name} = true
        RUBY
      end

      <<~RUBY
      unless defined?(#{method_name}__mp_unpatched)
        alias_method :#{method_name}__mp_unpatched, :#{method_name}
        def #{method_name}(*args, &blk)
          unless prof = Thread.current[:_method_profiler]
                  requestobject = nil
                  donottrack = false
                  gcare_telemetry_uri = URI("#{gcareurl}")
                  case __method__.to_s
                        when 'request'
                                if args[0].is_a? Net::HTTPRequest
                                  requestobject = args[0]
                                  if requestobject.path == gcare_telemetry_uri.path
                                        donottrack = true
                                  else
                                    donottrack = false
                                  end
                                end
                        when 'get'
                          path =  args[0]
                        when 'get_response'
                          uri_or_host = args[0]
                          path  = args[1]
                          port  = args[2]
                        when 'post'
                          path =  args[0]
                        when 'post_form'
                          uri_or_host = args[0]
                        when 'get2'
                          path =  args[0]
                        when 'head2'
                          path =  args[0]
                        when 'patch'
                          path =  args[0]
                        when 'post2'
                          path =  args[0]
                  end
                  gcareid = requestobject['GCareID']
                  if gcareid == nil
                    gcareid = SecureRandom.uuid
                        requestobject['GCareID'] = gcareid
                  end

          startTime = Time.now
                  #{recurse_protection}
                  returnvalue = #{method_name}__mp_unpatched(*args, &blk)
                  if donottrack == false
                        donottrack = true
            endTime = Time.now
                        timestamp = startTime.utc.iso8601(0)
                        scheme  = self.use_ssl? == true ? 'https' : 'http'
                        local_host = Socket.gethostname
                        local_ip = Resolv.getaddress(local_host)
                        remote_host = self.address
                        remote_ip = Resolv.getaddress(remote_host)
                        iKeyValue = "#{iKey}"
                        duration = Time.at(endTime - startTime).gmtime.strftime("00.%H:%M:%S.%7N")
                        teledata = {
                                'ver' => 2,
                                'name' => 'Gavs.ApplicationMonitoring.' + iKeyValue + '.RemoteDependency',
                                'time' => timestamp,
                                'sampleRate' => '100',
                                'iKey' => iKeyValue,
                                'tags' => {
                                        'ai' => {
                                                'internal.sdkVersion' => 'rb:1.0.0',
                                                'operation.id' => nil,
                                                'operation.name' => requestobject.method,
                                                'gcare.id' => gcareid,
                                                'device.roleInstance' => local_host
                                        }
                                },
                                'data' => {
                                'baseType' => 'RemoteDependencyData',
                                'baseData' => {
                                        'ver' => 2,
                                        'platform_version' => "#{RUBY_VERSION}",
                                        'platform_description' => 'ruby',
                                        'id' => nil,
                                        'GCareID' => gcareid,
                                        'referer' => requestobject['referer'],
                                        'scheme' =>  scheme,
                                        'remote_ip' => local_ip,
                                        'remote_host' => local_host,
                                        'forwarding_ip' => nil,
                                        'client_ip' => local_ip,
                                        'server_host' => remote_host,
                                        'server_ip' => remote_ip,
                                        'server_hostname' => remote_host,
                                        'useragent' => requestobject['user-agent'],
                                        'session_id' =>  nil,
                                        'timestamp' => timestamp,
                                        'name' => requestobject.method,
                                        'duration' => duration,
                                        'responseCode' => returnvalue.code,
                                        'success' => returnvalue.message,
                                        'url' => returnvalue.uri == nil ? scheme + ":" + "//" + self.address + ":" + self.port.to_s + requestobject.path : returnvalue.uri,
                                        'server_port' => self.port,
                                        'properties' => {
                                                'httpMethod' => requestobject.method
                                        }
                                }
                        },
                        'machine' => {
                                'from_ip' => 'USER',
                                'from_name' => 'USER',
                                'to_ip' => remote_ip,
                                'to_name' => requestobject.path
                        }
                        }
                        puts teledata.to_json
            
                        headers = {
                                'Accept' => 'application/json',
                                'Content-Type' => 'application/json; charset=utf-8'
                        }
                        request = Net::HTTP::Post.new(gcare_telemetry_uri.path, headers)
                        request.body = teledata.to_json
                        http = Net::HTTP.new gcare_telemetry_uri.hostname, gcare_telemetry_uri.port
                        if gcare_telemetry_uri.scheme.downcase == 'https'
                                http.use_ssl = true
                                http.verify_mode = OpenSSL::SSL::VERIFY_NONE
                        end
                        p "Sending RemoteDependency telemery data to GCare (http)"
                        response = http.request(request)

                        if !response.kind_of? Net::HTTPSuccess
                        end
                  end
                  if returnvalue.is_a?(Net::HTTPResponse)
                          
                  end
                  if returnvalue.is_a?(String)
                          
                  end
                  return returnvalue
        end
                #{recurse_protection}
        begin
          start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
                  puts 'test2'
                  puts args
          #{method_name}__mp_unpatched(*args, &blk)
        ensure
          data = (prof[:#{name}] ||= {duration: 0.0, calls: 0})
          data[:duration] += Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
          data[:calls] += 1
                  #{"@mp_recurse_protect_#{method_name} = false" if no_recurse}
        end
      end
    end
    RUBY
    end.join("\n")
         Net::HTTP.class_eval patches
  end
decorateSql(klass, methods, name) click to toggle source
# File lib/gcarerubymethodprofiler.rb, line 215
    def self.decorateSql(klass, methods, name)
    patches = methods.map do |method_name|
      <<~RUBY
      unless defined?(#{method_name}__mp_unpatched)
        alias_method :#{method_name}__mp_unpatched, :#{method_name}
        def #{method_name}(*args, &blk)
          unless prof = Thread.current[:_method_profiler]
                        puts 'test1'
            return #{method_name}__mp_unpatched(*args, &blk)
          end
          begin
            start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
                        puts 'test2'
                        puts args
            #{method_name}__mp_unpatched(*args, &blk)
          ensure
            data = (prof[:#{name}] ||= {duration: 0.0, calls: 0})
            data[:duration] += Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
            data[:calls] += 1
          end
        end
      end
      RUBY
    end.join("\n")

    klass.class_eval patches
  end
start() click to toggle source
# File lib/gcarerubymethodprofiler.rb, line 250
def self.start
  Thread.current[:_method_profiler] = transfer || {
    __start: Process.clock_gettime(Process::CLOCK_MONOTONIC)
  }
  puts "GCare Profiling Started"
end
stop() click to toggle source
# File lib/gcarerubymethodprofiler.rb, line 261
def self.stop
  finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  if data = Thread.current[:_method_profiler]
    Thread.current[:_method_profiler] = nil
    start = data.delete(:__start)
    data[:total_duration] = finish - start
    data
  end
  puts "GCare Profiling Stopped"
end
transfer() click to toggle source
# File lib/gcarerubymethodprofiler.rb, line 243
def self.transfer
  result = Thread.current[:_method_profiler]
  Thread.current[:_method_profiler] = nil
  result
end

Public Instance Methods

format_request_duration(duration_seconds) click to toggle source
# File lib/gcarerubymethodprofiler.rb, line 176
def format_request_duration(duration_seconds)
      if duration_seconds >= 86400
              # just return 1 day when it takes more than 1 day which should not happen for requests.
              return "%02d.%02d:%02d:%02d.%07d" % [1, 0, 0, 0, 0]
      end
      Time.at(duration_seconds).gmtime.strftime("00.%H:%M:%S.%7N")
end
send(data_to_send) click to toggle source
# File lib/gcarerubymethodprofiler.rb, line 297
def send(data_to_send)
      uri = URI(@service_endpoint_uri)
      headers = {
              'Accept' => 'application/json',
              'Content-Type' => 'application/json; charset=utf-8'
      }
      #,
      #  'Content-Encoding' => 'gzip' # currently no encryption enabled
      request = Net::HTTP::Post.new(uri.path, headers)

      # Use JSON.generate instead of to_json, otherwise it will
      # default to ActiveSupport::JSON.encode for Rails app
      json = JSON.generate(data_to_send)
      puts "sending data to CCare Server"
      puts json
      # compressed_data = compress(json)
      request.body = json

      http = Net::HTTP.new uri.hostname, uri.port #, 'localhost', 8888 # uncomment if proxy is used
      if uri.scheme.downcase == 'https'
              http.use_ssl = true
              http.verify_mode = OpenSSL::SSL::VERIFY_NONE
      end

      response = http.request(request)
      http.finish if http.started?

      if !response.kind_of? Net::HTTPSuccess
              @logger.warn('application_insights') { "Failed to send data: #{response.message}" }
      end

end
telemetrydata(telemetryversion, name, time, sampleRate, iKey, sdkVersion, operation_id, baseType, baseData_ver, baseData_id, gCareID, remote_ip, remote_host, forwarding_ip, client_ip, server_host, server_ip, server_hostname, useragent, session_id, timestamp, duration, responseCode, success, url, httpMethod, version, machine_from_ip, machine_from_name, machine_to_ip, machine_to_name, operation_name, roleInstance, server_port) click to toggle source
# File lib/gcarerubymethodprofiler.rb, line 272
def telemetrydata(telemetryversion, name, time, sampleRate, iKey, sdkVersion,
              operation_id, baseType, baseData_ver, baseData_id, gCareID,
              remote_ip, remote_host, forwarding_ip, client_ip, server_host, server_ip, server_hostname,
              useragent, session_id, timestamp, duration, responseCode, success,
              url, httpMethod, version, machine_from_ip, machine_from_name, machine_to_ip,
              machine_to_name, operation_name, roleInstance, server_port)

              teledata = {
                      'ver' => telemetryversion,
                      'name' => name,
                      'time' => time,
                      'sampleRate' => sampleRate,
                      'iKey' => iKey,
                      'tags' => {
                              'ai' => {
                                      'internal.sdkVersion' => sdkVersion,
                                      'operation.id' => operation_id,
                                      'operation.name' => operation_name,
                                      'gcare.id' => gCareID,
                                      'device.roleInstance' => roleInstance
                              }
                      }
              }
end