File: infocard\Diagnostics\Managed\Microsoft\InfoCards\Diagnostics\InfocardTrace.cs
Project: ndp\cdf\src\WCF\System.IdentityModel.Selectors.csproj (System.IdentityModel.Selectors)
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
namespace Microsoft.InfoCards.Diagnostics
{
    using System;
    using System.Xml;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Globalization;
    using System.ComponentModel;    //win32exception
    using System.Runtime.InteropServices;
    using System.Runtime.CompilerServices;
    using System.Runtime.ConstrainedExecution;
    using Microsoft.Win32.SafeHandles;
    using System.Security;
    using System.Security.Principal;
    using System.Runtime;
    using System.ServiceModel.Diagnostics;
    using System.Threading;
 
    //
    // For InfoCardBaseException
    //
    using System.IdentityModel.Selectors;
 
    // Summary
    // InfoCardTrace is the main driver class for the managed tracing infrastructure.
    // Essentially it is a wrapper over the Indigo DiagnosticsAndTracing classes. 
    // Externally a facade of simple TraceXXXX calls is provided which 
    // internally thunk across to the indigo classes to perform the work.
    //
    // The trace class also provides support for flowing of correlation ids allowing
    // tracing of requests across process and managed / unmanaged boundaries
    // See the Infocard Tracing documentation at http://team/sites/infocard for
    // detail on configuration and usage.
    //
    // Remarks
    // All functions are thread safe
    // 
    // Example usage looks like:
    // using IDT=Microsoft.InfoCards.Diagnostics.InfoCardTrace
    // IDT.TraceVerbose( InfoCardTraceCode.StoreInvalidKey, myKey );
    // IDT.TraceDebug( "Got an infocard {0} with name {1}", card, card.Name );
    // 
    //
    static class InfoCardTrace
    {
        static class TraceCode
        {
            public const int IdentityModelSelectors = 0xD0000;
            public const int GeneralInformation = TraceCode.IdentityModelSelectors | 0X0001;
            public const int StoreLoading = TraceCode.IdentityModelSelectors | 0X0002;
            public const int StoreBeginTransaction = TraceCode.IdentityModelSelectors | 0X0003;
            public const int StoreCommitTransaction = TraceCode.IdentityModelSelectors | 0X0004;
            public const int StoreRollbackTransaction = TraceCode.IdentityModelSelectors | 0X0005;
            public const int StoreClosing = TraceCode.IdentityModelSelectors | 0X0006;
            public const int StoreFailedToOpenStore = TraceCode.IdentityModelSelectors | 0X0007;
            public const int StoreSignatureNotValid = TraceCode.IdentityModelSelectors | 0X0008;
            public const int StoreDeleting = TraceCode.IdentityModelSelectors | 0X0009;
        }
 
        static Dictionary<int, string> traceCodes = new Dictionary<int, string>(9)
        {
            { TraceCode.GeneralInformation, "GeneralInformation" },
            { TraceCode.StoreLoading, "StoreLoading" },
            { TraceCode.StoreBeginTransaction, "StoreBeginTransaction" },
            { TraceCode.StoreCommitTransaction, "StoreCommitTransaction" },
            { TraceCode.StoreRollbackTransaction, "StoreRollbackTransaction" },
            { TraceCode.StoreClosing, "StoreClosing" },
            { TraceCode.StoreFailedToOpenStore, "StoreFailedToOpenStore" },
            { TraceCode.StoreSignatureNotValid, "StoreSignatureNotValid" },
            { TraceCode.StoreDeleting, "StoreDeleting" },
        };
 
        static string GetTraceString(int traceCode)
        {
            return traceCodes[traceCode];
        }
 
        static string GetMsdnTraceCode(int traceCode)
        {
            return LegacyDiagnosticTrace.GenerateMsdnTraceCode("System.IdentityModel.Selectors", GetTraceString(traceCode));
        }
 
        [DllImport("advapi32",
                CharSet = CharSet.Unicode,
                EntryPoint = "ReportEventW",
                ExactSpelling = true,
                SetLastError = true)]
        private static extern bool ReportEvent([In] SafeHandle hEventLog,
                                               [In] short type,
                                               [In] ushort category,
                                               [In] uint eventID,
                                               [In] byte[] userSID,
                                               [In] short numStrings,
                                               [In] int dataLen,
                                               [In] HandleRef strings,
                                               [In] byte[] rawData);
 
 
 
