Giter Club home page Giter Club logo

xyeger's Introduction

Xyeger

Table of content

Basic Usage

Xyeger Logger was created to be suitable with ElasticSearch logs, so when you log anything you will get JSON representation of your message.

Xyeger.configure {}
logger = Logger.new(STDOUT)
logger.extend(Xyeger::Logger)
logger.info('Some message')
{
  "hostname": "",
  "pid": 61915,
  "app": "",
  "env": "",
  "level": "INFO",
  "time": "2017-08-03 16:24:57 +0300",
  "message": "Some message",
  "context": {}
}

Installation

Add this line to your application's Gemfile:

gem 'xyeger'

And then execute:

$ bundle

Or install it yourself as:

$ gem install xyeger

Configuration

Add environments:

XYEGER_HOSTNAME='localhost' #f.e.: rails, sidekiq, sneakers
XYEGER_APPNAME='some_service'
XYEGER_ENV='staging'

Add into initializer file:

#config/initializers/xyeger.rb
Xyeger.configure do |config|
  config.output = STDOUT                      # default to STDOUT
  config.formatter = MyCustomFormatter        # default to Xyeger::Formatters::Json.new
  config.app = ''                             # default to ENV['XYEGER_APPNAME'] or emtpy string
  config.env = Rails.env                      # default to ENV['XYEGER_ENV'] or empty string
  config.context_resolver = MyContextResolver # ContextResolver class
  config.message_resolver = MyMessageResolver # MessageResolver class
end

Context

It was found out that just JSON-looking logs does not solve the problem of tracking request flow. So context was added.

  Xyeger.add_context(flow_id: SecureRandom.uuid)
  logger.debug('With Context')
{
  "hostname": "",
  "pid": 61915,
  "app": "",
  "env": "",
  "level": "DEBUG",
  "time": "2017-08-03 16:26:38 +0300",
  "message": "With Context",
  "context": {
    "flow_id": "6821a053-ad20-4d58-905a-25a923f7a412"
  }
}

Context Resolver

You are not wired to add only hash object to context, but in that keys you might want to create your own ContextResolver, which expect self.call(object) method and return hash-representation at the end.

class MyContextResolver
  def self.call(object)
    case object
    when User
      { user_id: object.uuid }
    end
  end
end  

Xyeger.configure { config.context_resolver = MyContextResolver }

user = User.first
Xyeger.add_context(user)

Message Resolver

Same way as it is done in context resolver you might find useful to create your own MessageResolver, which expect self.call(message, progname) method to be implemented and return string at the end.

class MessageResolver
  def self.call(message, progname)
    message =
      case message
      when ::StandardError
        [message.class.name, message].compact.join(' ')
      else
        message.to_s
      end
    [progname, message].compact.join(' ')
  end
end

Xyeger.configure { config.message_resolver = MyContextResolver }

begin
  raise
rescue => error
  Xyeger.add_context(error)
  raise error
end

Formatters

By default you have following formatters

Formatter Description
Xyeger::Formatters::Base
Xyeger::Formatters::Json default formater
Xyeger::Formatters::Values show only values
Xyeger::Formatters::Text show text form

Base formatter

All built-in formatters inherit from Xyeger::Formatters::Base, which prepare result hash with following keys: hostname, pid, app, env, level, time, message, context.

JSON Formatter

Default representation of logs:

logger.formatter = Xyeger::Formatters::Json.new # default formatter
{
  "hostname": "",
  "pid": 61915,
  "app": "",
  "env": "",
  "level": "DEBUG",
  "time": "2017-08-03 16:26:38 +0300",
  "message": "With Context ",
  "context": {
    "flow_id": "6821a053-ad20-4d58-905a-25a923f7a412"
  }
}

Values Formatter

All the values of Base formatter hash concatenated with space delimiter.

logger.formatter = Xyeger::Formatters::Values.new
 61915   DEBUG 2017-08-03 17:00:07 +0300 With Context  {:flow_id=>"6821a053-ad20-4d58-905a-25a923f7a412"}

Text Formatter

Context represented via list of key-value. Message is just string at the end

logger.formatter = Xyeger::Formatters::Text.new
 [2017-08-03 16:59:51 +0300] [DEBUG] flow_id=6821a053-ad20-4d58-905a-25a923f7a412 With Context 

Custom Formatter

You are free to implement your own formatters, but things to be mentioned: if you need all default keys accessible inside your formatter, you have to inherit from Xyeger::Formatters::Base formatter. See lib/xyeger/formatters directory for more info.

Integrations

You can easily use Xyeger with different type of applications and here are some built in integrations

Rails

Integration with rails add Xyeger::Rails::FlowIdMiddlare in application middlware stack so it will automatically add end-to-end identifier(:fid) inside context for each request and clear it out when request is ended.

Grape

Grape has it's own logger inside. Most of the time you create extra module to specify logging preferences. It may look something like that.

module API
  module Helpers
    module Logger
      extend ActiveSupport::Concern

      included do
        logger.extend(Xyeger::Logger)
        logger.formatter = Xyeger.config.formatter

        use GrapeLogging::Middleware::RequestLogger,
          logger: logger,
          formatter: logger.formatter,
          include: [
            GrapeLogging::Loggers::Response.new,
            GrapeLogging::Loggers::FilterParameters.new,
            GrapeLogging::Loggers::ClientEnv.new
          ]
      end
    end
  end
end

So inside your application you just include API::Helpers::Logger

module API
  class Root < Grape::API
    include API::Helpers::Logger
  end
end

Sidekiq

Sidekiq integration is really useful too. It store fid inside job and you can track logs even for retries. You don't have to do anything extra.

Sentry

Sentry integration is hardcoded inside gem. So when you add anything inside context of Xyeger, it also means that you add something to Sentry context.

Plain ruby app

For plain ruby application you have implement several steps:

# Configure your Xyeger
Xyeger.configure {}

# Create instance of some logger
logger = Logger.new(STDOUT)

# Extend your logger with Xyeger::Logger
logger.extend(Xyeger::Logger)

# You are ready to go
logger.info('Some message')

License

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

xyeger's People

Contributors

ivanshamatov avatar vsevolod avatar

Stargazers

Simon avatar Rustam Ibragimov avatar Vladimir Dementyev avatar George avatar Max Surkov avatar  avatar Vova Smyshliaev avatar  avatar  avatar Lily avatar

Watchers

 avatar Lily avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.