2009-12-15 4 views
7

log4net 메시지에 호출 스택 (예 : 나에게 전화 한 메소드)을 포함시키고 싶습니다. 이 작업을 수행하는 표준 방법이 있습니까?로그 메시지에 호출 스택을 포함하여 log4net 지원을 수행합니까?

(I이 느린 것 알고 있지만, 나는 단지 몇 가지 오류에 그것을 할 필요)

+0

log4net 오류 (문자열, 예외) 방법으로는 충분하지 않습니다. 이? – CodeMonkeyKing

+1

@CodeMonkeyKing - 나는 OP가 그가 예외가없는 몇몇 시나리오에서 스택 추적을 기록하려고한다고 말합니다. –

답변

11

예 - 당신이 패턴 레이아웃에 다음과 같은 패턴을 사용하여이 스택 정보를 얻을 수 있습니다 :

%type %file %line %method %location %class 

자세한 내용은 PatternLayout의 this 설명서를 참조하십시오. 아래 이안의 의견에 응답

편집 : 내가하지 log4net 전체 스택을 작성하도록 구성 할 수 있다고 생각합니다.

new StackTrace().ToString()과 같은 것을 사용하여 언제든지 직접 작성할 수 있습니다. 그러나 로깅 구성에서이 설정을 구성 할 수 있는지 묻고 싶습니다.

더 자세히 살펴볼 것이지만, 구성 할 방법이 없으며 자신 만의 레이아웃 클래스를 구현해야 할 것입니다.

편집 ++ OK - 여기 PatternLayout에서 유래하지만, 레이아웃 % 스택에 추가하는 사용자 정의 패턴 레이아웃 클래스입니다.

이 코드는 약간 거칠다. (레이아웃의 끝에서 노트 % 스택)

public class CustomPatternLayout : PatternLayout 
{ 
    public CustomPatternLayout() 
    { 
     this.AddConverter("stack", typeof(StackTraceConverter)); 
    } 
} 

public class StackTraceConverter : PatternLayoutConverter 
{ 
    protected override void Convert(TextWriter writer, LoggingEvent loggingEvent) 
    { 
     var stack = new StackTrace(); 

     var frames = stack.GetFrames(); 
     for (var i = 0; i < frames.Length; i++) 
     { 
      var frame = frames[i]; 

      // if the stack frame corresponds to still being inside the log4net assembly, skip it. 
      if (frame.GetMethod().DeclaringType.Assembly != typeof(LogManager).Assembly) 
      { 
       writer.WriteLine("{0}.{1} line {2}", 
        frame.GetMethod().DeclaringType.FullName, 
        frame.GetMethod().Name, 
        frame.GetFileLineNumber()); 
      } 
     } 
    } 
} 

당신은 다음 패턴의 구성이를 구성 할 수 있습니다 (예를 들어, 당신은 당신이 인쇄하려고하는 스택에 액세스 할 수있는 보안 권한이 없을 수 있습니다) :

<layout type="ScratchPad.CustomPatternLayout,ScratchPad"> 
    <conversionPattern value="%date %-5level %message%newline %type %file %line %method %location %class %stack" /> 
    </layout> 
+0

그 페이지를 raed했을 때 전체 호출 스택이 아닌 호출하는 메서드의 정규화 된 이름 만 % location을 사용했습니다. –

+0