        //
        // Summary:
        // Provides a wrapper over a handle retrieved by RegisterEventSource
        //
        internal class SafeEventLogHandle : SafeHandle
        {
 
            [DllImport("advapi32",
                    CharSet = CharSet.Unicode,
                    EntryPoint = "RegisterEventSourceW",
                    ExactSpelling = true,
                    SetLastError = true)]
            private static extern SafeEventLogHandle RegisterEventSource(string uncServerName, string sourceName);
 
            [DllImport("advapi32",
                    CharSet = CharSet.Unicode,
                    EntryPoint = "DeregisterEventSource",
                    ExactSpelling = true,
                    SetLastError = true)]
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
            private static extern bool DeregisterEventSource(IntPtr eventLog);
 
            public static SafeEventLogHandle Construct()
            {
                SafeEventLogHandle h = RegisterEventSource(null, InfoCardTrace.InfoCardEventSource);
 
                if (null == h || h.IsInvalid)
                {
                    int error = Marshal.GetLastWin32Error();
                    TraceDebug("failed to registereventsource with error {0}", error);
 
                }
                return h;
            }
            //
            // Summary:
            // Manages the lifetime of a native handle retrieved by register event source.
            // Parameters:
            // handle - the handle to wrap.
            //
            private SafeEventLogHandle()
                : base(IntPtr.Zero, true)
            {
 
 
            }
 
 
            public override bool IsInvalid
            {
                get
                {
                    return (IntPtr.Zero == base.handle);
                }
            }
 
            //
            // Summary:
            // Releases the eventlog handle.
            //
            protected override bool ReleaseHandle()
            {
#pragma warning suppress 56523
                return DeregisterEventSource(base.handle);
 
            }
        }
 
        //
        // Summary:
        // Returns whether the current exception is fatal.
        // Notes:
        // Currently this delegates to the code in ExceptionUtility.cs
        //
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        public static bool IsFatal(Exception e)
        {
            return Fx.IsFatal(e);
        }
 
        public static TimerCallback ThunkCallback(TimerCallback callback)
        {
            return Fx.ThunkCallback(callback);
        }
 
        public static WaitCallback ThunkCallback(WaitCallback callback)
        {
            return Fx.ThunkCallback(callback);
        }
 
        public static void CloseInvalidOutSafeHandle(SafeHandle handle)
        {
            Utility.CloseInvalidOutSafeHandle(handle);
        }
 
        //
        // The event source we log against. May need to be updated should our name change before rtm
        //
 
        const string InfoCardEventSource = "CardSpace 4.0.0.0";
 
 
        //
        // Summary:
        // Writes an audit message to the application's event log
        //
        public static void Audit(EventCode code)
        {
            LogEvent(code, null, EventLogEntryType.Information);
        }
 
