skylight 0.3.6 → 0.3.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3b26b3f575af56669c5257a37d8d7ca11544aba4
4
- data.tar.gz: 5fb2964195f3d146693f62b6593ff2b0bbf3944d
3
+ metadata.gz: 727271788a0fddacdf3b7e53451c413023d74a0d
4
+ data.tar.gz: 0b911dd320834be2608b7cd294e5aacf395188b7
5
5
  SHA512:
6
- metadata.gz: 5e9759155ce35d86bd96b058788b153544dff9aa73d08cfb4f742ddd5dc2871b4c4c8bc4e4799eb006b59e3e8bb99b89920b98a67698fd601d612793b2f68ec3
7
- data.tar.gz: 0009517b20943ce01703c10210b925f3d687b16e471f7b57af1066bbdeb28e88f3f91937b00a4c4942167f2d7983d89b1621d10891f16962c644965dbf573fb8
6
+ metadata.gz: 425fe8a9ece2086b79e08cadcd7687c1d808ce65e2772c6b3d457c7f5b79c57fe9284d78f9964a7a161e95f67d0e87d2cf4dc89370488d6d7ad7906abec53357
7
+ data.tar.gz: bbbe029afd5bfaa9c203ad7103ac818bdebbc95a78b94435ed43344b5a00feb74e7992d75bc8fdca27e1fe63dadb784fcd64ef63abbb41130092c4511988f5ea
@@ -1,91 +1,89 @@
1
1
  require 'mkmf'
2
- require 'rbconfig'
3
- require 'net/http'
4
- require 'zlib'
5
2
  require 'yaml'
6
- require 'digest/sha2'
3
+ require 'logger'
7
4
 
8
- require_relative '../lib/skylight/version.rb'
5
+ LOG = Logger.new(STDOUT)
6
+ SKYLIGHT_REQUIRED = ENV.key?("SKYLIGHT_REQUIRED") && ENV['SKYLIGHT_REQUIRED'] !~ /^false$/i
9
7
 
10
- checksums = YAML.load_file("checksums.yml")
8
+ require_relative '../lib/skylight/version'
9
+ require_relative '../lib/skylight/util/native_ext_fetcher'
11
10
 
12
- rust_version = "74fb9b3"
11
+ include Skylight::Util
13
12
 
14
- arch = RbConfig::CONFIG["arch"]
13
+ # Handles terminating in the case of a failure. If we have a bug, we do not
14
+ # want to break our customer's deploy, but extconf.rb requires a Makefile to be
15
+ # present upon a successful exit. To satisfy this requirement, we create a
16
+ # dummy Makefile.
17
+ def fail(msg)
18
+ LOG.error msg
15
19
 
16
- url = "https://github.com/skylightio/skylight-rust/releases/download/#{rust_version}/libskylight.#{arch}.a.gz"
20
+ if SKYLIGHT_REQUIRED
21
+ exit 1
22
+ else
23
+ File.open("Makefile", "w") do |file|
24
+ file.puts "default:"
25
+ file.puts "install:"
26
+ end
17
27
 
18
- required = ENV.key?("SKYLIGHT_REQUIRED")
28
+ exit
29
+ end
30
+ end
19
31
 
20
- unless File.exist?("libskylight.a")
21
- puts "[SKYLIGHT] [#{Skylight::VERSION}] Downloading from #{url.inspect}"
22
- location = nil
23
- uri = URI.parse(url)
32
+ libskylight_a = File.expand_path('../libskylight.a', __FILE__)
33
+ libskylight_yml = File.expand_path('../libskylight.yml', __FILE__)
24
34
 
25
- begin
26
- Net::HTTP.start("github.com", 443, use_ssl: true) do |http|
27
- response = http.get(uri.request_uri)
28
- location = response["Location"]
29
- end
35
+ unless File.exist?(libskylight_a)
36
+ # Ensure that libskylight.yml is present and load it
37
+ unless File.exist?(libskylight_yml)
38
+ fail "`#{libskylight_yml}` does not exist"
39
+ end
30
40
 
31
- if location
32
- archive = nil
33
-
34
- uri = URI(location)
35
- Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
36
- response = http.get(uri.request_uri)
37
- archive = response.body
38
- end
39
- else
40
- raise "No location returned" if required
41
- missing_a = true
42
- end
43
- rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError,
44
- Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError
45
- raise if required
46
- missing_a = true
41
+ unless libskylight_info = YAML.load_file(libskylight_yml)
42
+ fail "`#{libskylight_yml}` does not contain data"
47
43
  end
48
44
 
49
- unless missing_a
50
- expected_checksum = checksums[arch]
51
- actual_checksum = Digest::SHA2.hexdigest(archive)
45
+ unless version = libskylight_info["version"]
46
+ fail "libskylight version missing from `#{libskylight_yml}`"
47
+ end
52
48
 
53
- if expected_checksum == actual_checksum
54
- inflater, dest = Zlib::Inflate.new(32 + Zlib::MAX_WBITS), ""
55
- dest << inflater.inflate(archive)
56
- inflater.close
49
+ unless checksums = libskylight_info["checksums"]
50
+ fail "libskylight checksums missing from `#{libskylight_yml}`"
51
+ end
57
52
 
