README.md in timber-1.1.14 vs README.md in timber-2.0.0
- old
+ new
@@ -1,386 +1,171 @@
-# 🌲 Timber - Master your Ruby apps with structured logging
+# 🌲 Timber - Log Better. Solve Problems Faster.
-<p align="center" style="background: #140f2a;">
-<a href="http://files.timber.io/images/readme-interface.gif"><img src="http://files.timber.io/images/readme-interface.gif" width="100%" /></a>
-</p>
-
[](LICENSE.md)
[](https://circleci.com/gh/timberio/timber-ruby/tree/master)
-[](https://coveralls.io/github/timberio/timber-ruby?branch=master)
[](https://codeclimate.com/github/timberio/timber-ruby)
[](http://www.rubydoc.info/github/timberio/timber-ruby)
-Still logging raw text? Timber is a complete *structured* logging solution that you can setup in
-minutes. It solves logging so you don't have to!
+* [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)
-To learn more, checkout out [timber.io](https://timber.io).
+## Overview
-## Installation
+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.
-1. *Add* the `timber` gem in `Gemfile`:
+For example, Timber turns this:
- ```ruby
- # Gemfile
+```
+Sent 200 in 45.ms
+```
- gem 'timber'
- ```
+Into this:
-2. *Install* the `Timber::Logger` in `config/environments/production.rb`:
+```
+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}}}
+```
- ```ruby
- # config/environments/production.rb
+Allowing you to run queries like:
- # config.log_formatter = ::Logger::Formatter.new # <--------------------------- REMOVE ME
- # config.logger = ActiveSupport::TaggedLogging.new(logger) # <----------------- REMOVE ME
+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!
- config.logger = ActiveSupport::TaggedLogging.new(Timber::Logger.new(STDOUT)) # <-- ADD ME
- ```
----
+## Installation
-<details><summary><strong>Prefer to see an example pull request?</strong></summary><p>
+1. In `Gemfile`, add the `timber` gem:
-Checkout our the [Timber install example pull request](https://github.com/timberio/ruby-rails-example-app/pull/1/files)
+ ```ruby
+ gem 'timber', '~> 2.0'
+ ```
----
+2. In your `shell`, run `bundle install`
-</p></details>
+3. In your `shell`, run `bundle exec timber install`
-<details><summary><strong>Not using Rails?</strong></summary><p>
-No problem! You can easily install Timber following these steps:
-
-1. *Insert* the Timber probes:
-
- This should be executed *immediately after* you have required your dependencies.
-
- ```ruby
- Timber::Probes.insert!
- ```
-
-2. *Add* the Rack middlewares:
-
- This should be included where you build your `Rack` application. Usually `config.ru`:
-
- ```ruby
- # Most likely config.ru
-
- Timber::RackMiddlewares.middlewares.each do |m|
- use m
- end
- ```
-
-2. *Instantiate* the Timber logger:
-
- This should be *globally* available to your application:
-
- ```ruby
- logger = Timber::Logger.new(STDOUT)
- ```
-
----
-
-</p></details>
-
-
-## Send your logs (choose one)
-
-<details><summary><strong>Heroku (log drains)</strong></summary><p>
-
-The recommended strategy for Heroku is to setup a
-[log drain](https://devcenter.heroku.com/articles/log-drains). To get your Timber log drain URL:
-
-👉 **[Add your app to Timber](https://app.timber.io)**
-
----
-
-</p></details>
-
-<details><summary><strong>Or, all other platforms (Network / HTTP)</strong></summary><p>
-
-1. *Specify* the Timber HTTP logger backend in `config/environments/production.rb`:
-
- Replace any existing `config.logger =` calls with:
-
- ```ruby
- # config/environments/production.rb (or staging, etc)
-
- http_log_device = Timber::LogDevices::HTTP.new(ENV['TIMBER_LOGS_KEY'])
- config.logger = ActiveSupport::TaggedLogging.new(Timber::Logger.new(http_log_device))
- ```
-
-2. Obtain your Timber API :key: by **[adding your app in Timber](https://app.timber.io)**.
-
-3. Assign your API key to the `TIMBER_LOGS_KEY` environment variable.
-
-</p></details>
-
-<details><summary><strong>Or, advanced setup (syslog, file tailing agent, etc)</strong></summary><p>
-
-Checkout our [docs](https://timber.io/docs) for a comprehensive list of install instructions.
-
-</p></details>
-
-
## Usage
<details><summary><strong>Basic logging</strong></summary><p>
Use `Logger` as normal:
```ruby
logger.info("My log message")
-# My log message @metadata {"level": "info", "context": {...}}
+# => My log message @metadata {"level": "info", "context": {...}}
```
Timber will *never* deviate from the public `::Logger` interface in *any* way.
---
</p></details>
-<details><summary><strong>Tagging logs</strong></summary><p>
+<details><summary><strong>Custom events</strong></summary><p>
-Tags provide a quick way to identify logs. They work just like any tagging system.
-In the context of logging, they prevent obstructing the log message to
-accomplish the same thing, while also being a step down from creating a classified custom
-event. If the event is meaningful in any way, we recommend creating a custom event.
+Custom events allow you to extend beyond events already defined in
+the [`Timber::Events`](lib/timber/events) namespace.
```ruby
-logger.info(message: "My log message", tag: "tag")
+Logger.warn "Payment rejected", payment_rejected: {customer_id: "abcd1234", amount: 100, reason: "Card expired"}
-# My log message @metadata {"level": "info", "tags": ["tag"], "context": {...}}
+# => Payment rejected @metadata {"level": "warn", "event": {"payment_rejected": {"customer_id": "abcd1234", "amount": 100, "reason": "Card expired"}}, "context": {...}}
```
-Multiple tags:
+* 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/)
-```ruby
-logger.info(message: "My log message", tags: ["tag1", "tag2"])
-
-# My log message @metadata {"level": "info", "tags": ["tag1", "tag2"], "context": {...}}
-```
-
-Using `ActiveSupport::TaggedLogging`? It works with that as well:
-
-```ruby
-logger.tagged("tag") do
- logger.info(message: "My log message", tags: ["important", "slow"])
-end
-
-# My log message @metadata {"level": "info", "tags": ["tag"], "context": {...}}
-```
-
-* In the Timber console use the query: `tags:tag`.
-
---
</p></details>
-<details><summary><strong>Timing events</strong></summary><p>
+<details><summary><strong>Custom contexts</strong></summary><p>
-Timings provid a simple way to time code execution:
+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
-start = Time.now
-# ...my code to time...
-time_ms = (Time.now - start) * 1000
-logger.info(message: "Task complete", tag: "my_task", time_ms: time_ms)
+Timber::CurrentContext.with({build: {version: "1.0.0"}}) do
+ logger.info("My log message")
+end
-# My log message @metadata {"level": "info", tags: ["my_task"], "time_ms": 54.2132, "context": {...}}
+# => My log message @metadata {"level": "info", "context": {"build": {"version": "1.0.0"}}}
```
-* In the Timber console use the query: `tags:my_task time_ms>500`
-* The Timber console will also display this value inline with your logs. No need to include it
- in the log message, but you certainly can if you'd prefer.
+* 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/)
----
-
</p></details>
+<details><summary><strong>Metrics</strong></summary><p>
-<details><summary><strong>Custom events</strong></summary><p>
+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.
-Custom events can be used to structure information about events that are central
-to your line of business like receiving credit card payments, saving a draft of a post,
-or changing a user's password. You have 2 options to do this:
-
-1. Log a structured Hash (simplest)
-
- ```ruby
- Logger.warn message: "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": {...}}
- ```
-
- * The hash can *only* have 2 keys: `:message` and "event type" key; `:payment_rejected` in this example.
- * Timber will keyspace your event data by the event type key passed.
-
-2. Log a Struct (recommended)
-
- Defining structs for your important events just feels oh so good :) It creates a strong contract
- with down stream consumers and gives you compile time guarantees.
-
- ```ruby
- 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")
-
- # Payment rejected @metadata {"level": "warn", "event": {"payment_rejected": {"customer_id": "abcd1234", "amount": 100, "reason": "Card expired"}}, "context": {...}}
- ```
-
-* In the Timber console use queries like: `payment_rejected.customer_id:xiaus1934` or `payment_rejected.amount>100`
-* For more advanced examples see [`Timber::Logger`](lib/timber.logger.rb).
-* Also, notice there is no mention of Timber in the above code. Just plain old logging.
-
-#### What about regular Hashes, JSON, or logfmt?
-
-Go for it! Timber will parse the data server side, but we *highly* recommend the above examples.
-Providing a `:type` allows timber to classify the event, create a namespace for the data you
-send, and make it easier to search, graph, alert, etc.
-
-```ruby
-logger.info({key: "value"})
-# {"key": "value"} @metadata {"level": "info", "context": {...}}
-
-logger.info('{"key": "value"}')
-# {"key": "value"} @metadata {"level": "info", "context": {...}}
-
-logger.info('key=value')
-# key=value @metadata {"level": "info", "context": {...}}
-```
-
----
-
</p></details>
-<details><summary><strong>Custom contexts</strong></summary><p>
-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. For example, the
-`http.request_id` field is included in the context, allowing you to find all log lines related
-to that request ID, if desired. This is in contrast to *only* showing log lines that contain this
-value.
-
-1. Add a Hash (simplest)
-
- ```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"}}}
- ```
-
- This adds data to the context keyspaced by `build`.
-
-2. Add a Struct (recommended)
-
- Just like events, we recommend defining your custom contexts. It makes a stronger contract
- with downstream consumers.
-
- ```ruby
- BuildContext = Struct.new(:version) do
- def type; :build; end
- end
- build_context = BuildContext.new("1.0.0")
- Timber::CurrentContext.with(build_context) do
- logger.info("My log message")
- end
-
- # My log message @metadata {"level": "info", "context": {"build": {"version": "1.0.0"}}}
- ```
-
-</p></details>
-
-
## Jibber-Jabber
-<details><summary><strong>What specifically does the Timber library do?</strong></summary><p>
+<details><summary><strong>Which log events does Timber structure for me?</strong></summary><p>
-1. Captures and structures your framework and 3rd party logs. (see next question)
-2. Adds useful context to every log line. (see next question)
-3. Allows you to easily add tags and timings to log. (see [Usage](#usage))
-4. Provides a framework for logging custom structured events. (see [Usage](#usage))
-5. Offers transport strategies to [send your logs](#send-your-logs) to the Timber service.
+Out of the box you get everything in the [`Timber::Events`](lib/timber/events) namespace.
----
-
-</p></details>
-
-<details><summary><strong>What are the benefits of using Timber?</strong></summary><p>
-
-1. **Data quality.** The usefulness of your logs starts here. This is why we ship libraries that
- structure logs from *within* your application; a fundamental difference from parsing. Not only
- is it much more stable, but we can include data you couldn't obtain otherwise.
-2. **Human readability.** Structuring your logs doesn't mean they have to be unreadable. Timber
- *augments* your logs with structured data. Meaning we do not alter the original log message,
- we simply attach metadata to it. And our console is specifically designed to give you access
- to this data, without compromising readability. 😮
-3. **Reliable downstream consumption.** All log events adhere to a
- [normalized, shared, schema](https://github.com/timberio/log-event-json-schema) that follows
- [semantic versioning](http://semver.org/) and goes through a [standard release process](https://github.com/timberio/log-event-json-schema/releases).
- This means you can *rely* on the structure of your logs and interact consistently with them
- across apps of any language: queries, graphs, alerts, and other downstream consumers.
-4. **Zero risk of code debt or lock-in.** Logging is a standard that has been around since the dawn
- of computers. It's built into every language, framework, and library. Timber adheres strictly
- to the default `Logger` interface. There are no special APIs, and no need to pepper your app
- with Timber specific code. It's just better logging. If you choose to stop using Timber, you
- can do so without consequence.
-5. **Long term retention.** Timber is designed on modern big-data principles. As a result, we can
- offer 6+ months of retention at prices cheaper than alternatives offering <1 month.
- This allows you to unlock your logs for purposes beyond debugging.
-
----
-
-</p></details>
-
-<details><summary><strong>What events does Timber capture & structure for me?</strong></summary><p>
-
-Out of the box you get everything in the [`Timber::Events`](lib/timber/events) namespace:
-
-1. [Controller Call Event](lib/timber/events/controller_call.rb)
-2. [Exception Event](lib/timber/events/exception.rb)
-3. [HTTP Client Request Event (net/http outgoing)](lib/timber/events/http_client_request.rb)
-4. [HTTP Client Response Event (resposne from net/http outgoing)](lib/timber/events/http_client_response.rb)
-5. [HTTP Server Request Event (incoming client request)](lib/timber/events/http_server_request.rb)
-6. [HTTP Server Response Event (response to incoming client request)](lib/timber/events/http_server_response.rb)
-7. [SQL Query Event](lib/timber/events/sql_query.rb)
-8. [Template Render Event](lib/timber/events/template_render.rb)
-9. ...more coming soon, [file an issue](https://github.com/timberio/timber-ruby/issues) to request.
-
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:
+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.
-1. [HTTP Context](lib/timber/contexts/http.rb)
-2. [Organization Context](lib/timber/contexts/organization.rb)
-3. [Process Context](lib/timber/contexts/process.rb)
-4. [Server Context](lib/timber/contexts/server.rb)
-5. [Runtime Context](lib/timber/contexts/runtime.rb)
-5. [User Context](lib/timber/contexts/user.rb)
-6. ...more coming soon, [file an issue](https://github.com/timberio/timber-ruby/issues) to request.
-
---
</p></details>
<details><summary><strong>What about my current log statements?</strong></summary><p>
-They'll continue to work as expected. Timber adheres strictly to the default `::Logger` interface
-and will never deviate in *any* way.
+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).
</p></details>
+<details><summary><strong>How is Timber different?</strong></summary><p>
+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).
+
---
+</p></details>
+
+---
+
<p align="center" style="background: #221f40;">
-<a href="http://github.com/timberio/timber-ruby"><img src="http://files.timber.io/images/ruby-library-readme-log-truth.png" height="947" /></a>
+<a href="http://github.com/timberio/timber-elixir"><img src="http://files.timber.io/images/ruby-library-readme-log-truth.png" height="947" /></a>
</p>
\ No newline at end of file