L2meter
L2meter is a little gem that helps you build loggers that outputs things in l2met-friendly format.
Basics
A new logger might be created like so:
metrics = L2meter.build
If you plan to use it globally across different components of your app,consider making it constant.
The base log
method accepts two type of things: bare values and key-value
pairs in form of hashes.
metrics.log "Hello world" # => hello-world
metrics.log :db_query, result: :success # => db-query result=success
It can also take a block. In this case the message will be emitted twice, once at the start of the execution and another at the end. The end result might look like so:
metrics.log :doing_work do # => doing-work at=start
do_some_work #
metrics.log :work_done # => work-done
end # => doing-work at=finish elapsed=1.2345s
In case the exception is raised inside the block, l2meter will report is like so:
metrics.log :doing_work do # => doing-work
raise ArgumentError, \ #
"something is wrong" #
end # => doing-work at=exception exception=ArgumentError message="something is wrong" elapsed=1.2345s
Context
L2meter allows setting context for a block. It might work something like this:
def do_work_with_retries
attempt = 1
begin
metrics.context attempt: attempt do
do_some_work # => doing-work attempt=1
# => doing-work attempt=2
# => doing-work attempt=3
end
rescue => error
attempt += 1
retry
end
end
L2meter supports dynamic contexts as well. You can pass a proc instead of raw value in porder to use it.
The same example as above could be written like ths instead:
def do_work_with_retries
attempt = 1
metrics.context ->{{ attempt: attempt }} do
begin
do_some_work
rescue => error
attempt +=1
retry
end
end
end
Other
Some other l2met-specific methods are supported.
metrics.count :user_registered # => count#user-registered=1
metrics.count :registered_users, 10 # => count#registered-users=10
metrics.measure :connection_count, 20 # => measure#connection-count=20
metrics.measure :db_query, 235, unit: :ms, # => measure#db-query.ms=235
metrics.sample :connection_count, 20, # => sample#connection-count=235
metrics.sample :db_query, 235, unit: :ms, # => sample#db-query.ms=235
metrics.unique :user, "[email protected]" # => unique#[email protected]
L2meter also allows to append elapsed time to your log messages automatically.
metrics.with_elapsed do
do_work_step_1
log :step_1_done # => step-1-done elapsed=1.2345s
do_work_step_2
log :step_2_done # => step-2-done elapsed=2.3456s
end
Configuration
L2meter supports configuration. Here's how you can configure things:
metrics = L2meter.build do |config|
# configuration happens here
end
Here's the list of all configurable things:
Global context
Global context works similary to context method, but globally:
config.context = { app_name: "my-app-name" }
# ...
metrics.log foo: :bar # => app-name=my-app-name foo-bar
Dynamic context is also supported:
context.context do
{ request_id: CurrentContext.request_id }
end
Sorting
By default l2meter doesn't sort tokens before output, putting them in the order they're passed. But you can make it sorted like so:
config.sort = true
# ...
metrics.log :c, :b, :a # => a b c
Source
Source is a special parameter that'll be appended to all emitted messages.
config.source = "production"
# ...
metrics.log foo: :bar # => source=production foo=bar
Prefix
Prefix allows namespacing your measure/count/unique/sample calls.
config.prefix = "my-app"
# ...
metrics.count :users, 100500 # => count#my-app.users=100500
Silence
There's a way to temporary silence the log emitter. This might be userful for tests for example.
metrics.silence do
# logger is completely silenced
metrics.log "hello world" # nothing is emitted here
end
# works normally again
metrics.log :foo # => foo
The typical setup for RSpec might look like this:
RSpec.configure do |config|
config.around :each do |example|
Metrics.silence &example
end
end
Note that this code will only silence logger in the current thread. It'll
still produce ouput if you fire up a new thread. To silence it completely,
use disable!
method, like so:
# spec/spec_helper.rb
Metrics.disable!