# 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. [Why timber?](#why-timber) 4. [Logging Custom Events](#logging-custom-events) 5. [The Timber Console / Pricing](#the-timber-console--pricing) 6. [Install](#install) ## What is Timber? [Timber](http://timber.io) is a different kind of logging platform; it goes beyond traditional logging by automatically enriching your logs with application level metadata, turning them into rich, structured events without altering the essence of logging. For example, it turns this: ``` Completed 200 OK in 117ms (Views: 85.2ms | ActiveRecord: 25.3ms) ``` Into this: ```javascript { "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": { // <---- http://i.giphy.com/EldfH1VJdbrwY.gif "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`](lib/timber/events)) ## Why Timber? Glad you asked! :) 1. It's application aware and enriches your logs with data you can't get otherwise. 2. It defines a shared schema across all of our libraries. Meaning your log data, across all applications, is normalized. 3. It does not alter the original log message, giving you the best of both worlds: human readable logs *and* rich structured events. 4. It's completely transparent with absolutely no vendor lock-in or risk of code debt. It does not introduce a special API, it's just good ol' loggin'. ## Logging Custom Events > Another service? More lock-in? :*( Nope! Logging custom events is Just Logging™. 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](lib/timber/logger.rb)) No mention of Timber anywhere! ## The Timber Console / Pricing > What good is structured log data if you can't search and visualize it? Enter [the Timber Console](https://timber.io). It's a modern, fast, and beautiful console for searching and visualizing your logs. A few example queries: 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! > This is all gravy, but wouldn't the extra data get expensive? If you opt use the [Timber Console](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. We charge per GB sent to us and retained. No user limits, no weird feature matrixes, just data. 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 'timber' ``` ### 2. Install the logger: #### Heroku: ```ruby # config/environments/production.rb (or staging, etc) config.logger = 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 = 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!* #### Rails TaggedLogging? No probs! Use it as normal, Timber will even pull out the tags and include them in the `context`. ```ruby config.logger = ActiveSupport::TaggedLogging.new(Timber::Logger.new(STDOUT)) ``` ---