58
- File.open("libskylight.a", "w") { |file| file.write dest }
59
- else
60
- raise "Checksum mismatched; expected=#{expected_checksum.inspect}; actual=#{actual_checksum.inspect}" if required
61
- missing_a = true
53
+ begin
54
+ res = NativeExtFetcher.fetch(
55
+ version: version,
56
+ target: libskylight_a,
57
+ checksums: checksums,
58
+ required: SKYLIGHT_REQUIRED,
59
+ logger: LOG)
60
+
61
+ unless res
62
+ fail "could not fetch archive -- aborting skylight native extension build"
62
63
  end
64
+ rescue => e
65
+ fail "unable to fetch native extension; msg=#{e.message}\n#{e.backtrace.join("\n")}"
63
66
  end
64
67
  end
65
68
 
66
- if missing_a
67
- puts "[SKYLIGHT] [#{Skylight::VERSION}] Could not download Skylight native code from Github; version=#{rust_version.inspect}; arch=#{arch.inspect}"
69
+ #
70
+ #
71
+ # ===== By this point, libskylight.a is present =====
72
+ #
73
+ #
68
74
 
69
- exit 1 if required
75
+ have_header 'dlfcn.h'
70
76
 
71
- File.open("Makefile", "w") do |file|
72
- file.puts "default:"
73
- file.puts "install:"
74
- end
75
- else
76
- have_header 'dlfcn.h'
77
+ find_library("skylight", "factory", ".")
77
78
 
78
- find_library("skylight", "factory", ".")
79
-
80
- $CFLAGS << " -Werror"
81
- if RbConfig::CONFIG["arch"] =~ /darwin(\d+)?/
82
- $LDFLAGS << " -lpthread"
83
- else
84
- $LDFLAGS << " -Wl,--version-script=skylight.map"
85
- $LDFLAGS << " -lrt -ldl -lm -lpthread"
86
- end
79
+ $CFLAGS << " -Werror"
80
+ if RbConfig::CONFIG["arch"] =~ /darwin(\d+)?/
81
+ $LDFLAGS << " -lpthread"
82
+ else
83
+ $LDFLAGS << " -Wl,--version-script=skylight.map"
84
+ $LDFLAGS << " -lrt -ldl -lm -lpthread"
85
+ end
87
86
 
88
- CONFIG['warnflags'].gsub!('-Wdeclaration-after-statement', '')
87
+ CONFIG['warnflags'].gsub!('-Wdeclaration-after-statement', '')
89
88
 
