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

  1. //------------------------------------------------------------------------------
  2. // <copyright file="TraceSource.cs" company="Microsoft">
  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. // </copyright>
  14. //------------------------------------------------------------------------------
  15. using System;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.Collections.Specialized;
  19. using System.Threading;
  20. using System.Configuration;
  21. using System.Security;
  22. using System.Security.Permissions;
  23. namespace System.Diagnostics
  24. {
  25.     public class TraceSource
  26.     {
  27.         private static List<WeakReference> tracesources = new List<WeakReference>();
  28.        
  29.         private readonly TraceEventCache manager = new TraceEventCache();
  30.         private SourceSwitch internalSwitch;
  31.         private TraceListenerCollection listeners;
  32.         private StringDictionary attributes;
  33.         private SourceLevels switchLevel;
  34.         private string sourceName;
  35.         internal bool _initCalled = false;
  36.         // Whether we've called Initialize already.
  37.         public TraceSource(string name) : this(name, SourceLevels.Off)
  38.         {
  39.         }
  40.        
  41.         public TraceSource(string name, SourceLevels defaultLevel)
  42.         {
  43.             if (name == null)
  44.                 throw new ArgumentNullException("name");
  45.             if (name.Length == 0)
  46.                 throw new ArgumentException("name");
  47.            
  48.             sourceName = name;
  49.             switchLevel = defaultLevel;
  50.            
  51.             // Delay load config to avoid perf (and working set) issues in retail
  52.            
  53.             // Add a weakreference to this source
  54.             lock (tracesources) {
  55.                 tracesources.Add(new WeakReference(this));
  56.             }
  57.         }
  58.        
  59.         private void Initialize()
  60.         {
  61.             if (!_initCalled) {
  62.                 lock (this) {
  63.                     if (_initCalled)
  64.                         return;
  65.                    
  66.                     SourceElementsCollection sourceElements = DiagnosticsConfiguration.Sources;
  67.                    
  68.                     if (sourceElements != null) {
  69.                         SourceElement sourceElement = sourceElements[sourceName];
  70.                         if (sourceElement != null) {
  71.                             if (!String.IsNullOrEmpty(sourceElement.SwitchName)) {
  72.                                 CreateSwitch(sourceElement.SwitchType, sourceElement.SwitchName);
  73.                             }
  74.                             else {
  75.                                 CreateSwitch(sourceElement.SwitchType, sourceName);
  76.                                
  77.                                 if (!String.IsNullOrEmpty(sourceElement.SwitchValue))
  78.                                     internalSwitch.Level = (SourceLevels)Enum.Parse(typeof(SourceLevels), sourceElement.SwitchValue);
  79.                             }
  80.                            
  81.                             listeners = sourceElement.Listeners.GetRuntimeObject();
  82.                            
  83.                             attributes = new StringDictionary();
  84.                             TraceUtils.VerifyAttributes(sourceElement.Attributes, GetSupportedAttributes(), this);
  85.                             attributes.contents = sourceElement.Attributes;
  86.                         }
  87.                         else
  88.                             NoConfigInit();
  89.                     }
  90.                     else
  91.                         NoConfigInit();
  92.                    
  93.                     _initCalled = true;
  94.                 }
  95.             }
  96.         }
  97.        
  98.         private void NoConfigInit()
  99.         {
  100.             internalSwitch = new SourceSwitch(sourceName, switchLevel.ToString());
  101.             listeners = new TraceListenerCollection();
  102.             listeners.Add(new DefaultTraceListener());
  103.             attributes = null;
  104.         }
  105.        
  106.         [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  107.         public void Close()
  108.         {
  109.             // No need to call Initialize()
  110.             if (listeners != null) {
  111.                 // Use global lock
  112.                 lock (TraceInternal.critSec) {
  113.                     foreach (TraceListener listener in listeners) {
  114.                         listener.Close();
  115.                     }
  116.                 }
  117.             }
  118.         }
  119.        
  120.         public void Flush()
  121.         {
  122.             // No need to call Initialize()
  123.             if (listeners != null) {
  124.                 if (TraceInternal.UseGlobalLock) {
  125.                     lock (TraceInternal.critSec) {
  126.                         foreach (TraceListener listener in listeners) {
  127.                             listener.Flush();
  128.                         }
  129.                     }
  130.                 }
  131.                 else {
  132.                     foreach (TraceListener listener in listeners) {
  133.                         if (!listener.IsThreadSafe) {
  134.                             lock (listener) {
  135.                                 listener.Flush();
  136.                             }
  137.                         }
  138.                         else {
  139.                             listener.Flush();
  140.                         }
  141.                     }
  142.                 }
  143.             }
  144.         }
  145.        
  146.         protected internal virtual string[] GetSupportedAttributes()
  147.         {
  148.             return null;
  149.         }
  150.        
  151.         static internal void RefreshAll()
  152.         {
  153.             lock (tracesources) {
  154.                 for (int i = 0; i < tracesources.Count; i++) {
  155.                     TraceSource tracesource = ((TraceSource)tracesources[i].Target);
  156.                     if (tracesource != null) {
  157.                         tracesource.Refresh();
  158.                     }
  159.                 }
  160.             }
  161.         }
  162.        
  163.         internal void Refresh()
  164.         {
  165.             if (!_initCalled) {
  166.                 Initialize();
  167.                 return;
  168.             }
  169.            
  170.             SourceElementsCollection sources = DiagnosticsConfiguration.Sources;
  171.            
  172.             if (sources != null) {
  173.                 SourceElement sourceElement = sources[Name];
  174.                 if (sourceElement != null) {
  175.                    
  176.                     // first check if the type changed
  177.                     if ((String.IsNullOrEmpty(sourceElement.SwitchType) && internalSwitch.GetType() != typeof(SourceSwitch)) || (sourceElement.SwitchType != internalSwitch.GetType().AssemblyQualifiedName)) {
  178.                        
  179.                         if (!String.IsNullOrEmpty(sourceElement.SwitchName)) {
  180.                             CreateSwitch(sourceElement.SwitchType, sourceElement.SwitchName);
  181.                         }
  182.                         else {
  183.                             CreateSwitch(sourceElement.SwitchType, Name);
  184.                            
  185.                             if (!String.IsNullOrEmpty(sourceElement.SwitchValue))
  186.                                 internalSwitch.Level = (SourceLevels)Enum.Parse(typeof(SourceLevels), sourceElement.SwitchValue);
  187.                         }
  188.                     }
  189.                     else if (!String.IsNullOrEmpty(sourceElement.SwitchName)) {
  190.                         // create a new switch if the name changed, otherwise just refresh.
  191.                         if (sourceElement.SwitchName != internalSwitch.DisplayName)
  192.                             CreateSwitch(sourceElement.SwitchType, sourceElement.SwitchName);
  193.                         else
  194.                             internalSwitch.Refresh();
  195.                     }
  196.                     else {
  197.                         // the switchValue changed. Just update our internalSwitch.
  198.                         if (!String.IsNullOrEmpty(sourceElement.SwitchValue))
  199.                             internalSwitch.Level = (SourceLevels)Enum.Parse(typeof(SourceLevels), sourceElement.SwitchValue);
  200.                         else
  201.                             internalSwitch.Level = SourceLevels.Off;
  202.                     }
  203.                    
  204.                     TraceListenerCollection newListenerCollection = new TraceListenerCollection();
  205.                     foreach (ListenerElement listenerElement in sourceElement.Listeners) {
  206.                         TraceListener listener = listeners[listenerElement.Name];
  207.                         if (listener != null) {
  208.                             newListenerCollection.Add(listenerElement.RefreshRuntimeObject(listener));
  209.                         }
  210.                         else {
  211.                             newListenerCollection.Add(listenerElement.GetRuntimeObject());
  212.                         }
  213.                     }
  214.                    
  215.                     TraceUtils.VerifyAttributes(sourceElement.Attributes, GetSupportedAttributes(), this);
  216.                    
  217.                     attributes = new StringDictionary();
  218.                     attributes.contents = sourceElement.Attributes;
  219.                    
  220.                     listeners = newListenerCollection;
  221.                 }
  222.                 else {
  223.                     // there was no config, so clear whatever we have.
  224.                     internalSwitch.Level = switchLevel;
  225.                     listeners.Clear();
  226.                     attributes = null;
  227.                 }
  228.             }
  229.         }
  230.        
  231.         [Conditional("TRACE")]
  232.         public void TraceEvent(TraceEventType eventType, int id)
  233.         {
  234.             // Ensure that config is loaded
  235.             Initialize();
  236.            
  237.             if (internalSwitch.ShouldTrace(eventType) && listeners != null) {
  238.                 if (TraceInternal.UseGlobalLock) {
  239.                     // we lock on the same object that Trace does because we're writing to the same Listeners.
  240.                     lock (TraceInternal.critSec) {
  241.                         for (int i = 0; i < listeners.Count; i++) {
  242.                             TraceListener listener = listeners[i];
  243.                             listener.TraceEvent(manager, Name, eventType, id);
  244.                             if (Trace.AutoFlush)
  245.                                 listener.Flush();
  246.                         }
  247.                     }
  248.                 }
  249.                 else {
  250.                     for (int i = 0; i < listeners.Count; i++) {
  251.                         TraceListener listener = listeners[i];
  252.                         if (!listener.IsThreadSafe) {
  253.                             lock (listener) {
  254.                                 listener.TraceEvent(manager, Name, eventType, id);
  255.                                 if (Trace.AutoFlush)
  256.                                     listener.Flush();
  257.                             }
  258.                         }
  259.                         else {
  260.                             listener.TraceEvent(manager, Name, eventType, id);
  261.                             if (Trace.AutoFlush)
  262.                                 listener.Flush();
  263.                         }
  264.                     }
  265.                 }
  266.                 manager.Clear();
  267.             }
  268.         }
  269.        
  270.         [Conditional("TRACE")]
  271.         public void TraceEvent(TraceEventType eventType, int id, string message)
  272.         {
  273.             // Ensure that config is loaded
  274.             Initialize();
  275.            
  276.             if (internalSwitch.ShouldTrace(eventType) && listeners != null) {
  277.                 if (TraceInternal.UseGlobalLock) {
  278.                     // we lock on the same object that Trace does because we're writing to the same Listeners.
  279.                     lock (TraceInternal.critSec) {
  280.                         for (int i = 0; i < listeners.Count; i++) {
  281.                             TraceListener listener = listeners[i];
  282.                             listener.TraceEvent(manager, Name, eventType, id, message);
  283.                             if (Trace.AutoFlush)
  284.                                 listener.Flush();
  285.                         }
  286.                     }
  287.                 }
  288.                 else {
  289.                     for (int i = 0; i < listeners.Count; i++) {
  290.                         TraceListener listener = listeners[i];
  291.                         if (!listener.IsThreadSafe) {
  292.                             lock (listener) {
  293.                                 listener.TraceEvent(manager, Name, eventType, id, message);
  294.                                 if (Trace.AutoFlush)
  295.                                     listener.Flush();
  296.                             }
  297.                         }
  298.                         else {
  299.                             listener.TraceEvent(manager, Name, eventType, id, message);
  300.                             if (Trace.AutoFlush)
  301.                                 listener.Flush();
  302.                         }
  303.                     }
  304.                 }
  305.                 manager.Clear();
  306.             }
  307.         }
  308.        
  309.         [Conditional("TRACE")]
  310.         public void TraceEvent(TraceEventType eventType, int id, string format, params object[] args)
  311.         {
  312.             // Ensure that config is loaded
  313.             Initialize();
  314.            
  315.             if (internalSwitch.ShouldTrace(eventType) && listeners != null) {
  316.                 if (TraceInternal.UseGlobalLock) {
  317.                     // we lock on the same object that Trace does because we're writing to the same Listeners.
  318.                     lock (TraceInternal.critSec) {
  319.                         for (int i = 0; i < listeners.Count; i++) {
  320.                             TraceListener listener = listeners[i];
  321.                             listener.TraceEvent(manager, Name, eventType, id, format, args);
  322.                             if (Trace.AutoFlush)
  323.                                 listener.Flush();
  324.                         }
  325.                     }
  326.                 }
  327.                 else {
  328.                     for (int i = 0; i < listeners.Count; i++) {
  329.                         TraceListener listener = listeners[i];
  330.                         if (!listener.IsThreadSafe) {
  331.                             lock (listener) {
  332.                                 listener.TraceEvent(manager, Name, eventType, id, format, args);
  333.                                 if (Trace.AutoFlush)
  334.                                     listener.Flush();
  335.                             }
  336.                         }
  337.                         else {
  338.                             listener.TraceEvent(manager, Name, eventType, id, format, args);
  339.                             if (Trace.AutoFlush)
  340.                                 listener.Flush();
  341.                         }
  342.                     }
  343.                 }
  344.                 manager.Clear();
  345.             }
  346.         }
  347.        
  348.         [Conditional("TRACE")]
  349.         public void TraceData(TraceEventType eventType, int id, object data)
  350.         {
  351.             // Ensure that config is loaded
  352.             Initialize();
  353.            
  354.             if (internalSwitch.ShouldTrace(eventType) && listeners != null) {
  355.                 if (TraceInternal.UseGlobalLock) {
  356.                     // we lock on the same object that Trace does because we're writing to the same Listeners.
  357.                     lock (TraceInternal.critSec) {
  358.                         for (int i = 0; i < listeners.Count; i++) {
  359.                             TraceListener listener = listeners[i];
  360.                             listener.TraceData(manager, Name, eventType, id, data);
  361.                             if (Trace.AutoFlush)
  362.                                 listener.Flush();
  363.                         }
  364.                     }
  365.                 }
  366.                 else {
  367.                     for (int i = 0; i < listeners.Count; i++) {
  368.                         TraceListener listener = listeners[i];
  369.                         if (!listener.IsThreadSafe) {
  370.                             lock (listener) {
  371.                                 listener.TraceData(manager, Name, eventType, id, data);
  372.                                 if (Trace.AutoFlush)
  373.                                     listener.Flush();
  374.                             }
  375.                         }
  376.                         else {
  377.                             listener.TraceData(manager, Name, eventType, id, data);
  378.                             if (Trace.AutoFlush)
  379.                                 listener.Flush();
  380.                         }
  381.                     }
  382.                 }
  383.                 manager.Clear();
  384.             }
  385.         }
  386.        
  387.         [Conditional("TRACE")]
  388.         public void TraceData(TraceEventType eventType, int id, params object[] data)
  389.         {
  390.             // Ensure that config is loaded
  391.             Initialize();
  392.            
  393.             if (internalSwitch.ShouldTrace(eventType) && listeners != null) {
  394.                 if (TraceInternal.UseGlobalLock) {
  395.                     // we lock on the same object that Trace does because we're writing to the same Listeners.
  396.                     lock (TraceInternal.critSec) {
  397.                         for (int i = 0; i < listeners.Count; i++) {
  398.                             TraceListener listener = listeners[i];
  399.                             listener.TraceData(manager, Name, eventType, id, data);
  400.                             if (Trace.AutoFlush)
  401.                                 listener.Flush();
  402.                         }
  403.                     }
  404.                 }
  405.                 else {
  406.                     for (int i = 0; i < listeners.Count; i++) {
  407.                         TraceListener listener = listeners[i];
  408.                         if (!listener.IsThreadSafe) {
  409.                             lock (listener) {
  410.                                 listener.TraceData(manager, Name, eventType, id, data);
  411.                                 if (Trace.AutoFlush)
  412.                                     listener.Flush();
  413.                             }
  414.                         }
  415.                         else {
  416.                             listener.TraceData(manager, Name, eventType, id, data);
  417.                             if (Trace.AutoFlush)
  418.                                 listener.Flush();
  419.                         }
  420.                     }
  421.                 }
  422.                 manager.Clear();
  423.             }
  424.         }
  425.        
  426.         [Conditional("TRACE")]
  427.         public void TraceInformation(string message)
  428.         {
  429.             // eventType= TraceEventType.Info, id=0
  430.             // No need to call Initialize()
  431.             TraceEvent(TraceEventType.Information, 0, message, null);
  432.         }
  433.        
  434.         [Conditional("TRACE")]
  435.         public void TraceInformation(string format, params object[] args)
  436.         {
  437.             // No need to call Initialize()
  438.             TraceEvent(TraceEventType.Information, 0, format, args);
  439.         }
  440.        
  441.         [Conditional("TRACE")]
  442.         public void TraceTransfer(int id, string message, Guid relatedActivityId)
  443.         {
  444.             // Ensure that config is loaded
  445.             Initialize();
  446.            
  447.             if (internalSwitch.ShouldTrace(TraceEventType.Transfer) && listeners != null) {
  448.                 if (TraceInternal.UseGlobalLock) {
  449.                     // we lock on the same object that Trace does because we're writing to the same Listeners.
  450.                     lock (TraceInternal.critSec) {
  451.                         for (int i = 0; i < listeners.Count; i++) {
  452.                             TraceListener listener = listeners[i];
  453.                             listener.TraceTransfer(manager, Name, id, message, relatedActivityId);
  454.                             if (Trace.AutoFlush)
  455.                                 listener.Flush();
  456.                         }
  457.                     }
  458.                 }
  459.                 else {
  460.                     for (int i = 0; i < listeners.Count; i++) {
  461.                         TraceListener listener = listeners[i];
  462.                         if (!listener.IsThreadSafe) {
  463.                             lock (listener) {
  464.                                 listener.TraceTransfer(manager, Name, id, message, relatedActivityId);
  465.                                 if (Trace.AutoFlush)
  466.                                     listener.Flush();
  467.                             }
  468.                         }
  469.                         else {
  470.                             listener.TraceTransfer(manager, Name, id, message, relatedActivityId);
  471.                             if (Trace.AutoFlush)
  472.                                 listener.Flush();
  473.                         }
  474.                     }
  475.                 }
  476.                 manager.Clear();
  477.             }
  478.         }
  479.        
  480.         private void CreateSwitch(string typename, string name)
  481.         {
  482.             if (!String.IsNullOrEmpty(typename))
  483.                 internalSwitch = (SourceSwitch)TraceUtils.GetRuntimeObject(typename, typeof(SourceSwitch), name);
  484.             else
  485.                 internalSwitch = new SourceSwitch(name, switchLevel.ToString());
  486.         }
  487.        
  488.         public StringDictionary Attributes {
  489.             get {
  490.                 // Ensure that config is loaded
  491.                 Initialize();
  492.                
  493.                 if (attributes == null)
  494.                     attributes = new StringDictionary();
  495.                
  496.                 return attributes;
  497.             }
  498.         }
  499.        
  500.         public string Name {
  501.             get { return sourceName; }
  502.         }
  503.        
  504.         public TraceListenerCollection Listeners {
  505.             [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  506.             get {
  507.                 // Ensure that config is loaded
  508.                 Initialize();
  509.                
  510.                 return listeners;
  511.             }
  512.         }
  513.        
  514.         public SourceSwitch Switch {
  515.             // No need for security demand here. SourceSwitch.set_Level is protected already.
  516.             get {
  517.                 // Ensure that config is loaded
  518.                 Initialize();
  519.                
  520.                 return internalSwitch;
  521.             }
  522.             [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  523.             set {
  524.                 if (value == null)
  525.                     throw new ArgumentNullException("Switch");
  526.                
  527.                 // Ensure that config is loaded
  528.                 Initialize();
  529.                
  530.                 internalSwitch = value;
  531.             }
  532.         }
  533.     }
  534. }

Developer Fusion