apminsight 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE.txt +60 -0
- data/README.rdoc +69 -0
- data/Rakefile +63 -0
- data/VERSION +1 -0
- data/conf/apminsight.conf +105 -0
- data/lib/agent/am_objectholder.rb +66 -0
- data/lib/agent/configuration/am_configuration.rb +190 -0
- data/lib/agent/logging/am_logger.rb +109 -0
- data/lib/agent/metrics/am_metricscollector.rb +30 -0
- data/lib/agent/metrics/am_metricsformatter.rb +263 -0
- data/lib/agent/metrics/am_metricsparser.rb +540 -0
- data/lib/agent/metrics/am_metricstore.rb +29 -0
- data/lib/agent/server/am_agent.rb +108 -0
- data/lib/agent/server/am_connector.rb +195 -0
- data/lib/agent/server/instrument/am_apm.rb +99 -0
- data/lib/agent/server/instrument/am_instrumenter.rb +43 -0
- data/lib/agent/server/worker/am_worker.rb +254 -0
- data/lib/agent/util/am_constants.rb +64 -0
- data/lib/agent/util/am_util.rb +130 -0
- data/lib/apminsight.rb +5 -0
- metadata +134 -0
@@ -0,0 +1,254 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'thread'
|
3
|
+
|
4
|
+
module ManageEngine
|
5
|
+
class APMWorker
|
6
|
+
@work =nil;
|
7
|
+
@status = 'not_init'
|
8
|
+
@id = 0
|
9
|
+
attr_accessor :id
|
10
|
+
def initialize
|
11
|
+
@status = "initialized"
|
12
|
+
@id = Process.pid
|
13
|
+
end
|
14
|
+
|
15
|
+
def start
|
16
|
+
@obj = ManageEngine::APMObjectHolder.instance
|
17
|
+
|
18
|
+
if @status=="working"
|
19
|
+
@obj.log.debug "woker thread already started"
|
20
|
+
elsif @status == "initialized"
|
21
|
+
@obj.log.info "start worker thread for - #{Process.pid} :: #{@status} "
|
22
|
+
#@obj.log.info "Starting APMWorker Thread #{Process.pid} "
|
23
|
+
@apm = Thread.new do
|
24
|
+
@status = 'working'
|
25
|
+
while !@obj.shutdown do
|
26
|
+
checkforagentstatus
|
27
|
+
updateConfig
|
28
|
+
dc
|
29
|
+
sleep (@obj.config.connect_interval).to_i
|
30
|
+
end#w
|
31
|
+
@status= "end"
|
32
|
+
@obj.log.debug "Worker thread ends"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.getInstance
|
38
|
+
if(@work==nil || @work.id!=Process.pid)
|
39
|
+
@work = ManageEngine::APMWorker.new
|
40
|
+
end
|
41
|
+
return @work
|
42
|
+
end
|
43
|
+
|
44
|
+
def updateConfig
|
45
|
+
if(@obj.config.lastupdatedtime!=File.mtime(@obj.constants.apm_conf).to_i)
|
46
|
+
@obj.log.info "Configuration File Changed... So Updating Configuration."
|
47
|
+
@obj.config.lastupdatedtime=File.mtime(@obj.constants.apm_conf).to_i
|
48
|
+
@obj.config.configureFile
|
49
|
+
@obj.config.assignConfig
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def checkforagentstatus
|
54
|
+
prevState = @obj.config.agent_enabled
|
55
|
+
@obj.config.checkAgentInfo
|
56
|
+
if !@obj.config.agent_enabled
|
57
|
+
@obj.log.info "Agent in Disabled State."
|
58
|
+
if prevState
|
59
|
+
@obj.log.info "Agent in Disabled State. Going to unsubscribe"
|
60
|
+
@obj.instrumenter.doUnSubscribe
|
61
|
+
end
|
62
|
+
else
|
63
|
+
if !prevState
|
64
|
+
@obj.log.info "Agent in Active State."
|
65
|
+
@obj.instrumenter.doSubscribe
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def stop
|
71
|
+
dc
|
72
|
+
@obj.shutdown = true;
|
73
|
+
end
|
74
|
+
|
75
|
+
def dc
|
76
|
+
begin
|
77
|
+
@obj.log.debug "[dc] collecting..."
|
78
|
+
now = @obj.util.currenttimemillis
|
79
|
+
result = Array.new
|
80
|
+
result.push(@obj.last_dispatch_time)
|
81
|
+
result.push(now)
|
82
|
+
data = Array.new
|
83
|
+
trd= nil;
|
84
|
+
@last_dispatch_time = now
|
85
|
+
if @obj.config.agent_enabled
|
86
|
+
d = @obj.parser.parse @obj.store.metrics_dup
|
87
|
+
if(d!=nil && d.has_key?("trace-data"))
|
88
|
+
trd = d.delete("trace-data");
|
89
|
+
#@obj.log.info "[dc] [TRACE] : #{d}"
|
90
|
+
end
|
91
|
+
#@obj.log.info "[dc] Data - #{d}"
|
92
|
+
if(d.length>0)
|
93
|
+
data =@obj.formatter.format d
|
94
|
+
#@obj.log.debug "[dc] Formatted Data - #{data}"
|
95
|
+
end
|
96
|
+
@obj.store.remove @obj.formatter.keysToRemove
|
97
|
+
end #if
|
98
|
+
fd = Array.new
|
99
|
+
fd.push(data)
|
100
|
+
if(trd!=nil)
|
101
|
+
fd.push(trd)
|
102
|
+
end
|
103
|
+
@obj.log.debug "[dc] data to store : #{fd}"
|
104
|
+
send_save fd
|
105
|
+
@obj.log.debug "[dc] collecting ends"
|
106
|
+
rescue Exception=>e
|
107
|
+
@obj.log.logException "[dc] Exception during data Collection. #{e.message}",e
|
108
|
+
@obj.shutdown=true
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def senddata d
|
113
|
+
# @obj.log.info("Send data --- #{d}")
|
114
|
+
result = Array.new
|
115
|
+
result.push( (File.mtime(@obj.constants.agent_lock).to_f*1000).to_i)
|
116
|
+
now = @obj.util.currenttimemillis
|
117
|
+
result.push(now)
|
118
|
+
write @obj.constants.agent_lock ,"#{Process.pid}"
|
119
|
+
data = read @obj.constants.agent_store
|
120
|
+
data.push(d);
|
121
|
+
tdata = Array.new;
|
122
|
+
trdata = Array.new;
|
123
|
+
data.each do |val|
|
124
|
+
case val.size
|
125
|
+
when 1
|
126
|
+
tdata.concat(val[0])
|
127
|
+
when 2
|
128
|
+
tdata.concat(val[0])
|
129
|
+
trdata.concat(val[1])
|
130
|
+
end
|
131
|
+
end
|
132
|
+
result.push(merge(tdata))
|
133
|
+
resp = @obj.connector.post @obj.constants.connect_data_uri+@obj.config.instance_id,result
|
134
|
+
if trdata.size>0
|
135
|
+
result[2]=trdata;
|
136
|
+
resp = @obj.connector.post @obj.constants.connect_trace_uri+@obj.config.instance_id,result
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def save fd
|
141
|
+
begin
|
142
|
+
data = fd.to_json;
|
143
|
+
write @obj.constants.agent_store,data
|
144
|
+
rescue Exception=>e
|
145
|
+
@obj.log.logException "[dc] Exception during save. #{e.message}",e
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def send_save data
|
150
|
+
begin
|
151
|
+
if FileTest.exist?(@obj.constants.agent_lock)
|
152
|
+
if Time.now.to_i - File.mtime(@obj.constants.agent_lock).to_i > (@obj.config.connect_interval).to_i
|
153
|
+
@obj.log.debug "worker send signal"
|
154
|
+
senddata data
|
155
|
+
else
|
156
|
+
@obj.log.info "worker save signal"
|
157
|
+
save data
|
158
|
+
end
|
159
|
+
else
|
160
|
+
@obj.log.info "worker save signals"
|
161
|
+
save data
|
162
|
+
write @obj.constants.agent_lock,"#{Process.pid}"
|
163
|
+
end
|
164
|
+
rescue Exception=>e
|
165
|
+
@obj.log.logException "Exception in decision making send or save #{e.message}",e
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def read p
|
170
|
+
data = Array.new
|
171
|
+
File.open( p, "r+" ) { |f|
|
172
|
+
f.flock(File::LOCK_EX)
|
173
|
+
begin
|
174
|
+
f.each_line do |line|
|
175
|
+
data.push(JSON.parse(line))
|
176
|
+
end
|
177
|
+
f.truncate 0
|
178
|
+
rescue Exception=>e
|
179
|
+
@obj.log.logException "Exception while reading data #{e}",e
|
180
|
+
ensure
|
181
|
+
f.flock(File::LOCK_UN)
|
182
|
+
end
|
183
|
+
}
|
184
|
+
data
|
185
|
+
end
|
186
|
+
|
187
|
+
|
188
|
+
def write (p, data )
|
189
|
+
File.open( p, "a+" ) { |f|
|
190
|
+
f.flock(File::LOCK_EX)
|
191
|
+
begin
|
192
|
+
f.write "#{data}\n"
|
193
|
+
rescue Exception=>e
|
194
|
+
@obj.log.logException "Exception while writing data #{e.message}",e
|
195
|
+
ensure
|
196
|
+
f.flock(File::LOCK_UN)
|
197
|
+
end
|
198
|
+
}
|
199
|
+
end
|
200
|
+
|
201
|
+
def merge data
|
202
|
+
# @obj.log.info "BEFORE MERGE : #{data}"
|
203
|
+
tdata =Hash.new ;
|
204
|
+
data.each do |sd|
|
205
|
+
name= sd[0]["ns"] + sd[0]["name"];
|
206
|
+
if tdata.has_key?(name)
|
207
|
+
if (sd[0]["name"]=="apdex")
|
208
|
+
tdata[name][1] = mapdx(tdata[name][1],sd[1])
|
209
|
+
else
|
210
|
+
tdata[name][1] = mapdb(tdata[name][1],sd[1])
|
211
|
+
end
|
212
|
+
else
|
213
|
+
tdata[name]=sd;
|
214
|
+
end
|
215
|
+
end
|
216
|
+
#@obj.log.info "MERGED DATA : #{tdata}"
|
217
|
+
res = Array.new;
|
218
|
+
tdata.each do|key,value|
|
219
|
+
res.push(value);
|
220
|
+
end
|
221
|
+
res
|
222
|
+
end
|
223
|
+
|
224
|
+
|
225
|
+
def mapdx res,dat
|
226
|
+
res[0] = res[0]+dat[0];
|
227
|
+
if dat[1]<res[1]
|
228
|
+
res[1]=dat[1]
|
229
|
+
end
|
230
|
+
if dat[2]>res[2]
|
231
|
+
res[2]=dat[2]
|
232
|
+
end
|
233
|
+
res[3] = res[3]+dat[3]
|
234
|
+
res[5] = res[5]+dat[5]
|
235
|
+
res[6] = res[6]+dat[6]
|
236
|
+
res[7] = res[7]+dat[7]
|
237
|
+
res[4] = (res[5].to_f + (res[6].to_f/2).to_f).to_f/res[3].to_f
|
238
|
+
res
|
239
|
+
end
|
240
|
+
|
241
|
+
def mapdb res,dat
|
242
|
+
res[0] = res[0]+dat[0];
|
243
|
+
if dat[1]<res[1]
|
244
|
+
res[1]=dat[1]
|
245
|
+
end
|
246
|
+
if dat[2]>res[2]
|
247
|
+
res[2]=dat[2]
|
248
|
+
end
|
249
|
+
res[3] = res[3]+dat[3]
|
250
|
+
res
|
251
|
+
end
|
252
|
+
|
253
|
+
end#c
|
254
|
+
end#m
|
@@ -0,0 +1,64 @@
|
|
1
|
+
|
2
|
+
module ManageEngine
|
3
|
+
class APMConstants
|
4
|
+
|
5
|
+
attr_reader :apm_gem,:apm_conf,:agent_conf,:connection_open_timeout,:connection_read_timeout,:connect_uri,:connect_data_uri,:connect_trace_uri
|
6
|
+
attr_reader :licence_exceeds,:licence_expired,:unmanage_agent,:manage_agent,:error_notfound,:error_server,:delete_agent,:response_code
|
7
|
+
attr_reader :mf_transaction,:mf_separator,:mf_db,:mf_apdex,:mf_namespace,:mf_name,:mf_all,:agent_store,:agent_lock
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
|
11
|
+
#File path for APM Conf file
|
12
|
+
@apm_gem="apminsight"
|
13
|
+
#File path for APM Conf file
|
14
|
+
@apm_conf="apminsight.conf"
|
15
|
+
|
16
|
+
#file path for agent id, enable details
|
17
|
+
@agent_conf="apminsight.info"
|
18
|
+
|
19
|
+
#file path for agent data store lock
|
20
|
+
@agent_lock="apminsight.lock"
|
21
|
+
|
22
|
+
#file path for agent data store lock
|
23
|
+
@agent_store="apminsight.store"
|
24
|
+
|
25
|
+
|
26
|
+
#Timeout for opening Connections
|
27
|
+
@connection_open_timeout=60
|
28
|
+
|
29
|
+
#Timeout for Reading data from Connections
|
30
|
+
@connection_read_timeout=60
|
31
|
+
|
32
|
+
#Connection uri
|
33
|
+
@connect_uri="arh/connect"
|
34
|
+
|
35
|
+
#Connection uri for data
|
36
|
+
@connect_data_uri="arh/data?instance_id="
|
37
|
+
|
38
|
+
#Connection uri for trace
|
39
|
+
@connect_trace_uri="arh/trace?instance_id="
|
40
|
+
|
41
|
+
#Response Codes
|
42
|
+
@licence_expired = 701
|
43
|
+
@licence_exceeds = 702
|
44
|
+
@delete_agent = 900
|
45
|
+
@unmanage_agent =910
|
46
|
+
@manage_agent = 911
|
47
|
+
@error_notfound = 404
|
48
|
+
@error_server = 500
|
49
|
+
@response_code = "response-code"
|
50
|
+
|
51
|
+
#Metrics Formatter -mf
|
52
|
+
@mf_apdex = "apdex"
|
53
|
+
@mf_namespace = "ns"
|
54
|
+
@mf_name = "name"
|
55
|
+
@mf_all = "all"
|
56
|
+
|
57
|
+
@mf_separator = "/"
|
58
|
+
@mf_transaction = "transaction" + @mf_separator + "http"
|
59
|
+
@mf_db = "db"
|
60
|
+
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'socket'
|
2
|
+
module ManageEngine
|
3
|
+
class APMUtil
|
4
|
+
|
5
|
+
def setLogger log
|
6
|
+
@log = log
|
7
|
+
end
|
8
|
+
|
9
|
+
#Reads the Property Files and returns a Hashes
|
10
|
+
def readProperties filepath
|
11
|
+
props = {}
|
12
|
+
begin
|
13
|
+
propsFile=File.open(filepath, 'r')
|
14
|
+
propsFile.read.each_line do |line|
|
15
|
+
line.strip!
|
16
|
+
if (line[0] != ?# and line[0] != ?=)
|
17
|
+
i = line.index('=')
|
18
|
+
if (i)
|
19
|
+
props[line[0..i - 1].strip] = line[i + 1..-1].strip
|
20
|
+
else
|
21
|
+
props[line] = ''
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
rescue Exception=>e
|
26
|
+
@log.info "Problem in Reading Property File : #{e.message} "
|
27
|
+
@log.error "#{e.backtrace}"
|
28
|
+
ensure
|
29
|
+
propsFile.close
|
30
|
+
end
|
31
|
+
props
|
32
|
+
end
|
33
|
+
|
34
|
+
#write the Properties into the Property file
|
35
|
+
def writeProperties(f,props)
|
36
|
+
begin
|
37
|
+
file = File.new(f,"w+")
|
38
|
+
props.each {|key,value| file.puts "#{key}=#{value}\n"}
|
39
|
+
rescue Exception=>e
|
40
|
+
@log.info "Problem in Writing Property File : \n File : #{f}"
|
41
|
+
@log.logException "#{e.message}",e
|
42
|
+
ensure
|
43
|
+
file.close
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def copyFiles src, dest
|
48
|
+
result = false
|
49
|
+
begin
|
50
|
+
srcFile = File.open(src)
|
51
|
+
destFile = File.open(dest , "w")
|
52
|
+
destFile.write( srcFile.read(100) ) while not srcFile.eof?
|
53
|
+
result = true
|
54
|
+
rescue Exception=>e
|
55
|
+
@log.info "Problem in Copying File : \n File : #{src} to #{dest}"
|
56
|
+
@log.logException "#{e.message}",e
|
57
|
+
result = false;
|
58
|
+
ensure
|
59
|
+
srcFile.close
|
60
|
+
destFile.close
|
61
|
+
end
|
62
|
+
|
63
|
+
result
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
def getBooleanValue(str)
|
68
|
+
if str == true || str == "true" || str == "True" || str == "TRUE"
|
69
|
+
return true
|
70
|
+
else
|
71
|
+
return false
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def currenttimemillis
|
76
|
+
(Time.now.to_f*1000).to_i
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
def getArray value,sep
|
81
|
+
arr = Array.new
|
82
|
+
if(value!=nil && value.length>0)
|
83
|
+
arr = value.split(sep)
|
84
|
+
end
|
85
|
+
arr
|
86
|
+
end
|
87
|
+
def isPortBusy(port)
|
88
|
+
Timeout::timeout(1) do
|
89
|
+
begin
|
90
|
+
TCPSocket.new('localhost', port).close
|
91
|
+
true
|
92
|
+
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
|
93
|
+
false
|
94
|
+
end
|
95
|
+
end
|
96
|
+
rescue Timeout::Error
|
97
|
+
false
|
98
|
+
end
|
99
|
+
|
100
|
+
def is_integer(val)
|
101
|
+
Integer(val)
|
102
|
+
rescue ArgumentError
|
103
|
+
false
|
104
|
+
else
|
105
|
+
true
|
106
|
+
end
|
107
|
+
|
108
|
+
def is_float(val)
|
109
|
+
Float(val)
|
110
|
+
rescue ArgumentError
|
111
|
+
false
|
112
|
+
else
|
113
|
+
true
|
114
|
+
end
|
115
|
+
|
116
|
+
def parametrizeQuery qry
|
117
|
+
begin
|
118
|
+
qry.gsub!(/'(.*?[^'])??'/,"?")
|
119
|
+
qry.gsub!(/\"(.*?[^\"])??\"/,"?")
|
120
|
+
qry.gsub!(/=.\d+/,"=?")
|
121
|
+
qry.gsub!(/,.\d+/,", ?")
|
122
|
+
rescue Exception=>e
|
123
|
+
@log.info "Problem in Parameterizing query: #{e.message} "
|
124
|
+
@log.logException "#{e.message}",e
|
125
|
+
end
|
126
|
+
qry
|
127
|
+
end
|
128
|
+
|
129
|
+
end#c
|
130
|
+
end#m
|