observability 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,22 @@
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+
4
+ require 'observability/instrumentation' unless defined?( Observability::Instrumentation )
5
+
6
+
7
+ # Instrumentation for the Grape HTTP API framework
8
+ # Refs:
9
+ # - http://www.ruby-grape.org/
10
+ module Observability::Instrumentation::Grape
11
+ extend Observability::Instrumentation
12
+
13
+ depends_on 'Grape'
14
+
15
+
16
+ when_installed( 'Grape::API' ) do
17
+ Grape::API.extend( Observability )
18
+ Grape::API.observe_method( :call )
19
+ end
20
+
21
+ end # module Observability::Instrumentation::Grape
22
+
@@ -0,0 +1,23 @@
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+
4
+ require 'observability/instrumentation' unless defined?( Observability::Instrumentation )
5
+
6
+
7
+ # Instrumentation for the Rack HTTP interface library
8
+ # Refs:
9
+ # - https://rack.github.io
10
+ module Observability::Instrumentation::Rack
11
+ extend Observability::Instrumentation
12
+
13
+ depends_on 'Rack'
14
+
15
+
16
+ when_installed( 'Rack::Builder' ) do
17
+ Rack::Builder.extend( Observability )
18
+ Rack::Builder.observe_method( :call )
19
+ end
20
+
21
+
22
+ end # module Observability::Instrumentation::Rack
23
+
@@ -0,0 +1,37 @@
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+
4
+ require 'observability/instrumentation' unless defined?( Observability::Instrumentation )
5
+
6
+
7
+ # Instrumentation for the Sequel database toolkit.
8
+ # Refs:
9
+ # - http://sequel.jeremyevans.net/
10
+ module Observability::Instrumentation::Sequel
11
+ extend Observability::Instrumentation
12
+
13
+ depends_on 'Sequel::Database'
14
+
15
+
16
+ when_installed( 'Sequel::Database' ) do
17
+ Sequel::Database.extend( Observability )
18
+ Sequel::Database.observe_class_method( :connect )
19
+ Sequel::Database.observe_method( :disconnect )
20
+ end
21
+
22
+
23
+ when_installed( 'Sequel::Postgres::Adapter' ) do
24
+ Sequel::Postgres::Adapter.extend( Observability )
25
+ Sequel::Postgres::Adapter.observe_method( :execute, timed: true ) do |sql, *|
26
+ begin
27
+ nsql = PgQuery.normalize( sql )
28
+ Observability.observer.add( query: nsql )
29
+ rescue => err
30
+ Loggability[ Observability ].warn "Couldn't normalize query: %p" % [ sql ]
31
+ end
32
+ end
33
+ end
34
+
35
+
36
+ end # module Observability::Instrumentation::Sequel
37
+
@@ -271,17 +271,23 @@ class Observability::Observer
271
271
  ### Return a Hash of fields to add to the current event derived from the given
272
272
  ### +exception+ object.
273
273
  def fields_from_exception( exception )
274
- trace_frames = exception.backtrace_locations.map do |loc|
275
- { label: loc.label, path: loc.absolute_path, lineno: loc.lineno }
274
+ fields = {
275
+ type: exception.class.name,
276
+ message: exception.message,
277
+ }
278
+
279
+ if exception.cause
280
+ cause_fields = self.fields_from_exception( exception.cause )
281
+ fields[ :cause ] = cause_fields[ :error ]
276
282
  end
277
283
 
278
- return {
279
- error: {
280
- type: exception.class.name,
281
- message: exception.message,
282
- backtrace: trace_frames
283
- }
284
- }
284
+ if ( locations = exception.backtrace_locations )
285
+ fields[ :backtrace ] = locations.map do |loc|
286
+ { label: loc.label, path: loc.absolute_path, lineno: loc.lineno }
287
+ end
288
+ end
289
+
290
+ return { error: fields }
285
291
  end
286
292
 
287
293
 
@@ -25,7 +25,9 @@ class Observability::Sender
25
25
 
26
26
  ##
27
27
  # The sender type to use
28
- setting :type, default: :null
28
+ setting :type, default: :null do |value|
29
+ value && value.to_sym
30
+ end
29
31
 
30
32
  end
31
33
 
