Lua Academy · Lektion

xpcall og meddelelseshåndterere

Brug xpcall med en brugerdefineret håndterer til detaljerede fejlspor.

Lektion 3 af 412 trin

xpcall og meddelelseshåndterere er en gratis Lua Academy-lektion på CoddyKit. Dette er lektion 3 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i Lua Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Lua Academy-kurset indeholder 4 lektioner i alt.

xpcall-syntaks

xpcall(f, handler, ...) kalder f med argumenterne ... i beskyttet tilstand og kalder ved fejl handler(errorObject). Handlerens returværdi bliver xpcalls anden returværdi. I modsætning til pcall kører xpcall handleren, mens stakken er intakt.

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

Den mest almindelige xpcall-handler er debug.traceback. Angiv den direkte som handler — den formaterer fejlen med et komplet kaldestakspor, som er uvurderligt ved fejlfinding af fejl i produktion.

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

Brugerdefineret handler med kontekst

En brugerdefineret handler kan tilføje kontekst: tidsstempel, logge til en fil, underrette overvågningssystemer og derefter returnere den formaterede fejl. Det er standardmønsteret til fejlhåndtering i Lua-applikationer i produktion.

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)

Handleren må ikke give fejl

Hvis selve meddelelseshandleren giver en fejl, returnerer Lua en fejlindikator uden at kalde handleren igen. Skriv altid skudsikre handlere — ingen IO, der kan mislykkes, og ingen indeksering af 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 til hovedløkken

I langvarigt kørende programmer (servere, spilloops) skal du pakke hovedfunktionen ind i xpcall for at fange og logge ubehandlede fejl uden at få programmet til at gå ned. Hovedløkken kan derefter beslutte, om den skal genstarte eller afslutte.

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

Struktureret fejlrapportering

Kombinér xpcall med strukturerede fejlobjekter og en omfattende handler for at generere detaljerede, handlingsanvisende fejlrapporter til fejlfinding eller overvågningspaneler.

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

Inde i en coroutine fungerer pcall normalt. Hvis du vil have stakspor fra fejl inde i coroutines, skal du pakke coroutine-kroppen ind i xpcall. Handleren kører i coroutine-stakkens kontekst.

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)

Berigelse af fejlobjekter

Handleren kan omdanne en simpel strengfejl til et omfattende objekt eller berige et omfattende objekt yderligere. Det lader kode på lavere niveau kaste simple fejl, mens handleren tilføjer kontekst (anmodnings-ID, brugersession, miljøoplysninger).

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

Sammenligning af pcall og xpcall

Brug pcall, når: du kun har brug for fejlværdien, fejlen er forventet og håndteres lokalt, eller enkelhed er vigtig. Brug xpcall, når: du har brug for stakspor, du befinder dig ved en grænse på øverste niveau, eller du vil tilføje kontekst til alle fejl.

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

Handlerens returværdi

Uanset hvad handleren returnerer, bliver det den anden værdi fra xpcall. Hvis handleren returnerer nil, er xpcalls anden returværdi nil. En handler, der returnerer det oprindelige fejlobjekt sammen med ekstra oplysninger, er den mest fleksible løsning.

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

Hurtigt tjek

Hvad er den vigtigste fordel ved xpcall frem for pcall?

Opsummering: xpcall

Opsummering:

  • xpcall(f, handler, ...) — handleren kører, mens stakken er intakt
  • Brug debug.traceback som handler for komplette stakspor
  • Handleren må ikke give fejl — hold den enkel
  • Berig fejl med kontekst i handleren
  • Pak hovedløkker/serverhandlere ind i xpcall
  • Handlerens returværdi bliver xpcalls anden returværdi
Gratis at komme i gang

Lær Lua med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
40
Lektioner
159

Ofte stillede spørgsmål

Er lektionen “xpcall og meddelelseshåndterere” gratis?

Ja — alle 3 lektioner i læringssporet Lua Academy, inklusive “xpcall og meddelelseshåndterere”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Lua Academy-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “xpcall og meddelelseshåndterere”?

Brug xpcall med en brugerdefineret håndterer til detaljerede fejlspor. Du øver dig i Lua Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Lua Academy?

Der kræves ingen tidligere erfaring. Lua Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 3 af 4.

Hvor lang tid tager lektionen “xpcall og meddelelseshåndterere”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Lua Academy-lektion?

Ja. Alle Lua Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Funktionen error()
  2. Beskyttede kald med pcall
  3. xpcall og meddelelseshåndterere
  4. Strukturerede fejlobjekter
← Tilbage til Lua Academy