        public static void Audit(EventCode code, string message)
        {
            LogEvent(code, message, EventLogEntryType.Information);
        }
        public static void Assert(bool condition, string format, params object[] parameters)
        {
 
            if (condition)
            {
                return;
            }
 
            string message = format;
            if (null != parameters && 0 != parameters.Length)
            {
                message = String.Format(CultureInfo.InvariantCulture, format, parameters);
            }
            TraceDebug("An assertion fired: {0}", message);
#if DEBUG
            // 
            // Let DebugAssert handle this for us....
            // If not in debugger,  Assertion Failed: Abort=Quit, Retry=Debug, Ignore=Continue
            // If in debugger, will hit a DebugBreak()
            //
            DiagnosticUtility.DebugAssert( false, message );
#else
            //
            // Retail assert failfasts service
            //
            FailFast(message);
#endif
 
        }
 
 
        [Conditional("DEBUG")]
        public static void DebugAssert(bool condition, string format, params object[] parameters)
        {
#if DEBUG
            if (condition)
            {
                return;
            }
 
            string message = format;
            if (null != parameters && 0 != parameters.Length)
            {
                message = String.Format( CultureInfo.InvariantCulture, format, parameters );
            }
            TraceDebug( "An assertion fired: {0}", message );
            if (Debugger.IsAttached)
            {
                Debugger.Launch();
                Debugger.Break();
            }
            DiagnosticUtility.DebugAssert( false, message );
            FailFast( message );
#endif
        }
 
 
        // 
        // Facade functions to allow simple call semantics.
        //
        public static void FailFast(string message)
        {
            DiagnosticUtility.FailFast(message);
        }
        [Conditional("DEBUG")]
        public static void TraceVerbose(int traceCode)
        {
            TraceInternal(TraceEventType.Verbose, traceCode, null);
 
        }
        [Conditional("DEBUG")]
        public static void TraceVerbose(int traceCode, params object[] parameters)
        {
            TraceInternal(TraceEventType.Verbose, traceCode, parameters);
        }
        [Conditional("DEBUG")]
        public static void TraceInfo(int traceCode)
        {
            TraceInternal(TraceEventType.Information, traceCode, null);
        }
        [Conditional("DEBUG")]
        public static void TraceInfo(int traceCode, params object[] parameters)
        {
            TraceInternal(TraceEventType.Information, traceCode, parameters);
        }
        [Conditional("DEBUG")]
        public static void TraceWarning(int traceCode)
        {
            TraceInternal(TraceEventType.Warning, traceCode, null);
        }
        [Conditional("DEBUG")]
        public static void TraceWarning(int traceCode, params object[] parameters)
        {
            TraceInternal(TraceEventType.Warning, traceCode, parameters);
        }
        [Conditional("DEBUG")]
        public static void TraceError(int traceCode)
        {
            TraceInternal(TraceEventType.Error, traceCode, null);
        }
        [Conditional("DEBUG")]
        public static void TraceError(int traceCode, params object[] parameters)
        {
            TraceInternal(TraceEventType.Error, traceCode, parameters);
        }
        [Conditional("DEBUG")]
        public static void TraceCritical(int traceCode)
        {
            TraceInternal(TraceEventType.Critical, traceCode, null);
        }
        [Conditional("DEBUG")]
        public static void TraceCritical(int traceCode, params object[] parameters)
        {
            TraceInternal(TraceEventType.Critical, traceCode, parameters);
        }
 
        //
        // Enable the setting of level explicitly.
        //
        [Conditional("DEBUG")]
        public static void Trace(TraceEventType level, int traceCode)
        {
            TraceInternal(level, traceCode, null);
        }
        [Conditional("DEBUG")]
        public static void Trace(TraceEventType level, int traceCode, params object[] parameters)
        {
            TraceInternal(level, traceCode, parameters);
        }
 
        //
        // Summary
        // DebugTrace is an additional level of tracing, intended for 
        // use by the devleopment team during the product development cycle.
        // The trace funcitons need no localization and can be fed arbitrary strings as 
        // the format specifier.
        //
        // Remarks
        // Will be turned off in RETAIL builds.
        // All tracing is done at the VERBOSE level.
        //
        // Parameters
        // format       - a format string using the standard .net string format specifier syntax
        // parameters   - optional parmaters to be embedded in the format string.
        //
        [Conditional("DEBUG")]
        public static void TraceDebug(string format, params object[] parameters)
        {
#if DEBUG
            if (DiagnosticUtility.ShouldTraceVerbose)
            {
 
 
                // Retrieve the string from resources and build the message.
                //
                string message = format;
 
                if (null != parameters && 0 != parameters.Length)
                {
                    message = String.Format( CultureInfo.InvariantCulture, format, parameters );
                }
 
 
                //
                // If we were passed a null message, at least flag it
                //
                if (String.IsNullOrEmpty(message))
                {
                    message = "NULL DEBUG TRACE MESSAGE!";
                }
                //
                // Build a trace message conforming to the ETL trace schema and 
                // call down through the diagnostic support classes to trace the call.
                //
                InfoCardTraceRecord tr = new InfoCardTraceRecord(
                                            GetTraceString(TraceCode.GeneralInformation),
                                            message );
 
                DiagnosticUtility.DiagnosticTrace.TraceEvent(
                                    TraceEventType.Verbose,
                                    TraceCode.GeneralInformation,
                                    SR.GetString(GetTraceString(TraceCode.GeneralInformation)),
                                    GetMsdnTraceCode(TraceCode.GeneralInformation),
                                    tr, null, message);
            }
#endif
        }
 