@@ -0,0 +1,114 @@
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+
4
+ require 'socket'
5
+ require 'configurability'
6
+
7
+ require 'observability/sender' unless defined?( Observability::Sender )
8
+
9
+ # A sender that sends events as JSON over multicast UDP.
10
+ class Observability::Sender::UdpMulticast < Observability::Sender
11
+ extend Configurability
12
+
13
+
14
+ # Number of seconds to wait between retrying a blocked write
15
+ RETRY_INTERVAL = 0.25
16
+
17
+ # The pipeline to use for turning events into network data
18
+ SERIALIZE_PIPELINE = :resolve.to_proc >> JSON.method( :generate )
19
+
20
+
21
+ # Declare configurable settings
22
+ configurability( 'observability.sender.udp' ) do
23
+
24
+ ##
25
+ # The local address to bind to
26
+ setting :bind_address, default: '0.0.0.0'
27
+
28
+ ##
29
+ # The address of the multicast group to join
30
+ setting :multicast_address, default: '224.15.7.75'
31
+
32
+ ##
33
+ # The TTL of the outgoing messages, i.e., how many hops they will be limited to
34
+ setting :multicast_ttl, default: 1
35
+
36
+ ##
37
+ # The port to bind to
38
+ setting :port, default: 15775
39
+
40
+ end
41
+
42
+
43
+ ### Return an IPAddr that represents the local + multicast addresses to bind to.
44
+ def self::bind_addr
45
+ return IPAddr.new( self.bind_address ).hton + IPAddr.new( self.multicast_address ).hton
46
+ end
47
+
48
+
49
+ ### Create a new UDP sender
50
+ def initialize( * )
51
+ @multicast_address = self.class.multicast_address
52
+ @port = self.class.port
53
+ @socket = self.create_socket
54
+ end
55
+
56
+
57
+ ######
58
+ public
59
+ ######
60
+
61
+ ##
62
+ # The address of the multicast group to send to
63
+ attr_reader :multicast_address
64
+
65
+ ##
66
+ # The port to send on
67
+ attr_reader :port
68
+
69
+ ##
70
+ # The socket to send events over
71
+ attr_reader :socket
72
+
73
+
74
+ ### Stop the sender's executor.
75
+ def stop
76
+ super
77
+
78
+ self.socket.shutdown( :WR )
79
+ end
80
+
81
+
82
+ ### Serialize each the given +events+ and return the results.
83
+ def serialize_events( events )
84
+ return events.map( &SERIALIZE_PIPELINE )
85
+ end
86
+
87
+
88
+ ### Send the specified +event+.
89
+ def send_event( data )
90
+
91
+ until data.empty?
92
+ bytes = self.socket.send( data, 0, self.multicast_address, self.port )
93
+
94
+ self.log.debug "Sent: %p" % [ data[0, bytes] ]
95
+ data[ 0, bytes ] = ''
96
+ end
97
+ end
98
+
99
+
100
+ ### Create and return a UDPSocket after setting it up for multicast.
101
+ def create_socket
102
+ iaddr = self.class.bind_addr
103
+ socket = UDPSocket.new
104
+
105
+ socket.setsockopt( :IPPROTO_IP, :IP_ADD_MEMBERSHIP, iaddr )
106
+ socket.setsockopt( :IPPROTO_IP, :IP_MULTICAST_TTL, self.class.multicast_ttl )
107
+ socket.setsockopt( :IPPROTO_IP, :IP_MULTICAST_LOOP, 1 )
108
+ socket.setsockopt( :SOL_SOCKET, :SO_REUSEPORT, 1 )
109
+
110
+ return socket
111
+ end
112
+
113
+ end # class Observability::Sender::UDP
114
+
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env rspec -cfd
2
+
3
+ require_relative '../spec_helper'
4
+
5
+ require 'observability/instrumentation'
6
+
7
+
8
+ describe Observability::Instrumentation do
9
+
10
+ let( :instrumentation ) do
11
+ mod = Module.new
12
+ mod.extend( described_class )
13
+ return mod
14
+ end
15
+
16
+
17
+ it "provides a way to load instrumentation for common libraries" do
18
+ expect( described_class ).to receive( :require ).
19
+ with( 'observability/instrumentation/rack' )
20
+
21
+ described_class.load( :rack )
22
+ end
23
+
24
+
25
+ it "can load several libraries at once" do
26
+ expect( described_class ).to receive( :require ).
27
+ with( 'observability/instrumentation/sequel' )
28
+ expect( described_class ).to receive( :require ).
29
+ with( 'observability/instrumentation/bunny' )
30
+
31
+ described_class.load( :sequel, :bunny )
32
+ end
33
+
34
+
35
+ it "can install loaded instrumentation" do
36
+ installation_callback_called = false
37
+
38
+ instrumentation.when_installed do
39
+ installation_callback_called = true
40
+ end
41
+
42
+ expect {
43
+ described_class.install
44
+ }.to change { installation_callback_called }.to( true )
45
+ end
46
+
47
+ end
48
+
@@ -252,6 +252,37 @@ describe Observability::Observer do
252
252
  end
