xpcall и обработчики сообщений
Используйте xpcall с пользовательским обработчиком для получения подробных трассировок ошибок.
«xpcall и обработчики сообщений» — бесплатный урок Lua Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Lua Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Lua Academy содержит 4 уроков всего.
Синтаксис xpcall
xpcall(f, handler, ...) вызывает f с аргументами ... в защищённом режиме, а при ошибке вызывает handler(errorObject). Возвращаемое обработчиком значение становится вторым возвращаемым значением xpcall. В отличие от pcall, xpcall запускает обработчик, пока стек не изменён.
local function handler(err)
return "HANDLED: " .. tostring(err)
end
local ok, msg = xpcall(
function() error("something bad") end,
handler
)
print(ok) -- false
print(msg) -- HANDLED: ...: something baddebug.traceback в качестве обработчика
Самый распространённый обработчик xpcall — debug.traceback. Передайте его непосредственно как обработчик: он форматирует ошибку с полной трассировкой стека вызовов, что незаменимо при отладке ошибок в рабочей среде.
local function level3() error("deep error") end
local function level2() level3() end
local function level1() level2() end
local ok, err = xpcall(level1, debug.traceback)
if not ok then
-- err contains the full stack trace
print(err)
endПользовательский обработчик с контекстом
Пользовательский обработчик может добавить контекст: временную метку, запись в файл, уведомление систем мониторинга, а затем вернуть отформатированную ошибку. Это стандартный шаблон обработки ошибок в рабочих приложениях на Lua.
local function errorHandler(err)
local trace = debug.traceback(err, 2)
local ts = os.date("%H:%M:%S")
local report = string.format("[%s] ERROR\n%s", ts, trace)
-- Could log to file here
io.stderr:write(report .. "\n")
return report
end
local ok, msg = xpcall(
function()
local t = nil
return t.field -- error!
end,
errorHandler
)
print("ok:", ok)Обработчик не может завершиться ошибкой
Если в самом обработчике сообщения возникает ошибка, Lua возвращает индикатор ошибки, не вызывая обработчик повторно. Всегда пишите надёжные обработчики: не используйте операции IO, которые могут завершиться сбоем, и не обращайтесь к индексам nil.
local function safeHandler(err)
-- Keep handler simple and safe
local ok, trace = pcall(debug.traceback, err, 2)
if ok then return trace
else return tostring(err) .. " (traceback failed)"
end
end
local ok, msg = xpcall(
function() error({complex="error table"}) end,
safeHandler
)
print(ok, type(msg))xpcall для главного цикла
В долгоживущих программах (серверах, игровых циклах) оберните главную функцию в xpcall, чтобы перехватывать и записывать все необработанные ошибки, не допуская аварийного завершения. Затем главный цикл может решить, перезапустить программу или завершить её.
local function mainApp()
-- simulate work
for i = 1, 3 do
print("Tick", i)
if i == 2 then error("transient error") end
end
end
local function handler(e)
return debug.traceback("App error: "..tostring(e), 2)
end
local ok, err = xpcall(mainApp, handler)
if not ok then
print("Application crashed:\n" .. err)
endСтруктурированное представление ошибок
Объедините xpcall со структурированными объектами ошибок и информативным обработчиком, чтобы создавать подробные отчёты об ошибках, полезные для отладки или мониторинга.
local function handler(err)
local info = {
error = tostring(err),
time = os.date("!%Y-%m-%dT%H:%M:%SZ"),
trace = debug.traceback(nil, 2),
}
return info
end
local ok, report = xpcall(
function() error({code=500, msg="internal error"}) end,
handler
)
if not ok then
print("Time:", report.time)
print("Error:", report.error)
-- print("Trace:", report.trace)
endxpcall для сопрограмм
Внутри сопрограммы pcall работает обычно. Чтобы получать трассировки ошибок внутри сопрограмм, оберните тело сопрограммы в xpcall. Обработчик выполняется в контексте стека сопрограммы.
local function co_body()
error("error inside coroutine")
end
local co = coroutine.create(function()
local ok, err = xpcall(co_body, debug.traceback)
if not ok then
print("Caught in coroutine:", err:match("([^\n]+)"))
end
end)
coroutine.resume(co)Обогащение объекта ошибки
Обработчик может преобразовать обычную строковую ошибку в информативный объект или дополнительно обогатить уже информативный объект. Это позволяет коду нижнего уровня возбуждать простые ошибки, а обработчику добавлять контекст (идентификатор запроса, сеанс пользователя, сведения об окружении).
local requestID = "req-123"
local function handler(err)
if type(err) == "string" then
return {message=err, requestID=requestID, level="error"}
end
err.requestID = requestID
return err
end
local ok, result = xpcall(
function() error("database timeout") end,
handler
)
if not ok then
print(result.message, result.requestID)
-- database timeout req-123
endСравнение pcall и xpcall
Используйте pcall, когда Вам достаточно значения ошибки, ошибка ожидаема и обрабатывается на месте или важна простота. Используйте xpcall, когда нужны трассировки стека, Вы находитесь на границе верхнего уровня или хотите добавлять контекст ко всем ошибкам.
-- pcall: simple, no overhead
local ok, err = pcall(function()
return 1/0 -- no error in Lua! returns inf
end)
print(ok, err) -- true inf
-- xpcall: adds traceback
local ok2, err2 = xpcall(
function() error("real error") end,
debug.traceback
)
print(ok2) -- false
print(err2:sub(1,40)) -- first line of tracebackВозвращаемое значение обработчика
Всё, что возвращает обработчик, становится вторым значением, возвращаемым xpcall. Если обработчик возвращает nil, вторым возвращаемым значением xpcall будет nil. Наиболее гибкий подход — возвращать исходный объект ошибки вместе с дополнительными сведениями.
local function enrichedHandler(err)
return {
original = err,
traceback = debug.traceback(nil, 2),
timestamp = os.time(),
}
end
local ok, report = xpcall(
function() error("oops") end,
enrichedHandler
)
if not ok then
print(type(report)) -- table
print(report.original) -- ...: oops
print(report.timestamp > 0) -- true
endБыстрая проверка
В чём главное преимущество xpcall перед pcall?
Итоги: xpcall
Краткое содержание:
xpcall(f, handler, ...)— обработчик выполняется, пока стек не изменён- Используйте
debug.tracebackкак обработчик для получения полной трассировки - Обработчик не должен завершаться ошибкой — сохраняйте его простым
- Добавляйте контекст к ошибкам в обработчике
- Оборачивайте главные циклы и обработчики сервера в xpcall
- Возвращаемое обработчиком значение становится вторым возвращаемым значением xpcall
Часто задаваемые вопросы
Урок «xpcall и обработчики сообщений» бесплатный?
Да — полный текст урока «xpcall и обработчики сообщений» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Lua Academy, подпишись на CoddyKit PRO. Курс Lua Academy содержит 4 уроков всего.
Чему я научусь в уроке «xpcall и обработчики сообщений»?
Используйте xpcall с пользовательским обработчиком для получения подробных трассировок ошибок. Ты практикуешь Lua Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Lua Academy?
Предыдущий опыт не требуется. Lua Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «xpcall и обработчики сообщений»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Lua Academy?
Да. Каждый урок Lua Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Функция error()
- Защищённые вызовы с pcall
- xpcall и обработчики сообщений
- Структурированные объекты ошибок