The Labs \ Source Viewer \ SSCLI \ System \ BCLDebug

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*============================================================
  16. **
  17. ** Class: BCLDebug
  18. **
  19. **
  20. ** Purpose: Debugging Macros for use in the Base Class Libraries
  21. **
  22. **
  23. ============================================================*/
  24. namespace System
  25. {
  26.    
  27.     using System.IO;
  28.     using System.Text;
  29.     using System.Runtime.Remoting;
  30.     using System.Diagnostics;
  31.     using Microsoft.Win32;
  32.     using System.Runtime.CompilerServices;
  33.     using System.Runtime.Versioning;
  34.     using System.Security.Permissions;
  35.     using System.Security;
  36.    
  37.     [Serializable()]
  38.     internal enum LogLevel
  39.     {
  40.         Trace = 0,
  41.         Status = 20,
  42.         Warning = 40,
  43.         Error = 50,
  44.         Panic = 100
  45.     }
  46.    
  47.     internal struct SwitchStructure
  48.     {
  49.         internal string name;
  50.         internal int value;
  51.        
  52.         internal SwitchStructure(string n, int v)
  53.         {
  54.             name = n;
  55.             value = v;
  56.         }
  57.     }
  58.    
  59.    
  60.     // Only statics, does not need to be marked with the serializable attribute
  61.     static internal class BCLDebug
  62.     {
  63.         static internal bool m_registryChecked = false;
  64.         static internal bool m_loggingNotEnabled = false;
  65.         static internal bool m_perfWarnings;
  66.         static internal bool m_correctnessWarnings;
  67.         static internal bool m_safeHandleStackTraces;
  68.         #if _DEBUG
  69.         static internal bool m_domainUnloadAdded;
  70.         #endif
  71.         static internal PermissionSet m_MakeConsoleErrorLoggingWork;
  72.        
  73.         static readonly SwitchStructure[] switches = {new SwitchStructure("NLS", 1), new SwitchStructure("SER", 2), new SwitchStructure("DYNIL", 4), new SwitchStructure("REMOTE", 8), new SwitchStructure("BINARY", 16), new SwitchStructure("SOAP", 32), new SwitchStructure("REMOTINGCHANNELS", 64), new SwitchStructure("CACHE", 128), new SwitchStructure("RESMGRFILEFORMAT", 256), new SwitchStructure("PERF", 512),
  74.             //Binary Formatter
  75.             // Soap Formatter
  76.             // .resources files
  77.         new SwitchStructure("CORRECTNESS", 1024), new SwitchStructure("MEMORYFAILPOINT", 2048)};
  78.        
  79.         static readonly LogLevel[] levelConversions = {LogLevel.Panic, LogLevel.Error, LogLevel.Error, LogLevel.Warning, LogLevel.Warning, LogLevel.Status, LogLevel.Status, LogLevel.Trace, LogLevel.Trace, LogLevel.Trace,
  80.         LogLevel.Trace};
  81.        
  82.        
  83.         #if _DEBUG
  84.         static internal void WaitForFinalizers(object sender, EventArgs e)
  85.         {
  86.             if (!m_registryChecked) {
  87.                 CheckRegistry();
  88.             }
  89.             if (m_correctnessWarnings) {
  90.                 GC.GetTotalMemory(true);
  91.                 GC.WaitForPendingFinalizers();
  92.             }
  93.         }
  94.         #endif
  95.        
  96.         [Conditional("_DEBUG")]
  97.         [ResourceExposure(ResourceScope.None)]
  98.         public static void Assert(bool condition, string message)
  99.         {
  100.             #if _DEBUG
  101.             // Speed up debug builds marginally by avoiding the garbage from
  102.             // concatinating "BCL Assert: " and the message.
  103.             if (!condition)
  104.                 System.Diagnostics.Assert.Check(condition, "BCL Assert", message);
  105.             #endif
  106.         }
  107.        
  108.         [Conditional("_LOGGING")]
  109.         public static void Log(string message)
  110.         {
  111.             if (AppDomain.CurrentDomain.IsUnloadingForcedFinalize())
  112.                 return;
  113.             if (!m_registryChecked) {
  114.                 CheckRegistry();
  115.             }
  116.             System.Diagnostics.Log.Trace(message);
  117.             System.Diagnostics.Log.Trace(Environment.NewLine);
  118.         }
  119.        
  120.         [Conditional("_LOGGING")]
  121.         public static void Log(string switchName, string message)
  122.         {
  123.             if (AppDomain.CurrentDomain.IsUnloadingForcedFinalize())
  124.                 return;
  125.             if (!m_registryChecked) {
  126.                 CheckRegistry();
  127.             }
  128.             try {
  129.                 LogSwitch ls;
  130.                 ls = LogSwitch.GetSwitch(switchName);
  131.                 if (ls != null) {
  132.                     System.Diagnostics.Log.Trace(ls, message);
  133.                     System.Diagnostics.Log.Trace(ls, Environment.NewLine);
  134.                 }
  135.             }
  136.             catch {
  137.                 System.Diagnostics.Log.Trace("Exception thrown in logging." + Environment.NewLine);
  138.                 System.Diagnostics.Log.Trace("Switch was: " + ((switchName == null) ? "<null>" : switchName) + Environment.NewLine);
  139.                 System.Diagnostics.Log.Trace("Message was: " + ((message == null) ? "<null>" : message) + Environment.NewLine);
  140.             }
  141.         }
  142.        
  143.         //
  144.         // This code gets called during security startup, so we can't go through Marshal to get the values. This is
  145.         // just a small helper in native code instead of that.
  146.         //
  147.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  148.         private static extern int GetRegistryLoggingValues(out bool loggingEnabled, out bool logToConsole, out int logLevel, out bool perfWarnings, out bool correctnessWarnings, out bool safeHandleStackTraces);
  149.        
  150.         private static void CheckRegistry()
  151.         {
  152.             if (AppDomain.CurrentDomain.IsUnloadingForcedFinalize())
  153.                 return;
  154.             if (m_registryChecked) {
  155.                 return;
  156.             }
  157.            
  158.             m_registryChecked = true;
  159.            
  160.             bool loggingEnabled;
  161.             bool logToConsole;
  162.             int logLevel;
  163.             int facilityValue;
  164.             facilityValue = GetRegistryLoggingValues(out loggingEnabled, out logToConsole, out logLevel, out m_perfWarnings, out m_correctnessWarnings, out m_safeHandleStackTraces);
  165.            
  166.             // Note we can get into some recursive situations where we call
  167.             // ourseves recursively through the .cctor. That's why we have the
  168.             // check for levelConversions == null.
  169.             if (!loggingEnabled) {
  170.                 m_loggingNotEnabled = true;
  171.             }
  172.             if (loggingEnabled && levelConversions != null) {
  173.                 try {
  174.                     //The values returned for the logging levels in the registry don't map nicely onto the
  175.                     //values which we support internally (which are an approximation of the ones that
  176.                     //the System.Diagnostics namespace uses) so we have a quick map.
  177.                     Assert(logLevel >= 0 && logLevel <= 10, "logLevel>=0 && logLevel<=10");
  178.                     logLevel = (int)levelConversions[logLevel];
  179.                    
  180.                     if (facilityValue > 0) {
  181.                         for (int i = 0; i < switches.Length; i++) {
  182.                             if ((switches[i].value & facilityValue) != 0) {
  183.                                 LogSwitch L = new LogSwitch(switches[i].name, switches[i].name, System.Diagnostics.Log.GlobalSwitch);
  184.                                 L.MinimumLevel = (LoggingLevels)logLevel;
  185.                             }
  186.                         }
  187.                         System.Diagnostics.Log.GlobalSwitch.MinimumLevel = (LoggingLevels)logLevel;
  188.                         System.Diagnostics.Log.IsConsoleEnabled = logToConsole;
  189.                     }
  190.                    
  191.                 }
  192.                 catch {
  193.                     //Silently eat any exceptions.
  194.                 }
  195.             }
  196.         }
  197.        
  198.         static internal bool CheckEnabled(string switchName)
  199.         {
  200.             if (AppDomain.CurrentDomain.IsUnloadingForcedFinalize())
  201.                 return false;
  202.             if (!m_registryChecked)
  203.                 CheckRegistry();
  204.             LogSwitch logSwitch = LogSwitch.GetSwitch(switchName);
  205.             if (logSwitch == null) {
  206.                 return false;
  207.             }
  208.             return ((int)logSwitch.MinimumLevel <= (int)LogLevel.Trace);
  209.         }
  210.        
  211.         private static bool CheckEnabled(string switchName, LogLevel level, out LogSwitch logSwitch)
  212.         {
  213.             if (AppDomain.CurrentDomain.IsUnloadingForcedFinalize()) {
  214.                 logSwitch = null;
  215.                 return false;
  216.             }
  217.             logSwitch = LogSwitch.GetSwitch(switchName);
  218.             if (logSwitch == null) {
  219.                 return false;
  220.             }
  221.             return ((int)logSwitch.MinimumLevel <= (int)level);
  222.         }
  223.        
  224.         [Conditional("_LOGGING")]
  225.         public static void Log(string switchName, LogLevel level, params object[] messages)
  226.         {
  227.             if (AppDomain.CurrentDomain.IsUnloadingForcedFinalize())
  228.                 return;
  229.             //Add code to check if logging is enabled in the registry.
  230.             LogSwitch logSwitch;
  231.            
  232.             if (!m_registryChecked) {
  233.                 CheckRegistry();
  234.             }
  235.            
  236.             if (!CheckEnabled(switchName, level, out logSwitch)) {
  237.                 return;
  238.             }
  239.            
  240.             StringBuilder sb = new StringBuilder();
  241.            
  242.             for (int i = 0; i < messages.Length; i++) {
  243.                 string s;
  244.                 try {
  245.                     if (messages[i] == null) {
  246.                         s = "<null>";
  247.                     }
  248.                     else {
  249.                         s = messages[i].ToString();
  250.                     }
  251.                 }
  252.                 catch {
  253.                     s = "<unable to convert>";
  254.                 }
  255.                 sb.Append(s);
  256.             }
  257.             System.Diagnostics.Log.LogMessage((LoggingLevels)((int)level), logSwitch, sb.ToString());
  258.         }
  259.        
  260.         // Note this overload doesn't take a format string. You probably don't
  261.         // want this one.
  262.         [Conditional("_LOGGING")]
  263.         public static void Trace(string switchName, params object[] messages)
  264.         {
  265.             if (m_loggingNotEnabled) {
  266.                 return;
  267.             }
  268.            
  269.             LogSwitch logSwitch;
  270.             if (!CheckEnabled(switchName, LogLevel.Trace, out logSwitch)) {
  271.                 return;
  272.             }
  273.            
  274.             StringBuilder sb = new StringBuilder();
  275.            
  276.             for (int i = 0; i < messages.Length; i++) {
  277.                 string s;
  278.                 try {
  279.                     if (messages[i] == null) {
  280.                         s = "<null>";
  281.                     }
  282.                     else {
  283.                         s = messages[i].ToString();
  284.                     }
  285.                 }
  286.                 catch {
  287.                     s = "<unable to convert>";
  288.                 }
  289.                 sb.Append(s);
  290.             }
  291.            
  292.             sb.Append(Environment.NewLine);
  293.             System.Diagnostics.Log.LogMessage(LoggingLevels.TraceLevel0, logSwitch, sb.ToString());
  294.         }
  295.        
  296.         [Conditional("_LOGGING")]
  297.         public static void Trace(string switchName, string format, params object[] messages)
  298.         {
  299.             if (m_loggingNotEnabled) {
  300.                 return;
  301.             }
  302.            
  303.             LogSwitch logSwitch;
  304.             if (!CheckEnabled(switchName, LogLevel.Trace, out logSwitch)) {
  305.                 return;
  306.             }
  307.            
  308.             StringBuilder sb = new StringBuilder();
  309.             sb.AppendFormat(format, messages);
  310.             sb.Append(Environment.NewLine);
  311.            
  312.             System.Diagnostics.Log.LogMessage(LoggingLevels.TraceLevel0, logSwitch, sb.ToString());
  313.         }
  314.        
  315.         [Conditional("_LOGGING")]
  316.         public static void DumpStack(string switchName)
  317.         {
  318.             LogSwitch logSwitch;
  319.            
  320.             if (!m_registryChecked) {
  321.                 CheckRegistry();
  322.             }
  323.            
  324.             if (!CheckEnabled(switchName, LogLevel.Trace, out logSwitch)) {
  325.                 return;
  326.             }
  327.            
  328.             StackTrace trace = new StackTrace();
  329.             System.Diagnostics.Log.LogMessage(LoggingLevels.TraceLevel0, logSwitch, trace.ToString());
  330.         }
  331.        
  332.         // For logging errors related to the console - we often can't expect to
  333.         // write to stdout if it doesn't exist.
  334.         [Conditional("_DEBUG")]
  335.         [ResourceExposure(ResourceScope.None)]
  336.         // Debug-only extra logging code
  337.         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  338.         static internal void ConsoleError(string msg)
  339.         {
  340.             if (AppDomain.CurrentDomain.IsUnloadingForcedFinalize())
  341.                 return;
  342.            
  343.             if (m_MakeConsoleErrorLoggingWork == null) {
  344.                 PermissionSet perms = new PermissionSet();
  345.                 perms.AddPermission(new EnvironmentPermission(PermissionState.Unrestricted));
  346.                 perms.AddPermission(new FileIOPermission(FileIOPermissionAccess.AllAccess, Path.GetFullPath(".")));
  347.                 m_MakeConsoleErrorLoggingWork = perms;
  348.             }
  349.             m_MakeConsoleErrorLoggingWork.Assert();
  350.            
  351.             using (TextWriter err = File.AppendText("ConsoleErrors.log")) {
  352.                 err.WriteLine(msg);
  353.             }
  354.         }
  355.        
  356.         // For perf-related asserts. On a debug build, set the registry key
  357.         // BCLPerfWarnings to non-zero.
  358.         [Conditional("_DEBUG")]
  359.         [ResourceExposure(ResourceScope.None)]
  360.         static internal void Perf(bool expr, string msg)
  361.         {
  362.             if (AppDomain.CurrentDomain.IsUnloadingForcedFinalize())
  363.                 return;
  364.             if (!m_registryChecked)
  365.                 CheckRegistry();
  366.             if (!m_perfWarnings)
  367.                 return;
  368.            
  369.             if (!expr) {
  370.                 Log("PERF", "BCL Perf Warning: " + msg);
  371.             }
  372.             System.Diagnostics.Assert.Check(expr, "BCL Perf Warning: Your perf may be less than perfect because...", msg);
  373.         }
  374.        
  375.         // For correctness-related asserts. On a debug build, set the registry key
  376.         // BCLCorrectnessWarnings to non-zero.
  377.         [Conditional("_DEBUG")]
  378.         [ResourceExposure(ResourceScope.None)]
  379.         static internal void Correctness(bool expr, string msg)
  380.         {
  381.             #if _DEBUG
  382.             if (AppDomain.CurrentDomain.IsUnloadingForcedFinalize())
  383.                 return;
  384.             if (!m_registryChecked)
  385.                 CheckRegistry();
  386.             if (!m_correctnessWarnings)
  387.                 return;
  388.            
  389.             if (!m_domainUnloadAdded) {
  390.                 m_domainUnloadAdded = true;
  391.                 AppDomain.CurrentDomain.DomainUnload += new EventHandler(WaitForFinalizers);
  392.             }
  393.            
  394.             if (!expr) {
  395.                 Log("CORRECTNESS", "BCL Correctness Warning: " + msg);
  396.             }
  397.             System.Diagnostics.Assert.Check(expr, "BCL Correctness Warning: Your program may not work because...", msg);
  398.             #endif
  399.         }
  400.        
  401.         static internal bool CorrectnessEnabled()
  402.         {
  403.             #if WIN32
  404.             if (AppDomain.CurrentDomain.IsUnloadingForcedFinalize())
  405.                 return false;
  406.             if (!m_registryChecked)
  407.                 CheckRegistry();
  408.             return m_correctnessWarnings;
  409.             #else
  410.             return false;
  411.             #endif // WIN32
  412.         }
  413.        
  414.         // Whether SafeHandles include a stack trace showing where they
  415.         // were allocated. Only useful in checked & debug builds.
  416.         static internal bool SafeHandleStackTracesEnabled {
  417.             get {
  418.                 #if _DEBUG
  419.                 if (!m_registryChecked)
  420.                     CheckRegistry();
  421.                 return m_safeHandleStackTraces;
  422.                 #else
  423.                 return false;
  424.                 #endif
  425.             }
  426.         }
  427.     }
  428. }

Developer Fusion