90
- create_makefile 'skylight_native', '.'
91
- end
89
+ create_makefile 'skylight_native', '.'
@@ -0,0 +1,6 @@
1
+ ---
2
+ version: "74fb9b3"
3
+ checksums:
4
+ linux-x86_64: "98b04f7d73c1894cc79621a135b4598a679c421f5ff3eecc652f84ba07258d9c"
5
+ linux-x86: "1d4bbd58e319237b18752607d087ce0c895fe99c58482e994abe62a9f07d41dd"
6
+
@@ -0,0 +1,93 @@
1
+ #ifndef __SKYLIGHT_H__
2
+ #define __SKYLIGHT_H__
3
+
4
+ #include <stddef.h>
5
+ #include <stdint.h>
6
+ #include <stdbool.h>
7
+
8
+ /**
9
+ * Rust types
10
+ */
11
+
12
+ typedef struct {
13
+ size_t fill; // in bytes; if zero, heapified
14
+ size_t alloc; // in bytes
15
+ uint8_t data[0];
16
+ } rust_str;
17
+
18
+ typedef struct {
19
+ char * data;
20
+ long len;
21
+ } RustSlice;
22
+
23
+ typedef struct {
24
+ uint8_t discrim;
25
+ RustSlice slice;
26
+ } OptionRustSlice;
27
+
28
+ typedef rust_str * RustString;
29
+ typedef RustString RustVector;
30
+
31
+ /**
32
+ * Externed Rust functions from libskylight
33
+ */
34
+
35
+ typedef void * RustHello;
36
+ typedef void * RustError;
37
+ typedef void * RustTrace;
38
+ typedef void * RustBatch;
39
+
40
+ void factory();
41
+
42
+ // Rust skylight_hello prototypes
43
+ bool skylight_hello_new(RustSlice, uint32_t, RustHello*);
44
+ bool skylight_hello_free(RustHello);
45
+ bool skylight_hello_load(RustSlice, RustHello*);
46
+ bool skylight_hello_cmd_add(RustHello, RustSlice);
47
+ bool skylight_hello_get_version(RustHello, RustSlice*);
48
+ bool skylight_hello_cmd_length(RustHello, uint32_t*);
49
+ bool skylight_hello_get_cmd(RustHello, int, RustSlice*);
50
+ bool skylight_hello_serialize_into_new_buffer(RustHello, RustString*);
51
+ bool skylight_high_res_time(uint64_t*);
52
+
53
+ // Rust skylight_trace prototypes
54
+ bool skylight_trace_new(uint64_t, RustSlice, RustTrace*);
55
+ bool skylight_trace_free(RustTrace);
56
+ bool skylight_trace_load(RustSlice, RustTrace*);
57
+ bool skylight_trace_name_from_serialized_into_new_buffer(RustSlice, RustString*);
58
+ bool skylight_trace_get_started_at(RustTrace, uint64_t*);
59
+ bool skylight_trace_set_name(RustTrace, RustSlice);
60
+ bool skylight_trace_get_name(RustTrace, RustSlice*);
61
+ bool skylight_trace_get_uuid(RustTrace, RustSlice*);
62
+ bool skylight_trace_start_span(RustTrace, uint64_t, RustSlice, uint32_t*);
63
+ bool skylight_trace_stop_span(RustTrace, uint32_t, uint64_t);
64
+ bool skylight_trace_serialize_into_new_buffer(RustTrace, RustString*);
65
+ bool skylight_trace_span_set_title(RustTrace, uint64_t, RustSlice);
66
+ bool skylight_trace_span_set_description(RustTrace, uint64_t, RustSlice);
67
+
68
+ // Trace annotation methods
69
+ bool skylight_trace_add_annotation_int(RustTrace, uint32_t, uint32_t*, RustSlice*, int64_t);
70
+ bool skylight_trace_add_annotation_double(RustTrace, uint32_t, uint32_t*, RustSlice*, double);
71
+ bool skylight_trace_add_annotation_string(RustTrace, uint32_t, uint32_t*, RustSlice*, RustSlice);
72
+ bool skylight_trace_add_annotation_nested(RustTrace, uint32_t, uint32_t*, RustSlice*, uint32_t*);
73
+
74
+ // Batch methods
75
+ bool skylight_batch_new(uint32_t, RustString, RustBatch*);
76
+ bool skylight_batch_free(RustBatch);
77
+ bool skylight_batch_set_endpoint_count(RustBatch, RustSlice, uint64_t);
78
+ bool skylight_batch_move_in(RustBatch, RustString);
79
+ bool skylight_batch_serialize_into_new_buffer(RustBatch, RustString*);
80
+
81
+ // Error methods
82
+ bool skylight_error_new(RustSlice, RustSlice, RustError*);
83
+ bool skylight_error_free(RustError);
84
+ bool skylight_error_load(RustSlice, RustError*);
85
+ bool skylight_error_get_group(RustError, RustSlice*);
86
+ bool skylight_error_get_description(RustError, RustSlice*);
87
+ bool skylight_error_get_details(RustError, RustSlice*);
88
+ bool skylight_error_set_details(RustError, RustSlice);
89
+ bool skylight_error_serialize_into_new_buffer(RustError, RustString*);
90
+
91
+ void skylight_free_buf(RustString);
92
+
93
+ #endif
@@ -1,5 +1,5 @@
1
+ #include <skylight.h>
1
2
  #include <ruby.h>
2
- #include <stdbool.h>
3
3
 
4
4
  #ifdef HAVE_RUBY_ENCODING_H
5
5
  #include <ruby/encoding.h>
@@ -49,104 +49,50 @@
49
49
  } \
50
50
 
51
51
  #define CHECK_FFI(success, message) \
52
- { \
52
+ ({ \
53
53
  if (!(success)) \
54
54
  rb_raise(rb_eRuntimeError, message); \
55
- } \
56
-
57
- /**
58
- * Rust types
59
- */
60
-
61
- typedef struct {
62
- size_t fill; // in bytes; if zero, heapified
63
- size_t alloc; // in bytes
64
- uint8_t data[0];
65
- } rust_str;
66
-
67
- typedef struct {
68
- char * data;
69
- long len;
70
- } RustSlice;
71
-
72
- typedef rust_str * RustString;
73
- typedef RustString RustVector;
74
- #define VEC2STR(vector) ({ RustVector v = (vector); VALUE ret = rb_str_new((char *)v->data, v->fill); ret; })
75
- #define SLICE2STR(slice) ({ RustSlice s = (slice); VALUE str = rb_str_new(s.data, s.len); rb_enc_associate(str, rb_utf8_encoding()); str; })
76
- #define STR2SLICE(string) ({ RustSlice s; VALUE rb_str = (string); s.data = RSTRING_PTR(rb_str); s.len = RSTRING_LEN(rb_str); s; })
77
-
78
- #define UnwrapOption(T, val, transform) ({ T * v = (val); VALUE ret; if (v == NULL) ret = Qnil; else ret = transform(*v); ret; })
79
-
80
- typedef struct {
81
- uint8_t discrim;
82
- RustSlice slice;
83
- } OptionRustSlice;
55
+ })
56
+
57
+ #define VEC2STR(vector) \
58
+ ({ \
59
+ RustVector v = (vector); \
60
+ VALUE ret = rb_str_new((char *)v->data, v->fill); \
61
+ ret; \
62
+ })
63
+
64
+ #define SLICE2STR(slice) \
65
+ ({ \
66
+ RustSlice s = (slice); \
67
+ VALUE str = rb_str_new(s.data, s.len); \
68
+ rb_enc_associate(str, rb_utf8_encoding()); \
69
+ str; \
70
+ })
71
+
72
+ #define STR2SLICE(string) \
73
+ ({ \
74
+ RustSlice s; \
75
+ VALUE rb_str = (string); \
76
+ s.data = RSTRING_PTR(rb_str); \
77
+ s.len = RSTRING_LEN(rb_str); \
78
+ s; \
79
+ })
80
+
81
+ #define UnwrapOption(T, val, transform) \
82
+ ({ \
83
+ T * v = (val); \
84
+ VALUE ret; \
85
+ if (v == NULL) { \
86
+ ret = Qnil; \
87
+ } \
88
+ else { \
89
+ ret = transform(*v); \
90
+ } \
91
+ ret; \
92
+ })
84
93
 
