diff --git a/.gitignore b/.gitignore index fea0565..463c1b1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,11 @@ +*.swp /Manifest /newrelic.yml log/ doc/ docs html/ - -*~ +Gemfile.lock .DS_Store newrelic_ia.log @@ -17,5 +17,3 @@ newrelic_ia.log # other scm .svn - - diff --git a/.loadpath b/.loadpath deleted file mode 100644 index 948efaa..0000000 --- a/.loadpath +++ /dev/null @@ -1,9 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<loadpath> - <pathentry path="" type="src"/> - <pathentry path="org.rubypeople.rdt.launching.RUBY_CONTAINER" type="con"/> - <pathentry path="/Library/Ruby/Gems/1.8/gems/newrelic_rpm-2.9.0/lib" type="lib"/> - <pathentry path="GEM_LIB/rspec-1.2.0/lib" type="var"/> - <pathentry path="GEM_LIB/newrelic_rpm-2.9.0/lib" type="var"/> - <pathentry path="GEM_LIB/newrelic_rpm-2.9.2/lib" type="var"/> -</loadpath> diff --git a/.project b/.project deleted file mode 100644 index 4f5ad18..0000000 --- a/.project +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<projectDescription> - <name>Monitor</name> - <comment></comment> - <projects> - </projects> - <buildSpec> - <buildCommand> - <name>org.rubypeople.rdt.core.rubybuilder</name> - <arguments> - </arguments> - </buildCommand> - </buildSpec> - <natures> - <nature>org.rubypeople.rdt.core.rubynature</nature> - </natures> -</projectDescription> diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..d65e2a6 --- /dev/null +++ b/Gemfile @@ -0,0 +1,3 @@ +source 'http://rubygems.org' + +gemspec diff --git a/PostInstall.txt b/PostInstall.txt deleted file mode 100644 index a267c62..0000000 --- a/PostInstall.txt +++ /dev/null @@ -1,4 +0,0 @@ - -For more information refer to http://support.newrelic.com or -say 'newrelic' at #newrelic on freenode IRC. - diff --git a/README.rdoc b/README.rdoc index d6b78b6..31e5a32 100644 --- a/README.rdoc +++ b/README.rdoc @@ -9,7 +9,7 @@ to your RPM console which can be viewed with custom dashboards. == Synopsis - newrelic_ia [ options ] aspect, aspect.. + newrelic_ia [ options ] aspect, aspect.. aspect: one or more of 'iostat' or 'disk' or 'memcached' (more to come) @@ -17,7 +17,7 @@ to your RPM console which can be viewed with custom dashboards. -v, --verbose debug output -q, --quiet quiet output -e, --environment=ENV use ENV section in newrelic.yml - --install create a default newrelic.yml + --install KEY create a default newrelic.yml -h, --help Show this help message. == Requirements @@ -29,15 +29,15 @@ to your RPM console which can be viewed with custom dashboards. sudo gem install newrelic_ia -Once installed, run from the home directory of your Rails +Once installed, run from the home directory of your Rails application, or create a separate working directory and run - newrelic_ia --install + newrelic_ia --install KEY to create a template newrelic.yml file you can use. Edit this file and substitute your license key and app_name value. -specify memcached nodes in memcached-nodes.txt. +specify memcached nodes in memcached-nodes.txt. == Credits @@ -58,24 +58,24 @@ Memcached stats are reported for each node and also sample reports aggregated st uptime Number of seconds this server has been running curr_items Current number of items stored by the server - total_items Total number of items stored by this server + total_items Total number of items stored by this server ever since it started bytes Current number of bytes used by this server to store items curr_connections Number of open connections - total_connections Total number of connections opened since + total_connections Total number of connections opened since the server started running connection_structures Number of connection structures allocated by the server cmd_get Cumulative number of retrieval requests cmd_set Cumulative number of storage requests get_hits Number of keys that have been requested and found present get_misses Number of items that have been requested and not found - evictions Number of valid items removed from cache to free + evictions Number of valid items removed from cache to free memory for new items bytes_read Total number of bytes read by this server from network bytes_written Total number of bytes sent by this server to network limit_maxbytes Number of bytes this server is allowed to use for storage threads Number of worker threads requested - + Derived Stats (computed stats): free_maxbytes Number of free bytes this server has available for storage @@ -84,7 +84,7 @@ Stats Derivatives (time derivatives of stats): hit_ratio Percent of keys that have been requested and found present miss_ratio Percent of keys that have been requested and found missing - rpm Requests per minutes + rpm Requests per minutes gpm Gets per minutes hpm Hits per minutes mpm Misses per minutes @@ -99,34 +99,34 @@ Liquid template for NewRelic custom dashboard: <div> <div style="float: left; width: 50%;"> - {% line_chart value:average_value title:'Cache Miss Ratio' metric:'System/Memcached/Miss Ratio' simple_tooltip:true label:segment_3 value_suffix:'%' %} + {% line_chart value:average_value title:'Cache Miss Ratio' metric:'System/Memcached/all/miss_ratio' simple_tooltip:true label:segment_3 value_suffix:'%' %} </div> <div style="float: left; width: 50%;"> - {% line_chart value:average_value title:'Cache Memory' regexp:'System/Memcached/(Bytes|Free Bytes|Limit Maxbytes)' simple_tooltip:true label:segment_3 %} + {% line_chart value:average_value title:'Cache Memory' regexp:'System/Memcached/all/(bytes|free_bytes|limit_maxbytes)' simple_tooltip:true label:segment_3 %} </div> <br style="clear: both" /> </div> - + <div style="padding-top: 20px"> </div> - + <div> <div style="float: left; width: 50%;"> - {% line_chart value:average_value title:'Cache Gets & Sets' regexp:'System/Memcached/(Gpm|Spm)' simple_tooltip:true label:segment_3 %} + {% line_chart value:average_value title:'Cache Gets & Sets' regexp:'System/Memcached/all/(gpm|spm)' simple_tooltip:true label:segment_3 %} </div> <div style="float: left; width: 50%;"> - {% line_chart value:average_value title:'Cache Misses, Flushes, & Evictions' regexp:'System/Memcached/(Mpm|Epm|Fpm)' simple_tooltip:true label:segment_3 %} + {% line_chart value:average_value title:'Cache Misses, Flushes, & Evictions' regexp:'System/Memcached/all/(mpm|epm|fpm)' simple_tooltip:true label:segment_3 %} </div> <br style="clear: both" /> </div> - + <div style="padding-top: 20px"> </div> - + <div> <div style="float: left; width: 50%;"> - {% line_chart value:average_value title:'Active Connections' metric:'System/Memcached/Curr Connections' simple_tooltip:true hide_legend:true %} + {% line_chart value:average_value title:'Active Connections' metric:'System/Memcached/all/curr_connections' simple_tooltip:true hide_legend:true %} </div> <div style="float: left; width: 50%;"> - {% line_chart value:average_value title:'Cache Objects' metric:'System/Memcached/Curr Items' simple_tooltip:true hide_legend:true %} + {% line_chart value:average_value title:'Cache Objects' metric:'System/Memcached/all/curr_items' simple_tooltip:true hide_legend:true %} </div> <br style="clear: both" /> </div> diff --git a/Rakefile b/Rakefile index 45bf431..d95c3f1 100644 --- a/Rakefile +++ b/Rakefile @@ -1,87 +1,10 @@ -require 'rubygems' -require 'rake' -require File.dirname(__FILE__) + '/lib/new_relic/ia/version.rb' -require 'rake/testtask' - -GEM_NAME = "newrelic_ia" -GEM_VERSION = NewRelic::IA::VERSION -AUTHOR = "Bill Kayser" -EMAIL = "bkayser@newrelic.com" -HOMEPAGE = "http://www.newrelic.com" -SUMMARY = "New Relic Gem for gathering system metrics" -DESCRIPTION = <<EOF -The New Relic Infrastructure Agent (IA) collects system metrics and transmits -them to the RPM server where they can be viewed with custom dashboards. -EOF - -# See http://www.rubygems.org/read/chapter/20 -begin - require 'jeweler' - Jeweler::Tasks.new do |gem| - gem.name = GEM_NAME - gem.summary = SUMMARY - gem.description = DESCRIPTION - gem.email = EMAIL - gem.homepage = HOMEPAGE - gem.author = AUTHOR - gem.version = GEM_VERSION - gem.files = FileList['Rakefile', 'README*', 'CHANGELOG', 'spec/**/*','tasks/*', 'lib/**/*'].to_a - gem.test_files = FileList['spec/**/*.rb'] - gem.rdoc_options << - "--line-numbers" << - "--inline-source" << - "--title" << SUMMARY << - "-m" << "README.rdoc" - - gem.files.reject! { |fn| fn =~ /PostInstall.txt|pkg\/|rdoc\// } - gem.extra_rdoc_files = %w[CHANGELOG LICENSE README.rdoc bin/newrelic_ia] - gem.add_dependency 'newrelic_rpm', '>=2.10.6' - gem.post_install_message = File.read 'PostInstall.txt' - end - Jeweler::GemcutterTasks.new -rescue LoadError - puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler" +#!/usr/bin/env rake +require "bundler/gem_tasks" +require "rspec" +require "rspec/core/rake_task" +RSpec::Core::RakeTask.new("spec") do |spec| + spec.pattern = "spec/*_spec.rb" end -load "#{File.dirname(__FILE__)}/tasks/rspec.rake" - -task :manifest do - puts "Manifest task is no longer used since switching to jeweler." -end - -begin - require 'rcov/rcovtask' - Rcov::RcovTask.new do |test| - test.libs << 'test' - test.pattern = 'spec/**/*.rb' - test.verbose = true - end -rescue LoadError - task :rcov do - abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov" - end -end - -require 'spec/rake/spectask' -Spec::Rake::SpecTask.new(:spec) do |spec| - spec.libs << 'lib' << 'spec' - spec.spec_files = FileList['spec/**/*_spec.rb'] -end - -task :spec => :check_dependencies task :default => :spec - -require 'rake/rdoctask' -Rake::RDocTask.new do |rdoc| - rdoc.title = SUMMARY - rdoc.main = "README.rdoc" - rdoc.rdoc_files << 'LICENSE' << 'README*' << 'CHANGELOG' << 'lib/**/*.rb' << 'bin/**/*' - rdoc.inline_source = true -end - -begin - require 'sdoc_helpers' -rescue LoadError - puts "sdoc support not enabled. Please gem install sdoc-helpers." -end diff --git a/config/newrelic.yml b/config/newrelic.yml new file mode 100644 index 0000000..3406829 --- /dev/null +++ b/config/newrelic.yml @@ -0,0 +1,35 @@ +# +# This is a configuration file for the RPM Agent, tailored +# for use as a system monitor. +# +# Generated on Oct 12, 2011, from version 0.2.2 +# +common: &default_settings + log_level: info + license_key: 'test' + + app_name: System Monitor + ssl: false + + # Set the array of nodes for the memcache monitor + memcached_nodes: + - localhost:11211 +# - localhost:11212 +# - localhost:11213 + + # These settings ensure we don't end up actually monitoring + # the IA agent itself--we aren't really interested in that. + # Don't change these. + disable_samplers: true + capture_params: false + transaction_tracer: + enabled: false + +# NOTE if your application has other named environments, you should +# provide newrelic conifguration settings for these enviromnents here. +production: + <<: *default_settings + +development: + <<: *default_settings + diff --git a/lib/new_relic/ia/cli.rb b/lib/new_relic/ia/cli.rb index a1b3b4b..1d21093 100644 --- a/lib/new_relic/ia/cli.rb +++ b/lib/new_relic/ia/cli.rb @@ -5,34 +5,35 @@ module NewRelic::IA class InitError < StandardError; end - + class CLI - + LOGFILE = "newrelic_ia.log" - + class << self - + def log @log ||= Logger.new LOGFILE end - + def level= l log.level = l end - + # Run the command line args. Return nil if running # or an exit status if not. def execute(stdout, arguments=[]) + log.level = Logger::INFO @aspects = [] parser = OptionParser.new do |opts| opts.banner = <<-BANNER.gsub(/^ */,'') New Relic Infrastructure Agent (IA) version #{NewRelic::IA::VERSION} - Monitor different aspects of your environment with New Relic RPM. + Monitor different aspects of your environment with New Relic RPM. - Usage: #{File.basename($0)} [ options ] aspect, aspect.. + Usage: #{File.basename($0)} [ options ] aspect, aspect.. aspect: one or more of 'memcached', 'iostat' or 'disk' (more to come) - BANNER + BANNER opts.separator "" opts.on("-a", "--all", "use all available aspects") { @aspects = %w[iostat disk memcached] } @@ -42,9 +43,9 @@ def execute(stdout, arguments=[]) "quiet output") { NewRelic::IA::CLI.log.level = Logger::ERROR } opts.on("-e", "--environment=ENV", "use ENV section in newrelic.yml") { |e| @env = e } - opts.on("--install", - "create a default newrelic.yml") { |e| return self.install(stdout) } - + opts.on("--install license_key", + "create a default newrelic.yml") { |key| return self.install(key, stdout) } + opts.on("-h", "--help", "Show this help message.") { stdout.puts "#{opts}\n"; return 0 } begin @@ -59,7 +60,7 @@ def execute(stdout, arguments=[]) end end @aspects.delete_if do |aspect| - unless self.instance_methods(false).include? aspect + unless ASPECTS.include? aspect.to_sym stdout.puts "Unknown aspect: #{aspect}" true end @@ -69,12 +70,10 @@ def execute(stdout, arguments=[]) stdout.puts parser return 1 end - require_newrelic_rpm + require_newrelic_rpm NewRelic::Agent.manual_start :env => @env, :monitor_mode => true, :log => self.log # connected? due in a future version - if not (NewRelic::Agent.instance.connected? rescue true) - raise InitError, "Unable to connect to RPM server. Agent not started." - end + raise InitError, "Unable to connect to RPM server. Agent not started." unless NewRelic::Agent.instance.connected? cli = new @aspects.each do | aspect | cli.send aspect @@ -84,8 +83,10 @@ def execute(stdout, arguments=[]) stdout.puts e.message return 1 end - + end + + ASPECTS = [:iostat, :disk, :memcached] # Aspect definitions def iostat # :nodoc: self.class.log.info "Starting iostat monitor..." @@ -93,13 +94,13 @@ def iostat # :nodoc: reader = NewRelic::IA::IostatReader.new Thread.new { reader.run } end - + def disk self.class.log.info "Starting disk sampler..." require 'new_relic/ia/disk_sampler' - NewRelic::Agent.instance.stats_engine.add_harvest_sampler NewRelic::IA::DiskSampler.new + NewRelic::Agent.instance.stats_engine.add_harvest_sampler NewRelic::IA::DiskSampler.new end - + def memcached require 'new_relic/ia/memcached_sampler' s = NewRelic::IA::MemcachedSampler.new @@ -108,11 +109,11 @@ def memcached end private - + def log self.class.log end - + def self.require_newrelic_rpm begin require 'newrelic_rpm' @@ -127,31 +128,22 @@ def self.require_newrelic_rpm end end end - - def self.install stdout + + def self.install license_key, stdout require_newrelic_rpm - if NewRelic::VersionNumber.new(NewRelic::VERSION::STRING) < '2.12' - if File.exists? "newrelic.yml" - stdout.puts "A newrelic.yml file already exists. Please remove it before installing another." - return 1 # error - else - FileUtils.copy File.join(File.dirname(__FILE__), "newrelic.yml"), "." - stdout.puts "A newrelic.yml template was copied to #{File.expand_path('.')}." - stdout.puts "Please add a license key to the file before starting." - return 0 # normal - end - else - begin - require 'new_relic/command' - cmd = NewRelic::Command::Install.new \ - :src_file => File.join(File.dirname(__FILE__), "newrelic.yml"), - :generated_for_user => "Generated on #{Time.now.strftime('%b %d, %Y')}, from version #{NewRelic::IA::VERSION}" - cmd.run - 0 # normal - rescue NewRelic::Command::CommandFailure => e - stdout.puts e.message - 1 # error - end + begin + require 'new_relic/command' + FileUtils.mkdir(File.join(File.dirname(__FILE__), "config")) + cmd = NewRelic::Command::Install.new \ + :src_file => File.join(File.dirname(__FILE__), "config/newrelic.yml"), + :generated_for_user => "Generated on #{Time.now.strftime('%b %d, %Y')}, from version #{NewRelic::IA::VERSION}", + :app_name => 'System Monitor', + :license_key => license_key + cmd.run + 0 # normal + rescue NewRelic::Command::CommandFailure => e + stdout.puts e.message + 1 # error end end end diff --git a/lib/new_relic/ia/memcached_sampler.rb b/lib/new_relic/ia/memcached_sampler.rb index fe73d84..0cf1817 100644 --- a/lib/new_relic/ia/memcached_sampler.rb +++ b/lib/new_relic/ia/memcached_sampler.rb @@ -8,7 +8,7 @@ class NewRelic::IA::MemcachedSampler < NewRelic::Agent::Sampler include NewRelic::IA::MetricNames - case RUBY_PLATFORM + case RUBY_PLATFORM when /darwin/ # Do some special stuff... when /linux/ @@ -23,11 +23,11 @@ def initialize :cmd_flush, :cmd_get, :cmd_set, :get_hits, :get_misses, :evictions, :bytes_read, :bytes_written, :limit_maxbytes, :threads] @derived_values = [ :free_bytes] @derivatives = [:hit_ratio, :miss_ratio, :rpm, :gpm, :hpm, :mpm, :spm, :fpm, :epm] - + @last_stats = Hash.new @memcached_nodes = parse_config end - + def parse_config # file with a list of mecached nodes. each line have hostname:port memcached_nodes = NewRelic::Control.instance['memcached_nodes'] @@ -40,17 +40,17 @@ def parse_config def memcached_nodes @memcached_nodes end - + # Sanity check, make sure the servers are there. def check down_servers = [] memcached_nodes.each do | hostname_port | - stats_text = issue_stats hostname_port + stats_text = issue_stats hostname_port down_servers << hostname_port unless stats_text end raise NewRelic::Agent::Sampler::Unsupported, "Servers not available: #{down_servers.join(", ")}" unless down_servers.empty? end - + # This gets called once a minute in the agent worker thread. It # pings each host in the array 'memcached_nodes' def poll @@ -61,22 +61,22 @@ def poll @last_stats[hostname_port] = parse_and_report_stats hostname_port, stats_text else @last_stats[hostname_port] = nil #{} - end + end end aggregate_stats - debug "done with aggs" + debug "done with aggs" end end - - def logger + + def logger NewRelic::IA::CLI.log end - + def aggregate_stats begin - - aggs_stats = Hash.new + + aggs_stats = Hash.new @int_values.each {|metric| aggs_stats[metric] = 0} @derived_values.each {|metric| aggs_stats[metric] = 0} @@ -95,9 +95,9 @@ def aggregate_stats @derivatives[0,2].each do |metric| aggs_stats[metric] += v[metric] end - aggs_count += 1 + aggs_count += 1 - @derivatives[2,@derivatives.length - 2].each do |metric| + @derivatives[2,@derivatives.length - 2].each do |metric| aggs_stats[metric] += v[metric] end end @@ -106,9 +106,9 @@ def aggregate_stats aggs_stats[:hit_ratio] = aggs_stats[:hit_ratio] /aggs_count aggs_stats[:miss_ratio] = aggs_stats[:miss_ratio] /aggs_count end - - if aggs_stats[:uptime] > 0 - @int_values.each do |stat| + + if aggs_stats[:uptime] > 0 + @int_values.each do |stat| debug "recording #{MEMCACHED}/all/#{stat.to_s} = #{aggs_stats[stat]}" begin stats("#{MEMCACHED}/all/#{stat.to_s}").record_data_point(aggs_stats[stat]) @@ -117,7 +117,7 @@ def aggregate_stats end end - @derived_values.each do |stat| + @derived_values.each do |stat| debug "recording #{MEMCACHED}/all/#{stat.to_s} = #{aggs_stats[stat]}" begin stats("#{MEMCACHED}/all/#{stat.to_s}").record_data_point(aggs_stats[stat]) @@ -135,15 +135,15 @@ def aggregate_stats end end end - else - debug "skipping aggregates since aggregate uptime is zero" + else + debug "skipping aggregates since aggregate uptime is zero" end rescue => e debug "Could not record stat: stats\n #{e.backtrace.join("\n")}" end end - - + + #TODO send stats for down nodes def issue_stats(hostname_port) debug "get stats from hostname #{hostname_port}" @@ -151,10 +151,10 @@ def issue_stats(hostname_port) split = hostname_port.split(':', 2) hostname = split.first port = split.last - + socket = TCPSocket.open(hostname, port) socket.send("stats\r\n", 0) - + # TODO UDP or use memcached gem to use udp first and fallback to tcp # socket = UDPSocket.open # socket.connect(@host, @port) @@ -182,28 +182,28 @@ def issue_stats(hostname_port) end nil end - - def parse_stats(hostname_port, stats_text) + + def parse_stats(hostname_port, stats_text) end_index = stats_text =~ /\s+END\s+$/ stats_text = stats_text[0, end_index] if end_index sss = stats_text.split(/\s+/) if sss.size % 3 != 0 logger.error "memcached: unexcpected stats output from #{hostname_port}: #{stats_text}" - break + raise "memcached: unexcpected stats output from #{hostname_port}: #{stats_text}" end triplets = [] while sss.any? do triplets << [ sss.shift, sss.shift, sss.shift] end stats = Hash.new - triplets.each do |triplet| + triplets.each do |triplet| debug "#{triplet[1].to_sym} = #{triplet[2]}" stats[triplet[1].to_sym] = triplet[2] end return stats end - def parse_and_report_stats(hostname_port, stats_text) + def parse_and_report_stats(hostname_port, stats_text) # pid = 21355 # uptime = 2089 # time = 1264673782 @@ -229,46 +229,46 @@ def parse_and_report_stats(hostname_port, stats_text) # threads = 5 # accepting_conns = 1 # listen_disabled_num = 0 - - + + # average_value # * Active Connections - free # * Current items # * evictions # * Total Size (memcache stat: limit_maxbytes) # * Used size (memcache stat: bytes) - # + # # need to compute during collection # * Hit Ratio (%) - # * Requests per interval + # * Requests per interval # * Hits per interval # * Misses per interval # * Sets per interval # * Free size (memcache stat: limit_maxbytes - bytes) - # + # # Also send all stats. - # - # - stats = parse_stats(hostname_port, stats_text) + # + # + stats = parse_stats(hostname_port, stats_text) #we store ints in the hash - @int_values.each do |stat| - stats[stat] = stats[stat].to_i + @int_values.each do |stat| + stats[stat] = stats[stat].to_i end #time is not shipped to collector but we add it for derivative calculations - stats[:time] = Time.at stats[:time].to_i + stats[:time] = Time.at stats[:time].to_i stats[:free_bytes] = stats[:limit_maxbytes] - stats[:bytes] - + previous_stats = @last_stats[hostname_port] if previous_stats tn = stats[:time] - tm = previous_stats[:time] + tm = previous_stats[:time] previous_r = previous_stats[:cmd_get] + previous_stats[:cmd_set]+ previous_stats[:cmd_flush] current_r = stats[:cmd_get] + stats[:cmd_set]+ stats[:cmd_flush] - - #unit per minute - stats[:rpm] = (current_r - previous_r) / (tn - tm) * 60 + + #unit per minute + stats[:rpm] = (current_r - previous_r) / (tn - tm) * 60 stats[:gpm] = (stats[:cmd_get] - previous_stats[:cmd_get]) / (tn - tm) * 60 stats[:spm] = (stats[:cmd_set] - previous_stats[:cmd_set]) / (tn - tm) * 60 stats[:fpm] = (stats[:cmd_flush] - previous_stats[:cmd_flush]) / (tn - tm) * 60 @@ -283,11 +283,11 @@ def parse_and_report_stats(hostname_port, stats_text) stats[:miss_ratio] = 0 end end - + #string_values = [:version] #float_values = [:rusage_user, :rusage_system] - - @int_values.each do |stat| + + @int_values.each do |stat| debug "recording #{MEMCACHED}/#{hostname_port}/#{stat.to_s} = #{stats[stat]}" begin stats("#{MEMCACHED}/#{hostname_port}/#{stat.to_s}").record_data_point(stats[stat]) @@ -295,7 +295,7 @@ def parse_and_report_stats(hostname_port, stats_text) debug "Could not record stat: #{stat}\n #{e.backtrace.join("\n")}" end end - @derived_values.each do |stat| + @derived_values.each do |stat| debug "recording #{MEMCACHED}/#{hostname_port}/#{stat.to_s} = #{stats[stat]}" begin stats("#{MEMCACHED}/#{hostname_port}/#{stat.to_s}").record_data_point(stats[stat]) @@ -317,7 +317,7 @@ def parse_and_report_stats(hostname_port, stats_text) end end - # float_values.each do |stat| + # float_values.each do |stat| # debug "recording #{MEMCACHED}/#{hostname_port}/#{stat.to_s} = #{stats[stat].to_f}" # begin # stats("#{MEMCACHED}/#{hostname_port}/#{stat.to_s}").record_data_point(stats[stat].to_f) @@ -328,11 +328,11 @@ def parse_and_report_stats(hostname_port, stats_text) debug "Done with record data" return stats end - + def stats(s) NewRelic::Agent.get_stats_no_scope(s) end - + def debug(msg) logger.debug "memcached: #{msg}" end diff --git a/lib/new_relic/ia/version.rb b/lib/new_relic/ia/version.rb index 95eb8f4..755166f 100644 --- a/lib/new_relic/ia/version.rb +++ b/lib/new_relic/ia/version.rb @@ -1,5 +1,5 @@ module NewRelic module IA - VERSION = '0.2.1' + VERSION = '0.2.3' end end diff --git a/newrelic_ia.gemspec b/newrelic_ia.gemspec index a875e00..a9715aa 100644 --- a/newrelic_ia.gemspec +++ b/newrelic_ia.gemspec @@ -1,82 +1,26 @@ -# Generated by jeweler -# DO NOT EDIT THIS FILE DIRECTLY -# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command # -*- encoding: utf-8 -*- +require File.expand_path('../lib/new_relic/ia/version', __FILE__) -Gem::Specification.new do |s| - s.name = %q{newrelic_ia} - s.version = "0.2.1" +Gem::Specification.new do |gem| + gem.authors = ["Bill Kayser"] + gem.email = ["bkayser@newrelic.com"] + gem.description = %q{The New Relic Infrastructure Agent (IA) collects system metrics and transmits +them to the RPM server where they can be viewed with custom dashboards.} + gem.summary = %q{New Relic Gem for gathering system metrics} + gem.homepage = "http://www.newrelic.com" - s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= - s.authors = ["Bill Kayser"] - s.date = %q{2010-04-12} - s.default_executable = %q{newrelic_ia} - s.description = %q{The New Relic Infrastructure Agent (IA) collects system metrics and transmits -them to the RPM server where they can be viewed with custom dashboards. -} - s.email = %q{bkayser@newrelic.com} - s.executables = ["newrelic_ia"] - s.extra_rdoc_files = [ - "CHANGELOG", - "LICENSE", - "README.rdoc", - "bin/newrelic_ia" - ] - s.files = [ - "CHANGELOG", - "README.rdoc", - "Rakefile", - "lib/new_relic/ia/cli.rb", - "lib/new_relic/ia/disk_sampler.rb", - "lib/new_relic/ia/iostat_reader.rb", - "lib/new_relic/ia/iostat_reader/linux.rb", - "lib/new_relic/ia/iostat_reader/osx.rb", - "lib/new_relic/ia/memcached_sampler.rb", - "lib/new_relic/ia/metric_names.rb", - "lib/new_relic/ia/newrelic.yml", - "lib/new_relic/ia/version.rb", - "lib/newrelic_ia.rb", - "spec/cli_spec.rb", - "spec/disk_sampler_spec.rb", - "spec/iostat-linux.out", - "spec/iostat-osx.out", - "spec/iostat_reader_spec.rb", - "spec/memcached-1.out", - "spec/memcached-nodes.txt", - "spec/memcached_sampler_spec.rb", - "spec/spec.opts", - "spec/spec_helper.rb", - "tasks/rspec.rake" - ] - s.homepage = %q{http://www.newrelic.com} - s.post_install_message = %q{ -For more information refer to http://support.newrelic.com or -say 'newrelic' at #newrelic on freenode IRC. + gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } + gem.files = `git ls-files`.split("\n") + gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") + gem.name = "newrelic_ia" + gem.require_paths = ["lib"] + gem.version = NewRelic::IA::VERSION + gem.extra_rdoc_files = %w[CHANGELOG LICENSE README.rdoc bin/newrelic_ia] + gem.post_install_message = %q{For more information refer to http://support.newrelic.com or +say 'newrelic' at #newrelic on freenode IRC.} -} - s.rdoc_options = ["--charset=UTF-8", "--line-numbers", "--inline-source", "--title", "New Relic Gem for gathering system metrics", "-m", "README.rdoc"] - s.require_paths = ["lib"] - s.rubygems_version = %q{1.3.6} - s.summary = %q{New Relic Gem for gathering system metrics} - s.test_files = [ - "spec/cli_spec.rb", - "spec/disk_sampler_spec.rb", - "spec/iostat_reader_spec.rb", - "spec/memcached_sampler_spec.rb", - "spec/spec_helper.rb" - ] - - if s.respond_to? :specification_version then - current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION - s.specification_version = 3 - - if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then - s.add_runtime_dependency(%q<newrelic_rpm>, [">= 2.10.6"]) - else - s.add_dependency(%q<newrelic_rpm>, [">= 2.10.6"]) - end - else - s.add_dependency(%q<newrelic_rpm>, [">= 2.10.6"]) - end + gem.add_dependency 'newrelic_rpm', '>=3.1.0' + gem.add_development_dependency 'rspec', '>= 2.0.0' + gem.add_development_dependency 'mocha', '>= 0' end diff --git a/spec/cli_spec.rb b/spec/cli_spec.rb index a018b8b..f3154e8 100644 --- a/spec/cli_spec.rb +++ b/spec/cli_spec.rb @@ -6,6 +6,7 @@ describe NewRelic::IA::CLI, "execute" do before(:each) do @stdout_io = StringIO.new + NewRelic::Agent::Agent.any_instance.stubs(:connected?).returns(true) end it "should print help" do NewRelic::IA::CLI.execute(@stdout_io, [ "-h"]) @@ -30,12 +31,16 @@ end it "should start memcached" do NewRelic::Agent::StatsEngine.any_instance.expects(:add_harvest_sampler) + NewRelic::IA::MemcachedSampler.any_instance.stubs(:check) stat = NewRelic::IA::CLI.execute(@stdout_io, [ "memcached"]) stat.should == nil end + it "should install a newrelic.yml" do + NewRelic::IA::CLI.execute(@stdout_io, ["--install", "01234567"]) + end it "should override the env" do stat = NewRelic::IA::CLI.execute(@stdout_io, [ "disk", "-e", "production"]) stat.should == nil NewRelic::Control.instance.env.should == "production" end -end \ No newline at end of file +end diff --git a/spec/disk_sampler_spec.rb b/spec/disk_sampler_spec.rb index 9617889..511b6db 100644 --- a/spec/disk_sampler_spec.rb +++ b/spec/disk_sampler_spec.rb @@ -2,18 +2,18 @@ require 'new_relic/ia/disk_sampler' # http://rspec.info/ describe NewRelic::IA::DiskSampler do - + before do @sampler = NewRelic::IA::DiskSampler.new # @statsengine = stub(:get_stats => @stats) @statsengine = NewRelic::Agent::StatsEngine.new @sampler.stats_engine = @statsengine end - + it "should poll on demand" do 2.times { @sampler.poll } @statsengine.metrics.each do |m| - stats = @statsengine.lookup_stat m + stats = @statsengine.lookup_stats m stats.call_count.should == 2 m.should match(/System\/Filesystem\/.*percent/) end diff --git a/spec/iostat_reader_spec.rb b/spec/iostat_reader_spec.rb index 01c9186..a2f3a15 100644 --- a/spec/iostat_reader_spec.rb +++ b/spec/iostat_reader_spec.rb @@ -10,53 +10,53 @@ def cmd; "iostat -dCI 2" ; end end describe NewRelic::IA::IostatReader do - + include NewRelic::IA::MetricNames - METRICS = [NewRelic::IA::MetricNames::SYSTEM_CPU, NewRelic::IA::MetricNames::USER_CPU, NewRelic::IA::MetricNames::DISK_IO].sort + METRICS = [NewRelic::IA::MetricNames::SYSTEM_CPU, NewRelic::IA::MetricNames::USER_CPU, NewRelic::IA::MetricNames::DISK_IO].sort before do @statsengine = NewRelic::Agent::StatsEngine.new NewRelic::Agent.instance.stubs(:stats_engine).returns(@statsengine) @reader = NewRelic::IA::IostatReader.new end - + def canned_data_loader(filename) @reader.instance_eval do @pipe = File.open(File.join(File.dirname(__FILE__),filename)) end - @reader.init + @reader.init @reader.read_next @reader.read_next @reader.read_next metrics = [NewRelic::IA::MetricNames::SYSTEM_CPU, NewRelic::IA::MetricNames::USER_CPU, NewRelic::IA::MetricNames::DISK_IO].sort @statsengine.metrics.sort.should == metrics - stats = metrics.map { | m | [m, @statsengine.lookup_stat(m) ] } + stats = metrics.map { | m | [m, @statsengine.lookup_stats(m) ] } Hash[*stats.flatten] end - + it "should read repeatedly" do @reader.init @reader.read_next @reader.read_next @statsengine.metrics.sort.should == METRICS @statsengine.metrics.each do |m| - stats = @statsengine.lookup_stat m + stats = @statsengine.lookup_stats m stats.call_count.should == 2 end end - + it "should process linux stats" do # NewRelic::IA::CLI.log.level=Logger::DEBUG @reader.extend NewRelic::IA::IostatReader::Linux stats = canned_data_loader("iostat-linux.out") - + stats[NewRelic::IA::MetricNames::DISK_IO].total_call_time.should == 8261632.0 stats[NewRelic::IA::MetricNames::DISK_IO].call_count.should == 9 - stats[NewRelic::IA::MetricNames::SYSTEM_CPU].call_count.should == 3 - stats[NewRelic::IA::MetricNames::SYSTEM_CPU].total_call_time.should == 1.51 - stats[NewRelic::IA::MetricNames::USER_CPU].call_count.should == 3 + stats[NewRelic::IA::MetricNames::SYSTEM_CPU].call_count.should == 3 + stats[NewRelic::IA::MetricNames::SYSTEM_CPU].total_call_time.should == 1.51 + stats[NewRelic::IA::MetricNames::USER_CPU].call_count.should == 3 stats[NewRelic::IA::MetricNames::USER_CPU].total_call_time.should == 33.0 end - + it "should process osx stats" do # NewRelic::IA::CLI.log.level=Logger::DEBUG @reader.extend NewRelic::IA::IostatReader::OSX @@ -66,5 +66,5 @@ def canned_data_loader(filename) stats[NewRelic::IA::MetricNames::USER_CPU].total_call_time.should == 15.0 stats[NewRelic::IA::MetricNames::DISK_IO].total_call_time.round.should == 1468006.0 end - + end diff --git a/spec/memcached_sampler_spec.rb b/spec/memcached_sampler_spec.rb index 3e4203d..c622952 100644 --- a/spec/memcached_sampler_spec.rb +++ b/spec/memcached_sampler_spec.rb @@ -2,7 +2,7 @@ require 'new_relic/ia/memcached_sampler' # http://rspec.info/ describe NewRelic::IA::MemcachedSampler do - + before do #NewRelic::Agent.instance.log.level = Logger::DEBUG NewRelic::Agent.reset_stats @@ -10,22 +10,22 @@ logger = Logger.new(STDOUT) logger.level = Logger::INFO @sampler.stubs(:logger).returns(logger) - + # @statsengine = stub(:get_stats => @stats) @statsengine = NewRelic::Agent::StatsEngine.new @sampler.stats_engine = @statsengine @sampler.stubs(:memcached_nodes).returns(["localhost:11211"]) - @statsengine.clear_stats + @statsengine.clear_stats end - + it "should parse stats" do file = File.open(File.join(File.dirname(__FILE__),"memcached-1.out"), "r") stats_text = file.read @sampler.stubs(:issue_stats).returns(stats_text) - + @sampler.poll @statsengine.metrics.each do |m| - stats = @statsengine.lookup_stat m + stats = @statsengine.lookup_stats m stats.call_count.should == 1 m.should match(/System\/Memcached.*/) end @@ -34,15 +34,15 @@ @sampler.stubs(:issue_stats).returns(nil) @sampler.poll @statsengine.metrics.each do |m| - stats = @statsengine.lookup_stat m + stats = @statsengine.lookup_stats m stats.call_count.should == 0 end @sampler.stubs(:issue_stats).returns("") @sampler.poll - + @statsengine.metrics.each do |m| - stats = @statsengine.lookup_stat m + stats = @statsengine.lookup_stats m puts "#{m}: #{stats}" stats.call_count.should == 0 end @@ -50,7 +50,7 @@ # it "should poll on demand" do # 2.times { @sampler.poll } # @statsengine.metrics.each do |m| - # stats = @statsengine.lookup_stat m + # stats = @statsengine.lookup_stats m # stats.call_count.should == 2 # m.should match(/System\/Filesystem\/.*percent/) # end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6abc103..dbb5776 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -4,8 +4,7 @@ require 'newrelic_rpm' rescue LoadError require 'rubygems' unless ENV['NO_RUBYGEMS'] - gem 'rspec' - require 'spec' + require 'rspec' require 'newrelic_ia' require 'newrelic_rpm' end @@ -15,7 +14,7 @@ module NewRelic; TEST = true; end unless defined? NewRelic::TEST NewRelic::IA::CLI.level = Logger::ERROR -Spec::Runner.configure do |config| +RSpec.configure do |config| # == Fixtures # # You can declare fixtures for each example_group like this: @@ -49,6 +48,6 @@ module NewRelic; TEST = true; end unless defined? NewRelic::TEST config.mock_with :mocha # == Notes - # + # # For more information take a look at Spec::Example::Configuration and Spec::Runner end diff --git a/tasks/rspec.rake b/tasks/rspec.rake deleted file mode 100644 index 31a99b0..0000000 --- a/tasks/rspec.rake +++ /dev/null @@ -1,21 +0,0 @@ -begin - require 'spec' -rescue LoadError - require 'rubygems' unless ENV['NO_RUBYGEMS'] - require 'spec' -end -begin - require 'spec/rake/spectask' -rescue LoadError - puts <<-EOS -To use rspec for testing you must install rspec gem: - gem install rspec -EOS - exit(0) -end - -desc "Run the specs under spec/models" -Spec::Rake::SpecTask.new do |t| - t.spec_opts = ['--options', "spec/spec.opts"] - t.spec_files = FileList['spec/**/*_spec.rb'] -end