log4net 메시지에 호출 스택 (예 : 나에게 전화 한 메소드)을 포함시키고 싶습니다. 이 작업을 수행하는 표준 방법이 있습니까?로그 메시지에 호출 스택을 포함하여 log4net 지원을 수행합니까?
(I이 느린 것 알고 있지만, 나는 단지 몇 가지 오류에 그것을 할 필요)
log4net 메시지에 호출 스택 (예 : 나에게 전화 한 메소드)을 포함시키고 싶습니다. 이 작업을 수행하는 표준 방법이 있습니까?로그 메시지에 호출 스택을 포함하여 log4net 지원을 수행합니까?
(I이 느린 것 알고 있지만, 나는 단지 몇 가지 오류에 그것을 할 필요)
예 - 당신이 패턴 레이아웃에 다음과 같은 패턴을 사용하여이 스택 정보를 얻을 수 있습니다 :
%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>
그 페이지를 raed했을 때 전체 호출 스택이 아닌 호출하는 메서드의 정규화 된 이름 만 % location을 사용했습니다. –
일부 메시지에 콜 스택을 포함하고 싶지만 다른 것은 기본적으로 포함하지 않습니다. (예 : Ilog에 로그.호출 스택을 포함하는 Error()가 자리 잡을 것입니다. –
호출 스택을 작성하는 데 루프를 사용할 필요가 없습니다. StackFrame.ToString에 대한 설명서를 살펴보십시오. http://msdn.microsoft.com/en-us/library/system.diagnostics.stackframe.tostring.aspx – CodeMonkeyKing
예외를 잡는 경우에는 전체 스택 추적을 포함하기 때문에 Exception.ToString() 만 기록하면 정상적인 로그 메시지로 사용할 수 있습니다.
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();
}
}
}
}
}
이것은 나에게 잘 맞았습니다 - 감사합니다! 로그 호출에 예외를 포함해야합니다 (예 : 분명히). 'log.Fatal (message, ex)' – Geoff
그것은 가장 깨끗한 방법은 아니지만, 이것을 달성하는 빠른 방법은 원하는 스택 추적을 포함하는 인공 예외를 생성하는 것입니다 : 다음
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}";
}
}
당신이 수를 다음과 같이 사용하십시오 :
Log.Error("It went kaboom", new ArtificialStackTraceException());
log4net 오류 (문자열, 예외) 방법으로는 충분하지 않습니다. 이? – CodeMonkeyKing
@CodeMonkeyKing - 나는 OP가 그가 예외가없는 몇몇 시나리오에서 스택 추적을 기록하려고한다고 말합니다. –