        [Conditional("DEBUG")]
        public static void TraceDebug(string message)
        {
#if DEBUG
            if (DiagnosticUtility.ShouldTraceVerbose)
            {
 
 
 
                //
                // If we were passed a null message, at least flag it
                //
                if (String.IsNullOrEmpty(message))
                {
                    message = "NULL DEBUG TRACE MESSAGE!";
                }
                //
                // Build a trace message conforming to the ETL trace schema and 
                // call down through the diagnostic support classes to trace the call.
                //
                InfoCardTraceRecord tr = new InfoCardTraceRecord(
                                            GetTraceString(TraceCode.GeneralInformation),
                                            message );
 
                DiagnosticUtility.DiagnosticTrace.TraceEvent(
                                    TraceEventType.Verbose,
                                    TraceCode.GeneralInformation,
                                    SR.GetString(GetTraceString(TraceCode.GeneralInformation)),
                                    GetMsdnTraceCode(TraceCode.GeneralInformation),
                                    tr, null, message);
            }
#endif
        }
 
        //
        // Summary:
        // Logs the event for the appropriate infocard error code. This code should 
        // match the entries in messages,mc
        // Parameters:
        // code         - the event code to log
        // Notes: 
        // This code may need to be extended to support an array of string parameters. We will do this if our event
        // log messages require it.
        // 
        private static void LogEvent(EventCode code, string message, EventLogEntryType type)
        {
 
 
 
 
            using (SafeEventLogHandle handle = SafeEventLogHandle.Construct())
            {
                string parameter = message;
                if (null != handle)
                {
                    if (String.IsNullOrEmpty(parameter))
                    {
                        parameter = SR.GetString(SR.GeneralExceptionMessage);
                    }
 
 
                    //
                    // Report event expects a LPCTSTR* lpStrings. Use GCHandle, instead 
                    // of writing code with unsafe because InfoCard client uses this 
                    // and our client cannot contain any unsafe code.
                    //
 
                    //
                    // This is the array of LPCTSTRs 
                    //
                    IntPtr[] stringRoots = new IntPtr[1];
 
                    //
                    // This is to pin the parameter string itself. Use an array here if you want more than 1 string
                    //
                    GCHandle stringParamHandle = new GCHandle();
 
                    //
                    // This is to pin the pointer to the array of LPCTSTRs
                    //
                    GCHandle stringsRootHandle = new GCHandle();
 
                    try
                    {
                        //
                        // Pin the IntPtrs (ie array of LPCTSTRs)
                        //
                        stringsRootHandle = GCHandle.Alloc(stringRoots, GCHandleType.Pinned);
 
                        //
                        // Pin the parameter string itself
                        //
                        stringParamHandle = GCHandle.Alloc(parameter, GCHandleType.Pinned);
 
                        //
                        // Give the intptr address of the pinned string
                        //
                        stringRoots[0] = stringParamHandle.AddrOfPinnedObject();
 
                        //
                        // From msdn: The interop marshaler passes only the handle [2nd arg to constructor in our case] 
                        // to unmanaged code, and guarantees that the wrapper (passed as the first parameter
                        // to the constructor of the HandleRef) remains alive for the duration of the [PInvoke] call.
                        //
                        HandleRef data = new HandleRef(handle, stringsRootHandle.AddrOfPinnedObject());
 
 
                        SecurityIdentifier sid = WindowsIdentity.GetCurrent().User;
                        byte[] sidBA = new byte[sid.BinaryLength];
                        sid.GetBinaryForm(sidBA, 0);
 
                        if (!ReportEvent(
                                 handle,
                                 (short)type,
                                 (ushort)InfoCardEventCategory.General,
                                 (uint)code,
                                 sidBA,
                                 1,
                                 0,
                                 data,
                                 null))
                        {
                            //
                            // Errors in the eventlog API should be ignored by applications
                            //
                            int error = Marshal.GetLastWin32Error();
                            TraceDebug("Failed to report the event with error {0}", error);
                        }
                    }
                    finally
                    {
                        if (stringsRootHandle.IsAllocated)
                        {
                            stringsRootHandle.Free();
                        }
 
                        if (stringParamHandle.IsAllocated)
                        {
                            stringParamHandle.Free();
                        }
                    }
                }
            }
 
        }
 
