有没有办法在Perl脚本中的当前位置之前访问(打印输出)子+模块列表到任意深度的子调用?
我需要更改一些Perl模块(.pm).工作流通过cgi脚本从网页启动,通过在我需要使用数据的模块中结束的几个模块/对象传递输入.在某个地方,数据发生了变化,我需要找出原因.
我最近发现了一个导致NullPointerException的错误.使用标准的slf4j语句捕获并记录异常.以下简要代码:
for(Action action : actions.getActions()) {
try {
context = action.execute(context);
} catch (Exception e) {
logger.error("...", e);
break;
}
}
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,没什么特别的.但是,在我们拥有的所有异常日志记录语句中,只有这一个不打印堆栈跟踪.它打印的全部是消息(表示为"...")和异常类的名称(java.lang.NullPointerException).
由于异常上的堆栈跟踪是延迟加载的,我想可能存在某种指令重新排序问题,并决定在日志语句之前调用e.getStackTrace().这没有任何区别.
所以我决定在启用调试代理的情况下重新启动.但是,因为我甚至连接到这个过程,我注意到现在堆栈的痕迹正在打印.很明显,调试代理的存在导致一些额外的调试信息变得可用.
从那时起我就修复了异常的根本原因.但我想了解为什么没有调试器就无法使用堆栈跟踪.谁知道?
澄清:这不是日志记录问题.想象一下相同的try/catch子句,但在catch中,我打印的值为:
e.getStackTrace().length
Run Code Online (Sandbox Code Playgroud)
没有调试器,它打印'0',调试器打印一个正数(在这种情况下为9).
更多信息:这发生在JDK 1.6.0_13,64bit,amd64,linux 2.6.9上
使用这样的函数:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
void print_trace() {
char pid_buf[30];
sprintf(pid_buf, "--pid=%d", getpid());
char name_buf[512];
name_buf[readlink("/proc/self/exe", name_buf, 511)]=0;
int child_pid = fork();
if (!child_pid) {
dup2(2,1); // redirect output to stderr
fprintf(stdout,"stack trace for %s pid=%s\n",name_buf,pid_buf);
execlp("gdb", "gdb", "--batch", "-n", "-ex", "thread", "-ex", "bt", name_buf, pid_buf, NULL);
abort(); /* If gdb failed to start */
} else {
waitpid(child_pid,NULL,0);
}
}
Run Code Online (Sandbox Code Playgroud)
我在输出中看到了print_trace的细节.
有什么其他方法可以做到这一点?
我需要在Ruby中获取堆栈跟踪对象; 不要打印它,只是为了让它做一些录音和倾倒以供以后分析.那可能吗?怎么样?
我的一个类的实例变量正在发生一些事情.我想让变量成为一个属性,无论何时访问它,我都要打印出导致该点的所有代码的堆栈跟踪,这样我就可以看到它被搞乱了.如果没有引发异常,如何打印堆栈跟踪?我知道如果有例外,我可以做类似的事情traceback.format_tb(sys.exc_info()[2]).
另外可能有用的是仅打印最后3-4个级别,因为前几个级别可能不会那么有趣.
我们在专有的assert宏中使用堆栈跟踪来捕获开发人员的错误 - 当捕获错误时,打印堆栈跟踪.
我发现gcc的配对backtrace()/ backtrace_symbols()方法不足:
第一个问题可以通过abi :: __ cxa_demangle来解决.
然而,第二个问题更加艰难.我发现了替换backtrace_symbols().这比gcc的backtrace_symbols()更好,因为它可以检索行号(如果使用-g编译),并且不需要使用-rdynamic进行编译.
Hoverer代码是GNU许可的,所以恕我直言我不能在商业代码中使用它.
任何建议?
PS
gdb能够打印传递给函数的参数.可能已经要求太多了:)
PS 2
类似的问题(感谢nobar)
很清楚为什么堆栈跟踪会受到微软新编程范式的影响.我们现在有一个语义堆栈和几个物理堆栈(我选择的单词).
我看到的是异常的StackTrace属性(在调试器中)是物理的属性,连接起来:
private async Task CheckFooAndBar()
{
var log = LogManager.GetLogger("Test");
log.Info("CheckFooAndBar");
try
{
await Foo();
}
catch (Exception ex)
{
log.Info("StackTrace of last exception: " + ex.StackTrace);
}
Console.ReadKey();
}
private async Task Foo()
{
await Task.Factory.StartNew(() => Thread.Sleep(1000));
await Bar();
await Task.Factory.StartNew(() => Thread.Sleep(1000));
}
private async Task Bar()
{
await Task.Factory.StartNew(() => Thread.Sleep(1000));
throw new Exception();
await Task.Factory.StartNew(() => Thread.Sleep(1000));
}
Run Code Online (Sandbox Code Playgroud)
这给出了:
StackTrace of last exception: at NLogAsyncExceptionTestCase.Program.<Bar>d__d.MoveNext() in c:\Users\Jens\Documents\Visual Studio 2012\Projects\NLogAsyncExceptionTestCase\NLogAsyncExceptionTestCase.Console\Program.cs:line 53
--- End …Run Code Online (Sandbox Code Playgroud) 在记录异常时,我遇到了一些常见问题.似乎有各种不同类型可以处理.例如,有些包装其他Exceptions,有些根本没有消息 - 只是一种类型.
大多数代码我已经使用或者看到日志异常getMessage()或toString(),但这些并不总是捕捉查明问题所需的所有信息-其他方法,如getCause()和getStackTrace()有时提供额外的信息.
作为一个例子,我现在在Eclipse Inspect窗口中看到的异常是一个InvocationTargetException.Exception本身没有原因,没有消息,没有堆栈跟踪......但getCause()的目标是InvalidUseOfMatchersException填充这些详细信息.
所以我的问题是:给定一个异常作为输入的任何类型,请提供一个单一的方法,将输出一个格式良好的字符串,其中包含有关异常的所有相关信息(例如可能递归调用getCause()其他东西?)在发布此问题之前我几乎我自己也会捅这个但是真的不想重新发明轮子 - 当然这样的事情必须要多次做过......?
请不要指向任何特定的日志记录或实用程序框架来执行此操作.我正在寻找代码片段而不是库,因为我没有权利在我正在处理的项目上添加外部依赖项,它实际上是记录到网页的一部分而不是文件.如果这是一个从这样的框架中复制代码片段(并归因于它)的情况那很好:-)
当我使用NLog的默认布局时,它只打印例外的名称.我被告知log4jxmlevent布局不会打印关于异常的任何内容.什么布局会对我有帮助?
示例代码:
try
{
throw new SystemException();
}
catch (Exception ex)
{
logger.Error("oi", ex);
}
Run Code Online (Sandbox Code Playgroud)
默认布局输出:
2011-01-14 09:14:48.0343|ERROR|ConsoleApplication.Program|oi
Run Code Online (Sandbox Code Playgroud)
log4jxmlevent输出:
<log4j:event logger="ConsoleApplication.Program"
level="ERROR"
timestamp="1295003776872"
thread="9">
<log4j:message>oi</log4j:message>
<log4j:NDC />
<log4j:locationInfo class="ConsoleApplication.Program"
method="Void Main(System.String[])"
file="C:\Users\User\Documents\Visual Studio 2010\Projects\ConsoleApplication\ConsoleApplication\Program.cs"
line="21" />
<nlog:eventSequenceNumber>3</nlog:eventSequenceNumber>
<nlog:locationInfo assembly="ConsoleApplication, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<log4j:properties>
<log4j:data name="log4japp"
value="true" />
<log4j:data name="log4jmachinename"
value="MACHINE" />
</log4j:properties>
Run Code Online (Sandbox Code Playgroud)
我试图在一个线程中捕获异常并在主线程中重新引发它:
import threading
import sys
class FailingThread(threading.Thread):
def run(self):
try:
raise ValueError('x')
except ValueError:
self.exc_info = sys.exc_info()
failingThread = FailingThread()
failingThread.start()
failingThread.join()
print failingThread.exc_info
raise failingThread.exc_info[1]
Run Code Online (Sandbox Code Playgroud)
这基本上起作用并产生以下输出:
(<type 'exceptions.ValueError'>, ValueError('x',), <traceback object at 0x1004cc320>)
Traceback (most recent call last):
File "test.py", line 16, in <module>
raise failingThread.exc_info[1]
Run Code Online (Sandbox Code Playgroud)
但是,异常的来源指向第16行,其中发生了重新加注.原始异常来自第7行.如何修改主线程以使输出显示:
Traceback (most recent call last):
File "test.py", line 7, in <module>
Run Code Online (Sandbox Code Playgroud)