일부 메시지에 콜 스택을 포함하고 싶지만 다른 것은 기본적으로 포함하지 않습니다. (예 : Ilog에 로그.호출 스택을 포함하는 Error()가 자리 잡을 것입니다. –

+0

호출 스택을 작성하는 데 루프를 사용할 필요가 없습니다. StackFrame.ToString에 대한 설명서를 살펴보십시오. http://msdn.microsoft.com/en-us/library/system.diagnostics.stackframe.tostring.aspx – CodeMonkeyKing

2

예외를 잡는 경우에는 전체 스택 추적을 포함하기 때문에 Exception.ToString() 만 기록하면 정상적인 로그 메시지로 사용할 수 있습니다.

2

Robs 대답은 내가 찾은 최고의 것이 었습니다. 다른 사람에게 도움이된다면 예외를 위해 전체 스택 추적을 인쇄하기 위해 약간 확장했습니다.

public class StackTraceConverter : PatternLayoutConverter 
{ 
    private static readonly Assembly _assembly = typeof (PatternLayoutConverter).Assembly; 

    public StackTraceConverter() 
    { 
     base.IgnoresException = false; 
    } 

    protected override void Convert(TextWriter writer, LoggingEvent loggingEvent) 
    { 
     var ex = loggingEvent.ExceptionObject; 
     if (ex == null) 
      return; 
     writer.WriteLine(ex.ToString()); 

     bool displayFilenames = true; // we'll try, but demand may fail 
     var stack = new StackTrace(displayFilenames); 
     int skip = 0; 
     for (var i = 0; i < stack.FrameCount; i++) 
     { 
      var sf = stack.GetFrame(i); 
      var mb = sf.GetMethod(); 
      if (mb != null) 
      { 
       var t = mb.DeclaringType; 
       if (t.Assembly != _assembly) 
       { 
        //this skips the current method and the method catching the exception 
        if (skip < 2) 
        { 
         skip++; 
         continue; 
        } 
        writer.Write(" at "); 

        // if there is a type (non global method) print it 
        if (t != null) 
        { 
         writer.Write(t.FullName.Replace('+', '.')); 
         writer.Write("."); 
        } 
        writer.Write(mb.Name); 

        // deal with the generic portion of the method 
        if (mb is MethodInfo && mb.IsGenericMethod) 
        { 
         Type[] typars = ((MethodInfo) mb).GetGenericArguments(); 
         writer.Write("["); 
         int k = 0; 
         bool fFirstTyParam = true; 
         while (k < typars.Length) 
         { 
          if (fFirstTyParam == false) 
           writer.Write(","); 
          else 
           fFirstTyParam = false; 

          writer.Write(typars[k].Name); 
          k++; 
         } 
         writer.Write("]"); 
        } 

        // arguments printing 
        writer.Write("("); 
        ParameterInfo[] pi = mb.GetParameters(); 
        bool fFirstParam = true; 
        for (int j = 0; j < pi.Length; j++) 
        { 
         if (fFirstParam == false) 
          writer.Write(", "); 
         else 
          fFirstParam = false; 

         String typeName = "<UnknownType>"; 
         if (pi[j].ParameterType != null) 
          typeName = pi[j].ParameterType.Name; 
         writer.Write(typeName + " " + pi[j].Name); 
        } 
        writer.Write(")"); 

        // source location printing 
        if (displayFilenames && (sf.GetILOffset() != -1)) 
        { 
         // If we don't have a PDB or PDB-reading is disabled for the module, 
         // then the file name will be null. 
         String fileName = null; 

         // Getting the filename from a StackFrame is a privileged operation - we won't want 
         // to disclose full path names to arbitrarily untrusted code. Rather than just omit 
         // this we could probably trim to just the filename so it's still mostly usefull. 
         try 
         { 
          fileName = sf.GetFileName(); 
         } 
         catch (SecurityException) 
         { 
          // If the demand for displaying filenames fails, then it won't 
          // succeed later in the loop. Avoid repeated exceptions by not trying again. 
          displayFilenames = false; 
         } 

         if (fileName != null) 
         { 
          // tack on " in c:\tmp\MyFile.cs:line 5" 
          writer.Write(" in {0}:line {1}", fileName, sf.GetFileLineNumber()); 
         } 
        } 
        writer.WriteLine(); 
       } 
      } 
     } 
    } 
} 
+0

이것은 나에게 잘 맞았습니다 - 감사합니다! 로그 호출에 예외를 포함해야합니다 (예 : 분명히). 'log.Fatal (message, ex)' – Geoff

0

그것은 가장 깨끗한 방법은 아니지만, 이것을 달성하는 빠른 방법은 원하는 스택 추적을 포함하는 인공 예외를 생성하는 것입니다 : 다음

public class ArtificialStackTraceException : Exception 
{ 
    public ArtificialStackTraceException(
     bool shouldIncludeFileInfo = true, 
     string message = "Artificial exception used to generate a stack trace." 
    ) : base(message) 
    { 
     var stackTrace = new System.Diagnostics.StackTrace(shouldIncludeFileInfo); 
     StackTrace = stackTrace.ToString(); 
    } 

    public override string StackTrace { get; } 

    public override string ToString() 
    { 
     return $"{nameof(ArtificialStackTraceException)}:{Environment.NewLine}{StackTrace}"; 
    } 
} 

(full source)

당신이 수를 다음과 같이 사용하십시오 :

Log.Error("It went kaboom", new ArtificialStackTraceException()); 
관련 문제