1

I'm trying to create a NLog layout config like so:

layout = "${callsite} > ${message} (${exception:format=tostring})"

The output for this layout is (when I test it):

TestProject.Program.Main > exception thrown (System.Exception: exception message)

However, if I try to output a message that doesn't have an exception, it shows up like this:

TestProject.Program.Main > no exception thrown ()

Is there any way to modify this layout so that the parenthesis only show up when there's actually an exception?

Daniel T.
  • 37,212
  • 36
  • 139
  • 206

1 Answers1

0

You could write you own LayoutRenderer like this:

  [LayoutRenderer("MyCustomExceptionLayoutRenderer")]
  class MyCustomExceptionLayoutRenderer : LayoutRenderer
  {
    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {
      if (logEvent.Exception == null)
      {
        builder.Append("no exception thrown");
      }
      else
      {
        //Might want fancier formatting of exception here...
        builder.Append("exception thrown ({0})", logEvent.Exception.ToString());
      }
    }

    protected override int GetEstimatedBufferSize(LogEventInfo logEvent)
    {
      return 100;
    }
  }

I think (but have not tried it) that you could also define your LayoutRenderer to take one (or more parameters) like this:

  public enum BracketOption
  {
    None,
    Parentheses,        // ()
    CurlyBraces,        // {}
    SquareBraces,       // []
    LessThanGreaterThan // <>
  }

  [LayoutRenderer("MyCustomExceptionLayoutRenderer")]
  class MyCustomExceptionLayoutRenderer : LayoutRenderer
  {
    public BracketOption Option { get; set; }

    private string left = "";
    private string right = "";

    public MyCustomExceptionLayoutRenderer()
      :base()
    {
      Option = BracketOption.None;
    }

    protected override void Initialize()
    {
      switch(Option)
      {
        case BracketOption.Parentheses:
          left = "(";
          right = ")";
          break;
        case BracketOption.CurlyBraces:
          left = "{";
          right = "}";
          break;
        case BracketOption.SquareBraces:
          left = "[";
          right = "]";
          break;
        case BracketOption.LessThanGreaterThan:
          left = "<";
          right = ">";
          break;
        case BracketOption.None:
        default:
          left = "";
          right = "";
          break;
      }
    }

    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {
      if (logEvent.Exception == null)
      {
        builder.Append("no exception thrown");
      }
      else
      {
        //Might want fancier formatting of exception here...
        builder.Append(string.Format("exception thrown {0}{1}{2}", 
                        left, logEvent.Exception.ToString(), right);
      }
    }

    protected override int GetEstimatedBufferSize(LogEventInfo logEvent)
    {
      return 100;
    }
  }

To use, add lines like this to NLog.config (or app.config if configuring inline):

<extensions>
  <add assembly="MyNLogExtensions" />
</extensions>

And add to your layout like this:

<targets>
  <target type="Console" layout="Exception: ${MyCustomException}" />
</targets>

The parameterized layout might look like this (not sure of exact format for specifying options):

<targets>
  <target type="Console" layout="Exception: ${MyCustomException:BracketOption=Parentheses}" />
</targets>
wageoghe
  • 27,390
  • 13
  • 88
  • 116
  • Thanks, I'm currently not using NLog but if I ever need to do a conditional layout with it, I'll refer to your answer. – Daniel T. Oct 28 '10 at 19:49
  • FYI, see Pat's answer to this question: http://stackoverflow.com/questions/4091606/most-useful-nlog-configurations for a configuration-only technique that might solve your problem (or the problem you had when you originally asked). Essentially he defines two targets with the same output filename. One target contains the exception layout renderer and one doesn't. The "exception target" gets wrapped in a filtering wrapper that only logs if the length of the value of {exception} is > 0. Anyway, you or someone else might find the information useful. – wageoghe Nov 04 '10 at 21:42