Wow, good catch Ron. I read the docs on that property and didn't think it was related to the output so dismissed it.
Thanks for the help! Jon -----Original Message----- From: Ron Grabowski [mailto:[EMAIL PROTECTED] Sent: Thursday, September 15, 2005 7:02 PM To: Log4NET User Subject: RE: LayoutSkeleton Help I was able to reproduce your exception text outputing after the xml was written. I fixed it by setting the IgnoresException propety to false: public class GSIEventLayout : LayoutSkeleton { public override void ActivateOptions() { IgnoresException = false; } public override void Format(TextWriter writer, LoggingEvent loggingEvent) { writer.Write("<GSIEventLog>"); writer.Write(Environment.NewLine); writer.Write(" <Domain>{0}</Domain>", loggingEvent.Domain); writer.Write(Environment.NewLine); writer.Write("</GSIEventLog>"); writer.WriteLine(); } } Layouts are optional and not all appenders require them. Appenders should know how to process both messages and exceptions. If a layout does not deal with an exception (IgnoreException=true), then the appender will process it. Log4net has the ability to define custom renderers for objects via the renderer node in the log4net config file: <log4net> <renderer renderingClass="Company.Project.Logging.SqlExceptionRenderer" renderedClass="System.Data.SqlClient.SqlException" /> ... </log4net> Its possible that someone would want to render certain exceptions in a special way. For example someone may want to only output the ErrorCode property of an HttpException instead of calling ToString on it. When you extend LayoutSkeleton, the default behavior is for your layout to not process the exception and let the appender handle it. In the case of a RollingFileAppender, the base AppenderSkeleton checks if there are any custom renderers setup and if so delegates the rendering of the exception. If there aren't any custom renderers, AppenderSkeleton uses the DefaultRenderer which basically calls ToString on the exception. That's what is generating the exception message in your log file. Why does the constructor of the commonly used PatternLayout layout keep the default value of IgnoresException=true? Doesn't this mean that the exception message will appear after PatternLayout outputs its text? The short answer is that the ExceptionPatternConverter takes responsibility for handling the exception which in turn notifies the parent layout and in turn notifies the parent appender. The part I'm still fuzzy on is how the ExceptionPatternConverter's IgnoreException property gets bubbled back up to the layout then to the appender which then knows to _not_ output the exception. --- Jon Finley <[EMAIL PROTECTED]> wrote: > Sure thing: > > <appender name="RollingLogFileAppender2" > type="log4net.Appender.RollingFileAppender"> > <param name="File" value="Test1-log2.txt" /> > <param name="AppendToFile" value="true" /> > <param name="MaxSizeRollBackups" value="5" /> > <param name="MaximumFileSize" value="2MB" /> > <param name="RollingStyle" value="Size" /> > <param name="StaticLogFileName" value="true" /> > <layout type="log4net.Ext.GSI.GSIEventLayout" /> > </appender> > > The complete layout class is: > using System; > using System.IO; > using log4net.Core; > using log4net.Layout; > > namespace log4net.Ext.GSI > { > public class GSIEventLayout : LayoutSkeleton > { > private PatternLayout m_nestedLayout; > > public override void ActivateOptions() > { > this.IgnoresException = true; > this.Footer = ""; > this.Header = ""; > } > > public override void Format(TextWriter writer, LoggingEvent > loggingEvent) > { > writer.Write("<GSIEventLog>"); > writer.Write("<Domain>" + loggingEvent.Domain + "</Domain>"); > writer.Write("<ClassName>" + > loggingEvent.LocationInformation.ClassName + "</ClassName>"); > writer.Write("<RenderedMessage>" + > loggingEvent.RenderedMessage + "</message>"); > writer.Write("<HostName>" + > loggingEvent.LookupProperty("log4net:HostName").ToString() + > "</HostName>"); > writer.Write("<Identity>" + loggingEvent.UserName + "</Identity>"); > writer.Write("<LoggerName>" + > loggingEvent.LoggerName + "</LoggerName>"); > writer.Write("<ThreadName>" + > loggingEvent.ThreadName + "</ThreadName>"); > writer.Write("<TimeStamp>" + loggingEvent.TimeStamp > + "</TimeStamp>"); > writer.Write("<EventId>" + > loggingEvent.LookupProperty("EventId").ToString() + "</EventId>"); > writer.Write("<Message2>" + > loggingEvent.LookupProperty("Message").ToString() + "</Message2>"); > writer.Write("<AppUser>" + > loggingEvent.LookupProperty("AppUser").ToString() + "</AppUser>"); > writer.Write("<SourceId>" + > loggingEvent.LookupProperty("SourceId").ToString() + "</SourceId>"); > writer.Write("<ExMessage>" + > loggingEvent.ExceptionObject.Message + "</ExMessage>"); > writer.Write("<ExStackTrace>" + > loggingEvent.ExceptionObject.StackTrace + "</ExStackTrace>"); > writer.Write("</GSIEventLog>"); > > writer.WriteLine(); > } > > public PatternLayout PatternLayout > { > get { return m_nestedLayout; } > set { m_nestedLayout = value; } > } > } > } > > > -----Original Message----- > From: Ron Grabowski [mailto:[EMAIL PROTECTED] > Sent: Thursday, September 15, 2005 4:04 PM > To: Log4NET User > Subject: RE: LayoutSkeleton Help > > Could you post the complete appender node that is using this layout? > > --- Jon Finley <[EMAIL PROTECTED]> wrote: > > > That line is loading the exception text inside the appropriate XML > > element. > > > > Using UltraEdit to view the results. > > > > If every element from the layout is removed, the only thing that > shows > > up is the exception text. > > > > If elements are removed one at a time, I see the correct XML but > still > > get the exception text appended to the output. > > > > Jon > > > > -----Original Message----- > > From: Ron Grabowski [mailto:[EMAIL PROTECTED] > > Sent: Thursday, September 15, 2005 3:41 PM > > To: Log4NET User > > Subject: RE: LayoutSkeleton Help > > > > What about this line: > > > > writer.Write("<RenderedMessage>" + loggingEvent.RenderedMessage + > > "</message>"); > > > > Are you viewing the output in a browser or with a program like > > Notepad? > > > > Have you tried removing all the elements and adding each one back > one > > by one starting from the bottom? > > > > --- Jon Finley <[EMAIL PROTECTED]> wrote: > > > > > No, same issue Leo. Thanks for the catch though, I'm sure it > saved > > me > > > from some troubleshooting down the road. ;-) > > > > > > Jon > > > > > > > > > _____ > > > > > > From: Hart, Leo [mailto:[EMAIL PROTECTED] > > > Sent: Thursday, September 15, 2005 3:16 PM > > > To: Log4NET User > > > Subject: RE: LayoutSkeleton Help > > > > > > > > > It looks like you are missing a "<" in this line: > > > > > > writer.Write("<ClassName>" + > > > loggingEvent.LocationInformation.ClassName + "/ClassName>"); > > > > > > Does that fix the problem? > > > > > > > > > -----Original Message----- > > > From: Jon Finley [mailto:[EMAIL PROTECTED] > > > Sent: Thursday, September 15, 2005 4:13 PM > > > To: 'Log4NET User' > > > Subject: LayoutSkeleton Help > > > > > > > > > > > > Hi, > > > > > > I have a very simple Layout based on LayoutSkeleton that > generates > > XML > > > using the LoggingEvent values. However; the exception text > always > > > prints at the end of the XML. Is there a way to turn this off? > > > > > > My Format routine is as follows: > > > > > > public override void Format(TextWriter writer, > > > LoggingEvent > > > loggingEvent) > > > { > > > writer.Write("<GSIEventLog>"); > > > writer.Write("<Domain>" + loggingEvent.Domain + > > > "</Domain>"); > > > writer.Write("<ClassName>" + > > > loggingEvent.LocationInformation.ClassName + "/ClassName>"); > > > writer.Write("<RenderedMessage>" + > > > loggingEvent.RenderedMessage + "</message>"); > > > writer.Write("<HostName>" + > > > loggingEvent.LookupProperty("log4net:HostName").ToString() + > > > "</HostName>"); > > > writer.Write("<Identity>" + > > > loggingEvent.UserName + "</Identity>"); > > > writer.Write("<LoggerName>" + > > > loggingEvent.LoggerName + "</LoggerName>"); > > > writer.Write("<ThreadName>" + > > > loggingEvent.ThreadName + "</ThreadName>"); > > > writer.Write("<TimeStamp>" + > > > loggingEvent.TimeStamp > > > + "</TimeStamp>"); > > > writer.Write("<EventId>" + > > > loggingEvent.LookupProperty("EventId").ToString() + > "</EventId>"); > > > writer.Write("<Message2>" + > > > loggingEvent.LookupProperty("Message").ToString() + > "</Message2>"); > > > writer.Write("<AppUser>" + > > > loggingEvent.LookupProperty("AppUser").ToString() + > "</AppUser>"); > > > writer.Write("<SourceId>" + > > > loggingEvent.LookupProperty("SourceId").ToString() + > === message truncated ===