253
253
 
254
254
 
255
+ it "can be added for a secondary Exception" do
256
+ observer = described_class.new( :testing )
257
+ observer.event( 'acme.engine.start' )
258
+
259
+ expect {
260
+ observer.finish_after_block do
261
+ begin
262
+ raise "misfire!"
263
+ rescue => err
264
+ raise ArgumentError, "Cleared a misfire."
265
+ end
266
+ end
267
+ }.to raise_error( ArgumentError, 'Cleared a misfire.' )
268
+
269
+ event = observer.sender.enqueued_events.last
270
+ expect( event.type ).to eq( 'acme.engine.start' )
271
+
272
+ expect( event.fields ).to include(
273
+ error: a_hash_including(
274
+ type: 'ArgumentError',
275
+ message: 'Cleared a misfire.',
276
+ cause: a_hash_including(
277
+ type: 'RuntimeError',
278
+ message: 'misfire!',
279
+ backtrace: an_instance_of( Array )
280
+ )
281
+ )
282
+ )
283
+ end
284
+
285
+
255
286
  it "can be added for any object that responds to #to_h" do
256
287
  observer = described_class.new( :testing )
257
288
  observer.event( 'acme.engine.start' )
@@ -271,7 +302,6 @@ describe Observability::Observer do
271
302
  end
272
303
 
273
304
 
274
-
275
305
  describe "context" do
276
306
 
277
307
  it "can be added for all inner events" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: observability
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Granger
@@ -11,8 +11,8 @@ cert_chain:
11
11
  - |
12
12
  -----BEGIN CERTIFICATE-----
13
13
  MIIENDCCApygAwIBAgIBATANBgkqhkiG9w0BAQsFADAiMSAwHgYDVQQDDBdnZWQv
14
- REM9RmFlcmllTVVEL0RDPW9yZzAeFw0xODExMjAxODI5NTlaFw0xOTExMjAxODI5
15
- NTlaMCIxIDAeBgNVBAMMF2dlZC9EQz1GYWVyaWVNVUQvREM9b3JnMIIBojANBgkq
14
+ REM9RmFlcmllTVVEL0RDPW9yZzAeFw0xOTEwMDkwMDM2NTdaFw0yMDEwMDgwMDM2
15
+ NTdaMCIxIDAeBgNVBAMMF2dlZC9EQz1GYWVyaWVNVUQvREM9b3JnMIIBojANBgkq
16
16
  hkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAvyVhkRzvlEs0fe7145BYLfN6njX9ih5H
17
17
  L60U0p0euIurpv84op9CNKF9tx+1WKwyQvQP7qFGuZxkSUuWcP/sFhDXL1lWUuIl
18
18
  M4uHbGCRmOshDrF4dgnBeOvkHr1fIhPlJm5FO+Vew8tSQmlDsosxLUx+VB7DrVFO
@@ -24,17 +24,17 @@ cert_chain:
24
24
  N2I4L/ZOIe2DIVuYH7aLHfjZDQv/mNgpAgMBAAGjdTBzMAkGA1UdEwQCMAAwCwYD
25
25
  VR0PBAQDAgSwMB0GA1UdDgQWBBRyjf55EbrHagiRLqt5YAd3yb8k4DAcBgNVHREE
26
26
  FTATgRFnZWRARmFlcmllTVVELm9yZzAcBgNVHRIEFTATgRFnZWRARmFlcmllTVVE
