Gem Version Build Status Code Climate Test Coverage

Logmsg

This is a simple log gem based on the standard Ruby Logger library that aims to be a simple alternative in order to manage multiple log output files that may or may not share common properties.

Changelog

Version Changes
1.0.7 Validated for Ruby 2.3.0; added default value for threshold in Logfile;

Installation

Add this line to your application's Gemfile:

gem 'logmsg'

And then execute:

$ bundle

Or install it yourself as:

$ gem install logmsg

Documentation

To read the code documentation please visit it here.

Usage

Two things are provided inside this gem, one is the library and the other one is a command line tool.

Command Line Tool

If you are a someone that just want to have a better tool to log messages for your scripts the logmsg gem provides a logmsg command line interface for you. You can check it out in the bin/ directory. This should already be in your $PATH variable, so the tool should be available once yiu install the gem.

Start by checking the help contant provided with the tool, it should be really straightforward:

$ logmsg -h

This tool will first try to load a configuration file in the same directory where you are running it from, if not found then it will look for one in your home directory and last but not least will then load the configuration provided by default with the gem. Here are the paths it will look in:

  1. ./.logmsg.yml
  2. ~/.logmsg.yml
  3. LOGMSG_INSTALL_DIR/logmsg/yaml/logmsg.yml

As an example, if you want to output an error message to your log files:

$ logmsg -s error "file cannot be read"

If you have a different configuration file then you can provide its path:

$ logmsg -c /path/to/config.yml -s error "file cannot be read"

And if you need to provide a different namespace (which also will be used as an identification for your message) then you can provide it like this:

$ logmsg -n myscript -c /path/to/config.yml -s error "file cannot be read"

The namespace is like a section within the config file. We will discuss it later when we go deep into the config file structure.

Library

Another way to use this gem is to actually require our library's classes into your own software. The only class you need to worry is the LogMsg, this class will look for a configuration file which will tell it what log files to use, what are the messages to output in them (based on their severities) and default formats to output the message.

You start by requiring the library in you code:

After that you can just require it in your code:

require 'logmsg'

And then instantiating a LogMsg object:

logmsg = Logmsg::LogMsg.new('myprograme')

This will instantiate and object and, as part of the intialization process, it will look for the following files for settings:

  1. ./.logmsg.yml
  2. ~/.logmsg.yml
  3. LOGMSG_INSTALL_DIR/logmsg/yaml/logmsg.yml

It will look for those files in that exact order and once it finds one of them it will parse it and stop, not loading the others. This is an important concept to understand as it there is no inheritance of settings from two different settings files.

You can also specify a different configuration file, if necessary by just providing its path for the constructor:

logmsg = Logmsg::LogMsg.new('myprogram', '/path/to/config.yml')

Note that, the first argument is the namespace while the second one is the path to the configuration file. The way that the namespace works is that it will be the name of the section within your seetings file where all your log files will belong to. So, during the parse process LogMsg will look for a top level section named as 'myprogram' (per the example above) and then set all the log files within it. Any other top level sections within that settings file will be ignored.

OK, if everything is correct with your YAML configuration file then LogMsg will have all your logfiles initialized and properly set up. Now you can just output your log messages like this:

logmsg.debug('A debug message')
logmsg.info('An informational message')
logmsg.warn('A warning message')
logmsg.error('An error message')
logmsg.fatal('A fatal message')
logmsg.unknown('A message with an unknown severity')

As you can see, we have six common severities you can use in order of importance to an issue. That is no coincidence, as we use the Logger default library in the background:

  • Debug
  • Info
  • Warn
  • Error
  • Fatal
  • Unknown

Usually a log file will be associated with severities in one out of two ways:

  • A severity threshold
  • A list of severities

In the first case, a threshold, we only output messages to a log file in case the message's severity is equal or higher to the threshold. For example, if the log file's threshold is set to error then only error, fatal and unknown messages will be printed into it, the other ones will be skipped.

Let's say you have a fancy way to manage your log messages and you want to sort them out differently. You want to put debug, warn and unknown messages in one file and the others in a different one. For that you will need to list the severities you need to link to those files specifically.

The way to do either of the above two options is by setting them up in your config file (check the next section for information on that). If you want to do it programatically, then you will need to use the LogFile class provided by this gem. The scope of this documentation is not to go further in these advanced topics but that class is well documented in our YARD documentation (link above).

The last thing you need to do is. Before you close your program you should also close your log files:

logmsg.close

And that's basically it! =)

Settings

The LogMsg's configuration file is written in YAML and it ships with a default configuration file located in lib/logmsg/yaml/logmsg.yml. Here is a portion of this containing the defaults:

default:
  globals: &globals
    datetime_format: '%Y-%m-%d %H:%M:%S'
    format: '%{progname} [%{datetime}] %{severity}: %{msg}'
    threshold: info

  stdout: &stdout
    <<: *globals
    format: '%{severity}: %{msg}'
    path: stdout
    severities:
      - debug
      - info
      - warn

  stderr: &stderr
    <<: *globals
    format: '%{severity}: %{msg}'
    path: stderr
    severities:
      - error
      - fatal
      - unknown

This section above named as the default namespace is actually a skeleton to build other sections from. Let's go over the structure of the file. The level one options are the namespaces and the level two are the log files. In the code above we have only one namespace called default and three log files called globals, stdout and stderr.

As we said previously this example above is just a skeleton and not an actual configuration for a program, the globals is just a special section there we global default options to be further inherited. A real life example that uses the above skeleton would be like this:

logmsg:
  stdout: *stdout
  stderr: *stderr
  all:
    <<: *globals
    path: ./logmsg_all.log

Here we have a logmsg namespace with three log files configured: stdout, stderr and all. The forst two are inherited directly from the defaults while the all logfile only gets its settings from the globals section and adds a path option with the path for the log file in the filesystem.

As you might be wondering, stdout and stderr are special cases for the standard output and error streams and are treated as such during the parse process. However, you can use anything you want for the namespace and log file names.

All log files may contain the following options:

  • datetime_format: the format used to output the date and time of the message following the directived from strftime;
  • format: the format of the message to be output, the variables are: progname, datetime, severity and message. Note that progname will be expanded to the log file name;
  • threshold: the severity threshold used for this log file;
  • severities: a list of severities linked to this file, if used then the threshold option will be ignored;
  • path: the filesystem path of the file (stderr and stdout don't need this)

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/egonbraun/logmsg. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

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