2 // System.Diagnostics.DefaultTraceListener.cs
5 // Jonathan Pryor (jonpryor@vt.edu)
6 // Atsushi Enomoto (atsushi@ximian.com)
8 // Comments from John R. Hicks <angryjohn69@nc.rr.com> original implementation
9 // can be found at: /mcs/docs/apidocs/xml/en/System.Diagnostics
11 // (C) 2002 Jonathan Pryor
12 // (C) 2007 Novell, Inc.
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 using System
.Collections
;
39 using System
.Diagnostics
;
40 using System
.Reflection
;
41 using System
.Runtime
.CompilerServices
;
42 using System
.Runtime
.InteropServices
;
43 using System
.Threading
;
45 namespace System
.Diagnostics
{
50 public class DefaultTraceListener
: TraceListener
{
52 private static readonly bool OnWin32
;
54 private const string ConsoleOutTrace
= "Console.Out";
55 private const string ConsoleErrorTrace
= "Console.Error";
57 private static readonly string MonoTracePrefix
;
58 private static readonly string MonoTraceFile
;
60 static DefaultTraceListener ()
62 // Determine what platform we're on. This impacts how where we send
63 // messages. On Win32 platforms (OnWin32 = true), we use the
64 // `OutputDebugString' api.
66 // On Linux platforms, we use MONO_TRACE_LISTENER to figure things out. See the
67 // API documentation for more information on MONO_TRACE_LISTENER.
68 OnWin32
= (Path
.DirectorySeparatorChar
== '\\');
72 string trace
= java
.lang
.System
.getProperty("MONO_TRACE");
74 // If we're running on Unix, we don't have OutputDebugString.
75 // Instead, send output to...wherever the MONO_TRACE_LISTENER environment
77 String trace
= Environment
.GetEnvironmentVariable("MONO_TRACE_LISTENER");
84 if (trace
.StartsWith (ConsoleOutTrace
)) {
85 file
= ConsoleOutTrace
;
86 prefix
= GetPrefix (trace
, ConsoleOutTrace
);
88 else if (trace
.StartsWith (ConsoleErrorTrace
)) {
89 file
= ConsoleErrorTrace
;
90 prefix
= GetPrefix (trace
, ConsoleErrorTrace
);
95 // We can't firgure out what the prefix would be, as ':' is a
96 // valid filename character. Thus, arbitrary files don't support
99 // I don't consider this to be a major issue. Prefixes are useful
100 // with Console.Out and Console.Error to help separate trace
101 // output from the actual program output. Writing to an arbitrary
102 // file doesn't introduce issues with disambiguation.
106 MonoTraceFile
= file
;
107 MonoTracePrefix
= prefix
;
113 * Get the prefix for the specified variable.
115 * "Prefixes" are used in the MONO_TRACE_LISTENER variable, and specify text that
116 * should precede each message printed to the console. The prefix is
117 * appended to the console location with a colon (':') separating them.
118 * For example, if MONO_TRACE_LISTENER is "Console.Out:** my prefix", the prefix is
121 * Everything after the colon, if the colon is present, is used as the
124 * @param var The current MONO_TRACE_LISTENER variable
125 * @param target The name of the output location, e.g. "Console.Out"
127 private static string GetPrefix (string var, string target
)
129 // actually, we permit any character to separate `target' and the prefix;
130 // we just skip over target the ':' would be. This means that a space or
131 // anything else would suffice, as long as it was only a single
133 if (var.Length
> target
.Length
)
134 return var.Substring (target
.Length
+ 1);
138 private string logFileName
= null;
140 private bool assertUiEnabled
= false;
142 public DefaultTraceListener () : base ("Default")
146 public bool AssertUiEnabled
{
147 get { return assertUiEnabled; }
148 set { assertUiEnabled = value; }
152 public string LogFileName
{
153 get {return logFileName;}
154 set {logFileName = value;}
157 public override void Fail (string message
)
162 public override void Fail (string message
, string detailMessage
)
164 base.Fail (message
, detailMessage
);
165 if (ProcessUI (message
, detailMessage
) == DialogResult
.Abort
)
166 Thread
.CurrentThread
.Abort ();
167 WriteLine (new StackTrace().ToString());
170 DialogResult
ProcessUI (string message
, string detailMessage
)
173 if (!AssertUiEnabled
)
174 return DialogResult
.None
;
176 object messageBoxButtonsAbortRetryIgnore
;
177 MethodInfo msgboxShow
;
180 Assembly wfAsm
= Assembly
.Load (Consts
.AssemblySystem_Windows_Forms
);
182 return DialogResult
.None
;
184 Type buttons
= wfAsm
.GetType ("System.Windows.Forms.MessageBoxButtons");
185 messageBoxButtonsAbortRetryIgnore
= Enum
.Parse (buttons
, "AbortRetryIgnore");
186 msgboxShow
= wfAsm
.GetType ("System.Windows.Forms.MessageBox").GetMethod (
188 new Type
[] {typeof (string), typeof (string), buttons}
);
190 return DialogResult
.None
;
193 if (msgboxShow
== null || messageBoxButtonsAbortRetryIgnore
== null)
194 return DialogResult
.None
;
196 string caption
= String
.Format ("Assertion Failed: {0} to quit, {1} to debug, {2} to continue", "Abort", "Retry", "Ignore");
197 string msg
= String
.Format ("{0}{1}{2}{1}{1}{3}", message
, Environment
.NewLine
, detailMessage
, new StackTrace ());
199 switch (msgboxShow
.Invoke (null, new object [] {msg, caption, messageBoxButtonsAbortRetryIgnore}
).ToString ()) {
201 return DialogResult
.Ignore
;
203 return DialogResult
.Abort
;
205 return DialogResult
.Retry
;
217 private void WriteDebugString (string message
)
220 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
221 private extern static void WriteWindowsDebugString (string message
);
223 private void WriteDebugString (string message
)
226 WriteWindowsDebugString (message
);
229 WriteMonoTrace (message
);
232 private void WriteMonoTrace (string message
)
234 switch (MonoTraceFile
) {
235 case ConsoleOutTrace
:
236 Console
.Out
.Write (message
);
238 case ConsoleErrorTrace
:
239 Console
.Error
.Write (message
);
242 WriteLogFile (message
, MonoTraceFile
);
247 private void WritePrefix ()
250 WriteMonoTrace (MonoTracePrefix
);
254 private void WriteImpl (string message
)
261 WriteDebugString (message
);
263 if (Debugger
.IsLogging())
264 Debugger
.Log (0, null, message
);
266 WriteLogFile (message
, LogFileName
);
269 private void WriteLogFile (string message
, string logFile
)
271 string fname
= logFile
;
272 if (fname
!= null && fname
.Length
!= 0) {
273 FileInfo info
= new FileInfo (fname
);
274 StreamWriter sw
= null;
279 sw
= info
.AppendText ();
281 sw
= info
.CreateText ();
284 // We weren't able to open the file for some reason.
285 // We can't write to the log file; so give up.
296 public override void Write (string message
)
301 public override void WriteLine (string message
)
303 string msg
= message
+ Environment
.NewLine
;