apminsight 1.0.1 → 1.8.2

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.
Files changed (33) hide show
  1. data/VERSION +1 -1
  2. data/apm-agent.gemspec +64 -0
  3. data/conf/apminsight.conf +15 -24
  4. data/lib/agent/am_objectholder.rb +25 -19
  5. data/lib/agent/api/custom_tracker.rb +79 -0
  6. data/lib/agent/configuration/am_configuration.rb +249 -37
  7. data/lib/agent/handler/custom_api_handler.rb +40 -0
  8. data/lib/agent/handler/sequence_book.rb +118 -0
  9. data/lib/agent/handler/tracker_handler.rb +58 -0
  10. data/lib/agent/logging/am_logger.rb +13 -9
  11. data/lib/agent/metrics/am_metricsformatter.rb +117 -59
  12. data/lib/agent/metrics/am_metricsparser.rb +195 -468
  13. data/lib/agent/metrics/am_metricstore.rb +7 -6
  14. data/lib/agent/metrics/exception_record.rb +24 -0
  15. data/lib/agent/server/am_agent.rb +42 -17
  16. data/lib/agent/server/am_connector.rb +65 -21
  17. data/lib/agent/server/instrument/action_view.rb +64 -0
  18. data/lib/agent/server/instrument/active_record.rb +52 -0
  19. data/lib/agent/server/instrument/am_apm.rb +107 -97
  20. data/lib/agent/server/instrument/am_instrumenter.rb +54 -42
  21. data/lib/agent/server/instrument/environment.rb +42 -0
  22. data/lib/agent/server/instrument/rails.rb +56 -0
  23. data/lib/agent/server/instrument/sinatra.rb +97 -0
  24. data/lib/agent/server/worker/am_worker.rb +93 -49
  25. data/lib/agent/trackers/database_tracker.rb +107 -0
  26. data/lib/agent/trackers/default_tracker.rb +57 -0
  27. data/lib/agent/trackers/root_tracker.rb +43 -0
  28. data/lib/agent/util/am_constants.rb +46 -3
  29. data/lib/agent/util/am_util.rb +64 -1
  30. data/lib/agent/util/transaction_util.rb +35 -0
  31. data/lib/agent/version.rb +13 -0
  32. data/lib/apminsight.rb +4 -1
  33. metadata +114 -76