27
- Lm9yZzANBgkqhkiG9w0BAQsFAAOCAYEAP9Ffkvg4e8CjIWi8SykQ8oJSS8jbmbgF
28
- abke3vXWLG6V9kFiObuJd5wZRBluJANu7bEtjgc3fFaGVP2XxVdCpVjNbmMDg4Qp
29
- ovvczP53X6pQP2RSZgxF6Lblvy8y11RziUTVRG/Z2aJHsElo6gI7vQznE/OSDrhC
30
- gEhr8uaIUt7D+HZWRbU0+MkKPpL5uMqaFuJbqXEvSwPTuUuYkDfNfsjQO7ruWBac
31
- bxHCrvpZ6Tijc0nrlyXi6gPOCLeaqhau2xFnlvKgELwsGYSoKBJyDwqtQ5kwrOlU
32
- tkSyLrfZ+RZcH535Hyvif7ZxB0v5OxXXoec+N2vrUsEUMRDL9dg4/WFdN8hIOixF
33
- 3IPKpZ1ho0Ya5q7yhygtBK9/NBFHw+nbJjcltfPDBXleRe8u73gnQo8AZIhStYSP
34
- v4qqqa27Bs468d6SoPxjSm8a2mM9HZ4OdWhq4tFsbTeXDVquCfi64OTEaTt2xQdR
35
- JnC4lpJfCP6aCXa5h2XAQfPSH636cQap
27
+ Lm9yZzANBgkqhkiG9w0BAQsFAAOCAYEAFqsr6o0SvQRgjQVmhbQvExRnCMCoW1yb
28
+ FJiN7A5RA2Iy2E61OG1Ul5nGmaDmx/PNB/6JIbIV3B9Uq8aTZx4uOjK7r8vMl1/t
29
+ ZfY7r6HejJfXlcO2m6JDMbpdyEVv916LncBkzZRz6vnnNCx+31f15FKddxujpAFd
30
+ qpn3JRQY+oj7ZkoccL/IUiDpxQWeS3oOoz9qr2kVTp8R50InZimt79FqCl/1m66W
31
+ kdOuf+wM3DDx7Rt4IVNHrhGlyfMr7xjKW1Q3gll+pMN1DT6Ajx/t3JDSEg7BnnEW
32
+ r7AciSO6J4ApUdqyG+coLFlGdtgFTgRHv7ihbQtDI7Z/LV7A4Spn1j2PK3j0Omri
33
+ kSl1hPVigRytfgdVGiLXzvkkrkgj9EknCaj5UHbac7XvVBrljXj9hsnnqTANaKsg
34
+ jBZSA+N+xUTgUWpXjjwsLZjzJkhWATJWq+krNXcqpwXo6HsjmdUxoFMt63RBb+sI
35
+ XrxOxp8o0uOkU7FdLSGsyqJ2LzsR4obN
36
36
  -----END CERTIFICATE-----
37
- date: 2019-07-24 00:00:00.000000000 Z
37
+ date: 2019-10-17 00:00:00.000000000 Z
38
38
  dependencies:
39
39
  - !ruby/object:Gem::Dependency
40
40
  name: concurrent-ruby
@@ -42,28 +42,28 @@ dependencies:
42
42
  requirements:
43
43
  - - "~>"
44
44
  - !ruby/object:Gem::Version
45
- version: 1.1.5
45
+ version: '1.1'
46
46
  type: :runtime
47
47
  prerelease: false
48
48
  version_requirements: !ruby/object:Gem::Requirement
49
49
  requirements:
50
50
  - - "~>"
51
51
  - !ruby/object:Gem::Version
52
- version: 1.1.5
52
+ version: '1.1'
53
53
  - !ruby/object:Gem::Dependency
54
54
  name: concurrent-ruby-ext
55
55
  requirement: !ruby/object:Gem::Requirement
56
56
  requirements:
57
57
  - - "~>"
58
58
  - !ruby/object:Gem::Version
59
- version: 1.1.5
59
+ version: '1.1'
60
60
  type: :runtime
61
61
  prerelease: false
62
62
  version_requirements: !ruby/object:Gem::Requirement
63
63
  requirements:
64
64
  - - "~>"
65
65
  - !ruby/object:Gem::Version
66
- version: 1.1.5
66
+ version: '1.1'
67
67
  - !ruby/object:Gem::Dependency
68
68
  name: loggability
69
69
  requirement: !ruby/object:Gem::Requirement
