2010-04-06 Jb Evain <jbevain@novell.com>
[mcs.git] / class / System / System.Diagnostics / DefaultTraceListener.cs
blob2ee3a8ee2da09ca0d8eb4755f67f87edbe96ca23
1 //
2 // System.Diagnostics.DefaultTraceListener.cs
3 //
4 // Authors:
5 // Jonathan Pryor (jonpryor@vt.edu)
6 // Atsushi Enomoto (atsushi@ximian.com)
7 //
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:
23 //
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
26 //
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.
36 using System;
37 using System.IO;
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 {
46 #if NET_2_0
47 #else
48 [ComVisible(false)]
49 #endif
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 == '\\');
70 if (!OnWin32) {
71 #if TARGET_JVM
72 string trace = java.lang.System.getProperty("MONO_TRACE");
73 #else
74 // If we're running on Unix, we don't have OutputDebugString.
75 // Instead, send output to...wherever the MONO_TRACE_LISTENER environment
76 // variables says to.
77 String trace = Environment.GetEnvironmentVariable("MONO_TRACE_LISTENER");
78 #endif
80 if (trace != null) {
81 string file = null;
82 string prefix = null;
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);
92 else {
93 file = trace;
95 // We can't firgure out what the prefix would be, as ':' is a
96 // valid filename character. Thus, arbitrary files don't support
97 // prefixes.
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.
103 prefix = "";
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
119 * "** my prefix".
121 * Everything after the colon, if the colon is present, is used as the
122 * prefix.
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
132 // character.
133 if (var.Length > target.Length)
134 return var.Substring (target.Length + 1);
135 return "";
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; }
151 [MonoTODO]
152 public string LogFileName {
153 get {return logFileName;}
154 set {logFileName = value;}
157 public override void Fail (string message)
159 base.Fail (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;
179 try {
180 Assembly wfAsm = Assembly.Load (Consts.AssemblySystem_Windows_Forms);
181 if (wfAsm == null)
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 (
187 "Show",
188 new Type [] {typeof (string), typeof (string), buttons});
189 } catch {
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 ()) {
200 case "Ignore":
201 return DialogResult.Ignore;
202 case "Abort":
203 return DialogResult.Abort;
204 default:
205 return DialogResult.Retry;
209 enum DialogResult {
210 None,
211 Retry,
212 Ignore,
213 Abort
216 #if TARGET_JVM
217 private void WriteDebugString (string message)
219 #else
220 [MethodImplAttribute(MethodImplOptions.InternalCall)]
221 private extern static void WriteWindowsDebugString (string message);
223 private void WriteDebugString (string message)
225 if (OnWin32)
226 WriteWindowsDebugString (message);
227 else
228 #endif
229 WriteMonoTrace (message);
232 private void WriteMonoTrace (string message)
234 switch (MonoTraceFile) {
235 case ConsoleOutTrace:
236 Console.Out.Write (message);
237 break;
238 case ConsoleErrorTrace:
239 Console.Error.Write (message);
240 break;
241 default:
242 WriteLogFile (message, MonoTraceFile);
243 break;
247 private void WritePrefix ()
249 if (!OnWin32) {
250 WriteMonoTrace (MonoTracePrefix);
254 private void WriteImpl (string message)
256 if (NeedIndent) {
257 WriteIndent ();
258 WritePrefix ();
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;
276 // Open the file
277 try {
278 if (info.Exists)
279 sw = info.AppendText ();
280 else
281 sw = info.CreateText ();
283 catch {
284 // We weren't able to open the file for some reason.
285 // We can't write to the log file; so give up.
286 return;
289 using (sw) {
290 sw.Write (message);
291 sw.Flush ();
296 public override void Write (string message)
298 WriteImpl (message);
301 public override void WriteLine (string message)
303 string msg = message + Environment.NewLine;
304 WriteImpl (msg);
306 NeedIndent = true;