Add --enable-deletion option to buildindex. If used, buildindex will remove deleted...
[beagle.git] / Util / Log.cs
blobf6de6112f711fb0f9ba6b8235003e4aa5c5a0de2
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 void Initialize (string log_directory,
59 string program_identifier,
60 LogLevel cutoff_level,
61 bool running_in_foreground)
63 Log.log_directory = log_directory;
64 Log.program_identifier = program_identifier;
65 Log.cutoff_level = cutoff_level;
66 Log.running_in_foreground = running_in_foreground;
68 PruneOldLogs ();
70 log_name_prefix = String.Format ("{0:yyyy-MM-dd-HH-mm-ss}-", DateTime.Now);
71 program_identifier_truncated = program_identifier.Substring (0, 6);
73 log_writer = NewLogWriter (program_identifier);
74 exception_writer = NewDelayedLogWriter (program_identifier + "Exceptions");
76 TextWriter console_log_writer;
77 console_log_writer = NewDelayedLogWriter (program_identifier + "Console");
79 TextWriter console_redirect_writer;
80 if (running_in_foreground) {
81 foreground_echo_writer = Console.Out;
82 console_redirect_writer = new TeeTextWriter (Console.Out, console_log_writer);
83 } else {
84 console_redirect_writer = console_log_writer;
87 Console.SetOut (console_redirect_writer);
88 Console.SetError (console_redirect_writer);
90 // If we are running in the background, redirect stdin to /dev/null
91 if (! running_in_foreground) {
92 FileStream dev_null_stream = new FileStream ("/dev/null",
93 FileMode.Open,
94 FileAccess.Read,
95 FileShare.ReadWrite);
96 TextReader dev_null_reader = new StreamReader (dev_null_stream);
97 Console.SetIn (dev_null_reader);
101 static public void Disable ()
103 cutoff_level = LogLevel.Ignored;
106 static private void PruneOldLogs ()
108 DateTime magic_date = DateTime.Now.AddDays (-7);
109 DirectoryInfo dir = new DirectoryInfo (log_directory);
111 string current_str;
112 current_str = "current-" + program_identifier;
114 foreach (FileInfo file in dir.GetFiles ()) {
116 // Clean up old symlinks
117 if (file.Name.StartsWith (current_str) && FileSystem.IsSymLink (file.FullName)) {
118 file.Delete ();
119 continue;
122 int last_dash = file.Name.LastIndexOf ("-");
123 if (last_dash == -1)
124 continue; // skip strange-looking files
126 string date = file.Name.Substring (0, last_dash);
128 try {
129 DateTime log_date;
130 log_date = DateTime.ParseExact (date, "yyyy-MM-dd-HH-mm-ss", null);
131 if (log_date < magic_date)
132 file.Delete ();
133 } catch (Exception e) { }
137 static private TextWriter NewLogWriter (string name)
139 string log_path;
140 log_path = Path.Combine (log_directory, log_name_prefix + name);
142 FileStream stream;
143 stream = new FileStream (log_path,
144 FileMode.CreateNew,
145 FileAccess.Write,
146 FileShare.ReadWrite);
148 StreamWriter writer;
149 writer = new StreamWriter (stream);
150 writer.AutoFlush = true;
152 string log_link;
153 log_link = Path.Combine (log_directory, "current-" + name);
154 Mono.Unix.Native.Syscall.symlink (log_path, log_link);
156 return writer;
159 private class DelayedClosure {
161 string name;
163 public DelayedClosure (string name)
165 this.name = name;
168 public TextWriter Build ()
170 return NewLogWriter (name);
174 static private TextWriter NewDelayedLogWriter (string name)
176 DelayedClosure closure;
177 closure = new DelayedClosure (name);
178 return new DelayedTextWriter (new DelayedTextWriter.Builder (closure.Build));
181 /////////////////////////////////////////////////////////////////////////////////////////
183 static object write_lock = new object ();
185 static private void WriteLine (LogLevel level, string format, object [] args, Exception ex)
187 if (cutoff_level < level)
188 return;
190 string ex_str = null;
191 if (ex != null)
192 ex_str = ex.ToString ();
194 // This only happens if Log.Initialize was never called.
195 if (running_in_foreground && foreground_echo_writer == null)
196 foreground_echo_writer = Console.Out;
198 if (foreground_echo_writer != null) {
199 foreground_echo_writer.Write (level);
200 foreground_echo_writer.Write (": ");
201 if (format != null)
202 foreground_echo_writer.WriteLine (format, args);
203 if (ex_str != null)
204 foreground_echo_writer.WriteLine (ex_str);
205 foreground_echo_writer.Flush ();
208 if (log_writer == null) // i.e. if Log.Initialize has not been called
209 return;
211 StringBuilder prefix_builder;
212 prefix_builder = new StringBuilder ();
213 prefix_builder.Append ('\n'); // start w/ a newline
214 prefix_builder.AppendFormat ("{0:yyMMdd HHmmssffff} {1:00000} ",
215 DateTime.Now, Process.GetCurrentProcess ().Id);
216 prefix_builder.Append (program_identifier_truncated);
218 prefix_builder.Append (' ');
219 switch (level) {
220 case LogLevel.Error:
221 prefix_builder.Append ("ERROR");
222 break;
223 case LogLevel.Warn:
224 prefix_builder.Append (" WARN");
225 break;
226 case LogLevel.Debug:
227 prefix_builder.Append ("DEBUG");
228 break;
229 default:
230 prefix_builder.Append (" HUH?");
231 break;
234 if (ex != null)
235 prefix_builder.Append (" EX");
236 prefix_builder.Append (": ");
238 string prefix;
239 prefix = prefix_builder.ToString ();
241 StringBuilder message;
242 message = new StringBuilder ();
243 message.Append (prefix);
244 message.Remove (0, 1); // remove leading \n
245 if (format != null)
246 message.AppendFormat (format, args);
247 if (ex_str != null) {
248 if (format != null)
249 message.Append ('\n');
250 message.Append (ex_str);
252 message.Replace ("\n", prefix);
254 string message_str;
255 message_str = message.ToString ();
257 lock (write_lock) {
258 log_writer.WriteLine (message_str);
259 if (ex != null && exception_writer != null)
260 exception_writer.WriteLine (message_str);
264 /////////////////////////////////////////////////////////////////////////////////////////
266 static public void Debug (string message, params object [] args)
268 WriteLine (LogLevel.Debug, message, args, null);
271 static public void Debug (Exception ex, string message, params object [] args)
273 WriteLine (LogLevel.Debug, message, args, ex);
276 static public void Debug (Exception ex)
278 WriteLine (LogLevel.Debug, null, null, ex);
281 static public void Info (string message, params object [] args)
283 // The Info log level is deprecated: just map it to Debug.
284 Debug (message, args);
287 static public void Info (Exception ex, string message, params object [] args)
289 Debug (ex, message, args);
292 static public void Info (Exception ex)
294 Debug (ex);
297 static public void Warn (string message, params object [] args)
299 WriteLine (LogLevel.Warn, message, args, null);
302 static public void Warn (Exception ex, string message, params object [] args)
304 WriteLine (LogLevel.Warn, message, args, ex);
307 static public void Warn (Exception ex)
309 WriteLine (LogLevel.Warn, null, null, ex);
312 static public void Error (string message, params object [] args)
314 WriteLine (LogLevel.Error, message, args, null);
317 static public void Error (Exception ex, string message, params object [] args)
319 WriteLine (LogLevel.Error, message, args, ex);
322 static public void Error (Exception ex)
324 WriteLine (LogLevel.Error, null, null, ex);