0Pricing
Lua Academy · Lezione

xpcall e gestori dei messaggi

Utilizzi xpcall con un gestore personalizzato per ottenere traceback dettagliati degli errori.

xpcall e gestori dei messaggi è una lezione Lua Academy gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Lua Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Lua Academy include 4 lezioni in totale.

Sintassi di xpcall

xpcall(f, handler, ...) chiama f con gli argomenti ... in modalità protetta e, in caso di errore, chiama handler(errorObject). Il valore restituito dal gestore diventa il secondo valore restituito da xpcall. A differenza di pcall, xpcall esegue il gestore mentre lo stack è ancora intatto.

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

Il gestore di xpcall più comune è debug.traceback. Lo passi direttamente come gestore: formatta l'errore con uno stack trace completo delle chiamate, indispensabile per il debug degli errori in produzione.

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

Gestore personalizzato con contesto

Un gestore personalizzato può aggiungere contesto, come un timestamp, registrare l'errore su file o inviare notifiche ai sistemi di monitoraggio, quindi restituire l'errore formattato. Questo è lo schema standard per la gestione degli errori in produzione nelle applicazioni 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)

Il gestore non può generare errori

Se il gestore dei messaggi genera a sua volta un errore, Lua restituisce un indicatore di errore senza chiamare nuovamente il gestore. Scriva sempre gestori a prova di errore: nessuna operazione di I/O che possa fallire e nessun accesso a indici 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 per il ciclo principale

Nei programmi a esecuzione prolungata (server, cicli di gioco), racchiuda la funzione principale in xpcall per intercettare e registrare gli errori non gestiti senza causare un arresto anomalo. Il ciclo principale potrà quindi decidere se riavviarsi o terminare.

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

Segnalazione strutturata degli errori

Combini xpcall con oggetti di errore strutturati e un gestore completo per produrre report dettagliati e utili sugli errori, destinati al debug o ai pannelli di monitoraggio.

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 per le coroutine

All'interno di una coroutine, pcall funziona normalmente. Per ottenere i traceback dagli errori all'interno delle coroutine, racchiuda il corpo della coroutine in xpcall. Il gestore viene eseguito nel contesto dello stack della coroutine.

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)

Arricchimento degli oggetti di errore

Il gestore può trasformare un semplice errore stringa in un oggetto completo oppure arricchire ulteriormente un oggetto già completo. In questo modo il codice di livello inferiore può generare errori semplici, mentre il gestore aggiunge contesto (ID della richiesta, sessione dell'utente, informazioni sull'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

Confronto tra pcall e xpcall

Usi pcall quando: ha bisogno solo del valore dell'errore, l'errore è previsto e viene gestito inline, oppure la semplicità è importante. Usi xpcall quando: ha bisogno degli stack trace, si trova a un confine di alto livello o desidera aggiungere contesto a tutti gli errori.

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

Valore restituito dal gestore

Qualunque valore restituisca il gestore diventa il secondo valore restituito da xpcall. Se il gestore restituisce nil, il secondo valore restituito da xpcall è nil. Un gestore che restituisce l'oggetto di errore originale insieme a informazioni aggiuntive è l'approccio più flessibile.

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 rapida

Qual è il principale vantaggio di xpcall rispetto a pcall?

Riepilogo: xpcall

Riepilogo:

  • xpcall(f, handler, ...) — il gestore viene eseguito mentre lo stack è intatto
  • Usi debug.traceback come gestore per ottenere traceback completi
  • Il gestore non deve generare errori: lo mantenga semplice
  • Arricchisca gli errori con il contesto nel gestore
  • Racchiuda i cicli principali e i gestori dei server in xpcall
  • Il valore restituito dal gestore diventa il secondo valore restituito da xpcall

Domande Frequenti

La lezione «xpcall e gestori dei messaggi» è gratuita?

Sì — il testo completo di «xpcall e gestori dei messaggi» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Lua Academy, passa a CoddyKit PRO. Il corso Lua Academy include 4 lezioni in totale.

Cosa imparerò in «xpcall e gestori dei messaggi»?

Utilizzi xpcall con un gestore personalizzato per ottenere traceback dettagliati degli errori. Eserciti Lua Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Lua Academy?

Non è richiesta alcuna esperienza precedente. Lua Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.

Quanto tempo richiede la lezione «xpcall e gestori dei messaggi»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Lua Academy?

Sì. Ogni lezione Lua Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. La funzione error()
  2. Chiamate protette con pcall
  3. xpcall e gestori dei messaggi
  4. Oggetti di errore strutturati
← Torna a Lua Academy