@@ -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,118 @@
1
+ require 'agent/metrics/exception_record'
2
+
3
+ module APMInsight
4
+ module Agent
5
+ class SequenceBook
6
+ attr_reader :openTracker, :closedTracker, :rootTracker, :trackerCount, :exceptionBag, :listenFlag
7
+
8
+ def initialize
9
+ @rootTracker = createDummyTracker()
10
+ @closedTracker = @rootTracker
11
+ @openTracker = nil
12
+
13
+ @trackerCount = 0
14
+ @listenFlag = -1
15
+ # @exceptionBag = Array.new
16
+ end
17
+
18
+ def attachTracker tracker
19
+ if tracker == nil
20
+ return nil
21
+ end
22
+
23
+ # If RootTracker is not set, check type and set
24
+ if @rootTracker == @closedTracker
25
+ if !tracker.is_a?(ManageEngine::Tracker::RootTracker)
26
+ closeSequence()
27
+ return nil
28
+ end
29
+ @rootTracker = tracker
30
+
31
+ updateListenFlag()
32
+ end
33
+
34
+
35
+ # Attach tracker as Sibling or Child and set nominee
36
+ if @closedTracker != nil
37
+ tracker.sibling = @closedTracker
38
+ @closedTracker.sibling = tracker # Nominee - if dropped/corrupted, defaults to this tracker
39
+ @openTracker = tracker
40
+ @closedTracker = nil
41
+ else
42
+ if tracker.equal?(@openTracker)
43
+ return nil
44
+ end
45
+
46
+ @openTracker.child = tracker
47
+ tracker.sibling = @openTracker
48
+ @openTracker = tracker
49
+ end
50
+
51
+ checkAndArrestSequence()
52
+
53
+ return tracker
54
+ end
55
+
56
+ def closeTracker tracker
57
+ @closedTracker = tracker
58
+ tracker.sibling = nil
59
+ @openTracker = nil
60
+
61
+ # Marks end of transaction
62
+ if @rootTracker == tracker
63
+ if @listenFlag < 1 || (@listenFlag >= 1 && @trackerCount > 1)
64
+
65
+ sequenceBag = Hash.new
66
+ sequenceBag["roottracker"] = @rootTracker
67
+ sequenceBag["exceptions"] = @exceptionBag
68
+
69
+ ManageEngine::APMObjectHolder.instance.collector.updateTransaction(@rootTracker.url, sequenceBag)
70
+ end
71
+ closeSequence()
72
+ end
73
+ end
74
+
75
+ def closeSequence
76
+ @rootTracker = nil
77
+ @openTracker = @closedTracker = nil
78
+ @trackerCount = 0
79
+ Thread.current[:apminsight] = nil
80
+ end
81
+
82
+ def addExceptionInfo(exception)
83
+ begin
84
+ if @exceptionBag == nil
85
+ @exceptionBag = Set.new
86
+ end
87
+ if (@exceptionBag.size() < 10)
88
+ exceptionRecord = ::APMInsight::Errors::ExceptionRecord.new(exception)
89
+ @exceptionBag.add(exceptionRecord)
90
+ end
91
+ rescue Exception=>e
92
+ end
93
+ end
94
+
95
+ def updateListenFlag
96
+ if !ManageEngine::APMObjectHolder.instance.txn_util.listen?(@rootTracker.url())
97
+ @listenFlag = 1
98
+ end
99
+
100
+ ## Check for sampling factor & for bg txn chk if enabled
101
+ end
102
+
103
+ def checkAndArrestSequence
104
+ @trackerCount += 1
105
+ if @trackerCount == 1000
106
+ @listenFlag = 1
107
+ end
108
+
109
+ ## Can check for timeout
110
+ end
111
+
112
+ def createDummyTracker
113
+ return ManageEngine::Tracker::DefaultTracker.new("dummy")
114
+ end
115
+
116
+ end
117
+ end
118
+ 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
@@ -14,12 +14,18 @@ module ManageEngine
14
14
  path= path + '/apm.log'
15
15
  #puts "#{path}"
16
16
  # file = open(path, File::WRONLY | File::APPEND | File::CREAT)
17
- @apmlog = Logger.new(path, 10, 100 * 1024 * 1024)
18
- # @apmlog = Logger.new(file)
19
- @apmlog.level = Logger::INFO
20
- @apmlog.datetime_format = "%Y-%m-%d %H:%M:%S"
17
+ begin
18
+ @apmlog = Logger.new(path, 10, 5 * 1024 * 1024)
19
+ @apmlog.level = Logger::INFO
20
+ rescue Exception => e
21
+ puts "Unable to create/edit the log file #{path}. Writing agent logs to STDOUT.\nError: #{e.message}"
22
+ @apmlog = Logger.new(STDOUT)
23
+ @apmlog.level = Logger::WARN
24
+ end
25
+ # @apmlog = Logger.new(file)
26
+ @apmlog.datetime_format = "%Y-%m-%d %H:%M:%S"
21
27
  @apmlog.formatter = proc do |severity, datetime, progname, msg|
22
- "[#{datetime}|#{Process.pid}]:#{msg}\n"
28
+ "[#{datetime}|#{Process.pid}][#{severity}]:#{msg}\n"
23
29
  end
24
30
  @apmlog.debug("[LOGGER] APM Agent Logging Initialized")
25
31
 
@@ -96,10 +102,8 @@ module ManageEngine
96
102
 
97
103
 
98
104
  def logException(msg,e)
