* DiagnosticsConfigurationHandler.cs: Rename ValidateIntegralValue
[mono.git] / mcs / class / System / System.Diagnostics / DefaultTraceListener.cs
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
10 //
11 // (C) 2002 Jonathan Pryor
12 // (C) 2007 Novell, Inc.
13 //
14
15 //
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.
34 //
35
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;
44
45 namespace System.Diagnostics {
46 #if NET_2_0
47 #else
48         [ComVisible(false)]
49 #endif
50         public class DefaultTraceListener : TraceListener {
51
52                 private static readonly bool OnWin32;
53
54                 private const string ConsoleOutTrace = "Console.Out";
55                 private const string ConsoleErrorTrace = "Console.Error";
56
57                 private static readonly string MonoTracePrefix;
58                 private static readonly string MonoTraceFile;
59
60                 private static readonly object messageBoxButtonsAbortRetryIgnore;
61                 private static readonly MethodInfo msgboxShow;
62
63                 static DefaultTraceListener ()
64                 {
65                         // Determine what platform we're on.  This impacts how where we send
66                         // messages.  On Win32 platforms (OnWin32 = true), we use the
67                         // `OutputDebugString' api.
68                         //
69                         // On Linux platforms, we use MONO_TRACE_LISTENER to figure things out.  See the
70                         // API documentation for more information on MONO_TRACE_LISTENER.
71                         OnWin32 = (Path.DirectorySeparatorChar == '\\');
72
73                         if (!OnWin32) {
74 #if TARGET_JVM
75                                 string trace = java.lang.System.getProperty("MONO_TRACE");
76 #else
77                                 // If we're running on Unix, we don't have OutputDebugString.
78                                 // Instead, send output to...wherever the MONO_TRACE_LISTENER environment
79                                 // variables says to.
80                                 String trace = Environment.GetEnvironmentVariable("MONO_TRACE_LISTENER");
81 #endif
82
83                                 if (trace != null) {
84                                         string file = null;
85                                         string prefix = null;
86
87                                         if (trace.StartsWith (ConsoleOutTrace)) {
88                                                 file = ConsoleOutTrace;
89                                                 prefix = GetPrefix (trace, ConsoleOutTrace);
90                                         }
91                                         else if (trace.StartsWith (ConsoleErrorTrace)) {
92                                                 file = ConsoleErrorTrace;
93                                                 prefix = GetPrefix (trace, ConsoleErrorTrace);
94                                         }
95                                         else {
96                                                 file = trace;
97
98                                                 // We can't firgure out what the prefix would be, as ':' is a
99                                                 // valid filename character.  Thus, arbitrary files don't support
100                                                 // prefixes.
101                                                 //
102                                                 // I don't consider this to be a major issue.  Prefixes are useful 
103                                                 // with Console.Out and Console.Error to help separate trace
104                                                 // output from the actual program output.  Writing to an arbitrary
105                                                 // file doesn't introduce issues with disambiguation.
106                                                 prefix = "";
107                                         }
108
109                                         MonoTraceFile = file;
110                                         MonoTracePrefix = prefix;
111                                 }
112                         }
113
114                         // AssertUiEnabled support
115                         try {
116                                 Assembly wfAsm = Assembly.Load (Consts.AssemblySystem_Windows_Forms);
117                                 if (wfAsm != null) {
118                                         Type buttons = wfAsm.GetType ("System.Windows.Forms.MessageBoxButtons");
119                                         messageBoxButtonsAbortRetryIgnore = Enum.Parse (buttons, "AbortRetryIgnore");
120                                         msgboxShow = wfAsm.GetType ("System.Windows.Forms.MessageBox").GetMethod ("Show", new Type [] {typeof (string), typeof (string), buttons});
121                                 }
122                         } catch {
123                                 // failed to load the assembly (likely when
124                                 // MWF is not installed).
125                         }
126                 }
127
128                 /**
129                  * Get the prefix for the specified variable.
130                  *
131                  * "Prefixes" are used in the MONO_TRACE_LISTENER variable, and specify text that
132                  * should precede each message printed to the console.  The prefix is
133                  * appended to the console location with a colon (':') separating them.
134                  * For example, if MONO_TRACE_LISTENER is "Console.Out:** my prefix", the prefix is
135                  * "** my prefix".
136                  *
137                  * Everything after the colon, if the colon is present, is used as the
138                  * prefix.
139                  *
140                  * @param       var             The current MONO_TRACE_LISTENER variable
141                  * @param       target  The name of the output location, e.g. "Console.Out"
142                  */
143                 private static string GetPrefix (string var, string target)
144                 {
145                         // actually, we permit any character to separate `target' and the prefix;
146                         // we just skip over target the ':' would be.  This means that a space or
147                         // anything else would suffice, as long as it was only a single
148                         // character.
149                         if (var.Length > target.Length)
150                                 return var.Substring (target.Length + 1);
151                         return "";
152                 }
153
154                 private string logFileName = null;
155
156                 private bool assertUiEnabled = true;
157
158                 public DefaultTraceListener () : base ("Default")
159                 {
160                 }
161
162                 public bool AssertUiEnabled {
163                         get { return assertUiEnabled; }
164                         set { assertUiEnabled = value; }
165                 }
166
167                 [MonoTODO]
168                 public string LogFileName {
169                         get {return logFileName;}
170                         set {logFileName = value;}
171                 }
172
173                 public override void Fail (string message)
174                 {
175                         base.Fail (message);
176                 }
177
178                 public override void Fail (string message, string detailMessage)
179                 {
180                         base.Fail (message, detailMessage);
181                         if (ProcessUI (message, detailMessage) == DialogResult.Abort)
182                                 Thread.CurrentThread.Abort ();
183                         WriteLine (new StackTrace().ToString());
184                 }
185
186                 DialogResult ProcessUI (string message, string detailMessage)
187                 {
188                         if (!AssertUiEnabled || msgboxShow == null || messageBoxButtonsAbortRetryIgnore == null)
189                                 return DialogResult.None;
190
191                         string caption = String.Format ("Assertion Failed: {0} to quit, {1} to debug, {2} to continue", "Abort", "Retry", "Ignore");
192                         string msg = String.Format ("{0}{1}{2}{1}{1}{3}", message, Environment.NewLine, detailMessage, new StackTrace ());
193
194                         switch (msgboxShow.Invoke (null, new object [] {msg, caption, messageBoxButtonsAbortRetryIgnore}).ToString ()) {
195                         case "Ignore":
196                                 return DialogResult.Ignore;
197                         case "Abort":
198                                 return DialogResult.Abort;
199                         default:
200                                 return DialogResult.Retry;
201                         }
202                 }
203
204                 enum DialogResult {
205                         None,
206                         Retry,
207                         Ignore,
208                         Abort
209                 }
210
211 #if TARGET_JVM
212                 private void WriteDebugString (string message)
213                 {
214 #else
215                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
216                 private extern static void WriteWindowsDebugString (string message);
217
218                 private void WriteDebugString (string message)
219                 {
220                         if (OnWin32)
221                                 WriteWindowsDebugString (message);
222                         else
223 #endif
224                                 WriteMonoTrace (message);
225                 }
226
227                 private void WriteMonoTrace (string message)
228                 {
229                         switch (MonoTraceFile) {
230                         case ConsoleOutTrace:
231                                 Console.Out.Write (message);
232                                 break;
233                         case ConsoleErrorTrace:
234                                 Console.Error.Write (message);
235                                 break;
236                         default:
237                                 WriteLogFile (message, MonoTraceFile);
238                                 break;
239                         }
240                 }
241
242                 private void WritePrefix ()
243                 {
244                         if (!OnWin32) {
245                                 WriteMonoTrace (MonoTracePrefix);
246                         }
247                 }
248
249                 private void WriteImpl (string message)
250                 {
251                         if (NeedIndent) {
252                                 WriteIndent ();
253                                 WritePrefix ();
254                         }
255
256                         WriteDebugString (message);
257
258                         if (Debugger.IsLogging())
259                                 Debugger.Log (0, null, message);
260
261                         WriteLogFile (message, LogFileName);
262                 }
263
264                 private void WriteLogFile (string message, string logFile)
265                 {
266                         string fname = logFile;
267                         if (fname != null && fname.Length != 0) {
268                                 FileInfo info = new FileInfo (fname);
269                                 StreamWriter sw = null;
270
271                                 // Open the file
272                                 try {
273                                         if (info.Exists)
274                                                 sw = info.AppendText ();
275                                         else
276                                                 sw = info.CreateText ();
277                                 }
278                                 catch {
279                                         // We weren't able to open the file for some reason.
280                                         // We can't write to the log file; so give up.
281                                         return;
282                                 }
283
284                                 using (sw) {
285                                         sw.Write (message);
286                                         sw.Flush ();
287                                 }
288                         }
289                 }
290
291                 public override void Write (string message)
292                 {
293                         WriteImpl (message);
294                 }
295
296                 public override void WriteLine (string message)
297                 {
298                         string msg = message + Environment.NewLine;
299                         WriteImpl (msg);
300
301                         NeedIndent = true;
302                 }
303         }
304 }
305