Yet another. Init the gobject type system.
[beagle.git] / Util / Log.cs
blob2ed6c8d998a4807e77cbfa366348124a120538d9
1 //
2 // Log.cs
3 //
4 // Copyright (C) 2004-2005 Novell, Inc.
5 //
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to deal
10 // in the Software without restriction, including without limitation the rights
11 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 // copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in all
16 // copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 // SOFTWARE.
27 using System;
28 using System.Collections;
29 using System.Text;
30 using System.IO;
31 using System.Diagnostics;
33 namespace Beagle.Util {
35 public enum LogLevel {
36 Error,
37 Warn,
38 Debug,
39 Ignored
42 static public class Log {
44 static private string log_directory;
45 static private string log_name_prefix;
46 static private string program_identifier;
47 static private string program_identifier_truncated;
49 // If we don't call Log.Initialize, these defaults ensure that
50 // everything will just get spewed to the console.
51 static private bool running_in_foreground = true;
52 static private LogLevel cutoff_level = LogLevel.Debug;
54 static private TextWriter log_writer;
55 static private TextWriter exception_writer;
56 static private TextWriter foreground_echo_writer;
58 static public LogLevel Level {
59 get { return cutoff_level; }
60 set { cutoff_level = value; }
63 static public void Initialize (string log_directory,
64 string program_identifier,
65 LogLevel cutoff_level,
66 bool running_in_foreground)
68 Log.log_directory = log_directory;
69 Log.program_identifier = program_identifier;
70 Log.cutoff_level = cutoff_level;
71 Log.running_in_foreground = running_in_foreground;
73 PruneOldLogs ();
75 log_name_prefix = String.Format ("{0:yyyy-MM-dd-HH-mm-ss}-", DateTime.Now);
76 program_identifier_truncated = program_identifier.Substring (0, 6);
78 log_writer = NewLogWriter (program_identifier);
79 exception_writer = NewDelayedLogWriter (program_identifier + "Exceptions");
81 TextWriter console_log_writer;
82 console_log_writer = NewDelayedLogWriter (program_identifier + "Console");
84 TextWriter console_redirect_writer;
85 if (running_in_foreground) {
86 foreground_echo_writer = Console.Out;
87 console_redirect_writer = new TeeTextWriter (Console.Out, console_log_writer);
88 } else {
89 console_redirect_writer = console_log_writer;
92 Console.SetOut (console_redirect_writer);
93 Console.SetError (console_redirect_writer);
95 // If we are running in the background, redirect stdin to /dev/null
96 if (! running_in_foreground) {
97 FileStream dev_null_stream = new FileStream ("/dev/null",
98 FileMode.Open,
99 FileAccess.Read,
100 FileShare.ReadWrite);
101 TextReader dev_null_reader = new StreamReader (dev_null_stream);
102 Console.SetIn (dev_null_reader);
106 static public void Disable ()
108 cutoff_level = LogLevel.Ignored;
111 static private void PruneOldLogs ()
113 DateTime magic_date = DateTime.Now.AddDays (-7);
114 DirectoryInfo dir = new DirectoryInfo (log_directory);
116 string current_str;
117 current_str = "current-" + program_identifier;
119 foreach (FileInfo file in dir.GetFiles ()) {
121 // Clean up old symlinks
122 if (file.Name.StartsWith (current_str) && FileSystem.IsSymLink (file.FullName)) {
123 // Work around a Mono bug in which FileInfo.Delete()
124 // doesn't delete dangling symlinks. See
125 // http://bugzilla.ximian.com/show_bug.cgi?id=78664
127 //file.Delete ();
128 File.Delete (file.FullName);
130 continue;
133 int last_dash = file.Name.LastIndexOf ("-");
134 if (last_dash == -1)
135 continue; // skip strange-looking files
137 string date = file.Name.Substring (0, last_dash);
139 try {
140 DateTime log_date;
141 log_date = DateTime.ParseExact (date, "yyyy-MM-dd-HH-mm-ss", null);
142 if (log_date < magic_date)
143 file.Delete ();
144 } catch (Exception e) { }
148 static private TextWriter NewLogWriter (string name)
150 string log_path;
151 log_path = Path.Combine (log_directory, log_name_prefix + name);
153 FileStream stream;
154 stream = new FileStream (log_path,
155 FileMode.CreateNew,
156 FileAccess.Write,
157 FileShare.ReadWrite);
159 StreamWriter writer;
160 writer = new StreamWriter (stream);
161 writer.AutoFlush = true;
163 string log_link;
164 log_link = Path.Combine (log_directory, "current-" + name);
165 Mono.Unix.Native.Syscall.symlink (log_path, log_link);
167 return writer;
170 private class DelayedClosure {
172 string name;
174 public DelayedClosure (string name)
176 this.name = name;
179 public TextWriter Build ()
181 return NewLogWriter (name);
185 static private TextWriter NewDelayedLogWriter (string name)
187 DelayedClosure closure;
188 closure = new DelayedClosure (name);
189 return new DelayedTextWriter (new DelayedTextWriter.Builder (closure.Build));
192 /////////////////////////////////////////////////////////////////////////////////////////
194 static object write_lock = new object ();
196 static private void WriteLine (LogLevel level, string format, object [] args, Exception ex)
198 if (cutoff_level < level)
199 return;
201 string ex_str = null;
202 if (ex != null)
203 ex_str = ex.ToString ();
205 // This only happens if Log.Initialize was never called.
206 if (running_in_foreground && foreground_echo_writer == null)
207 foreground_echo_writer = Console.Out;
209 if (foreground_echo_writer != null) {
210 foreground_echo_writer.Write (level);
211 foreground_echo_writer.Write (": ");
212 if (format != null)
213 foreground_echo_writer.WriteLine (format, args);
214 if (ex_str != null)
215 foreground_echo_writer.WriteLine (ex_str);
216 foreground_echo_writer.Flush ();
219 if (log_writer == null) // i.e. if Log.Initialize has not been called
220 return;
222 StringBuilder prefix_builder;
223 prefix_builder = new StringBuilder ();
224 prefix_builder.Append ('\n'); // start w/ a newline
225 prefix_builder.AppendFormat ("{0:yyMMdd HHmmssffff} {1:00000} ",
226 DateTime.Now, Process.GetCurrentProcess ().Id);
227 prefix_builder.Append (program_identifier_truncated);
229 prefix_builder.Append (' ');
230 switch (level) {
231 case LogLevel.Error:
232 prefix_builder.Append ("ERROR");
233 break;
234 case LogLevel.Warn:
235 prefix_builder.Append (" WARN");
236 break;
237 case LogLevel.Debug:
238 prefix_builder.Append ("DEBUG");
239 break;
240 default:
241 prefix_builder.Append (" HUH?");
242 break;
245 if (ex != null)
246 prefix_builder.Append (" EX");
247 prefix_builder.Append (": ");
249 string prefix;
250 prefix = prefix_builder.ToString ();
252 StringBuilder message;
253 message = new StringBuilder ();
254 message.Append (prefix);
255 message.Remove (0, 1); // remove leading \n
256 if (format != null)
257 message.AppendFormat (format, args);
258 if (ex_str != null) {
259 if (format != null)
260 message.Append ('\n');
261 message.Append (ex_str);
263 message.Replace ("\n", prefix);
265 string message_str;
266 message_str = message.ToString ();
268 lock (write_lock) {
269 log_writer.WriteLine (message_str);
270 if (ex != null && exception_writer != null)
271 exception_writer.WriteLine (message_str);
275 /////////////////////////////////////////////////////////////////////////////////////////
277 static public void Debug (string message, params object [] args)
279 WriteLine (LogLevel.Debug, message, args, null);
282 static public void Debug (Exception ex, string message, params object [] args)
284 WriteLine (LogLevel.Debug, message, args, ex);
287 static public void Debug (Exception ex)
289 WriteLine (LogLevel.Debug, null, null, ex);
292 static public void Info (string message, params object [] args)
294 // The Info log level is deprecated: just map it to Debug.
295 Debug (message, args);
298 static public void Info (Exception ex, string message, params object [] args)
300 Debug (ex, message, args);
303 static public void Info (Exception ex)
305 Debug (ex);
308 static public void Warn (string message, params object [] args)
310 WriteLine (LogLevel.Warn, message, args, null);
313 static public void Warn (Exception ex, string message, params object [] args)
315 WriteLine (LogLevel.Warn, message, args, ex);
318 static public void Warn (Exception ex)
320 WriteLine (LogLevel.Warn, null, null, ex);
323 static public void Error (string message, params object [] args)
325 WriteLine (LogLevel.Error, message, args, null);
328 static public void Error (Exception ex, string message, params object [] args)
330 WriteLine (LogLevel.Error, message, args, ex);
333 static public void Error (Exception ex)
335 WriteLine (LogLevel.Error, null, null, ex);