skylight-core 2.0.0.beta1

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 (86) hide show
  1. checksums.yaml +7 -0
  2. data/lib/skylight/core/config.rb +454 -0
  3. data/lib/skylight/core/errors.rb +6 -0
  4. data/lib/skylight/core/fanout.rb +44 -0
  5. data/lib/skylight/core/formatters/http.rb +23 -0
  6. data/lib/skylight/core/gc.rb +107 -0
  7. data/lib/skylight/core/instrumentable.rb +144 -0
  8. data/lib/skylight/core/instrumenter.rb +249 -0
  9. data/lib/skylight/core/middleware.rb +101 -0
  10. data/lib/skylight/core/normalizers/action_controller/process_action.rb +50 -0
  11. data/lib/skylight/core/normalizers/action_controller/send_file.rb +50 -0
  12. data/lib/skylight/core/normalizers/action_view/render_collection.rb +22 -0
  13. data/lib/skylight/core/normalizers/action_view/render_partial.rb +21 -0
  14. data/lib/skylight/core/normalizers/action_view/render_template.rb +21 -0
  15. data/lib/skylight/core/normalizers/active_job/enqueue_at.rb +21 -0
  16. data/lib/skylight/core/normalizers/active_model_serializers/render.rb +26 -0
  17. data/lib/skylight/core/normalizers/active_record/instantiation.rb +17 -0
  18. data/lib/skylight/core/normalizers/active_record/sql.rb +33 -0
  19. data/lib/skylight/core/normalizers/active_support/cache.rb +20 -0
  20. data/lib/skylight/core/normalizers/active_support/cache_clear.rb +16 -0
  21. data/lib/skylight/core/normalizers/active_support/cache_decrement.rb +16 -0
  22. data/lib/skylight/core/normalizers/active_support/cache_delete.rb +16 -0
  23. data/lib/skylight/core/normalizers/active_support/cache_exist.rb +16 -0
  24. data/lib/skylight/core/normalizers/active_support/cache_fetch_hit.rb +16 -0
  25. data/lib/skylight/core/normalizers/active_support/cache_generate.rb +16 -0
  26. data/lib/skylight/core/normalizers/active_support/cache_increment.rb +16 -0
  27. data/lib/skylight/core/normalizers/active_support/cache_read.rb +16 -0
  28. data/lib/skylight/core/normalizers/active_support/cache_read_multi.rb +16 -0
  29. data/lib/skylight/core/normalizers/active_support/cache_write.rb +16 -0
  30. data/lib/skylight/core/normalizers/coach/handler_finish.rb +36 -0
  31. data/lib/skylight/core/normalizers/coach/middleware_finish.rb +23 -0
  32. data/lib/skylight/core/normalizers/couch_potato/query.rb +20 -0
  33. data/lib/skylight/core/normalizers/data_mapper/sql.rb +12 -0
  34. data/lib/skylight/core/normalizers/default.rb +27 -0
  35. data/lib/skylight/core/normalizers/elasticsearch/request.rb +20 -0
  36. data/lib/skylight/core/normalizers/faraday/request.rb +37 -0
  37. data/lib/skylight/core/normalizers/grape/endpoint.rb +30 -0
  38. data/lib/skylight/core/normalizers/grape/endpoint_render.rb +26 -0
  39. data/lib/skylight/core/normalizers/grape/endpoint_run.rb +33 -0
  40. data/lib/skylight/core/normalizers/grape/endpoint_run_filters.rb +23 -0
  41. data/lib/skylight/core/normalizers/moped/query.rb +100 -0
  42. data/lib/skylight/core/normalizers/sequel/sql.rb +12 -0
  43. data/lib/skylight/core/normalizers/sql.rb +49 -0
  44. data/lib/skylight/core/normalizers.rb +170 -0
  45. data/lib/skylight/core/probes/action_controller.rb +31 -0
  46. data/lib/skylight/core/probes/action_view.rb +37 -0
  47. data/lib/skylight/core/probes/active_model_serializers.rb +55 -0
  48. data/lib/skylight/core/probes/elasticsearch.rb +37 -0
  49. data/lib/skylight/core/probes/excon/middleware.rb +72 -0
  50. data/lib/skylight/core/probes/excon.rb +26 -0
  51. data/lib/skylight/core/probes/faraday.rb +22 -0
  52. data/lib/skylight/core/probes/grape.rb +80 -0
  53. data/lib/skylight/core/probes/httpclient.rb +46 -0
  54. data/lib/skylight/core/probes/middleware.rb +58 -0
  55. data/lib/skylight/core/probes/mongo.rb +171 -0
  56. data/lib/skylight/core/probes/mongoid.rb +21 -0
  57. data/lib/skylight/core/probes/moped.rb +39 -0
  58. data/lib/skylight/core/probes/net_http.rb +64 -0
  59. data/lib/skylight/core/probes/redis.rb +71 -0
  60. data/lib/skylight/core/probes/sequel.rb +33 -0
  61. data/lib/skylight/core/probes/sinatra.rb +69 -0
  62. data/lib/skylight/core/probes/tilt.rb +27 -0
  63. data/lib/skylight/core/probes.rb +129 -0
  64. data/lib/skylight/core/railtie.rb +166 -0
  65. data/lib/skylight/core/subscriber.rb +124 -0
  66. data/lib/skylight/core/test.rb +98 -0
  67. data/lib/skylight/core/trace.rb +190 -0
  68. data/lib/skylight/core/user_config.rb +61 -0
  69. data/lib/skylight/core/util/allocation_free.rb +26 -0
  70. data/lib/skylight/core/util/clock.rb +56 -0
  71. data/lib/skylight/core/util/deploy.rb +132 -0
  72. data/lib/skylight/core/util/gzip.rb +21 -0
  73. data/lib/skylight/core/util/inflector.rb +112 -0
  74. data/lib/skylight/core/util/logging.rb +127 -0
  75. data/lib/skylight/core/util/platform.rb +77 -0
  76. data/lib/skylight/core/util/proxy.rb +13 -0
  77. data/lib/skylight/core/util.rb +14 -0
  78. data/lib/skylight/core/vendor/active_support/notifications.rb +207 -0
  79. data/lib/skylight/core/vendor/active_support/per_thread_registry.rb +52 -0
  80. data/lib/skylight/core/vendor/thread_safe/non_concurrent_cache_backend.rb +133 -0
  81. data/lib/skylight/core/vendor/thread_safe/synchronized_cache_backend.rb +76 -0
  82. data/lib/skylight/core/vendor/thread_safe.rb +126 -0
  83. data/lib/skylight/core/version.rb +6 -0
  84. data/lib/skylight/core/vm/gc.rb +70 -0
  85. data/lib/skylight/core.rb +99 -0
  86. metadata +254 -0
