apminsight 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|