union_station_hooks_core 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YThkZmM0ZGI0ZTViOWUxODNkODE4ZDMxZTI1MjM0ZDYxYzk2ODdhNQ==
5
+ data.tar.gz: !binary |-
6
+ M2Q5NjgyNzI5MGQxZDlkOGIwZGViYjcwMzllMDI2ZjA4YmNjMTkzYQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NzMxNjZiMDRjY2U3N2I5ZDYzZjcwZjIxMjVhNGM0YWU5ZWJiOGM0ZmI5MjA2
10
+ NGU2NmFiMjMxMjdmY2ZmMTQ3MWRhMmM2ZDJkMjYxZjc2MzlhN2EyMjBlYmVm
11
+ NGZkOTcyYmVkNDM2MjAwOTZiNDlkYzE1NzZlZTM3YTFhYTUyYTE=
12
+ data.tar.gz: !binary |-
13
+ OGJiNTcwNzVlZjZjMzE4NmI1MDdhMjM0MjU3MDg1ZjJiMmI0MDBiNGI1YzVl
14
+ N2NiNjJkOWU0ZTU0YmQwNzU0ZGQ3NGZhYTkwNWUxMzVjZjI0NDUxYjJkOTlj
15
+ MGJlZTNhODA3NWQyNjMxMDc1ZGNmNWU1MmIyM2NiZmQwMTk2ZjY=
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2010-2015 Phusion Holding B.V.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,117 @@
1
+ # Union Station Ruby hooks core
2
+
3
+ [![Build Status](https://travis-ci.org/phusion/union_station_hooks_core.svg?branch=master)](https://travis-ci.org/phusion/union_station_hooks_core)
4
+
5
+ [Union Station](https://www.unionstationapp.com) is a web application monitoring and performance analytics platform for Ruby. In order for Union Station to analyze your application, your application must send data to Union Station. This gem allows you to do that.
6
+
7
+ `union_station_hooks_core` is a web-framework-agnostic gem that **hooks into various Ruby internals** in order to send generic Ruby application analytics information to Union Station. Not all information can be automatically inferred by hooking into the Ruby internals, so this gem also provides an **API** that you can call at key places in the codebase to supply the right information.
8
+
9
+ ### Using Ruby on Rails?
10
+
11
+ If your application is a Rails application, then you should use the [union_station_hooks_rails](https://github.com/phusion/union_station_hooks_rails) gem instead of this gem. `union_station_hooks_rails` automatically hooks into Rails to send the right information to Union Station, so that you don't have to call any APIs. Under the hood, `union_station_hooks_rails` makes use of the `union_station_hooks_core` API.
12
+
13
+ **Resources:** [About Union Station](https://www.unionstationapp.com) | [Github](https://github.com/phusion/union_station_hooks_core) | [API docs](http://www.rubydoc.info/github/phusion/union_station_hooks_core/UnionStationHooks)
14
+
15
+ **Table of contents**
16
+
17
+ * [Installation](#installation)
18
+ - [Using with Passenger](#using-with-passenger)
19
+ - [Overriding Passenger's version](#overriding-passengers-version)
20
+ - [Using without Passenger](#using-without-passenger)
21
+ * [API](#api)
22
+ * [Legacy code](#legacy-code)
23
+ * [Contributing](contributing)
24
+
25
+ ---
26
+
27
+ ## Installation
28
+
29
+ ### Using with Passenger
30
+
31
+ **Note: This documentation section only applies to Passenger X.X.X or later!**
32
+
33
+ If you use [Passenger](https://www.phusionpassenger.com/), then you do not need to install the `union_station_hooks_core` gem. `union_station_hooks_core` is bundled with Passenger.
34
+
35
+ The only thing you need to do is to ensure that the code is called during application startup:
36
+
37
+ if defined?(UnionStationHooks)
38
+ UnionStationHooks.initialize!
39
+ end
40
+
41
+ (Are you already calling `PhusionPassenger.install_framework_extensions!` from somewhere in your codebase? Please read [Legacy code](#legacy-code) for important information.)
42
+
43
+ A good place to call this is in your Rackup file, `config.ru`. Or if you are using Rails, you should create a file `config/initializers/union_station.rb` in which you call this.
44
+
45
+ When you have this call in place, enable Union Station support in Passenger. Here are some examples:
46
+
47
+ * _Passenger with Nginx integration mode_<br>
48
+
49
+ Insert the following config in your virtual host configuration, then restart Nginx:
50
+
51
+ union_station_support on;
52
+ union_station_key <YOUR KEY HERE>;
53
+
54
+ * _Passenger with Apache integration mode_<br>
55
+
56
+ Insert the following config in your virtual host configuration, then restart Apache:
57
+
58
+ UnionStationSupport on
59
+ UnionStationKey <YOUR KEY HERE>
60
+
61
+ * _Passenger Standalone_<br>
62
+
63
+ Start Passenger with the `--union-station-key` parameter:
64
+
65
+ $ passenger start --union-station-key <YOUR KEY HERE>
66
+
67
+ Or set the `union_station_key` configuration option in Passengerfile.json:
68
+
69
+ {
70
+ "union_station_key": "<YOUR KEY HERE>"
71
+ }
72
+
73
+ ### Overriding Passenger's version
74
+
75
+ **_Note: Are you using `union_station_hooks_rails`? Then be sure sure to follow the "Overriding Passenger's version" instructions in that gem's README, in addition to following the instructions below._**
76
+
77
+ Each version of Passenger bundles its own version of the `union_station_hooks_core` gem. The Passenger maintainers regularly update their bundled version with the latest version. Sometimes, you may wish to use a specific version of `union_station_hooks_core`, overriding the version that came bundled with Passenger. For example, we have may published a new version of `union_station_hooks_core` with some bug fixes, even though Passenger hasn't been updated yet.
78
+
79
+ You can override Passenger's bundled version as follows.
80
+
81
+ 1. Add `union_station_hooks_core` to your Gemfile, like this:
82
+
83
+ gem 'union_station_hooks_core'
84
+
85
+ 2. Install your gem bundle:
86
+
87
+ bundle install
88
+
89
+ 3. Ensure that your application calls `require 'union_station_hooks_core'` during startup, before you access anything in the `UnionStationHooks` module (so before the `UnionStationHooks.initialize!` call).
90
+
91
+ If you are using Rails, then Rails takes care of that automatically by calling `Bundler.require` in `config/application.rb`, so in that case you don't need to follow this step.
92
+
93
+ ### Using without Passenger
94
+
95
+ It is currently not possible to use Union Station without Passenger. If you would like to have this feature, please let us know.
96
+
97
+ ## API
98
+
99
+ Please refer to [the API documentation website](http://www.rubydoc.info/github/phusion/union_station_hooks_core/UnionStationHooks).
100
+
101
+ ## Legacy code
102
+
103
+ Before Passenger X.X.X, the Union Station setup instructions used to tell you to create a `config/initializers/passenger.rb` in which you call the following code:
104
+
105
+ PhusionPassenger.install_framework_extensions! if defined?(PhusionPassenger)
106
+
107
+ Since Passenger X.X.X, `PhusionPassenger.install_framework_extensions!` has become an alias for `UnionStationHooks.initialize!`, but the former is considered deprecated. Please replace the above code with:
108
+
109
+ if defined?(UnionStationHooks)
110
+ UnionStationHooks.initialize!
111
+ end
112
+
113
+ And please also rename `config/initializers/passenger.rb` to `config/initializers/union_station.rb`.
114
+
115
+ ## Contributing
116
+
117
+ Looking to contribute to this gem? Please read the documentation in the [hacking/](https://github.com/phusion/union_station_hooks_core/blob/master/hacking) directory.
@@ -0,0 +1,360 @@
1
+ # Union Station - https://www.unionstationapp.com/
2
+ # Copyright (c) 2015 Phusion Holding B.V.
3
+ #
4
+ # "Union Station" and "Passenger" are trademarks of Phusion Holding B.V.
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files (the "Software"), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be included in
14
+ # all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ # THE SOFTWARE.
23
+
24
+ if defined?(UnionStationHooks::VERSION_STRING)
25
+ if UnionStationHooks.initialized?
26
+ raise 'Attempted to load union_station_hooks_core even though an ' \
27
+ 'alternative version was already loaded and initialized'
28
+ end
29
+ if UnionStationHooks.vendored?
30
+ # Passenger loaded its vendored Union Station hooks code, but the
31
+ # application has also included 'union_station_hooks_*' in its Gemfile. We
32
+ # want the version in the Gemfile to take precedence, so we unload the old
33
+ # version. At this point, the Union Station hooks aren't installed yet, so
34
+ # removing the module is enough to unload the old version.
35
+ #
36
+ # See also hacking/Vendoring.md
37
+ config_from_vendored_ush = UnionStationHooks.config
38
+ initializers_from_vendored_ush = UnionStationHooks.initializers
39
+ Object.send(:remove_const, :UnionStationHooks)
40
+ end
41
+ end
42
+
43
+ # The UnionStationHooks module is the entry point to the
44
+ # `union_station_hooks_core` gem's public API. Note that this API is only
45
+ # available since Passenger X.X.X!
46
+ #
47
+ # **_Not familiar with `union_station_hooks_core`? Please read the
48
+ # [README](https://github.com/phusion/union_station_hooks_core)
49
+ # for an introduction._**
50
+ #
51
+ # ## Places of interest
52
+ #
53
+ # You will probably be most interested in these:
54
+ #
55
+ # * {UnionStationHooks.initialize!}
56
+ # * {UnionStationHooks.begin_rack_request} and
57
+ # {UnionStationHooks.end_rack_request}
58
+ # * {UnionStationHooks::RequestReporter}
59
+ #
60
+ # ## Rack example
61
+ #
62
+ # Here is a small example showing to use `union_station_hooks_core` with a
63
+ # bare Rack application. There are three main things you see in this example:
64
+ #
65
+ # 1. The `union_station_hooks_*` gems are initialized.
66
+ # 2. Obtaining a RequestReporter object, which is the main object that you
67
+ # will be using as an application developer to log information to Union
68
+ # Station.
69
+ # 3. Using the RequestReporter object by calling methods on it.
70
+ #
71
+ # Example code follows:
72
+ #
73
+ # # (1) Initialize all `union_station_hooks_*` gems.
74
+ # UnionStationHooks.initialize!
75
+ #
76
+ # # Define application object.
77
+ # app = lambda do |env|
78
+ # body, rendering_time = process_this_request(env)
79
+ #
80
+ # # (2) You can obtain a RequestReporter object as follows. With that
81
+ # # object, you can log to Union Station information about the current
82
+ # # request.
83
+ # reporter = env['union_station_hooks']
84
+ # reporter = Thread.current[:union_station_hooks]
85
+ #
86
+ # # The reporter object may be nil because of various error conditions,
87
+ # # so you must check for it.
88
+ # if reporter
89
+ # # (3) For example you can log the amount of time it took to render
90
+ # # the view.
91
+ # reporter.log_total_view_rendering_time(rendering_time)
92
+ # end
93
+ #
94
+ # [200, { "Content-Type" => "text/plain" }, body]
95
+ # end
96
+ #
97
+ # # Tell the application server to run this application object.
98
+ # run app
99
+ module UnionStationHooks
100
+ # The path to the `union_station_hooks_core` Ruby library directory.
101
+ #
102
+ # @private
103
+ LIBROOT = File.expand_path(File.dirname(__FILE__))
104
+
105
+ # The path to the `union_station_hooks_core` gem root directory.
106
+ #
107
+ # @private
108
+ ROOT = File.dirname(LIBROOT)
109
+
110
+ class << self
111
+ # This error is raised by {UnionStationHooks.initialize!} if a required
112
+ # {UnionStationHooks.config configuration option} is missing.
113
+ class ConfigurationError < StandardError
114
+ end
115
+
116
+ # @private
117
+ @@config = {}
118
+ # @private
119
+ @@context = nil
120
+ # @private
121
+ @@initializers = []
122
+ # @private
123
+ @@initialized = false
124
+ # @private
125
+ @@app_group_name = nil
126
+ # @private
127
+ @@key = nil
128
+ # @private
129
+ @@vendored = false
130
+
131
+ # Initializes the Union Station hooks. If there are any other
132
+ # `union_station_hooks_*` gems loaded, then they are initialized too.
133
+ #
134
+ # Applications must call this during startup. Hooks aren't actually
135
+ # installed until this method is called, so until you call this you cannot
136
+ # use the public APIs of any `union_station_hooks_*` gems (besides trivial
137
+ # things such as {UnionStationHooks.initialized?}).
138
+ #
139
+ # A good place to call this is in the Rackup file `config.ru`. Or, if your
140
+ # application is a Rails app, then you should create an initializer file
141
+ # `config/initializers/union_station.rb` in which you call this.
142
+ #
143
+ # If this method successfully initializes, then it returns true.
144
+ #
145
+ # Calling this method may or may not actually initialize the hooks. If
146
+ # this gem determines that initialization is not desired, then this method
147
+ # won't do anything and will return `false`. See
148
+ # {UnionStationHooks#should_initialize?}.
149
+ #
150
+ # Initialization takes place according to parameters set in the
151
+ # {UnionStationHooks.config configuration hash}. If a required
152
+ # configuration option is missing, then this method will raise a
153
+ # {ConfigurationError}.
154
+ #
155
+ # Initializing twice is a no-op. It only causes this method to return true.
156
+ #
157
+ # @raise [ConfigurationError] A required configuration option is missing.
158
+ # @return [Boolean] Whether initialization was successful.
159
+ def initialize!
160
+ return false if !should_initialize?
161
+ return true if initialized?
162
+
163
+ finalize_and_validate_config
164
+ require_lib('api')
165
+ create_context
166
+ install_event_pre_hook
167
+ initialize_other_union_station_hooks_gems
168
+ finalize_install
169
+
170
+ true
171
+ end
172
+
173
+ # Returns whether the Union Station hooks are initialized.
174
+ def initialized?
175
+ @@initialized
176
+ end
177
+
178
+ # Returns whether the Union Station hooks should be initialized. If this
179
+ # method returns false, then {UnionStationHooks.initialize!} doesn't do
180
+ # anything.
181
+ #
182
+ # At present, this method only returns true when the app is running inside
183
+ # Passenger. This may change if and when in the future Union Station
184
+ # supports application servers besides Passenger.
185
+ def should_initialize?
186
+ if defined?(PhusionPassenger)
187
+ PhusionPassenger::App.options['analytics']
188
+ else
189
+ true
190
+ end
191
+ end
192
+
193
+ # Returns whether this `union_station_hooks_core` gem is bundled with
194
+ # Passenger (as opposed to a standalone gem added to the Gemfile).
195
+ # See the README and the file `hacking/Vendoring.md` for information
196
+ # about how Passenger bundles `union_station_hooks_*` gems.
197
+ #
198
+ # @private
199
+ def vendored?
200
+ @@vendored
201
+ end
202
+
203
+ # @private
204
+ def vendored=(val)
205
+ @@vendored = val
206
+ end
207
+
208
+ # @private
209
+ def require_lib(name)
210
+ require("#{LIBROOT}/union_station_hooks_core/#{name}")
211
+ end
212
+
213
+ # Returns the configuration hash. This configuration is used by all
214
+ # `union_station_hooks_*` gems. You are supposed to set this hash
215
+ # before calling {UnionStationHooks.initialize!}.
216
+ #
217
+ # At present, none of the `union_station_hooks_*` gems require
218
+ # additional configuration. All necessary configuration is pulled from
219
+ # Passenger. This may change if and when Union Station in the future
220
+ # supports application servers besides Passenger.
221
+ #
222
+ # This hash is supposed to only contain symbol keys, not string keys.
223
+ # When {UnionStationHooks.initialize!} is called, that method will
224
+ # convert all string keys to symbol keys before doing anything else
225
+ # with the config hash, so assigning string keys works even though
226
+ # we don't recommend it. Furthermore, the config hash is frozen after
227
+ # initialization.
228
+ #
229
+ # @return [Hash]
230
+ def config
231
+ @@config
232
+ end
233
+
234
+ # The singleton {Context} object, created during initialization.
235
+ # All the `union_station_hooks_*` gem internals make use of this context
236
+ # object.
237
+ #
238
+ # @private
239
+ def context
240
+ @@context
241
+ end
242
+
243
+ # An array of objects on which `#initialize!` will be called when
244
+ # {UnionStationHooks.initialize!} is called. Other `union_station_hooks_*`
245
+ # gems register themselves in this list when they are loaded, so that
246
+ # a call to {UnionStationHooks.initialize!} will initialize them too.
247
+ #
248
+ # @private
249
+ def initializers
250
+ @@initializers
251
+ end
252
+
253
+ # @private
254
+ def app_group_name
255
+ @@app_group_name
256
+ end
257
+
258
+ # The currently active Union Station key. This is pulled from the
259
+ # {UnionStationHooks.config configuration}.
260
+ #
261
+ # @private
262
+ def key
263
+ @@key
264
+ end
265
+
266
+ # @private
267
+ def call_event_pre_hook(_event)
268
+ raise 'This method may only be called after ' \
269
+ 'UnionStationHooks.initialize! is called'
270
+ end
271
+
272
+ # Called by Passenger after loading the application, to check whether or
273
+ # not the application developer forgot to call
274
+ # {UnionStationHooks.initialize!}
275
+ #
276
+ # @private
277
+ # @raise RuntimeError
278
+ def check_initialized
279
+ if should_initialize? && !initialized?
280
+ if defined?(::Rails)
281
+ raise 'The Union Station hooks are not initialized. Please ensure ' \
282
+ 'that you have an initializer file ' \
283
+ '`config/initializers/union_station.rb` in which you call ' \
284
+ "this:\n\n" \
285
+ " if defined?(UnionStationHooks)\n" \
286
+ " UnionStationHooks.initialize!\n" \
287
+ ' end'
288
+ else
289
+ raise 'The Union Station hooks are not initialized. Please ensure ' \
290
+ 'that the following code is called during application ' \
291
+ "startup:\n\n" \
292
+ " if defined?(UnionStationHooks)\n" \
293
+ " UnionStationHooks.initialize!\n" \
294
+ ' end'
295
+ end
296
+ end
297
+ end
298
+
299
+ def now
300
+ # When `initialize!` is called, the definition in
301
+ # `api.rb` will override this implementation.
302
+ nil
303
+ end
304
+
305
+ def begin_rack_request(_rack_env)
306
+ # When `initialize!` is called, the definition in
307
+ # `api.rb` will override this implementation.
308
+ nil
309
+ end
310
+
311
+ def end_rack_request(_rack_env,
312
+ _uncaught_exception_raised_during_request = false)
313
+ # When `initialize!` is called, the definition in
314
+ # `api.rb` will override this implementation.
315
+ nil
316
+ end
317
+
318
+ private
319
+
320
+ def finalize_and_validate_config
321
+ final_config = {}
322
+
323
+ if defined?(PhusionPassenger)
324
+ import_into_final_config(final_config, PhusionPassenger::App.options)
325
+ end
326
+ import_into_final_config(final_config, config)
327
+
328
+ validate_final_config(final_config)
329
+
330
+ @@config = final_config
331
+ end
332
+
333
+ def import_into_final_config(dest, source)
334
+ source.each_pair do |key, val|
335
+ dest[key.to_sym] = val
336
+ end
337
+ end
338
+
339
+ def validate_final_config(config)
340
+ require_non_empty_config_key(config, :union_station_key)
341
+ require_non_empty_config_key(config, :app_group_name)
342
+ require_non_empty_config_key(config, :ust_router_address)
343
+ require_non_empty_config_key(config, :ust_router_password)
344
+ end
345
+
346
+ def require_non_empty_config_key(config, key)
347
+ if config[key].nil? || config[key].empty?
348
+ raise ArgumentError,
349
+ "Union Station hooks configuration option required: #{key}"
350
+ end
351
+ end
352
+ end
353
+ end
354
+
355
+ UnionStationHooks.require_lib('version')
356
+
357
+ if config_from_vendored_ush
358
+ UnionStationHooks.config.replace(config_from_vendored_ush)
359
+ UnionStationHooks.initializers.replace(initializers_from_vendored_ush)
360
+ end