85
94
  #define IsNone(val) val.discrim == 0
86
95
 
87
- /**
88
- * Externed Rust functions from libskylight
89
- */
90
-
91
- typedef void * RustHello;
92
- typedef void * RustError;
93
- typedef void * RustTrace;
94
- typedef void * RustBatch;
95
-
96
- void factory();
97
-
98
-
99
- // Rust skylight_hello prototypes
100
- bool skylight_hello_new(RustSlice, uint32_t, RustHello*);
101
- bool skylight_hello_free(RustHello);
102
- bool skylight_hello_load(RustSlice, RustHello*);
103
- bool skylight_hello_cmd_add(RustHello, RustSlice);
104
- bool skylight_hello_get_version(RustHello, RustSlice*);
105
- bool skylight_hello_cmd_length(RustHello, uint32_t*);
106
- bool skylight_hello_get_cmd(RustHello, int, RustSlice*);
107
- bool skylight_hello_serialize_into_new_buffer(RustHello, RustString*);
108
- bool skylight_high_res_time(uint64_t*);
109
-
110
- // Rust skylight_trace prototypes
111
- bool skylight_trace_new(uint64_t, RustSlice, RustTrace*);
112
- bool skylight_trace_free(RustTrace);
113
- bool skylight_trace_load(RustSlice, RustTrace*);
114
- bool skylight_trace_name_from_serialized_into_new_buffer(RustSlice, RustString*);
115
- bool skylight_trace_get_started_at(RustTrace, uint64_t*);
116
- bool skylight_trace_set_name(RustTrace, RustSlice);
117
- bool skylight_trace_get_name(RustTrace, RustSlice*);
118
- bool skylight_trace_get_uuid(RustTrace, RustSlice*);
119
- bool skylight_trace_start_span(RustTrace, uint64_t, RustSlice, uint32_t*);
120
- bool skylight_trace_stop_span(RustTrace, uint32_t, uint64_t);
121
- bool skylight_trace_serialize_into_new_buffer(RustTrace, RustString*);
122
- bool skylight_trace_span_set_title(RustTrace, uint64_t, RustSlice);
123
- bool skylight_trace_span_set_description(RustTrace, uint64_t, RustSlice);
124
-
125
- // Trace annotation methods
126
- bool skylight_trace_add_annotation_int(RustTrace, uint32_t, uint32_t*, RustSlice*, int64_t);
127
- bool skylight_trace_add_annotation_double(RustTrace, uint32_t, uint32_t*, RustSlice*, double);
128
- bool skylight_trace_add_annotation_string(RustTrace, uint32_t, uint32_t*, RustSlice*, RustSlice);
129
- bool skylight_trace_add_annotation_nested(RustTrace, uint32_t, uint32_t*, RustSlice*, uint32_t*);
130
-
131
- // Batch methods
132
- bool skylight_batch_new(uint32_t, RustString, RustBatch*);
133
- bool skylight_batch_free(RustBatch);
134
- bool skylight_batch_set_endpoint_count(RustBatch, RustSlice, uint64_t);
135
- bool skylight_batch_move_in(RustBatch, RustString);
136
- bool skylight_batch_serialize_into_new_buffer(RustBatch, RustString*);
137
-
138
- // Error methods
139
- bool skylight_error_new(RustSlice, RustSlice, RustError*);
140
- bool skylight_error_free(RustError);
141
- bool skylight_error_load(RustSlice, RustError*);
142
- bool skylight_error_get_group(RustError, RustSlice*);
143
- bool skylight_error_get_description(RustError, RustSlice*);
144
- bool skylight_error_get_details(RustError, RustSlice*);
145
- bool skylight_error_set_details(RustError, RustSlice);
146
- bool skylight_error_serialize_into_new_buffer(RustError, RustString*);
147
-
148
- void skylight_free_buf(RustString);
149
-
150
96
  /**
151
97
  * Convert Ruby String to a Rust String
152
98
  */
@@ -154,7 +100,13 @@ void skylight_free_buf(RustString);
154
100
  RustString skylight_slice_to_owned(RustSlice);
155
101
  RustString skylight_bytes_to_new_vec(uint8_t*, uint64_t);
156
102
 