        public static void TraceAndLogException(Exception e)
        {
            bool shouldLog = false;
            bool isInformational = false;
            InfoCardBaseException ie = e as InfoCardBaseException;
 
            //
            // We only log if this is an infocard exception that hasnt been previous logged, 
            // and isnt the user cancelled exception.
            //
            if (null != ie && !(ie is UserCancelledException) && !ie.Logged)
            {
                shouldLog = true;
            }
            if (shouldLog)
            {
                //
                // If this is the parent of a previously logged exception then log as
                // informational. 
                // If one of the children is UserCancelled, don't log at all
                //
                Exception current = ie.InnerException;
                while (null != current)
                {
                    if (current is UserCancelledException)
                    {
                        shouldLog = false;
                        break;
                    }
                    else if (current is InfoCardBaseException)
                    {
                        if ((current as InfoCardBaseException).Logged)
                        {
                            isInformational = true;
                        }
                    }
                    current = current.InnerException;
                }
            }
            if (shouldLog)
            {
                EventLogEntryType logType = isInformational ? EventLogEntryType.Information : EventLogEntryType.Error;
                string message = ie.Message;
                if (!isInformational)
                {
                    message = BuildMessage(ie);
                }
                LogEvent((EventCode)ie.NativeHResult, message, logType);
 
            }
            TraceException(e);
        }
 
        private static string BuildMessage(InfoCardBaseException ie)
        {
 
            Exception ex = ie;
            String errString = ex.Message + "\n";
 
            if (null != ex.InnerException)
            {
                while (null != ex.InnerException)
                {
                    errString += String.Format(System.Globalization.CultureInfo.CurrentUICulture,
                                         SR.GetString(SR.InnerExceptionTraceFormat),
                                         ex.InnerException.Message);
                    ex = ex.InnerException;
                }
                errString += String.Format(System.Globalization.CultureInfo.CurrentUICulture,
                                         SR.GetString(SR.CallStackTraceFormat),
                                         ie.ToString());
 
            }
            else
            {
                if (!String.IsNullOrEmpty(Environment.StackTrace))
                {
                    errString += String.Format(System.Globalization.CultureInfo.CurrentUICulture,
                                            SR.GetString(SR.CallStackTraceFormat),
                                            Environment.StackTrace);
                }
            }
 
            return errString;
 
        }
        //
        // Summary:
        // Logs a general exception in the event log
        // Parameters:
        // e        - the exception to log.
        //
        [Conditional("DEBUG")]
        public static void TraceException(Exception e)
        {
            Exception current = e;
            int indent = 0;
            while (null != current)
            {
                TraceDebug("{0}Exception: message={1}\n stack trace={2}",
                                new string(' ', indent * 2),
                                e.Message,
                                e.StackTrace);
                current = current.InnerException;
                indent++;
            }
 
        }
 
        //
        // Summary
        //  Throw an exception and log an error in the event log
        //
        public static Exception ThrowHelperError(Exception e)
        {
            TraceAndLogException(e);
            return DiagnosticUtility.ExceptionUtility.ThrowHelperError(e);
        }
 
 
        //
        // Summary
        // Throw an exception but don't log in the event log
        //
        public static Exception ThrowHelperErrorWithNoLogging(Exception e)
        {
            return DiagnosticUtility.ExceptionUtility.ThrowHelperError(e);
        }
 
 
        //
        // Summary
        //  Throw an exception and log a warning in the event log
        //
        public static Exception ThrowHelperWarning(Exception e)
        {
            TraceAndLogException(e);
            return DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(e);
        }
 
        //
        // Summary
        //  Throw an exception and log a critical event in the event log
        //
        public static Exception ThrowHelperCritical(Exception e)
        {
            TraceAndLogException(e);
            return DiagnosticUtility.ExceptionUtility.ThrowHelperCritical(e);
        }
 
        //
        // Summary:
        // Throws an infocard argument exception. Currently mapped to a communication exception,
        //
        public static void ThrowInvalidArgumentConditional(bool condition, string argument)
        {
            if (condition)
            {
                string message = string.Format(
                                    System.Globalization.CultureInfo.CurrentUICulture,
                                    SR.GetString(SR.ServiceInvalidArgument),
                                    argument);
                throw ThrowHelperError(new InfoCardArgumentException(message));
            }
        }
 
 
 
        //
        // Summary
        //  Throw an ArgumentNullException and log an error in the event log
        //
        public static Exception ThrowHelperArgumentNull(string err)
        {
 
            return DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(err);
        }
 
        //
        // Summary
        //  Throw an ArgumentException and log an error in the event log
        //
        public static Exception ThrowHelperArgument(string message)
        {
            return DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(message);
        }
 
        //
        // Summary
        //  Throw an ArgumentNullException and log an error in the event log
        //
        public static Exception ThrowHelperArgumentNull(string err, string message)
        {
            return DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(err, message);
        }
 
