2016-06-02 11 views
3

IKVM.OpenJDK.Jdbc 어셈블리에서 발생한 예외를 기록하려고합니다. 한 가지 예외는 java.sql.SQLException (및 하위 클래스)입니다. log4Net은 java.sql.SQLExceptionIEnumerable을 구현하고 그 구현이 그 자체를 반환하기 때문에이 문제를 해결할 것으로 보인다. 나는 log4net 코드를 밟았으며 log4net은 다음과 같이 말합니다 :로깅 java.sql.SQLException으로 인해 오버플로가 발생합니다.

"여기에 기록 할 SQLException이 있습니다. 기록해야 할 정보가 있습니까? 예, 있습니다. IEnumerable, IEnumerable 내부에 물건을 더 잘 기록해야합니다. 그래서 IEnumerable에 무엇이 있습니까? 아, 로그하는 SQLException입니다. 로그해야하는 항목이 있습니까? 예, 있습니다. IEnumerable, 나는 더는 IEnumerable 내부의 물건을 기록했다. 그는 IEnumerable에 그래서 뭐? 아, SQLException이있다 보면 ... "

은 결국 우리가 StackOverflowException를 얻을.

아무도이 문제를 이미 가지고 있었고 해결 했습니까?

최소한의 검증 가능한 완전한 예 :

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(); 
} 

그리고 내가 컴파일 할 수있는 권한 NuGets를 얻기 위해 사용되는 packages.config (NuGet 소스 = https://www.nuget.org/api/v2/) :

<packages> 
    <package id="log4net" version="2.0.5" targetFramework="net452" /> 
    <package id="IKVM.OpenJDK.Jdbc" version="7.2.4630.5" targetFramework="net452" /> 
    <!-- The packages below are dependencies from manually getting the packages above. --> 
    <package id="IKVM.OpenJDK.Charsets" version="7.2.4630.5" targetFramework="net452" /> 
    <package id="IKVM.OpenJDK.Core" version="7.2.4630.5" targetFramework="net452" /> 
    <package id="IKVM.OpenJDK.Misc" version="7.2.4630.5" targetFramework="net452" /> 
    <package id="IKVM.OpenJDK.Naming" version="7.2.4630.5" targetFramework="net452" /> 
    <package id="IKVM.OpenJDK.Remoting" version="7.2.4630.5" targetFramework="net452" /> 
    <package id="IKVM.OpenJDK.Security" version="7.2.4630.5" targetFramework="net452" /> 
    <package id="IKVM.OpenJDK.SwingAWT" version="7.2.4630.5" targetFramework="net452" /> 
    <package id="IKVM.OpenJDK.Text" version="7.2.4630.5" targetFramework="net452" /> 
    <package id="IKVM.OpenJDK.Util" version="7.2.4630.5" targetFramework="net452" /> 
    <package id="IKVM.OpenJDK.XML.API" version="7.2.4630.5" targetFramework="net452" /> 
    <package id="IKVM.Runtime" version="7.2.4630.5" targetFramework="net452" /> 
</packages> 

답변

3

를 갖는 예외 구현 IEnumerable은 틀림없이 설계 오류입니다. .NET에서는 일반적인 경우는 Exception.InnerException이고 특히 데이터베이스 오류의 경우 SqlException.Errors을 통해 구현됩니다. 그러나 IKVM의 목표는 .NET에서 Java를 구현하는 것이므로 버그 보고서를 제출하는 것이 좋지 않을 것입니다. 따라서 뿌리 가까이에 붙어 있어야합니다.

log4net을 사용하여 버그 보고서를 작성하는 것은 완전히 일반적인 방법으로 처리 할 때 열거 형에서주기를 감지해야하므로 엄청난 고통입니다.

다행히도 간단한 해결 방법이 있습니다. log4net은 커스터마이징이 가능하며, 커스텀 오브젝트 렌더러를 사용하여 우리가 원할 경우 예외를 적용 할 수 있습니다. 열거 예외의 기이가 iKVM을에 국한 될 것으로 보인다 때문에, 우리는 아마 특정 Throwable을 만드는 멀리 얻을 수 있습니다 :

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); 
    } 
    } 
} 

을 그리고 당신은과 같이 사용자 정의 렌더러를 구성합니다

var rendererMap = log4net.LogManager.GetRepository().RendererMap; 
rendererMap.Put(typeof(Throwable), new ThrowableRenderer(rendererMap)); 

에서 위의 구현에서는 Throwable의 렌더링을 사용자 지정하여 Throwable 자체를 플랫 개체로 렌더링 한 다음 체인의 중첩 예외는 있지만 첫 번째 예외 자체는 렌더링하지 않았습니다. 표준 Exception과 달리 Throwable.ToString()은 스택 추적을 포함하지 않는 것으로 표시되기 때문에 (log4net에서 스택 추적을 오류 메시지에 추가 할 수는 있지만이 스택 추적을 검색하는 속도는 훨씬 느리기 때문에)이 옵션을 추가로 사용자 정의 할 수 있습니다. 기본 렌더링을 회피하여 스택 오버플로를 피하는 기본 개념을 보여줍니다.