mnemosyne-ruby 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +50 -0
  5. data/.travis.yml +6 -0
  6. data/Gemfile +5 -0
  7. data/LICENSE +21 -0
  8. data/README.md +36 -0
  9. data/Rakefile +7 -0
  10. data/lib/mnemosyne/client.rb +48 -0
  11. data/lib/mnemosyne/clock.rb +15 -0
  12. data/lib/mnemosyne/config.rb +53 -0
  13. data/lib/mnemosyne/global.rb +13 -0
  14. data/lib/mnemosyne/instrumenter.rb +111 -0
  15. data/lib/mnemosyne/middleware/acfs.rb +46 -0
  16. data/lib/mnemosyne/middleware/rack.rb +93 -0
  17. data/lib/mnemosyne/middleware/restify.rb +50 -0
  18. data/lib/mnemosyne/probe.rb +37 -0
  19. data/lib/mnemosyne/probes/acfs/request.rb +40 -0
  20. data/lib/mnemosyne/probes/action_controller/process_action.rb +34 -0
  21. data/lib/mnemosyne/probes/action_controller/renderers.rb +42 -0
  22. data/lib/mnemosyne/probes/action_view/render_partial.rb +26 -0
  23. data/lib/mnemosyne/probes/action_view/render_template.rb +26 -0
  24. data/lib/mnemosyne/probes/active_record/query.rb +34 -0
  25. data/lib/mnemosyne/probes/grape/endpoint_render.rb +31 -0
  26. data/lib/mnemosyne/probes/grape/endpoint_run.rb +31 -0
  27. data/lib/mnemosyne/probes/grape/endpoint_run_filters.rb +31 -0
  28. data/lib/mnemosyne/probes/mnemosyne/tracer.rb +26 -0
  29. data/lib/mnemosyne/probes/responder/respond.rb +43 -0
  30. data/lib/mnemosyne/probes/restify/em.rb +29 -0
  31. data/lib/mnemosyne/probes/restify/typhoeus.rb +29 -0
  32. data/lib/mnemosyne/probes.rb +90 -0
  33. data/lib/mnemosyne/railtie.rb +25 -0
  34. data/lib/mnemosyne/span.rb +36 -0
  35. data/lib/mnemosyne/trace.rb +46 -0
  36. data/lib/mnemosyne/version.rb +16 -0
  37. data/lib/mnemosyne.rb +44 -0
  38. data/mnemosyne-ruby.gemspec +29 -0
  39. data/scripts/console +15 -0
  40. data/scripts/setup +8 -0
  41. metadata +168 -0
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mnemosyne
4
+ module Probes
5
+ module ActionController
6
+ module ProcessAction
7
+ class Probe < ::Mnemosyne::Probe
8
+ subscribe 'process_action.action_controller'
9
+
10
+ # rubocop:disable Metrics/ParameterLists
11
+ def call(trace, _name, start, finish, _id, payload)
12
+ start = ::Mnemosyne::Clock.to_tick(start)
13
+ finish = ::Mnemosyne::Clock.to_tick(finish)
14
+
15
+ meta = {
16
+ controller: payload[:controller],
17
+ action: payload[:action],
18
+ format: payload[:format]
19
+ }
20
+
21
+ span = ::Mnemosyne::Span.new 'app.controller.request.rails',
22
+ start: start, finish: finish, meta: meta
23
+
24
+ trace << span
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ register 'ActionController::Base',
31
+ 'action_controller',
32
+ ActionController::ProcessAction::Probe.new
33
+ end
34
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mnemosyne
4
+ module Probes
5
+ module ActionController
6
+ module Renderers
7
+ CATEGORY = 'render_to_body.renderers.action_controller'.freeze
8
+
9
+ class Probe < ::Mnemosyne::Probe
10
+ subscribe CATEGORY
11
+
12
+ def setup
13
+ ::ActionController::Base.prepend Instrumentation
14
+ end
15
+
16
+ # rubocop:disable Metrics/ParameterLists
17
+ def call(trace, _name, start, finish, _id, _payload)
18
+ start = ::Mnemosyne::Clock.to_tick(start)
19
+ finish = ::Mnemosyne::Clock.to_tick(finish)
20
+
21
+ span = ::Mnemosyne::Span.new 'app.controller.renderers.rails',
22
+ start: start, finish: finish
23
+
24
+ trace << span
25
+ end
26
+ end
27
+
28
+ module Instrumentation
29
+ def render_to_body(*args, &block)
30
+ ::ActiveSupport::Notifications.instrument CATEGORY do
31
+ super
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ register 'ActionController::Base',
39
+ 'action_controller/metal/renderers',
40
+ ActionController::Renderers::Probe.new
41
+ end
42
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mnemosyne
4
+ module Probes
5
+ module ActionView
6
+ module RenderPartial
7
+ class Probe < ::Mnemosyne::Probe
8
+ subscribe 'render_partial.action_view'
9
+
10
+ # rubocop:disable Metrics/ParameterLists
11
+ def call(trace, _name, start, finish, _id, payload)
12
+ start = ::Mnemosyne::Clock.to_tick(start)
13
+ finish = ::Mnemosyne::Clock.to_tick(finish)
14
+
15
+ span = ::Mnemosyne::Span.new 'view.render.template.rails',
16
+ start: start, finish: finish, meta: payload
17
+
18
+ trace << span
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ register nil, nil, ActionView::RenderPartial::Probe.new
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mnemosyne
4
+ module Probes
5
+ module ActionView
6
+ module RenderTemplate
7
+ class Probe < ::Mnemosyne::Probe
8
+ subscribe 'render_template.action_view'
9
+
10
+ # rubocop:disable Metrics/ParameterLists
11
+ def call(trace, _name, start, finish, _id, payload)
12
+ start = ::Mnemosyne::Clock.to_tick(start)
13
+ finish = ::Mnemosyne::Clock.to_tick(finish)
14
+
15
+ span = ::Mnemosyne::Span.new 'view.render.template.rails',
16
+ start: start, finish: finish, meta: payload
17
+
18
+ trace << span
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ register nil, nil, ActionView::RenderTemplate::Probe.new
25
+ end
26
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mnemosyne
4
+ module Probes
5
+ module ActiveRecord
6
+ module Query
7
+ class Probe < ::Mnemosyne::Probe
8
+ subscribe 'sql.active_record'
9
+
10
+ # rubocop:disable Metrics/ParameterLists
11
+ def call(trace, _name, start, finish, _id, payload)
12
+ return if payload[:name] == 'SCHEMA' || payload[:name] == 'CACHE'
13
+
14
+ start = ::Mnemosyne::Clock.to_tick(start)
15
+ finish = ::Mnemosyne::Clock.to_tick(finish)
16
+
17
+ meta = {
18
+ sql: payload[:sql]
19
+ }
20
+
21
+ span = ::Mnemosyne::Span.new 'db.query.active_record',
22
+ start: start, finish: finish, meta: meta
23
+
24
+ trace << span
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ register 'ActiveRecord::Base',
31
+ 'active_record',
32
+ ActiveRecord::Query::Probe.new
33
+ end
34
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mnemosyne
4
+ module Probes
5
+ module Grape
6
+ module EndpointRender
7
+ class Probe < ::Mnemosyne::Probe
8
+ subscribe 'endpoint_render.grape'
9
+
10
+ # rubocop:disable Metrics/ParameterLists
11
+ def call(trace, _name, start, finish, _id, payload)
12
+ start = ::Mnemosyne::Clock.to_tick(start)
13
+ finish = ::Mnemosyne::Clock.to_tick(finish)
14
+
15
+ endpoint = payload[:endpoint]
16
+ return unless endpoint
17
+
18
+ span = ::Mnemosyne::Span.new 'view.render.grape',
19
+ start: start, finish: finish
20
+
21
+ trace << span
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ register 'Grape::Endpoint',
28
+ 'grape/endpoint',
29
+ Grape::EndpointRender::Probe.new
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mnemosyne
4
+ module Probes
5
+ module Grape
6
+ module EndpointRun
7
+ class Probe < ::Mnemosyne::Probe
8
+ subscribe 'endpoint_run.grape'
9
+
10
+ # rubocop:disable Metrics/ParameterLists
11
+ def call(trace, _name, start, finish, _id, payload)
12
+ start = ::Mnemosyne::Clock.to_tick(start)
13
+ finish = ::Mnemosyne::Clock.to_tick(finish)
14
+
15
+ endpoint = payload[:endpoint]
16
+ return unless endpoint
17
+
18
+ span = ::Mnemosyne::Span.new 'app.controller.request.grape',
19
+ start: start, finish: finish
20
+
21
+ trace << span
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ register 'Grape::Endpoint',
28
+ 'grape/endpoint',
29
+ Grape::EndpointRun::Probe.new
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mnemosyne
4
+ module Probes
5
+ module Grape
6
+ module EndpointRunFilters
7
+ class Probe < ::Mnemosyne::Probe
8
+ subscribe 'endpoint_run_filters.grape'
9
+
10
+ # rubocop:disable Metrics/ParameterLists
11
+ def call(trace, _name, start, finish, _id, payload)
12
+ start = ::Mnemosyne::Clock.to_tick(start)
13
+ finish = ::Mnemosyne::Clock.to_tick(finish)
14
+
15
+ endpoint = payload[:endpoint]
16
+ return unless endpoint
17
+
18
+ span = ::Mnemosyne::Span.new 'app.controller.filter.grape',
19
+ start: start, finish: finish
20
+
21
+ trace << span
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ register 'Grape::Endpoint',
28
+ 'grape/endpoint',
29
+ Grape::EndpointRunFilters::Probe.new
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mnemosyne
4
+ module Probes
5
+ module Mnemosyne
6
+ module Tracer
7
+ class Probe < ::Mnemosyne::Probe
8
+ subscribe 'trace.mnemosyne'
9
+
10
+ # rubocop:disable Metrics/ParameterLists
11
+ def call(trace, _name, start, finish, _id, payload)
12
+ start = ::Mnemosyne::Clock.to_tick(start)
13
+ finish = ::Mnemosyne::Clock.to_tick(finish)
14
+
15
+ span = ::Mnemosyne::Span.new 'custom.trace',
16
+ start: start, finish: finish, meta: payload
17
+
18
+ trace << span
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ register nil, nil, Mnemosyne::Tracer::Probe.new
25
+ end
26
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mnemosyne
4
+ module Probes
5
+ module Responder
6
+ module Respond
7
+ class Probe < ::Mnemosyne::Probe
8
+ subscribe 'respond.responders.mnemosyne'
9
+
10
+ def setup
11
+ ::ActionController::Responder.prepend \
12
+ ::Mnemosyne::Probes::Responder::Respond::Instrumentation
13
+ end
14
+
15
+ # rubocop:disable Metrics/ParameterLists
16
+ def call(trace, _name, start, finish, _id, _payload)
17
+ start = ::Mnemosyne::Clock.to_tick(start)
18
+ finish = ::Mnemosyne::Clock.to_tick(finish)
19
+
20
+ span = ::Mnemosyne::Span.new 'app.responder.respond',
21
+ start: start, finish: finish
22
+
23
+ trace << span
24
+ end
25
+ end
26
+
27
+ module Instrumentation
28
+ def respond
29
+ ::ActiveSupport::Notifications.instrument \
30
+ 'respond.responders.mnemosyne' do
31
+
32
+ super
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ register 'ActionController::Responder',
40
+ 'action_controller/responder',
41
+ Responder::Respond::Probe.new
42
+ end
43
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mnemosyne
4
+ module Probes
5
+ module Restify
6
+ module EM
7
+ class Probe < ::Mnemosyne::Probe
8
+ def setup
9
+ require 'mnemosyne/middleware/restify'
10
+
11
+ ::Restify::Adapter::EM::Connection.prepend Instrumentation
12
+ end
13
+
14
+ module Instrumentation
15
+ def call(request, writer, *args)
16
+ ::Mnemosyne::Middleware::Restify.call(request, writer) do |r, w|
17
+ super(r, w, *args)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ register 'Restify::Adapter::EM::Connection',
26
+ 'restify/adapter/em',
27
+ Restify::EM::Probe.new
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mnemosyne
4
+ module Probes
5
+ module Restify
6
+ module Typhoeus
7
+ class Probe < ::Mnemosyne::Probe
8
+ def setup
9
+ require 'mnemosyne/middleware/restify'
10
+
11
+ ::Restify::Adapter::Typhoeus.prepend Instrumentation
12
+ end
13
+
14
+ module Instrumentation
15
+ def queue(request, writer)
16
+ ::Mnemosyne::Middleware::Restify.call(request, writer) do |r, w|
17
+ super(r, w)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ register 'Restify::Adapter::Typhoeus',
26
+ 'restify/adapter/typhoeus',
27
+ Restify::Typhoeus::Probe.new
28
+ end
29
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+ require 'forwardable'
3
+
4
+ module Mnemosyne
5
+ module Probes
6
+ class Registration
7
+ extend ::Forwardable
8
+
9
+ attr_reader :class_name, :require_paths
10
+
11
+ def initialize(class_name, require_paths, probe)
12
+ @class_name = class_name
13
+ @require_paths = Array require_paths
14
+ @probe = probe
15
+ end
16
+
17
+ def installable?
18
+ return true unless class_name
19
+
20
+ ::Mnemosyne::Probes.class_available? class_name
21
+ end
22
+
23
+ delegate install: :@probe
24
+ end
25
+
26
+ class << self
27
+ def class_available?(class_name)
28
+ Module.const_get(class_name).is_a? Class
29
+ rescue NameError
30
+ false
31
+ end
32
+
33
+ def register(*args)
34
+ registration = Registration.new(*args)
35
+
36
+ if registration.installable?
37
+ registration.install
38
+ else
39
+ register_require_hook registration
40
+ end
41
+ end
42
+
43
+ def require_hook(name)
44
+ registration = require_hooks[name]
45
+ return unless registration
46
+ return unless registration.installable?
47
+
48
+ registration.install
49
+
50
+ unregister_require_hook registration
51
+ end
52
+
53
+ def register_require_hook(registration)
54
+ registration.require_paths.each do |path|
55
+ require_hooks[path] = registration
56
+ end
57
+ end
58
+
59
+ def unregister_require_hook(registration)
60
+ registration.require_paths.each do |path|
61
+ require_hooks.delete path
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def require_hooks
68
+ @require_hooks ||= {}
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ module Kernel
75
+ alias require_without_mn require
76
+
77
+ def require(name)
78
+ ret = require_without_mn(name)
79
+
80
+ # rubocop:disable Lint/RescueException
81
+ begin
82
+ ::Mnemosyne::Probes.require_hook(name)
83
+
84
+ # rubocop:disable Lint/HandleExceptions
85
+ rescue Exception
86
+ end
87
+
88
+ ret
89
+ end
90
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ require 'rails'
3
+
4
+ module Mnemosyne
5
+ class Railtie < ::Rails::Railtie
6
+ initializer 'mnemosyne.initialize' do |app|
7
+ config = app.config_for('mnemosyne')
8
+
9
+ config['application'] ||= app.class.name.underscore.titleize
10
+
11
+ # config['logger'] = Rails.logger
12
+ config['enabled'] ||= config.key?('server')
13
+
14
+ config = ::Mnemosyne::Config.new(config)
15
+
16
+ if config.enabled?
17
+ ::Mnemosyne::Instrumenter.start!(config)
18
+
19
+ app.middleware.insert 0, ::Mnemosyne::Middleware::Rack
20
+ else
21
+ config.logger.warn '[MNEMOSYNE] Instrumenter not enabled.'
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mnemosyne
4
+ class Span
5
+ attr_reader :uuid, :name, :start, :finish, :meta
6
+
7
+ def initialize(name, start: false, finish: false, meta: {})
8
+ @name = name
9
+ @meta = meta
10
+ @uuid = ::SecureRandom.uuid
11
+
12
+ @start = start
13
+ @finish = finish
14
+ end
15
+
16
+ def start!
17
+ @start = ::Mnemosyne::Clock.tick
18
+ self
19
+ end
20
+
21
+ def finish!
22
+ @finish = ::Mnemosyne::Clock.tick
23
+ self
24
+ end
25
+
26
+ def serialize
27
+ {
28
+ uuid: uuid,
29
+ name: name,
30
+ start: start,
31
+ stop: finish,
32
+ meta: meta
33
+ }
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mnemosyne
4
+ class Trace < Span
5
+ attr_reader :uuid, :transaction, :origin
6
+
7
+ def initialize(instrumenter, name, transaction: nil, origin: nil)
8
+ super name
9
+
10
+ @uuid = ::SecureRandom.uuid
11
+ @span = []
12
+
13
+ @origin = origin
14
+ @transaction = transaction
15
+
16
+ @instrumenter = instrumenter
17
+ end
18
+
19
+ def <<(span)
20
+ @span << span
21
+ end
22
+
23
+ def submit
24
+ finish! unless finish
25
+
26
+ @instrumenter.submit self
27
+ end
28
+
29
+ def release
30
+ @instrumenter.release self
31
+ end
32
+
33
+ def serialize
34
+ {
35
+ uuid: uuid,
36
+ origin: origin,
37
+ transaction: transaction,
38
+ name: name,
39
+ start: start,
40
+ stop: finish,
41
+ meta: meta,
42
+ span: @span.map(&:serialize)
43
+ }
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mnemosyne
4
+ module VERSION
5
+ MAJOR = 0
6
+ MINOR = 1
7
+ PATCH = 0
8
+ STAGE = nil
9
+
10
+ STRING = [MAJOR, MINOR, PATCH, STAGE].reject(&:nil?).join('.')
11
+
12
+ def self.to_s
13
+ STRING
14
+ end
15
+ end
16
+ end
data/lib/mnemosyne.rb ADDED
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+ require 'mnemosyne/version'
3
+
4
+ require 'active_support'
5
+ require 'active_support/notifications'
6
+
7
+ module Mnemosyne
8
+ require 'mnemosyne/global'
9
+ extend Global
10
+
11
+ require 'mnemosyne/clock'
12
+ require 'mnemosyne/span'
13
+ require 'mnemosyne/trace'
14
+
15
+ require 'mnemosyne/config'
16
+ require 'mnemosyne/client'
17
+ require 'mnemosyne/instrumenter'
18
+
19
+ require 'mnemosyne/probe'
20
+ require 'mnemosyne/probes'
21
+
22
+ module Probes
23
+ require 'mnemosyne/probes/mnemosyne/tracer'
24
+
25
+ require 'mnemosyne/probes/acfs/request'
26
+ require 'mnemosyne/probes/action_controller/process_action'
27
+ require 'mnemosyne/probes/action_controller/renderers'
28
+ require 'mnemosyne/probes/action_view/render_partial'
29
+ require 'mnemosyne/probes/action_view/render_template'
30
+ require 'mnemosyne/probes/active_record/query'
31
+ require 'mnemosyne/probes/grape/endpoint_render'
32
+ require 'mnemosyne/probes/grape/endpoint_run'
33
+ require 'mnemosyne/probes/grape/endpoint_run_filters'
34
+ require 'mnemosyne/probes/responder/respond'
35
+ require 'mnemosyne/probes/restify/em'
36
+ require 'mnemosyne/probes/restify/typhoeus'
37
+ end
38
+
39
+ module Middleware
40
+ require 'mnemosyne/middleware/rack'
41
+ end
42
+
43
+ require 'mnemosyne/railtie' if defined?(Rails)
44
+ end
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ # frozen_string_literal: true
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'mnemosyne/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'mnemosyne-ruby'
9
+ spec.version = Mnemosyne::VERSION
10
+ spec.authors = ['Jan Graichen']
11
+ spec.email = ['jgraichen@altimos.de']
12
+
13
+ spec.summary = 'Ruby/Rails client for Mnemosynce'
14
+ spec.homepage = 'http://github.com/jgraichen/mnemosyne-ruby'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject {|f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = 'bin'
19
+ spec.executables = spec.files.grep(%r{^exe/}) {|f| File.basename(f) }
20
+ spec.require_paths = %w(lib)
21
+
22
+ spec.add_runtime_dependency 'bunny'
23
+ spec.add_runtime_dependency 'activesupport', '>= 4'
24
+
25
+ spec.add_development_dependency 'bundler', '~> 1.11'
26
+ spec.add_development_dependency 'rake', '~> 10.0'
27
+ spec.add_development_dependency 'rspec', '~> 3.0'
28
+ spec.add_development_dependency 'timecop', '~> 0.8.0'
29
+ end