Nicko,

Thanks for the response.  This is a bit more challenging that it first
appeared, but I'm hoping it is still solvable.

Seems like there are some options

1)  Set expectations that DebugFormat is simply a convenience method
that wraps string.Format.  Any exceptions are rendered into a string
along with the other parameters via a call to string.Format.  The
rationale is that if you want to include exception for remote
transmission use the Debug methods.  DebugFormat is then understood to
be just a wrapper for string.Format.  Those who want the shortcut then
have the advantage of not needing lots of external string.Format calls.
Code comments could state this too to make sure there is no confusion
("This method calls string.Format using the input arguments, and passes
the result to Debug.  If you need special control over Exceptions, call
Debug directly instead").

2)  Capture the parameters as part of LoggingEvent, and deal with it at
Render time (possible at a remote location)

3)  Overloads (like you presented) that include exception as a direct
parameter.

Would it be acceptible to assume (1)?

If so, then the method is very simple:

public void DebugFormat( string format, params object[] args )
{
        string message = string.Format( format, args );
        Debug( message );
}

If it turns out that special formatting control is needed above the
default Exception.ToString that would occur like this, then maybe the
existing formatting logic could be used

public void DebugFormat( string format, params object[] args )
{
        string message;

        if( ContainsExceptionArgs( args ) )
        {
                object[] inlinedArgs = RenderExceptionsToString( args );
// special formatting of exceptions
                message = string.Format( format, inlinedArgs );
        }
        else
        {       
                message = string.Format( format, args );
        }

        Debug( message );
}

private object[] RenderExceptionsToString( args )
{
        object[] inlined = new object[ args.Length ];
        for( int i=0; i<args.Length; i++ )
        {
                if( args[ i ] is Exception )
                {       
                        inlined[ i ] = RenderException( (Exception)
args[ i ] );
                }
                else
                {
                        inlined[ i ] = args[ i ];
                }
        }
        return inlined;
}

private string RenderException( Exception ex )
{
        ... call LoggingEvent.GetExceptionStrRep() or an equivalent
method to convert the exception to a string
}


What do you think?  Is it OK to assume a DebugFormat method could be
treated as a wrapper for string.Format without needing to generalize it
to forward exceptions?  Would the message need to be rendered specially
or is Exception.ToString (via string.Format) sufficient?  

Is there anything else that would be needed to proceed with this?

-Doug

-----Original Message-----
From: Nicko Cadell [mailto:[EMAIL PROTECTED] 
Sent: Thursday, September 16, 2004 3:07 PM
To: Log4NET Dev
Subject: RE: New code to allow formatting during logging

Doug, 

> I don't see a need to include Exception as a separate argument, since 
> it can be passed as a parameter.  Am I missing something here?

The Exception is not part of the message. It is stored separately in the
LoggingEvent. If, for example, the RemotingAppender is used then the
exception will be serialised and sent to the remoting listener where it
can be desterilised.


> Seems that having it as the first
> parameter is confusing for users since most would try to pass it as a 
> parameter.

I certainly agree that putting the Exception argument first is confusing
for users. It reminds me of the inconsistencies with the
ArgumentNullException:

ArgumentException(message, paramName)
ArgumentNullException(paramName, message)


> Maybe there is something special (related to ExceptionLayout) that is 
> being done above what we get via Exception.ToString that log4net 
> performs and you are trying to preserve this logic?

As above, the Exception is stored seperatly to the message.


>  Is there any way to test the
> parameters and automatically grab the exeception if needed?

The issue with this is how to detect that an exception has been passed
to the DebugFormat method as part of the params array, but it is not
meant to be part of the message. Also how do we really explain this to
users and how discoverable will this be as it won't show up in the
method signature.

This is valid Format string syntax:

string.Format("Exception {0}", exception);

And so it this:

string.Format("Exception {0}", exception, otherException);

Note that you don't have to use all you parameters in the format string.
You can use any parameter zero or more times in any order.

It would be possible to examine the last parameter, and if it is of type
Exception then to see if that index is used anywhere in the format
string. If the last parameter is an Exception and is the 5th item in the
array then we could look for "{4" followed by either "}", ",", or ":".
We would still need to check for the open brace escape "{{". 
That would tell us if the last exception is used in the format string.
If the exception is not used then we could use that as the exception for
the LoggingEvent.

In order to determine if the exception is specified we would need to
examine the whole of the format message string.

The advantage of this method would be to reduce the number of methods in
the interface and reduce confusion as to the placement of method
arguments.
The disadvantages of this are that the complexity of the logging method
is increased, an additional performance overhead is introduced, it does
not conform exactly to the string.Format syntax and it becomes less
discoverable. By discoverable I mean that Visual Studio intellisense
does not inform you as there isn't an exception argument. A user would
need to read the docs to find out that they just pass the exception as
the last argument.

To be honest neither solution is particularly appealing to me.

Nicko



Reply via email to