Module: UnionStationHooks

Defined in:
lib/union_station_hooks_core.rb,
lib/union_station_hooks_core/api.rb,
lib/union_station_hooks_core/log.rb,
lib/union_station_hooks_core/lock.rb,
lib/union_station_hooks_core/utils.rb,
lib/union_station_hooks_core/context.rb,
lib/union_station_hooks_core/version.rb,
lib/union_station_hooks_core/connection.rb,
lib/union_station_hooks_core/time_point.rb,
lib/union_station_hooks_core/spec_helper.rb,
lib/union_station_hooks_core/transaction.rb,
lib/union_station_hooks_core/message_channel.rb,
lib/union_station_hooks_core/request_reporter.rb,
lib/union_station_hooks_core/request_reporter/misc.rb,
lib/union_station_hooks_core/request_reporter/basics.rb,
lib/union_station_hooks_core/request_reporter/controllers.rb,
lib/union_station_hooks_core/request_reporter/view_rendering.rb

Overview

The UnionStationHooks module is the entry point to the ‘union_station_hooks_core` gem’s public API. Note that this API is only available since Passenger X.X.X!

**_Not familiar with ‘union_station_hooks_core`? Please read the [README](github.com/phusion/union_station_hooks_core) for an introduction._**

## Places of interest

You will probably be most interested in these:

* {UnionStationHooks.initialize!}
* {UnionStationHooks.begin_rack_request} and
  {UnionStationHooks.end_rack_request}
* {UnionStationHooks::RequestReporter}

## Rack example

Here is a small example showing to use ‘union_station_hooks_core` with a bare Rack application. There are three main things you see in this example:

1. The `union_station_hooks_*` gems are initialized.
2. Obtaining a RequestReporter object, which is the main object that you
   will be using as an application developer to log information to Union
   Station.
3. Using the RequestReporter object by calling methods on it.

Example code follows:

# (1) Initialize all `union_station_hooks_*` gems.
UnionStationHooks.initialize!

# Define application object.
app = lambda do |env|
  body, rendering_time = process_this_request(env)

  # (2) You can obtain a RequestReporter object as follows. With that
  # object, you can log to Union Station information about the current
  # request.
  reporter = env['union_station_hooks']
  reporter = Thread.current[:union_station_hooks]

  # The reporter object may be nil because of various error conditions,
  # so you must check for it.
  if reporter
    # (3) For example you can log the amount of time it took to render
    # the view.
    reporter.log_total_view_rendering_time(rendering_time)
  end

  [200, { "Content-Type" => "text/plain" }, body]
end

# Tell the application server to run this application object.
run app

Defined Under Namespace

Modules: Log, SpecHelper, Utils Classes: ConfigurationError, Connection, Context, Lock, MessageChannel, RequestReporter, TimePoint, Transaction

Constant Summary collapse

LIBROOT =

The path to the ‘union_station_hooks_core` Ruby library directory.

File.expand_path(File.dirname(__FILE__))
ROOT =

The path to the ‘union_station_hooks_core` gem root directory.

File.dirname(LIBROOT)
MAJOR_VERSION =
version_data[:major]
MINOR_VERSION =
version_data[:minor]
TINY_VERSION =
version_data[:tiny]
VERSION_STRING =
version_data[:string]
@@config =
{}
@@context =
nil
@@initializers =
[]
@@initialized =
false
@@app_group_name =
nil
@@key =
nil
@@vendored =
false

Class Method Summary collapse

Class Method Details

.app_group_nameObject



254
255
256
# File 'lib/union_station_hooks_core.rb', line 254

def app_group_name
  @@app_group_name
end

.begin_rack_request(rack_env) ⇒ RequestReporter?

Note:

You do not have to call this! Passenger automatically calls this for you! Just obtain the RequestReporter object that has been made available for you.

Indicates that a Rack request has begun. Given a Rack environment hash, this method returns RequestReporter object, which you can use for logging Union Station information about this request. This method should be called as early as possible during a request, before any processing has begun. Only after calling this method will it be possible to log request-specific information to Union Station.

The RequestReporter object that this method creates is also made available through the ‘union_station_hooks` key in the Rack environment hash, as well as the `:union_station_hooks` key in the current thread’s object:

