Модуль:DebugLog (Bk;rl,&DebugLog)
Этот модуль оценён как альфа-версия. Он готов для тестирований и может быть использован на небольшом количестве страниц для обнаружения проблем. Предложения по изменениям и дополнениям приветствуются. |
Модуль предназначен для формирования отладочного лога других модулей. Может быть использован при разработке или на страницах с тестами других модулей.
Методы
[править код]- Основные:
DebugLog:new()
— конструктор.DebugLog:write(message, caller, state)
— запись в лог сообщенияmessage
.caller
— имя функции,state
— статус (error
,warning
,info
). Типmessage
может быть любым.DebugLog:getAll()
— вывод лога.
- Прочие:
DebugLog:getIssues()
— вывод только ошибок и предупрежденийDebugLog:tail(num)
— вывод последних num записейDebugLog:getFormatted(first, last, nowrap)
— вывод записей с first по lastDebugLog:getSummary()
— вывод строки с числом ошибок и предупрежденийDebugLog:getEntry(num)
— получение записи num в табличном видеDebugLog:formatEntry(num)
— форматирование записи num в строку
Особенности
[править код]Экземпляр таблицы с логом обычно должен быть продекларирован и инициализирован с помощью конструктора глобально, чтобы быть доступным в любом контексте. В любом случае он должен быть доступен в инициализированном виде в тех контекстах, где вызываются его методы. За включение режима логирования отвечает DebugLog.enabled
, который по умолчанию false
. Обычно имеет смысл установить его в true
в отдельном методе, как в примере ниже. Этот отдельный метод вызывать из предпросмотра или на отдельной странице тестов.
При обычном вызове модуля DebugLog.enabled = false
, это означает, что лог не пишется и не расходует ресурсы.
Использование
[править код]В модуле:
-- подключение
local DebugLog = require( 'Module:DebugLog' )
local debLog = DebugLog:new() -- инициализация экземпляра debLog на основе прототипа DebugLog
local function foo()
-- пример записи сообщения в лог в произвольном месте
debLog:write('my message', 'foo', 'warning')
...
function p.loggedCall(frame)
debLog.enabled = true -- включение для логируемого вызова
local args = getArgs(frame) -- получение таблицы параметров фрейма, см. Module:Arguments
local success, result = pcall(p[ args['function-name'] ], frame) -- вызов основной функции
return debLog:getAll() .. mw.text.nowiki(tostring(result)) -- вывод лога и результата работы
end
На странице тестов или аналогичной:
{{#invoke:MyModule|loggedCall|function-name=MyFunc}}
local mwLang = mw.getContentLanguage()
local function pushRight( tab, val )
local last = tab.last + 1
tab.last = last
tab[last] = val
end
local function wrapInPreTag( str, nowrap )
if not nowrap then
return table.concat{'<pre>', result, '</pre>'}
else return str end
end
local DebugLog = {}
DebugLog.stateStrings = {
['ERROR'] = 'ERROR', ['ERR']='ERROR', ['E'] = 'ERROR',
['WARNING'] = 'WARN', ['WARN']='WARN', ['W'] = 'WARN',
}
DebugLog.errWrapL = '<span style="color:red; font-weight:bold;">'
DebugLog.errWrapR = '</span>'
DebugLog.warnWrapL = '<span style="color:orange;">'
DebugLog.warnWrapR = '</span>'
-- Constructor
function DebugLog:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
o.first = 1
o.last = 0
o.warnings = 0
o.errors = 0
o.enabled = false
return o
end
-- Appends an entry to log
-- message - string with a message
-- caller - string with a name of a caller function
-- state - status of an entry: info/warning/error
function DebugLog:write(message, caller, state)
if not self.enabled then return end
if type(message) == 'nil' then
message = 'nil'
elseif type(message) == 'string' then
do end
elseif type(message) ~= 'table' then
message = tostring(message)
else
message = mw.dumpObject(message)
end
caller = tostring(caller or '')
state = tostring(state or '')
state = mwLang:uc(tostring(state or ''))
state = self.stateStrings[state] or state
if state == 'ERROR' then
self.errors = self.errors + 1
elseif state == 'WARN' then
self.warnings = self.warnings + 1
end
local entry = {
['message'] = message,
['caller'] = caller,
['state'] = state,
}
pushRight(self, entry)
end
-- returns table with an entry
function DebugLog:getEntry(num)
num = num or self.last
if type(num) ~= 'number' then num = self.last end
if num > self.last then num = self.last end
if num < self.first then num = self.first end
return self[num]
end
-- returns formatted string for entry 'num'
function DebugLog:formatEntry(num)
local entry = self:getEntry(num)
local message = self[num].message
local state = self[num].state
if state == 'ERROR' then
state = table.concat{'[', self.errWrapL , state, self.errWrapR , ']'}
elseif state == 'WARN' then
state = table.concat{'[', self.warnWrapL , state, self.warnWrapR, ']'}
else state = '[INFO]'
end
local caller = self[num].caller
if caller ~= '' then
caller = table.concat{' <i>', caller, '()</i>: '}
end
local message = self[num].message
return table.concat{state, caller, message}
end
-- returns formatted string with number of warnings and errors
function DebugLog:getSummary()
local errorsFmtd, warningsFmtd
if self.errors > 0 then
local errStr = string.format('%s errors', self.errors)
errorsFmtd = table.concat{self.errWrapL , errStr, self.errWrapR}
else
errorsFmtd = 'no errors'
end
if self.warnings > 0 then
local warnStr = string.format('%s warnings', self.warnings)
warningsFmtd = table.concat{self.warnWrapL , warnStr, self.warnWrapR}
else
warningsFmtd = 'no warnings'
end
return table.concat{'Found ' , errorsFmtd, ' and ', warningsFmtd}
end
-- returns formatted string with entries from 'first' to 'last'
-- 'nowrap' prevents wrapping in <pre></pre>
function DebugLog:getFormatted(first, last, nowrap)
first = first or self.first
if type(first) ~= 'number' then first = self.first end
if first < self.first then first = self.first end
last = last or self.last
if type(last) ~= 'number' then last = self.last end
if last > self.last then last = self.last end
local formattedEntries = {}
for i = first, last do
formattedEntries[i] = self:formatEntry(i)
end
local result = table.concat(formattedEntries, '<br>', first, last)
return wrapInPreTag(result, nowrap)
end
-- returns formatted string with 'num' of last entries
function DebugLog:tail(num)
num = num or 10
if type(num) ~= 'number' then num = 10 end
return wrapInPreTag(self:getFormatted(self.last - num, self.last))
end
-- returns formatted string, containing log entries with warnings and errors
function DebugLog:getIssues()
local result = {first = 1, last = 0, }
for i = self.first, self.last do
if self[i]['state'] == 'ERROR' or self[i]['state'] == 'WARN' then
pushRight(result, self:formatEntry(i))
end
end
return wrapInPreTag(table.concat(result, '<br>'))
end
-- returns formatted string with all entries and summary
function DebugLog:getAll()
local fullLog = self:getFormatted( nil, nil, true)
local summary = self:getSummary()
return table.concat{'<pre>', fullLog, '<br>', summary, '</pre>'}
end
local p = DebugLog
return p