0Pricing
Lua Academy · Lección

xpcall y gestores de mensajes

Utilice xpcall con un gestor personalizado para obtener trazas detalladas de errores.

xpcall y gestores de mensajes es una lección gratuita de Lua Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Lua Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Lua Academy incluye 4 lecciones en total.

Sintaxis de xpcall

xpcall(f, handler, ...) llama a f con los argumentos ... en modo protegido y, si se produce un error, llama a handler(errorObject). El valor devuelto por el controlador se convierte en el segundo valor devuelto por xpcall. A diferencia de pcall, xpcall ejecuta el controlador mientras la pila 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 controlador

El controlador de xpcall más habitual es debug.traceback. Páselo directamente como controlador: formatea el error con una traza completa de la pila de llamadas, lo que resulta inestimable para depurar errores en producción.

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

Controlador personalizado con contexto

Un controlador personalizado puede añadir contexto: una marca de tiempo, un registro en un archivo o una notificación a los sistemas de monitorización; después, puede devolver el error formateado. Este es el patrón estándar para gestionar errores en producción en aplicaciones de 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)

El controlador no puede producir errores

Si el propio controlador de mensajes produce un error, Lua devuelve un indicador de error sin volver a llamar al controlador. Escriba siempre controladores a prueba de fallos: no use operaciones de E/S que puedan fallar ni acceda a índices 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 el bucle principal

En programas de ejecución prolongada (servidores o bucles de juego), envuelva la función principal en xpcall para capturar y registrar cualquier error no gestionado sin provocar un cierre inesperado. Después, el bucle principal puede decidir si reiniciarse o finalizar.

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

Informes de errores estructurados

Combine xpcall con objetos de error estructurados y un controlador completo para generar informes de errores detallados y útiles para la depuración o los paneles de monitorización.

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 corrutinas

Dentro de una corrutina, pcall funciona con normalidad. Para obtener trazas de los errores que se producen dentro de corrutinas, envuelva el cuerpo de la corrutina en xpcall. El controlador se ejecuta dentro del contexto de la pila de la corrutina.

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)

Enriquecimiento de objetos de error

El controlador puede convertir un error de tipo cadena en un objeto completo, o enriquecer aún más un objeto ya completo. Esto permite que el código de niveles inferiores lance errores simples mientras el controlador añade contexto (ID de solicitud, sesión del usuario e información del entorno).

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

Comparación entre pcall y xpcall

Use pcall cuando solo necesite el valor del error, cuando el error sea esperado y se gestione en línea, o cuando sea importante la simplicidad. Use xpcall cuando necesite trazas de la pila, se encuentre en un límite de nivel superior o quiera añadir contexto a todos los errores.

-- 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 devuelto por el controlador

Todo lo que devuelva el controlador se convierte en el segundo valor devuelto por xpcall. Si el controlador devuelve nil, el segundo valor devuelto por xpcall será nil. Un controlador que devuelve el objeto de error original junto con información adicional ofrece la mayor flexibilidad.

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

Comprobación rápida

¿Cuál es la principal ventaja de xpcall frente a pcall?

Resumen: xpcall

Resumen:

  • xpcall(f, handler, ...) — el controlador se ejecuta mientras la pila está intacta
  • Use debug.traceback como controlador para obtener trazas completas
  • El controlador no debe producir errores; manténgalo sencillo
  • Enriquezca los errores con contexto en el controlador
  • Envuelva los bucles principales y los controladores de servidor en xpcall
  • El valor devuelto por el controlador se convierte en el segundo valor devuelto por xpcall

Preguntas frecuentes

¿La lección «xpcall y gestores de mensajes» es gratis?

Sí — el texto completo de «xpcall y gestores de mensajes» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Lua Academy, actualiza a CoddyKit PRO. El curso de Lua Academy incluye 4 lecciones en total.

¿Qué aprenderé en «xpcall y gestores de mensajes»?

Utilice xpcall con un gestor personalizado para obtener trazas detalladas de errores. Practicas Lua Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Lua Academy?

No se requiere experiencia previa. Lua Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.

¿Cuánto tiempo toma la lección «xpcall y gestores de mensajes»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Lua Academy?

Sí. Cada lección de Lua Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. La función error()
  2. Llamadas protegidas con pcall
  3. xpcall y gestores de mensajes
  4. Objetos de error estructurados
← Volver a Lua Academy