traceback
Definition
-- @/lua/common/libs/StackTracePlus/StackTracePlus.lua:435
---
-- Public:
-- Collects a detailed stack trace, dumping locals, resolving function names when they're not available, etc.
-- This function is suitable to be used as an error handler with pcall or xpcall
--
-- @param thread An optional thread whose stack is to be inspected (defaul is the current thread)
-- @param message An optional error string or object.
-- @param level An optional number telling at which level to start the traceback (default is 1)
--
-- Returns a string with the stack trace and a string with the original error.
--
function _M.stacktrace(thread, message, level, level_limit, dump_locals)
if type(thread) ~= "thread" then
-- shift parameters left
thread, message, level, level_limit, dump_locals = nil, thread, message, level, level_limit
end
thread = thread or coroutine.running()
level = level or 1
if dump_locals == nil then
dump_locals = true
end
local dumper = Dumper.new(thread)
local original_error
if type(message) == "table" then
dumper:add("an error object {\n")
local first = true
for k,v in pairs(message) do
if first then
dumper:add(" ")
first = false
else
dumper:add(",\n ")
end
dumper:add(safe_tostring(k))
dumper:add(": ")
dumper:add(safe_tostring(v))
end
dumper:add("\n}")
original_error = dumper:concat_lines()
elseif type(message) == "string" then
dumper:add(message)
original_error = message
end
dumper:add('\n=============== Stack Traceback >> START >>\n')
--print(error_message)
local level_to_show = level
if dumper.dumping_same_thread then level = level + 1 end
local info = dumper.getinfo(level, "nSlf")
while info do
if info.what == "main" then
if string_sub(info.source, 1, 1) == "@" then
dumper:add_f("(%d) main chunk of file '%s' at line %d\n", level_to_show, string_sub(info.source, 2), info.currentline)
else
dumper:add_f("(%d) main chunk of %s at line %d\n", level_to_show, info.source, info.currentline)
end
elseif info.what == "C" then
--print(info.namewhat, info.name)
--for k,v in pairs(info) do print(k,v, type(v)) end
local function_name = m_user_known_functions[info.func] or m_known_functions[info.func] or info.name or tostring(info.func)
dumper:add_f("(%d) %s C function '%s'\n", level_to_show, info.namewhat, function_name)
--dumper:add_f("%s%s = C %s\n", prefix, name, (m_known_functions[value] and ("function: " .. m_known_functions[value]) or tostring(value)))
elseif info.what == "tail" then
--print("tail")
--for k,v in pairs(info) do print(k,v, type(v)) end--print(info.namewhat, info.name)
dumper:add_f("(%d) tail call\n", level_to_show)
if dump_locals then
dumper:DumpLocals(level)
end
elseif info.what == "Lua" then
local source = info.source
local function_name = m_user_known_functions[info.func] or m_known_functions[info.func] or info.name
if source:sub(2, 7) == "string" then
source = source:sub(9)
end
local was_guessed = false
if not function_name or function_name == "?" then
--for k,v in pairs(info) do print(k,v, type(v)) end
function_name = GuessFunctionName(info)
was_guessed = true
end
-- test if we have a file name
local function_type = (info.namewhat == "") and "function" or info.namewhat
if info.source and info.source:sub(1, 1) == "@" then
dumper:add_f("(%d) Lua %s '%s' at file '%s:%d'%s\n", level_to_show, function_type, function_name, info.source:sub(2), info.currentline, was_guessed and " (best guess)" or "")
elseif info.source and info.source:sub(1,1) == '#' then
dumper:add_f("(%d) Lua %s '%s' at template '%s:%d'%s\n", level_to_show, function_type, function_name, info.source:sub(2), info.currentline, was_guessed and " (best guess)" or "")
else
dumper:add_f("(%d) Lua %s '%s' at line %d of chunk '%s'\n", level_to_show, function_type, function_name, info.currentline, source)
end
if dump_locals then
dumper:DumpLocals(level)
end
else
dumper:add_f("(%d) unknown frame %s\n", level_to_show, info.what)
end
level = level + 1
level_to_show = level_to_show + 1
if level_limit ~= nil and level > level_limit then
break
end
info = dumper.getinfo(level, "nSlf")
end
dumper:add('--------------- << END <<\n')
return dumper:concat_lines(), original_error
end
Callers
@/lua/ge/main.lua
log("A", "print", tostring(...))
-- log('A', "print", debug.traceback()) -- find where print is used
end
@/lua/common/libs/timerwheel/timerwheel.lua
local default_err_handler = function(err)
io.stderr:write(debug.traceback("TimerWheel callback failed with: " .. tostring(err)))
end
@/lua/ge/extensions/core/jobsystem.lua
if runningFct[fct] then
--log('D', 'jobsystem', 'job already running. ' .. debug.traceback())
return
if not errorfree then
log('E', 'jobsystem', "job error: " .. tostring(value) .. ' / ' .. debug.traceback(co.t))
end
@/lua/vehicle/controller.lua
log("D", "controller.getControllerSafe", string.format("Didn't find controller '%s', returning nilController.", name))
--log("D", "controller.getControllerSafe", debug.traceback())
--return our nilController that accepts all indexes and can be called without errors
log("E", "controller.loadControllerExternal", errorStr)
log("E", "controller.loadControllerExternal", debug.traceback())
end
log("E", "controller.init", errorStr)
log("E", "controller.init", debug.traceback())
end
@/lua/vehicle/bullettime.lua
guihooks.trigger("toastrMsg", {type="error", title="Deprecated API: bullettime", msg="At least one mod is obsolete and needs to be updated by its author. Check the logs for more information"})
log("E","", "An obsolete mod is using a deprecated API. See traceback below for more information:\n"..debug.traceback())
end
@/lua/vehicle/extensions/dynamicVehicleData.lua
if not errorfree then
log("E", logTag, debug.traceback(workerCoroutine, "workerCoroutine: " .. value))
end
@/lua/common/luaBinding.lua
if not mt then
--log('E', '', string.format("property '%s.%s' is not found or not writable: %s", getmetatable(t).___type, k, debug.traceback()))
return
if not mt then
--log('E', '', string.format("property '%s.%s' is not found or not writable: %s", getmetatable(t).___type, k, debug.traceback()))
return
@/lua/ge/extensions/core/quickAccess.lua
M.addEntry = addEntry
M.registerMenu = function() log('E', 'quickAccess', 'registerMenu is deprecated. Please use quickAccess.addEntry: ' .. debug.traceback()) end
@/lua/ge/map.lua
if not be then return end
--log('A', "map.loadMap-calledby", debug.traceback())
--local timer = hptimer()
@/lua/vehicle/partCondition.lua
log("E", "partCondition.getConditions", err)
log("E", "partCondition.getConditions", debug.traceback())
end
@/lua/vehicle/extensions/escMeasurement.lua
if not errorfree then
log("E", logTag, debug.traceback(workerCoroutine, "workerCoroutine: " .. value))
end
@/lua/common/utils.lua
-- to find out who is calling this, you can use this snippet:
--log('A', "lua.utils.dump-calledby", debug.traceback())
rawset(_G, key, val)
log('W', 'globals', debug.traceback('set new global variable: "' .. tostring(key) .. '" to "' .. tostring(val) .. '"', 2, 1, false))
end,
@/lua/common/libs/StackTracePlus/StackTracePlus.lua
-- @param message An optional error string or object.
-- @param level An optional number telling at which level to start the traceback (default is 1)
--
@/lua/vehicle/extensions/core/quickAccess.lua
M.registerMenu = function()
log("E", "quickAccess", "registerMenu is deprecated. Please use core_quickAccess.addEntry: " .. debug.traceback())
end
@/lua/ge/extensions/util/screenshotCreator.lua
log('E', '', "workerCoroutine: "..value)
log("E", '', debug.traceback(workerCoroutine))
end
@/lua/vehicle/energyStorage.lua
log("D", "energyStorage.getStorageSafe", string.format("Didn't find storage '%s', returning nilStorage.", name))
--log("D", "energyStorage.getStorageSafe", debug.traceback())
--return our nilStorage that accepts all indexes and can be called without errors
@/lua/vehicle/main.lua
log("A", "print", tostring(...))
-- log('A', "print", debug.traceback()) -- find where print is used
end
@/lua/vehicle/controller/drivingDynamics/CMU.lua
-- dump(currentDefaultControlParam)
-- print(debug.traceback())
return false