The Labs \ Source Viewer \ SSCLI \ System.Diagnostics \ Log

  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. namespace System.Diagnostics
  16. {
  17.     using System.Runtime.Remoting;
  18.     using System;
  19.     using System.Security.Permissions;
  20.     using System.IO;
  21.     using System.Collections;
  22.     using System.Runtime.CompilerServices;
  23.     using Encoding = System.Text.Encoding;
  24.     using System.Runtime.Versioning;
  25.    
  26.     // LogMessageEventHandlers are triggered when a message is generated which is
  27.     // "on" per its switch.
  28.     //
  29.     // By default, the debugger (if attached) is the only event handler.
  30.     // There is also a "built-in" console device which can be enabled
  31.     // programatically, by registry (specifics....) or environment
  32.     // variables.
  33.     [Serializable()]
  34.     [HostProtection(Synchronization = true, ExternalThreading = true)]
  35.     internal delegate void LogMessageEventHandler(LoggingLevels level, LogSwitch category, string message, StackTrace location);
  36.    
  37.    
  38.     // LogSwitchLevelHandlers are triggered when the level of a LogSwitch is modified
  39.     // NOTE: These are NOT triggered when the log switch setting is changed from the
  40.     // attached debugger.
  41.     //
  42.     [Serializable()]
  43.     internal delegate void LogSwitchLevelHandler(LogSwitch ls, LoggingLevels newLevel);
  44.    
  45.    
  46.     static internal class Log
  47.     {
  48.        
  49.         // Switches allow relatively fine level control of which messages are
  50.         // actually shown. Normally most debugging messages are not shown - the
  51.         // user will typically enable those which are relevant to what is being
  52.         // investigated.
  53.         //
  54.         // An attached debugger can enable or disable which messages will
  55.         // actually be reported to the user through the COM+ debugger
  56.         // services API. This info is communicated to the runtime so only
  57.         // desired events are actually reported to the debugger.
  58.         static internal Hashtable m_Hashtable;
  59.         private static bool m_fConsoleDeviceEnabled;
  60.         private static Stream[] m_rgStream;
  61.         private static int m_iNumOfStreamDevices;
  62.         private static int m_iStreamArraySize;
  63.         //private static StreamWriter pConsole;
  64.         static internal int iNumOfSwitches;
  65.         //private static int iNumOfMsgHandlers;
  66.         //private static int iMsgHandlerArraySize;
  67.         private static LogMessageEventHandler _LogMessageEventHandler;
  68.         private static LogSwitchLevelHandler _LogSwitchLevelHandler;
  69.         private static object locker;
  70.        
  71.         // Constant representing the global switch
  72.         public static readonly LogSwitch GlobalSwitch;
  73.        
  74.        
  75.         static Log()
  76.         {
  77.             m_Hashtable = new Hashtable();
  78.             m_fConsoleDeviceEnabled = false;
  79.             m_rgStream = null;
  80.             m_iNumOfStreamDevices = 0;
  81.             m_iStreamArraySize = 0;
  82.             //pConsole = null;
  83.             //iNumOfMsgHandlers = 0;
  84.             //iMsgHandlerArraySize = 0;
  85.             locker = new object();
  86.            
  87.             // allocate the GlobalSwitch object
  88.             GlobalSwitch = new LogSwitch("Global", "Global Switch for this log");
  89.            
  90.             GlobalSwitch.MinimumLevel = LoggingLevels.ErrorLevel;
  91.         }
  92.        
  93.         public static void AddOnLogMessage(LogMessageEventHandler handler)
  94.         {
  95.             lock (locker)
  96.                 _LogMessageEventHandler = (LogMessageEventHandler)MulticastDelegate.Combine(_LogMessageEventHandler, handler);
  97.         }
  98.        
  99.         public static void RemoveOnLogMessage(LogMessageEventHandler handler)
  100.         {
  101.            
  102.             lock (locker)
  103.                 _LogMessageEventHandler = (LogMessageEventHandler)MulticastDelegate.Remove(_LogMessageEventHandler, handler);
  104.         }
  105.        
  106.         public static void AddOnLogSwitchLevel(LogSwitchLevelHandler handler)
  107.         {
  108.             lock (locker)
  109.                 _LogSwitchLevelHandler = (LogSwitchLevelHandler)MulticastDelegate.Combine(_LogSwitchLevelHandler, handler);
  110.         }
  111.        
  112.         public static void RemoveOnLogSwitchLevel(LogSwitchLevelHandler handler)
  113.         {
  114.             lock (locker)
  115.                 _LogSwitchLevelHandler = (LogSwitchLevelHandler)MulticastDelegate.Remove(_LogSwitchLevelHandler, handler);
  116.         }
  117.        
  118.         static internal void InvokeLogSwitchLevelHandlers(LogSwitch ls, LoggingLevels newLevel)
  119.         {
  120.             LogSwitchLevelHandler handler = _LogSwitchLevelHandler;
  121.             if (handler != null)
  122.                 handler(ls, newLevel);
  123.         }
  124.        
  125.        
  126.         // Property to Enable/Disable ConsoleDevice. Enabling the console device
  127.         // adds the console device as a log output, causing any
  128.         // log messages which make it through filters to be written to the
  129.         // application console. The console device is enabled by default if the
  130.         // ??? registry entry or ??? environment variable is set.
  131.         public static bool IsConsoleEnabled {
  132.             get { return m_fConsoleDeviceEnabled; }
  133.             set { m_fConsoleDeviceEnabled = value; }
  134.         }
  135.        
  136.         // AddStream uses the given stream to create and add a new log
  137.         // device. Any log messages which make it through filters will be written
  138.         // to the stream.
  139.         //
  140.         public static void AddStream(Stream stream)
  141.         {
  142.             if (stream == null)
  143.                 throw new ArgumentNullException("stream");
  144.             if (m_iStreamArraySize <= m_iNumOfStreamDevices) {
  145.                 // increase array size in chunks of 4
  146.                 Stream[] newArray = new Stream[m_iStreamArraySize + 4];
  147.                
  148.                 // copy the old array objects into the new one.
  149.                 if (m_iNumOfStreamDevices > 0)
  150.                     Array.Copy(m_rgStream, newArray, m_iNumOfStreamDevices);
  151.                
  152.                 m_iStreamArraySize += 4;
  153.                
  154.                 m_rgStream = newArray;
  155.             }
  156.            
  157.             m_rgStream[m_iNumOfStreamDevices++] = stream;
  158.         }
  159.        
  160.        
  161.         // Generates a log message. If its switch (or a parent switch) allows the
  162.         // level for the message, it is "broadcast" to all of the log
  163.         // devices.
  164.         //
  165.         public static void LogMessage(LoggingLevels level, string message)
  166.         {
  167.             LogMessage(level, GlobalSwitch, message);
  168.         }
  169.        
  170.         // Generates a log message. If its switch (or a parent switch) allows the
  171.         // level for the message, it is "broadcast" to all of the log
  172.         // devices.
  173.         //
  174.         [ResourceExposure(ResourceScope.None)]
  175.         [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
  176.         public static void LogMessage(LoggingLevels level, LogSwitch logswitch, string message)
  177.         {
  178.             if (logswitch == null)
  179.                 throw new ArgumentNullException("LogSwitch");
  180.            
  181.             if (level < 0)
  182.                 throw new ArgumentOutOfRangeException("level", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  183.            
  184.             // Is logging for this level for this switch enabled?
  185.             if (logswitch.CheckLevel(level) == true) {
  186.                 // Send message for logging
  187.                
  188.                 // first send it to the debugger
  189.                 Debugger.Log((int)level, logswitch.strName, message);
  190.                
  191.                 // Send to the console device
  192.                 if (m_fConsoleDeviceEnabled) {
  193.                     Console.Write(message);
  194.                 }
  195.                
  196.                 // Send it to the streams
  197.                 for (int i = 0; i < m_iNumOfStreamDevices; i++) {
  198.                     StreamWriter sw = new StreamWriter(m_rgStream[i]);
  199.                     sw.Write(message);
  200.                     sw.Flush();
  201.                 }
  202.             }
  203.         }
  204.        
  205. /*
  206.     * Following are convenience entry points; all go through Log()
  207.     * Note that the (Switch switch, String message) variations
  208.     * are preferred.
  209.     */       
  210.         public static void Trace(LogSwitch logswitch, string message)
  211.         {
  212.             LogMessage(LoggingLevels.TraceLevel0, logswitch, message);
  213.         }
  214.        
  215.         public static void Trace(string switchname, string message)
  216.         {
  217.             LogSwitch ls;
  218.             ls = LogSwitch.GetSwitch(switchname);
  219.             LogMessage(LoggingLevels.TraceLevel0, ls, message);
  220.         }
  221.        
  222.         public static void Trace(string message)
  223.         {
  224.             LogMessage(LoggingLevels.TraceLevel0, GlobalSwitch, message);
  225.         }
  226.        
  227.         public static void Status(LogSwitch logswitch, string message)
  228.         {
  229.             LogMessage(LoggingLevels.StatusLevel0, logswitch, message);
  230.         }
  231.        
  232.         public static void Status(string switchname, string message)
  233.         {
  234.             LogSwitch ls;
  235.             ls = LogSwitch.GetSwitch(switchname);
  236.             LogMessage(LoggingLevels.StatusLevel0, ls, message);
  237.         }
  238.        
  239.         public static void Status(string message)
  240.         {
  241.             LogMessage(LoggingLevels.StatusLevel0, GlobalSwitch, message);
  242.         }
  243.        
  244.         public static void Warning(LogSwitch logswitch, string message)
  245.         {
  246.             LogMessage(LoggingLevels.WarningLevel, logswitch, message);
  247.         }
  248.        
  249.         public static void Warning(string switchname, string message)
  250.         {
  251.             LogSwitch ls;
  252.             ls = LogSwitch.GetSwitch(switchname);
  253.             LogMessage(LoggingLevels.WarningLevel, ls, message);
  254.         }
  255.        
  256.         public static void Warning(string message)
  257.         {
  258.             LogMessage(LoggingLevels.WarningLevel, GlobalSwitch, message);
  259.         }
  260.        
  261.         public static void Error(LogSwitch logswitch, string message)
  262.         {
  263.             LogMessage(LoggingLevels.ErrorLevel, logswitch, message);
  264.         }
  265.        
  266.         public static void Error(string switchname, string message)
  267.         {
  268.             LogSwitch ls;
  269.             ls = LogSwitch.GetSwitch(switchname);
  270.             LogMessage(LoggingLevels.ErrorLevel, ls, message);
  271.            
  272.         }
  273.        
  274.         public static void Error(string message)
  275.         {
  276.             LogMessage(LoggingLevels.ErrorLevel, GlobalSwitch, message);
  277.         }
  278.        
  279.         public static void Panic(string message)
  280.         {
  281.             LogMessage(LoggingLevels.PanicLevel, GlobalSwitch, message);
  282.         }
  283.        
  284.        
  285.         // Native method to inform the EE about the creation of a new LogSwitch
  286.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  287.         static internal extern void AddLogSwitch(LogSwitch logSwitch);
  288.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  289.         static internal extern void ModifyLogSwitch(int iNewLevel, string strSwitchName, string strParentName);
  290.     }
  291.    
  292. }

Developer Fusion