mnemosyne-ruby 0.1.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.
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