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

  1. //------------------------------------------------------------------------------
  2. // <copyright file="DefaultTraceListener.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. #define DEBUG
  16. #define TRACE
  17. namespace System.Diagnostics
  18. {
  19.     using System;
  20.     using System.IO;
  21.     using System.Text;
  22.     using System.Collections;
  23.     using System.Reflection;
  24.     using System.Runtime.InteropServices;
  25.     using System.Security.Permissions;
  26.     using System.Security;
  27.     using Microsoft.Win32;
  28.     using System.Globalization;
  29.     using System.Runtime.Versioning;
  30.    
  31.     /// <devdoc>
  32.     /// <para>Provides
  33.     /// the default output methods and behavior for tracing.</para>
  34.     /// </devdoc>
  35.     [HostProtection(Synchronization = true)]
  36.     public class DefaultTraceListener : TraceListener
  37.     {
  38.        
  39.         bool assertUIEnabled;
  40.         string logFileName;
  41.         bool settingsInitialized;
  42.         const int internalWriteSize = 16384;
  43.        
  44.        
  45.         /// <devdoc>
  46.         /// <para>Initializes a new instance of the <see cref='System.Diagnostics.DefaultTraceListener'/> class with
  47.         /// Default as its <see cref='System.Diagnostics.TraceListener.Name'/>.</para>
  48.         /// </devdoc>
  49.         public DefaultTraceListener() : base("Default")
  50.         {
  51.         }
  52.        
  53.         /// <devdoc>
  54.         /// <para>[To be supplied.]</para>
  55.         /// </devdoc>
  56.         public bool AssertUiEnabled {
  57.             get {
  58.                 if (!settingsInitialized)
  59.                     InitializeSettings();
  60.                 return assertUIEnabled;
  61.             }
  62.             set {
  63.                 if (!settingsInitialized)
  64.                     InitializeSettings();
  65.                 assertUIEnabled = value;
  66.             }
  67.         }
  68.        
  69.         /// <devdoc>
  70.         /// <para>[To be supplied.]</para>
  71.         /// </devdoc>
  72.         public string LogFileName {
  73.             [ResourceExposure(ResourceScope.Machine)]
  74.             [ResourceConsumption(ResourceScope.Machine)]
  75.             get {
  76.                 if (!settingsInitialized)
  77.                     InitializeSettings();
  78.                 return logFileName;
  79.             }
  80.             [ResourceExposure(ResourceScope.Machine)]
  81.             [ResourceConsumption(ResourceScope.Machine)]
  82.             set {
  83.                 if (!settingsInitialized)
  84.                     InitializeSettings();
  85.                 logFileName = value;
  86.             }
  87.         }
  88.        
  89.         /// <devdoc>
  90.         /// <para>
  91.         /// Emits or displays a message
  92.         /// and a stack trace for an assertion that
  93.         /// always fails.
  94.         /// </para>
  95.         /// </devdoc>
  96.         public override void Fail(string message)
  97.         {
  98.             Fail(message, null);
  99.         }
  100.        
  101.         /// <devdoc>
  102.         /// <para>
  103.         /// Emits or displays messages and a stack trace for an assertion that
  104.         /// always fails.
  105.         /// </para>
  106.         /// </devdoc>
  107.         public override void Fail(string message, string detailMessage)
  108.         {
  109.             StackTrace stack = new StackTrace(true);
  110.             int userStackFrameIndex = 0;
  111.             string stackTrace;
  112.             bool uiPermission = UiPermission;
  113.            
  114.             try {
  115.                 stackTrace = StackTraceToString(stack, userStackFrameIndex, stack.FrameCount - 1);
  116.             }
  117.             catch {
  118.                 stackTrace = "";
  119.             }
  120.            
  121.             WriteAssert(stackTrace, message, detailMessage);
  122.             if (AssertUiEnabled && uiPermission) {
  123.                 AssertWrapper.ShowAssert(stackTrace, stack.GetFrame(userStackFrameIndex), message, detailMessage);
  124.             }
  125.         }
  126.        
  127.         [ResourceExposure(ResourceScope.Machine)]
  128.         [ResourceConsumption(ResourceScope.Machine)]
  129.         private void InitializeSettings()
  130.         {
  131.             // don't use the property setters here to avoid infinite recursion.
  132.             assertUIEnabled = DiagnosticsConfiguration.AssertUIEnabled;
  133.             logFileName = DiagnosticsConfiguration.LogFileName;
  134.             settingsInitialized = true;
  135.         }
  136.        
  137.         private void WriteAssert(string stackTrace, string message, string detailMessage)
  138.         {
  139.             string assertMessage = SR.GetString(SR.DebugAssertBanner) + "\r\n" + SR.GetString(SR.DebugAssertShortMessage) + "\r\n" + message + "\r\n" + SR.GetString(SR.DebugAssertLongMessage) + "\r\n" + detailMessage + "\r\n" + stackTrace;
  140.             WriteLine(assertMessage);
  141.         }
  142.        
  143.         [ResourceExposure(ResourceScope.None)]
  144.         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  145.         private void WriteToLogFile(string message, bool useWriteLine)
  146.         {
  147.             try {
  148.                 FileInfo file = new FileInfo(LogFileName);
  149.                 using (Stream stream = file.Open(FileMode.OpenOrCreate)) {
  150.                     using (StreamWriter writer = new StreamWriter(stream)) {
  151.                         stream.Position = stream.Length;
  152.                         if (useWriteLine)
  153.                             writer.WriteLine(message);
  154.                         else
  155.                             writer.Write(message);
  156.                     }
  157.                 }
  158.             }
  159.             catch (Exception e) {
  160.                 WriteLine(SR.GetString(SR.ExceptionOccurred, LogFileName, e.ToString()), false);
  161.             }
  162.             catch {
  163.                 WriteLine(SR.GetString(SR.ExceptionOccurred, LogFileName, ""), false);
  164.             }
  165.         }
  166.        
  167.        
  168.         // Given a stack trace and start and end frame indexes, construct a
  169.         // callstack that contains method, file and line number information.
  170.         private string StackTraceToString(StackTrace trace, int startFrameIndex, int endFrameIndex)
  171.         {
  172.             StringBuilder sb = new StringBuilder(512);
  173.            
  174.             for (int i = startFrameIndex; i <= endFrameIndex; i++) {
  175.                 StackFrame frame = trace.GetFrame(i);
  176.                 MethodBase method = frame.GetMethod();
  177.                 sb.Append("\r\n at ");
  178.                 if (method.ReflectedType != null) {
  179.                     sb.Append(method.ReflectedType.Name);
  180.                 }
  181.                 else {
  182.                     // This is for global methods and this is what shows up in windbg.
  183.                     sb.Append("<Module>");
  184.                 }
  185.                 sb.Append(".");
  186.                 sb.Append(method.Name);
  187.                 sb.Append("(");
  188.                 ParameterInfo[] parameters = method.GetParameters();
  189.                 for (int j = 0; j < parameters.Length; j++) {
  190.                     ParameterInfo parameter = parameters[j];
  191.                     if (j > 0)
  192.                         sb.Append(", ");
  193.                     sb.Append(parameter.ParameterType.Name);
  194.                     sb.Append(" ");
  195.                     sb.Append(parameter.Name);
  196.                 }
  197.                 sb.Append(") ");
  198.                 sb.Append(frame.GetFileName());
  199.                 int line = frame.GetFileLineNumber();
  200.                 if (line > 0) {
  201.                     sb.Append("(");
  202.                     sb.Append(line.ToString(CultureInfo.InvariantCulture));
  203.                     sb.Append(")");
  204.                 }
  205.             }
  206.             sb.Append("\r\n");
  207.            
  208.             return sb.ToString();
  209.         }
  210.        
  211.         /// <devdoc>
  212.         /// <para>
  213.         /// Writes the output to the OutputDebugString
  214.         /// API and
  215.         /// to System.Diagnostics.Debugger.Log.
  216.         /// </para>
  217.         /// </devdoc>
  218.         public override void Write(string message)
  219.         {
  220.             Write(message, true);
  221.         }
  222.        
  223.         private void Write(string message, bool useLogFile)
  224.         {
  225.             if (NeedIndent)
  226.                 WriteIndent();
  227.            
  228.             // really huge messages mess up both VS and dbmon, so we chop it up into
  229.             // reasonable chunks if it's too big
  230.             if (message == null || message.Length <= internalWriteSize) {
  231.                 internalWrite(message);
  232.             }
  233.             else {
  234.                 int offset;
  235.                 for (offset = 0; offset < message.Length - internalWriteSize; offset += internalWriteSize) {
  236.                     internalWrite(message.Substring(offset, internalWriteSize));
  237.                 }
  238.                 internalWrite(message.Substring(offset));
  239.             }
  240.            
  241.             if (useLogFile && LogFileName.Length != 0)
  242.                 WriteToLogFile(message, false);
  243.         }
  244.        
  245.         void internalWrite(string message)
  246.         {
  247.             if (Debugger.IsLogging()) {
  248.                 Debugger.Log(0, null, message);
  249.             }
  250.             else {
  251.                 if (message == null)
  252.                     SafeNativeMethods.OutputDebugString(String.Empty);
  253.                 else
  254.                     SafeNativeMethods.OutputDebugString(message);
  255.             }
  256.         }
  257.        
  258.         /// <devdoc>
  259.         /// <para>
  260.         /// Writes the output to the OutputDebugString
  261.         /// API and to System.Diagnostics.Debugger.Log
  262.         /// followed by a line terminator. The default line terminator is a carriage return
  263.         /// followed by a line feed (\r\n).
  264.         /// </para>
  265.         /// </devdoc>
  266.         public override void WriteLine(string message)
  267.         {
  268.             WriteLine(message, true);
  269.         }
  270.        
  271.         private void WriteLine(string message, bool useLogFile)
  272.         {
  273.             if (NeedIndent)
  274.                 WriteIndent();
  275.             // I do the concat here to make sure it goes as one call to the output.
  276.             // we would save a stringbuilder operation by calling Write twice.
  277.             Write(message + "\r\n", useLogFile);
  278.             NeedIndent = true;
  279.         }
  280.        
  281.         /// <devdoc>
  282.         /// It returns true if the current permission set allows an assert dialog to be displayed.
  283.         /// </devdoc>
  284.         private static bool UiPermission {
  285.             get {
  286.                 bool uiPermission = false;
  287.                
  288.                 try {
  289.                     new UIPermission(UIPermissionWindow.SafeSubWindows).Demand();
  290.                     uiPermission = true;
  291.                 }
  292.                 catch {
  293.                 }
  294.                 return uiPermission;
  295.             }
  296.         }
  297.     }
  298. }

Developer Fusion