netuitived 0.10.1 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +21 -10
- data/bin/netuitived +12 -53
- data/config/agent.yml +3 -0
- data/lib/netuitived.rb +137 -12
- data/lib/netuitived/api_emissary.rb +51 -0
- data/lib/netuitived/config_manager.rb +91 -0
- data/lib/netuitived/event_handler.rb +40 -0
- data/lib/netuitived/ingest_attribute.rb +12 -0
- data/lib/netuitived/ingest_element.rb +26 -0
- data/lib/netuitived/ingest_event.rb +25 -0
- data/lib/netuitived/ingest_metric.rb +21 -0
- data/lib/netuitived/ingest_sample.rb +27 -0
- data/lib/netuitived/ingest_tag.rb +13 -0
- data/lib/netuitived/metric_aggregator.rb +142 -0
- data/lib/netuitived/netuitive_logger.rb +49 -0
- data/lib/netuitived/netuitived_server.rb +58 -0
- data/lib/netuitived/scheduler.rb +17 -0
- metadata +15 -13
- data/lib/netuitive/api_emissary.rb +0 -43
- data/lib/netuitive/ingest_attribute.rb +0 -10
- data/lib/netuitive/ingest_element.rb +0 -17
- data/lib/netuitive/ingest_metric.rb +0 -15
- data/lib/netuitive/ingest_sample.rb +0 -18
- data/lib/netuitive/ingest_tag.rb +0 -10
- data/lib/netuitive/metric_aggregator.rb +0 -146
- data/lib/netuitive/netuitived_config_manager.rb +0 -92
- data/lib/netuitive/netuitived_logger.rb +0 -24
- data/lib/netuitive/netuitived_server.rb +0 -53
- data/lib/netuitive/scheduler.rb +0 -14
data/README.md
CHANGED
@@ -1,20 +1,31 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
NetuitiveD
|
2
|
+
===========
|
3
3
|
|
4
|
-
|
4
|
+
NetuitiveD is a dRuby application submits and aggregates metrics through the use of DRbObjects. NetuitiveD is meant to work in conjunction with the [netuitive_ruby_api](https://rubygems.org/gems/netuitive_ruby_api) and [netuitive_rails_agent](https://rubygems.org/gems/netuitive_rails_agent) gems to help [Netuitive](https://www.netuitive.com) monitor your Ruby applications.
|
5
5
|
|
6
|
-
|
6
|
+
For more information on NetuitiveD, see our Ruby agent [help docs](https://help.netuitive.com/Content/Misc/Datasources/new_ruby_datasource.htm), or contact Netuitive support at [support@netuitive.com](mailto:support@netuitive.com).
|
7
|
+
|
8
|
+
Installing and Running NetuitiveD
|
9
|
+
---------------------------------
|
10
|
+
|
11
|
+
### Install
|
7
12
|
|
8
13
|
gem install netuitived
|
9
14
|
|
10
|
-
|
15
|
+
### Run
|
11
16
|
|
12
|
-
|
17
|
+
1. Run the start script (make sure the user using the command has access rights to the
|
18
|
+
gem's install directory):
|
13
19
|
|
14
|
-
|
20
|
+
netuitived start
|
15
21
|
|
16
|
-
The start script will prompt you for
|
22
|
+
1. The start script will prompt you for an API key and an element name. You can get an API key from creating a Ruby datasource in [Netuitive](https://app.netuitive.com/auth/login).
|
17
23
|
|
18
|
-
|
24
|
+
please enter an element name:
|
25
|
+
my_app_name
|
26
|
+
please enter an api key:
|
27
|
+
DEMOab681D46bf5616dba8337c85DEMO
|
28
|
+
|
29
|
+
If you're unsure about what element name you should use, just use the name of your Ruby application.
|
19
30
|
|
20
|
-
|
31
|
+
>**Note:** The extra config information is found in config/agent.yml. Each field in the config file can also be set using environment variables.
|
data/bin/netuitived
CHANGED
@@ -1,57 +1,16 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
require 'drb/drb'
|
3
|
+
require 'netuitived'
|
2
4
|
require 'yaml'
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
elementName = STDIN.gets.chomp
|
13
|
-
data["elementName"] = elementName
|
14
|
-
written = true
|
15
|
-
end
|
16
|
-
end
|
17
|
-
apiId=ENV["NETUITIVED_API_ID"]
|
18
|
-
if(apiId == nil or apiId == "")
|
19
|
-
apiId = data["apiId"]
|
20
|
-
if(apiId == "apiId" or apiId == "")
|
21
|
-
puts "please enter an api key: "
|
22
|
-
apiId = STDIN.gets.chomp
|
23
|
-
data["apiId"] = apiId
|
24
|
-
written = true
|
25
|
-
end
|
26
|
-
end
|
27
|
-
if written
|
28
|
-
File.open("#{gem_root}/config/agent.yml", 'w') {|f| f.write data.to_yaml }
|
29
|
-
end
|
30
|
-
require 'drb/drb'
|
31
|
-
netuitivedAddr=data["netuitivedAddr"]
|
32
|
-
netuitivedPort=data["netuitivedPort"]
|
33
|
-
SERVER_URI="druby://#{netuitivedAddr}:#{netuitivedPort}"
|
34
|
-
DRb.start_service
|
35
|
-
begin
|
36
|
-
DRbObject.new_with_uri(SERVER_URI).stopServer
|
37
|
-
sleep(2)
|
38
|
-
rescue
|
39
|
-
|
40
|
-
end
|
41
|
-
require 'netuitived'
|
42
|
-
puts "netuitived started"
|
43
|
-
elsif ARGV[0] == "stop"
|
44
|
-
require 'drb/drb'
|
45
|
-
netuitivedAddr=data["netuitivedAddr"]
|
46
|
-
netuitivedPort=data["netuitivedPort"]
|
47
|
-
SERVER_URI="druby://#{netuitivedAddr}:#{netuitivedPort}"
|
48
|
-
DRb.start_service
|
49
|
-
begin
|
50
|
-
DRbObject.new_with_uri(SERVER_URI).stopServer
|
51
|
-
puts "netuitived stopped"
|
52
|
-
rescue
|
53
|
-
puts "netuitived isn't running"
|
54
|
-
end
|
5
|
+
|
6
|
+
# Check command line arguments
|
7
|
+
case ARGV[0]
|
8
|
+
when 'run' # runs netuitived in the foreground
|
9
|
+
Netuitived.start(true)
|
10
|
+
when 'start' # runs netuitived in the background
|
11
|
+
Netuitived.start
|
12
|
+
when 'stop' # stops running netuitived
|
13
|
+
Netuitived.stop
|
55
14
|
else
|
56
|
-
|
15
|
+
puts 'invalid option. options are: run, start, stop'
|
57
16
|
end
|
data/config/agent.yml
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
#all are configurable using environment variables
|
2
|
+
logLocation: #absolute path of log file. leave blank for default location in the gem directory. environment variable: NETUITIVED_LOG_LOCATION
|
3
|
+
logAge: daily #Number of old log files to keep, or frequency of rotation (daily, weekly or monthly). environment variable: NETUITIVED_LOG_AGE
|
4
|
+
logSize: #Maximum logfile size (only applies when shift_age is a number). environment variable: NETUITIVED_LOG_SIZE
|
2
5
|
apiId: apiId #apiId for the datasources. found in the datasources section in the netuitive ui. environment variable: NETUITIVED_API_ID
|
3
6
|
baseAddr: "api.app.netuitive.com" #where to send the data. in most cases use the default. environment variable: NETUITIVED_BASE_ADDR
|
4
7
|
port: nil #in most cases this will be nil. environment variable: NETUITIVED_PORT
|
data/lib/netuitived.rb
CHANGED
@@ -1,12 +1,137 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
1
|
+
require 'drb/drb'
|
2
|
+
require 'net/http'
|
3
|
+
require 'json'
|
4
|
+
require 'yaml'
|
5
|
+
require 'drb/drb'
|
6
|
+
require 'logger'
|
7
|
+
require 'netuitived/config_manager'
|
8
|
+
require 'netuitived/netuitive_logger'
|
9
|
+
require 'netuitived/ingest_event'
|
10
|
+
require 'netuitived/ingest_tag'
|
11
|
+
require 'netuitived/ingest_metric'
|
12
|
+
require 'netuitived/ingest_sample'
|
13
|
+
require 'netuitived/ingest_element'
|
14
|
+
require 'netuitived/netuitived_server'
|
15
|
+
require 'netuitived/api_emissary'
|
16
|
+
require 'netuitived/metric_aggregator'
|
17
|
+
require 'netuitived/event_handler'
|
18
|
+
require 'netuitived/scheduler'
|
19
|
+
|
20
|
+
##
|
21
|
+
# Provides facilities for running Netuitived
|
22
|
+
class Netuitived
|
23
|
+
class << self
|
24
|
+
attr_reader :server_uri
|
25
|
+
|
26
|
+
##
|
27
|
+
# The DRb front object
|
28
|
+
#
|
29
|
+
# @return [NetuitivedServer] The NetuitivedServer front object
|
30
|
+
def front_object
|
31
|
+
@front_object ||= new_front_object
|
32
|
+
end
|
33
|
+
|
34
|
+
def new_front_object
|
35
|
+
apiEmissary = NetuitiveD::APIEmissary.new
|
36
|
+
NetuitiveD::NetuitivedServer.new(NetuitiveD::MetricAggregator.new(apiEmissary), NetuitiveD::EventHandler.new(apiEmissary))
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# Checks that config values are provided and prompts for them if not
|
41
|
+
def interactively_check_config
|
42
|
+
gem_root = File.expand_path('../..', __FILE__)
|
43
|
+
data = YAML.load_file("#{gem_root}/config/agent.yml")
|
44
|
+
|
45
|
+
written = false
|
46
|
+
element_name = ENV['NETUITIVED_ELEMENT_NAME'] || data['elementName'] || ''
|
47
|
+
|
48
|
+
if element_name == 'elementName' || element_name == ''
|
49
|
+
puts 'please enter an element name: '
|
50
|
+
element_name = STDIN.gets.chomp
|
51
|
+
data['elementName'] = element_name
|
52
|
+
written = true
|
53
|
+
end
|
54
|
+
|
55
|
+
api_id = ENV['NETUITIVED_API_ID'] || data['apiId'] || ''
|
56
|
+
|
57
|
+
if api_id == 'apiId' || api_id == ''
|
58
|
+
puts 'please enter an api key: '
|
59
|
+
api_id = STDIN.gets.chomp
|
60
|
+
data['apiId'] = api_id
|
61
|
+
written = true
|
62
|
+
end
|
63
|
+
|
64
|
+
return unless written
|
65
|
+
|
66
|
+
File.open("#{gem_root}/config/agent.yml", 'w') { |f| f.write data.to_yaml }
|
67
|
+
end
|
68
|
+
|
69
|
+
##
|
70
|
+
# Starts netuitived
|
71
|
+
#
|
72
|
+
# @param foreground [true, false] If true, run netuitived in the foreground
|
73
|
+
def start(foreground = false)
|
74
|
+
# Maintain the initial setup behavior
|
75
|
+
interactively_check_config
|
76
|
+
|
77
|
+
# Load the config from disk into ConfigManager
|
78
|
+
load_config
|
79
|
+
|
80
|
+
# Stop the service if it's already running
|
81
|
+
stop(true)
|
82
|
+
|
83
|
+
# Create a proc to run netuitived
|
84
|
+
runner = proc do
|
85
|
+
NetuitiveD::NetuitiveLogger.log.debug 'starting scheduler'
|
86
|
+
NetuitiveD::Scheduler.startSchedule
|
87
|
+
NetuitiveD::NetuitiveLogger.log.debug 'starting drb service'
|
88
|
+
begin
|
89
|
+
DRb.start_service(server_uri, front_object)
|
90
|
+
DRb.thread.join
|
91
|
+
rescue => e
|
92
|
+
NetuitiveD::NetuitiveLogger.log.error "drb error: #{e.message} backtrace: #{e.backtrace}"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
if foreground
|
97
|
+
puts 'netuitived running'
|
98
|
+
runner.call
|
99
|
+
else
|
100
|
+
fork(&runner)
|
101
|
+
puts 'netuitived started'
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
##
|
106
|
+
# Stops netuitived if it's running
|
107
|
+
#
|
108
|
+
# @param suppress_not_running_message [true, false] suppresses the "netuitived isn't running" message
|
109
|
+
def stop(suppress_not_running_message = false)
|
110
|
+
load_config
|
111
|
+
|
112
|
+
DRb.start_service
|
113
|
+
|
114
|
+
begin
|
115
|
+
DRbObject.new_with_uri(@server_uri).stopServer
|
116
|
+
puts 'netuitived stopped'
|
117
|
+
rescue
|
118
|
+
puts "netuitived isn't running" unless suppress_not_running_message
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
|
124
|
+
##
|
125
|
+
# Loads the configuration if necessary
|
126
|
+
def load_config
|
127
|
+
unless @config_manager_setup
|
128
|
+
NetuitiveD::ConfigManager.load_config
|
129
|
+
NetuitiveD::NetuitiveLogger.setup
|
130
|
+
NetuitiveD::ConfigManager.read_config
|
131
|
+
end
|
132
|
+
|
133
|
+
@config_manager_setup = true
|
134
|
+
@server_uri ||= "druby://#{NetuitiveD::ConfigManager.netuitivedAddr}:#{NetuitiveD::ConfigManager.netuitivedPort}".freeze
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module NetuitiveD
|
2
|
+
class APIEmissary
|
3
|
+
def sendElements(elementString)
|
4
|
+
NetuitiveD::NetuitiveLogger.log.debug 'start sending elements'
|
5
|
+
send("/ingest/ruby/#{NetuitiveD::ConfigManager.apiId}", elementString)
|
6
|
+
NetuitiveD::NetuitiveLogger.log.debug 'finish sending elements'
|
7
|
+
end
|
8
|
+
|
9
|
+
def sendEvents(eventString)
|
10
|
+
NetuitiveD::NetuitiveLogger.log.debug 'finish sending events'
|
11
|
+
send("/ingest/events/ruby/#{NetuitiveD::ConfigManager.apiId}", eventString)
|
12
|
+
NetuitiveD::NetuitiveLogger.log.debug 'finish sending events'
|
13
|
+
end
|
14
|
+
|
15
|
+
def send(uri, body)
|
16
|
+
NetuitiveD::NetuitiveLogger.log.debug "post body: #{body}"
|
17
|
+
req = Net::HTTP::Post.new(uri.to_s, 'Content-Type' => 'application/json')
|
18
|
+
req.body = body
|
19
|
+
NetuitiveD::NetuitiveLogger.log.debug 'starting post'
|
20
|
+
port = if NetuitiveD::ConfigManager.port =~ /(.*)nil(.*)/
|
21
|
+
nil
|
22
|
+
else
|
23
|
+
NetuitiveD::ConfigManager.port.to_int
|
24
|
+
end
|
25
|
+
NetuitiveD::NetuitiveLogger.log.debug "port: #{port}"
|
26
|
+
NetuitiveD::NetuitiveLogger.log.debug "path: #{req.path}"
|
27
|
+
NetuitiveD::NetuitiveLogger.log.debug "addr: #{NetuitiveD::ConfigManager.baseAddr}"
|
28
|
+
response = Net::HTTP.start(NetuitiveD::ConfigManager.baseAddr.to_s, port, use_ssl: true, read_timeout: 30, open_timeout: 30) do |http|
|
29
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
30
|
+
http.ssl_version = :SSLv3
|
31
|
+
http.request req
|
32
|
+
end
|
33
|
+
NetuitiveD::NetuitiveLogger.log.debug 'post finished'
|
34
|
+
if response.code.to_s != '202' && response.code.to_s != '200'
|
35
|
+
NetuitiveD::NetuitiveLogger.log.error "Response from submitting netuitive metrics to api
|
36
|
+
code: #{response.code}
|
37
|
+
message: #{response.message}
|
38
|
+
body: #{response.body}"
|
39
|
+
else
|
40
|
+
NetuitiveD::NetuitiveLogger.log.info "Response from submitting netuitive metrics to api
|
41
|
+
code: #{response.code}
|
42
|
+
message: #{response.message}
|
43
|
+
body: #{response.body}"
|
44
|
+
end
|
45
|
+
rescue => exception
|
46
|
+
NetuitiveD::NetuitiveLogger.log.error 'error with http post: '
|
47
|
+
NetuitiveD::NetuitiveLogger.log.error exception.message
|
48
|
+
NetuitiveD::NetuitiveLogger.log.error exception.backtrace
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module NetuitiveD
|
2
|
+
class ConfigManager
|
3
|
+
class << self
|
4
|
+
attr_reader :apiId
|
5
|
+
|
6
|
+
attr_reader :baseAddr
|
7
|
+
|
8
|
+
attr_reader :port
|
9
|
+
|
10
|
+
attr_reader :elementName
|
11
|
+
|
12
|
+
attr_reader :netuitivedAddr
|
13
|
+
|
14
|
+
attr_reader :netuitivedPort
|
15
|
+
|
16
|
+
attr_reader :interval
|
17
|
+
|
18
|
+
attr_reader :data
|
19
|
+
|
20
|
+
def property(name, var, default = nil)
|
21
|
+
prop = ENV[var]
|
22
|
+
prop = data[name] if prop.nil? || (prop == '')
|
23
|
+
return prop unless prop.nil? || (prop == '')
|
24
|
+
default
|
25
|
+
end
|
26
|
+
|
27
|
+
def boolean_property(name, var)
|
28
|
+
prop = ENV[var].nil? ? nil : ENV[var].dup
|
29
|
+
if prop.nil? || (prop == '')
|
30
|
+
prop = data[name]
|
31
|
+
else
|
32
|
+
prop.strip!
|
33
|
+
prop = prop.casecmp('true').zero?
|
34
|
+
end
|
35
|
+
prop
|
36
|
+
end
|
37
|
+
|
38
|
+
def float_property(name, var)
|
39
|
+
prop = ENV[var].nil? ? nil : ENV[var]
|
40
|
+
if prop.nil? || (prop == '')
|
41
|
+
data[name].to_f
|
42
|
+
else
|
43
|
+
prop.to_f
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def string_list_property(name, var)
|
48
|
+
list = []
|
49
|
+
prop = ENV[var].nil? ? nil : ENV[var].dup
|
50
|
+
if prop.nil? || (prop == '')
|
51
|
+
list = data[name] if !data[name].nil? && data[name].is_a?(Array)
|
52
|
+
else
|
53
|
+
list = prop.split(',')
|
54
|
+
end
|
55
|
+
list.each(&:strip!) unless list.empty?
|
56
|
+
list
|
57
|
+
end
|
58
|
+
|
59
|
+
def load_config
|
60
|
+
gem_root = File.expand_path('../../..', __FILE__)
|
61
|
+
@data = YAML.load_file "#{gem_root}/config/agent.yml"
|
62
|
+
end
|
63
|
+
|
64
|
+
def read_config
|
65
|
+
@apiId = property('apiId', 'NETUITIVED_API_ID')
|
66
|
+
@baseAddr = property('baseAddr', 'NETUITIVED_BASE_ADDR')
|
67
|
+
@port = property('port', 'NETUITIVED_PORT')
|
68
|
+
@elementName = property('elementName', 'NETUITIVED_ELEMENT_NAME')
|
69
|
+
@netuitivedAddr = property('netuitivedAddr', 'NETUITIVED_NETUITIVED_ADDR')
|
70
|
+
@netuitivedPort = property('netuitivedPort', 'NETUITIVED_NETUITIVED_PORT')
|
71
|
+
@interval = property('interval', 'NETUITIVED_INTERVAL')
|
72
|
+
debugLevelString = property('debugLevel', 'NETUITIVED_DEBUG_LEVEL')
|
73
|
+
NetuitiveD::NetuitiveLogger.log.level = if debugLevelString == 'error'
|
74
|
+
Logger::ERROR
|
75
|
+
elsif debugLevelString == 'info'
|
76
|
+
Logger::INFO
|
77
|
+
elsif debugLevelString == 'debug'
|
78
|
+
Logger::DEBUG
|
79
|
+
else
|
80
|
+
Logger::ERROR
|
81
|
+
end
|
82
|
+
NetuitiveD::NetuitiveLogger.log.debug "read config file. Results:
|
83
|
+
apiId: #{apiId}
|
84
|
+
baseAddr: #{baseAddr}
|
85
|
+
port: #{port}
|
86
|
+
elementName: #{elementName}
|
87
|
+
debugLevel: #{debugLevelString}"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module NetuitiveD
|
2
|
+
class EventHandler
|
3
|
+
def initialize(apiEmissary)
|
4
|
+
@apiEmissary = apiEmissary
|
5
|
+
end
|
6
|
+
|
7
|
+
def handleEvent(message, timestamp, title, level, source, type, tags)
|
8
|
+
NetuitiveD::NetuitiveLogger.log.debug "self: #{object_id}"
|
9
|
+
NetuitiveD::NetuitiveLogger.log.debug "Thread: #{Thread.current.object_id}"
|
10
|
+
NetuitiveD::NetuitiveLogger.log.debug "Received event: message:#{message}, timestamp:#{timestamp}, title:#{title}, level:#{level}, source:#{source}, type:#{type}, tags:#{tags}"
|
11
|
+
event = NetuitiveD::IngestEvent.new(NetuitiveD::ConfigManager.elementName, message, timestamp, title, level, source, type, tags)
|
12
|
+
events = [event]
|
13
|
+
eventString = events.to_json
|
14
|
+
@apiEmissary.sendEvents(eventString)
|
15
|
+
rescue => e
|
16
|
+
NetuitiveD::NetuitiveLogger.log.error "error in handling event: #{e.message}, backtrace: #{e.backtrace}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def handleExceptionEvent(exception, klass, tags = {})
|
20
|
+
message = "Exception Message: #{exception[:message]}\n" if (defined? exception[:message]) && !exception[:message].nil?
|
21
|
+
message ||= ''
|
22
|
+
timestamp = Time.new
|
23
|
+
title = 'Ruby Exception'
|
24
|
+
level = 'Warning'
|
25
|
+
source = 'Ruby Agent'
|
26
|
+
type = 'INFO'
|
27
|
+
ingest_tags = []
|
28
|
+
tags [:Exception] = klass unless klass.nil?
|
29
|
+
tags.each do |key, value|
|
30
|
+
next if !(defined? value) || value.nil? || value == ''
|
31
|
+
ingest_tags << NetuitiveD::IngestTag.new(key, value)
|
32
|
+
message += "#{key}: #{value}\n"
|
33
|
+
end
|
34
|
+
message += "Backtrace:\n\t#{exception[:backtrace]}" if (defined? exception[:backtrace]) && !exception[:backtrace].nil?
|
35
|
+
handleEvent(message, timestamp, title, level, source, type, ingest_tags)
|
36
|
+
rescue => e
|
37
|
+
NetuitiveD::NetuitiveLogger.log.error "error in exception event: #{e.message}, backtrace: #{e.backtrace}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|