# 🌲 Timber - Log Better. Solve Problems Faster.
[![ISC License](https://img.shields.io/badge/license-ISC-ff69b4.svg)](LICENSE.md)
[![CircleCI](https://circleci.com/gh/timberio/timber-ruby.svg?style=shield&circle-token=:circle-token)](https://circleci.com/gh/timberio/timber-ruby/tree/master)
[![Code Climate](https://codeclimate.com/github/timberio/timber-ruby/badges/gpa.svg)](https://codeclimate.com/github/timberio/timber-ruby)
[![View docs](https://img.shields.io/badge/docs-viewdocs-blue.svg?style=flat-square "Viewdocs")](http://www.rubydoc.info/github/timberio/timber-ruby)
* [Timber website](https://timber.io)
* [Timber docs](https://timber.io/docs)
* [Library docs](http://www.rubydoc.info/github/timberio/timber-ruby)
* [Support](mailto:support@timber.io)
## Overview
Timber turns your raw text logs into rich JSON events that can be consumed by the
[Timber.io service](https://timber.io). It improves log data quality at the source, adding
critical event and context data to your logs so that you can filter out the noise and
solve problems faster.
For example, Timber turns this:
```
Sent 200 in 45.ms
```
Into this:
```
Sent 200 in 45.2ms @metadata {"dt": "2017-02-02T01:33:21.154345Z", "level": "info", "context": {"user": {"id": 1, "name": "Ben Johnson"}, "http": {"method": "GET", "host": "timber.io", "path": "/path", "request_id": "abcd1234"}}, "event": {"http_server_response": {"status": 200, "time_ms": 45.2}}}
```
Allowing you to run queries like:
1. `context.request_id:abcd1234` - View all logs generated for a specific request.
2. `context.user.id:1` - View logs generated by a specific user.
3. `type:http_response` - View specific events (exceptions, sql queries, etc)
4. `http_server_response.time_ms:>=1000` - View slow responses with the ability to zoom out and view them in context (request, user, etc).
5. `level:error` - Levels in your logs!
## Installation
1. In `Gemfile`, add the `timber` gem:
```ruby
gem 'timber', '~> 2.0'
```
2. In your `shell`, run `bundle install`
3. In your `shell`, run `bundle exec timber install`
## Usage
Use `Logger` as normal:
```ruby
logger.info("My log message")
# => My log message @metadata {"level": "info", "context": {...}}
```
Timber will *never* deviate from the public `::Logger` interface in *any* way.
---
Custom events allow you to extend beyond events already defined in
the [`Timber::Events`](lib/timber/events) namespace.
```ruby
Logger.warn "Payment rejected", payment_rejected: {customer_id: "abcd1234", amount: 100, reason: "Card expired"}
# => Payment rejected @metadata {"level": "warn", "event": {"payment_rejected": {"customer_id": "abcd1234", "amount": 100, "reason": "Card expired"}}, "context": {...}}
```
* Notice the `:payment_rejected` root key. Timber will classify this event as such.
* In the [Timber console](https://app.timber.io) use the query: `type:payment_rejected` or `payment_rejected.amount:>100`.
* See more details on our [custom events docs page](https://timber.io/docs/ruby/custom-events/)
---
Context is additional data shared across log lines. Think of it like log join data.
Custom contexts allow you to extend beyond contexts already defined in
the [`Timber::Contexts`](lib/timber/contexts) namespace.
```ruby
Timber::CurrentContext.with({build: {version: "1.0.0"}}) do
logger.info("My log message")
end
# => My log message @metadata {"level": "info", "context": {"build": {"version": "1.0.0"}}}
```
* Notice the `:build` root key. Timber will classify this context as such.
* In the [Timber console](https://app.timber.io) use queries like: `build.version:1.0.0`
* See more details on our [custom contexts docs page](https://timber.io/docs/ruby/custom-contexts/)
Logging metrics is accomplished by logging custom events. Please see our
[metrics docs page](https://timber.io/docs/ruby/metrics/) for a more detailed explanation
with examples.
Out of the box you get everything in the [`Timber::Events`](lib/timber/events) namespace.
We also add context to every log, everything in the [`Timber::Contexts`](lib/timber/contexts)
namespace. Context is structured data representing the current environment when the log line
was written. It is included in every log line. Think of it like join data for your logs.
---
They'll continue to work as expected. Timber adheres to the default `Logger` interface.
Your previous logger calls will work as they always do.
In fact, traditional log statements for non-meaningful events, debug statements, etc, are
encouraged. In cases where the data is meaningful, consider [logging a custom event](#usage).
1. **It's just _better_ logging**. Nothing beats well structured raw data. And that's exactly
what Timber aims to provide. There are no agents, special APIs, or proprietary data
sets that you can't access.
2. **Improved log data quality.** Instead of relying on parsing alone, Timber ships libraries that
structure and augment your logs from _within_ your application. Improving your log data at the
source.
3. **Human readability.** Timber _augments_ your logs without sacrificing human readability. For
example: `log message @metadata {...}`. And when you view your logs in the
[Timber console](https://app.timber.io), you'll see the human friendly messages
with the ability to view the associated metadata.
4. **Long retention**. Logging is notoriously expensive with low retention. Timber
offers _6 months_ of retention by default with sane prices.
5. **Normalized schema.** Have multiple apps? All of Timber's libraries adhere to our
[JSON schema](https://github.com/timberio/log-event-json-schema). This means queries, alerts,
and graphs for your ruby app can also be applied to your elixir app (for example).
---
Basic logging
Custom events
Custom contexts
Metrics
Which log events does Timber structure for me?
What about my current log statements?
How is Timber different?