Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/fundingcircle/loga

Unified logging across environments
https://github.com/fundingcircle/loga

fluentd-plugin gelf-format logging rack rails railtie sinatra

Last synced: 7 days ago
JSON representation

Unified logging across environments

Awesome Lists containing this project

README

        

# Loga

[![Gem Version](https://badge.fury.io/rb/loga.svg)](https://badge.fury.io/rb/loga)
![CI Build status](https://github.com/FundingCircle/loga/actions/workflows/build-and-test.yml/badge.svg?branch=master)
[![Code Quality](https://codeclimate.com/repos/5563694f6956805723005d2f/badges/8eecb9144730614fb39e/gpa.svg)](https://codeclimate.com/repos/5563694f6956805723005d2f/feed)
[![Test Coverage](https://codeclimate.com/repos/5563694f6956805723005d2f/badges/8eecb9144730614fb39e/coverage.svg)](https://codeclimate.com/repos/5563694f6956805723005d2f/coverage)
[![Dependency Status](https://img.shields.io/librariesio/release/rubygems/loga)](https://libraries.io/rubygems/loga)

## Description

Loga provides consistent logging across frameworks and environments.

Includes:
- One tagged logger for all environments
- Human readable logs for development
- Structured logs for production ([GELF](http://docs.graylog.org/en/2.1/pages/gelf.html))
- One Rack logger for all Rack based applications

## TOC

- [Installation](#installation)
- [Rails](#rails)
- [Reduced logs](#reduced-logs)
- [Request log tags](#request-log-tags)
- [Sinatra](#sinatra)
- [Output example](#output-example)
- [GELF Format](#gelf-format)
- [Simple Format](#simple-format)
- [Road map](#road-map)
- [Contributing](#contributing)
- [Running tests](#running-tests)
- [Credits](#credits)
- [License](#license)

## Installation

Add this line to your application's Gemfile:

```
gem 'loga'
```

### Rails

Let Loga know what your application name is and Loga will do the rest.

```ruby
# config/application.rb
class MyApp::Application < Rails::Application
config.loga = { service_name: 'my_app' }
end
```

Loga hooks into the Rails logger initialization process and defines its own logger for all environments.

The logger configuration is adjusted based on the environment:

| | Production | Test | Development | Others |
|--------|------------|--------------|-------------|--------|
| Output | STDOUT | log/test.log | STDOUT | STDOUT |
| Format | gelf | simple | simple | simple |

You can customize the configuration to your liking:

```ruby
# config/application.rb
class MyApp::Application < Rails::Application
config.loga = {
device: File.open("log/application.log", 'a'),
format: :gelf,
service_name: 'my_app',
}
end
```

Loga leverages existing Rails configuration options:

- `config.filter_parameters`
- `config.log_level`
- `config.log_tags`

Use these options to customize Loga instead of the Loga options hash.

Inside your application use `Rails.logger` instead of `Loga.logger`, even though
they are equivalent, to prevent lock-in.

#### Reduced logs

When the format set to `gelf` requests logs are reduced to a single log entry, which
could include an exception.

This is made possible by silencing these loggers:

- `Rack::Request::Logger`
- `ActionDispatch::DebugExceptions`
- `ActionController::LogSubscriber`
- `ActionView::LogSubscriber`
- `ActionMailer::LogSubscriber`

#### Request log tags

To provide consistency between Rails and other Rack frameworks, tags (e.i `config.log_tags`)
are computed with a [Loga::Rack::Request](lib/loga/rack/request.rb) as
opposed to a `ActionDispatch::Request`.

### Sinatra

With Sinatra Loga needs to be configured manually:

```ruby
# config.ru
require 'sinatra/base'
require 'loga'

Loga.configure(
filter_parameters: [:password],
format: :gelf,
service_name: 'my_app',
tags: [:uuid],
)

class MyApp < Sinatra::Base
set :logging, false # suppress Sinatra request logger

get '/' do
Loga.logger.info('Everything is Awesome!')
'Hello World!'
end
end

use Loga::Rack::RequestId
use Loga::Rack::Logger

run MyApp
```

You can now use `Loga.logger` or assign it to your existing logger.
The above configuration also inserts two middleware:

- `Loga::Rack::RequestId` makes the request id available to the request logger
- `Loga::Rack::Logger` logs requests

You can easily switch between formats by using the `LOGA_FORMAT`
environment variable. The `format` key in the options takes precedence over the
environment variable therefore it must be removed.

```
LOGA_FORMAT=simple rackup
```

### Sidekiq

Loga `2.7` provides an out-of-the-box support for `Sidekiq ~> 7.0`.

## Output Example

### GELF Format

Rails request logger: (includes controller/action name):

`curl localhost:3000/ok -X GET -H "X-Request-Id: 12345"`

```json
{
"_request.status": 200,
"_request.method": "GET",
"_request.path": "/ok",
"_request.params": {},
"_request.request_id": "12345",
"_request.request_ip": "127.0.0.1",
"_request.user_agent": null,
"_request.controller": "ApplicationController#ok",
"_request.duration": 0,
"_type": "request",
"_service.name": "my_app",
"_service.version": "1.0",
"_tags": "12345",
"short_message": "GET /ok 200 in 0ms",
"timestamp": 1450150205.123,
"host": "example.com",
"level": 6,
"version": "1.1"
}
```

Sinatra request output is identical to Rails but without the `_request.controller` key.

Logger output:

```ruby
# Rails.logger
# or
# Loga.logger

Loga.configure(service_name: 'my_app', format: :gelf)

Loga.logger.info('I love Loga')
Loga.logger.tagged(%w(USER_123 CRM)) do
Loga.logger.info('I love Loga with tags')
end
```

```json
{
"_service.name": "my_app",
"_service.version": "v1.0.0",
"_tags": "",
"host": "example.com",
"level": 6,
"short_message": "I love Loga",
"timestamp": 1479402679.663,
"version": "1.1"
}
```

```json
{
"_service.name": "my_app",
"_service.version": "v1.0.0",
"_tags": "USER_123 CRM",
"host": "example.com",
"level": 6,
"short_message": "I love Loga",
"timestamp": 1479402706.102,
"version": "1.1"
}
```

### Simple Format

Request logger:

`curl localhost:3000/ok -X GET -H "X-Request-Id: 12345"`

Rails

```
I, [2016-11-15T16:05:03.614081+00:00 #1][12345] Started GET "/ok" for ::1 at 2016-11-15 16:05:03 +0000
I, [2016-11-15T16:05:03.620176+00:00 #1][12345] Processing by ApplicationController#ok as HTML
I, [2016-11-15T16:05:03.624807+00:00 #1][12345] Rendering text template
I, [2016-11-15T16:05:03.624952+00:00 #1][12345] Rendered text template (0.0ms)
I, [2016-11-15T16:05:03.625137+00:00 #1][12345] Completed 200 OK in 5ms (Views: 4.7ms)
```

Sinatra

```
I, [2016-11-15T16:10:08.645521+00:00 #1][12345] GET /ok 200 in 0ms type=request data={:request=>{"status"=>200, "method"=>"GET", "path"=>"/ok", "params"=>{}, "request_id"=>"12345", "request_ip"=>"127.0.0.1", "user_agent"=>nil, "duration"=>0}}
```

Logger output:

```ruby
Loga.configure(service_name: 'my_app', format: :simple)

Loga.logger.info('I love Loga')
Loga.logger.tagged(%w(USER_123 CRM)) do
Loga.logger.info('I love Loga with tags')
end
```

```
I, [2016-11-17T17:07:46.714215+00:00 #595] I love Loga
I, [2016-11-17T17:07:46.725624+00:00 #595][USER_123 CRM] I love Loga with tags
```

## Road map

Consult the [milestones](https://github.com/FundingCircle/loga/milestones).

## Contributing

Loga is in active development, feedback and contributions are welcomed.

### Running tests

This project uses [`appraisal`](https://github.com/thoughtbot/appraisal/tree/v2.0.2)
to run tests against different versions of dependencies (e.g. Rails, Sinatra).

Install Loga dependencies with `bundle install` and then appraisals
with `bundle exec appraisal install`.

Run all tests with `bundle exec appraisal rspec`.

You can run tests for one appraisal with `bundle exec appraisal appraisal-name rspec`.
Refer to the [Appraisals](Appraisals) file for a complete lists of appraisals.

Prefix test command with RACK\_ENV to switch between environments for Rack based tests
`RACK_ENV=production bundle exec appraisal rspec`.

Experiment Guard support introduced to ease running tests locally `bundle exec guard`.

[CI](https://circleci.com/gh/FundingCircle/loga) results are the source of truth.

## Credits

- [Lograge](https://github.com/roidrage/lograge)
- [LogStashLogger](https://github.com/dwbutler/logstash-logger)
- [Rails](https://github.com/rails/rails)
- [RackLogstasher](https://github.com/alphagov/rack-logstasher)

## License

Copyright (c) 2015 Funding Circle. All rights reserved.

Distributed under the BSD 3-Clause License.