0Pricing
Lua Academy · Aula

xpcall e manipuladores de mensagens

Use xpcall com um manipulador personalizado para obter rastreamentos detalhados de erros.

xpcall e manipuladores de mensagens é uma aula grátis de Lua Academy no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Lua Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Lua Academy inclui 4 aulas no total.

Sintaxe de xpcall

xpcall(f, handler, ...) chama f com os argumentos ... em modo protegido e, em caso de erro, chama handler(errorObject). O valor retornado pelo manipulador torna-se o segundo valor retornado por xpcall. Diferentemente de pcall, xpcall executa o manipulador enquanto a pilha está intacta.

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 bad

debug.traceback como manipulador

O manipulador de xpcall mais comum é debug.traceback. Passe-o diretamente como manipulador — ele formata o erro com um rastreamento completo da pilha de chamadas, algo indispensável para depurar erros em produção.

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

Manipulador personalizado com contexto

Um manipulador personalizado pode adicionar contexto: registrar o horário, gravar em um arquivo, notificar sistemas de monitoramento e então retornar o erro formatado. Esse é o padrão comum para o tratamento de erros em produção em aplicações 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)

O manipulador não pode gerar erros

Se o próprio manipulador de mensagens gerar um erro, Lua retornará um indicador de erro sem chamar o manipulador novamente. Escreva sempre manipuladores à prova de falhas — sem E/S que possa falhar e sem indexação de valores 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 para o laço principal

Em programas de longa duração (servidores, laços de jogos), envolva a função principal em xpcall para capturar e registrar quaisquer erros não tratados sem causar uma falha. O laço principal poderá então decidir se deve reiniciar ou sair.

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

Relatórios de erros estruturados

Combine xpcall com objetos de erro estruturados e um manipulador avançado para produzir relatórios de erro detalhados e acionáveis para depuração ou painéis de monitoramento.

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)
end

xpcall para corrotinas

Dentro de uma corrotina, pcall funciona normalmente. Para obter rastreamentos de erros dentro de corrotinas, envolva o corpo da corrotina em xpcall. O manipulador é executado dentro do contexto da pilha da corrotina.

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)

Enriquecimento de objetos de erro

O manipulador pode transformar um erro simples em string em um objeto avançado, ou enriquecer ainda mais um objeto avançado. Isso permite que o código de baixo nível gere erros simples enquanto o manipulador adiciona contexto (ID da solicitação, sessão do usuário e informações do ambiente).

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

Comparação entre pcall e xpcall

Use pcall quando: você precisar apenas do valor do erro, o erro for esperado e tratado no próprio local, ou a simplicidade for importante. Use xpcall quando: precisar de rastreamentos da pilha, estiver em um limite de nível superior ou quiser adicionar contexto a todos os erros.

-- 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

Valor retornado pelo manipulador

Qualquer valor retornado pelo manipulador torna-se o segundo valor de xpcall. Se o manipulador retornar nil, o segundo retorno de xpcall será nil. Um manipulador que retorna o objeto de erro original junto com informações adicionais é a abordagem mais flexível.

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

Verificação rápida

Qual é a principal vantagem de xpcall em relação a pcall?

Recapitulação: xpcall

Resumo:

  • xpcall(f, handler, ...) — o manipulador é executado enquanto a pilha está intacta
  • Use debug.traceback como manipulador para obter rastreamentos completos
  • O manipulador não pode gerar erros — mantenha-o simples
  • Enriqueça os erros com contexto no manipulador
  • Envolva os laços principais e os manipuladores de servidor em xpcall
  • O retorno do manipulador torna-se o segundo valor retornado por xpcall

Perguntas Frequentes

A aula “xpcall e manipuladores de mensagens” é grátis?

Sim — o texto completo de “xpcall e manipuladores de mensagens” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Lua Academy, atualize para CoddyKit PRO. O curso de Lua Academy inclui 4 aulas no total.

O que vou aprender em “xpcall e manipuladores de mensagens”?

Use xpcall com um manipulador personalizado para obter rastreamentos detalhados de erros. Você pratica Lua Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Lua Academy?

Nenhuma experiência prévia é necessária. Lua Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.

Quanto tempo leva a aula “xpcall e manipuladores de mensagens”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Lua Academy?

Sim. Cada aula de Lua Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. A função error()
  2. Chamadas protegidas com pcall
  3. xpcall e manipuladores de mensagens
  4. Objetos de erro estruturados
← Voltar para Lua Academy