C# 记录java.sql.SQLException会导致溢出
我试图记录来自IKVM.OpenJDK.Jdbc程序集的异常。发生的一个异常是C# 记录java.sql.SQLException会导致溢出,c#,jdbc,log4net,ikvm,C#,Jdbc,Log4net,Ikvm,我试图记录来自IKVM.OpenJDK.Jdbc程序集的异常。发生的一个异常是java.sql.SQLException(和子类)。log4Net似乎在这个问题上出错了,因为java.sql.SQLException实现了IEnumerable,而它的实现只是返回它自己。我已经详细介绍了log4net代码,它看起来像log4net所说的: “这里有一个要记录的SQLException。它是否包含我应该记录的任何信息?哦,是的。有一个IEnumerable,我最好把东西记录在IEnumerable
java.sql.SQLException
(和子类)。log4Net似乎在这个问题上出错了,因为java.sql.SQLException
实现了IEnumerable
,而它的实现只是返回它自己。我已经详细介绍了log4net代码,它看起来像log4net所说的:
“这里有一个要记录的SQLException。它是否包含我应该记录的任何信息?哦,是的。有一个IEnumerable,我最好把东西记录在IEnumerable里面。那么,在这个IEnumerable中是什么呢?哦,看,这是一个SQLException日志。它是否包含任何我应该记录的内容?哦,是的。有一个IEnumerable,我最好把东西记录在IEnumerable里面。那么,在这个IEnumerable中是什么呢?哦,看,这是个例外……”
最终我们得到了一个堆栈溢出异常
以前有人解决过这个问题吗
最小可验证完整示例:
static void Main(string[] args)
{
java.sql.SQLException ex = new java.sql.SQLException();
log4net.Config.BasicConfigurator.Configure();
log4net.ILog logger = log4net.LogManager.GetLogger("foo");
logger.Error("This exception overflows the stack -> ", ex); // Exception here
Console.WriteLine("Finished. Press any key...");
Console.ReadKey();
}
我使用packages.config获取正确的NuGet以使其编译(NuGet source=):
有一个异常实现IEnumerable
可以说是一个设计错误——在.NET中,对于一般情况,这是通过exception.InnerException
实现的,对于数据库错误,尤其是SqlException.Errors
实现的。然而,提交错误报告可能对您没有好处,因为IKVM的目标是在.NET中使用Java,因此它希望紧跟其根
使用log4net提交bug报告的成功几率稍高一些,但不会太高,因为以完全通用的方式处理这个问题需要在可枚举中进行周期检测,这是一个巨大的难题
幸运的是,有一个更简单的解决方法;log4net是高度可定制的,通过使用自定义对象渲染器,我们可以随心所欲地处理这些异常。由于可枚举异常的奇怪之处似乎仅限于IKVM,因此我们可能不必将其特定于可丢弃的
:
class ThrowableRenderer : log4net.ObjectRenderer.IObjectRenderer {
private readonly IObjectRenderer fallback;
public ThrowableRenderer(RendererMap rendererMap) {
this.fallback = rendererMap.Get(typeof(Throwable));
}
public void RenderObject(RendererMap rendererMap, object obj, TextWriter writer) {
var filteredEnumerable = (obj as IEnumerable)?.Cast<object>().Skip(1);
if (filteredEnumerable != null) {
rendererMap.FindAndRender(obj.ToString(), writer);
if (filteredEnumerable.Any()) {
writer.WriteLine();
rendererMap.FindAndRender(filteredEnumerable, writer);
}
} else {
fallback.RenderObject(rendererMap, obj, writer);
}
}
}
在上面的实现中,我定制了Throwable
s的呈现,首先将Throwable
本身呈现为平面对象,然后是链中的任何嵌套异常,但不是第一个异常本身。您可能希望进一步定制它,因为与标准exception
不同,Throwable.ToString()
似乎不包含堆栈跟踪(虽然您可以让log4net将堆栈跟踪添加到任何错误消息中,但检索此堆栈跟踪的速度要慢得多),但这演示了通过避开默认渲染来避免堆栈溢出的基本思想
var rendererMap = log4net.LogManager.GetRepository().RendererMap;
rendererMap.Put(typeof(Throwable), new ThrowableRenderer(rendererMap));