Project

green_log

0.0
No release in over a year
Structured logging for cloud-native systems.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
 Dependencies

Development

~> 2.0
~> 0.12.2
>= 0
~> 13.0
~> 3.0
~> 0.77

Runtime

~> 1.8
 Project Readme

GreenLog

GreenLog is a logging library for Ruby applications. It:

  • focuses on structured logging - treating log entries as data
  • is optimised for use in modern "cloud-native" applications
  • can be used in place of Ruby's stdlib Logger

Design approach

GreenLog:

Installation

Add this line to your application's Gemfile:

gem 'green_log'

And then execute:

$ bundle

Usage

tl;dr

require 'green_log'

logger = GreenLog::Logger.build

logger.info("Stuff happened")
# outputs: I -- Stuff happened

Basic logging

GreenLog implements all the expected logging shortcuts:

logger.debug("Nitty gritty detail")
# outputs: D -- Nitty gritty detail
logger.info("Huh, interesting.")
# outputs: I -- Huh, interesting.
logger.warn("Careful now.")
# outputs: W -- Careful now.
logger.error("Oh, that's really not good!")
# outputs: E -- Oh, that's really not good!
logger.fatal("Byeeee ...")
# outputs: F -- Byeeee ...

Adding context

Logger#with_context adds detail about the source of log messages.

logger = GreenLog::Logger.build.with_context(pid: Process.pid, thread: Thread.current.object_id)
logger.info("Hello")
# outputs: I [pid=13545 thread=70260187418160] -- Hello

It can be chained to inject additional context:

logger.with_context(request: 16273).info("Handled")
# outputs: I [pid=13545 thread=70260187418160 request=16273] -- Handled

Context can also be calculated dynamically, using a block:

logger = GreenLog::Logger.build.with_context do
  {
    request_id: Thread.current[:request_id]
  }
end
# outputs: I [pid=13545 thread=70260187418160 request=16273] -- Handled

Including data and exceptions

A Hash of data can be included along with the log message:

logger = GreenLog::Logger.build
logger.info("New widget", id: widget.id)
# outputs: I -- New widget [id=12345]

And/or, you can attach an exception:

begin
  Integer("abc")
rescue => e
  logger.error("parse error", e)
end
# outputs: E -- parse error
#            ! ArgumentError: invalid value for Integer(): "abc"
#              (irb):50:in `Integer'
#              (irb):50:in `irb_binding'
#              ...

Alternate output format

By default GreenLog logs with a human-readable format; specify an alternate format class if you want a different serialisation format. It comes bundled with a JSON writer, e.g.

logger = GreenLog::Logger.build(format: GreenLog::JsonWriter)
# OR
logger = GreenLog::Logger.build(format: "json")

logger.info("Structured!", foo: "bar")

outputs

{"severity":"INFO","message":"Structured!","data":{"foo":"bar"},"context":{}}

Alternate output destination

Logs go to STDOUT by default; specify dest to override, e.g.

logger = GreenLog::Logger.build(dest: STDERR)

Null logger

GreenLog::Logger.null returns a "null object" Logger, which routes log entries to /dev/null.

logger = GreenLog::Logger.null

Filtering by log severity

By default all log entries will result in output. You can add a severity-threshold to avoid emitting debug-level log messages, e.g.

logger = GreenLog::Logger.build(severity_threshold: :INFO)
# OR
logger = GreenLog::Logger.build.with_severity_threshold(:INFO)

log.debug("Whatever") # ignored

Block form

Rather than passing arguments, you can provide a block to generate log messages:

logger.info do
  "generated message"
end
# outputs: I -- generated message

The block may be ignored, if a severity-threshold is in effect:

logger = GreenLog::Logger.build(severity_threshold: :INFO)

log.debug do
  # not evaluated
end

Compatibility with stdlib Logger

GreenLog includes a backward-compatibile adapter for code written to use Ruby's built-in Logger:

require 'green_log/classic_logger'

legacy_logger = logger.to_classic_logger
legacy_logger.warn("Old skool")
# outputs: W -- Old skool

Rack request-logging

GreenLog bundles a Rack middleware - an alternative to Rack::CommonLogger - that generates structured HTTP access logs:

require "green_log"
require "green_log/rack/request_logging"

logger = GreenLog::Logger.build(format: "json")
use GreenLog::Rack::RequestLogging, logger

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/mdub/green_log.

License

The gem is available as open source under the terms of the MIT License.