Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way in Log4Net or NLog (or some other logger) to output logs in an execution-stack-nested XML or JSON format?

Is there a way in Log4Net or NLog (or some other logger) to output logs in an execution-stack-nested XML or JSON format, such that if function A() calls B(7) that calls C("something"), it'll output something like:

<Method name="A">
    <Method name="B" params="(int) 7">
        <Method name="C" params="(string) 'something'"/>
    </Method>
</Method>

or even better:

<Method name="A">
    <Method name="B" params="(int) 7">
        <Params>
            <int>7</int>
        </Params>
        <Method name="C">
            <Params>
                <string>something</string>
            </Params>
        </Method>
    </Method>
</Method>

Why? so I'd be able to use (e.g.) XML Notepad or some JSON-viewer (don't know of any remarkable one...) to quickly fold (irrelevant) or unfold (relevant) sub-calls when trying to understand what went wrong. I use PostSharp to log (currently using mere indentation) every method entry/exit and exceptions

like image 873
Tar Avatar asked Dec 22 '13 14:12

Tar


1 Answers

The logging framework doesn't have info about your method boundaries, and so it cannot format the XML appropriately. You can try to extend the framework and pass the additional info into the logging methods.

The easier way to get this output though is to perform all the message formatting in your aspect class and configure the logging framework to output only the message text without any other info.

For example, in log4net configuration:

<layout type="log4net.Layout.PatternLayout">
  <conversionPattern value="%message%newline" />
</layout>

In your aspect's OnEntry method you would open the XML tag (or JSON object), and in the OnExit method close the tag. You can start with the simple example below and optimize the code for your particular case (e.g. initialize the logger instance and formatting strings in RuntimeInitialize, CompileTimeInitialize methods).

[Serializable]
public class XmlLogAttribute : OnMethodBoundaryAspect
{
    public override void OnEntry(MethodExecutionArgs args)
    {
        ILog log = LogManager.GetLogger(args.Method.DeclaringType);
        if (log.IsDebugEnabled)
        {
            log.DebugFormat("<Method name=\"{0}\">", args.Method.Name);
            log.Debug("<Params>");
            foreach (object methodArgument in args.Arguments)
            {
                if (methodArgument == null)
                {
                    log.Debug("<null/>");
                }
                else
                {
                    log.DebugFormat("<{0}>{1}</{0}>", methodArgument.GetType(), methodArgument);
                }
            }
            log.Debug("</Params>");
        }
    }

    public override void OnExit(MethodExecutionArgs args)
    {
        ILog log = LogManager.GetLogger(args.Method.DeclaringType);
        log.Debug("</Method>");
    }
}
like image 117
AlexD Avatar answered Nov 13 '22 12:11

AlexD