A RequestReporter object is used for logging request-specific information to Union Station. "Information" may include (and are not limited to):
* Web framework controller and action name. * Exceptions raised during the request. * Cache hits and misses. * Database actions.
A unique RequestReporter is created by Passenger at the beginning of every request (by calling {UnionStationHooks.begin_rack_request}). This object is closed at the end of the same request (after the Rack body object is closed).
As an application developer, the RequestReporter is the main class that you will be interfacing with. See the {UnionStationHooks} module description for an example of how you can use RequestReporter.
## Obtaining a RequestReporter
You are not supposed to create a RequestReporter object directly. You are supposed to obtain the RequestReporter object that Passenger creates for you. This is done through the `union_station_hooks` key in the Rack environment hash, as well as through 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
Note that Passenger may not have created such an object because of an error. At present, there are two error conditions that would cause a RequestReporter object not to be created. However, your code should take into account that in the future more error conditions may trigger this.
1. There is no transaction ID associated with the current request.
When Union Station support is enabled in Passenger, Passenger always
assigns a transaction ID. However, administrators can also
{https://www.phusionpassenger.com/library/admin/nginx/request_individual_processes.html
access Ruby processes directly} through process-private HTTP sockets,
bypassing Passenger's load balancing mechanism. In that case, no
transaction ID will be assigned.
2. An error occurred recently while sending data to the UstRouter, either
because the UstRouter crashed or because of some other kind of
communication error occurred. This error condition isn't cleared until
certain a timeout has passed.
The UstRouter is a Passenger process which runs locally and is
responsible for aggregating Union Station log data from multiple
processes, with the goal of sending the aggregate data over the network
to the Union Station service.
This kind of error is automatically recovered from after a certain
period of time.
## Null mode
The error condition 2 described above may also cause an existing RequestReporter object to enter the "null mode". When this mode is entered, any further actions on the RequestReporter object will become no-ops. You can check whether the null mode is active by calling {null?}.
Closing a RequestReporter also causes it to enter the null mode.
## Thread-safety
RequestReporter is not thread-safe. If you access it concurrently, be sure to wrap its operations in a mutex.
| GC_MUTEX | = | Mutex.new |
A mutex for synchronizing GC stats reporting. We
do this because in multithreaded situations we don‘t want to
interleave GC stats access with calls to
`GC.clear_stats`. Not that GC stats are very
helpful in multithreaded situations, but this is better than nothing.
@private |
|
| OBJECT_SPACE_SUPPORTS_LIVE_OBJECTS | = | ObjectSpace.respond_to?(:live_objects) | @private | |
| OBJECT_SPACE_SUPPORTS_ALLOCATED_OBJECTS | = | ObjectSpace.respond_to?(:allocated_objects) | @private | |
| OBJECT_SPACE_SUPPORTS_COUNT_OBJECTS | = | ObjectSpace.respond_to?(:count_objects) | @private | |
| GC_SUPPORTS_TIME | = | GC.respond_to?(:time) | @private | |
| GC_SUPPORTS_CLEAR_STATS | = | GC.respond_to?(:clear_stats) | @private |
Returns a new RequestReporter object. You should not call `RequestReporter.new` directly. See "Obtaining a RequestReporter" in the {RequestReporter class description}.
@api private
Returns whether {log_controller_action_block} or {log_controller_action} has been called during this request.
@return [Boolean]
Logs a benchmarking activity, for display in the activity timeline.
An activity is a block in the activity timeline in the Union Station user interace. It has a name, a begin time and an end time.
The primary use case of this method is to integrate with Rails‘s benchmarking API (`ActiveSupport::Benchmarkable`). The Rails benchmarking API allows you to run a block and to log how long that block has taken. But you can also use it to integrate with the Ruby standard library‘s `Benchmark` class.
You can wrap a benchmark call in a `UnionStationHooks.log_benchmark_block` call, so that an entry for it is displayed in the acitivity timeline. This method measures the time before and after the block runs.
The difference between this method and {log_user_activity_block} is that this method generates timeline blocks of a different color, as to differentiate user-defined activities from benchmark activities.
If your app is a Rails app, then the `union_station_hooks_rails` gem automatically calls this for you every time `ActiveSupport::Benchmarkable#benchmark` is called. This includes `benchmark` calls from controllers and from views.
@param title A title for this benchmark. It can be any arbitrary name but
may not contain newlines.
@return The return value of the block. @yield The block is expected to perform the benchmarking activity. @example Rails example
# This example shows what to put inside a Rails controller action
# method. Note that the `log_benchmark_block` call is automatically done
# for you if you use the union_station_hooks_rails gem.
UnionStationHooks.log_benchmark_block('Process data files') do
benchmark('Process data files') do
expensive_files_operation
end
end
Logs that something was successfully retrieved from a cache. This can be any cache, be it an in-memory Hash, Redis, Memcached, a flat file or whatever.
There is just one exception. You should not use this method to log cache hits in the ActiveRecord SQL cache or similar mechanisms. Database-related timing should be logged with {log_database_query}.
If your app is a Rails app, then the `union_station_hooks_rails` gem automatically calls this for you every time an `ActiveSupport::Cache` `fetch` or `read` call success. This includes calls to `Rails.cache.fetch` or `Rails.cache.read`, because `Rails.cache` is an instance of `ActiveSupport::Cache`.
@param [String] name A unique name for this cache hit event. The cache
key is a good value to use.
@note At present (30 September 2015), logged cache hit/miss information
isn't shown in the Union Station interface. We may implement this feature in the near future.
Logs the failure to retrieve something from a cache. This can be any cache, be it an in-memory Hash, Redis, Memcached, a flat file or whatever.
There is just one exception. You should not use this method to log cache misses in the ActiveRecord SQL cache or similar mechanisms. Database-related timing should be logged with {log_database_query}.
If your app is a Rails app, then the `union_station_hooks_rails` gem automatically calls this for you every time an `ActiveSupport::Cache` `fetch` or `read` call success. This includes calls to `Rails.cache.fetch` or `Rails.cache.read`, because `Rails.cache` is an instance of `ActiveSupport::Cache`.
@param [String] name A unique name for this cache miss event. The cache
key is a good value to use.
@param [Numeric] miss_cost_duration The amount of time that was spent in
calculating or processing something, as a result of this cache miss. This time is in **microseconds**.
@note At present (30 September 2015), logged cache hit/miss information
isn't shown in the Union Station interface. We may implement this feature in the near future.
Logs that the application server is about to call `close` on the Rack body object.
This call must be followed by a call to {log_closing_rack_body_end} some time later.
This is automatically called by Passenger‘s Rack handler.
@private @return An ID to be passed later to {log_closing_rack_body_end}, or nil
on error.
Logs that you are calling a web framework controller action. Of course, you should only call this if your web framework has the concept of controller actions. For example Rails does, but Sinatra and Grape don‘t.
You can pass additional information about the web framework controller action, which will be logged.
Unlike {log_controller_action_block}, this form does not expect a block. However, you are expected to pass timing information to the options hash.
The `union_station_hooks_rails` gem automatically calls {log_controller_action_block} for you if your application is a Rails app.
@param [Hash] options Information about the controller action. @option options [String] :controller_name (optional)
The controller's name, e.g. `PostsController`.
@option options [String] :action_name (optional if :controller_name
isn't set) The controller action's name, e.g. `create`.
@option options [String] :method (optional)
The HTTP method that the web framework thinks this request should have, e.g. `GET` and `PUT`. The main use case for this option is to support Rails's HTTP verb emulation. Rails uses a parameter named [`_method`](http://guides.rubyonrails.org/form_helpers.html#how-do-forms-with-patch-put-or-delete-methods-work-questionmark) to emulate HTTP verbs besides GET and POST. Other web frameworks may have a similar mechanism.
@option options [TimePoint or Time] :begin_time The time at which the
controller action begun. See {UnionStationHooks.now} to learn more.
@option options [TimePoint or Time] :end_time The time at which the
controller action ended. See {UnionStationHooks.now} to learn more.
@option options [Boolean] :has_error (optional) Whether an uncaught
exception occurred during the request. Default: false.
@example
# This example shows what to put inside a Rails controller action
# method. Note that all of this is automatically done for you if you
# use the union_station_hooks_rails gem.
options = {
:controller_name => self.class.name,
:action_name => action_name,
:method => request.request_method,
:begin_time => UnionStationHooks.now
}
begin
do_some_request_processing_here
rescue Exception
options[:has_error] = true
raise
ensure
options[:end_time] = UnionStationHooks.now
reporter.log_controller_action(options)
end
Logs that you are calling a web framework controller action. Of course, you should only call this if your web framework has the concept of controller actions. For example Rails does, but Sinatra and Grape don‘t.
This form takes an options hash as well as a block. You can pass additional information about the web framework controller action, which will be logged. The block is expected to perform the actual request handling. When the block returns, timing information about the block is automatically logged.
See also {log_controller_action} for a form that doesn‘t expect a block.
The `union_station_hooks_rails` gem automatically calls this for you if your application is a Rails app.
@yield The given block is expected to perform request handling. @param [Hash] options Information about the controller action.
All options are optional.
@option options [String] :controller_name
The controller's name, e.g. `PostsController`.
@option options [String] :action_name
The controller action's name, e.g. `create`.
@option options [String] :method
The HTTP method that the web framework thinks this request should have, e.g. `GET` and `PUT`. The main use case for this option is to support Rails's HTTP verb emulation. Rails uses a parameter named [`_method`](http://guides.rubyonrails.org/form_helpers.html#how-do-forms-with-patch-put-or-delete-methods-work-questionmark) to emulate HTTP verbs besides GET and POST. Other web frameworks may have a similar mechanism.
@return The return value of the block.
@example Rails example
# This example shows what to put inside a Rails controller action
# method. Note that all of this is automatically done for you if you
# use the union_station_hooks_rails gem.
options = {
:controller_name => self.class.name,
:action_name => action_name,
:method => request.request_method
}
reporter.log_controller_action_block(options) do
do_some_request_processing_here
end
Logs a database query that was performed during the request.
@option options [String] :name (optional) A name for this database
query activity. Default: "SQL"
@option options [TimePoint or Time] :begin_time The time at which this
database query begun. See {UnionStationHooks.now} to learn more.
@option options [TimePoint or Time] :end_time The time at which this
database query ended. See {UnionStationHooks.now} to learn more.
@option options [String] :query The database query string.
Logs an exception that occurred during a request.
If you want to use an exception that occurred outside the request/response cycle, e.g. an exception that occurred in a thread, use {UnionStationHooks.log_exception} instead.
If {log_controller_action_block} or {log_controller_action} was called during the same request, then the information passed to those methods will be included in the exception report.
@param [Exception] exception
Logs the beginning of a Rack request. This is automatically called from {UnionStationHooks.begin_rack_request} (and thus automatically from Passenger).
@private
Logs the end of a Rack request. This means that the Rack response body has been written out, and that the `close` has been called on the Rack response body.
This does not necessarily indicate that any buffering mechanism in between the app and the client (e.g. Nginx, or the Passenger core) is done flushing the response to the client.
This is automatically called from {UnionStationHooks.begin_rack_request} (and thus automatically from Passenger).
@private
Logs a user-defined activity, for display in the activity timeline.
An activity is a block in the activity timeline in the Union Station user interace. It has a name, a begin time and an end time.
Unlike {log_user_activity_block}, this form does not expect a block. However, you are expected to pass timing information.
@param name The name that should show up in the activity timeline.
It can be any arbitrary name but may not contain newlines.
@param [TimePoint or Time] begin_time The time at which this activity
begun. See {UnionStationHooks.now} to learn more.
@param [TimePoint or Time] end_time The time at which this activity
ended. See {UnionStationHooks.now} to learn more.
@param [Boolean] has_error Whether an uncaught
exception occurred during the activity.
Logs the begin of a user-defined activity, for display in the activity timeline.
An activity is a block in the activity timeline in the Union Station user interace. It has a name, a begin time and an end time.
This form logs only the name and the begin time. You must also call {log_user_activity_end} later with the same name to log the end time.
@param name The name that should show up in the activity timeline.
It can be any arbitrary name but may not contain newlines.
@return id An ID which you must pass to {log_user_activity_end} later.
Logs a user-defined activity, for display in the activity timeline.
An activity is a block in the activity timeline in the Union Station user interace. It has a name, a begin time and an end time.
This form takes a block. Before and after the block runs, the time is measured.
@param name The name that should show up in the activity timeline.
It can be any arbitrary name but may not contain newlines.
@return The return value of the block. @yield The block is expected to perform the activity. @example
reporter.log_user_activity_block('Preheat cache') do
calculate_preheat_values.each_pair do |key, value|
Rails.cache.write(key, value)
end
end
Logs the end of a user-defined activity, for display in the activity timeline.
An activity is a block in the activity timeline in the Union Station user interace. It has a name, a begin time and an end time.
This form logs only the name and the end time. You must also have called {log_user_activity_begin} earlier with the same name to log the begin time.
@param id The ID which you obtained from {log_user_activity_begin}
earlier.
@param [Boolean] has_error Whether an uncaught
exception occurred during the activity.
Logs timing information about the rendering of a single view, template or partial.
Unlike {log_view_rendering_block}, this form does not expect a block. However, you are expected to pass timing information to the options hash.
The `union_station_hooks_rails` gem automatically calls {log_view_rendering_block} for you if your application is a Rails app. It will call this on every view or partial rendering.
@option options [String] :name Name of the view, template or partial
that is being rendered.
@option options [TimePoint or Time] :begin_time The time at which this
view rendering begun. See {UnionStationHooks.now} to learn more.
@option options [TimePoint or Time] :end_time The time at which this view
rendering ended. See {UnionStationHooks.now} to learn more.
@option options [Boolean] :has_error (optional) Whether an uncaught
exception occurred during the view rendering. Default: false.
Logs timing information about the rendering of a single view, template or partial. This form expects a block, which is to perform the view/template/partial rendering. Timing information is collected before and after the block returns.
The `union_station_hooks_rails` gem automatically calls this for you if your application is a Rails app. It will call this on every view or partial rendering.
@param [String] name Name of the view, template or partial that is being
rendered.
@yield The given block is expected to perform the actual view rendering. @return The return value of the block.
Logs that the application server is about to write out the Rack response body.
This call must be followed by a call to {log_writing_rack_body_end} some time later.
This is automatically called by Passenger‘s Rack handler.
@private @return An ID to be passed later to {log_writing_rack_body_end}, or nil
on error.
Logs that the application server is done writing out the Rack response body. This does not necessarily indicate that any buffering mechanism in between the app and the client (e.g. Nginx, or the Passenger core) is done flushing the response to the client.
This is automatically called by Passenger‘s Rack handler.
@private
Returns whether is this RequestReporter object is in null mode. See the {RequestReporter class description} for more information.