99
- @apmlog.info( "#{msg} => #{e.message}")
100
- @apmlog.debug( "!!!!!!!!!!!!!!!!!!!!!!EXCEPTION !!!!!!!!!!!!!!!!!!!!!!!!!!!!")
101
- @apmlog.debug( "Message : #{msg}\nTrace :\n#{e.backtrace}")
102
- @apmlog.debug( "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
105
+ @apmlog.warn( "#{msg} => #{e.message}")
106
+ @apmlog.warn( "Message : #{msg}\nTrace :\n#{e.backtrace}")
103
107
  end
104
108
 
105
109
  def close
@@ -6,8 +6,8 @@ module ManageEngine
6
6
  @obj = ManageEngine::APMObjectHolder.instance
7
7
  @apdex_threshold = 0
8
8
  end
9
- #trans Vs #[0-rspTime,1-min rt,2-max rt,3-cnt,4-apdx,5-stat,6-toler,7-frustating]
10
- #DBtrans Vs #[rspTime,min rt,max rt,cnt]
9
+ #trans Vs #[0-rspTime,1-min rt,2-max rt,3-cnt,4-apdx,5-stat,6-toler,7-frustating,8-error_count]
10
+ #DBtrans Vs #[rspTime,min rt,max rt,cnt,error_count]
11
11
  #trace
12
12
 
13
13
  def format d
@@ -95,34 +95,41 @@ module ManageEngine
95
95
  end
96
96
 
97
97
  def updateinstance
98
- ins_apdx = Array.new
99
- cnt = 0;
100
- rt = 0;
101
- s=0;
102
- t=0;
103
- f=0;
104
- min = -1;
105
- max = 0;
98
+ ins_apdx = [0,-1,-1,0,0,0,0,0,0]
99
+ logmetric = Hash.new
106
100
  @transaction.each do |key,value|
107
- rt = rt + value[0]
108
- if min == -1
109
- min = value[1]
110
- max = value[2]
111
- end
112
- if(value[1]<min)
113
- min = value[1]
114
- end
115
- if (value[2]>max)
116
- max = value[2]
101
+ apdexValue = value[0]
102
+ ins_apdx[0] += apdexValue[0]
103
+ if ins_apdx[1] == -1
104
+ ins_apdx[1] = apdexValue[1]
105
+ ins_apdx[2] = apdexValue[2]
106
+ else
107
+ if(apdexValue[1]<ins_apdx[1])
108
+ ins_apdx[1] = apdexValue[1]
109
+ end
110
+ if (apdexValue[2]>ins_apdx[2])
111
+ ins_apdx[2] = apdexValue[2]
112
+ end
117
113
  end
118
- cnt = cnt + value[3]
114
+ ins_apdx[3] += apdexValue[3]
119
115
 
120
- s = s + value[5]
121
- t = t + value[6]
122
- f = f + value[7]
116
+ ins_apdx[5] += apdexValue[5]
117
+ ins_apdx[6] += apdexValue[6]
118
+ ins_apdx[7] += apdexValue[7]
119
+ ins_apdx[8] += apdexValue[8]
120
+
121
+ exceptions = value[1][@obj.constants.mf_logmetric]
122
+ if (exceptions != nil)
123
+ exceptions.each do |name, count|
124
+ logmetric[name] = logmetric[name].to_i + count
125
+ end
126
+ end
127
+ end
128
+ if (ins_apdx[3] > 0)
129
+ ins_apdx[4] = (ins_apdx[5].to_f + (ins_apdx[6]/2).to_f).to_f/ins_apdx[3].to_f
130
+ ins_apdx[0] = ins_apdx[0].round(2)
123
131
  end
124
- apx = (s.to_f + (t/2).to_f).to_f/cnt.to_f
125
- @instance[":apdex"]=[rt.round(2),min,max,cnt,apx,s,t,f]
132
+ @instance[":apdex"]=[ins_apdx, {@obj.constants.mf_logmetric=>logmetric}]
126
133
  end
127
134
 
128
135
  def updatedbinstance
@@ -130,6 +137,7 @@ module ManageEngine
130
137
  rt = 0;
131
138
  min = -1;
132
139
  max = 0;
140
+ error_count = 0;
133
141
  if(@db.length>0)
134
142
  @db.each do |key,val|
135
143
  value = val["metrics"]
@@ -145,8 +153,9 @@ module ManageEngine
145
153
  max = value[2]
146
154
  end
147
155
  cnt = cnt + value[3]
156
+ error_count += value[4]
148
157
  end
149
- @dbinstance[":apdex"]=[rt.round(2),min,max,cnt]
158
+ @dbinstance[":apdex"]=[rt.round(2),min,max,cnt,error_count]
150
159
  end
151
160
  end
152
161
 
@@ -154,25 +163,61 @@ module ManageEngine
154
163
  begin
155
164
  pl = d["td"]
156
165
  dbl = d["db"]
166
+ exc = d["exception"]
157
167
 
158
168
  rt = pl["rt"].round(2)
159
- path = pl["path"]
160
- name = pl["name"]
161
-
162
- path = @obj.constants.mf_transaction + @obj.constants.mf_separator + path + " " +name
169
+ path = @obj.constants.mf_transaction + @obj.constants.mf_separator + pl["path"]
163
170
 
164
171
 
165
172
  apx_stat = nil
173
+ additionalInfo = nil
166
174
  if(@transaction.has_key?(path))
167
- apx_stat = @transaction[path]
175
+ apx_stat = @transaction[path][0]
176
+ additionalInfo = @transaction[path][1]
168
177
  else
178
+ if @transaction.length == @obj.config.metric_overflow_t
179
+ @obj.log.debug "Metricstore overflow. Current Size: #{@obj.config.metric_overflow_t} #{path}"
180
+ return
181
+ end
169
182
  apx_stat = Array.new
170
- apx_stat = [0,rt,rt,0,0,0,0,0]
183
+ apx_stat = [0,0,0,0,0,0,0,0,0]
184
+ additionalInfo = Hash.new
171
185
  end
172
- apx_stat = apxarray apx_stat,rt
173
- @transaction[path] = apx_stat
186
+
187
+ if (pl.has_key?("error"))
188
+ apx_stat[8] += 1
189
+ else
190
+ apx_stat = apxarray apx_stat,rt
191
+ end
192
+
193
+ if (exc != nil)
194
+ logmetric = additionalInfo[@obj.constants.mf_logmetric]
195
+ if (logmetric == nil)
196
+ additionalInfo[@obj.constants.mf_logmetric] = exc
197
+ else
198
+ exc.each do |name, count|
199
+ logmetric[name] = logmetric[name].to_i + count
200
+ end
201
+ end
202
+ end
203
+
204
+ @transaction[path] = [apx_stat, additionalInfo]
174
205
  if(dbl!=nil)
175
- updatedb dbl,path
206
+ if @db.length < @obj.config.dbmetric_overflow_t
207
+ updatedb dbl,path
208
+ elsif @db.length == @obj.config.dbmetric_overflow_t
209
+ @obj.log.debug "DB metric overflow. Current Size: #{@obj.config.dbmetric_overflow_t} #{path}"
210
+ #@obj.log.info "data = #{@db}"
211
+ of = Hash.new
212
+ stats = Array.new
213
+ stats = [0,0,0,0,0]
214
+ of["tpath"] = @obj.constants.mf_overflow
215
+ #of["tpath"] = @obj.constants.mf_transaction + @obj.constants.mf_separator + @obj.constants.mf_overflow #using this for testing purpose
216
+ of["path"] = @obj.constants.mf_db + @obj.constants.mf_separator + @obj.constants.mf_overflow + @obj.constants.mf_separator + "-" + @obj.constants.mf_separator
217
+ of["metrics"] = stats
218
+ @db[@obj.constants.mf_overflow]=of
219
+ #@obj.log.info "data updated = #{@db}"
220
+ end
176
221
  end
177
222
  rescue Exception=>e
178
223
  @obj.log.info "#{e.message}"
@@ -181,6 +226,7 @@ module ManageEngine
181
226
  # Apmagent::ApmLogger.instance.info "update transaction end"
182
227
  end
183
228
 
229
+ # Updates apdex score and increases statisfied, tolerating, frustrated count accordingly
184
230
  def apxarray apx_stat,rt
185
231
 
186
232
  # Apmagent::ApmLogger.instance.info "apxarray : start #{apx_stat}"
@@ -193,16 +239,19 @@ module ManageEngine
193
239
  apx_stat[6] = apx_stat[6] + 1
194
240
  end
195
241
 
196
- apx_stat[4] = (apx_stat[5].to_f + (apx_stat[6].to_f/2).to_f)/apx_stat[3].to_f
242
+ if (apx_stat[3] > 0)
243
+ apx_stat[4] = (apx_stat[5].to_f + (apx_stat[6].to_f/2).to_f)/apx_stat[3].to_f
244
+ end
197
245
  # Apmagent::ApmLogger.instance.info "apxarray : end #{apx_stat}"
198
246
  apx_stat
199
247
  end
200
248
 
249
+ # Updates resp time, min rt and max rt in apdex metric
201
250
  def updatert apx_stat,rt
202
251
  # Apmagent::ApmLogger.instance.info "updatert : start"
203
- apx_stat[3] = apx_stat[3] +1
252
+ apx_stat[3] = apx_stat[3] + 1
204
253
  apx_stat[0] = apx_stat[0] + rt
205
- if(rt < apx_stat[1])
254
+ if(apx_stat[1] == 0 || rt < apx_stat[1])
206
255
  apx_stat[1] = rt
207
256
  end
208
257
  if(rt > apx_stat[2])
@@ -211,7 +260,8 @@ module ManageEngine
211
260
  #Apmagent::ApmLogger.instance.info "updatert : end"
212
261
  apx_stat
213
262
  end
214
- #DBtrans Vs #[rspTime,min rt,max rt,cnt]
263
+
264
+ #DBtrans Vs #[rspTime,min rt,max rt,cnt,error_count]
215
265
  def updatedb dpl,tpath
216
266
  # Apmagent::ApmLogger.instance.info "updatedb : start"
217
267
  dpl.each do |pl|
@@ -227,37 +277,45 @@ module ManageEngine
227
277
  stat = val["metrics"]
228
278
  else
229
279
  val=Hash.new
280
+ val["tpath"] = tpath
281
+ val["path"] = dpath
230
282
  stat = Array.new
231
- stat = [rt,rt,rt,0]
283
+ stat = [0,rt,rt,0,0]
284
+ end
285
+ if (pl.has_key?("error"))
286
+ stat[4] += 1
287
+ else
288
+ stat = updatert stat,rt
232
289
  end
233
- stat = updatert stat,rt
234
- val["tpath"] = tpath
235
- val["path"] = dpath
236
290
  val["metrics"] = stat
237
291
  @db[path] = val
238
- updatedboperations rt, pl["operation"]
292
+ updatedboperations rt, pl["operation"], pl["error"]
239
293
  end
240
294
  #Apmagent::ApmLogger.instance.info "updatedb : end"
241
295
  end
242
296
 
243
- def updatedboperations rt,operation
244
- opstats = Array.new;
245
- #puts "#{operation} "
297
+ def updatedboperations rt, operation, isError
246
298
  if(@dboperations.has_key?(operation))
247
299
  opstats = @dboperations[operation]
248
300
  else
249
- opstats = [0.0,rt,rt,0]
250
- end
251
- opstats[0] = opstats[0] + rt
252
- if(rt<opstats[1])
253
- opstats[1] = rt
301
+ opstats = Array.new;
302
+ opstats = [0.0,rt,rt,0,0]
254
303
  end
255
- if (rt>opstats[2])
256
- opstats[2] = rt
257
- end
258
- opstats[3] = opstats[3] +1
304
+
305
+ if (isError)
306
+ opstats[4] += 1
307
+ else
308
+ opstats[0] = opstats[0] + rt
309
+ if(rt<opstats[1])
310
+ opstats[1] = rt
311
+ end
312
+ if (rt>opstats[2])
313
+ opstats[2] = rt
314
+ end
315
+ opstats[3] = opstats[3] +1
316
+ end
259
317
  @dboperations[operation]=opstats
260
318
  end
261
319
 
262
- end
263
- end
320
+ end#class
321
+ end#module