Remove debug statements from KCal backends.
[beagle.git] / Util / Log.cs
blobd3266c5640564da8fc6f6fd73432eb4dab4b5eb4
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);
77 if (program_identifier.Length > 6)
78 program_identifier_truncated = program_identifier.Substring (0, 6);
79 else
80 program_identifier_truncated = program_identifier;
82 log_writer = NewLogWriter (program_identifier);
83 exception_writer = NewDelayedLogWriter (program_identifier + "Exceptions");
85 TextWriter console_log_writer;
86 console_log_writer = NewDelayedLogWriter (program_identifier + "Console");
88 TextWriter console_redirect_writer;
89 if (running_in_foreground) {
90 foreground_echo_writer = Console.Out;
91 console_redirect_writer = new TeeTextWriter (Console.Out, console_log_writer);
92 } else {
93 console_redirect_writer = console_log_writer;
96 Console.SetOut (console_redirect_writer);
97 Console.SetError (console_redirect_writer);
99 // If we are running in the background, redirect stdin to /dev/null
100 if (! running_in_foreground) {
101 FileStream dev_null_stream = new FileStream ("/dev/null",
102 FileMode.Open,
103 FileAccess.Read,
104 FileShare.ReadWrite);
105 TextReader dev_null_reader = new StreamReader (dev_null_stream);
106 Console.SetIn (dev_null_reader);
110 static public void Disable ()
112 cutoff_level = LogLevel.Ignored;
115 static private void PruneOldLogs ()
117 DateTime magic_date = DateTime.Now.AddDays (-7);
118 DirectoryInfo dir = new DirectoryInfo (log_directory);
120 string current_str;
121 current_str = "current-" + program_identifier;
123 foreach (FileInfo file in dir.GetFiles ()) {
125 // Clean up old symlinks
126 if (file.Name.StartsWith (current_str) && FileSystem.IsSymLink (file.FullName)) {
127 // Work around a Mono bug in which FileInfo.Delete()
128 // doesn't delete dangling symlinks. See
129 // http://bugzilla.ximian.com/show_bug.cgi?id=78664
131 //file.Delete ();
132 File.Delete (file.FullName);
134 continue;
137 int last_dash = file.Name.LastIndexOf ("-");
138 if (last_dash == -1)
139 continue; // skip strange-looking files
141 string date = file.Name.Substring (0, last_dash);
143 try {
144 DateTime log_date;
145 log_date = DateTime.ParseExact (date, "yyyy-MM-dd-HH-mm-ss", null);
146 if (log_date < magic_date)
147 file.Delete ();
148 } catch (Exception e) { }
152 static private TextWriter NewLogWriter (string name)
154 string log_path;
155 log_path = Path.Combine (log_directory, log_name_prefix + name);
157 FileStream stream;
158 stream = new FileStream (log_path,
159 FileMode.CreateNew,
160 FileAccess.Write,
161 FileShare.ReadWrite);
163 StreamWriter writer;
164 writer = new StreamWriter (stream);
165 writer.AutoFlush = true;
167 string log_link;
168 log_link = Path.Combine (log_directory, "current-" + name);
169 Mono.Unix.Native.Syscall.symlink (log_path, log_link);
171 return writer;
174 private class DelayedClosure {
176 string name;
178 public DelayedClosure (string name)
180 this.name = name;
183 public TextWriter Build ()
185 return NewLogWriter (name);
189 static private TextWriter NewDelayedLogWriter (string name)
191 DelayedClosure closure;
192 closure = new DelayedClosure (name);
193 return new DelayedTextWriter (new DelayedTextWriter.Builder (closure.Build));
196 /////////////////////////////////////////////////////////////////////////////////////////
198 static object write_lock = new object ();
200 static private void WriteLine (LogLevel level, string format, object [] args, Exception ex)
202 if (cutoff_level < level)
203 return;
205 string ex_str = null;
206 if (ex != null)
207 ex_str = ex.ToString ();
209 // This only happens if Log.Initialize was never called.
210 if (running_in_foreground && foreground_echo_writer == null)
211 foreground_echo_writer = Console.Out;
213 if (foreground_echo_writer != null) {
214 foreground_echo_writer.Write (level);
215 foreground_echo_writer.Write (": ");
216 if (format != null)
217 foreground_echo_writer.WriteLine (format, args);
218 if (ex_str != null)
219 foreground_echo_writer.WriteLine (ex_str);
220 foreground_echo_writer.Flush ();
223 if (log_writer == null) // i.e. if Log.Initialize has not been called
224 return;
226 StringBuilder prefix_builder;
227 prefix_builder = new StringBuilder ();
228 prefix_builder.Append ('\n'); // start w/ a newline
229 prefix_builder.AppendFormat ("{0:yyMMdd HHmmssffff} {1:00000} ",
230 DateTime.Now, Process.GetCurrentProcess ().Id);
231 prefix_builder.Append (program_identifier_truncated);
233 prefix_builder.Append (' ');
234 switch (level) {
235 case LogLevel.Error:
236 prefix_builder.Append ("ERROR");
237 break;
238 case LogLevel.Warn:
239 prefix_builder.Append (" WARN");
240 break;
241 case LogLevel.Debug:
242 prefix_builder.Append ("DEBUG");
243 break;
244 default:
245 prefix_builder.Append (" HUH?");
246 break;
249 if (ex != null)
250 prefix_builder.Append (" EX");
251 prefix_builder.Append (": ");
253 string prefix;
254 prefix = prefix_builder.ToString ();
256 StringBuilder message;
257 message = new StringBuilder ();
258 message.Append (prefix);
259 message.Remove (0, 1); // remove leading \n
260 if (format != null)
261 message.AppendFormat (format, args);
262 if (ex_str != null) {
263 if (format != null)
264 message.Append ('\n');
265 message.Append (ex_str);
267 message.Replace ("\n", prefix);
269 string message_str;
270 message_str = message.ToString ();
272 lock (write_lock) {
273 log_writer.WriteLine (message_str);
274 if (ex != null && exception_writer != null)
275 exception_writer.WriteLine (message_str);
279 /////////////////////////////////////////////////////////////////////////////////////////
281 static public void Debug (string message, params object [] args)
283 WriteLine (LogLevel.Debug, message, args, null);
286 static public void Debug (Exception ex, string message, params object [] args)
288 WriteLine (LogLevel.Debug, message, args, ex);
291 static public void Debug (Exception ex)
293 WriteLine (LogLevel.Debug, null, null, ex);
296 static public void Info (string message, params object [] args)
298 // The Info log level is deprecated: just map it to Debug.
299 Debug (message, args);
302 static public void Info (Exception ex, string message, params object [] args)
304 Debug (ex, message, args);
307 static public void Info (Exception ex)
309 Debug (ex);
312 static public void Warn (string message, params object [] args)
314 WriteLine (LogLevel.Warn, message, args, null);
317 static public void Warn (Exception ex, string message, params object [] args)
319 WriteLine (LogLevel.Warn, message, args, ex);
322 static public void Warn (Exception ex)
324 WriteLine (LogLevel.Warn, null, null, ex);
327 static public void Error (string message, params object [] args)
329 WriteLine (LogLevel.Error, message, args, null);
332 static public void Error (Exception ex, string message, params object [] args)
334 WriteLine (LogLevel.Error, message, args, ex);
337 static public void Error (Exception ex)
339 WriteLine (LogLevel.Error, null, null, ex);