observability 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.document +5 -0
- data/.rdoc_options +16 -0
- data/.simplecov +9 -0
- data/ChangeLog +139 -0
- data/DevNotes.md +103 -0
- data/History.md +4 -0
- data/LICENSE.txt +20 -0
- data/Manifest.txt +31 -0
- data/README.md +93 -0
- data/Rakefile +102 -0
- data/bin/observability-collector +16 -0
- data/examples/basic-usage.rb +18 -0
- data/lib/observability.rb +122 -0
- data/lib/observability/collector.rb +61 -0
- data/lib/observability/collector/timescale.rb +140 -0
- data/lib/observability/event.rb +103 -0
- data/lib/observability/observer.rb +296 -0
- data/lib/observability/observer_hooks.rb +28 -0
- data/lib/observability/sender.rb +127 -0
- data/lib/observability/sender/logger.rb +37 -0
- data/lib/observability/sender/null.rb +30 -0
- data/lib/observability/sender/testing.rb +56 -0
- data/lib/observability/sender/udp.rb +88 -0
- data/spec/observability/event_spec.rb +106 -0
- data/spec/observability/observer_hooks_spec.rb +47 -0
- data/spec/observability/observer_spec.rb +292 -0
- data/spec/observability/sender/logger_spec.rb +28 -0
- data/spec/observability/sender/udp_spec.rb +86 -0
- data/spec/observability/sender_spec.rb +77 -0
- data/spec/observability_spec.rb +132 -0
- data/spec/spec_helper.rb +155 -0
- metadata +325 -0
- metadata.gz.sig +1 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9e8e5db4293106c0b48ed3ea428c4a786eec948d11f19e8a78950ee49383655b
|
4
|
+
data.tar.gz: a9195f349e14fbc0721c22af67f8cb115bb15264a68dbf12ffd4243418f62167
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a851f201c9ff6757fb53bd14455b062fec2e4923d1386ee0192bc7f3033b3bb74ce48549b2b21ce4888ed674cb6f48050c89039b9d678d32baf85721fde965db
|
7
|
+
data.tar.gz: b7eee539d2e8a7ea9ae40262071b21f986945786f2409e3721342e182e5acb6bee27c25a2dc35ae5db1952aa434c32faec23203946b345cdfb88201fc7f4b4f9
|
checksums.yaml.gz.sig
ADDED
Binary file
|
data.tar.gz.sig
ADDED
Binary file
|
data/.document
ADDED
data/.rdoc_options
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
--- !ruby/object:RDoc::Options
|
2
|
+
encoding: UTF-8
|
3
|
+
static_path: []
|
4
|
+
rdoc_include:
|
5
|
+
- .
|
6
|
+
charset: UTF-8
|
7
|
+
exclude:
|
8
|
+
hyperlink_all: false
|
9
|
+
line_numbers: false
|
10
|
+
main_page: README.md
|
11
|
+
markup: markdown
|
12
|
+
show_hash: false
|
13
|
+
tab_width: 8
|
14
|
+
title: Observability Documentation
|
15
|
+
visibility: :protected
|
16
|
+
webcvs:
|
data/.simplecov
ADDED
data/ChangeLog
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
2019-07-22 Michael Granger <ged@FaerieMUD.org>
|
2
|
+
|
3
|
+
@ * .hgignore, DevNotes.md, Manifest.txt, lib/observability.rb,
|
4
|
+
| lib/observability/event.rb, lib/observability/observer.rb,
|
5
|
+
| lib/observability/observer_hooks.rb, lib/observability/sender.rb,
|
6
|
+
| lib/observability/sender/logger.rb,
|
7
|
+
| lib/observability/sender/testing.rb,
|
8
|
+
| lib/observability/sender/udp.rb, spec/observability/event_spec.rb,
|
9
|
+
| spec/observability/observer_hooks_spec.rb,
|
10
|
+
| spec/observability/observer_spec.rb,
|
11
|
+
| spec/observability/sender/udp_spec.rb,
|
12
|
+
| spec/observability/sender_spec.rb, spec/observability_spec.rb:
|
13
|
+
| Add a bunch more work:
|
14
|
+
|
|
15
|
+
| - Add the beginnings of context
|
16
|
+
| - Refactor the sender to be more easily subclassed
|
17
|
+
| - Add a UDP sender
|
18
|
+
| - Refactor finishing around a block up to the Observer
|
19
|
+
| - Rename `observer` hook to `observability` to avoid colliding with
|
20
|
+
| observer-pattern systems.
|
21
|
+
| - Add pending specs for intended features
|
22
|
+
| - Removed unused `observed_system` DSL method
|
23
|
+
| - Concurrent logs to Observability logger
|
24
|
+
| [c206c306394e] [tip]
|
25
|
+
|
|
26
|
+
2019-07-19 Michael Granger <ged@FaerieMUD.org>
|
27
|
+
|
28
|
+
o * bin/observability-collector, experiments/postgres-events.sql,
|
29
|
+
| lib/observability.rb, lib/observability/collector.rb,
|
30
|
+
| lib/observability/collector/timescale.rb,
|
31
|
+
| lib/observability/event.rb, lib/observability/sender/logger.rb,
|
32
|
+
| spec/observability/sender/logger_spec.rb,
|
33
|
+
| spec/observability_spec.rb:
|
34
|
+
| More work on the collector spike, start adding callbacks to method
|
35
|
+
| wrappers
|
36
|
+
| [959d6bf1bdcd]
|
37
|
+
|
|
38
|
+
o * experiments/postgres-events.sql,
|
39
|
+
| lib/observability/collector/timescale.rb:
|
40
|
+
| Add more work on the timescale collector
|
41
|
+
| [f0056a02fa49]
|
42
|
+
|
|
43
|
+
2019-07-18 Michael Granger <ged@FaerieMUD.org>
|
44
|
+
|
45
|
+
o * experiments/singleton-prepend.rb, experiments/thread-closures.rb,
|
46
|
+
| lib/observability.rb, lib/observability/collector.rb,
|
47
|
+
| lib/observability/collector/timescale.rb,
|
48
|
+
| lib/observability/observer.rb, lib/observability/observer_hooks.rb,
|
49
|
+
| lib/observability/sender/logger.rb,
|
50
|
+
| spec/observability/event_spec.rb,
|
51
|
+
| spec/observability/observer_spec.rb, spec/observability_spec.rb:
|
52
|
+
| Start prototyping the collector, add observers for class methods
|
53
|
+
| [21f0ed971661]
|
54
|
+
|
|
55
|
+
o * .gems, .hgignore, DevNotes.md, lib/observability.rb,
|
56
|
+
| lib/observability/event.rb, lib/observability/observer.rb,
|
57
|
+
| lib/observability/observer_hooks.rb, lib/observability/sender.rb,
|
58
|
+
| lib/observability/sender/logger.rb, observability.gemspec,
|
59
|
+
| spec/observability/observer_spec.rb,
|
60
|
+
| spec/observability/sender/logger_spec.rb,
|
61
|
+
| spec/observability/sender_spec.rb:
|
62
|
+
| Add a bit more work on event and senders
|
63
|
+
| [4413e7b15a86]
|
64
|
+
|
|
65
|
+
2019-07-17 Michael Granger <ged@FaerieMUD.org>
|
66
|
+
|
67
|
+
o * .gems, DevNotes.md, lib/observability.rb,
|
68
|
+
| lib/observability/event.rb, lib/observability/observer.rb,
|
69
|
+
| lib/observability/observer_hooks.rb,
|
70
|
+
| spec/observability/event_spec.rb,
|
71
|
+
| spec/observability/observer_hooks_spec.rb,
|
72
|
+
| spec/observability/observer_spec.rb, spec/observability_spec.rb,
|
73
|
+
| spec/spec_helper.rb:
|
74
|
+
| Add base observation system
|
75
|
+
| [f1670098182b]
|
76
|
+
|
|
77
|
+
2019-07-16 Michael Granger <ged@FaerieMUD.org>
|
78
|
+
|
79
|
+
o * lib/observability.rb, lib/observability/event.rb,
|
80
|
+
| lib/observability/observer.rb, lib/observability/sender/testing.rb,
|
81
|
+
| spec/observability/observer_spec.rb, spec/spec_helper.rb:
|
82
|
+
| Checkpoint of more spec work
|
83
|
+
| [bb75996b36b1]
|
84
|
+
|
|
85
|
+
2019-07-15 Michael Granger <ged@FaerieMUD.org>
|
86
|
+
|
87
|
+
o * .gems, Rakefile, lib/observability.rb,
|
88
|
+
| lib/observability/observer.rb, lib/observability/observer_hooks.rb,
|
89
|
+
| spec/observability_spec.rb, spec/spec_helper.rb:
|
90
|
+
| Refine observer->sender and start working on specs
|
91
|
+
| [afada6860d6b]
|
92
|
+
|
|
93
|
+
o * Rakefile, lib/observability.rb, lib/observability/event.rb,
|
94
|
+
| lib/observability/sender.rb, lib/observability/sender/null.rb:
|
95
|
+
| Add the base and default sender classes
|
96
|
+
| [cb5a39a73863]
|
97
|
+
|
|
98
|
+
2019-07-13 Michael Granger <ged@FaerieMUD.org>
|
99
|
+
|
100
|
+
o * Rakefile, lib/observability.rb, lib/observability/event.rb,
|
101
|
+
| lib/observability/observer.rb, lib/observability/observer_hooks.rb,
|
102
|
+
| observability.gemspec:
|
103
|
+
| Add more spike work
|
104
|
+
| [9ac3e587898e]
|
105
|
+
|
|
106
|
+
2019-07-12 Michael Granger <ged@FaerieMUD.org>
|
107
|
+
|
108
|
+
o * experiments/superstar.rb, lib/observability.rb:
|
109
|
+
| Flesh out more of the spike implementation
|
110
|
+
| [50b6c0061b4a]
|
111
|
+
|
|
112
|
+
2019-07-11 Michael Granger <ged@FaerieMUD.org>
|
113
|
+
|
114
|
+
o * .gems, Rakefile, experiments/actors.rb, lib/observability.rb,
|
115
|
+
| lib/observability/observer.rb, observability.gemspec:
|
116
|
+
| Checkpoint of more spike code
|
117
|
+
| [0b903d4090c9]
|
118
|
+
|
|
119
|
+
2019-07-09 Michael Granger <ged@FaerieMUD.org>
|
120
|
+
|
121
|
+
o * .gems, DevNotes.md, experiments/actors.rb, lib/observability.rb,
|
122
|
+
| lib/observability/observer.rb, spec/observability_spec.rb,
|
123
|
+
| spec/spec_helper.rb:
|
124
|
+
| Checkpoint of notes and experiments
|
125
|
+
| [0a1d6c04a68d]
|
126
|
+
|
|
127
|
+
2019-07-05 Michael Granger <ged@FaerieMUD.org>
|
128
|
+
|
129
|
+
o * DevNotes.md, examples/basic-usage.rb, lib/observability.rb:
|
130
|
+
| Add notes and start of first example
|
131
|
+
| [9851c06beeb7]
|
132
|
+
|
|
133
|
+
o * .document, .editorconfig, .gems, .hgignore, .pryrc, .rdoc_options,
|
134
|
+
.ruby-gemset, .ruby-version, .simplecov, Gemfile, History.md,
|
135
|
+
LICENSE.txt, Manifest.txt, README.md, Rakefile, certs/ged.pem,
|
136
|
+
lib/observability.rb, spec/observability_spec.rb,
|
137
|
+
spec/spec_helper.rb:
|
138
|
+
Initial commit
|
139
|
+
[2f9f3818be0c]
|
data/DevNotes.md
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
# Developer Notes
|
2
|
+
|
3
|
+
Characteristics of an observation:
|
4
|
+
|
5
|
+
* Should it be timed?
|
6
|
+
* What kinds of event models to support:
|
7
|
+
- Process: PID, PPID, PGID, rusage stuff
|
8
|
+
- Thread: Thread ID, PID, thread group ID, name, priority, thread_variables
|
9
|
+
- Net: Local IP, Peer IP, socktype, family, protocol, flags
|
10
|
+
|
11
|
+
|
12
|
+
## Implementation
|
13
|
+
|
14
|
+
Classes which are Observable will:
|
15
|
+
|
16
|
+
* Create an "observer" Module that contains all of its observation hooks
|
17
|
+
* Prepend the module onto the Observable class and its subclasses
|
18
|
+
* Expose an instance method #observer that returns the module
|
19
|
+
* Keep pending events and adds data to the innermost one via #observer.add
|
20
|
+
|
21
|
+
The Observability module will:
|
22
|
+
|
23
|
+
* Allow configuration of a sink to send events to
|
24
|
+
* No-op if no sink is configured
|
25
|
+
* Provide pluggable abstractions to:
|
26
|
+
- Provide the formatting of events
|
27
|
+
- Provide the transport to the event store
|
28
|
+
|
29
|
+
|
30
|
+
## Possible Datapoints
|
31
|
+
|
32
|
+
* Cardinality
|
33
|
+
- UUIDs
|
34
|
+
- db raw queries
|
35
|
+
- normalized queries
|
36
|
+
- comments
|
37
|
+
- PID/PPID
|
38
|
+
- app ID
|
39
|
+
- device ID
|
40
|
+
- HTTP headers
|
41
|
+
- build ID
|
42
|
+
- IP:port
|
43
|
+
- userid
|
44
|
+
* Context
|
45
|
+
-
|
46
|
+
* Structured data
|
47
|
+
* Tracing+events
|
48
|
+
|
49
|
+
|
50
|
+
## Event Naming Convention
|
51
|
+
|
52
|
+
Event names are dot-separated namespaces for events. You can use any convention that makes sense for your organization, but we suggest a convention like:
|
53
|
+
|
54
|
+
<namespace>.<system>.<verb>[.<detail>]+
|
55
|
+
|
56
|
+
For a class named `FM::Manager::Players`, an event sent for a method called
|
57
|
+
`connect_player` might be:
|
58
|
+
|
59
|
+
fm.manager.players.connect_player
|
60
|
+
|
61
|
+
And an exception raised from that method call might generate:
|
62
|
+
|
63
|
+
fm.manager.players.connect_player.exception
|
64
|
+
|
65
|
+
For the Sequel database toolkit, establishing a PostgreSQL connection might generate an event named:
|
66
|
+
|
67
|
+
sequel.adapters.postgres.connect
|
68
|
+
|
69
|
+
and if the connection subsequently failed, it might be followed with:
|
70
|
+
|
71
|
+
sequel.adapters.postgres.connect.failure
|
72
|
+
|
73
|
+
|
74
|
+
## Event "Models"
|
75
|
+
|
76
|
+
If you pass a `:model` option when creating an event, you can pre-populate an event with a bunch of useful datapoints. Some ideas for models:
|
77
|
+
|
78
|
+
|
79
|
+
`process`
|
80
|
+
: Adds information about the current process: e.g., `getrusage(2)` deltas, `pid`, `pgid`, `ppid`, `uid`, `euid`, `egid`, `utime`, `stime`, `cutime`, `cstime`
|
81
|
+
: The context should be a method that is called when a process starts and which returns when the process is going to shut down or has been shut down.
|
82
|
+
|
83
|
+
`loop`
|
84
|
+
: Adds information about the execution of a loop: e.g., `getrusage(2)` deltas, GC stats, etc.
|
85
|
+
: It should be created immediately inside the loop to be measured.
|
86
|
+
|
87
|
+
`thread`
|
88
|
+
: Adds information about the execution of a thread: e.g., thread ID, name, priority, etc.
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
## Unresolved Issues
|
93
|
+
|
94
|
+
- How should events sent from class methods be distinguished from instance methods of the same name?
|
95
|
+
- The object ID used for the event name for events sent from wrapped methods of singleton methods of anonymous classes is that of the singleton class, not the anonymous class itself. Given how infrequent this will be the case I'm not sure it's worth solving.
|
96
|
+
- Is it worth the additional cost of duping arguments to callbacks of wrapper methods to ensure they don't accidentally modify them?
|
97
|
+
- Make observing with a null sender be more no-opish.
|
98
|
+
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
|
103
|
+
|
data/History.md
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2019 Michael Granger
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest.txt
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
.document
|
2
|
+
.rdoc_options
|
3
|
+
.simplecov
|
4
|
+
ChangeLog
|
5
|
+
DevNotes.md
|
6
|
+
History.md
|
7
|
+
LICENSE.txt
|
8
|
+
Manifest.txt
|
9
|
+
README.md
|
10
|
+
Rakefile
|
11
|
+
bin/observability-collector
|
12
|
+
examples/basic-usage.rb
|
13
|
+
lib/observability.rb
|
14
|
+
lib/observability/collector.rb
|
15
|
+
lib/observability/collector/timescale.rb
|
16
|
+
lib/observability/event.rb
|
17
|
+
lib/observability/observer.rb
|
18
|
+
lib/observability/observer_hooks.rb
|
19
|
+
lib/observability/sender.rb
|
20
|
+
lib/observability/sender/logger.rb
|
21
|
+
lib/observability/sender/null.rb
|
22
|
+
lib/observability/sender/testing.rb
|
23
|
+
lib/observability/sender/udp.rb
|
24
|
+
spec/observability/event_spec.rb
|
25
|
+
spec/observability/observer_hooks_spec.rb
|
26
|
+
spec/observability/observer_spec.rb
|
27
|
+
spec/observability/sender/logger_spec.rb
|
28
|
+
spec/observability/sender/udp_spec.rb
|
29
|
+
spec/observability/sender_spec.rb
|
30
|
+
spec/observability_spec.rb
|
31
|
+
spec/spec_helper.rb
|
data/README.md
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
# Observability
|
2
|
+
|
3
|
+
code
|
4
|
+
: http://bitbucket.org/ged/observability
|
5
|
+
|
6
|
+
github
|
7
|
+
: https://github.com/ged/observability
|
8
|
+
|
9
|
+
docs
|
10
|
+
: http://deveiate.org/code/observability
|
11
|
+
|
12
|
+
|
13
|
+
## Description
|
14
|
+
|
15
|
+
Observability is a toolkit for instrumenting code to make it more observable,
|
16
|
+
following the principle of Observability-Oriented Design as expressed by Charity
|
17
|
+
Majors (@mipsytipsy).
|
18
|
+
|
19
|
+
Its goals are [stolen from https://charity.wtf/2019/02/05/logs-vs-structured-events/]:
|
20
|
+
|
21
|
+
* Emit a rich record from the perspective of a single action as the code is
|
22
|
+
executing.
|
23
|
+
* Emit a single event per action per system that it occurs in. Write it out just
|
24
|
+
before the action completes or errors.
|
25
|
+
* Bypass local disk entirely, write to a remote service.
|
26
|
+
* Sample if needed for cost or resource constraints. Practice dynamic sampling.
|
27
|
+
* Treat this like operational data, not transactional data. Be profligate and
|
28
|
+
disposable.
|
29
|
+
* Feed this data into a columnar store or honeycomb or similar
|
30
|
+
* Now use it every day. Not just as a last resort. Get knee deep in production
|
31
|
+
every single day. Explore. Ask and answer rich questions about your systems,
|
32
|
+
system quality, system behavior, outliers, error conditions, etc. You will be
|
33
|
+
absolutely amazed how useful it is … and appalled by what you turn up. 🙂
|
34
|
+
|
35
|
+
|
36
|
+
## Prerequisites
|
37
|
+
|
38
|
+
* Ruby 2.6
|
39
|
+
|
40
|
+
|
41
|
+
## Installation
|
42
|
+
|
43
|
+
$ gem install observability
|
44
|
+
|
45
|
+
|
46
|
+
## Contributing
|
47
|
+
|
48
|
+
You can check out the current development source with Mercurial via its
|
49
|
+
[project page][bitbucket]. Or if you prefer Git, via
|
50
|
+
[its Github mirror][github].
|
51
|
+
|
52
|
+
After checking out the source, run:
|
53
|
+
|
54
|
+
$ rake newb
|
55
|
+
|
56
|
+
This task will install any missing dependencies, run the tests/specs,
|
57
|
+
and generate the API documentation.
|
58
|
+
|
59
|
+
|
60
|
+
## License
|
61
|
+
|
62
|
+
Copyright (c) 2019, Michael Granger
|
63
|
+
All rights reserved.
|
64
|
+
|
65
|
+
Redistribution and use in source and binary forms, with or without
|
66
|
+
modification, are permitted provided that the following conditions are met:
|
67
|
+
|
68
|
+
* Redistributions of source code must retain the above copyright notice,
|
69
|
+
this list of conditions and the following disclaimer.
|
70
|
+
|
71
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
72
|
+
this list of conditions and the following disclaimer in the documentation
|
73
|
+
and/or other materials provided with the distribution.
|
74
|
+
|
75
|
+
* Neither the name of the author/s, nor the names of the project's
|
76
|
+
contributors may be used to endorse or promote products derived from this
|
77
|
+
software without specific prior written permission.
|
78
|
+
|
79
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
80
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
81
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
82
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
83
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
84
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
85
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
86
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
87
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
88
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
89
|
+
|
90
|
+
|
91
|
+
[bitbucket]: http://bitbucket.org/ged/observability
|
92
|
+
[github]: https://github.com/ged/observability
|
93
|
+
|