stenotype 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.rspec +3 -0
- data/.rubocop.yml +6 -0
- data/.travis.yml +7 -0
- data/.yardopts +2 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +239 -0
- data/LICENSE.txt +21 -0
- data/README.md +251 -0
- data/Rakefile +8 -0
- data/TODO.md +17 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/stenotype/adapters/base.rb +36 -0
- data/lib/stenotype/adapters/google_cloud.rb +56 -0
- data/lib/stenotype/adapters/stdout_adapter.rb +23 -0
- data/lib/stenotype/adapters.rb +5 -0
- data/lib/stenotype/configuration.rb +49 -0
- data/lib/stenotype/context_handlers/base.rb +52 -0
- data/lib/stenotype/context_handlers/collection.rb +64 -0
- data/lib/stenotype/context_handlers/klass.rb +20 -0
- data/lib/stenotype/context_handlers/rails/active_job.rb +43 -0
- data/lib/stenotype/context_handlers/rails/controller.rb +34 -0
- data/lib/stenotype/context_handlers.rb +32 -0
- data/lib/stenotype/dispatcher.rb +37 -0
- data/lib/stenotype/event.rb +59 -0
- data/lib/stenotype/event_serializer.rb +61 -0
- data/lib/stenotype/exceptions.rb +31 -0
- data/lib/stenotype/frameworks/object_ext.rb +145 -0
- data/lib/stenotype/frameworks/rails/action_controller.rb +110 -0
- data/lib/stenotype/frameworks/rails/active_job.rb +57 -0
- data/lib/stenotype/version.rb +7 -0
- data/lib/stenotype.rb +98 -0
- data/stenotype.gemspec +47 -0
- metadata +262 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 714f7d5fce3afe07cb1f49653fc44410ca0570086a310c8aead9b88229981f08
|
4
|
+
data.tar.gz: 7f69e3448a22a9d1094dbab6a783e206ac36a5c22c1eb10db3f25180ce07d167
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5ac72dfb39d13e86dfee3617cbef85e06dec175541af1ec681298b74c970f0ef54f4e48a434b305778bc49c219604b6d3eeab3d444a9a670a4db8873ad7a0c94
|
7
|
+
data.tar.gz: 399afa50ff49b2b6b163a07345064193f3bdc18cb20719adb55b1ace92b6cafcedf3128f430df033e597836524138bce7f82134671378f113786e7e1f3948fe3
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/.travis.yml
ADDED
data/.yardopts
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,239 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
stenotype (0.1.0)
|
5
|
+
activesupport (>= 5.0.0)
|
6
|
+
google-cloud-pubsub (~> 1.0.0)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
actioncable (5.2.3)
|
12
|
+
actionpack (= 5.2.3)
|
13
|
+
nio4r (~> 2.0)
|
14
|
+
websocket-driver (>= 0.6.1)
|
15
|
+
actionmailer (5.2.3)
|
16
|
+
actionpack (= 5.2.3)
|
17
|
+
actionview (= 5.2.3)
|
18
|
+
activejob (= 5.2.3)
|
19
|
+
mail (~> 2.5, >= 2.5.4)
|
20
|
+
rails-dom-testing (~> 2.0)
|
21
|
+
actionpack (5.2.3)
|
22
|
+
actionview (= 5.2.3)
|
23
|
+
activesupport (= 5.2.3)
|
24
|
+
rack (~> 2.0)
|
25
|
+
rack-test (>= 0.6.3)
|
26
|
+
rails-dom-testing (~> 2.0)
|
27
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
28
|
+
actionview (5.2.3)
|
29
|
+
activesupport (= 5.2.3)
|
30
|
+
builder (~> 3.1)
|
31
|
+
erubi (~> 1.4)
|
32
|
+
rails-dom-testing (~> 2.0)
|
33
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
34
|
+
activejob (5.2.3)
|
35
|
+
activesupport (= 5.2.3)
|
36
|
+
globalid (>= 0.3.6)
|
37
|
+
activemodel (5.2.3)
|
38
|
+
activesupport (= 5.2.3)
|
39
|
+
activerecord (5.2.3)
|
40
|
+
activemodel (= 5.2.3)
|
41
|
+
activesupport (= 5.2.3)
|
42
|
+
arel (>= 9.0)
|
43
|
+
activestorage (5.2.3)
|
44
|
+
actionpack (= 5.2.3)
|
45
|
+
activerecord (= 5.2.3)
|
46
|
+
marcel (~> 0.3.1)
|
47
|
+
activesupport (5.2.3)
|
48
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
49
|
+
i18n (>= 0.7, < 2)
|
50
|
+
minitest (~> 5.1)
|
51
|
+
tzinfo (~> 1.1)
|
52
|
+
addressable (2.7.0)
|
53
|
+
public_suffix (>= 2.0.2, < 5.0)
|
54
|
+
arel (9.0.0)
|
55
|
+
ast (2.4.0)
|
56
|
+
builder (3.2.3)
|
57
|
+
coderay (1.1.2)
|
58
|
+
concurrent-ruby (1.1.5)
|
59
|
+
crass (1.0.5)
|
60
|
+
diff-lcs (1.3)
|
61
|
+
docile (1.3.2)
|
62
|
+
erubi (1.9.0)
|
63
|
+
faker (1.9.6)
|
64
|
+
i18n (>= 0.7)
|
65
|
+
faraday (0.17.0)
|
66
|
+
multipart-post (>= 1.2, < 3)
|
67
|
+
github-markup (3.0.4)
|
68
|
+
globalid (0.4.2)
|
69
|
+
activesupport (>= 4.2.0)
|
70
|
+
google-cloud-core (1.4.1)
|
71
|
+
google-cloud-env (~> 1.0)
|
72
|
+
google-cloud-env (1.3.0)
|
73
|
+
faraday (~> 0.11)
|
74
|
+
google-cloud-pubsub (1.0.2)
|
75
|
+
concurrent-ruby (~> 1.1)
|
76
|
+
google-cloud-core (~> 1.2)
|
77
|
+
google-gax (~> 1.7)
|
78
|
+
googleapis-common-protos (>= 1.3.9, < 2.0)
|
79
|
+
grpc-google-iam-v1 (~> 0.6.9)
|
80
|
+
google-gax (1.8.1)
|
81
|
+
google-protobuf (~> 3.9)
|
82
|
+
googleapis-common-protos (>= 1.3.9, < 2.0)
|
83
|
+
googleauth (~> 0.9)
|
84
|
+
grpc (~> 1.24)
|
85
|
+
rly (~> 0.2.3)
|
86
|
+
google-protobuf (3.10.1-universal-darwin)
|
87
|
+
googleapis-common-protos (1.3.9)
|
88
|
+
google-protobuf (~> 3.0)
|
89
|
+
googleapis-common-protos-types (~> 1.0)
|
90
|
+
grpc (~> 1.0)
|
91
|
+
googleapis-common-protos-types (1.0.4)
|
92
|
+
google-protobuf (~> 3.0)
|
93
|
+
googleauth (0.10.0)
|
94
|
+
faraday (~> 0.12)
|
95
|
+
jwt (>= 1.4, < 3.0)
|
96
|
+
memoist (~> 0.16)
|
97
|
+
multi_json (~> 1.11)
|
98
|
+
os (>= 0.9, < 2.0)
|
99
|
+
signet (~> 0.12)
|
100
|
+
grpc (1.25.0-universal-darwin)
|
101
|
+
google-protobuf (~> 3.8)
|
102
|
+
googleapis-common-protos-types (~> 1.0)
|
103
|
+
grpc-google-iam-v1 (0.6.9)
|
104
|
+
googleapis-common-protos (>= 1.3.1, < 2.0)
|
105
|
+
grpc (~> 1.0)
|
106
|
+
i18n (1.7.0)
|
107
|
+
concurrent-ruby (~> 1.0)
|
108
|
+
jaro_winkler (1.5.4)
|
109
|
+
json (2.2.0)
|
110
|
+
jwt (2.2.1)
|
111
|
+
loofah (2.3.1)
|
112
|
+
crass (~> 1.0.2)
|
113
|
+
nokogiri (>= 1.5.9)
|
114
|
+
mail (2.7.1)
|
115
|
+
mini_mime (>= 0.1.1)
|
116
|
+
marcel (0.3.3)
|
117
|
+
mimemagic (~> 0.3.2)
|
118
|
+
memoist (0.16.0)
|
119
|
+
method_source (0.9.2)
|
120
|
+
mimemagic (0.3.3)
|
121
|
+
mini_mime (1.0.2)
|
122
|
+
mini_portile2 (2.4.0)
|
123
|
+
minitest (5.12.2)
|
124
|
+
multi_json (1.14.1)
|
125
|
+
multipart-post (2.1.1)
|
126
|
+
nio4r (2.5.2)
|
127
|
+
nokogiri (1.10.4)
|
128
|
+
mini_portile2 (~> 2.4.0)
|
129
|
+
os (1.0.1)
|
130
|
+
parallel (1.18.0)
|
131
|
+
parser (2.6.5.0)
|
132
|
+
ast (~> 2.4.0)
|
133
|
+
pry (0.12.2)
|
134
|
+
coderay (~> 1.1.0)
|
135
|
+
method_source (~> 0.9.0)
|
136
|
+
public_suffix (4.0.1)
|
137
|
+
rack (2.0.7)
|
138
|
+
rack-test (1.1.0)
|
139
|
+
rack (>= 1.0, < 3)
|
140
|
+
rails (5.2.3)
|
141
|
+
actioncable (= 5.2.3)
|
142
|
+
actionmailer (= 5.2.3)
|
143
|
+
actionpack (= 5.2.3)
|
144
|
+
actionview (= 5.2.3)
|
145
|
+
activejob (= 5.2.3)
|
146
|
+
activemodel (= 5.2.3)
|
147
|
+
activerecord (= 5.2.3)
|
148
|
+
activestorage (= 5.2.3)
|
149
|
+
activesupport (= 5.2.3)
|
150
|
+
bundler (>= 1.3.0)
|
151
|
+
railties (= 5.2.3)
|
152
|
+
sprockets-rails (>= 2.0.0)
|
153
|
+
rails-dom-testing (2.0.3)
|
154
|
+
activesupport (>= 4.2.0)
|
155
|
+
nokogiri (>= 1.6)
|
156
|
+
rails-html-sanitizer (1.3.0)
|
157
|
+
loofah (~> 2.3)
|
158
|
+
railties (5.2.3)
|
159
|
+
actionpack (= 5.2.3)
|
160
|
+
activesupport (= 5.2.3)
|
161
|
+
method_source
|
162
|
+
rake (>= 0.8.7)
|
163
|
+
thor (>= 0.19.0, < 2.0)
|
164
|
+
rainbow (3.0.0)
|
165
|
+
rake (10.5.0)
|
166
|
+
redcarpet (3.5.0)
|
167
|
+
rly (0.2.3)
|
168
|
+
rspec (3.8.0)
|
169
|
+
rspec-core (~> 3.8.0)
|
170
|
+
rspec-expectations (~> 3.8.0)
|
171
|
+
rspec-mocks (~> 3.8.0)
|
172
|
+
rspec-core (3.8.2)
|
173
|
+
rspec-support (~> 3.8.0)
|
174
|
+
rspec-expectations (3.8.4)
|
175
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
176
|
+
rspec-support (~> 3.8.0)
|
177
|
+
rspec-mocks (3.8.1)
|
178
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
179
|
+
rspec-support (~> 3.8.0)
|
180
|
+
rspec-support (3.8.2)
|
181
|
+
rspice (0.14.2)
|
182
|
+
faker (~> 1.8)
|
183
|
+
rspec (~> 3.0)
|
184
|
+
rubocop (0.76.0)
|
185
|
+
jaro_winkler (~> 1.5.1)
|
186
|
+
parallel (~> 1.10)
|
187
|
+
parser (>= 2.6)
|
188
|
+
rainbow (>= 2.2.2, < 4.0)
|
189
|
+
ruby-progressbar (~> 1.7)
|
190
|
+
unicode-display_width (>= 1.4.0, < 1.7)
|
191
|
+
ruby-progressbar (1.10.1)
|
192
|
+
signet (0.12.0)
|
193
|
+
addressable (~> 2.3)
|
194
|
+
faraday (~> 0.9)
|
195
|
+
jwt (>= 1.5, < 3.0)
|
196
|
+
multi_json (~> 1.10)
|
197
|
+
simplecov (0.17.1)
|
198
|
+
docile (~> 1.1)
|
199
|
+
json (>= 1.8, < 3)
|
200
|
+
simplecov-html (~> 0.10.0)
|
201
|
+
simplecov-html (0.10.2)
|
202
|
+
sprockets (4.0.0)
|
203
|
+
concurrent-ruby (~> 1.0)
|
204
|
+
rack (> 1, < 3)
|
205
|
+
sprockets-rails (3.2.1)
|
206
|
+
actionpack (>= 4.0)
|
207
|
+
activesupport (>= 4.0)
|
208
|
+
sprockets (>= 3.0.0)
|
209
|
+
thor (0.20.3)
|
210
|
+
thread_safe (0.3.6)
|
211
|
+
timecop (0.9.1)
|
212
|
+
tzinfo (1.2.5)
|
213
|
+
thread_safe (~> 0.1)
|
214
|
+
unicode-display_width (1.6.0)
|
215
|
+
websocket-driver (0.7.1)
|
216
|
+
websocket-extensions (>= 0.1.0)
|
217
|
+
websocket-extensions (0.1.4)
|
218
|
+
yard (0.9.20)
|
219
|
+
|
220
|
+
PLATFORMS
|
221
|
+
ruby
|
222
|
+
|
223
|
+
DEPENDENCIES
|
224
|
+
bundler (~> 2.0)
|
225
|
+
github-markup (~> 3.0)
|
226
|
+
pry (~> 0.12)
|
227
|
+
rails (~> 5.2.3)
|
228
|
+
rake (~> 10.0)
|
229
|
+
redcarpet (~> 3.5)
|
230
|
+
rspec (~> 3.0)
|
231
|
+
rspice
|
232
|
+
rubocop (~> 0.76)
|
233
|
+
simplecov (~> 0.17)
|
234
|
+
stenotype!
|
235
|
+
timecop (~> 0.9)
|
236
|
+
yard (~> 0.9)
|
237
|
+
|
238
|
+
BUNDLED WITH
|
239
|
+
2.0.2
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2019 Roman Kapitonov
|
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
|
13
|
+
all 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
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,251 @@
|
|
1
|
+
# Stenotype
|
2
|
+
|
3
|
+
This gem is a tool providing extensions to several rails components in order to track events along with the execution context. Currently ActionController and ActionJob are supported to name a few.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'Stenotype'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install Stenotype
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
### Configuration
|
24
|
+
|
25
|
+
Configuring the library is as simple as:
|
26
|
+
```ruby
|
27
|
+
Stenotype.configure do |config|
|
28
|
+
config.targets = [ # Supported targets
|
29
|
+
Stenotype::Adapters::StdoutAdapter.new,
|
30
|
+
Stenotype::Adapters::GoogleCloud.new
|
31
|
+
]
|
32
|
+
|
33
|
+
config.uuid_generator = SecureRandom
|
34
|
+
config.dispatcher = Stenotype::Dispatcher.new
|
35
|
+
config.gc_project_id = 'google_cloud_project_id'
|
36
|
+
config.gc_credentials = 'path_to_key_json'
|
37
|
+
config.gc_topic = 'google_cloud_topic'
|
38
|
+
config.gc_mode = :async # either :sync or :async
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
#### config.targets
|
43
|
+
|
44
|
+
Contain an array of targets for the events to be published to. Targets must implement method `#publish(event_data, **additional_arguments)`.
|
45
|
+
|
46
|
+
#### config.uuid_generator
|
47
|
+
|
48
|
+
An object that must implement method `#uuid`. Used when an event is emitted to generate a unique id for each event.
|
49
|
+
|
50
|
+
#### config.dispatcher
|
51
|
+
|
52
|
+
Dispatcher used to dispatch the event. A dispatcher must implement method `#publish(even, serializer: Stenotype::EventSerializer)`. By default `Stenotype::EventSerializer` is used, which is responsible for collecting the data from the event and evaluation context.
|
53
|
+
|
54
|
+
#### config.gc_project_id
|
55
|
+
|
56
|
+
Google cloud project ID. Please refer to Google Cloud management console to get one.
|
57
|
+
|
58
|
+
#### config.gc_credentials
|
59
|
+
|
60
|
+
Google cloud credentials. Might be obtained from Google Cloud management console.
|
61
|
+
|
62
|
+
#### config.gc_topic
|
63
|
+
|
64
|
+
Google Cloud topic used for publishing the events.
|
65
|
+
|
66
|
+
#### config.gc_mode
|
67
|
+
|
68
|
+
Google Cloud publish mode. Two options are available: `:sync, :async`. When in `sync` mode the event will be published in the same thread (which might influence performance). For `async` mode the event will be put into a pull which is going to be flushed after a threshold is met.
|
69
|
+
|
70
|
+
#### Configuring context handlers
|
71
|
+
|
72
|
+
Each event is emitted in a context which might be an ActionController instance or an ActiveJob instance or potentially any other place. Context handlers are implemented as plain ruby classes, so before using them you must register them. By default a plain `Class` handler is registered when not used with any framework. In case Ruby on Rails is used, then there are two additional context handlers for `ActionController` and `ActiveJob` instances.
|
73
|
+
|
74
|
+
### Emitting Events
|
75
|
+
|
76
|
+
Emitting an event is as simple as:
|
77
|
+
```ruby
|
78
|
+
Stenotype::Event.emit!(
|
79
|
+
data,
|
80
|
+
options: additional_options,
|
81
|
+
eval_context: { name_of_registered_context_handler: context_object }
|
82
|
+
)
|
83
|
+
```
|
84
|
+
|
85
|
+
The event is then going to be passed to a dispatcher responsible for sending the evens to targets. Note that a context handler must be registered before using it. See [Custom context handlers](#custom-context-handlers) for more details.
|
86
|
+
|
87
|
+
#### ActionController
|
88
|
+
|
89
|
+
Upon loading the library `ActionController` is going to be extended with a class method `track_view(*actions)`, where `actions` is a list of trackable controller actions.
|
90
|
+
|
91
|
+
Here is an example usage:
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
class MyController < ActionController::Base
|
95
|
+
track_view :index, :show
|
96
|
+
|
97
|
+
def index
|
98
|
+
# do_something
|
99
|
+
end
|
100
|
+
|
101
|
+
def show
|
102
|
+
# do something
|
103
|
+
end
|
104
|
+
end
|
105
|
+
```
|
106
|
+
|
107
|
+
#### ActiveJob
|
108
|
+
|
109
|
+
Upon loading the library `ActiveJob` is going to be extended with a class method `trackable_job!`.
|
110
|
+
|
111
|
+
Example:
|
112
|
+
```ruby
|
113
|
+
class MyJob < ActiveJob::Base
|
114
|
+
trackable_job!
|
115
|
+
|
116
|
+
def perform(data)
|
117
|
+
# do_something
|
118
|
+
end
|
119
|
+
end
|
120
|
+
```
|
121
|
+
|
122
|
+
#### Plain Ruby classes
|
123
|
+
|
124
|
+
To track methods from arbitrary ruby classes `Object` is extended. Any instance method of a Ruby class might be prepended with sending an event:
|
125
|
+
```ruby
|
126
|
+
class PlainRubyClass
|
127
|
+
emit_event_before :some_method, :another_method
|
128
|
+
emit_klass_event_before :class_method
|
129
|
+
|
130
|
+
def some_method(data)
|
131
|
+
# do something
|
132
|
+
end
|
133
|
+
|
134
|
+
def another_method(args)
|
135
|
+
# do something
|
136
|
+
end
|
137
|
+
|
138
|
+
def self.class_method
|
139
|
+
# do something
|
140
|
+
end
|
141
|
+
end
|
142
|
+
```
|
143
|
+
|
144
|
+
You could also use a generic method `emit_event` from anywhere. The method is mixed into `Object` class. It takes several optional kw arguments. `data` is a hash which is going to be serialized and sent as event data, `method` is by default the method you trigger `emit_event` from. `eval_context` is a hash containing the name of context handler and a context object itself.
|
145
|
+
|
146
|
+
An example usage is as follows (see [Custom context handlers](#custom-context-handlers) for more details.):
|
147
|
+
```ruby
|
148
|
+
# BaseClass sets some state
|
149
|
+
class BaseClass
|
150
|
+
attr_reader :local_state
|
151
|
+
|
152
|
+
def initialize
|
153
|
+
@local_state = 'some state'
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# A custom handler is introduced
|
158
|
+
class CustomHandler < Stenotype::ContextHandlers::Base
|
159
|
+
self.handler_name = :overriden_handler
|
160
|
+
|
161
|
+
def as_json(*_args)
|
162
|
+
{
|
163
|
+
state: context.local_state
|
164
|
+
}
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
Stenotype::ContextHandlers.register CustomHandler
|
169
|
+
|
170
|
+
# Event is being emitted twice. First time with default options.
|
171
|
+
# Second time with overriden method name and eval_context.
|
172
|
+
class PlainRubyClass < BaseClass
|
173
|
+
def some_method(data)
|
174
|
+
event_data = collect_some_data_as_a_hash
|
175
|
+
emit_event(event_data) # method name will be `some_method`, eval_context: { klass: self }
|
176
|
+
other_event_data = do_something_else
|
177
|
+
emit_event(other_event_data, method: :custom_method_name, eval_context: { overriden_handler: self })
|
178
|
+
end
|
179
|
+
end
|
180
|
+
```
|
181
|
+
|
182
|
+
### Adding customizations
|
183
|
+
|
184
|
+
#### Custom adapters
|
185
|
+
By default two adapters are implemented: Google Cloud and simple Stdout adapter.
|
186
|
+
|
187
|
+
Adding a new one might be performed by defining a class inheriting from `Stenotype::Adapters::Base`:
|
188
|
+
```ruby
|
189
|
+
class CustomAdapter < Stenotype::Adapters::Base
|
190
|
+
# A client might be optionally passed to
|
191
|
+
# the constructor.
|
192
|
+
#
|
193
|
+
# def initialize(client: nil)
|
194
|
+
# @client = client
|
195
|
+
# end
|
196
|
+
|
197
|
+
def publish(event_data, **additional_arguments)
|
198
|
+
# custom publishing logic
|
199
|
+
end
|
200
|
+
end
|
201
|
+
```
|
202
|
+
|
203
|
+
After defining a custom adapter it must be added to the list of adapters:
|
204
|
+
```ruby
|
205
|
+
Stenotype.config.targets.push(CustomAdapter.new)
|
206
|
+
```
|
207
|
+
|
208
|
+
#### Custom context handlers
|
209
|
+
|
210
|
+
A list of context handlers might be extended by defining a class inheriting from `Stenotype::ContextHandlers::Base` and registering a new context handler. Event handler must have a `self.handler_name` in order to use it during context serialization. Also custom handler must implement method `#as_json`:
|
211
|
+
```ruby
|
212
|
+
class CustomHandler < Stenotype::ContextHandlers::Base
|
213
|
+
self.handler_name = :custom_handler_name
|
214
|
+
|
215
|
+
def as_json(*_args)
|
216
|
+
{
|
217
|
+
something: something,
|
218
|
+
another: another
|
219
|
+
}
|
220
|
+
end
|
221
|
+
|
222
|
+
private
|
223
|
+
|
224
|
+
def something_from_context
|
225
|
+
context.something
|
226
|
+
end
|
227
|
+
|
228
|
+
def another_from_context
|
229
|
+
context.another
|
230
|
+
end
|
231
|
+
end
|
232
|
+
```
|
233
|
+
|
234
|
+
After defining a new context handler you must register it as follows:
|
235
|
+
```ruby
|
236
|
+
Stenotype::ContextHandlers.register CustomHandler
|
237
|
+
```
|
238
|
+
|
239
|
+
## Development
|
240
|
+
|
241
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
242
|
+
|
243
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
244
|
+
|
245
|
+
## Contributing
|
246
|
+
|
247
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/Freshly/Stenotype.
|
248
|
+
|
249
|
+
## License
|
250
|
+
|
251
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/TODO.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# Stenotype TODO list
|
2
|
+
|
3
|
+
- [x] Figure out how to pass context to data publisher. **Context is passed explicitly**
|
4
|
+
- [x] Switch from synchronous to asynchronous message publishing. **A config option for this is available**
|
5
|
+
- [x] Figure out how to unwind from using a specific framework (e.g Rails), but rather implement events in a general way suitable for plain ruby classes. **Event emitters inject in dynamic way based on what framework the gem is being used in.**
|
6
|
+
- [x] Infer data in extensible way. Given a common context implement context handlers capable of fetching data for specific cases (Controller, ActiveJobs, Models, etc.). **Context handlers are introduced. New handlers might be implemented and registered easily**
|
7
|
+
- [x] Figure out the most common default context handlers (Controller, something else). **Controller, ActiveJob and Plain ruby classes are the case now**
|
8
|
+
- [x] Develop an extensible schema for formatting the messages. **A serializer is introduced**
|
9
|
+
- [x] Cover the existing code with specs. **Coverage increased to 100%**
|
10
|
+
- [ ] Consider using batch publishing in case the load is high (how do we measure this, perhaps rpm?)
|
11
|
+
- [ ] Consider using JSON schema to validate the input for publisher
|
12
|
+
- [ ] Consider enabling an option to publish to multiple topics. Do we need to publish to multiple topics?
|
13
|
+
- [ ] Consider adding state to message dispatcher and instantiate it on every event
|
14
|
+
- [ ] Consider using `::ActiveJob::Base.around_perform` or `::ActiveJob::Base.around_enqueue` in case we need to track all jobs.
|
15
|
+
- [ ] Figure out the params for plain ruby class context handler.
|
16
|
+
- [ ] Consider `ContextHandlers::ActiveJob` params. How to deal with \_args? It won't necessarily respond to `#as_json`.
|
17
|
+
- [ ] Consider a way to switch from evaluating ruby code to using plain modules extension.
|
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'stenotype'
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require 'pry'
|
15
|
+
Pry.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Stenotype
|
4
|
+
#
|
5
|
+
# A namespace containing implementations of various adapters
|
6
|
+
# for publishing events to various destinations.
|
7
|
+
# e. g. (Google Cloud, Kafka, Stdout, other)
|
8
|
+
#
|
9
|
+
module Adapters
|
10
|
+
#
|
11
|
+
# An abstract base class for implementing adapters
|
12
|
+
#
|
13
|
+
# @abstract
|
14
|
+
#
|
15
|
+
class Base
|
16
|
+
attr_reader :client
|
17
|
+
|
18
|
+
#
|
19
|
+
# @return {#publish} An adapter implementing method [#publish]
|
20
|
+
#
|
21
|
+
def initialize(client: nil)
|
22
|
+
@client = client
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# This method is expected to be implemented by subclasses
|
27
|
+
# @abstract
|
28
|
+
# @raise [NotImplementedError] unless implemented in a subclass
|
29
|
+
#
|
30
|
+
def publish(_event_data, **_additional_arguments)
|
31
|
+
raise NotImplementedError,
|
32
|
+
"#{self.class.name} must implement method #publish"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|