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/simple_json.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 5.0.20!

**_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}
* {UnionStationHooks.log_exception}

## 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']
  # -OR- (if you don't have access to the Rack env):
  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, SimpleJSON, 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



257
258
259
# File 'lib/union_station_hooks_core.rb', line 257

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



270
271
272
273
# File 'lib/union_station_hooks_core.rb', line 270

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!. If so, it logs the problem and initializes now.



281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
# File 'lib/union_station_hooks_core.rb', line 281

def check_initialized
  return if !should_initialize? || initialized?
  return if !config.fetch(:check_initialized, true)

  if defined?(::Rails)
    message = '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
    message = '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

  STDERR.puts(" *** WARNING: #{message}")
  @@config[:initialize_from_check] = true
  initialize!
  report_internal_information('HOOKS_NOT_INITIALIZED', message)
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)


233
234
235
# File 'lib/union_station_hooks_core.rb', line 233

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.



242
243
244
# File 'lib/union_station_hooks_core.rb', line 242

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.



105
106
107
108
109
110
# File 'lib/union_station_hooks_core/api.rb', line 105

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

.get_delta_monotonicObject

Returns a best-estimate delta (usec) between the wallclock and the monotonic clock (updated every request), such that: time_monotic_usec = time_wallclock_usec - delta



177
178
179
180
181
# File 'lib/union_station_hooks_core/api.rb', line 177

def get_delta_monotonic
  # 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:



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

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

  finalize_and_validate_config
  require_lib('api')
  create_context
  install_postfork_hook
  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)


177
178
179
# File 'lib/union_station_hooks_core.rb', line 177

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.



252
253
254
# File 'lib/union_station_hooks_core.rb', line 252

def initializers
  @@initializers
end

.keyObject

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



265
266
267
# File 'lib/union_station_hooks_core.rb', line 265

def key
  @@key
end

.log_exception(exception) ⇒ Object

Logs an exception that did NOT occur during a request.

This method should be used for logging exceptions outside the request-response cycle, e.g. exceptions in threads. If you want to log an exception that occurred during a request, use UnionStationHooks::RequestReporter#log_exception instead. That method will also log any related request-specific information, while this method does not.

Parameters:

  • exception (Exception)

Since:

  • 2.1.0



129
130
131
132
133
# File 'lib/union_station_hooks_core/api.rb', line 129

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

.nowTimePoint

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

This TimePoint samples monotonic time (with a fallback to wall clock time) as well 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 the object is opaque.

You should use it for the various API methods that require timing information. Those methods also accept standard Ruby ‘Time` objects, but we strongly recommended against doing this, because wall clock time can jump forwards and backwards, which may create issues.

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

Returns:



168
169
170
171
172
# File 'lib/union_station_hooks_core/api.rb', line 168

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

.require_lib(name) ⇒ Object



212
213
214
# File 'lib/union_station_hooks_core.rb', line 212

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)


188
189
190
191
192
193
194
# File 'lib/union_station_hooks_core.rb', line 188

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

.vendored=(val) ⇒ Object



207
208
209
# File 'lib/union_station_hooks_core.rb', line 207

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)


202
203
204
# File 'lib/union_station_hooks_core.rb', line 202

def vendored?
  @@vendored
end