raygun-apm 1.1.15.pre3

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.
@@ -0,0 +1,43 @@
1
+ require 'httpclient'
2
+
3
+ module Raygun
4
+ module Apm
5
+ module Hooks
6
+ module HTTPClient
7
+ private
8
+
9
+ def do_request(method, uri, query, body, header, &filtered_block)
10
+ if tracer = Raygun::Apm::Tracer.instance
11
+ started = tracer.now
12
+ response = super
13
+ ended = tracer.now
14
+ event = raygun_apm_http_out_event
15
+ event[:pid] = Process.pid
16
+ event[:url] = raygun_apm_url(uri, query)
17
+ event[:verb] = method.to_s.upcase
18
+ event[:status] = response.code.to_i
19
+ event[:duration] = ended - started
20
+ event[:timestamp] = started
21
+ event[:tid] = tracer.get_thread_id(Thread.current)
22
+ tracer.emit(event)
23
+ response
24
+ else
25
+ super
26
+ end
27
+ end
28
+
29
+ def raygun_apm_url(uri, query)
30
+ uri = uri.to_param if uri.respond_to?(:to_param)
31
+ query = query.to_param if query.respond_to?(:to_param)
32
+ query && uri ? URI.join(uri, query).to_s : uri.to_s
33
+ end
34
+
35
+ def raygun_apm_http_out_event
36
+ @_raygun_apm_http_out_event ||= Raygun::Apm::Event::HttpOut.new
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ Raygun::Apm::Tracer.patch(HTTPClient, Raygun::Apm::Hooks::HTTPClient)
@@ -0,0 +1,95 @@
1
+ require 'thread'
2
+
3
+ module Raygun
4
+ module Apm
5
+ module Hooks
6
+ module Object
7
+ def system(*args)
8
+ super
9
+ end
10
+
11
+ def sleep(*args)
12
+ super
13
+ end
14
+
15
+ def exec(*args)
16
+ super
17
+ end
18
+
19
+ def spawn(*args)
20
+ super
21
+ end
22
+
23
+ def fork(*args)
24
+ super
25
+ end
26
+ end
27
+
28
+ module IO
29
+ def sycall(*args)
30
+ super
31
+ end
32
+
33
+ def open(*args)
34
+ super
35
+ end
36
+
37
+ def puts(*args)
38
+ super
39
+ end
40
+
41
+ def gets(*args)
42
+ super
43
+ end
44
+
45
+ def readline(*args)
46
+ super
47
+ end
48
+
49
+ def readlines(*args)
50
+ super
51
+ end
52
+ end
53
+
54
+ module Random
55
+ def srand(*args)
56
+ super
57
+ end
58
+
59
+ def rand(*args)
60
+ super
61
+ end
62
+ end
63
+
64
+ module Signal
65
+ def trap(*args)
66
+ super
67
+ end
68
+ end
69
+
70
+ module Mutex
71
+ def synchronize(*args)
72
+ super
73
+ end
74
+
75
+ def lock(*args)
76
+ super
77
+ end
78
+
79
+ def unlock(*args)
80
+ super
81
+ end
82
+
83
+ def sleep(*args)
84
+ super
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ Raygun::Apm::Tracer.patch(Object, Raygun::Apm::Hooks::Object)
92
+ Raygun::Apm::Tracer.patch(IO, Raygun::Apm::Hooks::IO)
93
+ Raygun::Apm::Tracer.patch(Random, Raygun::Apm::Hooks::Random)
94
+ Raygun::Apm::Tracer.patch(Signal, Raygun::Apm::Hooks::Signal)
95
+ Raygun::Apm::Tracer.patch(Thread::Mutex, Raygun::Apm::Hooks::Mutex)
@@ -0,0 +1,45 @@
1
+ require 'mongo'
2
+
3
+ module Raygun
4
+ module Apm
5
+ module Hooks
6
+ module MongoDB
7
+ def do_execute(connection, client, options = {})
8
+ result = nil
9
+ if tracer = Raygun::Apm::Tracer.instance
10
+ started = tracer.now
11
+ result = super
12
+ ended = tracer.now
13
+ event = raygun_apm_sql_event
14
+ event[:pid] = Process.pid
15
+ event[:query] = raygun_format_query(connection)
16
+ event[:provider] = "mongodb"
17
+ event[:host] = connection.address.to_s
18
+ event[:database] = client.database.name
19
+ event[:duration] = ended - started
20
+ event[:timestamp] = started
21
+ event[:tid] = tracer.get_thread_id(Thread.current)
22
+ tracer.emit(event)
23
+ result
24
+ else
25
+ super
26
+ end
27
+ end
28
+
29
+ private
30
+ def raygun_format_query(connection)
31
+ payload = message(connection).payload
32
+ return "#{payload["database_name"]}.#{payload["command_name"]} #{payload["command"]}}"
33
+ end
34
+
35
+ def raygun_apm_sql_event
36
+ @_raygun_apm_sql_event ||= Raygun::Apm::Event::Sql.new
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ Mongo::Operation.constants.each do |operation|
44
+ Raygun::Apm::Tracer.patch(Mongo::Operation.const_get(operation), Raygun::Apm::Hooks::MongoDB) rescue nil
45
+ end
@@ -0,0 +1,44 @@
1
+ require 'net/http'
2
+
3
+ module Raygun
4
+ module Apm
5
+ module Hooks
6
+ module Net
7
+ module HTTP
8
+ private
9
+
10
+ def transport_request(request)
11
+ if tracer = Raygun::Apm::Tracer.instance
12
+ started = tracer.now
13
+ response = super
14
+ ended = tracer.now
15
+ event = raygun_apm_http_out_event
16
+ event[:pid] = Process.pid
17
+ event[:url] = raygun_apm_url(request)
18
+ event[:verb] = request.method
19
+ event[:status] = response.code.to_i
20
+ event[:duration] = ended - started
21
+ event[:timestamp] = started
22
+ event[:tid] = tracer.get_thread_id(Thread.current)
23
+ tracer.emit(event)
24
+ response
25
+ else
26
+ super
27
+ end
28
+ end
29
+
30
+ def raygun_apm_url(request)
31
+ return request.uri.to_s if request.uri
32
+ "#{use_ssl? ? "https" : "http"}://#{request["host"] || address}#{request.path}"
33
+ end
34
+
35
+ def raygun_apm_http_out_event
36
+ @_raygun_apm_http_out_event ||= Raygun::Apm::Event::HttpOut.new
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ Raygun::Apm::Tracer.patch(::Net::HTTP, Raygun::Apm::Hooks::Net::HTTP)
@@ -0,0 +1,46 @@
1
+ module Raygun
2
+ module Apm
3
+ module Hooks
4
+ module Redis
5
+ def process(commands)
6
+ result = nil
7
+ if tracer = Raygun::Apm::Tracer.instance
8
+ started = tracer.now
9
+ result = super
10
+ ended = tracer.now
11
+ event = raygun_apm_sql_event
12
+ event[:pid] = Process.pid
13
+ event[:query] = raygun_format_query(commands)
14
+ event[:provider] = "redis"
15
+ event[:host] = "#{host}:#{port}"
16
+ event[:database] = db.to_s
17
+ event[:duration] = ended - started
18
+ event[:timestamp] = started
19
+ event[:tid] = tracer.get_thread_id(Thread.current)
20
+ tracer.emit(event)
21
+ result
22
+ else
23
+ super
24
+ end
25
+ end
26
+
27
+ private
28
+ def raygun_format_query(commands)
29
+ commands.map do |command|
30
+ command.map(&:to_s).join(" ")
31
+ end.join(", ")
32
+ end
33
+
34
+ def raygun_apm_sql_event
35
+ @_raygun_apm_sql_event ||= Raygun::Apm::Event::Sql.new
36
+ end
37
+
38
+ def raygun_redis_call
39
+ yield
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ Raygun::Apm::Tracer.patch(::Redis::Client, Raygun::Apm::Hooks::Redis)
@@ -0,0 +1,131 @@
1
+ require 'raygun/apm/blacklist'
2
+ require 'rbconfig'
3
+
4
+ module Raygun
5
+ module Apm
6
+ class Tracer
7
+ @__mutex = Mutex.new
8
+
9
+ @__pids ||= {}
10
+ class << self
11
+ def synchronize(&block)
12
+ @__mutex.synchronize { block.call }
13
+ end
14
+
15
+ def instance
16
+ @__pids[Process.pid]
17
+ end
18
+
19
+ def instance=(tracer)
20
+ @__pids[Process.pid] = tracer
21
+ end
22
+
23
+ def patch(concern, hook)
24
+ concern.prepend(hook) unless concern.ancestors.include?(hook)
25
+ end
26
+ end
27
+
28
+ attr_accessor :config
29
+
30
+ def initialize(env=ENV)
31
+ configure(env)
32
+ initialize_blacklist
33
+ register_known_library_paths
34
+ run_agent_connectivity_diagnostics
35
+ require_hooks
36
+ ObjectSpace.define_finalizer(self, proc{ disable_tracepoints })
37
+ # Any fails here is kamikaze for the tracer
38
+ rescue => e
39
+ # XXX works for the middleware wrapped case, not for standalone - revisit
40
+ raise Raygun::Apm::FatalError, "Raygun APM tracer could not be initialized: #{e.message} #{e.backtrace.join("\n")}"
41
+ end
42
+
43
+ def udp_sink!
44
+ sock = UDPSocket.new
45
+ # For UDP sockets, SO_SNDBUF is the max packet size and NOT send buffer as with a connection oriented transport
46
+ sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF, Tracer::BATCH_PACKET_SIZE)
47
+ self.udp_sink(
48
+ socket: sock,
49
+ host: config.proton_udp_host,
50
+ port: config.proton_udp_port,
51
+ receive_buffer_size: sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_RCVBUF).int
52
+ )
53
+ rescue => e
54
+ # XXX works for the middleware wrapped case, not for standalone - revisit
55
+ raise Raygun::Apm::FatalError, "Raygun APM UDP sink could not be initialized: #{e.message} #{e.backtrace.join("\n")}"
56
+ end
57
+
58
+ def tcp_sink!
59
+ self.tcp_sink(
60
+ host: config.proton_tcp_host,
61
+ port: config.proton_tcp_port
62
+ )
63
+ rescue => e
64
+ # XXX works for the middleware wrapped case, not for standalone - revisit
65
+ raise Raygun::Apm::FatalError, "Raygun APM TCP sink could not be initialized: #{e.message} #{e.backtrace.join("\n")}"
66
+ end
67
+
68
+ def enable_sink!
69
+ if config.proton_network_mode == "Udp"
70
+ udp_sink!
71
+ elsif config.proton_network_mode == "Tcp"
72
+ tcp_sink!
73
+ end
74
+ end
75
+
76
+ private
77
+ def configure(env)
78
+ @config = Config.new(env)
79
+ # Special assignments from config to the Tracer
80
+ self.log_level = config.loglevel
81
+ self.environment = config.environment
82
+ self.api_key = config.proton_api_key
83
+ end
84
+
85
+ def initialize_blacklist
86
+ @blacklist_parser = Raygun::Apm::Blacklist::Parser.new(self)
87
+ file = @config.blacklist_file
88
+ @blacklist = if file && File.exist?(file)
89
+ File.readlines(file)
90
+ else
91
+ []
92
+ end
93
+ # Defaults
94
+ @blacklist_parser.add_filters Raygun::Apm::Blacklist.resolve_entries
95
+ # From file
96
+ @blacklist_parser.add_filters @blacklist
97
+ end
98
+
99
+ def register_known_library_paths
100
+ if defined?(Bundler)
101
+ libs = Bundler.load.specs.map(&:full_gem_path).sort << RbConfig::CONFIG['rubylibdir']
102
+ libs.delete(Dir.getwd)
103
+ self.register_libraries libs
104
+ else
105
+ self.register_libraries [RbConfig::CONFIG['rubylibdir']]
106
+ end
107
+ end
108
+
109
+ def run_agent_connectivity_diagnostics
110
+ check = Raygun::Apm::Diagnostics.new
111
+ check.verify_agent(self)
112
+ end
113
+
114
+ def require_hooks
115
+ require "raygun/apm/hooks/internals" if @config.proton_hook_internals
116
+ require "raygun/apm/hooks/net_http"
117
+ # conditionally required - may not be bundled
118
+ conditional_hooks = %w(httpclient excon mongodb)
119
+ conditional_hooks.each do |hook|
120
+ begin
121
+ require "raygun/apm/hooks/#{hook}"
122
+ rescue LoadError
123
+ end
124
+ end
125
+ if @config.proton_hook_redis
126
+ require "raygun/apm/hooks/redis" if defined?(Redis::Client)
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,6 @@
1
+ module Raygun
2
+ module Apm
3
+ VERSION = "1.1.15.pre3"
4
+ MINIMUM_AGENT_VERSION = "1.0.1190.0"
5
+ end
6
+ end
data/lib/raygun/apm.rb ADDED
@@ -0,0 +1,18 @@
1
+ require "raygun/apm/version"
2
+ require "socket"
3
+
4
+ begin
5
+ # Attempt to load a precompiled shared object (released gem)
6
+ RUBY_VERSION =~ /(\d+\.\d+)/
7
+ require "raygun/#{$1}/raygun_ext"
8
+ rescue LoadError
9
+ # Attempt to load the development specific extension (non-released gem, local dev)
10
+ require "raygun/raygun_ext"
11
+ end
12
+
13
+ require "raygun/apm/config"
14
+ require "raygun/apm/diagnostics"
15
+ require "raygun/apm/blacklist/parser"
16
+ require "raygun/apm/blacklist/translator"
17
+ require "raygun/apm/tracer"
18
+ require "raygun/apm/event"
@@ -0,0 +1,43 @@
1
+
2
+ require File.expand_path('../lib/raygun/apm/version', __FILE__)
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "raygun-apm"
6
+ spec.version = Raygun::Apm::VERSION
7
+
8
+ spec.authors = ["Raygun Limited"]
9
+ spec.email = ["ruby-apm@raygun.io", "support@raygun.com"]
10
+
11
+ spec.summary = %q{Raygun application performance monitoring core Profiler}
12
+ spec.homepage = "https://raygun.com/platform/apm"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = Dir['README.rdoc', 'raygun-apm.gemspec', 'LICENSE', 'LICENSE.bipbuffer', 'COPYING.rax', 'lib/**/*', 'bin/**/*'].reject { |f| f.match(/raygun_ext\./) }
16
+ spec.files += Dir['lib/raygun/**/{2}*/raygun_ext.*']
17
+ spec.bindir = "bin"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib", "ext"]
20
+
21
+ spec.platform = Gem::Platform::RUBY
22
+
23
+ spec.extensions = ["ext/raygun/extconf.rb"]
24
+ spec.required_ruby_version = '>= 3.0.0'
25
+
26
+ # Required at runtime for native extension compilation against Ruby VM internals
27
+ spec.add_dependency "debase-ruby_core_source", ">= 3.3.6"
28
+
29
+ spec.add_development_dependency "debase-ruby_core_source", ">= 3.3.6"
30
+ spec.add_development_dependency "bundler", ">= 2.2.15"
31
+ spec.add_development_dependency "rake", "~> 13.0.3"
32
+ spec.add_development_dependency "minitest", "~> 5.16"
33
+ spec.add_development_dependency "rake-compiler", "~> 1.1.1"
34
+ spec.add_development_dependency "rake-compiler-dock", "~> 1.11.0"
35
+ spec.add_development_dependency "benchmark_driver", "~> 0.15.9"
36
+ spec.add_development_dependency "faraday", "~> 1.0.1"
37
+ spec.add_development_dependency "multipart-post", "~> 2.1.1"
38
+ spec.add_development_dependency "rest-client", "~> 2.1.0"
39
+ spec.add_development_dependency "excon", "~> 0.73.0"
40
+ spec.add_development_dependency "httparty", "~> 0.18.0"
41
+ spec.add_development_dependency "httpclient", "~> 2.8.3"
42
+ spec.add_development_dependency "mongoid", "~> 7.1.2"
43
+ end