naijacloud-argus 0.1.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +43 -0
- data/CONTRIBUTING.md +93 -0
- data/LICENSE +21 -0
- data/README.md +255 -0
- data/SECURITY.md +60 -0
- data/lib/naijacloud/argus/client.rb +647 -0
- data/lib/naijacloud/argus/configuration.rb +95 -0
- data/lib/naijacloud/argus/dsn.rb +60 -0
- data/lib/naijacloud/argus/integrations/net_http.rb +77 -0
- data/lib/naijacloud/argus/integrations/rack.rb +134 -0
- data/lib/naijacloud/argus/integrations/rails.rb +131 -0
- data/lib/naijacloud/argus/logger.rb +60 -0
- data/lib/naijacloud/argus/otlp.rb +116 -0
- data/lib/naijacloud/argus/scope.rb +66 -0
- data/lib/naijacloud/argus/scrub.rb +108 -0
- data/lib/naijacloud/argus/span.rb +109 -0
- data/lib/naijacloud/argus/stack.rb +101 -0
- data/lib/naijacloud/argus/transport.rb +352 -0
- data/lib/naijacloud/argus/version.rb +14 -0
- data/lib/naijacloud/argus.rb +320 -0
- metadata +100 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 245ee709a587c9f68b9eef5f35f5e2a27105e0e2e8a2c58c0c3906a5021b3faf
|
|
4
|
+
data.tar.gz: 68f0528cdd050cc668eb0e2263ef5bd875e6aad21012fc1e1fcb3e2a5f8a50e8
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 2ee64e8216a1b732fcaf87f1e2db53bfee3ee4ec012568a30eb53e9c70461eca5e312ca622bb25a38b0986712941bbf4e2e1c7db8e76a1df54dc24dafc52cee0
|
|
7
|
+
data.tar.gz: 50d4d3875834fa3523daed9638ab847be2eaa02defc8cbd33772d740945d671301bd150f971f21ffa07cf1c9bb379339de49a3e70b1561315a6c2491200c259c
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `naijacloud-argus` are listed here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the gem uses
|
|
5
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.1.0] - 2026-10-26
|
|
10
|
+
|
|
11
|
+
First release, implementing the Argus SDK contract `argus.sdk/1`.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- `NaijaCloud::Argus.init`, with keywords or a block. Reads `ARGUS_DSN`,
|
|
16
|
+
`ARGUS_RELEASE` and `ARGUS_ENVIRONMENT`, then the `SENTRY_*` names. Without a
|
|
17
|
+
DSN every call is a no-op.
|
|
18
|
+
- **Errors:** `capture_exception` (with the `cause` chain and source context
|
|
19
|
+
lines), `capture_message`, `set_user`, `set_tag(s)`, `set_context`,
|
|
20
|
+
`add_breadcrumb`, `with_scope`, `before_send`, `before_breadcrumb`,
|
|
21
|
+
`excluded_exceptions`. Sent as gzipped Sentry envelopes.
|
|
22
|
+
- **Rails** (Railtie, no setup beyond `bundle add` and `ARGUS_DSN`): request
|
|
23
|
+
tracing named by route, unhandled exceptions, ActiveJob failures and spans, a
|
|
24
|
+
`Rails.error` subscriber, and optional `Rails.logger` forwarding
|
|
25
|
+
(`rails_logs`).
|
|
26
|
+
- **Rack middleware** `NaijaCloud::Argus::Rack` for Sinatra, Hanami, Roda,
|
|
27
|
+
Grape and plain Rack: server spans continuing W3C `traceparent`, and
|
|
28
|
+
unhandled exceptions with the request.
|
|
29
|
+
- **Outgoing `Net::HTTP`**: client spans, `traceparent` propagation and
|
|
30
|
+
breadcrumbs.
|
|
31
|
+
- **Logs, metrics and traces** over OTLP/HTTP JSON: `log.info` and the other
|
|
32
|
+
levels, a `::Logger`-compatible `NaijaCloud::Argus::Logger`,
|
|
33
|
+
`metrics.count` / `gauge` / `distribution`, `trace` and `start_span`.
|
|
34
|
+
- **Cron check-ins by monitor slug:** `cron.check_in` and `monitor`.
|
|
35
|
+
- **Feature flags:** `flags.on?`, `flags.variant` and `flags.all`, cached 30 s.
|
|
36
|
+
- **Transport:** one background thread and bounded queue per endpoint, retries
|
|
37
|
+
with backoff, `Retry-After` on 429, stops on a refused key, fork-safe, never
|
|
38
|
+
raises. Uncaught exceptions are reported and queues flushed at exit.
|
|
39
|
+
- **Privacy defaults on:** sensitive keys, card numbers, tokens and JWTs are
|
|
40
|
+
filtered; query strings, cookies and IP addresses are not sent.
|
|
41
|
+
|
|
42
|
+
[Unreleased]: https://github.com/naijacloud/argus-ruby/compare/v0.1.0...HEAD
|
|
43
|
+
[0.1.0]: https://github.com/naijacloud/argus-ruby/releases/tag/v0.1.0
|
data/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
## Setup
|
|
4
|
+
|
|
5
|
+
Nothing to install. The gem has no runtime dependencies, and minitest and rake
|
|
6
|
+
ship with Ruby.
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
rake test
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
or, without bundler or rake at all:
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
ruby -Ilib -Itest test/errors_test.rb
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Tests
|
|
19
|
+
|
|
20
|
+
The suite runs **offline**. `test/test_helper.rb` starts a small HTTP server on
|
|
21
|
+
`127.0.0.1` with an ephemeral port, built on raw `TCPServer` (webrick left the
|
|
22
|
+
standard library in Ruby 3.0). There is no WebMock and no VCR, and no test
|
|
23
|
+
makes an outbound connection.
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
@server.enqueue(status: 429, headers: { "Retry-After" => "7" })
|
|
27
|
+
@server.enqueue(status: 500)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Unscripted requests get a 200. Gzipped bodies are decoded for you, and
|
|
31
|
+
`envelope(request)` / `event_from(request)` parse an error envelope.
|
|
32
|
+
|
|
33
|
+
Retry timing is asserted, not slept through: `capture_sleeps(client)` (or
|
|
34
|
+
`transport.sleeper = ->(s) { ... }`) records the waits instead of waiting.
|
|
35
|
+
|
|
36
|
+
**Rails.** `test/rails_test.rb` boots a minimal Rails app in a child process.
|
|
37
|
+
It is skipped when Rails is not installed, which keeps the default suite
|
|
38
|
+
dependency-free. To run it:
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
gem install railties activejob
|
|
42
|
+
ruby -Ilib -Itest test/rails_test.rb
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
CI runs it against Rails 7.1, 7.2 and 8.0.
|
|
46
|
+
|
|
47
|
+
**Contract test.** `rake contract` sends one of each signal to a real Argus
|
|
48
|
+
and checks every endpoint answered 2xx:
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
ARGUS_CONTRACT_DSN=<dsn of a test source> rake contract
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
It expects a cron monitor with slug `argus-ruby-contract`; without one, the
|
|
55
|
+
cron check-in's 404 is reported, not failed.
|
|
56
|
+
|
|
57
|
+
## What to keep in mind when changing this gem
|
|
58
|
+
|
|
59
|
+
- **The contract is binding.** `nc-argus/spec/README.md` (`argus.sdk/1`) is the
|
|
60
|
+
document every Argus SDK implements. A behaviour change here is owed to the
|
|
61
|
+
others too. If the contract and ingest disagree, ingest wins and the contract
|
|
62
|
+
gets fixed.
|
|
63
|
+
- **Never raise into the app, never block it.** Public methods go through
|
|
64
|
+
`NaijaCloud::Argus.safely`; sending happens on the transport's threads.
|
|
65
|
+
- **Zero runtime dependencies.** See SECURITY.md.
|
|
66
|
+
- **Ruby 3.0 is the supported floor,** but keep the code 2.7-compatible: no
|
|
67
|
+
endless methods, no `Hash#except`, no pattern matching. And no keyword
|
|
68
|
+
arguments on a method that also takes an attributes hash: on Ruby 3 a
|
|
69
|
+
braceless `"key" => value` would be taken for keywords.
|
|
70
|
+
|
|
71
|
+
## House style
|
|
72
|
+
|
|
73
|
+
Comments explain **why**: the decision, the failure it prevents, the trap it
|
|
74
|
+
avoids. `# frozen_string_literal: true` at the top of every file.
|
|
75
|
+
|
|
76
|
+
## Releasing
|
|
77
|
+
|
|
78
|
+
1. Update `lib/naijacloud/argus/version.rb`.
|
|
79
|
+
2. Move the `Unreleased` changelog entries under `## [x.y.z] - YYYY-MM-DD` and
|
|
80
|
+
update the link definitions at the foot of the file.
|
|
81
|
+
3. Tag and push: `git tag v<version> && git push origin v<version>`.
|
|
82
|
+
|
|
83
|
+
`.github/workflows/release.yml` runs CI, refuses a tag that disagrees with
|
|
84
|
+
`VERSION` or has no changelog section, builds and pushes the gem with RubyGems
|
|
85
|
+
trusted publishing, then creates the GitHub release.
|
|
86
|
+
|
|
87
|
+
### One-time setup
|
|
88
|
+
|
|
89
|
+
- **rubygems.org → Settings → Trusted publishers → Create a pending trusted
|
|
90
|
+
publisher:** gem `naijacloud-argus`, owner `naijacloud`, repository
|
|
91
|
+
`argus-ruby`, workflow `release.yml`, environment `rubygems`.
|
|
92
|
+
- **GitHub → Settings → Environments → New environment `rubygems`.** Add
|
|
93
|
+
required reviewers to make a push wait for a human.
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 NaijaCloud
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://www.naijacloud.com/argus">
|
|
3
|
+
<img alt="Naijacloud Argus, Ruby SDK" src="https://raw.githubusercontent.com/naijacloud/argus-ruby/main/.github/assets/banner.png" width="100%">
|
|
4
|
+
</a>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://rubygems.org/gems/naijacloud-argus"><img alt="gem" src="https://img.shields.io/badge/gem-naijacloud--argus-008751?style=flat-square&labelColor=0A0E0C"></a>
|
|
9
|
+
<img alt="ruby" src="https://img.shields.io/badge/ruby-%3E%3D_3.0-E0483F?style=flat-square&labelColor=0A0E0C">
|
|
10
|
+
<img alt="dependencies" src="https://img.shields.io/badge/dependencies-0-46C98A?style=flat-square&labelColor=0A0E0C">
|
|
11
|
+
<a href="LICENSE"><img alt="license" src="https://img.shields.io/badge/license-MIT-8A988F?style=flat-square&labelColor=0A0E0C"></a>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
<a href="#install">Install</a> ·
|
|
16
|
+
<a href="#rails">Rails</a> ·
|
|
17
|
+
<a href="#rack-sinatra-and-plain-ruby">Rack</a> ·
|
|
18
|
+
<a href="#errors">Errors</a> ·
|
|
19
|
+
<a href="#logs-metrics-and-traces">Logs, metrics, traces</a> ·
|
|
20
|
+
<a href="#cron-check-ins">Crons</a> ·
|
|
21
|
+
<a href="#feature-flags">Flags</a> ·
|
|
22
|
+
<a href="#privacy">Privacy</a> ·
|
|
23
|
+
<a href="#options">Options</a>
|
|
24
|
+
</p>
|
|
25
|
+
|
|
26
|
+
# naijacloud-argus
|
|
27
|
+
|
|
28
|
+
The official Ruby SDK for [Argus](https://www.naijacloud.com/argus),
|
|
29
|
+
Naijacloud's monitoring. One gem sends errors, logs, metrics, traces, cron
|
|
30
|
+
check-ins and feature-flag checks, with one key: your app's **DSN**.
|
|
31
|
+
|
|
32
|
+
It has no runtime dependencies (standard-library `net/http`, `json` and `zlib`
|
|
33
|
+
only), implements the Argus SDK contract **`argus.sdk/1`**, and works for apps
|
|
34
|
+
hosted anywhere, not only on Naijacloud.
|
|
35
|
+
|
|
36
|
+
**Already using `sentry-ruby`?** Keep it. Argus accepts it: point its `dsn` at
|
|
37
|
+
Argus and you're done. Switch to this gem when you want logs, metrics, cron
|
|
38
|
+
check-ins and flags through the same setup.
|
|
39
|
+
|
|
40
|
+
## Install
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
bundle add naijacloud-argus
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Ruby 3.0 or newer. Copy the DSN (your app's key) from the source in Argus. It
|
|
47
|
+
looks like `https://<key>@argus-in.naijacloud.com/<number>`.
|
|
48
|
+
|
|
49
|
+
## Rails
|
|
50
|
+
|
|
51
|
+
```sh
|
|
52
|
+
bundle add naijacloud-argus
|
|
53
|
+
ARGUS_DSN=https://…@argus-in.naijacloud.com/41 bin/rails server
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
That's the whole setup. The gem's Railtie:
|
|
57
|
+
|
|
58
|
+
- **starts Argus** after your initializers, reading `ARGUS_DSN`,
|
|
59
|
+
`ARGUS_RELEASE` and `ARGUS_ENVIRONMENT` (falling back to `SENTRY_DSN`,
|
|
60
|
+
`SENTRY_RELEASE` and `SENTRY_ENVIRONMENT`). With no environment variable set,
|
|
61
|
+
the environment is `Rails.env` and the service name is your app's name;
|
|
62
|
+
- **traces every request**, named by its route (`GET /orders/:id`), and
|
|
63
|
+
continues a `traceparent` header from the caller;
|
|
64
|
+
- **reports unhandled exceptions** with the request they came from. A 404 or a
|
|
65
|
+
bad CSRF token is not reported;
|
|
66
|
+
- **reports ActiveJob failures** with the job's class, id and queue, and traces
|
|
67
|
+
each job. Your `retry_on` and `discard_on` still behave as before;
|
|
68
|
+
- **subscribes to `Rails.error`** (Rails 7.0+), so `Rails.error.report` and
|
|
69
|
+
`Rails.error.handle` reach Argus too;
|
|
70
|
+
- **traces outgoing `Net::HTTP` calls** (and Faraday, HTTParty and anything else
|
|
71
|
+
built on it) and adds a `traceparent` header to them.
|
|
72
|
+
|
|
73
|
+
Without a DSN it does nothing, so development and test need no changes. Apps
|
|
74
|
+
hosted on Naijacloud get these variables set when the Argus tab is on.
|
|
75
|
+
|
|
76
|
+
To change options, add an initializer. It runs before the Railtie's own start,
|
|
77
|
+
so it wins:
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
# config/initializers/argus.rb
|
|
81
|
+
NaijaCloud::Argus.init do |c|
|
|
82
|
+
c.release = ENV["GIT_SHA"]
|
|
83
|
+
c.traces_sample_rate = 0.2
|
|
84
|
+
c.rails_logs = true # also send Rails.logger lines to Argus Logs
|
|
85
|
+
end
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Rack, Sinatra and plain Ruby
|
|
89
|
+
|
|
90
|
+
```ruby
|
|
91
|
+
# config.ru
|
|
92
|
+
require "naijacloud/argus"
|
|
93
|
+
NaijaCloud::Argus.init # reads ARGUS_DSN
|
|
94
|
+
use NaijaCloud::Argus::Rack
|
|
95
|
+
run App
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The middleware gives you the same request spans and error reports as on Rails,
|
|
99
|
+
for Sinatra, Hanami, Roda, Grape and plain Rack.
|
|
100
|
+
|
|
101
|
+
**In a script or a worker,** call `init` at the top. An exception that ends the
|
|
102
|
+
process is reported, and whatever is queued is sent before the process exits.
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
require "naijacloud/argus"
|
|
106
|
+
NaijaCloud::Argus.init(dsn: ENV["ARGUS_DSN"], release: "1.4.2")
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Errors
|
|
110
|
+
|
|
111
|
+
```ruby
|
|
112
|
+
begin
|
|
113
|
+
charge_card(order)
|
|
114
|
+
rescue Paystack::Error => e
|
|
115
|
+
NaijaCloud::Argus.capture_exception(e, tags: { provider: "paystack" }, extra: { order_id: order.id })
|
|
116
|
+
raise
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
NaijaCloud::Argus.capture_message("Webhook signature mismatch", level: :warning)
|
|
120
|
+
NaijaCloud::Argus.set_user(id: current_user.id)
|
|
121
|
+
NaijaCloud::Argus.set_tag("region", "af-west")
|
|
122
|
+
NaijaCloud::Argus.add_breadcrumb(category: "cart", message: "coupon applied", data: { code: "NAIJA10" })
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
- **Causes:** an exception's `cause` chain is sent too.
|
|
126
|
+
- **Duplicates:** the same exception object is sent once, however many layers
|
|
127
|
+
(Rack, `Rails.error`, ActiveJob) see it.
|
|
128
|
+
- **Per request:** `set_user`, tags and breadcrumbs set during a request (or a
|
|
129
|
+
job) stay with that request; they don't leak to the next one on the same
|
|
130
|
+
thread or to other threads.
|
|
131
|
+
- **`before_send`** lets you change an event (a Hash), or return `nil` to drop it.
|
|
132
|
+
- `capture_exception` returns the event id, or `nil` when nothing was sent.
|
|
133
|
+
|
|
134
|
+
## Logs, metrics and traces
|
|
135
|
+
|
|
136
|
+
```ruby
|
|
137
|
+
NaijaCloud::Argus.log.info("order placed", order_id: "ord_81", total: 18_500)
|
|
138
|
+
NaijaCloud::Argus.log.error("paystack timed out", attempt: 3)
|
|
139
|
+
|
|
140
|
+
NaijaCloud::Argus.metrics.count("orders.placed", 1, method: "card")
|
|
141
|
+
NaijaCloud::Argus.metrics.gauge("queue.depth", jobs.size)
|
|
142
|
+
NaijaCloud::Argus.metrics.distribution("checkout.ms", elapsed_ms, nil, "ms")
|
|
143
|
+
|
|
144
|
+
NaijaCloud::Argus.trace("charge card", provider: "paystack") do |span|
|
|
145
|
+
span.set_attribute("amount", order.total)
|
|
146
|
+
paystack.charge(order)
|
|
147
|
+
end
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
- **Logs** are sent in batches every 5 seconds (or every 1,000 lines). A line
|
|
151
|
+
written inside a request carries that request's trace id.
|
|
152
|
+
- **A `::Logger`** that sends to Argus Logs, for any library that takes one:
|
|
153
|
+
`NaijaCloud::Argus::Logger.new(level: :info)`. On Rails 7.1+,
|
|
154
|
+
`Rails.logger.broadcast_to(NaijaCloud::Argus::Logger.new)` keeps your normal
|
|
155
|
+
log output and adds Argus (or set `rails_logs = true`).
|
|
156
|
+
- **Metrics** are added up in the process and sent every 10 seconds.
|
|
157
|
+
- **Spans** join the request or job they run in. `trace` returns the block's
|
|
158
|
+
value; an exception marks the span failed and is re-raised. For work that
|
|
159
|
+
doesn't fit a block, `span = NaijaCloud::Argus.start_span("upload")` and later
|
|
160
|
+
`span.finish` (or `span.finish(error)`).
|
|
161
|
+
- **Propagate a trace** through something the gem doesn't instrument (a queue
|
|
162
|
+
message, gRPC metadata) with `NaijaCloud::Argus.traceparent`.
|
|
163
|
+
- **Sample traces** with `traces_sample_rate` (0 to 1, default 1).
|
|
164
|
+
|
|
165
|
+
## Cron check-ins
|
|
166
|
+
|
|
167
|
+
Create a cron monitor in Argus first, then report runs by its slug:
|
|
168
|
+
|
|
169
|
+
```ruby
|
|
170
|
+
NaijaCloud::Argus.monitor("nightly-invoices") do
|
|
171
|
+
InvoiceRun.call
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# or by hand:
|
|
175
|
+
NaijaCloud::Argus.cron.check_in("nightly-invoices", :start)
|
|
176
|
+
NaijaCloud::Argus.cron.check_in("nightly-invoices", :ok) # or :error, or an exit code
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
`monitor` reports the start, then success or failure, and re-raises your job's
|
|
180
|
+
exception. An unknown slug is answered 404 by Argus and dropped.
|
|
181
|
+
|
|
182
|
+
## Feature flags
|
|
183
|
+
|
|
184
|
+
```ruby
|
|
185
|
+
if NaijaCloud::Argus.flags.on?("new-checkout", current_user.id)
|
|
186
|
+
# …
|
|
187
|
+
end
|
|
188
|
+
theme = NaijaCloud::Argus.flags.variant("theme", current_user.id, "light")
|
|
189
|
+
NaijaCloud::Argus.flags.all(current_user.id) # => {"new-checkout"=>"on", "theme"=>"dark"}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
- **Caching:** answers are cached for 30 seconds per user (and attributes).
|
|
193
|
+
- **Fallback:** if Argus can't be reached within 2 seconds, or the flag doesn't
|
|
194
|
+
exist, you get the fallback you passed.
|
|
195
|
+
- **Targeting attributes** go last: `on?("beta", user.id, false, plan: "pro")`.
|
|
196
|
+
|
|
197
|
+
## Privacy
|
|
198
|
+
|
|
199
|
+
On by default:
|
|
200
|
+
|
|
201
|
+
- The values of keys such as `password`, `token`, `secret`, `authorization`,
|
|
202
|
+
`cookie`, `bvn` and `card` are replaced with `[Filtered]`, at any depth: in
|
|
203
|
+
extra, contexts, breadcrumbs, log and span attributes.
|
|
204
|
+
- Card numbers, bearer tokens, JWTs and `password=…` pairs are filtered inside
|
|
205
|
+
strings, including exception messages and log lines.
|
|
206
|
+
- Query strings are removed from URLs in requests, breadcrumbs and spans.
|
|
207
|
+
- Request bodies and cookies are never sent.
|
|
208
|
+
- The user's IP address is not sent unless you set `send_default_pii: true`.
|
|
209
|
+
|
|
210
|
+
Argus filters again on arrival.
|
|
211
|
+
|
|
212
|
+
## Options
|
|
213
|
+
|
|
214
|
+
Pass them to `init` as keywords, or set them in its block.
|
|
215
|
+
|
|
216
|
+
| Option | Default | |
|
|
217
|
+
| -- | -- | -- |
|
|
218
|
+
| `dsn` | `ARGUS_DSN`, then `SENTRY_DSN` | Without one, nothing is sent |
|
|
219
|
+
| `release` | `ARGUS_RELEASE`, then `SENTRY_RELEASE` | Your app's version, like `1.4.2` or a git commit |
|
|
220
|
+
| `environment` | `ARGUS_ENVIRONMENT`, then `SENTRY_ENVIRONMENT`, else `production` (`Rails.env` on Rails) | |
|
|
221
|
+
| `service_name` | `ARGUS_SERVICE_NAME`, else `app` (the app's name on Rails) | Shown on logs, metrics and traces |
|
|
222
|
+
| `sample_rate` | `1.0` | Share of errors sent |
|
|
223
|
+
| `traces_sample_rate` | `1.0` | Share of traces sent |
|
|
224
|
+
| `send_default_pii` | `false` | Send the user's IP address |
|
|
225
|
+
| `max_breadcrumbs` | `100` | |
|
|
226
|
+
| `before_send` / `before_breadcrumb` | | Change or drop an event or crumb (return `nil`) |
|
|
227
|
+
| `excluded_exceptions` | 404-type Rails errors | Class names never reported |
|
|
228
|
+
| `project_root` | `Rails.root` on Rails | Frames under it are marked in-app |
|
|
229
|
+
| `context_lines` | `true` | Send the lines of source around in-app frames |
|
|
230
|
+
| `net_http` | `true` | Trace outgoing `Net::HTTP` calls |
|
|
231
|
+
| `trace_propagation` | `true` | Add `traceparent` to outgoing requests |
|
|
232
|
+
| `rails_logs` | `false` | Also send `Rails.logger` lines as logs |
|
|
233
|
+
| `capture_at_exit` | `true` | Report the exception that ends the process |
|
|
234
|
+
| `debug` | `false` | Print what the SDK does to `$stderr` (or `ARGUS_DEBUG=1`) |
|
|
235
|
+
| `enabled` | `true` | Turn the SDK off without removing it |
|
|
236
|
+
|
|
237
|
+
The gem never raises into your app and never blocks a request: everything is
|
|
238
|
+
sent from background threads, with retries and backoff. Call
|
|
239
|
+
`NaijaCloud::Argus.flush` before a short script exits if it calls `exit!`;
|
|
240
|
+
otherwise the exit hook sends what's queued. It is safe with forking servers
|
|
241
|
+
(Puma, Unicorn) and job runners (Sidekiq, Resque): each child process starts
|
|
242
|
+
its own sender.
|
|
243
|
+
|
|
244
|
+
## Not in this version
|
|
245
|
+
|
|
246
|
+
These are planned, and not done yet:
|
|
247
|
+
|
|
248
|
+
- automatic spans for ActiveRecord queries, Redis and view rendering;
|
|
249
|
+
- trace propagation from a request into the jobs it enqueues;
|
|
250
|
+
- reporting an ActiveJob failure only after its retries are used up (every
|
|
251
|
+
failed attempt is reported today).
|
|
252
|
+
|
|
253
|
+
## License
|
|
254
|
+
|
|
255
|
+
MIT
|
data/SECURITY.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Security
|
|
2
|
+
|
|
3
|
+
## Reporting a vulnerability
|
|
4
|
+
|
|
5
|
+
Email **security@naijacloud.com**. Please do not open a public issue, and do not
|
|
6
|
+
post a proof of concept anywhere public before we have shipped a fix.
|
|
7
|
+
|
|
8
|
+
Include what you did, what happened, and the version of the gem. We acknowledge
|
|
9
|
+
within two business days (West Africa Time) and will tell you what we intend to
|
|
10
|
+
do and by when.
|
|
11
|
+
|
|
12
|
+
## What the DSN is, and is not
|
|
13
|
+
|
|
14
|
+
The DSN's key is a **public, send-only** credential: it can add events to one
|
|
15
|
+
Argus source and read nothing. It is not a secret in the way an API key is, so
|
|
16
|
+
a leaked DSN is a spam risk for that source, not a data breach. Rotate it from
|
|
17
|
+
the source's settings if it is being abused.
|
|
18
|
+
|
|
19
|
+
Even so, the gem keeps it tidy: on a server it travels in a header
|
|
20
|
+
(`X-Sentry-Auth` or `Authorization: Bearer`), never in the URL, so it does not
|
|
21
|
+
end up in proxy access logs. `Dsn#inspect` and `Client#inspect` do not print it.
|
|
22
|
+
|
|
23
|
+
## What the gem does with your users' data
|
|
24
|
+
|
|
25
|
+
The gem sits inside your app and sees its exceptions, requests and logs, so it
|
|
26
|
+
is built to send as little as it can:
|
|
27
|
+
|
|
28
|
+
1. **Sensitive keys are filtered before anything leaves the process,** at any
|
|
29
|
+
depth: `password`, `token`, `secret`, `authorization`, `cookie`, `bvn`,
|
|
30
|
+
`card`, `cvv`, `session` and the rest of the list in the Argus SDK contract
|
|
31
|
+
(§7). Card numbers (Luhn-checked), bearer/basic tokens, JWTs and
|
|
32
|
+
`password=…` pairs are filtered inside strings.
|
|
33
|
+
2. **Request bodies and cookies are never sent.** Request headers are an
|
|
34
|
+
allowlist (host, user agent, accept, referer, request id, content type), not
|
|
35
|
+
a denylist, so a header nobody thought of is not sent.
|
|
36
|
+
3. **Query strings are removed** from every URL the gem records.
|
|
37
|
+
4. **IP addresses are not sent** unless you set `send_default_pii: true`.
|
|
38
|
+
5. **TLS is verified** (`VERIFY_PEER`, set explicitly) and **redirects are never
|
|
39
|
+
followed**: a followed redirect would resend the key to a host the response
|
|
40
|
+
chose.
|
|
41
|
+
6. **Debug output** (`debug: true`) prints what the SDK does, never payloads or
|
|
42
|
+
headers. `Net::HTTP#set_debug_output` is never called.
|
|
43
|
+
|
|
44
|
+
Argus filters again on arrival; the gem does not rely on that.
|
|
45
|
+
|
|
46
|
+
## Supply chain
|
|
47
|
+
|
|
48
|
+
The gem has **zero runtime dependencies**. Everything is standard library:
|
|
49
|
+
`net/http`, `openssl`, `json`, `zlib`, `securerandom`, `socket`, `uri`, and
|
|
50
|
+
`logger` only if you use `NaijaCloud::Argus::Logger`.
|
|
51
|
+
|
|
52
|
+
That is deliberate. This package runs in every process of the apps that use
|
|
53
|
+
it, so every third-party dependency would be another maintainer whose account
|
|
54
|
+
compromise becomes our customers' incident. Releases require MFA on the
|
|
55
|
+
RubyGems account (`rubygems_mfa_required`).
|
|
56
|
+
|
|
57
|
+
## Supported versions
|
|
58
|
+
|
|
59
|
+
Security fixes are released for the latest minor version. Ruby 3.0 and newer
|
|
60
|
+
are supported.
|