Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Simplistic logging, my hand-knitted logging modul

20 views
Skip to first unread message

Michael Uplawski

unread,
Dec 31, 2023, 10:37:09 AM12/31/23
to
Good afternoon.

I want to replace the Logger from Ruby core by my own simplistic Module
“BasicLogging”, after years, when I had to admit that I am anyway never using
all the features of the Logger class: It is the same formater for everything
and I had never use for object- or class-specific configurations. This
facilitates the configuration of the logger from an application-wide
configuration. I can still “mute” individual objects/classes to reduce the
output.

The whole module is attached below this post.

Chances are, I oversee a bunch of problems with my code. Programming is
just a hobby. Are there obvious glitches, which I must address? In one of
my programs, my module appears to work just as I like it to.

Here a usage example for a class-level logger:
------------
Array.extend(BasicLogging)
Array.set_level(BasicLogging::INFO)
Array.info('TEST')
-----------
output:
Array [class] info 16:22:26:662619: TEST

Object-level:
------------
ar = Array.new
ar.extend(BasicLogging)
# --- no output, default level is UNKNOWN :
l = __LINE__
ar.debug(l.next.to_s << ': debug-test 0')
# output on level debug
ar.set_level(BasicLogging::DEBUG)
l = __LINE__
ar.debug(l.next.to_s << ': debug-test 1')
--------------
output:
Array debug 16:22:26:662894: 124: debug-test 1

The file basic_logging.rb contains more test-code at the bottom. Thank you
for any comments. Shoot at will.

---------------------- basic_logging.rb -------------------
#!/bin/env ruby
#encoding: UTF-8
=begin
/***************************************************************************
* ©2023-2023, Michael Uplawski <news:michael....@uplawski.eu> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the WTFPL 2.0 or later, see *
* <http://www.wtfpl.net/about/> *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* *
***************************************************************************/
=end

#
# Simplified logging.
# See example code at the bottom of this file.
# Execute this file to see the output.

module BasicLogging

DEBUG = 0
INFO = 1
WARN = 2
ERROR = 3
FATAL = 4
UNKNOWN = nil

# this is mainly for the translation of method calls into log levels
Levels = {:debug => DEBUG, :info => INFO, :warn => WARN, :error => ERROR,
:fatal => FATAL, :unknown => UNKNOWN}

@@log_level = UNKNOWN
@@target = STDOUT
@@muted = []

# do not log, if caller is obj (class or instance)
def self.mute(obj)
name = obj.class == Class ? obj.name.dup : obj.class.name
@@muted << name
end

def self.is_muted?(obj)
name = obj.class == Class ? obj.name.dup : obj.class.name
@@muted.include?(name)
end

# set the log level
def set_level(lv)
if lv.respond_to?(:to_str)
lv = Levels[lv.to_sym]
end
if(!lv || (lv.respond_to?(:to_int) && lv >= DEBUG && lv <= FATAL) )
@@log_level = lv
else
STDERR.puts __FILE__.dup << ": ERROR : invalid log level \"" << lv.to_s << "\""
STDERR.puts "Keepinng old log level " << Levels.keys.detect {| k| Levels[k] == @@log_level}.to_s
end
end

# set the log target
def set_target(tg)
if tg.respond_to?(:to_io)
@@target = tg
elsif(!File::exist?(tg) || ( File.file?(tg) && File.writable?(tg) ) )
@@target = File.open(tg, 'w+')
else
STDERR.puts __FILE__.dup << ': ERROR : target ' << tg << ' cannot be set'
STDERR.puts "Keeping old target " << @@target.inspect
return
end
end

# Output of log messages, depending on the log level
# and the name of the alias method which is actually called.
def log(message)
if !BasicLogging.is_muted?(self)
# how has this method been called?
mlevel = __callee__
if Levels.has_key?(mlevel) && Levels[mlevel] <= FATAL
# output only for levels equal or above the value that corresponds to
# the calling alias.
format_log( message, mlevel) if @@log_level && Levels[mlevel] >= @@log_level
else
STDERR.puts __FILE__.dup << ": ERROR : invalid log level \"" << mlevel.to_s << "\""
end
end
end

alias :debug :log
alias :info :log
alias :warn :log
alias :error :log
alias :fatal :log

private

# 1 format for all loggers.
def format_log(message, mlevel)
# indicate if a class or an instance of a class is calling.
name = self.class == Class ? self.name.dup << ' [class]' : self.class.name
@@target.puts '' << name << ' ' << mlevel.to_s << ' ' << Time.now.strftime("%H:%M:%S:%6N") << ': ' << message
end
end
#---------test: execute file----------
if $0 == __FILE__
Array.extend(BasicLogging)
Array.set_level(BasicLogging::INFO)
Array.info('TEST')
ar = Array.new
ar.extend(BasicLogging)
# --- no output :
l = __LINE__
ar.debug(l.next.to_s << ': debug-test 0')
# output
ar.set_level(BasicLogging::DEBUG)
l = __LINE__
ar.debug(l.next.to_s << ': debug-test 1')

obj = Object.new
obj.extend(BasicLogging)
obj.set_level(BasicLogging::DEBUG)
puts "--------debug-----------"
obj.debug('debug')
obj.info('info')
obj.warn('warn')
obj.error('error')
obj.fatal('fatal')
puts "--------info-----------"
obj.set_level("info")
obj.debug('debug')
obj.info('info')
obj.warn('warn')
obj.error('error')
obj.fatal('fatal')
puts "--------fatal-----------"
obj.set_level("fatal")
obj.debug('debug')
obj.info('info')
obj.warn('warn')
obj.error('error')
obj.fatal('fatal')
puts "--------UNKNOWN-----------"
obj.set_level(nil)
obj.debug('debug')
obj.info('info')
obj.warn('warn')
obj.error('error')
obj.fatal('fatal')
puts " ------ Output into file ----"
obj.set_target "/tmp/test_log.log"
puts " ------ INFO -----------"
obj.set_level BasicLogging::INFO
obj.info('info output')

obj.info('info output 2')
puts "---------- invalid -------"
obj.set_target "/dev/sr0"
obj.set_level "power"
end

# EOF

Michael Uplawski

unread,
Jan 2, 2024, 2:16:32 AMJan 2
to
Michael Uplawski wrote in comp.lang.ruby:

> Chances are, I oversee a bunch of problems with my code. Programming is
> just a hobby. Are there obvious glitches, which I must address? In one of
> my programs, my module appears to work just as I like it to.

The project in question is here:
<https://www.rubydoc.info/gems/cremefraiche/1.2>

I plan to use the same “BasicLogging" in my other scripts and programs.

Cheerio
0 new messages