Skip to content

Commit b67a138

Browse files
committed
Capture frame locals via debug.getlocal, add associated conf options
1 parent c87da71 commit b67a138

File tree

1 file changed

+79
-5
lines changed

1 file changed

+79
-5
lines changed

raven.lua

+79-5
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ local version = "0.4.1"
3434
local os_date = os.date
3535
local os_time = os.time
3636
local debug_getinfo = debug.getinfo
37+
local debug_getlocal = debug.getlocal
3738
local math_random = math.random
3839
local json_encode = json.encode
3940
local string_format = string.format
@@ -140,7 +141,50 @@ local function _get_server_name()
140141
return ngx and ngx.var.server_name or "undefined"
141142
end
142143

143-
local function backtrace(level)
144+
local function get_function_details(f)
145+
local info = debug_getinfo(f, "fSl")
146+
return string_format("%s defined at line %d in %s", tostring(info.func), info.linedefined, info.short_src)
147+
end
148+
149+
-- these two are mutually recursive, hence declaration before instantiation
150+
local json_prep_table, json_prep_value
151+
json_prep_value = function (v, max_depth)
152+
if max_depth == nil then
153+
max_depth = 0
154+
end
155+
156+
local tv = type(v)
157+
if tv == "function" then
158+
return get_function_details(v)
159+
elseif tv == "lightuserdata" or tv == "userdata" or tv == "thread" then
160+
return tostring(v)
161+
elseif tv == "table" then
162+
if max_depth <= 0 then
163+
return tostring(v)
164+
else
165+
return json_prep_table(v, max_depth - 1)
166+
end
167+
else
168+
return v
169+
end
170+
end
171+
172+
json_prep_table = function (t, max_depth)
173+
if max_depth == nil then
174+
max_depth = 0
175+
end
176+
177+
local out = {}
178+
for k, v in pairs(t) do
179+
local tk = type(k)
180+
if tk == "number" or tk == "string" then
181+
out[k] = json_prep_value(v, max_depth)
182+
end
183+
end
184+
return out
185+
end
186+
187+
local function backtrace(level, capture_frame_locals, max_depth)
144188
local frames = {}
145189

146190
level = level + 1
@@ -151,12 +195,32 @@ local function backtrace(level)
151195
break
152196
end
153197

154-
table_insert(frames, 1, {
198+
local frame = {
155199
filename = info.short_src,
156200
["function"] = info.name,
157201
lineno = info.currentline,
158-
})
202+
}
203+
204+
if capture_frame_locals then
205+
local frame_locals = {}
206+
local frame_local_idx = 1
207+
while true do
208+
local k, v = debug_getlocal(level, frame_local_idx)
209+
if k == nil then
210+
break
211+
end
212+
213+
-- unsure whether this tostring is actually necessary
214+
k = tostring(k)
215+
if k:sub(0, 1) ~= "(" then -- internal/temp vars start with (, ignore them
216+
frame_locals[k] = json_prep_value(v, max_depth)
217+
end
218+
frame_local_idx = frame_local_idx + 1
219+
end
220+
frame.vars = frame_locals
221+
end
159222

223+
table_insert(frames, 1, frame)
160224
level = level + 1
161225
end
162226
return { frames = frames }
@@ -253,6 +317,8 @@ function _M.new(self, dsn, conf)
253317
obj.level = "error"
254318
obj.verify_ssl = true
255319
obj.cacert = "./data/cacert.pem"
320+
obj.capture_frame_locals = true
321+
obj.max_depth = 0
256322

257323
if conf then
258324
if conf.tags then
@@ -270,6 +336,14 @@ function _M.new(self, dsn, conf)
270336
if conf.cacert then
271337
obj.cacert = conf.cacert
272338
end
339+
340+
if conf.capture_frame_locals == false then
341+
obj.capture_frame_locals = false
342+
end
343+
344+
if conf.max_depth then
345+
obj.max_depth = conf.max_depth
346+
end
273347
end
274348

275349
return setmetatable(obj, mt)
@@ -319,7 +393,7 @@ function _M.captureException(self, exception, conf)
319393
trace_level = conf.trace_level
320394

321395
clear_tab(_json)
322-
exception[1].stacktrace = backtrace(trace_level)
396+
exception[1].stacktrace = backtrace(trace_level, self.capture_frame_locals, self.max_depth)
323397
_json.exception = exception
324398
_json.message = exception[1].value
325399

@@ -448,7 +522,7 @@ function _M.catcher(self, err)
448522

449523
clear_tab(_exception[1])
450524
_exception[1].value = err
451-
_exception[1].stacktrace = backtrace(catcher_trace_level)
525+
_exception[1].stacktrace = backtrace(catcher_trace_level, self.capture_frame_locals, self.max_depth)
452526

453527
clear_tab(_json)
454528
_json.exception = _exception

0 commit comments

Comments
 (0)