Interactive example of Dynamic scoping and evaluation order of expressions
I do not know other environments in existing languages, whether
statically or dynamically scoped. Also, that would be language
specific, hence off topic here.

Without a system environment, the way I would do this would be to
insert print statement in my program, either by hand if I am poor, or
with a some programmable program transformation system. I actually did
it often a very long time ago for debugging purposes, applying program
transformations I had developed in such a program transformation
system.

Your example is rather simple as the formal parameters j and k are
never modified, so that everything can be assumed to be call by value.
But things can get very hairy when formal parameters get modified in
the function, depending on the parameter passing mode.

I am also a bit surprised that your system gives you the post value
of i in f2 at the beginning rather than at the end of the trace.

You may try to trace the values of variable that are not visible in
the function currently executed, for example by printing them with a
function defined at the right place. But that can only work when the
function uses static scoping.

My basic philosophy is that dynamic scoping is an endless source of
problems because you cannot know what a free variable stands for, as
it may vary from call to call. I know that some people like it and say
it is useful. I will not comment.

Dynamic scoping was invented as a bug in the first Lisp interpreter, in the late fifties.
When they realized what they had done, the beast was out. Scheme
corrected that, but much later.

I am not sure I answered you. But I now realize this question is borderline on this site.