# Timber

[![CircleCI](https://circleci.com/gh/timberio/timber-ruby.svg?style=shield&circle-token=:circle-token)](https://circleci.com/gh/timberio/timber-ruby/tree/master) [![Coverage Status](https://coveralls.io/repos/github/timberio/timber-ruby/badge.svg?branch=master)](https://coveralls.io/github/timberio/timber-ruby?branch=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) 1. [What is timber?](#what-is-timber) 2. [Logger Examples](#logger-examples) 3. [Console Pricing](#console-pricing) 2. [Install](#install) ## What is Timber? Glad you asked! :) Timber turns your messy string logs into structured events with context where it can optionally be paired with our [simple modern console](https://timber.io) for querying. For example, it automatically turns this: ``` Completed 200 OK in 117ms (Views: 85.2ms | ActiveRecord: 25.3ms) ``` Into this: ```json { "dt": "2016-12-01T02:23:12.236543Z", "level": "info", "message": "Completed 200 OK in 117ms (Views: 85.2ms | ActiveRecord: 25.3ms)", "context": { "http": { "method": "GET", "path": "/checkout", "remote_addr": "123.456.789.10", "request_id": "abcd1234" }, "user": { "id": 2, "name": "Ben Johnson", "email": "ben@johnson.com" } }, "event": { "http_response": { "status": 200, "time_ms": 117 } } } ``` It does the same for `http requests`, `sql queries`, `exceptions`, `template renderings`, and any other event your framework logs. (for a full list see `Timber::Events`) This enables you to query your logs in a way that [even your mother would get excited about](http://i.giphy.com/7JYWGKgwxga5i.gif)! 1. `context.user.email:ben@johnson.com` - Tail a specific user! 2. `context.http.request_id:1234` - View *all* logs for a given HTTP request! 3. `event.http_reponse.time_ms>3000` - Easily find outliers and have the proper context to resolve them! 4. `level:warn` - Log levels in your logs. Imagine that! ## Logger Examples > Another service? More lock-in? More code debt? More sadness? :*( Nope! This is exactly why we created Timber. Timber is Just Logging™. No special API, no risk of code debt, no weird proprietary data format locked away in our servers. Absolutely no lock-in! Besides automatically capturing known events, you can also log custom events. Check it out: ```ruby # Simple string (original Logger interface remains untouched) Logger.warn "Payment rejected for customer abcd1234, reason: Card expired" # Structured hash Logger.warn message: "Payment rejected", type: :payment_rejected, data: %{customer_id: "abcd1234", amount: 100, reason: "Card expired"} # Using a Struct PaymentRejectedEvent = Struct.new(:customer_id, :amount, :reason) do def message; "Payment rejected for #{customer_id}"; end def type; :payment_rejected; end end Logger.warn PaymentRejectedEvent.new("abcd1234", 100, "Card expired") ``` (for more examples, see the `Timber::Logger` docs) No Timber specific code anywhere! In fact, this approach pushes things the opposite way. What if, as a result of structured logging, you could start decoupling other services from your application? Before: ``` |---[HTTP]---> sentry / bugsnag / etc My Application |---[HTTP]---> librato / graphite / etc |---[HTTP]---> new relic / etc |--[STDOUT]--> logs |---> Logging service |---> S3 |---> RedShift ``` After: ``` |-- sentry / bugsnag / etc |-- librato / graphite / etc My Application |--[STDOUT]--> logs ---> Timber ---> |-- new relic / etc ^ |-- S3 | |-- RedShift | ^ fast, efficient, durable, | replayable, auditable, change any of these without just logging touching your code *and* backfill them! ``` ## Console Pricing > This is all gravy, but wouldn't it get expensive? If you opt to send your data to the [Timber service](https://timber.io), we only charge for the size of the `message`, `dt`, and `event.custom` attributes. Everything else is stored at no cost to you. [Say wha?!](http://i.giphy.com/l0HlL2vlfpWI0meJi.gif). This ensures pricing remains predictable and simple. We charge per GB transferred to us and retained, no user limits, and no weird feature matrixes. Finally, the data is yours, in a simple non-proprietary JSON format that you can export to S3, Redshift, or any of our other integrations. For more details checkout out [timber.io](https://timber.io). ## Install ### 1. Install the gem: ```ruby # Gemfile gem 'timberio' ``` ### 2. Install the logger: #### Heroku: ```ruby # config/environments/production.rb (or staging, etc) config.logger = ActiveSupport::TaggedLogging.new(Timber::Logger.new(STDOUT)) ``` The command to add your log drain will be displayed in the [Timber app](https://app.timber.io) after you add your application. #### Non-Heroku: ```ruby # config/environments/production.rb (or staging, etc) log_device = Timber::LogDevices::HTTP.new(ENV['TIMBER_KEY']) # key can be obtained by signing up at https://timber.io config.logger = ActiveSupport::TaggedLogging.new(Timber::Logger.new(log_device)) ``` Your Timber application key will be displayed in the [Timber app](https://app.timber.io) after you add your application. *Other transport methods coming soon!* --- That's it! Log to your heart's content. For documentation on logging structured events, and other features, checkout [the docs](http://thedocs.com/). For more information on Timber visit [timber.io](https://timber.io).