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

3

6

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

Alphaalphabet answered 22/12, 2013 at 14:13 Comment(2)
possible duplicate of Log4net xml outputMartz
not a duplicate - the linked question doesn't discuss creating a nested outputFlorencia
F
2

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>");
    }
}
Florencia answered 24/12, 2013 at 11:15 Comment(4)
Basically it's what I do today, but without XML (simple indentation) and no logging framework. So why would I need log4net in that scenario? what added value would it give me?Alphaalphabet
Well, one advantage I see in the logging framework is its configurability. All your project's components just send the messages to the framework and don't care about the rest. While the config can specify various output targets, logging levels, etc. And this can be easily changed according to the current environment.Florencia
AlexD, to improve the performance of this aspect I would initialise the ILog log variable in the RuntimeInitialize method. That way it will not have to reinitialise the logger on each method exit and entry, and given that it should only occur at Debug levels in this code the potential improvement could be immense.Martz
@Martz Sure, it's also common to initialize format strings in CompileTimeInitialize method, where you already have info about your method name, argument names, etc. In this case I didn't want to obscure the example with implementation details.Florencia
M
0

You would have to create your own override of the XmlLayoutBase FormatXml method in log4net.

See a similar answer here

Martz answered 24/12, 2013 at 0:19 Comment(0)
S
0

See stacktrace of log4net PatternLayout. It is obviously expensive to harvest, but should give some results. It is also possible to change the rendering of the log information. In the log4net.Ext.Json project, there's a decorator that could be used to that effect. (I'm the author).

Savoyard answered 23/3, 2016 at 3:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.