orange_tap 0.1.1 → 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.
- checksums.yaml +4 -4
- data/README.md +27 -0
- data/lib/orange_tap/version.rb +1 -1
- data/lib/orange_tap.rb +48 -0
- data/sig/orange_tap.rbs +45 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ca009ebd31ae0ff1849d7975d602f1f87dccbada30458cd4943e6a526aa35647
|
|
4
|
+
data.tar.gz: 662aa3e960659b36c5febb1b1f59e2d39d2010146a208584155f7e860206b77a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bdd6c3f5b6158f7df4dd462c4aa6be2b38bd060d5a9c26596487c93510b03d3c9259efbeee60d1d5c960060f05265608b56e1edea922a3de534414ef5578934f
|
|
7
|
+
data.tar.gz: bbc112874962e22531f59e7fca2b5569831fbb956a690692c24f219fb32c67295d48aaf632ecb276f2ac6c22e4122e3992d8942f9976a96a9e6f5238a044b7f8
|
data/README.md
CHANGED
|
@@ -115,6 +115,33 @@ tape.open("checkout-flow")
|
|
|
115
115
|
tape.stop
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
+
### `record`: measure a block with config and error handling taken care of
|
|
119
|
+
|
|
120
|
+
`OrangeTap.record` wraps a single session for the common "measure this block
|
|
121
|
+
once" case (e.g. a Rails `around_action`). Compared to `open`, it handles two
|
|
122
|
+
things every caller otherwise re-implements by hand:
|
|
123
|
+
|
|
124
|
+
- **`config_overrides`** are applied for the duration of the block and
|
|
125
|
+
restored afterwards, *even on error*. `OrangeTap.config` is a process-global
|
|
126
|
+
singleton, so a leaked `trace_all_app_methods = true` would keep every later
|
|
127
|
+
session in the heaviest mode — `record` guarantees it is reset.
|
|
128
|
+
- **`on_output`** is called with the written JSON path in an `ensure`, so you
|
|
129
|
+
receive the path on **both success and failure**. (Block-form `open` cannot
|
|
130
|
+
return the path when the block raises.) The trace file is written either way,
|
|
131
|
+
since the worker drains on `stop`.
|
|
132
|
+
|
|
133
|
+
```ruby
|
|
134
|
+
OrangeTap.record(
|
|
135
|
+
"checkout-flow",
|
|
136
|
+
trace_all_app_methods: true, # applied, then restored
|
|
137
|
+
on_output: ->(path) { Rails.logger.info("OrangeTap: #{path}") }
|
|
138
|
+
) do
|
|
139
|
+
MyApp.handle(request)
|
|
140
|
+
end
|
|
141
|
+
# => output path on success; the original error is re-raised on failure
|
|
142
|
+
# (an on_output that itself raises is swallowed so it never masks it)
|
|
143
|
+
```
|
|
144
|
+
|
|
118
145
|
Other registration entry points:
|
|
119
146
|
|
|
120
147
|
```ruby
|
data/lib/orange_tap/version.rb
CHANGED
data/lib/orange_tap.rb
CHANGED
|
@@ -67,4 +67,52 @@ module OrangeTap
|
|
|
67
67
|
raise
|
|
68
68
|
end
|
|
69
69
|
end
|
|
70
|
+
|
|
71
|
+
# A batteries-included wrapper around a single session, meant for the
|
|
72
|
+
# common "measure this block once" case (e.g. a Rails around_action):
|
|
73
|
+
#
|
|
74
|
+
# OrangeTap.record("checkout", trace_all_app_methods: true,
|
|
75
|
+
# on_output: ->(path) { Rails.logger.info(path) }) { do_work }
|
|
76
|
+
#
|
|
77
|
+
# It handles the two things every caller otherwise has to re-implement by
|
|
78
|
+
# hand around #open:
|
|
79
|
+
#
|
|
80
|
+
# * config_overrides are applied for the duration of the block and restored
|
|
81
|
+
# afterwards, even on error. OrangeTap.config is a process-global
|
|
82
|
+
# singleton, so a leaked `trace_all_app_methods = true` would keep every
|
|
83
|
+
# later session in the heaviest mode; this guarantees it is reset.
|
|
84
|
+
# * on_output is called with the written JSON path in the ensure, so the
|
|
85
|
+
# path is delivered on BOTH success and failure. (Block form #open cannot
|
|
86
|
+
# return the path when the block raises.) The trace file is written either
|
|
87
|
+
# way, since the worker drains on stop.
|
|
88
|
+
#
|
|
89
|
+
# Returns the output path on success; re-raises the original error on
|
|
90
|
+
# failure (an on_output that raises is swallowed so it never masks it).
|
|
91
|
+
def record(name = nil, on_output: nil, **config_overrides)
|
|
92
|
+
previous = config_overrides.to_h { |key, _| [key, config.public_send(key)] }
|
|
93
|
+
config_overrides.each { |key, value| config.public_send("#{key}=", value) }
|
|
94
|
+
|
|
95
|
+
tape = new
|
|
96
|
+
tape.open(name)
|
|
97
|
+
path = nil
|
|
98
|
+
begin
|
|
99
|
+
yield
|
|
100
|
+
path = tape.stop
|
|
101
|
+
rescue Exception # rubocop:disable Lint/RescueException
|
|
102
|
+
path = begin
|
|
103
|
+
tape.stop
|
|
104
|
+
rescue StandardError
|
|
105
|
+
nil
|
|
106
|
+
end
|
|
107
|
+
raise
|
|
108
|
+
ensure
|
|
109
|
+
previous.each { |key, value| config.public_send("#{key}=", value) }
|
|
110
|
+
begin
|
|
111
|
+
on_output&.call(path)
|
|
112
|
+
rescue StandardError
|
|
113
|
+
nil
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
path
|
|
117
|
+
end
|
|
70
118
|
end
|
data/sig/orange_tap.rbs
CHANGED
|
@@ -1,4 +1,48 @@
|
|
|
1
1
|
module OrangeTap
|
|
2
2
|
VERSION: String
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
class Error < StandardError
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
class AlreadyOpenError < Error
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class NotOpenError < Error
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class UntraceableMethodError < Error
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# A Method/UnboundMethod, or a "Foo#bar" / "Foo.bar" notation String.
|
|
17
|
+
type method_obj = Method | UnboundMethod | String
|
|
18
|
+
|
|
19
|
+
def self.new: (**untyped opts) -> Session
|
|
20
|
+
|
|
21
|
+
def self.default_registry: () -> MethodRegistry
|
|
22
|
+
|
|
23
|
+
def self.config: () -> Config
|
|
24
|
+
|
|
25
|
+
def self.trace_method: (*method_obj method_objs) -> void
|
|
26
|
+
|
|
27
|
+
def self.untrace_method: (*method_obj method_objs) -> void
|
|
28
|
+
|
|
29
|
+
def self.trace_all_instance_methods: (Class klass) -> void
|
|
30
|
+
|
|
31
|
+
# Block form returns the output path; blockless form returns the Session.
|
|
32
|
+
def self.open: (?String? name) ?{ () -> void } -> (String | Session)
|
|
33
|
+
|
|
34
|
+
# Runs the block in a single session, applying config_overrides for its
|
|
35
|
+
# duration (restored afterwards, even on error) and delivering the output
|
|
36
|
+
# path to on_output on both success and failure. Returns the path on success.
|
|
37
|
+
def self.record: (?String? name, ?on_output: (^(String?) -> void)?, **untyped config_overrides) { () -> void } -> String?
|
|
38
|
+
|
|
39
|
+
class Config
|
|
40
|
+
attr_accessor output_dir: String
|
|
41
|
+
attr_accessor service_name: String
|
|
42
|
+
attr_accessor otel_converter: untyped
|
|
43
|
+
attr_accessor trace_c_methods: bool
|
|
44
|
+
attr_accessor trace_all_app_methods: bool
|
|
45
|
+
|
|
46
|
+
def initialize: () -> void
|
|
47
|
+
end
|
|
4
48
|
end
|