@@ -121,61 +121,33 @@ dependencies:
121
121
  - !ruby/object:Gem::Version
122
122
  version: '1.3'
123
123
  - !ruby/object:Gem::Dependency
124
- name: hoe-mercurial
125
- requirement: !ruby/object:Gem::Requirement
126
- requirements:
127
- - - "~>"
128
- - !ruby/object:Gem::Version
129
- version: '1.4'
130
- type: :development
131
- prerelease: false
132
- version_requirements: !ruby/object:Gem::Requirement
133
- requirements:
134
- - - "~>"
135
- - !ruby/object:Gem::Version
136
- version: '1.4'
137
- - !ruby/object:Gem::Dependency
138
- name: hoe-deveiate
139
- requirement: !ruby/object:Gem::Requirement
140
- requirements:
141
- - - "~>"
142
- - !ruby/object:Gem::Version
143
- version: '0.10'
144
- type: :development
145
- prerelease: false
146
- version_requirements: !ruby/object:Gem::Requirement
147
- requirements:
148
- - - "~>"
149
- - !ruby/object:Gem::Version
150
- version: '0.10'
151
- - !ruby/object:Gem::Dependency
152
- name: hoe-highline
124
+ name: timecop
153
125
  requirement: !ruby/object:Gem::Requirement
154
126
  requirements:
155
127
  - - "~>"
156
128
  - !ruby/object:Gem::Version
157
- version: '0.2'
129
+ version: '0.9'
158
130
  type: :development
159
131
  prerelease: false
160
132
  version_requirements: !ruby/object:Gem::Requirement
161
133
  requirements:
162
134
  - - "~>"
163
135
  - !ruby/object:Gem::Version
164
- version: '0.2'
136
+ version: '0.9'
165
137
  - !ruby/object:Gem::Dependency
166
- name: timecop
138
+ name: rake-deveiate
167
139
  requirement: !ruby/object:Gem::Requirement
168
140
  requirements:
169
141
  - - "~>"
170
142
  - !ruby/object:Gem::Version
171
- version: '0.9'
143
+ version: '0.4'
172
144
  type: :development
173
145
  prerelease: false
174
146
  version_requirements: !ruby/object:Gem::Requirement
175
147
  requirements:
176
148
  - - "~>"
177
149
  - !ruby/object:Gem::Version
178
- version: '0.9'
150
+ version: '0.4'
179
151
  - !ruby/object:Gem::Dependency
180
152
  name: simplecov
181
153
  requirement: !ruby/object:Gem::Requirement
@@ -204,82 +176,31 @@ dependencies:
204
176
  - - "~>"
205
177
  - !ruby/object:Gem::Version
206
178
  version: '0.1'
