newrelic_plugin 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in newrelic_plugin.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2013 New Relic, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,46 @@
1
+ # New Relic Platform Agent SDK
2
+
3
+ ## Requirements
4
+
5
+ * Tested with Ruby 1.8.7 and 1.9.3
6
+ * New Relic account on rpm.newrelic.com, with early access enabled
7
+ (contact cooper@newrelic.com to set up early access)
8
+
9
+ ## Get Started
10
+
11
+ This repo represents the core Ruby gem used to build plugin agents for
12
+ the New Relic platform. If you are looking to build or use a platform
13
+ component, please refer to the
14
+ [getting started documentation](http://newrelic.com/docs/platform/plugin-development).
15
+
16
+ Until this gem is published in rubygems.org, you will need to use this
17
+ gem by adding it to your [bundler](http://gembundler.com/) Gemfile like this:
18
+
19
+ ```ruby
20
+ gem "newrelic_plugin", :git => "git@github.com:newrelic-platform/newrelic_plugin.git", :branch => "release"
21
+ ```
22
+
23
+ Alternatively you can build and install the gem locally:
24
+
25
+ ```bash
26
+ git clone git@github.com:newrelic-platform/newrelic_plugin.git
27
+ cd newrelic_plugin
28
+ rake build
29
+ gem install pkg/newrelic_plugin*
30
+ ```
31
+
32
+ ## Support
33
+
34
+ Reach out to us at
35
+ [support.newrelic.com](http://support.newrelic.com/).
36
+ There you'll find documentation, FAQs, and forums where you can submit
37
+ suggestions and discuss with staff and other users.
38
+
39
+ Also available is community support on IRC: we generally use #newrelic
40
+ on irc.freenode.net
41
+
42
+ Find a bug? E-mail <support@newrelic.com>, or submit a ticket to
43
+
44
+ [support.newrelic.com](http://support.newrelic.com/).
45
+
46
+ Thank you!
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'date'
4
+ require "bundler/gem_tasks"
5
+
6
+ #############################################################################
7
+ #
8
+ # Standard tasks
9
+ #
10
+ #############################################################################
11
+
12
+ task :default => :test
13
+
14
+ require 'rake/testtask'
15
+ Rake::TestTask.new(:test) do |test|
16
+ test.libs << 'lib' << 'test'
17
+ test.pattern = 'test/**/*_test.rb'
18
+ test.verbose = true
19
+ end
@@ -0,0 +1,12 @@
1
+ require "newrelic_plugin/version"
2
+ require "newrelic_plugin/error"
3
+ require "newrelic_plugin/config"
4
+ require "newrelic_plugin/new_relic_connection"
5
+ require "newrelic_plugin/new_relic_message"
6
+ require "newrelic_plugin/agent"
7
+ require "newrelic_plugin/data_collector"
8
+ require "newrelic_plugin/setup" # cleanup needed
9
+ require "newrelic_plugin/run" # cleanup needed
10
+ require "newrelic_plugin/processor"
11
+ require "newrelic_plugin/processors/epoch_counter_processor" # port needed
12
+ require "newrelic_plugin/processors/rate_processor" # port needed
@@ -0,0 +1,155 @@
1
+ module NewRelic
2
+ module Plugin
3
+ #
4
+ # Primary newrelic_plugin agent.
5
+ #
6
+ # Author:: Lee Atchison <lee@newrelic.com>
7
+ # Copyright:: Copyright (c) 2012 New Relic, Inc.
8
+ #
9
+ module Agent
10
+ class Base
11
+ class << self
12
+ attr_reader :label,:instance_label_proc,:guid,:version
13
+ attr_accessor :config_options_list
14
+
15
+
16
+ #
17
+ # Define the GUID for this agent.
18
+ #
19
+ def agent_guid str
20
+ raise "Did not set GUID" if str.nil? or str==""
21
+ @guid=str
22
+ end
23
+
24
+ #
25
+ # Define version for this agent
26
+ #
27
+ def agent_version str
28
+ @version = str
29
+ end
30
+
31
+ #
32
+ #
33
+ # Human Readable labels for plugin.
34
+ # label - Name of the plugin
35
+ # block return - Name of a particular instance of a plugin component.
36
+ #
37
+ #
38
+ def agent_human_labels label,&block
39
+ @label=label
40
+ @instance_label_proc=block
41
+ end
42
+
43
+ #
44
+ #
45
+ # Support for single instance, non-configurable agents.
46
+ #
47
+ #
48
+ def no_config_required
49
+ @no_config_required=true
50
+ end
51
+ def config_required?
52
+ !@no_config_required
53
+ end
54
+
55
+ #
56
+ #
57
+ # Specify name of configuration values used in plugin implementation.
58
+ #
59
+ #
60
+ def agent_config_options *args
61
+ @config_options_list||=[]
62
+ args.each do |config|
63
+ attr_accessor config
64
+ @config_options_list << config
65
+ end
66
+ end
67
+ end
68
+
69
+ #
70
+ # Instance Info
71
+ #
72
+ attr_reader :name,:agent_info
73
+ def guid
74
+ return @guid if @guid
75
+ @guid=self.class.guid
76
+ #
77
+ # Verify GUID is set correctly...
78
+ #
79
+ if @guid=="guid" or @guid=="_TYPE_YOUR_GUID_HERE_"
80
+ #this feels tightly coupled to the config class, testing this is difficult, thinking about refactoring (NH)
81
+ @guid = NewRelic::Plugin::Config.config.newrelic['guids'][agent_info[:ident].to_s] if NewRelic::Plugin::Config.config.newrelic['guids']
82
+ puts "NOTE: GUID updated for #{instance_label} at run-time to '#{@guid}'"
83
+ end
84
+ raise "Did not set GUID" if @guid.nil? or @guid=="" or @guid=="guid" or @guid=="_TYPE_YOUR_GUID_HERE_"
85
+ @guid
86
+ end
87
+ def version
88
+ self.class.version
89
+ end
90
+ def label
91
+ self.class.label
92
+ end
93
+ #
94
+ # Instantiate a newrelic_plugin instance
95
+ def initialize name,agent_info,options={}
96
+ @name=name
97
+ @agent_info=agent_info
98
+ @ident=agent_info[:ident]
99
+ @options=options
100
+ if self.class.config_options_list
101
+ self.class.config_options_list.each do |config|
102
+ self.send("#{config}=",options[config])
103
+ end
104
+ end
105
+ @last_time=nil
106
+
107
+ #
108
+ # Run agent-specific metric setup, if necessary
109
+ setup_metrics if respond_to? :setup_metrics
110
+ end
111
+ def instance_label
112
+ if !respond_to? :instance_label_proc_method
113
+ mod=Module.new
114
+ mod.send :define_method,:instance_label_proc_method,self.class.instance_label_proc
115
+ self.extend mod
116
+ end
117
+ self.instance_label_proc_method
118
+ end
119
+
120
+ #
121
+ #
122
+ # Setup & Report Metrics
123
+ #
124
+ #
125
+ def report_metric metric_name,units,value,opts={}
126
+ return if value.nil?
127
+ @data_collector.add_data metric_name,units,value.to_f,opts
128
+ end
129
+
130
+ #
131
+ #
132
+ # Execute a poll cycle
133
+ #
134
+ #
135
+ def run poll_interval
136
+ #
137
+ # Start of cycle work, if any
138
+ cycle_start if respond_to? :cycle_start
139
+
140
+ #
141
+ # Collect Data
142
+ @data_collector=DataCollector.new self,poll_interval
143
+ poll_cycle
144
+ cnt=@data_collector.process
145
+ @data_collector=nil
146
+
147
+ #
148
+ # End of cycle work, if any
149
+ cycle_end if respond_to? :cycle_end
150
+ cnt
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,84 @@
1
+ require 'yaml'
2
+ module NewRelic
3
+ module Plugin
4
+ #
5
+ #
6
+ # Process global config file for NewRelic. This is defined per execution environment.
7
+ #
8
+ # Author:: Lee Atchison <lee@newrelic.com>
9
+ # Copyright:: Copyright (c) 2012 New Relic, Inc.
10
+ #
11
+ # The system configuration can be accessed as a hash using this method. For example:
12
+ #
13
+ # NewRelic::Plugin::Config.config.options['xxx']
14
+ # or:
15
+ # NewRelic::Plugin::Config.config.newrelic['...']
16
+ # or:
17
+ # NewRelic::Plugin::Config.config.agents['...']
18
+ #
19
+ #
20
+ class Config
21
+ attr_reader :options
22
+ # Creates an instance of a configuration object, loading the configuration
23
+ # from the YAML configuration file. Note: this method should not be used
24
+ # directly, rather the global method +config+ should be referenced instead.
25
+ def initialize
26
+ @options = YAML::load(Config.config_yaml) if Config.config_yaml
27
+ @options = YAML.load_file(Config.config_file) unless @options
28
+ end
29
+
30
+ #
31
+ # Return a hash of NewRelic configuration information.
32
+ #
33
+ # Usage: NewRelic::Plugin::Config.config.newrelic[...]
34
+ #
35
+ def newrelic
36
+ @options["newrelic"]
37
+ end
38
+ #
39
+ # Return a hash of agent configuration information.
40
+ #
41
+ # Usage: NewRelic::Plugin::Config.config.agents[...]
42
+ #
43
+ def agents
44
+ @options["agents"]
45
+ end
46
+
47
+ #
48
+ # Set the name of the configuration file:
49
+ #
50
+ # NewRelic::Plugin::Config.config_file="lib/config.yml"
51
+ #
52
+ def self.config_file= config_file
53
+ @config_file=config_file
54
+ @config_yaml=nil
55
+ @instance=nil
56
+ end
57
+ def self.config_file
58
+ @config_file||="config/newrelic_plugin.yml"
59
+ end
60
+ #
61
+ # Set the content of the configuration as a YAML string
62
+ #
63
+ # NewRelic::Plugin::Config.config_yaml="newrelic:\n test: 2\n test2: four\nagents:\n test: 4\n test2: six\n"
64
+ #
65
+ def self.config_yaml= config_yaml
66
+ @config_yaml=config_yaml
67
+ @config_file=nil
68
+ @instance=nil
69
+ end
70
+ def self.config_yaml
71
+ @config_yaml
72
+ end
73
+ #
74
+ # Returns a memoized version of the configuration object.
75
+ #
76
+ def self.config
77
+ @instance||=NewRelic::Plugin::Config.new
78
+ end
79
+ end
80
+ end
81
+ end
82
+ def plugin_config
83
+ NewRelic::Plugin::Config.config
84
+ end
@@ -0,0 +1,67 @@
1
+ module NewRelic
2
+ module Plugin
3
+ #
4
+ # Gather's data from agent and presents it to nr_connect for processing.
5
+ #
6
+ # This is a wrapper for nr_connect used in the context of an agent.
7
+ #
8
+ class DataCollector
9
+ #
10
+ #
11
+ # Methods used within an agent implementation:
12
+ #
13
+ #
14
+ def add_data metric_name,units,data,opts={}
15
+ nrmsg.add_stat_fullname(
16
+ "Component/#{metric_name}[#{units}]",
17
+ 1,
18
+ data,
19
+ :min => data,
20
+ :max => data,
21
+ :sum_of_squares => (data*data)
22
+ )
23
+ #puts "Metric '#{metric_name}' (#{units}): raw: #{value}, processed: #{data} (#{processor_type})" if verbose?
24
+ @cnt+=1
25
+ data
26
+ end
27
+
28
+
29
+ #
30
+ # Internal methods used within Agent class
31
+ #
32
+ def initialize agent,poll_interval
33
+ @agent=agent
34
+ @poll_interval=poll_interval
35
+ @cnt=0
36
+ end
37
+ def process
38
+ nrmsg_send
39
+ @cnt
40
+ end
41
+
42
+ ################################################################################
43
+ private
44
+
45
+ def verbose?
46
+ return @verbose unless @verbose.nil?
47
+ @verbose=NewRelic::Plugin::Config.config.newrelic["verbose"].to_i>0
48
+ end
49
+
50
+ #
51
+ # NewRelicConnection Handling
52
+ #
53
+ def nrmsg
54
+ @nrmsg||=nrobj.start_message @agent.instance_label,@agent.guid,@agent.version,@poll_interval
55
+ end
56
+ def nrmsg_send
57
+ return unless @nrmsg
58
+ @nrmsg.send_metrics
59
+ @nrmsg=nil
60
+ end
61
+ def nrobj
62
+ @nrobj||=NewRelic::Plugin::NewRelicConnection.new NewRelic::Plugin::Config.config.newrelic
63
+ end
64
+
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,22 @@
1
+ module NewRelic
2
+
3
+ # Standard Errors
4
+ #
5
+ # Author:: Lee Atchison <lee@newrelic.com>
6
+ # Copyright:: Copyright (c) 2012 New Relic, Inc.
7
+ #
8
+ module Plugin # :nodoc:
9
+ class AgentError<Exception;end
10
+ class NoAgents<Exception;end
11
+ class NoMetrics<Exception;end
12
+ class NewRelicCommError<Exception;end
13
+ class UnknownInstalledAgent<AgentError;end
14
+ class UnknownInstalledProcessor<AgentError;end
15
+ class CouldNotInitializeAgent<AgentError;end
16
+ class CouldNotInitializeProcessor<AgentError;end
17
+ class BadConfig<AgentError;end
18
+ class NoResultReturned<AgentError;end
19
+ class NoDataReturned<AgentError;end
20
+ class InvalidMetricValueType<AgentError;end
21
+ end
22
+ end
@@ -0,0 +1,67 @@
1
+ require 'faraday'
2
+
3
+ module NewRelic
4
+ module Plugin
5
+ class NewRelicConnection
6
+ #
7
+ # Allowed configuration Values:
8
+ # license_key [required] Specifies RPM account to store metrics in
9
+ # host [optional] override default production collector
10
+ # port [optional] override default production collector
11
+ # verbose [optional] log HTTP transactions to stdout
12
+ #
13
+ def initialize config = {}
14
+ @config = config
15
+ end
16
+ #
17
+ # Start creating a message containing a set of metrics to New Relic.
18
+ #
19
+ def start_message component_name,component_guid,component_version,duration_in_seconds
20
+ NewRelic::Plugin::NewRelicMessage.new self,component_name,component_guid,component_version,duration_in_seconds
21
+ end
22
+
23
+ #################### Internal Only
24
+ #
25
+ # Create HTTP tunnel to New Relic
26
+ #
27
+ def connect
28
+ @connect ||= Faraday.new(:url => url, :ssl => { :verify => ssl_host_verification } ) do |builder|
29
+ builder.request :url_encoded
30
+ builder.response :logger if @config["log_http"].to_i>0
31
+ builder.use AuthenticationMiddleware,license_key
32
+ builder.adapter :net_http
33
+ end
34
+ end
35
+ def url
36
+ @config["endpoint"] || "https://platform-api.newrelic.com"
37
+ end
38
+ def uri
39
+ @config["uri"] || "/platform/v1/metrics"
40
+ end
41
+ def ssl_host_verification
42
+ ssl_host_verification = @config["ssl_host_verification"]
43
+ return true if ssl_host_verification.nil?
44
+ !!ssl_host_verification
45
+ end
46
+ class AuthenticationMiddleware < Faraday::Middleware
47
+ def initialize(app,apikey)
48
+ super(app)
49
+ @apikey = apikey
50
+ end
51
+ def call(env)
52
+ unless env[:request_headers]['X-License-Key']
53
+ env[:request_headers]['X-License-Key'] = @apikey
54
+ end
55
+ @app.call(env)
56
+ end
57
+ end
58
+ def log_metrics?
59
+ @config["verbose"] || @config["log_metrics"]
60
+ end
61
+ def license_key
62
+ @config["license_key"]
63
+ end
64
+
65
+ end
66
+ end
67
+ end