env['union_station_hooks']
# => RequestReporter object or nil

Thread.current[:union_station_hooks]
# => RequestReporter object or nil

If this method was already called on this Rack request, then this method does nothing and merely returns the previously created RequestReporter.

See RequestReporter to learn what kind of information you can log to Union Station about Rack requests.

Returns:

  • (RequestReporter, nil)

    A RequestReporter object, or nil or because of certain error conditions. See the RequestReporter class description for when this may be nil.



61
62
63
64
65
# File 'lib/union_station_hooks_core/api.rb', line 61

def begin_rack_request(_rack_env)
  # When `initialize!` is called, the definition in
  # `api.rb` will override this implementation.
  nil
end

.call_event_pre_hook(_event) ⇒ Object



267
268
269
270
# File 'lib/union_station_hooks_core.rb', line 267

def call_event_pre_hook(_event)
  raise 'This method may only be called after ' \
    'UnionStationHooks.initialize! is called'
end

.check_initializedObject

Called by Passenger after loading the application, to check whether or not the application developer forgot to call initialize!

Raises:

  • RuntimeError



278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
# File 'lib/union_station_hooks_core.rb', line 278

def check_initialized
  if should_initialize? && !initialized?
    if defined?(::Rails)
      raise 'The Union Station hooks are not initialized. Please ensure ' \
        'that you have an initializer file ' \
        '`config/initializers/union_station.rb` in which you call ' \
        "this:\n\n" \
        "  if defined?(UnionStationHooks)\n" \
        "    UnionStationHooks.initialize!\n" \
        '  end'
    else
      raise 'The Union Station hooks are not initialized. Please ensure ' \
        'that the following code is called during application ' \
        "startup:\n\n" \
        "  if defined?(UnionStationHooks)\n" \
        "    UnionStationHooks.initialize!\n" \
        '  end'
    end
  end
end

.configHash

Returns the configuration hash. This configuration is used by all ‘union_station_hooks_*` gems. You are supposed to set this hash before calling initialize!.

At present, none of the ‘union_station_hooks_*` gems require additional configuration. All necessary configuration is pulled from Passenger. This may change if and when Union Station in the future supports application servers besides Passenger.

This hash is supposed to only contain symbol keys, not string keys. When initialize! is called, that method will convert all string keys to symbol keys before doing anything else with the config hash, so assigning string keys works even though we don’t recommend it. Furthermore, the config hash is frozen after initialization.

Returns:

  • (Hash)


230
231
232
# File 'lib/union_station_hooks_core.rb', line 230

def config
  @@config
end

.contextObject

The singleton Context object, created during initialization. All the ‘union_station_hooks_*` gem internals make use of this context object.



239
240
241
# File 'lib/union_station_hooks_core.rb', line 239

def context
  @@context
end

.end_rack_request(rack_env, uncaught_exception_raised_during_request = false) ⇒ Object

Note:

You do not have to call this! Passenger automatically calls this for you!

Indicates that a Rack request, on which begin_rack_request was called, has ended. You should call this method as late as possible during a request, after all processing have ended. Preferably after the Rack response body has closed.

The RequestReporter object associated with this Rack request and with the current, will be closed (by calling UnionStationHooks::RequestReporter#close), which finalizes the Union Station logs for this request.

This method MUST be called in the same thread that called begin_rack_request.

It is undefined what will happen if you call this method a Rack request on which begin_rack_request was not called, so don’t do that.

This method does nothing if it was already called on this Rack request.



100
101
102
103
104
105
# File 'lib/union_station_hooks_core/api.rb', line 100

def end_rack_request(_rack_env,
    _uncaught_exception_raised_during_request = false)
  # When `initialize!` is called, the definition in
  # `api.rb` will override this implementation.
  nil
end

.initialize!Boolean

Initializes the Union Station hooks. If there are any other ‘union_station_hooks_*` gems loaded, then they are initialized too.

