logline
logline
function logline( level [, ...] ) --> line, err
Description
This function adds common useful information to the data that you want to output.
When called with a single argument, it will set the global verbosity level. When called with additional arguments it will generate the log string. However the string will be generated only if the first argument, the line log level, is smaller than the global verbosity level. In this way you can dinamically enable or disable log messages in critical part of the code.
The verbosity level can be given in two way: as an integer or as a string representing the verbosity class.
The allowed verbosity classes are:
-
ERROR <= 25
-
DEBUG <= 50
-
INFO <= 75
-
VERBOSE <= 99
Each class will be considered to cantain any integer level just below it, e.g. 26, 30 and 50 all belongs to the DEBUG class. When specifying the verbosity level as a class name, the higher belonging integer will be used.
Parameters
- level
-
Integer verbosity level or string verbosity class name. When called without any other argument this is the global verbosity level to be set. If other arguments are present, it is the verbosity level of the log line. Note that the output will be generated only if the line have a level smaller than the global verbosity.
- …
-
Additional information that will be appended to the output.
Return Values
- line
-
It return nil if called with one arguments o if the global verbosity level is not high enough. Otherwise it will return a string containing:
-
Date
-
Time
-
os.clock() result
-
Incremental number
-
Verbosity level of the log line
-
Source position of function call
-
Additional info in the arguments
-
Note 1: The verbosity level will be reported both as number that as the symbolic class name.
Note 2: if the caller is a tail call or a function with a name that starts or ends with log, the position used will be the one of the caller of the caller (and so on).
- err
-
A message if an error occurse, otherwise nil.
Code
local skip_lower_level = 25 local log_count = 0 local level_list = { { 25, "ERROR" }, { 50, "DEBUG" }, { 75, "INFO"} , { 99, "VERBOSE" } } local level_map local function update_level_map() level_map = {} for k,v in ipairs( level_list ) do level_map[ v[ 2 ] ] = v end end update_level_map() --ZFUNC-logline-v0 local function logline( level, ... ) --> line -- Classify log level local level_class if "string" == type( level ) then level_class = level_map[ level:upper() ] if level_class then level = level_class[ 1 ] end elseif "number" == type( level ) then local level_num = #level_list for k = 1, level_num do if k == level_num or level <= level_list[k][1] then level_class = level_list[k] break end end else return nil, "Invalid type for argument #1" end if not level_class then return nil, "Invalid symbolic log level" end local n = select( "#", ... ) -- Single argument mode: set log level if n == 0 then skip_lower_level = level return end -- Multiple argument mode: generate log line -- Skip if the current log level is too small if skip_lower_level < level then return end log_count = log_count + 1 -- Get info about the function in the correct stack position local d = debug.getinfo( 2 ) local td = d local stackup = 2 while true do local n = td.name if not n then break end n = n:lower() if not n:match( "log$" ) and not n:match( "^log" ) and n ~= "" then break end stackup = stackup + 1 td = debug.getinfo(stackup) end if td then d = td end -- Log line common part local line = os.date( "%Y/%m/%d %H:%M:%S" ).." "..os.clock().." " ..log_count.." "..level_class[ 1 ].."."..level_class[ 2 ].." " ..d.short_src:match( "([^/\\]*)$" )..":"..d.currentline.." | " -- Append additional log info from arguments for m = 1,n do line = line..tostring( select( m, ... ) ).." | " end return line end return logline
Examples
local t = require "taptest" local logline = require "logline" -- The checker: when verifing strings use patern matchin -- Otherwise fallback to == local function pcheck( got, exp ) if type( exp ) ~= type( got ) then return false end if "string" ~= type( got ) then return ( got == exp ) end return ( nil ~= got:match( exp ) ) end -- Default log level is 25 a.k.a. ERROR -- Only logline with smaller level will generate a message t( logline( 10, "test" ), "|", pcheck ) t( logline( 25, "test" ), "|", pcheck ) t( logline( 26, "test" ), nil, pcheck ) t( logline( 99, "test" ), nil, pcheck ) -- Change log level logline( 60 ) t( logline( 10, "test" ), "|", pcheck ) t( logline( 60, "test" ), "|", pcheck ) t( logline( 61, "test" ), nil, pcheck ) t( logline( 99, "test" ), nil, pcheck ) -- Symbolic log level name logline( "error" ) t( logline( 25, "test" ), "|", pcheck ) t( logline( 26, "test" ), nil, pcheck ) t( logline( "error", "test" ), "|", pcheck ) t( logline( "debug", "test" ), nil, pcheck ) t( logline( "info", "test" ), nil, pcheck ) t( logline( "verbose", "test" ), nil, pcheck ) logline( "debug" ) t( logline( 50, "test" ), "|", pcheck ) t( logline( 51, "test" ), nil, pcheck ) t( logline( "error", "test" ), "|", pcheck ) t( logline( "debug", "test" ), "|", pcheck ) t( logline( "info", "test" ), nil, pcheck ) t( logline( "verbose", "test" ), nil, pcheck ) logline( "info" ) t( logline( 75, "test" ), "|", pcheck ) t( logline( 76, "test" ), nil, pcheck ) t( logline( "error", "test" ), "|", pcheck ) t( logline( "debug", "test" ), "|", pcheck ) t( logline( "info", "test" ), "|", pcheck ) t( logline( "verbose", "test" ), nil, pcheck ) logline( "verbose" ) t( logline( 99, "test" ), "|", pcheck ) t( logline( 100, "test" ), nil, pcheck ) t( logline( "error", "test" ), "|", pcheck ) t( logline( "debug", "test" ), "|", pcheck ) t( logline( "info", "test" ), "|", pcheck ) t( logline( "verbose", "test" ), "|", pcheck ) -- Message contains source position t( logline( 99, "test" ), "logline%.ex1%.lua:62", pcheck ) -- he line 62 is this one -- In some case the caller source position is used: -- - Tail calls -- - Functions with names that start or end with "log" function wraplog( ... ) return logline( 99, ... ) end function wraplogfakebarrier( ... ) return logline( 99, ... ) end function wraplogbarrier( ... ) local res = logline( 99, ... ) -- line 72 return res end t( wraplog( "test" ), "logline%.ex1%.lua:75", pcheck ) -- line 75 t( wraplogfakebarrier( "test" ), "logline%.ex1%.lua:76", pcheck ) -- line 76 t( wraplogbarrier( "test" ), "logline%.ex1%.lua:71", pcheck ) -- The argument are appended to the result string t( logline( 99, "a", 1), "| a | 1 | $", pcheck ) -- OTHER STUFF IN THE LOG: --TODO : TEST ? -- - date -- - time -- - os.clock() result -- - incremental number -- - log level of the line print( "# "..logline( 80, "ok" ) ) t( )