otp
otp copied to clipboard
Tracing: Allow traced function to return current stack trace
Recently in #5305 the caller_line
option was added (PR is not yet merged to master but this PR is complete). This feature allows match spec bodies to return the calling function name with the call site position using message
.
The next logical request would be to allow a new match spec body tracing option stack_trace
that will allow traced functions to return their whole stack trace.
Justification for feature
Is this feature useful? I think so. But better than that -- this feature is already available today in the Redbug Erlang tracer. The Redbug tracer has the the ability to return the stack trace of a function via stack
e.g.
redbug:start('test_mod:some_func->stack', [{msgs, 400}, {time, 10000}])
When you think about it, how is the Redbug tracer implementing this feature without any tracing primitives that give you a stack trace??? The answer is simple, Redbug uses tracing option process_dump
to first obtain a full process dump.
This process dump is later parsed for the all Return addr
lines to construct the stack trace (see here)
As this is currently implemented:
- It is inefficient because a lot of other data is collected during the
process_dump
- It is fragile because tomorrow if the process dump text output changes a bit, the functionality will break
- Currently the stack trace provided is a bit crude because it only has the function names. We can provide source file and location just like we did for
caller_line
. This will make the stack trace more useful
This is a useful functionality and in my view Erlang/OTP should provide a primitive for traced functions to return stack traces.
Implementation
The implementation looks relatively straightforward. I have looked at the stack dump related code within the process_dump
routines in otp
source. With the experience I got on #5305 I think I can implement it. But before I spend any time on this problem I'd like to ask if this is something you'd like to see implemented.
cc: @garazdawi @jhogberg
P.S. There are the usual issues with the stack trace looking funny when return_trace
is used. However, this problem is present with Redbug even today because it consults the process dump Return Addr
lines to construct the stack trace. You will see a lot of non-useful "undefined" frames (non-useful to humans anyways) when return_trace
is in effect.
Yes, this is something that we would like to have and we would appreciate help implementing it.
Something to keep in mind when looking at this is that the stack trace has to follow the max-depth of system_flag(backtrace_depth) and we think that it should also be possible to specify a smaller max-depth in the match spec. That is something like this:
[{'_',[],[{message,{current_stacktrace,2}}]}] %% depth is minimum of 2 and system_flag(backtrace_depth)
[{'_',[],[{message,{current_stacktrace}}]}] %% depth is system_flag(backtrace_depth)
The implementation looks relatively straightforward. I have looked at the stack dump related code within the process_dump routines in otp source. With the experience I got on #5305 I think I can implement it. But before I spend any time on this problem I'd like to ask if this is something you'd like to see implemented.
cc: @garazdawi @jhogberg
P.S. There are the usual issues with the stack trace looking funny when return_trace is used. However, this problem is present with Redbug even today because it consults the process dump Return Addr lines to construct the stack trace. You will see a lot of non-useful "undefined" frames (non-useful to humans anyways) when return_trace is in effect.
To save you some time, look at how current_stacktrace
in erl_bif_info.c
is implemented, it uses the internal stack crawling routines that take care of all edge cases surrounding tracing, alternate frame layouts, honoring backtrace depth, etc. It should make this about as straightforward as #5305.
As an aside, I think line numbers should be added to stack traces in process_dump
just to make crash dumps easier to read. It'll require changing all tools that inspect that format (e.g. crashdump_viewer
and apparently redbug
too) though, so maybe in another PR.
@sidkshatriya is there any update on this? I'd love this feature. I would like to use it to get the caller of a traced function that is defined in my project. Would be really helpful.
Based on your requirement, you can use caller_line
or caller
.
See https://www.erlang.org/doc/apps/erts/match_spec.html
(This issue pertains to return the whole stack trace)
Sorry for the confusion but I meant I'd like to have the callstack in some sane form (exactly what this issue is about). I'd like to iterate over calls on the callstack to get to the first call that is done by a module defined in my project. If I just use caller I can get some intermediary function call like Enum.map
or :erlang.apply
.