apminsight 1.0.1 → 1.8.6
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/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
|