4 // Copyright (C) 2004 Novell, Inc.
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
28 using System
.Collections
;
31 using System
.Diagnostics
;
33 namespace Beagle
.Util
{
35 public enum LogLevel
{
46 private static Hashtable loggers
= new Hashtable ();
47 private static TextWriter defaultWriter
= null;
48 private static bool defaultEcho
= true; //false;
49 private static string defaultLogName
= null;
51 // FIXME: The defaultLevel should be something higher
52 // than just LogLevel.Debug in the future. Users bitch
54 private static LogLevel defaultLevel
= LogLevel
.Debug
; //LogLevel.Info
56 public static Logger Log
{
62 public static Logger
Get (string logName
)
64 if (loggers
.ContainsKey (logName
)) {
65 return (Logger
)loggers
[logName
];
67 Logger log
= new Logger (logName
);
68 log
.Level
= defaultLevel
;
69 log
.Writer
= defaultWriter
;
70 log
.Echo
= defaultEcho
;
71 loggers
[logName
] = log
;
76 public static LogLevel DefaultLevel
{
77 get { return defaultLevel; }
78 set { defaultLevel = value; }
82 public static TextWriter DefaultWriter
{
83 get { return defaultWriter; }
84 set { defaultWriter = value; }
87 public static bool DefaultEcho
{
88 get { return defaultEcho; }
89 set { defaultEcho = value; }
92 private static object write_lock
= new object ();
94 private bool levelSet
= false;
95 private LogLevel level
;
96 private TextWriter writer
= null;
97 private bool echo
= false;
99 private Logger (string name
) {
102 public LogLevel Level
{
103 get { lock (this) { return (levelSet) ? level : DefaultLevel; }
}
104 set { lock (this) { level = value; levelSet = true; }
}
107 public TextWriter Writer
{
108 get { return writer; }
109 set { writer = value; }
114 set { echo = value; }
117 // Multiple logs can be merge-sorted via "sort -m log1 log2 ..."
118 private string GetStamp ()
120 StringBuilder builder
= new StringBuilder ();
121 builder
.AppendFormat ("{0:yy-MM-dd HH.mm.ss.ff} ", DateTime
.Now
);
122 builder
.AppendFormat ("{0:00000} ", Process
.GetCurrentProcess().Id
);
123 if (defaultLogName
!= null) {
124 builder
.AppendFormat (defaultLogName
);
125 builder
.Append (' ');
127 return builder
.ToString ();
130 private void WriteLine (string level
, string message
) {
131 if (Writer
!= null) {
133 Writer
.WriteLine ("{0}{1}: {2}", GetStamp (), level
, message
);
138 System
.Console
.WriteLine ("{0}: {1}", level
, message
);
141 public void Debug (string message
, params object [] args
)
143 if (IsDebugEnabled
) {
144 WriteLine ("DEBUG", String
.Format (message
, args
));
148 public void Debug (Exception e
)
153 public void Info (string message
, params object [] args
)
156 WriteLine ("INFO", String
.Format (message
, args
));
160 public void Info (Exception e
)
165 public void Warn (string message
, params object [] args
)
168 WriteLine ("WARN", String
.Format (message
, args
));
172 public void Warn (Exception e
)
177 public void Error (string message
, params object [] args
)
179 if (IsErrorEnabled
) {
180 WriteLine ("ERROR", String
.Format (message
, args
));
184 public void Error (Exception e
)
189 public void Fatal (string message
, params object [] args
)
191 if (IsFatalEnabled
) {
192 WriteLine ("FATAL", String
.Format (message
, args
));
196 public void Fatal (Exception e
)
201 public bool IsDebugEnabled { get { return level >= LogLevel.Debug; }
}
202 public bool IsInfoEnabled { get { return level >= LogLevel.Info; }
}
203 public bool IsWarnEnabled { get { return level >= LogLevel.Warn; }
}
204 public bool IsErrorEnabled { get { return level >= LogLevel.Error;}
}
205 public bool IsFatalEnabled { get { return level >= LogLevel.Fatal; }
}
207 ////////////////////////////////////////////////////////////////////////////////
209 static private void PruneOldLogs (string path
, string instance
)
211 DateTime magic_date
= DateTime
.Now
.AddDays (-7);
212 DirectoryInfo dir
= new DirectoryInfo (path
);
214 foreach (FileInfo file
in dir
.GetFiles ()) {
215 if (file
.Name
.StartsWith ("current") || (! file
.Name
.EndsWith (instance
)))
218 int last_dash
= file
.Name
.LastIndexOf ("-");
220 continue; // skip strange-looking files
222 string date
= file
.Name
.Substring (0, last_dash
);
226 log_date
= DateTime
.ParseExact (date
, "yyyy-MM-dd-HH-mm-ss", null);
227 if (log_date
< magic_date
)
229 } catch (Exception e
) { }
233 static public void LogToFile (string path
, string name
, bool foreground_mode
)
235 defaultLogName
= name
;
236 if (defaultLogName
.Length
> 6)
237 defaultLogName
= defaultLogName
.Substring (0, 6);
239 defaultLogName
= defaultLogName
.PadRight (6);
241 string timestamped_name
= String
.Format ("{0:yyyy-MM-dd-HH-mm-ss}-{1}", DateTime
.Now
, name
);
242 string log_path
= Path
.Combine (path
, timestamped_name
);
243 string log_link
= Path
.Combine (path
, "current-" + name
);
245 // Delete old and obsolete log files
246 PruneOldLogs (path
, name
);
248 // Open the log file and set it as the default
249 // destination for log messages.
250 // Also redirect stdout and stderr to the same file.
251 FileStream log_stream
= new FileStream (log_path
,
255 TextWriter log_writer
= new StreamWriter (log_stream
);
257 File
.Delete (log_link
);
258 Mono
.Posix
.Syscall
.symlink (log_path
, log_link
);
260 Logger
.DefaultWriter
= log_writer
;
261 Logger
.DefaultEcho
= foreground_mode
;
263 if (! foreground_mode
) {
265 // Redirect stdout and stderr to the logfile
266 Console
.SetOut (Logger
.DefaultWriter
);
267 Console
.SetError (Logger
.DefaultWriter
);
269 // Redirect stdin to /dev/null
270 FileStream dev_null_stream
= new FileStream ("/dev/null",
273 FileShare
.ReadWrite
);
274 TextReader dev_null_reader
= new StreamReader (dev_null_stream
);
275 Console
.SetIn (dev_null_reader
);
279 ////////////////////////////////////////////////////////////////////////////////
283 // Parse the contents of the BEAGLE_DEBUG environment variable
284 // and adjust the default log levels accordingly.
285 string debug
= System
.Environment
.GetEnvironmentVariable ("BEAGLE_DEBUG");
287 string[] debugArgs
= debug
.Split (',');
288 foreach (string arg
in debugArgs
) {
289 if (arg
.Trim () == "all") {
290 Logger
.DefaultLevel
= LogLevel
.Debug
;
294 foreach (string arg_raw
in debugArgs
) {
295 string arg
= arg_raw
.Trim ();
297 if (arg
.Length
== 0 || arg
== "all")
301 string name
= arg
.Substring (1);
302 Logger log
= Logger
.Get (name
);
303 log
.Level
= LogLevel
.Info
;
305 Logger log
= Logger
.Get (arg
);
306 log
.Level
= LogLevel
.Debug
;