Applications must call this during startup. Hooks aren’t actually installed until this method is called, so until you call this you cannot use the public APIs of any ‘union_station_hooks_*` gems (besides trivial things such as initialized?).

A good place to call this is in the Rackup file ‘config.ru`. Or, if your application is a Rails app, then you should create an initializer file `config/initializers/union_station.rb` in which you call this.

If this method successfully initializes, then it returns true.

Calling this method may or may not actually initialize the hooks. If this gem determines that initialization is not desired, then this method won’t do anything and will return ‘false`. See should_initialize?.

Initialization takes place according to parameters set in the configuration hash. If a required configuration option is missing, then this method will raise a ConfigurationError.

Initializing twice is a no-op. It only causes this method to return true.

Returns:

  • (Boolean)

    Whether initialization was successful.

Raises:



159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/union_station_hooks_core.rb', line 159

def initialize!
  return false if !should_initialize?
  return true if initialized?

  finalize_and_validate_config
  require_lib('api')
  create_context
  install_event_pre_hook
  initialize_other_union_station_hooks_gems
  finalize_install

  true
end

.initialized?Boolean

Returns whether the Union Station hooks are initialized.

Returns:

  • (Boolean)


174
175
176
# File 'lib/union_station_hooks_core.rb', line 174

def initialized?
  @@initialized
end

.initializersObject

An array of objects on which ‘#initialize!` will be called when initialize! is called. Other `union_station_hooks_*` gems register themselves in this list when they are loaded, so that a call to initialize! will initialize them too.



249
250
251
# File 'lib/union_station_hooks_core.rb', line 249

def initializers
  @@initializers
end

.keyObject

The currently active Union Station key. This is pulled from the configuration.



262
263
264
# File 'lib/union_station_hooks_core.rb', line 262

def key
  @@key
end

.nowTimePoint

Returns an opaque object (a TimePoint) that represents a collection of metrics about the current time.

Various API methods expect you to provide timing information. They accept standard Ruby ‘Time` objects, but it is generally better to pass `TimePoint` objects. Unlike the standard Ruby `Time` object, which only contains the wall clock time (the real time), `TimePoint` may contain additional timing information such as CPU time, time spent in userspace and kernel space, time spent context switching, etc. The exact information contained in the object is operating system specific, hence why the object is meant to be opaque.

See RequestReporter#log_controller_action_happened for an example of an API method which expects timing information. ‘RequestReporter#log_controller_action_happened` expects you to provide timing information about a controller action. That timing information is supposed to be obtained by calling `UnionStationHooks.now`.

In all API methods that expect a ‘TimePoint`, you can also pass a normal Ruby `Time` object instead. But if you do that, the logged timing information will be less detailed. Only do this if you cannot obtain a `TimePoint` object for some reason.

Returns:



139
140
141
142
143
# File 'lib/union_station_hooks_core/api.rb', line 139

def now
  # When `initialize!` is called, the definition in
  # `api.rb` will override this implementation.
  nil
end

.require_lib(name) ⇒ Object



209
210
211
# File 'lib/union_station_hooks_core.rb', line 209

def require_lib(name)
  require("#{LIBROOT}/union_station_hooks_core/#{name}")
end

.should_initialize?Boolean

Returns whether the Union Station hooks should be initialized. If this method returns false, then initialize! doesn’t do anything.

At present, this method only returns true when the app is running inside Passenger. This may change if and when in the future Union Station supports application servers besides Passenger.

Returns:

  • (Boolean)


185
186
187
188
189
190
191
# File 'lib/union_station_hooks_core.rb', line 185

def should_initialize?
  if defined?(PhusionPassenger)
    PhusionPassenger::App.options['analytics']
  else
    true
  end
end

.vendored=(val) ⇒ Object



204
205
206
# File 'lib/union_station_hooks_core.rb', line 204

def vendored=(val)
  @@vendored = val
end

.vendored?Boolean

Returns whether this ‘union_station_hooks_core` gem is bundled with Passenger (as opposed to a standalone gem added to the Gemfile). See the README and the file `hacking/Vendoring.md` for information about how Passenger bundles `union_station_hooks_*` gems.

Returns:

  • (Boolean)


199
200
201
# File 'lib/union_station_hooks_core.rb', line 199

def vendored?
  @@vendored
end