@@ -0,0 +1,56 @@
1
+ module Skylight::Core
2
+ module Util
3
+ # A more precise clock
4
+ class Clock
5
+
6
+ def self.use_native!
7
+ class_eval do
8
+ def tick
9
+ native_hrtime
10
+ end
11
+ end
12
+ end
13
+
14
+ def tick
15
+ now = Time.now
16
+ now.to_i * 1_000_000_000 + now.usec * 1_000
17
+ end
18
+
19
+ # TODO: rename to secs
20
+ def absolute_secs
21
+ Time.now.to_i
22
+ end
23
+
24
+ # TODO: remove
25
+ def nanos
26
+ tick
27
+ end
28
+
29
+ # TODO: remove
30
+ def secs
31
+ nanos / 1_000_000_000
32
+ end
33
+
34
+ def self.absolute_secs
35
+ default.absolute_secs
36
+ end
37
+
38
+ def self.nanos
39
+ default.nanos
40
+ end
41
+
42
+ def self.secs
43
+ default.secs
44
+ end
45
+
46
+ def self.default
47
+ @clock ||= Clock.new
48
+ end
49
+
50
+ def self.default=(clock)
51
+ @clock = clock
52
+ end
53
+
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,132 @@
1
+ require 'json'
2
+ require 'uri'
3
+ require 'skylight/core/util/logging'
4
+
5
+ module Skylight::Core
6
+ module Util
7
+
8
+ module Deploy
9
+
10
+ def self.build(config)
11
+ DEPLOY_TYPES.each do |type|
12
+ deploy = type.new(config)
13
+ return deploy if deploy.id
14
+ end
15
+ nil
16
+ end
17
+
18
+ class EmptyDeploy
19
+
20
+ attr_reader :config
21
+ attr_reader :timestamp
22
+
23
+ def initialize(config)
24
+ @config = config
25
+ @timestamp = Time.now.to_i
26
+ end
27
+
28
+ def id
29
+ git_sha
30
+ end
31
+
32
+ def git_sha
33
+ nil
34
+ end
35
+
36
+ def description
37
+ nil
38
+ end
39
+
40
+ def to_query_string
41
+ URI.encode_www_form(
42
+ timestamp: timestamp,
43
+ deploy_id: id.to_s[0..100], # Keep this sane
44
+ git_sha: git_sha ? git_sha[0..40] : nil, # A valid SHA will never exceed 40
45
+ description: description ? description[0..255] : nil) # Avoid massive descriptions
46
+ end
47
+
48
+ end
49
+
50
+ class DefaultDeploy < EmptyDeploy
51
+ include Logging
52
+
53
+ def initialize(*)
54
+ super
55
+ if description && !id
56
+ warn "The configured deploy will be ignored as an id or git_sha must be provided."
57
+ end
58
+ end
59
+
60
+ def id
61
+ config.get(:'deploy.id') || git_sha
62
+ end
63
+
64
+ def git_sha
65
+ config.get(:'deploy.git_sha')
66
+ end
67
+
68
+ def description
69
+ config.get(:'deploy.description')
70
+ end
71
+
72
+ end
73
+
74
+ class HerokuDeploy < EmptyDeploy
75
+
76
+ def initialize(*)
77
+ super
78
+ @info = get_info
79
+ end
80
+
81
+ def id
82
+ @info ? @info['id'] : nil
83
+ end
84
+
85
+ def git_sha
86
+ @info ? @info['commit'] : nil
87
+ end
88
+
89
+ def description
90
+ @info ? @info['description'] : nil
91
+ end
92
+
93
+ private
94
+
95
+ def get_info
96
+ info_path = config[:'heroku.dyno_info_path']
97
+
98
+ if File.exist?(info_path)
99
+ if info = JSON.parse(File.read(info_path))
100
+ info['release']
101
+ end
102
+ end
103
+ end
104
+
105
+ end
106
+
107
+ class GitDeploy < EmptyDeploy
108
+
109
+ attr_reader :git_sha, :description
110
+
111
+ def initialize(*)
112
+ super
113
+ @git_sha, @description = get_info
114
+ end
115
+
116
+ private
117
+
118
+ def get_info
119
+ Dir.chdir(config.root) do
120
+ info = `git log -1 --pretty="%H %s" 2>&1`
121
+ info.split(" ", 2).map(&:strip) if $?.success?
122
+ end
123
+ end
124
+
125
+ end
126
+
127
+ DEPLOY_TYPES = [DefaultDeploy, HerokuDeploy, GitDeploy]
128
+
129
+ end
130
+
131
+ end
132
+ end
@@ -0,0 +1,21 @@
1
+ require 'zlib'
2
+
3
+ module Skylight::Core
4
+ module Util
5
+ # Provides Gzip compressing support
6
+ module Gzip
7
+
8
+ # Compress a string with Gzip
9
+ #
10
+ # @param str [String] uncompressed string
11
+ # @return [String] compressed string
12
+ def self.compress(str)
13
+ output = StringIO.new
14
+ gz = Zlib::GzipWriter.new(output)
15
+ gz.write(str)
16
+ gz.close
17
+ output.string
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,112 @@
1
+ module Skylight::Core
2
+ module Util
3
+
4
+ # String Inflector methods
5
+ #
6
+ # From https://github.com/rails/rails/blob/f8e5022c73679f41db9bb6743179bab4571fb28e/activesupport/lib/active_support/inflector/methods.rb
7
+ module Inflector
8
+ extend self
9
+
10
+ # Tries to find a constant with the name specified in the argument string.
11
+ #
12
+ # 'Module'.constantize # => Module
13
+ # 'Test::Unit'.constantize # => Test::Unit
14
+ #
15
+ # The name is assumed to be the one of a top-level constant, no matter
16
+ # whether it starts with "::" or not. No lexical context is taken into
17
+ # account:
18
+ #
19
+ # C = 'outside'
20
+ # module M
21
+ # C = 'inside'
22
+ # C # => 'inside'
23
+ # 'C'.constantize # => 'outside', same as ::C
24
+ # end
25
+ #
26
+ # NameError is raised when the name is not in CamelCase or the constant is
27
+ # unknown.
28
+ def constantize(camel_cased_word)
29
+ names = camel_cased_word.split('::')
30
+
31
+ # Trigger a builtin NameError exception including the ill-formed constant in the message.
32
+ Object.const_get(camel_cased_word) if names.empty?
33
+
34
+ # Remove the first blank element in case of '::ClassName' notation.
35
+ names.shift if names.size > 1 && names.first.empty?
36
+
37
+ names.inject(Object) do |constant, name|
38
+ if constant == Object
39
+ constant.const_get(name)
40
+ else
41
+ candidate = constant.const_get(name)
42
+ next candidate if constant.const_defined?(name, false)
43
+ next candidate unless Object.const_defined?(name)
44
+
45
+ # Go down the ancestors to check it it's owned
46
+ # directly before we reach Object or the end of ancestors.
47
+ constant = constant.ancestors.inject do |const, ancestor|
48
+ break const if ancestor == Object
49
+ break ancestor if ancestor.const_defined?(name, false)
50
+ const
51
+ end
52
+
53
+ # owner is in Object, so raise
54
+ constant.const_get(name, false)
55
+ end
56
+ end
57
+ end
58
+
59
+ # Tries to find a constant with the name specified in the argument string.
60
+ #
61
+ # 'Module'.safe_constantize # => Module
62
+ # 'Test::Unit'.safe_constantize # => Test::Unit
63
+ #
64
+ # The name is assumed to be the one of a top-level constant, no matter
65
+ # whether it starts with "::" or not. No lexical context is taken into
66
+ # account:
67
+ #
68
+ # C = 'outside'
69
+ # module M
70
+ # C = 'inside'
71
+ # C # => 'inside'
72
+ # 'C'.safe_constantize # => 'outside', same as ::C
73
+ # end
74
+ #
75
+ # +nil+ is returned when the name is not in CamelCase or the constant (or
76
+ # part of it) is unknown.
77
+ #
78
+ # 'blargle'.safe_constantize # => nil
79
+ # 'UnknownModule'.safe_constantize # => nil
80
+ # 'UnknownModule::Foo::Bar'.safe_constantize # => nil
81
+ def safe_constantize(camel_cased_word)
82
+ constantize(camel_cased_word)
83
+ rescue NameError => e
84
+ raise unless e.message =~ /(uninitialized constant|wrong constant name) #{const_regexp(camel_cased_word)}$/ ||
85
+ e.name.to_s == camel_cased_word.to_s
86
+ rescue ArgumentError => e
87
+ raise unless e.message =~ /not missing constant #{const_regexp(camel_cased_word)}\!$/
88
+ end
89
+
90
+ private
91
+
92
+ # Mount a regular expression that will match part by part of the constant.
93
+ #
94
+ # const_regexp("Foo::Bar::Baz") # => /(Foo(::Bar(::Baz)?)?|Bar|Baz)/
95
+ # const_regexp("::") # => /::/
96
+ #
97
+ # NOTE: We also add each part in singly, because sometimes a search for a missing
98
+ # constant like Skylight::Foo::Bar will return an error just saying Foo was missing
99
+ def const_regexp(camel_cased_word) #:nodoc:
100
+ parts = camel_cased_word.split("::")
101
+
102
+ return Regexp.escape(camel_cased_word) if parts.empty?
103
+
104
+ regexp = parts.reverse.inject do |acc, part|
105
+ part.empty? ? acc : "#{part}(::#{acc})?"
106
+ end
107
+
108
+ "(" + ([regexp] + parts[1..-1]).join('|') + ")"
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,127 @@
1
+ require 'logger'
2
+
3
+ module Skylight::Core
4
+ module Util
5
+ # Log both to the specified logger and STDOUT
6
+ class AlertLogger
7
+ def initialize(logger)
8
+ @logger = logger
9
+ end
10
+
11
+ def write(*args)
12
+ STDERR.write *args
13
+
14
+ # Try to avoid writing to STDOUT/STDERR twice
15
+ logger_logdev = @logger.instance_variable_get(:@logdev)
16
+ logger_out = logger_logdev && logger_logdev.respond_to?(:dev) ? logger_logdev.dev : nil
17
+ if logger_out != STDOUT && logger_out != STDERR
18
+ @logger.<<(*args)
19
+ end
20
+ end
21
+
22
+ def close
23
+ end
24
+ end
25
+
26
+ module Logging
27
+
28
+ def self.trace?
29
+ ENV[Skylight::TRACE_ENV_KEY]
30
+ end
31
+
32
+ if trace?
33
+ # The second set is picked up by YARD
34
+ def trace(msg, *args)
35
+ log :debug, msg, *args
36
+ end
37
+
38
+ def t
39
+ log :debug, yield
40
+ end
41
+ else
42
+ # Logs if `ENV[TRACE_ENV_KEY]` is set.
43
+ #
44
+ # @param (see #debug)
45
+ #
46
+ # See {TRACE_ENV_KEY}.
47
+ def trace(msg, *args)
48
+ end
49
+
50
+ # Evaluates and logs the result of the block if `ENV[TRACE_ENV_KEY]` is set
51
+ #
52
+ # @yield block to be evaluted
53
+ # @yieldreturn arguments for {#debug}
54
+ #
55
+ # See {TRACE_ENV_KEY}.
56
+ def t
57
+ end
58
+ end
59
+
60
+ # @param msg (see #log)
61
+ # @param args (see #log)
62
+ def debug(msg, *args)
63
+ log :debug, msg, *args
64
+ end
65
+
66
+ # @param msg (see #log)
67
+ # @param args (see #log)
68
+ def info(msg, *args)
69
+ log :info, msg, *args
70
+ end
71
+
72
+ # @param msg (see #log)
73
+ # @param args (see #log)
74
+ def warn(msg, *args)
75
+ log :warn, msg, *args
76
+ end
77
+
78
+ # @param msg (see #log)
79
+ # @param args (see #log)
80
+ def error(msg, *args)
81
+ log :error, msg, *args
82
+ raise sprintf(msg, *args) if ENV['SKYLIGHT_RAISE_ON_ERROR']
83
+ end
84
+
85
+ alias log_trace trace
86
+ alias log_debug debug
87
+ alias log_info info
88
+ alias log_warn warn
89
+ alias log_error error
90
+
91
+ # Alias for `Kernel#sprintf`
92
+ # @return [String]
93
+ def fmt(*args)
94
+ sprintf(*args)
95
+ end
96
+
97
+ # @param level [String,Symbol] the method on `logger` to use for logging
98
+ # @param msg [String] the message to log
99
+ # @param args [Array] values for `Kernel#sprintf` on `msg`
100
+ def log(level, msg, *args)
101
+ c = if respond_to?(:config)
102
+ config
103
+ elsif self.is_a?(Config)
104
+ self
105
+ end
106
+
107
+ return unless c
108
+
109
+ if logger = c.logger
110
+ return unless logger.respond_to?(level)
111
+
112
+ if args.length > 0
113
+ logger.send level, sprintf("[SKYLIGHT] [#{Skylight::Core::VERSION}] #{msg}", *args)
114
+ else
115
+ logger.send level, "[SKYLIGHT] [#{Skylight::Core::VERSION}] #{msg}"
116
+ end
117
+ end
118
+ rescue Exception => e
119
+ if ENV[Skylight::TRACE_ENV_KEY]
120
+ puts "[ERROR] #{e.message}"
121
+ puts e.backtrace
122
+ end
123
+ end
124
+
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,77 @@
1
+ require 'rbconfig'
2
+
3
+ # Used from extconf and to load libskylight
4
+ module Skylight
5
+ module Core
6
+ module Util
7
+ module Platform
8
+ # Normalize the platform OS
9
+ OS = case os = RbConfig::CONFIG['host_os'].downcase
10
+ when /linux/
11
+ # The official ruby-alpine Docker containers pre-build Ruby. As a result,
12
+ # Ruby doesn't know that it's on a musl-based platform. `ldd` is the
13
+ # only reliable way to detect musl that we've found.
14
+ # See https://github.com/skylightio/skylight-ruby/issues/92
15
+ if ENV['SKYLIGHT_MUSL'] || `ldd --version 2>&1` =~ /musl/
16
+ "linux-musl"
17
+ else
18
+ "linux"
19
+ end
20
+ when /darwin/
21
+ "darwin"
22
+ when /freebsd/
23
+ "freebsd"
24
+ when /netbsd/
25
+ "netbsd"
26
+ when /openbsd/
27
+ "openbsd"
28
+ when /sunos|solaris/
29
+ "solaris"
30
+ when /mingw|mswin/
31
+ "windows"
32
+ else
33
+ os
34
+ end
35
+
36
+ # Normalize the platform CPU
37
+ ARCH = case cpu = RbConfig::CONFIG['host_cpu'].downcase
38
+ when /amd64|x86_64/
39
+ "x86_64"
40
+ when /i?86|x86|i86pc/
41
+ "x86"
42
+ when /ppc|powerpc/
43
+ "powerpc"
44
+ when /^arm/
45
+ "arm"
46
+ else
47
+ cpu
48
+ end
49
+
50
+ LIBEXT = case OS
51
+ when /darwin/
52
+ 'dylib'
53
+ when /linux|bsd|solaris/
54
+ 'so'
55
+ when /windows|cygwin/
56
+ 'dll'
57
+ else
58
+ 'so'
59
+ end
60
+
61
+ TUPLE = "#{ARCH}-#{OS}"
62
+
63
+ def self.tuple
64
+ TUPLE
65
+ end
66
+
67
+ def self.libext
68
+ LIBEXT
69
+ end
70
+
71
+ def self.dlext
72
+ RbConfig::CONFIG['DLEXT']
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,13 @@
1
+ module Skylight::Core
2
+ module Util
3
+ module Proxy
4
+ def self.detect_url(env)
5
+ u = env['HTTP_PROXY'] || env['http_proxy']
6
+ if u && !u.empty?
7
+ u = "http://#{u}" unless u =~ %r[://]
8
+ u
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ module Skylight::Core
2
+ # @api private
3
+ module Util
4
+ # Used from the main lib
5
+ require 'skylight/core/util/allocation_free'
6
+ require 'skylight/core/util/clock'
7
+ require 'skylight/core/util/deploy'
8
+ require 'skylight/core/util/logging'
9
+
10
+ # Used from the CLI
11
+ autoload :Gzip, 'skylight/core/util/gzip'
12
+ autoload :Inflector, 'skylight/core/util/inflector'
13
+ end
14
+ end