apminsight 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +60 -0
- data/README.rdoc +69 -0
- data/Rakefile +63 -0
- data/VERSION +1 -0
- data/conf/apminsight.conf +105 -0
- data/lib/agent/am_objectholder.rb +66 -0
- data/lib/agent/configuration/am_configuration.rb +190 -0
- data/lib/agent/logging/am_logger.rb +109 -0
- data/lib/agent/metrics/am_metricscollector.rb +30 -0
- data/lib/agent/metrics/am_metricsformatter.rb +263 -0
- data/lib/agent/metrics/am_metricsparser.rb +540 -0
- data/lib/agent/metrics/am_metricstore.rb +29 -0
- data/lib/agent/server/am_agent.rb +108 -0
- data/lib/agent/server/am_connector.rb +195 -0
- data/lib/agent/server/instrument/am_apm.rb +99 -0
- data/lib/agent/server/instrument/am_instrumenter.rb +43 -0
- data/lib/agent/server/worker/am_worker.rb +254 -0
- data/lib/agent/util/am_constants.rb +64 -0
- data/lib/agent/util/am_util.rb +130 -0
- data/lib/apminsight.rb +5 -0
- metadata +134 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'agent/am_objectholder'
|
2
|
+
|
3
|
+
module ManageEngine
|
4
|
+
class APMMetricsStore
|
5
|
+
attr_accessor :metrics
|
6
|
+
def initialize
|
7
|
+
@metrics = Hash.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def remove keys
|
11
|
+
if keys!=nil
|
12
|
+
keys.each {|key| @metrics.delete("#{key}")}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def metrics_dup
|
17
|
+
@metrics.dup
|
18
|
+
end
|
19
|
+
|
20
|
+
def removeData key, strt_indx,end_indx
|
21
|
+
if @metrics.has_key?(key)
|
22
|
+
val = @metrics[key]
|
23
|
+
val = val.drop(end_indx)
|
24
|
+
@metrics[key]=val
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require "agent/am_objectholder"
|
2
|
+
require "agent/server/worker/am_worker"
|
3
|
+
|
4
|
+
require 'socket'
|
5
|
+
|
6
|
+
module ManageEngine
|
7
|
+
class APMAgent
|
8
|
+
def initialize
|
9
|
+
@obj = ManageEngine::APMObjectHolder.instance
|
10
|
+
@obj.log.debug "Agent Initialization - START"
|
11
|
+
doConnect
|
12
|
+
|
13
|
+
if !@obj.shutdown && @obj.agent_initialized
|
14
|
+
@obj.log.info "Agent Initialization - DONE"
|
15
|
+
@obj.instrumenter.doSubscribe
|
16
|
+
doDispatcherActions
|
17
|
+
doCollect
|
18
|
+
puts "ManageEngine APM Ruby Agent Started"
|
19
|
+
else
|
20
|
+
@obj.log.info "Agent Initialization Failed - Going to shutdown"
|
21
|
+
@obj.instrumenter.doSubscribe
|
22
|
+
@obj.shutdownagent
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
def doConnect
|
29
|
+
begin
|
30
|
+
if @obj.shutdown
|
31
|
+
@obj.log.info "[ Problem in Agent Startup ]"
|
32
|
+
else
|
33
|
+
agentInfo = @obj.config.getAgentInfo
|
34
|
+
resp = nil
|
35
|
+
if @obj.config.alreadyconnected
|
36
|
+
@obj.log.debug "[doConnect] Already Connected - Make Contact - Instance id = #{@obj.config.instance_id}"
|
37
|
+
resp = startConnect "?instance_id="+@obj.config.instance_id,agentInfo
|
38
|
+
else
|
39
|
+
@obj.log.debug "[doConnect] Going to connect - New "
|
40
|
+
resp = startConnect "",agentInfo
|
41
|
+
if resp.has_key?("instance-info")
|
42
|
+
aData = resp["instance-info"]
|
43
|
+
aData["agent.id"]=aData.delete("instanceid")
|
44
|
+
aData["agent.enabled"]=true
|
45
|
+
@obj.config.updateAgentInfoFile(aData)
|
46
|
+
@obj.log.debug "[doConnect] Connected - InstanceID : #{@obj.config.instance_id}"
|
47
|
+
else
|
48
|
+
@obj.log.info "[doConnect] [ Problem in connecting server] [ Going to shutdown ]"
|
49
|
+
@obj.shutdown=true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
if resp==nil
|
54
|
+
@obj.log.info "[doConnect] [ Error in Response while connecting Server . [ Going to shutdown ]"
|
55
|
+
@obj.shutdown= true
|
56
|
+
end
|
57
|
+
|
58
|
+
if(!@obj.shutdown)
|
59
|
+
@obj.agent_initialized=true
|
60
|
+
end
|
61
|
+
end
|
62
|
+
rescue Exception=>e
|
63
|
+
@obj.shutdown = true
|
64
|
+
@obj.log.logException "[doConnect] Exception while connecting server. [ Going to shutdown ] ",e
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
def doCollect
|
70
|
+
@obj.log.info "[doCollect] Starts - Wait time : #{@obj.config.connect_interval} seconds "
|
71
|
+
begin
|
72
|
+
ManageEngine::APMWorker.getInstance.start
|
73
|
+
rescue Exception=>e
|
74
|
+
@obj.log.logException "[doCollect] Exception during worker startup #{e.message}",e
|
75
|
+
@obj.shutdown=true
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
def startConnect uri,data
|
81
|
+
resp = @obj.connector.post @obj.constants.connect_uri+uri,data
|
82
|
+
end
|
83
|
+
|
84
|
+
def doDispatcherActions
|
85
|
+
case @obj.config.app_dispatcher
|
86
|
+
when 'passenger'
|
87
|
+
#starting a new process
|
88
|
+
PhusionPassenger.on_event(:starting_worker_process) do |forked|
|
89
|
+
if forked
|
90
|
+
@obj.log.info "starting_worker_process : Process ID :#{Process.pid} : Creating new apm worker"
|
91
|
+
doCollect
|
92
|
+
else
|
93
|
+
doCollect
|
94
|
+
@obj.log.info "starting_worker_process : Conservative Process ID :#{Process.pid} - No new worker"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
# shutting down a process.
|
98
|
+
PhusionPassenger.on_event(:stopping_worker_process) do
|
99
|
+
ManageEngine::APMWorker.getInstance.stop
|
100
|
+
@obj.log.info "stopping_worker_process :Process ID :#{Process.pid} ----> #$$ "
|
101
|
+
end
|
102
|
+
else#case
|
103
|
+
|
104
|
+
end#case
|
105
|
+
end
|
106
|
+
end#c
|
107
|
+
end#m
|
108
|
+
|
@@ -0,0 +1,195 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
require 'uri'
|
4
|
+
require 'json'
|
5
|
+
require "agent/server/instrument/am_instrumenter"
|
6
|
+
|
7
|
+
module ManageEngine
|
8
|
+
class APMConnector
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@obj = ManageEngine::APMObjectHolder.instance
|
12
|
+
@pretry =0
|
13
|
+
@gretry =0
|
14
|
+
end
|
15
|
+
|
16
|
+
def post uri,data
|
17
|
+
@pretry = @pretry +1
|
18
|
+
begin
|
19
|
+
|
20
|
+
u = url uri
|
21
|
+
#@obj.log.info "[connector] [ POST] START"
|
22
|
+
@obj.log.debug "[connector] [ POST] : \n\n#{u}\n\n#{data}\n\n"
|
23
|
+
con = connection(u)
|
24
|
+
req = Net::HTTP::Post.new(u.request_uri,initheader = {'Content-Type' =>'application/json'})
|
25
|
+
req.body=data.to_json
|
26
|
+
resp = con.request(req)
|
27
|
+
@obj.log.debug "[connector] [POST ] \n Response : #{resp} \nResponse Code : #{resp.code}\nMessage : #{resp.message}\nBody : #{resp.body}"
|
28
|
+
rdata = responseParser resp
|
29
|
+
@pretry = 0
|
30
|
+
#@obj.log.info "[connector] [ POST] END"
|
31
|
+
return rdata
|
32
|
+
rescue Exception=>e
|
33
|
+
@obj.log.logException "[connector] Exception while connecting server- Data not sent \n",e
|
34
|
+
if @pretry >=@obj.config.connection_retry
|
35
|
+
#@obj.shutdown= true
|
36
|
+
return nil
|
37
|
+
else
|
38
|
+
@obj.log.info "[connector] Exception found in Post request - Retrying - Count - #{@pretry}"
|
39
|
+
return post uri,data
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
@pretry = 0
|
44
|
+
end
|
45
|
+
|
46
|
+
def get uri
|
47
|
+
@gretry = @gretry +1
|
48
|
+
begin
|
49
|
+
u = url uri
|
50
|
+
#@obj.log.info "[connector] [ GET ] START"
|
51
|
+
@obj.log.debug "[connector] [ GET] : \n#{u}\n"
|
52
|
+
req = Net::HTTP::Get.new(u.request_uri)
|
53
|
+
resp = con.request(req)
|
54
|
+
#@obj.log.info "[connector] [ GET ] END"
|
55
|
+
rescue Exception=>e
|
56
|
+
@obj.log.logException "[connector] [ GET] Exception while connecting server - Data not sent ",e
|
57
|
+
if @pretry >=@obj.config.connection_retry
|
58
|
+
#@obj.shutdown= true
|
59
|
+
else
|
60
|
+
@obj.log.info "[connector] Exception found in Get request - Retrying - Count - #{@gretry}"
|
61
|
+
return get uri
|
62
|
+
end
|
63
|
+
end
|
64
|
+
@gretry = 0
|
65
|
+
end
|
66
|
+
|
67
|
+
def url(uri)
|
68
|
+
ru=nil
|
69
|
+
p="http"
|
70
|
+
if(@obj.config.is_secured)
|
71
|
+
p="https"
|
72
|
+
end
|
73
|
+
u = p+"://"+@obj.config.apmhost+":#{@obj.config.apmport}/"+uri
|
74
|
+
begin
|
75
|
+
ru = URI.parse(u)
|
76
|
+
rescue
|
77
|
+
raise URI::InvalidURIError, "Invalid url '#{ru}'"
|
78
|
+
end
|
79
|
+
|
80
|
+
if (ru.class != URI::HTTP && ru.class != URI::HTTPS)
|
81
|
+
raise URI::InvalidURIError, "Invalid url '#{u}'"
|
82
|
+
end
|
83
|
+
ru
|
84
|
+
end
|
85
|
+
|
86
|
+
def connection(url)
|
87
|
+
|
88
|
+
if (@obj.config.proxyneeded)
|
89
|
+
@obj.log.debug "[connect] Through Proxy"
|
90
|
+
con = Net::HTTP::Proxy(@obj.config.proxy_host, @obj.config.proxy_port,@obj.config.proxy_user,@obj.config.proxy_pass).new(url.host, url.port)
|
91
|
+
else
|
92
|
+
#@obj.log.info "Proxy Not Needed"
|
93
|
+
con = Net::HTTP.new(url.host, url.port)
|
94
|
+
end
|
95
|
+
con=getScheme(con)
|
96
|
+
con.open_timeout = @obj.constants.connection_open_timeout
|
97
|
+
con.read_timeout = @obj.constants.connection_read_timeout
|
98
|
+
con
|
99
|
+
end
|
100
|
+
|
101
|
+
def getScheme(con)
|
102
|
+
if(@obj.config.is_secured)
|
103
|
+
#@obj.log.info "[connect] Secured"
|
104
|
+
con = Net::HTTP::Proxy(@obj.config.proxy_host, @obj.config.proxy_port,@obj.config.proxy_user,@obj.config.proxy_pass).new(url.host, url.port)
|
105
|
+
con.use_ssl=true
|
106
|
+
con.verify_mode=OpenSSL::SSL::VERIFY_NONE
|
107
|
+
end
|
108
|
+
con
|
109
|
+
end
|
110
|
+
|
111
|
+
def responseParser resp
|
112
|
+
if resp == Net::HTTPSuccess || Net::HTTPOK
|
113
|
+
rawData = resp.body
|
114
|
+
if rawData.length>=2
|
115
|
+
rBody = JSON.parse(rawData)
|
116
|
+
result = rBody["result"]
|
117
|
+
data = rBody["data"]
|
118
|
+
if !@obj.util.getBooleanValue result
|
119
|
+
if data!=nil
|
120
|
+
if data.has_key?("exception")
|
121
|
+
raise Exception.new("Exception from server - "+data["exception"])
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
if data!=nil && data.has_key?(@obj.constants.response_code)
|
127
|
+
|
128
|
+
srCode = data[@obj.constants.response_code]
|
129
|
+
response_action srCode
|
130
|
+
end
|
131
|
+
return data
|
132
|
+
end
|
133
|
+
return rawData
|
134
|
+
else
|
135
|
+
raise Exception.new("Http Connection Response Error #{resp.to_s}")
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
|
141
|
+
def response_action rCode
|
142
|
+
case rCode
|
143
|
+
when @obj.constants.licence_expired then
|
144
|
+
@obj.log.info "License Expired. Going to shutdown"
|
145
|
+
raise Exception.new("License Expired. Going to shutdown")
|
146
|
+
when @obj.constants.licence_exceeds then
|
147
|
+
@obj.log.info "License Exceeds. Going to shutdown"
|
148
|
+
raise Exception.new("License Exceeds. Going to shutdown")
|
149
|
+
when @obj.constants.delete_agent then
|
150
|
+
@obj.log.info "Action from Server - Delete the Agent. Going to shutdown and remove the Agent"
|
151
|
+
deleteAgent
|
152
|
+
raise Exception.new("Action from Server - Delete the Agent. Going to shutdown and remove the Agent")
|
153
|
+
when @obj.constants.unmanage_agent then
|
154
|
+
@obj.log.info "Action from Server - Unmanage the Agent. Going to Stop the DC - Disabling the Agent"
|
155
|
+
unManage
|
156
|
+
when @obj.constants.manage_agent then
|
157
|
+
@obj.log.info "Action from Server - Manage the Agent. Going to Sart the DC - Enabling the Agent"
|
158
|
+
manage
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def unManage
|
163
|
+
@obj.instrumenter.doUnSubscribe
|
164
|
+
@obj.instrumenter =nil
|
165
|
+
@obj.instrumenter = ManageEngine::APMInstrumenter.new
|
166
|
+
uManage = Hash.new
|
167
|
+
uManage["agent.id"]=@obj.config.instance_id
|
168
|
+
uManage["agent.enabled"]=false
|
169
|
+
@obj.config.updateAgentInfoFile uManage
|
170
|
+
end
|
171
|
+
|
172
|
+
def manage
|
173
|
+
@obj.instrumenter.doSubscribe
|
174
|
+
uManage = Hash.new
|
175
|
+
uManage["agent.id"]=@obj.config.instance_id
|
176
|
+
uManage["agent.enabled"]=true
|
177
|
+
@obj.config.updateAgentInfoFile uManage
|
178
|
+
end
|
179
|
+
|
180
|
+
def deleteAgent
|
181
|
+
@obj.instrumenter.doUnSubscribe
|
182
|
+
@obj.instrumenter =nil
|
183
|
+
uManage = Hash.new
|
184
|
+
uManage["agent.id"]=@obj.config.instance_id
|
185
|
+
uManage["agent.enabled"]=false
|
186
|
+
@obj.config.updateAgentInfoFile uManage
|
187
|
+
begin
|
188
|
+
File.delete(@obj.constants.agent_conf)
|
189
|
+
rescue Exceptione=>e
|
190
|
+
@obj.log.logException "#{e.message}",e
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
end#c
|
195
|
+
end#m
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'agent/am_objectholder'
|
2
|
+
@obj = ManageEngine::APMObjectHolder.instance
|
3
|
+
class Class
|
4
|
+
alias old_new new
|
5
|
+
def new(*args, &block)
|
6
|
+
result =nil;
|
7
|
+
begin
|
8
|
+
if(block==nil || block=="")
|
9
|
+
result = old_new(*args)
|
10
|
+
elsif
|
11
|
+
result = old_new(*args,&block)
|
12
|
+
end
|
13
|
+
rescue Excetion=>exe
|
14
|
+
raise exe
|
15
|
+
result = self
|
16
|
+
end
|
17
|
+
me_apm_injector(self,result)
|
18
|
+
|
19
|
+
return result
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def me_apm_injector(s,result)
|
24
|
+
begin
|
25
|
+
if(ManageEngine::APMObjectHolder.instance.config.include_packages.index(s.name)!=nil)
|
26
|
+
ms =s.instance_methods(false)
|
27
|
+
cms = s.methods(false)
|
28
|
+
begin
|
29
|
+
ms.each do |m|
|
30
|
+
if( m.to_s.index("APMTEST"))
|
31
|
+
return;
|
32
|
+
end
|
33
|
+
end
|
34
|
+
cms.each do |m|
|
35
|
+
if( m.to_s.index("APMTEST"))
|
36
|
+
return;
|
37
|
+
end
|
38
|
+
end
|
39
|
+
rescue Exception=>e
|
40
|
+
return;
|
41
|
+
end
|
42
|
+
ManageEngine::APMObjectHolder.instance.log.debug "Injection Method : #{ms} "
|
43
|
+
ManageEngine::APMObjectHolder.instance.log.debug "Injection Class Method : #{cms} "
|
44
|
+
ms.each do |m|
|
45
|
+
mn = m.to_s
|
46
|
+
#ManageEngine::APMObjectHolder.instance.log.info "ManageEngine Monitor Method : #{s.name} # #{m.to_s}"
|
47
|
+
omn = "APMTEST"+mn+"APMTEST"
|
48
|
+
s.class_eval %{
|
49
|
+
alias_method :#{omn}, :#{mn}
|
50
|
+
def #{mn} *args, &block
|
51
|
+
begin
|
52
|
+
ActiveSupport::Notifications.instrument("apm.methodstart", {:method=>"#{mn}",:args=>args})
|
53
|
+
res = #{omn} *args, &block
|
54
|
+
ActiveSupport::Notifications.instrument("apm.methodend", {:method=>"#{mn}",:args=>args})
|
55
|
+
return res
|
56
|
+
rescue Exception => exe
|
57
|
+
puts "error in calling method"
|
58
|
+
raise exe
|
59
|
+
ensure
|
60
|
+
end
|
61
|
+
end
|
62
|
+
}
|
63
|
+
end#do
|
64
|
+
default_methods = Array.new
|
65
|
+
default_methods.push("_helpers");
|
66
|
+
default_methods.push("middleware_stack");
|
67
|
+
default_methods.push("helpers_path");
|
68
|
+
default_methods.push("_wrapper_options");
|
69
|
+
cms.each do |m|
|
70
|
+
if(default_methods.index(m.to_s)==nil)
|
71
|
+
mn = m.to_s
|
72
|
+
#ManageEngine::APMObjectHolder.instance.log.debug "ManageEngine Monitor Singleton Method : #{s.name} ---> #{m.to_s}"
|
73
|
+
omn = "APMTEST"+mn+"APMTEST"
|
74
|
+
s.instance_eval %{
|
75
|
+
class << self
|
76
|
+
alias_method :#{omn}, :#{mn}
|
77
|
+
end
|
78
|
+
def self.#{mn} *args, &block
|
79
|
+
begin
|
80
|
+
ActiveSupport::Notifications.instrument("apm.methodstart", {:method=>"#{mn}",:args=>args})
|
81
|
+
res = #{omn} *args, &block
|
82
|
+
ActiveSupport::Notifications.instrument("apm.methodend", {:method=>"#{mn}",:args=>args})
|
83
|
+
return res
|
84
|
+
rescue Exception=>exe
|
85
|
+
puts "Instrument : error in calling class method"
|
86
|
+
raise exe
|
87
|
+
ensure
|
88
|
+
end
|
89
|
+
end
|
90
|
+
}
|
91
|
+
end
|
92
|
+
end#do
|
93
|
+
end#if
|
94
|
+
rescue Exception=>e
|
95
|
+
puts "Exception in instrument : #{e}"
|
96
|
+
ensure
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'agent/am_objectholder'
|
2
|
+
require 'socket'
|
3
|
+
module ManageEngine
|
4
|
+
class APMInstrumenter
|
5
|
+
@t =nil;
|
6
|
+
def initialize
|
7
|
+
@obj=ManageEngine::APMObjectHolder.instance
|
8
|
+
end
|
9
|
+
|
10
|
+
def doSubscribe
|
11
|
+
@obj=ManageEngine::APMObjectHolder.instance
|
12
|
+
@obj.log.debug "[ instrumenter ] [ Subscriber for Agent ]"
|
13
|
+
@subscriber = ActiveSupport::Notifications.subscribe do |name, start, finish, id, payload|
|
14
|
+
if(ManageEngine::APMObjectHolder.instance.config.agent_enabled)
|
15
|
+
rt = (finish-start).to_i
|
16
|
+
ManageEngine::APMWorker.getInstance.start
|
17
|
+
ManageEngine::APMObjectHolder.instance.log.debug "[ Notifications for Agent ] #{Thread.current} #{id} #{name} - #{rt} - #{payload}"
|
18
|
+
trace= caller;
|
19
|
+
id = "#{Thread.current}"
|
20
|
+
stats = Hash.new
|
21
|
+
stats["name"] = name;
|
22
|
+
stats["start"] = start.to_f * 1000;
|
23
|
+
stats["end"] = finish.to_f * 1000;
|
24
|
+
stats["id"] = id;
|
25
|
+
stats["payload"] = payload;
|
26
|
+
if (name=="sql.active_record" && (finish-start)>=(ManageEngine::APMObjectHolder.instance.config.sql_trace_t * 1000 ).to_i)
|
27
|
+
stats["trace"] = trace;
|
28
|
+
end
|
29
|
+
stats["ctime"] =ManageEngine::APMObjectHolder.instance.util.currenttimemillis;
|
30
|
+
ManageEngine::APMObjectHolder.instance.collector.updateTransaction(id,stats);
|
31
|
+
else
|
32
|
+
ActiveSupport::Notifications.unsubscribe @subscriber
|
33
|
+
@obj.log.info "[ instrumenter ] [ RETURNING NO METRICS] "
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def doUnSubscribe
|
39
|
+
ActiveSupport::Notifications.unsubscribe @subscriber
|
40
|
+
end
|
41
|
+
|
42
|
+
end #class
|
43
|
+
end#module
|