--[[--------------------------------------------------------------------------- Logging helper. Writes to a log file and prints to the console. This module is a lua script (@{logger.lua}), you need to explicitly load it with `require('logger')` @module logger @usage require('logger') local log = logger("MYLOG.LOG") log:write("hello world!") log:close() ]] logger = {} logger_metatable = {} --[[--------------------------------------------------------------------------- Creates a new logger @tparam string filename the filename of the log file @tparam[opt] table listener an additional 'listener' to write data to, should implement a t:write(str) function @treturn logger the new instance @function logger ]] function logger_metatable.__call(self,filename,listener) local t = {} t.filename = filename t.listener = listener t.logfile = io.open(filename, "a") t.logfile:setvbuf("line") local calling_filename = debug.getinfo(2,"S").short_src local date = dryos.date t.logfile:write(string.format([[ =============================================================================== %s - %d-%d-%d %02d:%02d:%02d =============================================================================== ]], tostring(calling_filename), date.year, date.month, date.day, date.hour, date.min, date.sec)) local m = {} m.__index = logger setmetatable(t,m) return t end setmetatable(logger,logger_metatable) --[[--------------------------------------------------------------------------- Splits a string into a table consisting of the lines of the original string @tparam string str @function logger.tolines ]] function logger.tolines(str) local t = {} local p1 = 1 local p2 = 1 local len = #str while p2 <= len do local c = str:sub(p2,p2) if p2 == len then if p1 == p2 then table.insert(t,"") else table.insert(t, str:sub(p1,p2)) end --ends in newline? if c == "\r" or c == "\n" then table.insert(t,"") end break elseif c == "\r" or c == "\n" then if p1 == p2 then table.insert(t,"") else table.insert(t, str:sub(p1,p2-1)) end p2 = p2 + 1 if c == "\r" and str:sub(p2,p2) == "\n" then p2 = p2 + 1 end p1 = p2 else p2 = p2 + 1 end end return t end --[[--------------------------------------------------------------------------- @type logger ]] --[[--------------------------------------------------------------------------- Writes a string to the log @param str the string @function write ]] function logger:write(str) str = tostring(str) if self.listener ~= nil then self.listener:write(str) end io.write(str) self.logfile:write(str) end --[[--------------------------------------------------------------------------- Writes a printf style formatted string to the log @tparam string fmt format string @param ... format arguments @function writef ]] function logger:writef(fmt,...) self:write(fmt:format(...)) end --[[--------------------------------------------------------------------------- Converts any Lua type to a string representation and logs it. Recursively enumerates table structures @param o the object to serialize @function serialize ]] function logger:serialize(o,l) if type(o) == "string" then self:writef("%q",o) elseif type(o) == "table" or type(o) == "userdata" then if l == nil then l = 1 end --prevent infinite recursion if l < 10 then local s,e = pcall(function() pairs(o) end) if s == true then -- something iterable self:writef("%s:\n",type(o)) for k,v in pairs(o) do for i=1,l,1 do self:write(" ") end if type(k) == "string" then self:writef("%s = ",k) else self:writef("[%s] = ",tostring(k)) end self:serialize(v,l+1) if type(v) ~= "table" then self:write("\n") end end else -- something not iterable self:writef("%s",type(o)) end end else self:write(tostring(o)) end end --[[--------------------------------------------------------------------------- Close the log @function close ]] function logger:close() self.logfile:close() end return logger