observability 0.1.0 → 0.2.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.
@@ -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: []