apminsight 0.0.3 → 1.8.8
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/Rakefile +4 -4
- data/VERSION +1 -1
- data/apm-agent.gemspec +64 -0
- data/conf/apminsight.conf +15 -24
- data/lib/agent/am_objectholder.rb +25 -19
- data/lib/agent/api/custom_tracker.rb +79 -0
- data/lib/agent/configuration/am_configuration.rb +306 -43
- data/lib/agent/handler/custom_api_handler.rb +40 -0
- data/lib/agent/handler/sequence_book.rb +125 -0
- data/lib/agent/handler/tracker_handler.rb +58 -0
- data/lib/agent/logging/am_logger.rb +21 -12
- data/lib/agent/metrics/am_metricsformatter.rb +117 -59
- data/lib/agent/metrics/am_metricsparser.rb +195 -468
- data/lib/agent/metrics/am_metricstore.rb +7 -6
- data/lib/agent/metrics/exception_record.rb +24 -0
- data/lib/agent/server/am_agent.rb +59 -21
- data/lib/agent/server/am_connector.rb +66 -22
- data/lib/agent/server/instrument/action_view.rb +64 -0
- data/lib/agent/server/instrument/active_record.rb +52 -0
- data/lib/agent/server/instrument/am_apm.rb +107 -97
- data/lib/agent/server/instrument/am_instrumenter.rb +54 -42
- data/lib/agent/server/instrument/environment.rb +42 -0
- data/lib/agent/server/instrument/rails.rb +56 -0
- data/lib/agent/server/instrument/sinatra.rb +97 -0
- data/lib/agent/server/worker/am_worker.rb +93 -49
- data/lib/agent/trackers/database_tracker.rb +107 -0
- data/lib/agent/trackers/default_tracker.rb +62 -0
- data/lib/agent/trackers/root_tracker.rb +43 -0
- data/lib/agent/util/am_constants.rb +57 -8
- data/lib/agent/util/am_util.rb +76 -14
- data/lib/agent/util/transaction_util.rb +35 -0
- data/lib/agent/version.rb +13 -0
- data/lib/apminsight.rb +4 -1
- metadata +115 -79
@@ -1,14 +1,15 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'json'
|
3
3
|
require 'socket'
|
4
|
-
require '
|
4
|
+
require 'net/http'
|
5
5
|
require 'agent/am_objectholder'
|
6
|
+
require 'agent/version'
|
6
7
|
|
7
8
|
module ManageEngine
|
8
9
|
class APMConfig
|
9
|
-
attr_reader :agenthost,:agentport,:instance_id,:alreadyconnected,:apmhost,:apmport
|
10
|
-
attr_reader :appname,:proxyneeded, :apdex_t, :trans_trace, :trans_trace_t, :sql_capture, :sql_capture_params, :sql_trace_t,:proxy_user,:proxy_pass
|
11
|
-
attr_reader :proxy_host,:proxy_port ,:is_secured, :logs_dir ,:connection_retry,:agent_enabled,:connect_interval,:db_operations,:
|
10
|
+
attr_reader :agenthost,:agentport,:instance_id,:alreadyconnected,:apmhost,:apmport,:license_key,:site24x7, :site24x7url, :hostType,:delayedStart
|
11
|
+
attr_reader :appname,:proxyneeded, :apdex_t, :trans_trace, :trans_trace_t, :sql_capture, :sql_capture_params, :sql_trace_t,:proxy_user,:proxy_pass, :metric_overflow_t, :trace_overflow_t, :dbmetric_overflow_t
|
12
|
+
attr_reader :proxy_host,:proxy_port ,:is_secured, :logs_dir ,:connection_retry,:agent_enabled,:connect_interval,:db_operations,:txn_skip_listen, :url_merge_pattern
|
12
13
|
attr_accessor :app_db,:app_dispatcher,:lastupdatedtime
|
13
14
|
def initialize
|
14
15
|
@obj = ManageEngine::APMObjectHolder.instance
|
@@ -21,19 +22,41 @@ module ManageEngine
|
|
21
22
|
@instance_id = 0
|
22
23
|
@agent_enabled = false
|
23
24
|
@alreadyconnected = checkAgentInfo
|
25
|
+
@site24x7 = checkLicenseFile
|
26
|
+
if (@site24x7)
|
27
|
+
@site24x7url = @license_key.start_with?('eu_') ? @obj.constants.site24x7EUurl :
|
28
|
+
@license_key.start_with?('cn_') ? @obj.constants.site24x7CNurl :
|
29
|
+
@license_key.start_with?('au_') ? @obj.constants.site24x7AUurl :
|
30
|
+
@license_key.start_with?('in_') ? @obj.constants.site24x7INurl :
|
31
|
+
@license_key.start_with?('gd_') ? @obj.constants.site24x7GDurl :
|
32
|
+
@license_key.start_with?('jp_') ? @obj.constants.site24x7JPurl :
|
33
|
+
@license_key.start_with?('gd_') ? @obj.constants.site24x7GDurl :
|
34
|
+
@license_key.start_with?('ca_') ? @obj.constants.site24x7CAurl :
|
35
|
+
@license_key.start_with?('sa_') ? @obj.constants.site24x7SAurl :
|
36
|
+
@license_key.start_with?('uk_') ? @obj.constants.site24x7UKurl :
|
37
|
+
@license_key.start_with?('in_hd_') ? @obj.constants.site24x7HDFCurl : @obj.constants.site24x7USurl
|
38
|
+
end
|
24
39
|
@db_operations =["select","insert","update","delete"]
|
25
|
-
|
26
|
-
@
|
27
|
-
@obj.log.
|
28
|
-
@obj.log.
|
29
|
-
@obj.log.
|
30
|
-
@obj.log.
|
31
|
-
|
32
|
-
|
33
|
-
@
|
34
|
-
@obj.log.info "
|
35
|
-
|
36
|
-
@obj.log.
|
40
|
+
urlMergePattern
|
41
|
+
@hostType = getHostType
|
42
|
+
@obj.log.info "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
43
|
+
@obj.log.info "APP HOME #{File.absolute_path(".")} "
|
44
|
+
@obj.log.info "APP HOME #{Dir.pwd} "
|
45
|
+
@obj.log.info "Agent Version : #{ManageEngine::APMInsight::VERSION}"
|
46
|
+
#@obj.log.info "Configuration : "
|
47
|
+
#@obj.log.info "Hostname : #{@agenthost}"
|
48
|
+
@obj.log.info "Host Type: #{@hostType}"
|
49
|
+
@obj.log.info "Agent Already Connected : #{@alreadyconnected}"
|
50
|
+
@obj.log.info "Agent Enabled : #{@agent_enabled}"
|
51
|
+
@obj.log.info "Allowed DB Operations : #{@db_operations}"
|
52
|
+
# @config.each do|key,val|
|
53
|
+
# @obj.log.info "#{key} => #{val}"
|
54
|
+
# end
|
55
|
+
@obj.log.info "URL Merge Patterns"
|
56
|
+
@url_merge_pattern.each do |key, val|
|
57
|
+
@obj.log.info "#{key} => #{val}"
|
58
|
+
end
|
59
|
+
@obj.log.info "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
37
60
|
@app_db="dummydb"
|
38
61
|
@app_dispatcher = getDispatcher
|
39
62
|
@lastupdatedtime=File.mtime(@obj.constants.apm_conf).to_i
|
@@ -41,27 +64,33 @@ module ManageEngine
|
|
41
64
|
|
42
65
|
def configureFile
|
43
66
|
begin
|
44
|
-
|
45
|
-
#gem_conf = File.join(gem_conf, 'lib')
|
46
|
-
gem_conf = File.join(gem_conf, 'conf')
|
47
|
-
gem_conf = File.join(gem_conf, 'apminsight.conf')
|
48
|
-
if(FileTest.exists?(@obj.constants.apm_conf))
|
67
|
+
if(FileTest.exist?(@obj.constants.apm_conf))
|
49
68
|
#conf file exists in APPlication Home
|
50
|
-
@obj.log.debug "Config File
|
69
|
+
@obj.log.debug "Config File Exists. It is read from #{@obj.constants.apm_conf}"
|
51
70
|
@config = @obj.util.readProperties(@obj.constants.apm_conf)
|
71
|
+
secureConfFile "#{@obj.constants.apm_conf}"
|
52
72
|
else
|
73
|
+
gemSpecs = Gem.loaded_specs[@obj.constants.s247_apm_gem]
|
74
|
+
if (gemSpecs == nil)
|
75
|
+
gemSpecs = Gem.loaded_specs[@obj.constants.apm_gem]
|
76
|
+
end
|
77
|
+
gem_conf = gemSpecs.full_gem_path
|
78
|
+
#gem_conf = File.join(gem_conf, 'lib')
|
79
|
+
gem_conf = File.join(gem_conf, 'conf')
|
80
|
+
gem_conf = File.join(gem_conf, 'apminsight.conf')
|
53
81
|
#conf file not exists in APPlications Home. So 1. copy it for gem locations
|
54
82
|
if @obj.util.copyFiles gem_conf,@obj.constants.apm_conf
|
55
83
|
#copied sucessfully
|
56
|
-
@obj.log.
|
84
|
+
@obj.log.info "Config File copied to application home directory. It is read from #{@obj.constants.apm_conf}"
|
57
85
|
@config = @obj.util.readProperties(@obj.constants.apm_conf)
|
86
|
+
secureConfFile "#{@obj.constants.apm_conf}"
|
58
87
|
else
|
59
88
|
#Problem in copying, so reading props from Conf file in Gem Location
|
60
|
-
@obj.log.
|
89
|
+
@obj.log.warn "Config File not copied. It is read from #{gem_conf}"
|
61
90
|
@config = @obj.util.readProperties(gem_conf)
|
91
|
+
secureConfFile gem_conf
|
62
92
|
end
|
63
93
|
end
|
64
|
-
|
65
94
|
rescue Exception=>e
|
66
95
|
@obj.log.info "[Exception] Problem in Reading Configuration File : \n File : #{@obj.constants.apm_conf}"
|
67
96
|
@obj.log.logException "#{e.message}",e
|
@@ -70,11 +99,29 @@ module ManageEngine
|
|
70
99
|
end
|
71
100
|
end
|
72
101
|
|
102
|
+
def secureConfFile(file)
|
103
|
+
begin
|
104
|
+
File.chmod(0600, file)
|
105
|
+
rescue Exception => e
|
106
|
+
@obj.log.warn "Unable to secure the conf file #{file}"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
73
110
|
def checkAgentInfo
|
74
|
-
if FileTest.
|
111
|
+
if FileTest.exist?(@obj.constants.agent_conf)
|
75
112
|
@obj.log.debug "Status : Agent Already Connected"
|
76
113
|
props = @obj.util.readProperties(@obj.constants.agent_conf)
|
77
|
-
|
114
|
+
instance_id = props["agent.id"]
|
115
|
+
|
116
|
+
if (instance_id == nil || instance_id == "")
|
117
|
+
# If instance id is not found or empty, it means the apminsight.info is being modified by user
|
118
|
+
# Ignore all its entry
|
119
|
+
@obj.log.warn "File: #{@obj.constants.agent_conf} is corrupted. Agent will continue ignoring these values."
|
120
|
+
return false
|
121
|
+
else
|
122
|
+
@instance_id = instance_id
|
123
|
+
end
|
124
|
+
|
78
125
|
@agent_enabled= @obj.util.getBooleanValue props["agent.enabled"]
|
79
126
|
true
|
80
127
|
else
|
@@ -83,10 +130,35 @@ module ManageEngine
|
|
83
130
|
end
|
84
131
|
end
|
85
132
|
|
133
|
+
def checkLicenseFile
|
134
|
+
@obj.constants.setLicenseKey @license_key
|
135
|
+
if(@license_key.start_with?('APMI_'))
|
136
|
+
@obj.log.info "Connecting to App Manager"
|
137
|
+
false
|
138
|
+
else
|
139
|
+
@obj.log.info "Connecting to Site24x7"
|
140
|
+
true
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def urlMergePattern
|
145
|
+
@url_merge_pattern = Hash.new
|
146
|
+
begin
|
147
|
+
if (FileTest.exist?(@obj.constants.mergepattern_conf))
|
148
|
+
@url_merge_pattern=@obj.util.readProperties(@obj.constants.mergepattern_conf)
|
149
|
+
end
|
150
|
+
rescue Exception => e
|
151
|
+
@obj.log.info "[Exception] Problem in Reading Configuration File : \n File : #{@obj.constants.mergepattern_conf}"
|
152
|
+
@obj.log.logException "#{e.message}",e
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
86
156
|
def updateAgentInfoFile(props)
|
87
157
|
@instance_id = props["agent.id"]
|
88
158
|
@agent_enabled= @obj.util.getBooleanValue props["agent.enabled"]
|
89
159
|
@obj.util.writeProperties(@obj.constants.agent_conf,props)
|
160
|
+
|
161
|
+
secureConfFile(@obj.constants.agent_conf)
|
90
162
|
end
|
91
163
|
|
92
164
|
def initValues
|
@@ -102,18 +174,31 @@ module ManageEngine
|
|
102
174
|
@connection_retry = 0
|
103
175
|
@connect_interval = 60
|
104
176
|
@apdex_t=0.5
|
105
|
-
@
|
177
|
+
@txn_skip_listen=Array.new
|
106
178
|
@trans_trace_t=2
|
107
179
|
@sql_trace_t=3
|
180
|
+
@metric_overflow_t=250
|
181
|
+
@dbmetric_overflow_t=500
|
182
|
+
@trace_overflow_t=30
|
183
|
+
@site24x7url = @obj.constants.site24x7USurl #default agent communication URL
|
184
|
+
@delayedStart = false
|
108
185
|
end
|
109
186
|
|
110
187
|
def assignConfig
|
111
188
|
initValues
|
112
189
|
@config.each do |key,value|
|
190
|
+
value = checkAndGetEnvValue(value)
|
113
191
|
case key
|
114
192
|
when "application.name" then @appname=value
|
193
|
+
if (ENV.has_key?('APM_APPLICATION_NAME'))
|
194
|
+
@appname = ENV['APM_APPLICATION_NAME']
|
195
|
+
end
|
115
196
|
when "apm.host" then @apmhost=value
|
116
197
|
when "apm.port" then @apmport=isInteger(@apmport,value)
|
198
|
+
when "license.key" then @license_key=value
|
199
|
+
if (@license_key.empty? && ENV.has_key?('S247_LICENSE_KEY'))
|
200
|
+
@license_key = ENV['S247_LICENSE_KEY']
|
201
|
+
end
|
117
202
|
when "behind.proxy" then @proxyneeded=@obj.util.getBooleanValue value
|
118
203
|
when "agent.server.port" then @agentport=isInteger(@agentport,value)
|
119
204
|
when "apdex.threshold" then @apdex_t=isFloat(@apdex_t,value)
|
@@ -123,46 +208,184 @@ module ManageEngine
|
|
123
208
|
when "transaction.trace.sql.parametrize" then @sql_capture_params=@obj.util.getBooleanValue value
|
124
209
|
when "transaction.trace.sql.stacktrace.threshold" then @sql_trace_t=isFloat(@sql_trace_t,value)
|
125
210
|
when "proxy.server.host" then @proxy_host=value
|
126
|
-
when "proxy.server.port" then @proxy_port=value
|
211
|
+
when "proxy.server.port" then @proxy_port=isInteger(@proxy_port,value)
|
127
212
|
when "proxy.auth.username" then @proxy_user=value
|
128
|
-
when "proxy.auth.password" then @proxy_pass
|
129
|
-
|
213
|
+
when "proxy.auth.password" then @proxy_pass=@obj.util.decrypt value, @license_key
|
214
|
+
if (@proxy_pass == nil)
|
215
|
+
@proxy_pass = value
|
216
|
+
end
|
217
|
+
when "apm.protocol.https" then @is_secured=@obj.util.getBooleanValue value
|
130
218
|
when "apminsight.log.dir" then @logs_dir=value
|
219
|
+
when "apminsight.log.level" then @obj.log.setLevel value
|
131
220
|
when "agent.connection.retry" then @connection_retry=value #Not in Conf - yet to come
|
132
|
-
|
133
|
-
|
221
|
+
when "agent.polling.interval" then @connect_interval=isInteger(@connect_interval, value)#Not in Conf - yet to come
|
222
|
+
when "transaction.skip.listening" then @txn_skip_listen=@obj.util.getArray value.gsub("\s", ""),","
|
223
|
+
when "metricstore.metric.bucket.size" then @metric_overflow_t = isInteger(@metric_overflow_t, value)
|
224
|
+
when "metricstore.dbmetric.bucket.size" then @dbmetric_overflow_t = isInteger(@dbmetric_overflow_t, value)
|
225
|
+
when "transaction.tracestore.size" then @trace_overflow_t = isInteger(@trace_overflow_t, value)
|
226
|
+
when "agent.delay.start" then @delayedStart=@obj.util.getBooleanValue value
|
134
227
|
end
|
135
228
|
end
|
229
|
+
store_encrypted_data(@config)
|
230
|
+
end
|
231
|
+
|
232
|
+
#Checks whether the given value is Environment Variable
|
233
|
+
def checkAndGetEnvValue(data)
|
234
|
+
begin
|
235
|
+
value = "#{data}"[/\{(.*)\}/,1]
|
236
|
+
if (value != nil && ENV.has_key?(value))
|
237
|
+
return data.gsub(/\{.*\}/, ENV[value])
|
238
|
+
end
|
239
|
+
rescue Exception=>e
|
240
|
+
end
|
241
|
+
return data
|
136
242
|
end
|
137
243
|
|
244
|
+
def store_encrypted_data config
|
245
|
+
data = config["proxy.auth.password"]
|
246
|
+
if (data != nil && @obj.util.decrypt(data, @license_key) == nil) # checking whether data is already encrypted
|
247
|
+
begin
|
248
|
+
file_contents = ""
|
249
|
+
conf_file = File.open(@obj.constants.apm_conf, 'r')
|
250
|
+
conf_file.read.each_line do |line|
|
251
|
+
if line.start_with?("proxy.auth.password")
|
252
|
+
file_contents += "proxy.auth.password=" + @obj.util.encrypt(config["proxy.auth.password"], @license_key)
|
253
|
+
else
|
254
|
+
file_contents += line
|
255
|
+
end
|
256
|
+
#file_contents += "\n"
|
257
|
+
end #end of do read loop
|
258
|
+
conf_file.close
|
259
|
+
conf_file = File.open(@obj.constants.apm_conf, "w+")
|
260
|
+
conf_file.puts file_contents
|
261
|
+
conf_file.close
|
262
|
+
file_contents = nil # clearing memory
|
263
|
+
rescue Exception=>e
|
264
|
+
@obj.log.logException "Error while encrypting file", e
|
265
|
+
end
|
266
|
+
end # if already encrypted
|
267
|
+
end
|
268
|
+
|
269
|
+
def getHostType
|
270
|
+
begin
|
271
|
+
# Check for AWS environment
|
272
|
+
url = URI.parse('http://169.254.169.254/latest/meta-data/') # AWS metadata url
|
273
|
+
request = Net::HTTP::Get.new(url.path)
|
274
|
+
response = Net::HTTP.start(url.host, url.port, :read_timeout => 2) {|http| http.request(request)}
|
275
|
+
if (response.kind_of? Net::HTTPOK)
|
276
|
+
@hostType = "AWS"
|
277
|
+
return @hostType
|
278
|
+
end
|
279
|
+
rescue Exception => e
|
280
|
+
end
|
281
|
+
|
282
|
+
begin
|
283
|
+
#Check for Azure environment
|
284
|
+
url = URI.parse('http://169.254.169.254/metadata/v1/maintenance') # Azure metadata url
|
285
|
+
request = Net::HTTP::Get.new(url.path)
|
286
|
+
response = Net::HTTP.start(url.host, url.port, :read_timeout => 2) {|http| http.request(request)}
|
287
|
+
if (response.kind_of? Net::HTTPOK)
|
288
|
+
@hostType = "AZURE"
|
289
|
+
return @hostType
|
290
|
+
end
|
291
|
+
rescue Exception => e
|
292
|
+
end
|
293
|
+
|
294
|
+
begin
|
295
|
+
# Check for Heroku env. In the backgroud it is using AWS EC2, hence sending as AWS
|
296
|
+
if (ENV.has_key?('DYNO') || ENV.has_key?('STACK'))
|
297
|
+
@hostType = "AWS"
|
298
|
+
return @hostType
|
299
|
+
end
|
300
|
+
rescue Exception => e
|
301
|
+
end
|
302
|
+
|
303
|
+
@hostType = nil
|
304
|
+
end
|
305
|
+
|
138
306
|
def getAgentInfo
|
139
307
|
data = Hash.new
|
140
308
|
agentdata = Hash.new
|
141
|
-
agentdata = {"application.type"=>"RUBY","application.name"=>@appname,"hostname"=>@agenthost,"port"=>@agentport,"agent.version"=>
|
309
|
+
agentdata = {"application.type"=>"RUBY","application.name"=>@appname,"hostname"=>@agenthost,"port"=>@agentport,"agent.version"=>ManageEngine::APMInsight::MAJOR_VERSION}
|
310
|
+
if (@hostType != nil)
|
311
|
+
agentdata["host.type"]=@hostType
|
312
|
+
end
|
313
|
+
begin
|
314
|
+
fqdn = Addrinfo.getaddrinfo(Socket.gethostname, nil).first.getnameinfo.first
|
315
|
+
if (fqdn != nil)
|
316
|
+
agentdata["fqdn"] = fqdn
|
317
|
+
end
|
318
|
+
rescue Exception=>e
|
319
|
+
@obj.log.warn("Unable to get fqdn value #{e.message}")
|
320
|
+
end
|
142
321
|
data["agent_info"]=agentdata
|
143
322
|
data["environment"]=getEnvData
|
323
|
+
data["custom_config_info"]=getAgentConfigData
|
144
324
|
data
|
145
325
|
end
|
146
326
|
|
147
327
|
def getEnvData
|
148
328
|
env = Hash.new
|
149
329
|
begin
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
330
|
+
env["OS"] = Gem::Platform.local.os
|
331
|
+
env["OS Version"] = Gem::Platform.local.version
|
332
|
+
env["OS Arch"] = Gem::Platform.local.cpu
|
333
|
+
env["Ruby Version"] = "#{RUBY_VERSION}"
|
334
|
+
gemSpecs = Gem.loaded_specs[@obj.constants.s247_apm_gem]
|
335
|
+
if (gemSpecs == nil)
|
336
|
+
gemSpecs = Gem.loaded_specs[@obj.constants.apm_gem]
|
337
|
+
end
|
338
|
+
if (gemSpecs != nil)
|
339
|
+
env["Agent Installed Path"] = gemSpecs.full_gem_path
|
340
|
+
end
|
341
|
+
|
342
|
+
# ENV.to_hash.each do |key, value|
|
343
|
+
# env[key] = value
|
344
|
+
# end
|
345
|
+
env["Application Path"] = "#{Dir.pwd}"
|
154
346
|
rescue Exception=>e
|
347
|
+
@obj.log.warn "Error in capturing env data. #{e.message}"
|
155
348
|
end
|
156
349
|
env
|
157
350
|
end
|
158
351
|
|
352
|
+
def getAgentConfigData
|
353
|
+
agentconfig = Hash.new
|
354
|
+
agentconfig["last.modified.time"]=@lastupdatedtime*1000
|
355
|
+
agentconfig["apdex.threshold"]=@apdex_t
|
356
|
+
agentconfig["sql.capture.enabled"]=0
|
357
|
+
if @sql_capture
|
358
|
+
agentconfig["sql.capture.enabled"]=1
|
359
|
+
end
|
360
|
+
agentconfig["transaction.trace.enabled"]=0
|
361
|
+
if @trans_trace
|
362
|
+
agentconfig["transaction.trace.enabled"]=1
|
363
|
+
end
|
364
|
+
agentconfig["transaction.trace.threshold"]=@trans_trace_t
|
365
|
+
agentconfig["transaction.trace.sql.parametrize"]=0
|
366
|
+
if @sql_capture_params
|
367
|
+
agentconfig["transaction.trace.sql.parametrize"]=1
|
368
|
+
end
|
369
|
+
agentconfig["transaction.trace.sql.stacktrace.threshold"]=@sql_trace_t
|
370
|
+
agentconfig["transaction.tracking.request.interval"]=1
|
371
|
+
agentconfig
|
372
|
+
end
|
159
373
|
|
160
374
|
def getDispatcher
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
375
|
+
|
376
|
+
@obj.log.info "Server: #{ENV['SERVER_SOFTWARE']}"
|
377
|
+
|
378
|
+
dispatcher = "unknown"
|
379
|
+
if defined?(PhusionPassenger) then
|
380
|
+
dispatcher = "passenger"
|
381
|
+
end
|
382
|
+
if defined?(Unicorn) then
|
383
|
+
dispatcher = "unicorn"
|
384
|
+
end
|
385
|
+
if defined?(Rainbows) then
|
386
|
+
dispatcher = "rainbows"
|
387
|
+
end
|
388
|
+
dispatcher
|
166
389
|
end
|
167
390
|
|
168
391
|
def isInteger default,value
|
@@ -184,6 +407,46 @@ module ManageEngine
|
|
184
407
|
end
|
185
408
|
end
|
186
409
|
|
410
|
+
def update_config configInfo
|
411
|
+
filepath = @obj.constants.apm_conf
|
412
|
+
f = "apminsight.conf.new"
|
413
|
+
begin
|
414
|
+
propsFile=File.open(filepath, 'r')
|
415
|
+
file = File.new(f,"w+")
|
416
|
+
propsFile.read.each_line do |line|
|
417
|
+
line.strip!
|
418
|
+
if (line[0] != ?# and line[0] != ?=)
|
419
|
+
i = line.index('=')
|
420
|
+
if (i)
|
421
|
+
key1 = line[0..i - 1].strip
|
422
|
+
if configInfo.has_key?(key1)
|
423
|
+
file.puts "#{key1}=#{configInfo[key1]}\n"
|
424
|
+
else
|
425
|
+
file.puts "#{line}\n"
|
426
|
+
end
|
427
|
+
else
|
428
|
+
file.puts "#{line}\n"
|
429
|
+
end
|
430
|
+
else
|
431
|
+
file.puts "#{line}\n"
|
432
|
+
end
|
433
|
+
end
|
434
|
+
rescue Exception=>e
|
435
|
+
@obj.log.info "Problem in Reading / Writing Property File : #{e.message} "
|
436
|
+
@obj.log.error "#{e.backtrace}"
|
437
|
+
ensure
|
438
|
+
propsFile.close
|
439
|
+
file.close
|
440
|
+
end
|
441
|
+
res = @obj.util.copyFiles f, filepath
|
442
|
+
if res
|
443
|
+
@obj.log.info "copyFiles result = #{res}"
|
444
|
+
#delete apminsight.conf.new has to be done
|
445
|
+
end
|
446
|
+
configureFile
|
447
|
+
assignConfig
|
448
|
+
end
|
449
|
+
|
187
450
|
|
188
451
|
end#c
|
189
452
|
end#m
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'agent/handler/sequence_book'
|
2
|
+
|
3
|
+
module APMInsight
|
4
|
+
module API
|
5
|
+
class CustomAPIHandler
|
6
|
+
|
7
|
+
## Create tracker for custom instrumented methods and send them to tracker handler
|
8
|
+
def self.invokeTracker name
|
9
|
+
begin
|
10
|
+
# @obj = ManageEngine::APMObjectHolder.instance
|
11
|
+
|
12
|
+
if Thread.current[:apminsight] != nil
|
13
|
+
tracker = ManageEngine::Tracker::DefaultTracker.new(name)
|
14
|
+
tracker = ManageEngine::Agent::TrackerHandler.invokeTracker(tracker)
|
15
|
+
return tracker
|
16
|
+
end
|
17
|
+
|
18
|
+
return nil
|
19
|
+
rescue Exception=>e
|
20
|
+
return nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.exitTracker tracker
|
25
|
+
if tracker != nil
|
26
|
+
tracker.finish
|
27
|
+
ManageEngine::Agent::TrackerHandler.exitTracker(tracker)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.track_exception exception
|
32
|
+
seqBook = Thread.current[:apminsight]
|
33
|
+
if seqBook != nil
|
34
|
+
seqBook.addExceptionInfo exception
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end #class CustomAPIhandler
|
39
|
+
end #module API
|
40
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'agent/metrics/exception_record'
|
2
|
+
|
3
|
+
module APMInsight
|
4
|
+
module Agent
|
5
|
+
class SequenceBook
|
6
|
+
attr_reader :openTracker, :closedTracker, :rootTracker, :trackerCount, :closedTrackerCount, :exceptionBag, :listenFlag
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@rootTracker = createDummyTracker()
|
10
|
+
@closedTracker = @rootTracker
|
11
|
+
@openTracker = nil
|
12
|
+
|
13
|
+
@trackerCount = 0
|
14
|
+
@closedTrackerCount = 0
|
15
|
+
@listenFlag = -1
|
16
|
+
# @exceptionBag = Array.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def attachTracker tracker
|
20
|
+
if tracker == nil
|
21
|
+
return nil
|
22
|
+
end
|
23
|
+
|
24
|
+
# If RootTracker is not set, check type and set
|
25
|
+
if @rootTracker == @closedTracker
|
26
|
+
if !tracker.is_a?(ManageEngine::Tracker::RootTracker)
|
27
|
+
closeSequence()
|
28
|
+
return nil
|
29
|
+
end
|
30
|
+
@rootTracker = tracker
|
31
|
+
|
32
|
+
updateListenFlag()
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
# Attach tracker as Sibling or Child and set nominee
|
37
|
+
if @closedTracker != nil
|
38
|
+
tracker.sibling = @closedTracker
|
39
|
+
@closedTracker.sibling = tracker # Nominee - if dropped/corrupted, defaults to this tracker
|
40
|
+
@openTracker = tracker
|
41
|
+
@closedTracker = nil
|
42
|
+
else
|
43
|
+
if tracker.equal?(@openTracker)
|
44
|
+
return nil
|
45
|
+
end
|
46
|
+
|
47
|
+
@openTracker.child = tracker
|
48
|
+
tracker.sibling = @openTracker
|
49
|
+
@openTracker = tracker
|
50
|
+
end
|
51
|
+
|
52
|
+
checkAndArrestSequence()
|
53
|
+
|
54
|
+
return tracker
|
55
|
+
end
|
56
|
+
|
57
|
+
def closeTracker tracker
|
58
|
+
@closedTrackerCount += 1
|
59
|
+
@closedTracker = tracker
|
60
|
+
tracker.sibling = nil
|
61
|
+
@openTracker = nil
|
62
|
+
|
63
|
+
# Marks end of transaction
|
64
|
+
if @rootTracker == tracker
|
65
|
+
if @listenFlag < 1 || (@listenFlag >= 1 && @trackerCount > 1)
|
66
|
+
# if some trackers are not closed, while processing the metrics, it may go into infinite loop
|
67
|
+
if (@closedTrackerCount - @trackerCount) == 0
|
68
|
+
sequenceBag = Hash.new
|
69
|
+
sequenceBag["roottracker"] = @rootTracker
|
70
|
+
sequenceBag["exceptions"] = @exceptionBag
|
71
|
+
|
72
|
+
ManageEngine::APMObjectHolder.instance.collector.updateTransaction(@rootTracker.url, sequenceBag)
|
73
|
+
else
|
74
|
+
ManageEngine::APMObjectHolder.instance.log.warn "Some trackers are not closed, dropping the metrics for #{@rootTracker.url}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
closeSequence()
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def closeSequence
|
82
|
+
@rootTracker = nil
|
83
|
+
@openTracker = @closedTracker = nil
|
84
|
+
@trackerCount = 0
|
85
|
+
@closedTrackerCount = 0
|
86
|
+
Thread.current[:apminsight] = nil
|
87
|
+
end
|
88
|
+
|
89
|
+
def addExceptionInfo(exception)
|
90
|
+
begin
|
91
|
+
if @exceptionBag == nil
|
92
|
+
@exceptionBag = Set.new
|
93
|
+
end
|
94
|
+
if (@exceptionBag.size() < 10)
|
95
|
+
exceptionRecord = ::APMInsight::Errors::ExceptionRecord.new(exception)
|
96
|
+
@exceptionBag.add(exceptionRecord)
|
97
|
+
end
|
98
|
+
rescue Exception=>e
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def updateListenFlag
|
103
|
+
if !ManageEngine::APMObjectHolder.instance.txn_util.listen?(@rootTracker.url())
|
104
|
+
@listenFlag = 1
|
105
|
+
end
|
106
|
+
|
107
|
+
## Check for sampling factor & for bg txn chk if enabled
|
108
|
+
end
|
109
|
+
|
110
|
+
def checkAndArrestSequence
|
111
|
+
@trackerCount += 1
|
112
|
+
if @trackerCount == 1000
|
113
|
+
@listenFlag = 1
|
114
|
+
end
|
115
|
+
|
116
|
+
## Can check for timeout
|
117
|
+
end
|
118
|
+
|
119
|
+
def createDummyTracker
|
120
|
+
return ManageEngine::Tracker::DefaultTracker.new("dummy")
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'agent/handler/sequence_book'
|
2
|
+
|
3
|
+
module ManageEngine
|
4
|
+
module Agent
|
5
|
+
class TrackerHandler
|
6
|
+
|
7
|
+
def self.invokeTracker tracker
|
8
|
+
begin
|
9
|
+
@obj = ManageEngine::APMObjectHolder.instance
|
10
|
+
|
11
|
+
if !@obj.config.agent_enabled || tracker == nil
|
12
|
+
return nil
|
13
|
+
end
|
14
|
+
|
15
|
+
seqBook = Thread.current[:apminsight]
|
16
|
+
if seqBook != nil
|
17
|
+
if seqBook.listenFlag == 1
|
18
|
+
return nil
|
19
|
+
end
|
20
|
+
else
|
21
|
+
seqBook = ::APMInsight::Agent::SequenceBook.new
|
22
|
+
Thread.current[:apminsight] = seqBook
|
23
|
+
end
|
24
|
+
|
25
|
+
tracker = seqBook.attachTracker(tracker)
|
26
|
+
|
27
|
+
return tracker
|
28
|
+
rescue Exception=>ex
|
29
|
+
# Logging to be done here, Not sure whether its safe to do
|
30
|
+
if (@obj != nil)
|
31
|
+
@obj.log.logException "[TrackerHandler] Exception occurred at invoketracker.", ex
|
32
|
+
end
|
33
|
+
return nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
# Closes tracker properly and set everything ready to process next tracker
|
39
|
+
# If roottracker closes, sequence book is cleaned and data are push to store
|
40
|
+
def self.exitTracker tracker
|
41
|
+
begin
|
42
|
+
if tracker != nil
|
43
|
+
seqBook = Thread.current[:apminsight]
|
44
|
+
if seqBook != nil
|
45
|
+
seqBook.closeTracker tracker
|
46
|
+
end
|
47
|
+
end
|
48
|
+
rescue Exception=>ex
|
49
|
+
if (@obj != nil)
|
50
|
+
@obj.log.logException "[TrackerHandler] Exception occurred at exittracker.", ex
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end # Class TrackerHandler
|
56
|
+
|
57
|
+
end # module Agent
|
58
|
+
end
|