157
- #define STR2RUST(string) ({ VALUE rb_str = (string); skylight_bytes_to_new_vec((uint8_t*)RSTRING_PTR(rb_str), RSTRING_LEN(rb_str)); })
103
+ #define STR2RUST(string) \
104
+ ({ \
105
+ VALUE rb_str = (string); \
106
+ skylight_bytes_to_new_vec( \
107
+ (uint8_t*) RSTRING_PTR(rb_str), \
108
+ RSTRING_LEN(rb_str)); \
109
+ })
158
110
 
159
111
  /**
160
112
  * Ruby types defined here
@@ -2,25 +2,32 @@ require 'rbconfig'
2
2
  require 'socket'
3
3
  require 'skylight/version'
4
4
 
5
- begin
6
- unless ENV["SKYLIGHT_DISABLE_AGENT"]
7
- require 'skylight_native'
8
- require 'skylight/native'
9
- has_native_ext = true
10
- end
11
- rescue LoadError
12
- if defined?(Rails) && !Rails.env.development? && !Rails.env.test?
13
- puts "[SKYLIGHT] [#{Skylight::VERSION}] The Skylight native extension for your platform wasn't found. We currently support monitoring in 32- and 64-bit Linux only. If you are on a supported platform, please contact support at support@skylight.io. The missing extension will not affect the functioning of your application."
14
- elsif defined?(Rails)
15
- puts "[SKYLIGHT] [#{Skylight::VERSION}] Running Skylight in #{Rails.env} mode. No data will be reported until you deploy your app."
16
- else
17
- puts "[SKYLIGHT] [#{Skylight::VERSION}] Running Skylight in development mode."
18
- end
19
- raise if ENV.key?("SKYLIGHT_REQUIRED")
20
- end
21
-
22
5
  module Skylight
23
6
  TRACE_ENV_KEY = 'SKYLIGHT_ENABLE_TRACE_LOGS'.freeze
7
+ STANDALONE_ENV_KEY = 'SKYLIGHT_STANDALONE'.freeze
8
+ STANDALONE_ENV_VAL = 'server'.freeze
9
+
10
+ # Whether or not the native extension is present
11
+ @@has_native_ext = false
12
+
13
+ def self.native?
14
+ @@has_native_ext
15
+ end
16
+
17
+ begin
18
+ unless ENV["SKYLIGHT_DISABLE_AGENT"]
19
+ # First attempt to require the native extension
20
+ require 'skylight_native'
21
+
22
+ # If nothing was thrown, then the native extension is present
23
+ @@has_native_ext = true
24
+
25
+ # Require ruby support for the native extension
26
+ require 'skylight/native'
27
+ end
28
+ rescue LoadError
29
+ raise if ENV.key?("SKYLIGHT_REQUIRED")
30
+ end
24
31
 
25
32
  autoload :Api, 'skylight/api'
26
33
  autoload :CLI, 'skylight/cli'
@@ -42,16 +49,16 @@ module Skylight
42
49
  if defined?(Rails)
43
50
  require 'skylight/railtie'
44
51
  end
45
- end
46
-
47
- if has_native_ext
48
52
 
49
- module Skylight
50
- STANDALONE_ENV_KEY = 'SKYLIGHT_STANDALONE'.freeze
51
- STANDALONE_ENV_VAL = 'server'.freeze
52
-
53
- def self.native?
54
- true
53
+ def self.warn_skylight_native_missing
54
+ # TODO: Dumping the error messages this way is pretty hacky
55
+ if defined?(Rails) && !Rails.env.development? && !Rails.env.test?
56
+ puts "[SKYLIGHT] [#{Skylight::VERSION}] The Skylight native extension for your platform wasn't found. We currently support monitoring in 32- and 64-bit Linux only. If you are on a supported platform, please contact support at support@skylight.io. The missing extension will not affect the functioning of your application."
57
+ elsif defined?(Rails)
58
+ puts "[SKYLIGHT] [#{Skylight::VERSION}] Running Skylight in #{Rails.env} mode. No data will be reported until you deploy your app."
59
+ else
60
+ puts "[SKYLIGHT] [#{Skylight::VERSION}] Running Skylight in development mode."
61
+ end
55
62
  end
56
63
 
57
64
  def self.daemon?
@@ -103,6 +110,12 @@ module Skylight
103
110
  DEFAULT_CATEGORY = "app.block".freeze
104
111
  DEFAULT_OPTIONS = { category: DEFAULT_CATEGORY }
105
112
 
113
+ #
114
+ #
115
+ # ===== Public API =====
116
+ #
117
+ #
118
+
106
119
  def self.start!(*args)
107
120
  Instrumenter.start!(*args)
108
121
  end
@@ -136,7 +149,7 @@ module Skylight
136
149
  end
137
150
 
138
151
  if Hash === opts
139
- category = opts.delete(:category)
152
+ category = opts.delete(:category) || DEFAULT_CATEGORY
140
153
  title = opts.delete(:title)
141
154
  desc = opts.delete(:description)
142
155
  else
@@ -170,34 +183,3 @@ module Skylight
170
183
 
171
184
  require 'skylight/probes'
172
185
  end
173
-
174
- else
175
-
176
- module Skylight
177
- def self.native?
178
- false
179
- end
180
-
181
- def self.start!(*)
182
- end
183
-
184
- def self.stop!(*)
185
- end
186
-
187
- def self.trace(*)
188
- yield if block_given?
189
- end
190
-
191
- def self.done(*)
192
- end
193
-
194
- def self.instrument(*)
195
- yield if block_given?
196
- end
197
-
198
- def self.disable(*)
199
- yield if block_given?
200
- end
201
- end
202
-
203
- end
@@ -1,6 +1,7 @@
1
1
  require 'thread'
2
2
  require 'set'
3
3
  require 'base64'
4
+ require 'strscan'
4
5
 
5
6
  module Skylight
6
7
  class Instrumenter
@@ -70,6 +71,11 @@ module Skylight
70
71
  def start!
71
72
  return unless config
72
73
 
74
+ unless Skylight.native?
75
+ Skylight.warn_skylight_native_missing
76
+ return
77
+ end
78
+
73
79
  t { "starting instrumenter" }
74
80
  @config.validate!
75
81
 
@@ -153,6 +159,8 @@ module Skylight
153
159
  end
154
160
 
155
161
  def instrument(cat, title=nil, desc=nil, annot=nil)
162
+ raise ArgumentError, 'cat is required' unless cat
163
+
156
164
  unless trace = @trace_info.current
157
165
  return yield if block_given?
158
166
  return
@@ -1,80 +1,83 @@
1
1
  module Skylight
2
- class Hello
3
- DIGITS = /^\s*\d+\s*$/
4
2
 
5
- alias serialize native_serialize
6
- alias version native_get_version
3
+ if native?
4
+ class Hello
5
+ DIGITS = /^\s*\d+\s*$/
7
6
 
8
- class << self
9
- alias deserialize native_load
10
- end
7
+ alias serialize native_serialize
8
+ alias version native_get_version
11
9
 
12
- def cmd
13
- native_cmd_length.times.map do |offset|
14
- native_cmd_get(offset)
10
+ class << self
11
+ alias deserialize native_load
15
12
  end
16
- end
17
13
 
18
- def newer?(other = VERSION)
19
- other = split(other)
20
- curr = split(version)
14
+ def cmd
15
+ native_cmd_length.times.map do |offset|
16
+ native_cmd_get(offset)
17
+ end
18
+ end
21
19
 
22
- [other.length, curr.length].max.times do |i|
23
- next if other[i] == curr[i]
24
- return true unless other[i]
20
+ def newer?(other = VERSION)
21
+ other = split(other)
22
+ curr = split(version)
25
23
 
26
- if other[i] =~ DIGITS
27
- if curr[i] =~ DIGITS
28
- other_i = other[i].to_i
29
- curr_i = curr[i].to_i
24
+ [other.length, curr.length].max.times do |i|
25
+ next if other[i] == curr[i]
26
+ return true unless other[i]
30
27
 
31
- next if other_i == curr_i
28
+ if other[i] =~ DIGITS
29
+ if curr[i] =~ DIGITS
30
+ other_i = other[i].to_i
31
+ curr_i = curr[i].to_i
32
32
 
33
- return curr_i > other_i
34
- else
35
- return false
36
- end
37
- else
38
- if curr[i] =~ DIGITS
39
- return true
33
+ next if other_i == curr_i
34
+
35
+ return curr_i > other_i
36
+ else
37
+ return false
38
+ end
40
39
  else
41
- next if curr[i] == other[i]
42
- return curr[i] > other[i]
40
+ if curr[i] =~ DIGITS
41
+ return true
42
+ else
43
+ next if curr[i] == other[i]
44
+ return curr[i] > other[i]
45
+ end
43
46
  end
44
47
  end
45
- end
46
48
 
47
- false
48
- end
49
+ false
50
+ end
49
51
 
50
- private
52
+ private
51
53
 
52
- def split(v)
53
- v.split('.')
54
- end
54
+ def split(v)
55
+ v.split('.')
56
+ end
55
57
 
56
- end
58
+ end
57
59
 
58
- class Error
59
- alias serialize native_serialize
60
- alias type native_get_group
61
- alias description native_get_description
62
- alias details native_get_details
60
+ class Error
61
+ alias serialize native_serialize
62
+ alias type native_get_group
63
+ alias description native_get_description
64
+ alias details native_get_details
63
65
 
64
- class << self
65
- alias deserialize native_load
66
+ class << self
67
+ alias deserialize native_load
68
+ end
66
69
  end
67
- end
68
70
 
69
- class Trace
70
- alias serialize native_serialize
71
+ class Trace
72
+ alias serialize native_serialize
71
73
 
72
- class << self
73
- alias deserialize native_load
74
+ class << self
75
+ alias deserialize native_load
76
+ end
74
77
  end
75
- end
76
78
 
77
- class Batch
78
- alias serialize native_serialize
79
+ class Batch
80
+ alias serialize native_serialize
81
+ end
79
82
  end
80
83
  end
@@ -39,6 +39,8 @@ module Skylight
39
39
  end
40
40
 
41
41
  def self.require_hook(require_path)
42
+ return unless Skylight.native?
43
+
42
44
  registration = lookup_by_require_path(require_path)
43
45
  return unless registration
44
46
 
@@ -6,8 +6,16 @@ module Skylight
6
6
  Time.now.to_i
7
7
  end
8
8
 
9
- def nanos
10
- native_hrtime
9
+ if Skylight.native?
10
+ def nanos
11
+ native_hrtime
12
+ end
13
+ else
14
+ # Implement nanos to work when native extension is not present
15
+ def nanos
16
+ now = Time.now
17
+ now.to_i * 1_000_000_000 + now.usec * 1_000
18
+ end
11
19
  end
12
20
 
13
21
  def secs
@@ -0,0 +1,195 @@
1
+ require 'uri'
2
+ require 'logger'
3
+ require 'zlib'
4
+ require 'net/http'
5
+ require 'digest/sha2'
6
+
7
+ # Must require 'rubygems/platform' vs. just requiring 'rubygems' to avoid a
8
+ # stack overflow bug on ruby 1.9.2.
9
+ require 'rubygems/platform'
10
+
11
+ module Skylight
12
+ module Util
13
+ class NativeExtFetcher
14
+ BASE_URL = "https://github.com/skylightio/skylight-rust/releases/download"
15
+ MAX_REDIRECTS = 5
16
+ MAX_RETRIES = 3
17
+
18
+ class FetchError < StandardError; end
19
+
20
+ def self.fetch(opts = {})
21
+ platform = Gem::Platform.local
22
+
23
+ fetcher = new(
24
+ BASE_URL,
25
+ opts[:target],
26
+ opts[:version],
27
+ opts[:checksums],
28
+ opts[:cpu] || platform.cpu,
29
+ opts[:os] || platform.os,
30
+ opts[:required],
31
+ opts[:logger] || Logger.new(STDOUT))
32
+
33
+ fetcher.fetch
34
+ end
35
+
36
+ def initialize(source, target, version, checksums, cpu, os, required, log)
37
+ raise "source required" unless source
38
+ raise "checksums required" unless checksums
39
+ raise "cpu required" unless cpu
40
+ raise "os required" unless os
41
+
42
+ @source = source
43
+ @target = target
44
+ @version = version
45
+ @checksums = checksums
46
+ @required = required
47
+ @arch = "#{os}-#{cpu}"
48
+ @log = log
49
+ end
50
+
51
+ def fetch
52
+ # Ensure that the requested arch is valid
53
+ unless @checksums[@arch]
54
+ maybe_raise "no checksum entry for requested architecture -- " \
55
+ "this probably means the requested architecture is not supported; " \
56
+ "arch=#{@arch}; available=#{@checksums.keys}"
57
+ return
58
+ end
59
+
60
+ log "fetching native ext; curr-platform=#{Gem::Platform.local.to_s}; " \
61
+ "requested-arch=#{@arch}; version=#{@version}"
62
+
63
+ unless gziped = fetch_native_ext(source_uri, MAX_RETRIES, MAX_REDIRECTS)
64
+ maybe_raise "could not fetch native extension"
65
+ return
66
+ end
67
+
68
+ unless verify_checksum(gziped)
69
+ maybe_raise "could not verify checksum"
70
+ return
71
+ end
72
+
73
+ archive = inflate(gziped)
74
+
75
+ if @target
76
+ File.open @target, 'w' do |f|
77
+ f.write(archive)
78
+ end
79
+ end
80
+
81
+ archive
82
+ end
83
+
84
+ def self.http_get(host, port, use_ssl, path)
85
+ Net::HTTP.start(host, port, use_ssl: use_ssl) do |http|
86
+ case response = http.get(path)
87
+ when Net::HTTPSuccess
88
+ return [ :success, response.body ]
89
+ when Net::HTTPRedirection
90
+ unless location = response['location']
91
+ raise "received redirect but no location"
92
+ end
93
+
94
+ return [ :redirect, location ]
95
+ else
96
+ raise "received HTTP status code #{response.code}"
97
+ end
98
+ end
99
+ end
100
+
101
+ def fetch_native_ext(uri, attempts, redirects)
102
+ redirects.times do |i|
103
+ remaining_attempts = attempts
104
+
105
+ log "attempting to fetch from remote; uri=#{uri}"
106
+
107
+ begin
108
+ host, port, use_ssl, path = deconstruct_uri(uri)
109
+
110
+ status, body = NativeExtFetcher.http_get(host, port, use_ssl, path)
111
+
112
+ case status
113
+ when :success
114
+ if body
115
+ log "successfully downloaded native ext; body=#{body.bytesize}bytes"
116
+ else
117
+ log "response did not contain a body"
118
+ end
119
+
120
+ return body
121
+ when :redirect
122
+ log "fetching native ext; uri=#{uri}; redirected=#{body}"
123
+ uri = body
124
+
125
+ next
126
+ else
127
+ raise "received unknown return; status=#{status}; body=#{body}"
128
+ end
129
+
130
+ rescue => e
131
+ remaining_attempts -= 1
132
+
133
+ log "failed to fetch native extension; uri=#{uri}; msg=#{e.message}; remaining-attempts=#{remaining_attempts}", e
134
+
135
+ if remaining_attempts > 0
136
+ sleep 2
137
+ retry
138
+ end
139
+
140
+ return
141
+ end
142
+ end
143
+
144
+ log "exceeded max redirects"
145
+ return
146
+ end
147
+
148
+ def verify_checksum(archive)
149
+ unless expected = @checksums[@arch]
150
+ log "no checksum provided; arch=#{@arch}"
151
+ return false
152
+ end
153
+
154
+ actual = Digest::SHA2.hexdigest(archive)
155
+
156
+ unless expected == actual
157
+ log "checksum mismatch; expected=#{expected}; actual=#{actual}"
158
+ return false
159
+ end
160
+
161
+ true
162
+ end
163
+
164
+ def inflate(archive)
165
+ inflater = Zlib::Inflate.new(32 + Zlib::MAX_WBITS)
166
+ inflated = inflater.inflate(archive)
167
+ inflater.close
168
+ inflated
169
+ end
170
+
171
+ def source_uri
172
+ "#{@source}/#{@version}/libskylight.#{@arch}.a.gz"
173
+ end
174
+
175
+ def deconstruct_uri(uri)
176
+ uri = URI(uri)
177
+ [ uri.host, uri.port, uri.scheme == 'https', uri.request_uri ]
178
+ end
179
+
180
+ def maybe_raise(err)
181
+ log err
182
+
183
+ if @required
184
+ raise err
185
+ end
186
+ end
187
+
188
+ def log(msg, e = nil)
189
+ msg = "[SKYLIGHT] #{msg}"
190
+ msg << "\n#{e.backtrace.join("\n")}" if e
191
+ @log.info msg
192
+ end
193
+ end
194
+ end
195
+ end
@@ -1,4 +1,4 @@
1
1
  module Skylight
2
- VERSION = '0.3.6'
2
+ VERSION = '0.3.7'
3
3
  end
4
4
 
metadata CHANGED
@@ -1,27 +1,27 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: skylight
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.6
4
+ version: 0.3.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tilde, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-27 00:00:00.000000000 Z
11
+ date: 2014-04-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - '>='
18
18
  - !ruby/object:Gem::Version
19
19
  version: 3.0.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: 3.0.0
27
27
  description:
@@ -33,13 +33,6 @@ extensions:
33
33
  - ext/extconf.rb
34
34
  extra_rdoc_files: []
35
35
  files:
36
- - CHANGELOG.md
37
- - README.md
38
- - bin/skylight
39
- - ext/checksums.yml
40
- - ext/extconf.rb
41
- - ext/skylight.map
42
- - ext/skylight_native.c
43
36
  - lib/skylight.rb
44
37
  - lib/skylight/api.rb
45
38
  - lib/skylight/cli.rb
@@ -78,6 +71,7 @@ files:
78
71
  - lib/skylight/util/http.rb
79
72
  - lib/skylight/util/inflector.rb
80
73
  - lib/skylight/util/logging.rb
74
+ - lib/skylight/util/native_ext_fetcher.rb
81
75
  - lib/skylight/util/queue.rb
82
76
  - lib/skylight/util/task.rb
83
77
  - lib/skylight/util/uniform_sample.rb
@@ -139,6 +133,14 @@ files:
139
133
  - lib/sql_lexer.rb
140
134
  - lib/sql_lexer/lexer.rb
141
135
  - lib/sql_lexer/version.rb
136
+ - ext/skylight.h
137
+ - ext/skylight_native.c
138
+ - ext/skylight.map
139
+ - ext/extconf.rb
140
+ - ext/libskylight.yml
141
+ - CHANGELOG.md
142
+ - README.md
143
+ - bin/skylight
142
144
  homepage: http://www.skylight.io
143
145
  licenses: []
144
146
  metadata: {}
@@ -148,17 +150,17 @@ require_paths:
148
150
  - lib
149
151
  required_ruby_version: !ruby/object:Gem::Requirement
150
152
  requirements:
151
- - - ">="
153
+ - - '>='
152
154
  - !ruby/object:Gem::Version
153
155
  version: 1.9.2
154
156
  required_rubygems_version: !ruby/object:Gem::Requirement
155
157
  requirements:
156
- - - ">="
158
+ - - '>='
157
159
  - !ruby/object:Gem::Version
158
160
  version: '0'
159
161
  requirements: []
160
162
  rubyforge_project:
161
- rubygems_version: 2.2.1
163
+ rubygems_version: 2.0.3
162
164
  signing_key:
163
165
  specification_version: 4
164
166
  summary: Skylight is a ruby application monitoring tool. Currently in closed beta.
@@ -1,3 +0,0 @@
1
- ---
2
- x86_64-linux: "98b04f7d73c1894cc79621a135b4598a679c421f5ff3eecc652f84ba07258d9c"
3
- i686-linux : "1d4bbd58e319237b18752607d087ce0c895fe99c58482e994abe62a9f07d41dd"