Sinlog
A very, very simple Ruby singleton logger with colored log levels.
Singleton means that the entire program will share the same instance (logger).
| Language/語言 | ID |
|---|---|
| English | en-Latn-US |
| 简体中文 | zh-Hans-CN |
| 繁體中文 | zh-Hant-TW |
- API DOC
- Quick Start
- Installation
- API Style
- Procedural Style
- OOP style
- FP Style
- API Style
- Monkey Patching
- Comparison Table
- Method List
- Mixin & Refin
- ShortMixin & ShortRefin
- Examples
- Refinement
- Mixin
- Learn Sinlog API by Example
- Advanced
- Real World Example
- Log Levels
- Environment Variables
- Log Output Device/Path
- Other Logger Methods
- Notes
- Side Note
- Changelog
- v0.0.7 (2025-12-03)
- License
API DOC
- Github Pages: https://2moe.github.io/sinlog-gem
Quick Start
Installation
# POSIX-sh
#
gem install sinlogAPI Style
In this library, a set of similar functionalities can be accessed through multiple different calling approaches.
Which style you choose mainly depends on your personal preference.
Procedural Style
require 'sinlog'
# update the Sinlog logger level
Sinlog.logger(level: "debug")
# OR: Sinlog::Logger.logger("debug")
Sinlog.dbg 'debug'
Sinlog.info 'information'
Sinlog.warn 'warning'
Sinlog.err 'error'
Sinlog.fatal 'fatal'
Sinlog.unk 'unknown'OR:
# POSIX-sh
# Set an environment variable for a custom log level
export YOUR_CUSTOM_LOG=debug# RUBY
require 'sinlog'
log = Sinlog.logger(env_name: "YOUR_CUSTOM_LOG")
log.debug "This is a debug message"
log.info 'information'
log.warn 'warning'
log.error 'error'
log.fatal 'fatal'
log.unknown 'unknown'OOP style
require 'sinlog'
using Sinlog::Refin
# OR: include Sinlog::Mixin
'debug'.log_dbg
'information'.log_info
'warning'.log_warn
'error'.log_err
'fatal'.log_fatal
'unknown'.log_unkFP Style
require 'sinlog'
# update the Sinlog logger level
{level: "dbg"}.then { Sinlog.logger **_1 }
Log = Sinlog::Proc
'debug'.tap &Log.dbg
# OR: Log.dbg['debug']
# OR: Log.dbg.call 'debug'
# OR: Log.dbg.('debug')
class Object; def ▷(f) = f.call(self) end
true.▷(Log.dbg >> Log.info >> Log.warn >> Log.err >> Log.fatal >> Log.unk)Monkey Patching
Comparison Table
| Module | Type | Activation | Method Naming |
|---|---|---|---|
| Mixin | Mixin | include | log_dbg, log_info, log_warn, log_err, log_fatal, log_unk |
| Refin | Refinement | using | log_dbg, log_info, log_warn, log_err, log_fatal, log_unk |
| ShortMixin | Mixin | include | dbg, info, warn, err, fatal, unk |
| ShortRefin | Refinement | using | dbg, info, warn, err, fatal, unk |
Method List
Mixin & Refin
-
log_dbg– DEBUG -
log_info– INFO -
log_warn– WARN -
log_err– ERROR -
log_fatal– FATAL -
log_unk– UNKNOWN
ShortMixin & ShortRefin
-
ShortRefin is similar to Refin
- Apart from the difference in method naming, their internal implementations are identical.
- Methods in Refin have the
log_prefix - ShortRefin does not
- Methods in Refin have the
- Apart from the difference in method naming, their internal implementations are identical.
-
ShortMixin is similar to Mixin
- The only difference is in naming
- Methods in Mixin have the
log_prefix - ShortMixin does not
- Methods in Mixin have the
- The only difference is in naming
-
dbg– DEBUG -
info– INFO -
warn– WARN -
err– ERROR -
fatal– FATAL -
unk– UNKNOWN
⚠️ Since ShortMixin and ShortRefin define a
warnmethod, they will override the defaultwarn. For Ruby code that useswarn "msg"(which outputs to stderr rather than using a log format), you may need to manually change it toKernel.warn "msg".If this bothers you, then use
using Sinlog::Refininstead ofusing Sinlog::ShortRefin.
Examples
Refinement
require 'sinlog'
using Sinlog::Refin
{ dir: "/path/to/xx" }.log_inforequire 'sinlog'
using Sinlog::ShortRefin
{ dir: "/path/to/xx" }.infoMixin
require 'sinlog'
include Sinlog::Mixin
"Hello".log_inforequire 'sinlog'
include Sinlog::ShortMixin
"Hello".infoLearn Sinlog API by Example
require 'sinlog'
module A
module_function
using Sinlog::ShortRefin
def log
['Hey hey hey, could you see this debug message?',
'You might find it a bit verbose, hahaha!'].dbg
'Just some info.'.info
'FBI, open the door!'.warn
{ error: "IO", type: "InvalidData" }.err
'Error occurred, continuing may break things.'.err
'Bzzzz... it is bro...ken...nnn~'.fatal
end
end
A.log
# update the log level to error
Sinlog.logger(level: 'err')
Kernel.warn 'Logger.level => error'
A.logAdvanced
After trying it out ourselves, we have a basic understanding of sinlog.
In most cases, knowing its basic usage is sufficient.
If you're interested, let's continue exploring together.
Real World Example
In the real world, our program might look like this:
require 'sinlog'
class EpubProcessor
def initialize(epub_file, logger = nil)
@epub = epub_file
logger ||= Sinlog::logger(env_name: "XX_LOG")
@logger = logger
@logger.debug "EpubProcessor class initialization completed."
end
endWe might define a class's @logger instance variable and allow for a custom logger.
Simply put, we might configure the logger more finely.
In the following content, we will explore how to perform "more fine-grained configuration."
Log Levels
Log levels from low to high are:
- debug = 0
- info = 1
- warn = 2
- error = 3
- fatal = 4
- unknown = 5
Interestingly, the log levels in Ruby’s standard library
Loggerare the opposite of Rust’s log::Level.
p Sinlog::LV
# => {debug: 0, info: 1, warn: 2, error: 3, fatal: 4, unknown: 5}
# Change the log level to warn
log = Sinlog.logger(level: 'warn')
# OR:
# log = Sinlog.logger(level: Sinlog::LV[:warn])
# OR:
# log = Sinlog.logger.tap { it.level = 2 }
log.error "This message will be displayed! Lower level WARN (2) will display higher level ERROR (3) logs."
log.info "This message will not be displayed! Higher level WARN (2) will not display lower level INFO (1) logs."- The lower the log level, the more detailed the content displayed.
- Lower levels will display higher level logs.
- Higher levels will not display lower level logs.
Environment Variables
In the real world, for client applications, the end users are typically regular users.
To allow them to configure log.level directly, we can use environment variables.
Using environment variables is simple and efficient.
By default, Sinlog::Logger will attempt to read the value of the environment variable RUBY_LOG.
- If the environment variable does not exist, it uses
debug(0). - If the environment variable exists but is empty, it uses
error(3). - If the environment variable's value is invalid, it uses
error(3).
We can set the environment variable using POSIX-sh, and then the logger will automatically set the log level to warn (the value of RUBY_LOG) during initialization.
# Possible values: debug, info, warn, error, fatal
export RUBY_LOG=warnIf you don't want to use the default RUBY_LOG environment variable and prefer to use the value of XX_CLI_LOG, you can do it like this:
POSIX-sh:
export XX_CLI_LOG=infoRuby:
logger = Sinlog.logger(env_name:"XX_CLI_LOG")
logger.debug "This message will not be displayed because the current log level is INFO(1)."
logger.info "Hello!"Log Output Device/Path
By default, Sinlog outputs to STDERR.
The data type of
Sinlog.loggeris::Logger(from Ruby's standard library).
If you need to customize the log output path, you can call the ::Logger's reopen method.
# Logs will be output to the file a.log
log = Sinlog.logger.tap { it.reopen("a.log") }
log.error "What happened! QuQ"OR:
log = Sinlog.logger
log.reopen("a.log")
log.error "What happened! QuQ"Other Logger Methods
In addition to .reopen and .level, we can also call other methods from Ruby's standard library logger on Sinlog.logger.
For details, see https://docs.ruby-lang.org/en/3.4/Logger.html
Notes
Sinlog::Logger uses the Singleton pattern, meaning the entire program will share the same instance (logger).
Modifying Sinlog.logger (a.k.a. Sinlog::Logger.instance.logger) in class A of the same program will affect Sinlog::Logger in class B.
Side Note
This is the first Ruby gem I have released. The API might not fully adhere to idiomatic Ruby usage, so I appreciate your understanding.
Changelog
v0.0.7 (2025-12-03)
- add
Sinlog::Procmodule - add
lib/sinlog/08_module_short_ext.rb:Sinlog.dbgSinlog.infoSinlog.warnSinlog.errSinlog.fatalSinlog.unk
- update
Sinlog::Logger.logger- Previous:
def self.logger - Current:
def self.logger(level = nil, env_name = nil)
- Previous:
Breaking changes:
-
Sinlog.to_log_level=>Sinlog.as_log_level - rename
lib/sinlog/*.rb- consts => 01_consts
- logger => 02_logger
- module_fn => 03_module_fn
- log_ext => 04_log_ext
- short_ext => 05_short_ext
- loggable => 06_loggable
