Does log4net support including the call stack in a log message

后端 未结 4 1820
故里飘歌
故里飘歌 2020-12-06 07:09

I wish to include the call stack (e.g. the methods that called me) in a log4net message. Is there a standard way of doing this?

(I know this will be slow, but I onl

4条回答
  •  长情又很酷
    2020-12-06 07:25

    Robs answer was the best i found, i decided to extend it a little to print the full stack trace only for exceptions if it helps anyone else.

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

提交回复
热议问题