# Copyright (c) 2013 AppNeta, Inc. # All rights reserved. module TraceView ## # Provides utility methods for use while in the business # of instrumenting code module Util class << self def contextual_name(cls) # Attempt to infer a contextual name if not indicated # # For example: # ::ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.to_s.split(/::/).last # => "AbstractMysqlAdapter" # cls.to_s.split(/::/).last rescue cls end ## # method_alias # # Centralized utility method to alias a method on an arbitrary # class or module. # def method_alias(cls, method, name = nil) name ||= contextual_name(cls) if cls.method_defined?(method.to_sym) || cls.private_method_defined?(method.to_sym) # Strip '!' or '?' from method if present safe_method_name = method.to_s.chop if method.to_s =~ /\?$|\!$/ safe_method_name ||= method without_traceview = "#{safe_method_name}_without_traceview" with_traceview = "#{safe_method_name}_with_traceview" # Only alias if we haven't done so already unless cls.method_defined?(without_traceview.to_sym) || cls.private_method_defined?(without_traceview.to_sym) cls.class_eval do alias_method without_traceview, "#{method}" alias_method "#{method}", with_traceview end end else TraceView.logger.warn "[traceview/loading] Couldn't properly instrument #{name}.#{method}. Partial traces may occur." end end ## # class_method_alias # # Centralized utility method to alias a class method on an arbitrary # class or module # def class_method_alias(cls, method, name = nil) name ||= contextual_name(cls) if cls.singleton_methods.include? method.to_sym # Strip '!' or '?' from method if present safe_method_name = method.to_s.chop if method.to_s =~ /\?$|\!$/ safe_method_name ||= method without_traceview = "#{safe_method_name}_without_traceview" with_traceview = "#{safe_method_name}_with_traceview" # Only alias if we haven't done so already unless cls.singleton_methods.include? without_traceview.to_sym cls.singleton_class.send(:alias_method, without_traceview, "#{method}") cls.singleton_class.send(:alias_method, "#{method}", with_traceview) end else TraceView.logger.warn "[traceview/loading] Couldn't properly instrument #{name}. Partial traces may occur." end end ## # send_extend # # Centralized utility method to send an extend call for an # arbitrary class def send_extend(target_cls, cls) target_cls.send(:extend, cls) if defined?(target_cls) end ## # send_include # # Centralized utility method to send a include call for an # arbitrary class def send_include(target_cls, cls) target_cls.send(:include, cls) if defined?(target_cls) end ## # static_asset? # # Given a path, this method determines whether it is a static asset or not (based # solely on filename) # def static_asset?(path) (path =~ Regexp.new(TraceView::Config[:dnt_regexp], TraceView::Config[:dnt_opts])) end ## # prettify # # Even to my surprise, 'prettify' is a real word: # transitive v. To make pretty or prettier, especially in a superficial or insubstantial way. # from The American Heritage Dictionary of the English Language, 4th Edition # # This method makes things 'purty' for reporting. def prettify(x) if (x.to_s =~ /^# 1 } begin platform_info['Force'] = true platform_info['Ruby.Platform.Version'] = RUBY_PLATFORM platform_info['Ruby.Version'] = RUBY_VERSION platform_info['Ruby.TraceView.Version'] = ::TraceView::Version::STRING platform_info['RubyHeroku.TraceView.Version'] = ::TraceViewHeroku::Version::STRING if defined?(::TraceViewHeroku) platform_info['Ruby.TraceMode.Version'] = ::TraceView::Config[:tracing_mode] # Report the framework in use if defined?(::RailsLts::VERSION) platform_info['Ruby.RailsLts.Version'] = "RailsLts-#{::RailsLts::VERSION}" elsif defined?(::Rails.version) platform_info['Ruby.Rails.Version'] = "Rails-#{::Rails.version}" end platform_info['Ruby.Grape.Version'] = "Grape-#{::Grape::VERSION}" if defined?(::Grape::VERSION) platform_info['Ruby.Cramp.Version'] = "Cramp-#{::Cramp::VERSION}" if defined?(::Cramp::VERSION) if defined?(::Padrino::VERSION) platform_info['Ruby.Padrino.Version'] = "Padrino-#{::Padrino::VERSION}" elsif defined?(::Sinatra::VERSION) platform_info['Ruby.Sinatra.Version'] = "Sinatra-#{::Sinatra::VERSION}" end # Report the instrumented libraries platform_info['Ruby.Cassandra.Version'] = "Cassandra-#{::Cassandra.VERSION}" if defined?(::Cassandra.VERSION) platform_info['Ruby.Dalli.Version'] = "Dalli-#{::Dalli::VERSION}" if defined?(::Dalli::VERSION) platform_info['Ruby.Excon.Version'] = "Excon-#{::Excon::VERSION}" if defined?(::Excon::VERSION) platform_info['Ruby.Faraday.Version'] = "Faraday-#{::Faraday::VERSION}" if defined?(::Faraday::VERSION) platform_info['Ruby.HTTPClient.Version'] = "HTTPClient-#{::HTTPClient::VERSION}" if defined?(::HTTPClient::VERSION) platform_info['Ruby.MemCache.Version'] = "MemCache-#{::MemCache::VERSION}" if defined?(::MemCache::VERSION) platform_info['Ruby.Moped.Version'] = "Moped-#{::Moped::VERSION}" if defined?(::Moped::VERSION) platform_info['Ruby.Redis.Version'] = "Redis-#{::Redis::VERSION}" if defined?(::Redis::VERSION) platform_info['Ruby.Resque.Version'] = "Resque-#{::Resque::VERSION}" if defined?(::Resque::VERSION) platform_info['Ruby.RestClient.Version'] = "RestClient-#{::RestClient::VERSION}" if defined?(::RestClient::VERSION) platform_info['Ruby.Typhoeus.Version'] = "Typhoeus-#{::Typhoeus::VERSION}" if defined?(::Typhoeus::VERSION) # Special case since the Mongo 1.x driver doesn't embed the version number in the gem directly if ::Gem.loaded_specs.key?('mongo') platform_info['Ruby.Mongo.Version'] = "Mongo-#{::Gem.loaded_specs['mongo'].version}" end # Report the DB adapter in use platform_info['Ruby.Mysql.Version'] = Mysql::GemVersion::VERSION if defined?(Mysql::GemVersion::VERSION) platform_info['Ruby.PG.Version'] = PG::VERSION if defined?(PG::VERSION) platform_info['Ruby.Mysql2.Version'] = Mysql2::VERSION if defined?(Mysql2::VERSION) platform_info['Ruby.Sequel.Version'] = ::Sequel::VERSION if defined?(::Sequel::VERSION) # Report the server in use (if possible) if defined?(::Unicorn::Const::UNICORN_VERSION) platform_info['Ruby.AppContainer.Version'] = "Unicorn-#{::Unicorn::Const::UNICORN_VERSION}" elsif defined?(::Puma::Const::PUMA_VERSION) platform_info['Ruby.AppContainer.Version'] = "Puma-#{::Puma::Const::PUMA_VERSION} (#{::Puma::Const::CODE_NAME})" elsif defined?(::PhusionPassenger::PACKAGE_NAME) platform_info['Ruby.AppContainer.Version'] = "#{::PhusionPassenger::PACKAGE_NAME}-#{::PhusionPassenger::VERSION_STRING}" elsif defined?(::Thin::VERSION::STRING) platform_info['Ruby.AppContainer.Version'] = "Thin-#{::Thin::VERSION::STRING} (#{::Thin::VERSION::CODENAME})" elsif defined?(::Mongrel::Const::MONGREL_VERSION) platform_info['Ruby.AppContainer.Version'] = "Mongrel-#{::Mongrel::Const::MONGREL_VERSION}" elsif defined?(::Mongrel2::VERSION) platform_info['Ruby.AppContainer.Version'] = "Mongrel2-#{::Mongrel2::VERSION}" elsif defined?(::Trinidad::VERSION) platform_info['Ruby.AppContainer.Version'] = "Trinidad-#{::Trinidad::VERSION}" elsif defined?(::WEBrick::VERSION) platform_info['Ruby.AppContainer.Version'] = "WEBrick-#{::WEBrick::VERSION}" else platform_info['Ruby.AppContainer.Version'] = File.basename($PROGRAM_NAME) end rescue StandardError, ScriptError => e # Also rescue ScriptError (aka SyntaxError) in case one of the expected # version defines don't exist platform_info['Error'] = "Error in build_report: #{e.message}" TraceView.logger.warn "[traceview/warn] Error in build_init_report: #{e.message}" TraceView.logger.debug e.backtrace end platform_info end end end end