Author: nicko Date: Fri Mar 17 12:26:53 2006 New Revision: 386707 URL: http://svn.apache.org/viewcvs?rev=386707&view=rev Log: Fix for LOG4NET-69. Added new wrapped implementation of String.Format in Transform.StringFormat. This method will not throw exceptions. Added some more exception handling code to the Logger.
Modified: logging/log4net/trunk/extensions/net/1.0/log4net.Ext.Trace/cs/src/TraceLogImpl.cs logging/log4net/trunk/log4net.build logging/log4net/trunk/src/Core/ILogger.cs logging/log4net/trunk/src/Core/LogImpl.cs logging/log4net/trunk/src/Repository/Hierarchy/Logger.cs logging/log4net/trunk/src/Util/Transform.cs Modified: logging/log4net/trunk/extensions/net/1.0/log4net.Ext.Trace/cs/src/TraceLogImpl.cs URL: http://svn.apache.org/viewcvs/logging/log4net/trunk/extensions/net/1.0/log4net.Ext.Trace/cs/src/TraceLogImpl.cs?rev=386707&r1=386706&r2=386707&view=diff ============================================================================== --- logging/log4net/trunk/extensions/net/1.0/log4net.Ext.Trace/cs/src/TraceLogImpl.cs (original) +++ logging/log4net/trunk/extensions/net/1.0/log4net.Ext.Trace/cs/src/TraceLogImpl.cs Fri Mar 17 12:26:53 2006 @@ -1,6 +1,6 @@ #region Copyright & License // -// Copyright 2001-2005 The Apache Software Foundation +// Copyright 2001-2006 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,8 +17,10 @@ #endregion using System; +using System.Globalization; using log4net.Core; +using log4net.Util; namespace log4net.Ext.Trace { @@ -68,7 +70,18 @@ public void TraceFormat(string format, params object[] args) { - Logger.Log(ThisDeclaringType, m_levelTrace, String.Format(format, args), null); + if (IsTraceEnabled) + { + Logger.Log(ThisDeclaringType, m_levelTrace, Transform.StringFormat(CultureInfo.InvariantCulture, format, args), null); + } + } + + public void TraceFormat(IFormatProvider provider, string format, params object[] args) + { + if (IsTraceEnabled) + { + Logger.Log(ThisDeclaringType, m_levelTrace, Transform.StringFormat(provider, format, args), null); + } } public bool IsTraceEnabled Modified: logging/log4net/trunk/log4net.build URL: http://svn.apache.org/viewcvs/logging/log4net/trunk/log4net.build?rev=386707&r1=386706&r2=386707&view=diff ============================================================================== --- logging/log4net/trunk/log4net.build (original) +++ logging/log4net/trunk/log4net.build Fri Mar 17 12:26:53 2006 @@ -399,6 +399,10 @@ </if> <if test="${not temp.build.skip}"> <csc keyfile="${path::combine(log4net.basedir, 'log4net.snk')}" nostdlib="true" noconfig="true" warnaserror="true" target="library" debug="${current.build.debug}" define="${current.build.defines.csc}" output="${current.bin.dir}/log4net.dll" doc="${current.bin.dir}/log4net.xml"> + <nowarn> + <!-- warning CS1058: A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a System.Runtime.CompilerServices.RuntimeWrappedException --> + <warning number="1058" /> + </nowarn> <sources basedir="${log4net.basedir}/src"> <include name="**/*.cs" /> </sources> @@ -437,6 +441,8 @@ <nowarn> <!-- workaround for Mono bug #61902 --> <warning number="0618" /> + <!-- warning CS1058: A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a System.Runtime.CompilerServices.RuntimeWrappedException --> + <warning number="1058" /> </nowarn> <sources basedir="${log4net.basedir}/src"> <include name="**/*.cs" /> @@ -474,6 +480,8 @@ <nowarn> <!-- workaround for Mono bug #61902 --> <warning number="0618" /> + <!-- warning CS1058: A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a System.Runtime.CompilerServices.RuntimeWrappedException --> + <warning number="1058" /> </nowarn> <sources basedir="${log4net.basedir}/src"> <include name="**/*.cs" /> Modified: logging/log4net/trunk/src/Core/ILogger.cs URL: http://svn.apache.org/viewcvs/logging/log4net/trunk/src/Core/ILogger.cs?rev=386707&r1=386706&r2=386707&view=diff ============================================================================== --- logging/log4net/trunk/src/Core/ILogger.cs (original) +++ logging/log4net/trunk/src/Core/ILogger.cs Fri Mar 17 12:26:53 2006 @@ -1,6 +1,6 @@ #region Copyright & License // -// Copyright 2001-2005 The Apache Software Foundation +// Copyright 2001-2006 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -30,6 +30,11 @@ /// <para> /// This interface supports logging events and testing if a level /// is enabled for logging. + /// </para> + /// <para> + /// These methods will not throw exceptions. Note to implementor, ensure + /// that the implementation of these methods cannot allow an exception + /// to be thrown to the caller. /// </para> /// </remarks> /// <author>Nicko Cadell</author> Modified: logging/log4net/trunk/src/Core/LogImpl.cs URL: http://svn.apache.org/viewcvs/logging/log4net/trunk/src/Core/LogImpl.cs?rev=386707&r1=386706&r2=386707&view=diff ============================================================================== --- logging/log4net/trunk/src/Core/LogImpl.cs (original) +++ logging/log4net/trunk/src/Core/LogImpl.cs Fri Mar 17 12:26:53 2006 @@ -1,6 +1,6 @@ #region Copyright & License // -// Copyright 2001-2005 The Apache Software Foundation +// Copyright 2001-2006 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ using System.Globalization; using log4net.Repository; +using log4net.Util; namespace log4net.Core { @@ -215,7 +216,7 @@ { if (IsDebugEnabled) { - Logger.Log(ThisDeclaringType, m_levelDebug, String.Format(CultureInfo.InvariantCulture, format, args), null); + Logger.Log(ThisDeclaringType, m_levelDebug, Transform.StringFormat(CultureInfo.InvariantCulture, format, args), null); } } @@ -241,7 +242,7 @@ { if (IsDebugEnabled) { - Logger.Log(ThisDeclaringType, m_levelDebug, String.Format(provider, format, args), null); + Logger.Log(ThisDeclaringType, m_levelDebug, Transform.StringFormat(provider, format, args), null); } } @@ -320,7 +321,7 @@ { if (IsInfoEnabled) { - Logger.Log(ThisDeclaringType, m_levelInfo, String.Format(CultureInfo.InvariantCulture, format, args), null); + Logger.Log(ThisDeclaringType, m_levelInfo, Transform.StringFormat(CultureInfo.InvariantCulture, format, args), null); } } @@ -346,7 +347,7 @@ { if (IsInfoEnabled) { - Logger.Log(ThisDeclaringType, m_levelInfo, String.Format(provider, format, args), null); + Logger.Log(ThisDeclaringType, m_levelInfo, Transform.StringFormat(provider, format, args), null); } } @@ -425,7 +426,7 @@ { if (IsWarnEnabled) { - Logger.Log(ThisDeclaringType, m_levelWarn, String.Format(CultureInfo.InvariantCulture, format, args), null); + Logger.Log(ThisDeclaringType, m_levelWarn, Transform.StringFormat(CultureInfo.InvariantCulture, format, args), null); } } @@ -451,7 +452,7 @@ { if (IsWarnEnabled) { - Logger.Log(ThisDeclaringType, m_levelWarn, String.Format(provider, format, args), null); + Logger.Log(ThisDeclaringType, m_levelWarn, Transform.StringFormat(provider, format, args), null); } } @@ -530,7 +531,7 @@ { if (IsErrorEnabled) { - Logger.Log(ThisDeclaringType, m_levelError, String.Format(CultureInfo.InvariantCulture, format, args), null); + Logger.Log(ThisDeclaringType, m_levelError, Transform.StringFormat(CultureInfo.InvariantCulture, format, args), null); } } @@ -556,7 +557,7 @@ { if (IsErrorEnabled) { - Logger.Log(ThisDeclaringType, m_levelError, String.Format(provider, format, args), null); + Logger.Log(ThisDeclaringType, m_levelError, Transform.StringFormat(provider, format, args), null); } } @@ -635,7 +636,7 @@ { if (IsFatalEnabled) { - Logger.Log(ThisDeclaringType, m_levelFatal, String.Format(CultureInfo.InvariantCulture, format, args), null); + Logger.Log(ThisDeclaringType, m_levelFatal, Transform.StringFormat(CultureInfo.InvariantCulture, format, args), null); } } @@ -661,7 +662,7 @@ { if (IsFatalEnabled) { - Logger.Log(ThisDeclaringType, m_levelFatal, String.Format(provider, format, args), null); + Logger.Log(ThisDeclaringType, m_levelFatal, Transform.StringFormat(provider, format, args), null); } } Modified: logging/log4net/trunk/src/Repository/Hierarchy/Logger.cs URL: http://svn.apache.org/viewcvs/logging/log4net/trunk/src/Repository/Hierarchy/Logger.cs?rev=386707&r1=386706&r2=386707&view=diff ============================================================================== --- logging/log4net/trunk/src/Repository/Hierarchy/Logger.cs (original) +++ logging/log4net/trunk/src/Repository/Hierarchy/Logger.cs Fri Mar 17 12:26:53 2006 @@ -1,6 +1,6 @@ #region Copyright & License // -// Copyright 2001-2005 The Apache Software Foundation +// Copyright 2001-2006 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -414,12 +414,26 @@ /// Generate a logging event for the specified <paramref name="level"/> using /// the <paramref name="message"/> and <paramref name="exception"/>. /// </para> + /// <para> + /// This method must not throw any exception to the caller. + /// </para> /// </remarks> virtual public void Log(Type callerStackBoundaryDeclaringType, Level level, object message, Exception exception) { - if (IsEnabledFor(level)) + try + { + if (IsEnabledFor(level)) + { + ForcedLog((callerStackBoundaryDeclaringType != null) ? callerStackBoundaryDeclaringType : ThisDeclaringType, level, message, exception); + } + } + catch (Exception ex) { - ForcedLog((callerStackBoundaryDeclaringType != null) ? callerStackBoundaryDeclaringType : ThisDeclaringType , level, message, exception); + log4net.Util.LogLog.Error("Log: Exception while logging", ex); + } + catch + { + log4net.Util.LogLog.Error("Log: Exception while logging"); } } @@ -432,17 +446,29 @@ /// <para> /// Logs the specified logging event through this logger. /// </para> + /// <para> + /// This method must not throw any exception to the caller. + /// </para> /// </remarks> - virtual public void Log(LoggingEvent logEvent) + virtual public void Log(LoggingEvent logEvent) { - if (logEvent == null) + try + { + if (logEvent != null) + { + if (IsEnabledFor(logEvent.Level)) + { + ForcedLog(logEvent); + } + } + } + catch (Exception ex) { - throw new ArgumentNullException("logEvent"); + log4net.Util.LogLog.Error("Log: Exception while logging", ex); } - - if (IsEnabledFor(logEvent.Level)) + catch { - ForcedLog(logEvent); + log4net.Util.LogLog.Error("Log: Exception while logging"); } } @@ -457,14 +483,32 @@ /// <para> /// Test if this logger is going to log events of the specified <paramref name="level"/>. /// </para> + /// <para> + /// This method must not throw any exception to the caller. + /// </para> /// </remarks> - virtual public bool IsEnabledFor(Level level) + virtual public bool IsEnabledFor(Level level) { - if (m_hierarchy.IsDisabled(level)) + try + { + if (level != null) + { + if (m_hierarchy.IsDisabled(level)) + { + return false; + } + return level >= this.EffectiveLevel; + } + } + catch (Exception ex) + { + log4net.Util.LogLog.Error("Log: Exception while logging", ex); + } + catch { - return false; + log4net.Util.LogLog.Error("Log: Exception while logging"); } - return level >= this.EffectiveLevel; + return false; } /// <summary> Modified: logging/log4net/trunk/src/Util/Transform.cs URL: http://svn.apache.org/viewcvs/logging/log4net/trunk/src/Util/Transform.cs?rev=386707&r1=386706&r2=386707&view=diff ============================================================================== --- logging/log4net/trunk/src/Util/Transform.cs (original) +++ logging/log4net/trunk/src/Util/Transform.cs Fri Mar 17 12:26:53 2006 @@ -1,6 +1,6 @@ #region Copyright & License // -// Copyright 2001-2005 The Apache Software Foundation +// Copyright 2001-2006 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -51,7 +51,7 @@ #endregion Private Instance Constructors - #region Public Static Methods + #region XML String Methods /// <summary> /// Write a string to an <see cref="XmlWriter"/> @@ -137,8 +137,158 @@ return INVALIDCHARS.Replace(textData, mask); } - #endregion Public Static Methods + #endregion XML String Methods + #region StringFormat + + /// <summary> + /// Replaces the format item in a specified <see cref="System.String"/> with the text equivalent + /// of the value of a corresponding <see cref="System.Object"/> instance in a specified array. + /// A specified parameter supplies culture-specific formatting information. + /// </summary> + /// <param name="provider">An <see cref="System.IFormatProvider"/> that supplies culture-specific formatting information.</param> + /// <param name="format">A <see cref="System.String"/> containing zero or more format items.</param> + /// <param name="args">An <see cref="System.Object"/> array containing zero or more objects to format.</param> + /// <returns> + /// A copy of format in which the format items have been replaced by the <see cref="System.String"/> + /// equivalent of the corresponding instances of <see cref="System.Object"/> in args. + /// </returns> + /// <remarks> + /// <para> + /// This method does not throw exceptions. If an exception thrown while formatting the result the + /// exception and arguments are returned in the result string. + /// </para> + /// </remarks> + public static string StringFormat(IFormatProvider provider, string format, params object[] args) + { + try + { + // The format is missing, log null value + if (format == null) + { + return null; + } + + // The args are missing - should not happen unless we are called explicitly with a null array + if (args == null) + { + return format; + } + + // Try to format the string + return String.Format(provider, format, args); + } + catch(Exception ex) + { + log4net.Util.LogLog.Error("StringFormat: Exception while rendering format ["+format+"]", ex); + return StringFormatError(ex, format, args); + } + catch + { + log4net.Util.LogLog.Error("StringFormat: Exception while rendering format ["+format+"]"); + return StringFormatError(null, format, args); + } + } + + /// <summary> + /// Process an error during StringFormat + /// </summary> + private static string StringFormatError(Exception formatException, string format, object[] args) + { + try + { + StringBuilder buf = new StringBuilder("<log4net.Error>"); + + if (formatException != null) + { + buf.Append("Exception during StringFormat: ").Append(formatException.Message); + } + else + { + buf.Append("Exception during StringFormat"); + } + buf.Append(" <format>").Append(format).Append("</format>"); + buf.Append("<args>"); + RenderArray(args, buf); + buf.Append("</args>"); + buf.Append("</log4net.Error>"); + + return buf.ToString(); + } + catch(Exception ex) + { + log4net.Util.LogLog.Error("StringFormat: INTERNAL ERROR during StringFormat error handling", ex); + return "<log4net.Error>Exception during StringFormat. See Internal Log.</log4net.Error>"; + } + catch + { + log4net.Util.LogLog.Error("StringFormat: INTERNAL ERROR during StringFormat error handling"); + return "<log4net.Error>Exception during StringFormat. See Internal Log.</log4net.Error>"; + } + } + + /// <summary> + /// Dump the contents of an array into a string builder + /// </summary> + private static void RenderArray(Array array, StringBuilder buffer) + { + if (array == null) + { + buffer.Append(SystemInfo.NullText); + } + else + { + if (array.Rank != 1) + { + buffer.Append(array.ToString()); + } + else + { + buffer.Append("{"); + int len = array.Length; + + if (len > 0) + { + RenderObject(array.GetValue(0), buffer); + for (int i = 1; i < len; i++) + { + buffer.Append(", "); + RenderObject(array.GetValue(i), buffer); + } + } + buffer.Append("}"); + } + } + } + + /// <summary> + /// Dump an object to a string + /// </summary> + private static void RenderObject(Object obj, StringBuilder buffer) + { + if (obj == null) + { + buffer.Append(SystemInfo.NullText); + } + else + { + try + { + buffer.Append(obj); + } + catch(Exception ex) + { + buffer.Append("<Exception: ").Append(ex.Message).Append(">"); + } + catch + { + buffer.Append("<Exception>"); + } + } + } + + #endregion StringFormat + #region Private Helper Methods /// <summary>