        //
        // Summary
        // The following series of calls enable finer grained control over tracing in the client
        // All calls simply delegate down to the indigo DiagnosticTrace implementation which
        // triggers it's behaviour based on the currently configured listeners.
        //
        // Remarks
        // Typical usage is
        // if( IDT.ShouldTraceVerbose() )
        // {
        //     string toTrace = this.SafeDumpState();
        //     IDT.TraceVerbose( InfocardTraceCode.InfoCardCreated, toTrace );
        // }
        //
        public static bool ShouldTrace(TraceEventType type)
        {
            return DiagnosticUtility.ShouldTrace(type);
        }
        public static bool ShouldTraceCritical
        {
            get { return DiagnosticUtility.ShouldTraceCritical; }
        }
        public static bool ShouldTraceError
        {
            get { return DiagnosticUtility.ShouldTraceError; }
        }
        public static bool ShouldTraceWarning
        {
            get { return DiagnosticUtility.ShouldTraceWarning; }
        }
        public static bool ShouldTraceInformation
        {
            get { return DiagnosticUtility.ShouldTraceInformation; }
        }
        public static bool ShouldTraceVerbose
        {
            get { return DiagnosticUtility.ShouldTraceVerbose; }
        }
 
 
        //
        // Summary
        // Expose the activity ids associated with the current flow of activity.
        // ActivityIDs allow the correlation of events across process and managed / unmanaged bounda
        // Normally they are managed implicitly. The .net runtime will ensure they flow across thread 
        // intra-process ( appdomain ) boundaries, and the indigo runtime will ensure they 
        // flow across indigo interactions ( cross process and cross machine ). 
        // We have a couple of responsibilities:
        // When transitioning from mananged to unmanaged code:
        //      grab the activity id
        //      pass it across to native code through the activityID rpc parameter.
        // When transitioning from unmanaged code
        //      call SetActivityId passing in the received id.
        //
        // Remarks
        // Trace calls automatically attach the activityID on all calls.
        //
        public static Guid GetActivityId()
        {
            return System.Runtime.Diagnostics.DiagnosticTraceBase.ActivityId;
        }
        public static void SetActivityId(Guid activityId)
        {
            //
            // This will trace by default at level verbose. 
            //
            System.Runtime.Diagnostics.DiagnosticTraceBase.ActivityId = activityId;
        }
 
        //
        // Summary
        // The main trace function. Responsible for extracting the appropriate string
        // from the application's resource file, formatting the string with the set of paramters
        // if appropriate, 
        // and passing the request down to the IndigoDiagnostics classes.
        // 
        // Parameters
        // level        - the level to trace at. verbose <= level <= critical
        // code         - the infocard trace code - a unique numeric / string identifier.
        // parameters   - an optional set of parameters used to supply additional diagnostic information
        //
        // Remarks
        // Trace calls automatically attach the activityID on all calls.
        //
        [Conditional("DEBUG")]
        private static void TraceInternal(
                            TraceEventType level,
                            int traceCode,
                            params object[] parameters)
        {
#if DEBUG
            if (DiagnosticUtility.ShouldTrace(level))
            {
                //
                // Retrieve the string from resources and build the message.
                //
#if INFOCARD_CLIENT
                string message = SR.GetString(GetTraceString(traceCode));
#else
                string message = SR.GetString(traceCode);
#endif
                Assert( !String.IsNullOrEmpty( message ), "resource string lookup failed!!!" );
 
                if (!String.IsNullOrEmpty( message ) && null != parameters)
                {
                    try
                    {
                        message = String.Format(
                                    System.Globalization.CultureInfo.CurrentUICulture,
                                    message,
                                    parameters );
                    }
                    catch (FormatException f)
                    {
                        Assert( false, "Invalid format: " + traceCode );
                        TraceException( f );
                        message = SR.GetString( SR.GeneralTraceMessage, traceCode );
 
                    }
 
                }
 
                //
                // Build a trace message conforming to the ETL trace schema and 
                // call down through the diagnostic support classes to trace the call.
                //
                DiagnosticUtility.DiagnosticTrace.TraceEvent( level,
                                            traceCode,
                                    SR.GetString(GetTraceString(traceCode)),
                                    GetMsdnTraceCode(TraceCode.GeneralInformation),
                                    new InfoCardTraceRecord( GetTraceString(traceCode), message ), null, message);
 
            }
#endif
        }
 
 
    }
}