tmueller@226
|
1 |
-------------------------------------------------------------------------------
|
tmueller@201
|
2 |
--
|
tmueller@201
|
3 |
-- tek.lib.debug
|
tmueller@244
|
4 |
-- Written by Timm S. Mueller <tmueller at schulze-mueller.de>
|
tmueller@201
|
5 |
-- See copyright notice in COPYRIGHT
|
tmueller@201
|
6 |
--
|
tmueller@226
|
7 |
-- OVERVIEW::
|
tmueller@226
|
8 |
-- Debug library - implements debug output and debug levels:
|
tmueller@226
|
9 |
--
|
tmueller@244
|
10 |
-- 2 || TRACE || used for tracking bugs
|
tmueller@244
|
11 |
-- 4 || INFO || informational messages
|
tmueller@244
|
12 |
-- 5 || WARN || something unexpected happened
|
tmueller@244
|
13 |
-- 10 || ERROR || something went wrong, e.g. resource unavailable
|
tmueller@244
|
14 |
-- 20 || FAIL || something went wrong that can't be coped with
|
tmueller@226
|
15 |
--
|
tmueller@244
|
16 |
-- The default debug level is 10 {{ERROR}}. To set the debug level
|
tmueller@226
|
17 |
-- globally, e.g.:
|
tmueller@226
|
18 |
-- db = require "tek.lib.debug"
|
tmueller@244
|
19 |
-- db.level = db.INFO
|
tmueller@226
|
20 |
--
|
tmueller@226
|
21 |
-- The default debug output stream is {{stderr}}.
|
tmueller@226
|
22 |
-- To override it globally, e.g.:
|
tmueller@226
|
23 |
-- db = require "tek.lib.debug"
|
tmueller@244
|
24 |
-- db.out = io.open("logfile", "w")
|
tmueller@244
|
25 |
--
|
tmueller@244
|
26 |
-- FUNCTIONS::
|
tmueller@244
|
27 |
-- - debug.console() - Enter debug console
|
tmueller@244
|
28 |
-- - debug.dump() - Dump a table recursively
|
tmueller@244
|
29 |
-- - debug.error() - Print a text in the {{ERROR}} debug level
|
tmueller@244
|
30 |
-- - debug.execute() - Execute a function in the specified debug level
|
tmueller@244
|
31 |
-- - debug.fail() - Print a text in the {{FAIL}} debug level
|
tmueller@244
|
32 |
-- - debug.info() - Print a text in the {{INFO}} debug level
|
tmueller@244
|
33 |
-- - debug.print() - Print a text in the specified debug level
|
tmueller@244
|
34 |
-- - debug.stacktrace() - Print a stacktrace in the specified debug level
|
tmueller@244
|
35 |
-- - debug.trace() - Print a text in the {{TRACE}} debug level
|
tmueller@244
|
36 |
-- - debug.warn() - Print a text in the {{WARN}} debug level
|
tmueller@226
|
37 |
--
|
tmueller@226
|
38 |
-------------------------------------------------------------------------------
|
tmueller@201
|
39 |
|
tmueller@244
|
40 |
local debug = require "debug"
|
tmueller@244
|
41 |
local getinfo = debug.getinfo
|
tmueller@244
|
42 |
local stderr = io.stderr
|
tmueller@244
|
43 |
local pairs = pairs
|
tmueller@244
|
44 |
local select = select
|
tmueller@244
|
45 |
local time = os.time
|
tmueller@244
|
46 |
local tonumber = tonumber
|
tmueller@201
|
47 |
local tostring = tostring
|
tmueller@244
|
48 |
local traceback = debug.traceback
|
tmueller@201
|
49 |
local type = type
|
tmueller@201
|
50 |
local unpack = unpack
|
tmueller@201
|
51 |
|
tmueller@201
|
52 |
module "tek.lib.debug"
|
tmueller@247
|
53 |
_VERSION = "Debug 4.1"
|
tmueller@244
|
54 |
|
tmueller@244
|
55 |
-- symbolic:
|
tmueller@244
|
56 |
|
tmueller@244
|
57 |
TRACE = 2
|
tmueller@244
|
58 |
INFO = 4
|
tmueller@244
|
59 |
WARN = 5
|
tmueller@244
|
60 |
ERROR = 10
|
tmueller@244
|
61 |
FAIL = 20
|
tmueller@201
|
62 |
|
tmueller@226
|
63 |
-- global defaults:
|
tmueller@244
|
64 |
|
tmueller@247
|
65 |
level = INFO
|
tmueller@244
|
66 |
out = stderr
|
tmueller@244
|
67 |
wrout = function(...) out:write(...) end
|
tmueller@226
|
68 |
|
tmueller@226
|
69 |
-------------------------------------------------------------------------------
|
tmueller@244
|
70 |
-- print(lvl, msg, ...): Prints formatted text if the global debug level
|
tmueller@226
|
71 |
-- is less or equal the specified level.
|
tmueller@226
|
72 |
-------------------------------------------------------------------------------
|
tmueller@201
|
73 |
|
tmueller@201
|
74 |
function print(lvl, msg, ...)
|
tmueller@201
|
75 |
if level and lvl >= level then
|
tmueller@201
|
76 |
local t = getinfo(3, "lS")
|
tmueller@201
|
77 |
local arg = { }
|
tmueller@205
|
78 |
for i = 1, select('#', ...) do
|
tmueller@205
|
79 |
local v = select(i, ...)
|
tmueller@226
|
80 |
arg[i] = v and type(v) ~= "number" and tostring(v) or v or 0
|
tmueller@201
|
81 |
end
|
tmueller@244
|
82 |
wrout(("(%02d %d %s:%d) " .. msg):format(lvl,
|
tmueller@226
|
83 |
time(), t.short_src, t.currentline, unpack(arg)) .. "\n")
|
tmueller@201
|
84 |
end
|
tmueller@201
|
85 |
end
|
tmueller@201
|
86 |
|
tmueller@226
|
87 |
-------------------------------------------------------------------------------
|
tmueller@244
|
88 |
-- execute(lvl, func, ...): Executes the specified function if the global
|
tmueller@226
|
89 |
-- debug library is less or equal the specified level.
|
tmueller@226
|
90 |
-------------------------------------------------------------------------------
|
tmueller@226
|
91 |
|
tmueller@205
|
92 |
function execute(lvl, func, ...)
|
tmueller@205
|
93 |
if level and lvl >= level then
|
tmueller@226
|
94 |
return func(...)
|
tmueller@205
|
95 |
end
|
tmueller@201
|
96 |
end
|
tmueller@201
|
97 |
|
tmueller@226
|
98 |
-------------------------------------------------------------------------------
|
tmueller@244
|
99 |
-- trace(msg, ...): Prints formatted debug info with {{TRACE}} level
|
tmueller@226
|
100 |
-------------------------------------------------------------------------------
|
tmueller@205
|
101 |
function trace(msg, ...) print(2, msg, ...) end
|
tmueller@226
|
102 |
|
tmueller@226
|
103 |
-------------------------------------------------------------------------------
|
tmueller@244
|
104 |
-- info(msg, ...): Prints formatted debug info with {{INFO}} level
|
tmueller@226
|
105 |
-------------------------------------------------------------------------------
|
tmueller@205
|
106 |
function info(msg, ...) print(4, msg, ...) end
|
tmueller@226
|
107 |
|
tmueller@226
|
108 |
-------------------------------------------------------------------------------
|
tmueller@244
|
109 |
-- warn(msg, ...): Prints formatted debug info with {{WARN}} level
|
tmueller@226
|
110 |
-------------------------------------------------------------------------------
|
tmueller@205
|
111 |
function warn(msg, ...) print(5, msg, ...) end
|
tmueller@226
|
112 |
|
tmueller@226
|
113 |
-------------------------------------------------------------------------------
|
tmueller@244
|
114 |
-- error(msg, ...): Prints formatted debug info with {{ERROR}} level
|
tmueller@226
|
115 |
-------------------------------------------------------------------------------
|
tmueller@205
|
116 |
function error(msg, ...) print(10, msg, ...) end
|
tmueller@226
|
117 |
|
tmueller@226
|
118 |
-------------------------------------------------------------------------------
|
tmueller@244
|
119 |
-- fail(msg, ...): Prints formatted debug info with {{FAIL}} level
|
tmueller@226
|
120 |
-------------------------------------------------------------------------------
|
tmueller@205
|
121 |
function fail(msg, ...) print(20, msg, ...) end
|
tmueller@201
|
122 |
|
tmueller@244
|
123 |
-------------------------------------------------------------------------------
|
tmueller@244
|
124 |
-- stacktrace(debuglevel, stacklevel): Prints a stacktrace starting at
|
tmueller@244
|
125 |
-- the function of the given {{level}} on the stack (excluding the
|
tmueller@244
|
126 |
-- {{stracktrace}} function itself) if the global debug level is less
|
tmueller@244
|
127 |
-- or equal the specified {{debuglevel}}.
|
tmueller@244
|
128 |
-------------------------------------------------------------------------------
|
tmueller@244
|
129 |
|
tmueller@244
|
130 |
function stacktrace(lvl, level)
|
tmueller@244
|
131 |
print(lvl, traceback("", level or 1 + 1))
|
tmueller@244
|
132 |
end
|
tmueller@244
|
133 |
|
tmueller@244
|
134 |
-------------------------------------------------------------------------------
|
tmueller@244
|
135 |
-- console(): Enter the debug console.
|
tmueller@244
|
136 |
-------------------------------------------------------------------------------
|
tmueller@244
|
137 |
|
tmueller@244
|
138 |
function console()
|
tmueller@244
|
139 |
stderr:write('Entering the debug console.\n')
|
tmueller@244
|
140 |
stderr:write('To redirect the output, e.g.:\n')
|
tmueller@244
|
141 |
stderr:write(' tek.lib.debug.out = io.open("logfile", "w")\n')
|
tmueller@244
|
142 |
stderr:write('To dump a table, e.g.:\n')
|
tmueller@247
|
143 |
stderr:write(' tek.lib.debug.dump(app)\n')
|
tmueller@244
|
144 |
stderr:write('Use "cont" to continue.\n')
|
tmueller@244
|
145 |
debug.debug()
|
tmueller@244
|
146 |
end
|
tmueller@244
|
147 |
|
tmueller@244
|
148 |
-------------------------------------------------------------------------------
|
tmueller@247
|
149 |
-- dump(table): Dump a table as Lua source using {{out}} as the output
|
tmueller@247
|
150 |
-- stream. Cyclic references are silently dropped.
|
tmueller@244
|
151 |
-------------------------------------------------------------------------------
|
tmueller@244
|
152 |
|
tmueller@247
|
153 |
local function encodenonascii(c)
|
tmueller@247
|
154 |
return ("\\%03d"):format(c:byte())
|
tmueller@244
|
155 |
end
|
tmueller@244
|
156 |
|
tmueller@247
|
157 |
local function encode(s)
|
tmueller@247
|
158 |
return s:gsub('([%z\001-\031\092"])', encodenonascii)
|
tmueller@247
|
159 |
end
|
tmueller@247
|
160 |
|
tmueller@247
|
161 |
local function dumpr(tab, indent, outfunc, saved)
|
tmueller@247
|
162 |
saved[tab] = tab
|
tmueller@247
|
163 |
local is = ("\t"):rep(indent)
|
tmueller@247
|
164 |
for key, val in pairs(tab) do
|
tmueller@247
|
165 |
if not saved[val] then
|
tmueller@247
|
166 |
outfunc(is)
|
tmueller@247
|
167 |
local t = type(key)
|
tmueller@247
|
168 |
if t == "number" or t == "boolean" then
|
tmueller@247
|
169 |
outfunc('[' .. tostring(key) .. '] = ')
|
tmueller@247
|
170 |
elseif t == "string" then
|
tmueller@247
|
171 |
if key:match("[^%a_]") then
|
tmueller@247
|
172 |
outfunc('["' .. encode(key) .. '"] = ')
|
tmueller@247
|
173 |
else
|
tmueller@247
|
174 |
outfunc(key .. ' = ')
|
tmueller@247
|
175 |
end
|
tmueller@247
|
176 |
else
|
tmueller@247
|
177 |
outfunc('["' .. tostring(key) .. '"] = ')
|
tmueller@247
|
178 |
end
|
tmueller@247
|
179 |
t = type(val)
|
tmueller@247
|
180 |
if t == "table" then
|
tmueller@247
|
181 |
outfunc('{\n')
|
tmueller@247
|
182 |
dumpr(val, indent + 1, outfunc, saved)
|
tmueller@247
|
183 |
outfunc(is .. '},\n')
|
tmueller@247
|
184 |
elseif t == "string" then
|
tmueller@247
|
185 |
outfunc('"' .. encode(val) .. '",\n')
|
tmueller@247
|
186 |
elseif t == "number" or t == "boolean" then
|
tmueller@247
|
187 |
outfunc(tostring(val) .. ',\n')
|
tmueller@247
|
188 |
else
|
tmueller@247
|
189 |
outfunc('"' .. tostring(val) .. '",\n')
|
tmueller@244
|
190 |
end
|
tmueller@244
|
191 |
end
|
tmueller@244
|
192 |
end
|
tmueller@244
|
193 |
end
|
tmueller@247
|
194 |
|
tmueller@247
|
195 |
function dump(tab, outf)
|
tmueller@247
|
196 |
dumpr(tab, 0, outf or wrout, { })
|
tmueller@247
|
197 |
end
|