207
- - !ruby/object:Gem::Dependency
208
- name: rdoc
209
- requirement: !ruby/object:Gem::Requirement
210
- requirements:
211
- - - ">="
212
- - !ruby/object:Gem::Version
213
- version: '4.0'
214
- - - "<"
215
- - !ruby/object:Gem::Version
216
- version: '7'
217
- type: :development
218
- prerelease: false
219
- version_requirements: !ruby/object:Gem::Requirement
220
- requirements:
221
- - - ">="
222
- - !ruby/object:Gem::Version
223
- version: '4.0'
224
- - - "<"
225
- - !ruby/object:Gem::Version
226
- version: '7'
227
- - !ruby/object:Gem::Dependency
228
- name: hoe
229
- requirement: !ruby/object:Gem::Requirement
230
- requirements:
231
- - - "~>"
232
- - !ruby/object:Gem::Version
233
- version: '3.17'
234
- type: :development
235
- prerelease: false
236
- version_requirements: !ruby/object:Gem::Requirement
237
- requirements:
238
- - - "~>"
239
- - !ruby/object:Gem::Version
240
- version: '3.17'
241
- description: "Observability is a toolkit for instrumenting code to make it more observable,\nfollowing
242
- the principle of Observability-Oriented Design as expressed by Charity\nMajors (@mipsytipsy).\n\nIts
243
- goals are [stolen from https://charity.wtf/2019/02/05/logs-vs-structured-events/]:\n\n*
244
- Emit a rich record from the perspective of a single action as the code is\n executing.\n*
245
- Emit a single event per action per system that it occurs in. Write it out just\n
246
- \ before the action completes or errors.\n* Bypass local disk entirely, write to
247
- a remote service.\n* Sample if needed for cost or resource constraints. Practice
248
- dynamic sampling.\n* Treat this like operational data, not transactional data. Be
249
- profligate and\n disposable.\n* Feed this data into a columnar store or honeycomb
250
- or similar\n* Now use it every day. Not just as a last resort. Get knee deep in
251
- production\n every single day. Explore. Ask and answer rich questions about your
252
- systems,\n system quality, system behavior, outliers, error conditions, etc. You
253
- will be\n absolutely amazed how useful it is … and appalled by what you turn up.
254
- \U0001F642"
179
+ description: |-
180
+ Observability is a toolkit for instrumenting code to make it more observable.
181
+ It follows the principle of Observability-Oriented Design as expressed by Charity
182
+ Majors (@mipsytipsy).
255
183
  email:
256
- - ged@FaerieMUD.org
257
- executables:
258
- - observability-collector
184
+ - ged@faeriemud.org
185
+ executables: []
259
186
  extensions: []
260
- extra_rdoc_files:
261
- - DevNotes.md
262
- - History.md
263
- - LICENSE.txt
264
- - Manifest.txt
265
- - README.md
187
+ extra_rdoc_files: []
266
188
  files:
267
- - ".document"
268
- - ".rdoc_options"
269
- - ".simplecov"
270
- - ChangeLog
271
189
  - DevNotes.md
272
190
  - History.md
273
191
  - LICENSE.txt
274
- - Manifest.txt
275
192
  - README.md
276
- - Rakefile
277
193
  - bin/observability-collector
278
- - examples/basic-usage.rb
279
194
  - lib/observability.rb
280
195
  - lib/observability/collector.rb
196
+ - lib/observability/collector/rabbitmq.rb
281
197
  - lib/observability/collector/timescale.rb
282
198
  - lib/observability/event.rb
199
+ - lib/observability/instrumentation.rb
200
+ - lib/observability/instrumentation/bunny.rb
201
+ - lib/observability/instrumentation/grape.rb
202
+ - lib/observability/instrumentation/rack.rb
203
+ - lib/observability/instrumentation/sequel.rb
283
204
  - lib/observability/observer.rb
284
205
  - lib/observability/observer_hooks.rb
285
206
  - lib/observability/sender.rb
@@ -287,7 +208,9 @@ files:
287
208
  - lib/observability/sender/null.rb
288
209
  - lib/observability/sender/testing.rb
289
210
  - lib/observability/sender/udp.rb
211
+ - lib/observability/sender/udp_multicast.rb
290
212
  - spec/observability/event_spec.rb
213
+ - spec/observability/instrumentation_spec.rb
291
214
  - spec/observability/observer_hooks_spec.rb
292
215
  - spec/observability/observer_spec.rb
293
216
  - spec/observability/sender/logger_spec.rb
@@ -295,21 +218,19 @@ files:
295
218
  - spec/observability/sender_spec.rb
296
219
  - spec/observability_spec.rb
297
220
  - spec/spec_helper.rb
298
- homepage: http://bitbucket.org/ged/observability
221
+ homepage: https://hg.sr.ht/~ged/Observability
299
222
  licenses:
300
223
  - BSD-3-Clause
301
224
  metadata: {}
302
225
  post_install_message:
303
- rdoc_options:
304
- - "--main"
305
- - README.md
226
+ rdoc_options: []
306
227
  require_paths:
307
228
  - lib
308
229
  required_ruby_version: !ruby/object:Gem::Requirement
309
230
  requirements:
310
231
  - - ">="
311
232
  - !ruby/object:Gem::Version
312
- version: 2.4.0
233
+ version: '0'
313
234
  required_rubygems_version: !ruby/object:Gem::Requirement
314
235
  requirements:
315
236
  - - ">="
@@ -319,7 +240,5 @@ requirements: []
319
240
  rubygems_version: 3.0.3
320
241
  signing_key:
321
242
  specification_version: 4
322
- summary: Observability is a toolkit for instrumenting code to make it more observable,
323
- following the principle of Observability-Oriented Design as expressed by Charity
324
- Majors (@mipsytipsy)
243
+ summary: Observability is a toolkit for instrumenting code to make it more observable.
325
244
  test_files: []