gcarerubymethodprofiler 1.0.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 902c21998bc34a46fe1c5afbce2bfedde2a5ae94
4
+ data.tar.gz: c328f9058a44d032e75da2b4f552eec15d6e2582
5
+ SHA512:
6
+ metadata.gz: eee6483fcc6c9f262f2d4f58d7715d13487a1ccb62a6f356fe270c983d80c8ccd078b812b68952a719a4ca77e62505fe777b9fb3a34f37c46ff39132ca8ec5a5
7
+ data.tar.gz: c1b04b4705343e18a2c26269343cd71aa952869c7aa88284bde3ea72f3963f0bb172a35a48c6466d6b2c28506025bab131123b6d5e14ab7af5659c7eff85ea49
@@ -0,0 +1,21 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'gcarerubymethodprofiler'
3
+ s.version = "1.0.0"
4
+ s.authors = ['Bipin V']
5
+ s.date = %q{2019-06-15}
6
+ s.summary = %q{generic method profiler for ruby}
7
+ s.description = 'Monitory ruby methods and send telemetry data to GCare Server'
8
+ s.authors = ['Bipin V']
9
+ s.email = ['bipin.v@gavstech.com']
10
+ s.homepage = 'http://www.gavstech.com'
11
+ s.license = 'Nonstandard'
12
+
13
+ s.files = Dir[
14
+ 'README.md',
15
+ 'Rakefile',
16
+ 'lib/**/*.rb',
17
+ '*.gemspec',
18
+ 'test/*.*'
19
+ ]
20
+ s.require_paths = ["lib"]
21
+ end
@@ -0,0 +1,330 @@
1
+ require 'net/http'
2
+ require 'json'
3
+ require 'securerandom'
4
+ require 'socket'
5
+ require 'resolv'
6
+
7
+ #https://pow.gs/mirror/discourse/blob/35d6fff69e86704081270333fbcb5248202a246a/lib/method_profiler.rb
8
+
9
+ class GCareRubyMethodProfiler
10
+ def self.decorateHttp(methods, name, iKey, gcareurl, no_recurse: false)
11
+ patches = methods.map do |method_name|
12
+ recurse_protection = ""
13
+ if no_recurse
14
+ recurse_protection = <<~RUBY
15
+ return #{method_name}__mp_unpatched(*args, &blk) if @mp_recurse_protect_#{method_name}
16
+ @mp_recurse_protect_#{method_name} = true
17
+ RUBY
18
+ end
19
+
20
+ <<~RUBY
21
+ unless defined?(#{method_name}__mp_unpatched)
22
+ alias_method :#{method_name}__mp_unpatched, :#{method_name}
23
+ def #{method_name}(*args, &blk)
24
+ unless prof = Thread.current[:_method_profiler]
25
+ requestobject = nil
26
+ donottrack = false
27
+ gcare_telemetry_uri = URI("#{gcareurl}")
28
+ case __method__.to_s
29
+ when 'request'
30
+ if args[0].is_a? Net::HTTPRequest
31
+ requestobject = args[0]
32
+ if requestobject.path == gcare_telemetry_uri.path
33
+ donottrack = true
34
+ else
35
+ donottrack = false
36
+ end
37
+ end
38
+ when 'get'
39
+ path = args[0]
40
+ when 'get_response'
41
+ uri_or_host = args[0]
42
+ path = args[1]
43
+ port = args[2]
44
+ when 'post'
45
+ path = args[0]
46
+ when 'post_form'
47
+ uri_or_host = args[0]
48
+ when 'get2'
49
+ path = args[0]
50
+ when 'head2'
51
+ path = args[0]
52
+ when 'patch'
53
+ path = args[0]
54
+ when 'post2'
55
+ path = args[0]
56
+ end
57
+ gcareid = requestobject['GCareID']
58
+ if gcareid == nil
59
+ gcareid = SecureRandom.uuid
60
+ requestobject['GCareID'] = gcareid
61
+ end
62
+
63
+ startTime = Time.now
64
+ #{recurse_protection}
65
+ returnvalue = #{method_name}__mp_unpatched(*args, &blk)
66
+ if donottrack == false
67
+ donottrack = true
68
+ endTime = Time.now
69
+ timestamp = startTime.utc.iso8601(0)
70
+ scheme = self.use_ssl? == true ? 'https' : 'http'
71
+ local_host = Socket.gethostname
72
+ local_ip = Resolv.getaddress(local_host)
73
+ remote_host = self.address
74
+ remote_ip = Resolv.getaddress(remote_host)
75
+ iKeyValue = "#{iKey}"
76
+ duration = Time.at(endTime - startTime).gmtime.strftime("00.%H:%M:%S.%7N")
77
+ teledata = {
78
+ 'ver' => 2,
79
+ 'name' => 'Gavs.ApplicationMonitoring.' + iKeyValue + '.RemoteDependency',
80
+ 'time' => timestamp,
81
+ 'sampleRate' => '100',
82
+ 'iKey' => iKeyValue,
83
+ 'tags' => {
84
+ 'ai' => {
85
+ 'internal.sdkVersion' => 'rb:1.0.0',
86
+ 'operation.id' => nil,
87
+ 'operation.name' => requestobject.method,
88
+ 'gcare.id' => gcareid,
89
+ 'device.roleInstance' => local_host
90
+ }
91
+ },
92
+ 'data' => {
93
+ 'baseType' => 'RemoteDependencyData',
94
+ 'baseData' => {
95
+ 'ver' => 2,
96
+ 'platform_version' => "#{RUBY_VERSION}",
97
+ 'platform_description' => 'ruby',
98
+ 'id' => nil,
99
+ 'GCareID' => gcareid,
100
+ 'referer' => requestobject['referer'],
101
+ 'scheme' => scheme,
102
+ 'remote_ip' => local_ip,
103
+ 'remote_host' => local_host,
104
+ 'forwarding_ip' => nil,
105
+ 'client_ip' => local_ip,
106
+ 'server_host' => remote_host,
107
+ 'server_ip' => remote_ip,
108
+ 'server_hostname' => remote_host,
109
+ 'useragent' => requestobject['user-agent'],
110
+ 'session_id' => nil,
111
+ 'timestamp' => timestamp,
112
+ 'name' => requestobject.method,
113
+ 'duration' => duration,
114
+ 'responseCode' => returnvalue.code,
115
+ 'success' => returnvalue.message,
116
+ 'url' => returnvalue.uri == nil ? scheme + ":" + "//" + self.address + ":" + self.port.to_s + requestobject.path : returnvalue.uri,
117
+ 'server_port' => self.port,
118
+ 'properties' => {
119
+ 'httpMethod' => requestobject.method
120
+ }
121
+ }
122
+ },
123
+ 'machine' => {
124
+ 'from_ip' => 'USER',
125
+ 'from_name' => 'USER',
126
+ 'to_ip' => remote_ip,
127
+ 'to_name' => requestobject.path
128
+ }
129
+ }
130
+ puts teledata.to_json
131
+
132
+ headers = {
133
+ 'Accept' => 'application/json',
134
+ 'Content-Type' => 'application/json; charset=utf-8'
135
+ }
136
+ request = Net::HTTP::Post.new(gcare_telemetry_uri.path, headers)
137
+ request.body = teledata.to_json
138
+ http = Net::HTTP.new gcare_telemetry_uri.hostname, gcare_telemetry_uri.port
139
+ if gcare_telemetry_uri.scheme.downcase == 'https'
140
+ http.use_ssl = true
141
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
142
+ end
143
+ p "Sending RemoteDependency telemery data to GCare (http)"
144
+ response = http.request(request)
145
+
146
+ if !response.kind_of? Net::HTTPSuccess
147
+ end
148
+ end
149
+ if returnvalue.is_a?(Net::HTTPResponse)
150
+
151
+ end
152
+ if returnvalue.is_a?(String)
153
+
154
+ end
155
+ return returnvalue
156
+ end
157
+ #{recurse_protection}
158
+ begin
159
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
160
+ puts 'test2'
161
+ puts args
162
+ #{method_name}__mp_unpatched(*args, &blk)
163
+ ensure
164
+ data = (prof[:#{name}] ||= {duration: 0.0, calls: 0})
165
+ data[:duration] += Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
166
+ data[:calls] += 1
167
+ #{"@mp_recurse_protect_#{method_name} = false" if no_recurse}
168
+ end
169
+ end
170
+ end
171
+ RUBY
172
+ end.join("\n")
173
+ Net::HTTP.class_eval patches
174
+ end
175
+
176
+ def format_request_duration(duration_seconds)
177
+ if duration_seconds >= 86400
178
+ # just return 1 day when it takes more than 1 day which should not happen for requests.
179
+ return "%02d.%02d:%02d:%02d.%07d" % [1, 0, 0, 0, 0]
180
+ end
181
+ Time.at(duration_seconds).gmtime.strftime("00.%H:%M:%S.%7N")
182
+ end
183
+
184
+ def self.decorateForOneArgument(klass, methods, name)
185
+ patches = methods.map do |method_name|
186
+ <<~RUBY
187
+ unless defined?(#{method_name}__mp_unpatched)
188
+ alias_method :#{method_name}__mp_unpatched, :#{method_name}
189
+ def #{method_name}(*args, &blk)
190
+ unless prof = Thread.current[:_method_profiler]
191
+ puts 'test1'
192
+ return #{method_name}__mp_unpatched(*args, &blk)
193
+ end
194
+ begin
195
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
196
+ puts 'test2'
197
+ a = __method__.to_s
198
+ argsdata = args.to_s
199
+ puts a
200
+ puts argsdata
201
+ #{method_name}__mp_unpatched(*args, &blk)
202
+ ensure
203
+ data = (prof[:#{name}] ||= {duration: 0.0, calls: 0})
204
+ data[:duration] += Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
205
+ data[:calls] += 1
206
+ end
207
+ end
208
+ end
209
+ RUBY
210
+ end.join("\n")
211
+
212
+ klass.class_eval patches
213
+ end
214
+
215
+ def self.decorateSql(klass, methods, name)
216
+ patches = methods.map do |method_name|
217
+ <<~RUBY
218
+ unless defined?(#{method_name}__mp_unpatched)
219
+ alias_method :#{method_name}__mp_unpatched, :#{method_name}
220
+ def #{method_name}(*args, &blk)
221
+ unless prof = Thread.current[:_method_profiler]
222
+ puts 'test1'
223
+ return #{method_name}__mp_unpatched(*args, &blk)
224
+ end
225
+ begin
226
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
227
+ puts 'test2'
228
+ puts args
229
+ #{method_name}__mp_unpatched(*args, &blk)
230
+ ensure
231
+ data = (prof[:#{name}] ||= {duration: 0.0, calls: 0})
232
+ data[:duration] += Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
233
+ data[:calls] += 1
234
+ end
235
+ end
236
+ end
237
+ RUBY
238
+ end.join("\n")
239
+
240
+ klass.class_eval patches
241
+ end
242
+
243
+ def self.transfer
244
+ result = Thread.current[:_method_profiler]
245
+ Thread.current[:_method_profiler] = nil
246
+ result
247
+ end
248
+
249
+
250
+ def self.start
251
+ Thread.current[:_method_profiler] = transfer || {
252
+ __start: Process.clock_gettime(Process::CLOCK_MONOTONIC)
253
+ }
254
+ puts "GCare Profiling Started"
255
+ end
256
+
257
+ def self.clear
258
+ Thread.current[:_method_profiler] = nil
259
+ end
260
+
261
+ def self.stop
262
+ finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
263
+ if data = Thread.current[:_method_profiler]
264
+ Thread.current[:_method_profiler] = nil
265
+ start = data.delete(:__start)
266
+ data[:total_duration] = finish - start
267
+ data
268
+ end
269
+ puts "GCare Profiling Stopped"
270
+ end
271
+
272
+ def telemetrydata(telemetryversion, name, time, sampleRate, iKey, sdkVersion,
273
+ operation_id, baseType, baseData_ver, baseData_id, gCareID,
274
+ remote_ip, remote_host, forwarding_ip, client_ip, server_host, server_ip, server_hostname,
275
+ useragent, session_id, timestamp, duration, responseCode, success,
276
+ url, httpMethod, version, machine_from_ip, machine_from_name, machine_to_ip,
277
+ machine_to_name, operation_name, roleInstance, server_port)
278
+
279
+ teledata = {
280
+ 'ver' => telemetryversion,
281
+ 'name' => name,
282
+ 'time' => time,
283
+ 'sampleRate' => sampleRate,
284
+ 'iKey' => iKey,
285
+ 'tags' => {
286
+ 'ai' => {
287
+ 'internal.sdkVersion' => sdkVersion,
288
+ 'operation.id' => operation_id,
289
+ 'operation.name' => operation_name,
290
+ 'gcare.id' => gCareID,
291
+ 'device.roleInstance' => roleInstance
292
+ }
293
+ }
294
+ }
295
+ end
296
+
297
+ def send(data_to_send)
298
+ uri = URI(@service_endpoint_uri)
299
+ headers = {
300
+ 'Accept' => 'application/json',
301
+ 'Content-Type' => 'application/json; charset=utf-8'
302
+ }
303
+ #,
304
+ # 'Content-Encoding' => 'gzip' # currently no encryption enabled
305
+ request = Net::HTTP::Post.new(uri.path, headers)
306
+
307
+ # Use JSON.generate instead of to_json, otherwise it will
308
+ # default to ActiveSupport::JSON.encode for Rails app
309
+ json = JSON.generate(data_to_send)
310
+ puts "sending data to CCare Server"
311
+ puts json
312
+ # compressed_data = compress(json)
313
+ request.body = json
314
+
315
+ http = Net::HTTP.new uri.hostname, uri.port #, 'localhost', 8888 # uncomment if proxy is used
316
+ if uri.scheme.downcase == 'https'
317
+ http.use_ssl = true
318
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
319
+ end
320
+
321
+ response = http.request(request)
322
+ http.finish if http.started?
323
+
324
+ if !response.kind_of? Net::HTTPSuccess
325
+ @logger.warn('application_insights') { "Failed to send data: #{response.message}" }
326
+ end
327
+
328
+ end
329
+ end
330
+
metadata ADDED
@@ -0,0 +1,46 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gcarerubymethodprofiler
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Bipin V
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-06-15 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Monitory ruby methods and send telemetry data to GCare Server
14
+ email:
15
+ - bipin.v@gavstech.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - gcarerubymethodprofiler.gemspec
21
+ - lib/gcarerubymethodprofiler.rb
22
+ homepage: http://www.gavstech.com
23
+ licenses:
24
+ - Nonstandard
25
+ metadata: {}
26
+ post_install_message:
27
+ rdoc_options: []
28
+ require_paths:
29
+ - lib
30
+ required_ruby_version: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ required_rubygems_version: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ requirements: []
41
+ rubyforge_project:
42
+ rubygems_version: 2.6.14.4
43
+ signing_key:
44
+ specification_version: 4
45
+ summary: generic method profiler for ruby
46
+ test_files: []