apminsight 1.0.1 → 1.8.6
Sign up to get free protection for your applications and to get access to all the features.
- 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 +284 -41
- 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 +20 -11
- 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 +46 -17
- data/lib/agent/server/am_connector.rb +65 -21
- 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 +53 -8
- data/lib/agent/util/am_util.rb +64 -1
- data/lib/agent/util/transaction_util.rb +35 -0
- data/lib/agent/version.rb +13 -0
- data/lib/apminsight.rb +4 -1
- metadata +114 -76
@@ -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
|
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,31 @@ 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 : @license_key.start_with?('cn_') ? @obj.constants.site24x7CNurl : @license_key.start_with?('au_') ? @obj.constants.site24x7AUurl : @license_key.start_with?('in_') ? @obj.constants.site24x7INurl : @license_key.start_with?('gd_') ? @obj.constants.site24x7GDurl : @license_key.start_with?('jp_') ? @obj.constants.site24x7JPurl : @obj.constants.site24x7USurl
|
28
|
+
end
|
24
29
|
@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.
|
30
|
+
urlMergePattern
|
31
|
+
@hostType = getHostType
|
32
|
+
@obj.log.info "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
33
|
+
@obj.log.info "APP HOME #{File.absolute_path(".")} "
|
34
|
+
@obj.log.info "APP HOME #{Dir.pwd} "
|
35
|
+
@obj.log.info "Agent Version : #{ManageEngine::APMInsight::VERSION}"
|
36
|
+
#@obj.log.info "Configuration : "
|
37
|
+
#@obj.log.info "Hostname : #{@agenthost}"
|
38
|
+
@obj.log.info "Host Type: #{@hostType}"
|
39
|
+
@obj.log.info "Agent Already Connected : #{@alreadyconnected}"
|
40
|
+
@obj.log.info "Agent Enabled : #{@agent_enabled}"
|
41
|
+
@obj.log.info "Allowed DB Operations : #{@db_operations}"
|
42
|
+
# @config.each do|key,val|
|
43
|
+
# @obj.log.info "#{key} => #{val}"
|
44
|
+
# end
|
45
|
+
@obj.log.info "URL Merge Patterns"
|
46
|
+
@url_merge_pattern.each do |key, val|
|
47
|
+
@obj.log.info "#{key} => #{val}"
|
48
|
+
end
|
49
|
+
@obj.log.info "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
37
50
|
@app_db="dummydb"
|
38
51
|
@app_dispatcher = getDispatcher
|
39
52
|
@lastupdatedtime=File.mtime(@obj.constants.apm_conf).to_i
|
@@ -41,27 +54,33 @@ module ManageEngine
|
|
41
54
|
|
42
55
|
def configureFile
|
43
56
|
begin
|
44
|
-
gem_conf = Gem.loaded_specs[@obj.constants.apm_gem].full_gem_path
|
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
57
|
if(FileTest.exists?(@obj.constants.apm_conf))
|
49
58
|
#conf file exists in APPlication Home
|
50
|
-
@obj.log.debug "Config File
|
59
|
+
@obj.log.debug "Config File Exists. It is read from #{@obj.constants.apm_conf}"
|
51
60
|
@config = @obj.util.readProperties(@obj.constants.apm_conf)
|
61
|
+
secureConfFile "#{@obj.constants.apm_conf}"
|
52
62
|
else
|
63
|
+
gemSpecs = Gem.loaded_specs[@obj.constants.s247_apm_gem]
|
64
|
+
if (gemSpecs == nil)
|
65
|
+
gemSpecs = Gem.loaded_specs[@obj.constants.apm_gem]
|
66
|
+
end
|
67
|
+
gem_conf = gemSpecs.full_gem_path
|
68
|
+
#gem_conf = File.join(gem_conf, 'lib')
|
69
|
+
gem_conf = File.join(gem_conf, 'conf')
|
70
|
+
gem_conf = File.join(gem_conf, 'apminsight.conf')
|
53
71
|
#conf file not exists in APPlications Home. So 1. copy it for gem locations
|
54
72
|
if @obj.util.copyFiles gem_conf,@obj.constants.apm_conf
|
55
73
|
#copied sucessfully
|
56
|
-
@obj.log.
|
74
|
+
@obj.log.info "Config File copied to application home directory. It is read from #{@obj.constants.apm_conf}"
|
57
75
|
@config = @obj.util.readProperties(@obj.constants.apm_conf)
|
76
|
+
secureConfFile "#{@obj.constants.apm_conf}"
|
58
77
|
else
|
59
78
|
#Problem in copying, so reading props from Conf file in Gem Location
|
60
|
-
@obj.log.
|
79
|
+
@obj.log.warn "Config File not copied. It is read from #{gem_conf}"
|
61
80
|
@config = @obj.util.readProperties(gem_conf)
|
81
|
+
secureConfFile gem_conf
|
62
82
|
end
|
63
83
|
end
|
64
|
-
|
65
84
|
rescue Exception=>e
|
66
85
|
@obj.log.info "[Exception] Problem in Reading Configuration File : \n File : #{@obj.constants.apm_conf}"
|
67
86
|
@obj.log.logException "#{e.message}",e
|
@@ -70,11 +89,29 @@ module ManageEngine
|
|
70
89
|
end
|
71
90
|
end
|
72
91
|
|
92
|
+
def secureConfFile(file)
|
93
|
+
begin
|
94
|
+
File.chmod(0600, file)
|
95
|
+
rescue Exception => e
|
96
|
+
@obj.log.warn "Unable to secure the conf file #{file}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
73
100
|
def checkAgentInfo
|
74
101
|
if FileTest.exists?(@obj.constants.agent_conf)
|
75
102
|
@obj.log.debug "Status : Agent Already Connected"
|
76
103
|
props = @obj.util.readProperties(@obj.constants.agent_conf)
|
77
|
-
|
104
|
+
instance_id = props["agent.id"]
|
105
|
+
|
106
|
+
if (instance_id == nil || instance_id == "")
|
107
|
+
# If instance id is not found or empty, it means the apminsight.info is being modified by user
|
108
|
+
# Ignore all its entry
|
109
|
+
@obj.log.warn "File: #{@obj.constants.agent_conf} is corrupted. Agent will continue ignoring these values."
|
110
|
+
return false
|
111
|
+
else
|
112
|
+
@instance_id = instance_id
|
113
|
+
end
|
114
|
+
|
78
115
|
@agent_enabled= @obj.util.getBooleanValue props["agent.enabled"]
|
79
116
|
true
|
80
117
|
else
|
@@ -83,10 +120,35 @@ module ManageEngine
|
|
83
120
|
end
|
84
121
|
end
|
85
122
|
|
123
|
+
def checkLicenseFile
|
124
|
+
@obj.constants.setLicenseKey @license_key
|
125
|
+
if(@license_key.start_with?('APMI_'))
|
126
|
+
@obj.log.info "Connecting to App Manager"
|
127
|
+
false
|
128
|
+
else
|
129
|
+
@obj.log.info "Connecting to Site24x7"
|
130
|
+
true
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def urlMergePattern
|
135
|
+
@url_merge_pattern = Hash.new
|
136
|
+
begin
|
137
|
+
if (FileTest.exists?(@obj.constants.mergepattern_conf))
|
138
|
+
@url_merge_pattern=@obj.util.readProperties(@obj.constants.mergepattern_conf)
|
139
|
+
end
|
140
|
+
rescue Exception => e
|
141
|
+
@obj.log.info "[Exception] Problem in Reading Configuration File : \n File : #{@obj.constants.mergepattern_conf}"
|
142
|
+
@obj.log.logException "#{e.message}",e
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
86
146
|
def updateAgentInfoFile(props)
|
87
147
|
@instance_id = props["agent.id"]
|
88
148
|
@agent_enabled= @obj.util.getBooleanValue props["agent.enabled"]
|
89
149
|
@obj.util.writeProperties(@obj.constants.agent_conf,props)
|
150
|
+
|
151
|
+
secureConfFile(@obj.constants.agent_conf)
|
90
152
|
end
|
91
153
|
|
92
154
|
def initValues
|
@@ -102,18 +164,30 @@ module ManageEngine
|
|
102
164
|
@connection_retry = 0
|
103
165
|
@connect_interval = 60
|
104
166
|
@apdex_t=0.5
|
105
|
-
@
|
167
|
+
@txn_skip_listen=Array.new
|
106
168
|
@trans_trace_t=2
|
107
169
|
@sql_trace_t=3
|
170
|
+
@metric_overflow_t=250
|
171
|
+
@dbmetric_overflow_t=500
|
172
|
+
@trace_overflow_t=30
|
173
|
+
@site24x7url = @obj.constants.site24x7USurl #default agent communication URL
|
108
174
|
end
|
109
175
|
|
110
176
|
def assignConfig
|
111
177
|
initValues
|
112
178
|
@config.each do |key,value|
|
179
|
+
value = checkAndGetEnvValue(value)
|
113
180
|
case key
|
114
181
|
when "application.name" then @appname=value
|
182
|
+
if (ENV.has_key?('APM_APPLICATION_NAME'))
|
183
|
+
@appname = ENV['APM_APPLICATION_NAME']
|
184
|
+
end
|
115
185
|
when "apm.host" then @apmhost=value
|
116
186
|
when "apm.port" then @apmport=isInteger(@apmport,value)
|
187
|
+
when "license.key" then @license_key=value
|
188
|
+
if (@license_key.empty? && ENV.has_key?('S247_LICENSE_KEY'))
|
189
|
+
@license_key = ENV['S247_LICENSE_KEY']
|
190
|
+
end
|
117
191
|
when "behind.proxy" then @proxyneeded=@obj.util.getBooleanValue value
|
118
192
|
when "agent.server.port" then @agentport=isInteger(@agentport,value)
|
119
193
|
when "apdex.threshold" then @apdex_t=isFloat(@apdex_t,value)
|
@@ -123,46 +197,175 @@ module ManageEngine
|
|
123
197
|
when "transaction.trace.sql.parametrize" then @sql_capture_params=@obj.util.getBooleanValue value
|
124
198
|
when "transaction.trace.sql.stacktrace.threshold" then @sql_trace_t=isFloat(@sql_trace_t,value)
|
125
199
|
when "proxy.server.host" then @proxy_host=value
|
126
|
-
when "proxy.server.port" then @proxy_port=value
|
200
|
+
when "proxy.server.port" then @proxy_port=isInteger(@proxy_port,value)
|
127
201
|
when "proxy.auth.username" then @proxy_user=value
|
128
|
-
when "proxy.auth.password" then @proxy_pass
|
129
|
-
|
202
|
+
when "proxy.auth.password" then @proxy_pass=@obj.util.decrypt value, @license_key
|
203
|
+
if (@proxy_pass == nil)
|
204
|
+
@proxy_pass = value
|
205
|
+
end
|
206
|
+
when "apm.protocol.https" then @is_secured=@obj.util.getBooleanValue value
|
130
207
|
when "apminsight.log.dir" then @logs_dir=value
|
208
|
+
when "apminsight.log.level" then @obj.log.setLevel value
|
131
209
|
when "agent.connection.retry" then @connection_retry=value #Not in Conf - yet to come
|
132
|
-
|
133
|
-
|
210
|
+
when "agent.polling.interval" then @connect_interval=isInteger(@connect_interval, value)#Not in Conf - yet to come
|
211
|
+
when "transaction.skip.listening" then @txn_skip_listen=@obj.util.getArray value.gsub("\s", ""),","
|
212
|
+
when "metricstore.metric.bucket.size" then @metric_overflow_t = isInteger(@metric_overflow_t, value)
|
213
|
+
when "metricstore.dbmetric.bucket.size" then @dbmetric_overflow_t = isInteger(@dbmetric_overflow_t, value)
|
214
|
+
when "transaction.tracestore.size" then @trace_overflow_t = isInteger(@trace_overflow_t, value)
|
134
215
|
end
|
135
216
|
end
|
217
|
+
store_encrypted_data(@config)
|
218
|
+
end
|
219
|
+
|
220
|
+
#Checks whether the given value is Environment Variable
|
221
|
+
def checkAndGetEnvValue(data)
|
222
|
+
begin
|
223
|
+
value = "#{data}"[/\{(.*)\}/,1]
|
224
|
+
if (value != nil && ENV.has_key?(value))
|
225
|
+
return data.gsub(/\{.*\}/, ENV[value])
|
226
|
+
end
|
227
|
+
rescue Exception=>e
|
228
|
+
end
|
229
|
+
return data
|
136
230
|
end
|
137
231
|
|
232
|
+
def store_encrypted_data config
|
233
|
+
data = config["proxy.auth.password"]
|
234
|
+
if (data != nil && @obj.util.decrypt(data, @license_key) == nil) # checking whether data is already encrypted
|
235
|
+
begin
|
236
|
+
file_contents = ""
|
237
|
+
conf_file = File.open(@obj.constants.apm_conf, 'r')
|
238
|
+
conf_file.read.each_line do |line|
|
239
|
+
if line.start_with?("proxy.auth.password")
|
240
|
+
file_contents += "proxy.auth.password=" + @obj.util.encrypt(config["proxy.auth.password"], @license_key)
|
241
|
+
else
|
242
|
+
file_contents += line
|
243
|
+
end
|
244
|
+
#file_contents += "\n"
|
245
|
+
end #end of do read loop
|
246
|
+
conf_file.close
|
247
|
+
conf_file = File.open(@obj.constants.apm_conf, "w+")
|
248
|
+
conf_file.puts file_contents
|
249
|
+
conf_file.close
|
250
|
+
file_contents = nil # clearing memory
|
251
|
+
rescue Exception=>e
|
252
|
+
@obj.log.logException "Error while encrypting file", e
|
253
|
+
end
|
254
|
+
end # if already encrypted
|
255
|
+
end
|
256
|
+
|
257
|
+
def getHostType
|
258
|
+
begin
|
259
|
+
# Check for AWS environment
|
260
|
+
url = URI.parse('http://169.254.169.254/latest/meta-data/') # AWS metadata url
|
261
|
+
request = Net::HTTP::Get.new(url.path)
|
262
|
+
response = Net::HTTP.start(url.host, url.port, :read_timeout => 2) {|http| http.request(request)}
|
263
|
+
if (response.kind_of? Net::HTTPOK)
|
264
|
+
@hostType = "AWS"
|
265
|
+
return @hostType
|
266
|
+
end
|
267
|
+
rescue Exception => e
|
268
|
+
end
|
269
|
+
|
270
|
+
begin
|
271
|
+
#Check for Azure environment
|
272
|
+
url = URI.parse('http://169.254.169.254/metadata/v1/maintenance') # Azure 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 = "AZURE"
|
277
|
+
return @hostType
|
278
|
+
end
|
279
|
+
rescue Exception => e
|
280
|
+
end
|
281
|
+
|
282
|
+
begin
|
283
|
+
# Check for Heroku env. In the backgroud it is using AWS EC2, hence sending as AWS
|
284
|
+
if (ENV.has_key?('DYNO') || ENV.has_key?('STACK'))
|
285
|
+
@hostType = "AWS"
|
286
|
+
return @hostType
|
287
|
+
end
|
288
|
+
rescue Exception => e
|
289
|
+
end
|
290
|
+
|
291
|
+
@hostType = nil
|
292
|
+
end
|
293
|
+
|
138
294
|
def getAgentInfo
|
139
295
|
data = Hash.new
|
140
296
|
agentdata = Hash.new
|
141
|
-
agentdata = {"application.type"=>"RUBY","application.name"=>@appname,"hostname"=>@agenthost,"port"=>@agentport,"agent.version"=>
|
297
|
+
agentdata = {"application.type"=>"RUBY","application.name"=>@appname,"hostname"=>@agenthost,"port"=>@agentport,"agent.version"=>ManageEngine::APMInsight::MAJOR_VERSION}
|
298
|
+
if (@hostType != nil)
|
299
|
+
agentdata["host.type"]=@hostType
|
300
|
+
end
|
142
301
|
data["agent_info"]=agentdata
|
143
302
|
data["environment"]=getEnvData
|
303
|
+
data["custom_config_info"]=getAgentConfigData
|
144
304
|
data
|
145
305
|
end
|
146
306
|
|
147
307
|
def getEnvData
|
148
308
|
env = Hash.new
|
149
309
|
begin
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
310
|
+
env["OS"] = Gem::Platform.local.os
|
311
|
+
env["OS Version"] = Gem::Platform.local.version
|
312
|
+
env["OS Arch"] = Gem::Platform.local.cpu
|
313
|
+
env["Ruby Version"] = "#{RUBY_VERSION}"
|
314
|
+
gemSpecs = Gem.loaded_specs[@obj.constants.s247_apm_gem]
|
315
|
+
if (gemSpecs == nil)
|
316
|
+
gemSpecs = Gem.loaded_specs[@obj.constants.apm_gem]
|
317
|
+
end
|
318
|
+
if (gemSpecs != nil)
|
319
|
+
env["Agent Installed Path"] = gemSpecs.full_gem_path
|
320
|
+
end
|
321
|
+
|
322
|
+
# ENV.to_hash.each do |key, value|
|
323
|
+
# env[key] = value
|
324
|
+
# end
|
325
|
+
env["Application Path"] = "#{Dir.pwd}"
|
154
326
|
rescue Exception=>e
|
327
|
+
@obj.log.warn "Error in capturing env data. #{e.message}"
|
155
328
|
end
|
156
329
|
env
|
157
330
|
end
|
158
331
|
|
332
|
+
def getAgentConfigData
|
333
|
+
agentconfig = Hash.new
|
334
|
+
agentconfig["last.modified.time"]=@lastupdatedtime*1000
|
335
|
+
agentconfig["apdex.threshold"]=@apdex_t
|
336
|
+
agentconfig["sql.capture.enabled"]=0
|
337
|
+
if @sql_capture
|
338
|
+
agentconfig["sql.capture.enabled"]=1
|
339
|
+
end
|
340
|
+
agentconfig["transaction.trace.enabled"]=0
|
341
|
+
if @trans_trace
|
342
|
+
agentconfig["transaction.trace.enabled"]=1
|
343
|
+
end
|
344
|
+
agentconfig["transaction.trace.threshold"]=@trans_trace_t
|
345
|
+
agentconfig["transaction.trace.sql.parametrize"]=0
|
346
|
+
if @sql_capture_params
|
347
|
+
agentconfig["transaction.trace.sql.parametrize"]=1
|
348
|
+
end
|
349
|
+
agentconfig["transaction.trace.sql.stacktrace.threshold"]=@sql_trace_t
|
350
|
+
agentconfig["transaction.tracking.request.interval"]=1
|
351
|
+
agentconfig
|
352
|
+
end
|
159
353
|
|
160
354
|
def getDispatcher
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
355
|
+
|
356
|
+
@obj.log.info "Server: #{ENV['SERVER_SOFTWARE']}"
|
357
|
+
|
358
|
+
dispatcher = "unknown"
|
359
|
+
if defined?(PhusionPassenger) then
|
360
|
+
dispatcher = "passenger"
|
361
|
+
end
|
362
|
+
if defined?(Unicorn) then
|
363
|
+
dispatcher = "unicorn"
|
364
|
+
end
|
365
|
+
if defined?(Rainbows) then
|
366
|
+
dispatcher = "rainbows"
|
367
|
+
end
|
368
|
+
dispatcher
|
166
369
|
end
|
167
370
|
|
168
371
|
def isInteger default,value
|
@@ -184,6 +387,46 @@ module ManageEngine
|
|
184
387
|
end
|
185
388
|
end
|
186
389
|
|
390
|
+
def update_config configInfo
|
391
|
+
filepath = @obj.constants.apm_conf
|
392
|
+
f = "apminsight.conf.new"
|
393
|
+
begin
|
394
|
+
propsFile=File.open(filepath, 'r')
|
395
|
+
file = File.new(f,"w+")
|
396
|
+
propsFile.read.each_line do |line|
|
397
|
+
line.strip!
|
398
|
+
if (line[0] != ?# and line[0] != ?=)
|
399
|
+
i = line.index('=')
|
400
|
+
if (i)
|
401
|
+
key1 = line[0..i - 1].strip
|
402
|
+
if configInfo.has_key?(key1)
|
403
|
+
file.puts "#{key1}=#{configInfo[key1]}\n"
|
404
|
+
else
|
405
|
+
file.puts "#{line}\n"
|
406
|
+
end
|
407
|
+
else
|
408
|
+
file.puts "#{line}\n"
|
409
|
+
end
|
410
|
+
else
|
411
|
+
file.puts "#{line}\n"
|
412
|
+
end
|
413
|
+
end
|
414
|
+
rescue Exception=>e
|
415
|
+
@obj.log.info "Problem in Reading / Writing Property File : #{e.message} "
|
416
|
+
@obj.log.error "#{e.backtrace}"
|
417
|
+
ensure
|
418
|
+
propsFile.close
|
419
|
+
file.close
|
420
|
+
end
|
421
|
+
res = @obj.util.copyFiles f, filepath
|
422
|
+
if res
|
423
|
+
@obj.log.info "copyFiles result = #{res}"
|
424
|
+
#delete apminsight.conf.new has to be done
|
425
|
+
end
|
426
|
+
configureFile
|
427
|
+
assignConfig
|
428
|
+
end
|
429
|
+
|
187
430
|
|
188
431
|
end#c
|
189
432
|
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
|