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 LogLevel defaultLevel
= LogLevel
.Debug
; //LogLevel.Info;
48 private static TextWriter defaultWriter
= null;
49 private static bool defaultEcho
= true; //false;
50 private static string defaultLogName
= null;
52 public static Logger Log
{
58 public static Logger
Get (string logName
)
60 if (loggers
.ContainsKey (logName
)) {
61 return (Logger
)loggers
[logName
];
63 Logger log
= new Logger (logName
);
64 log
.Level
= defaultLevel
;
65 log
.Writer
= defaultWriter
;
66 log
.Echo
= defaultEcho
;
67 loggers
[logName
] = log
;
72 public static LogLevel DefaultLevel
{
73 get { return defaultLevel; }
74 set { defaultLevel = value; }
78 public static TextWriter DefaultWriter
{
79 get { return defaultWriter; }
80 set { defaultWriter = value; }
83 public static bool DefaultEcho
{
84 get { return defaultEcho; }
85 set { defaultEcho = value; }
88 private static object write_lock
= new object ();
90 private bool levelSet
= false;
91 private LogLevel level
;
92 private TextWriter writer
= null;
93 private bool echo
= false;
95 private Logger (string name
) {
98 public LogLevel Level
{
99 get { lock (this) { return (levelSet) ? level : DefaultLevel; }
}
100 set { lock (this) { level = value; levelSet = true; }
}
103 public TextWriter Writer
{
104 get { return writer; }
105 set { writer = value; }
110 set { echo = value; }
113 // Multiple logs can be merge-sorted via "sort -m log1 log2 ..."
114 private string GetStamp ()
116 StringBuilder builder
= new StringBuilder ();
117 builder
.AppendFormat ("{0:yy-MM-dd HH.mm.ss.ff} ", DateTime
.Now
);
118 builder
.AppendFormat ("{0:00000} ", Process
.GetCurrentProcess().Id
);
119 if (defaultLogName
!= null) {
120 builder
.AppendFormat (defaultLogName
);
121 builder
.Append (' ');
123 return builder
.ToString ();
126 private void WriteLine (string level
, string message
) {
127 if (Writer
!= null) {
129 Writer
.WriteLine ("{0}{1}: {2}", GetStamp (), level
, message
);
134 System
.Console
.WriteLine ("{0}: {1}", level
, message
);
137 public void Debug (string message
, params object [] args
)
139 if (IsDebugEnabled
) {
140 WriteLine ("DEBUG", String
.Format (message
, args
));
144 public void Debug (Exception e
)
149 public void Info (string message
, params object [] args
)
152 WriteLine ("INFO", String
.Format (message
, args
));
156 public void Info (Exception e
)
161 public void Warn (string message
, params object [] args
)
164 WriteLine ("WARN", String
.Format (message
, args
));
168 public void Warn (Exception e
)
173 public void Error (string message
, params object [] args
)
175 if (IsErrorEnabled
) {
176 WriteLine ("ERROR", String
.Format (message
, args
));
180 public void Error (Exception e
)
185 public void Fatal (string message
, params object [] args
)
187 if (IsFatalEnabled
) {
188 WriteLine ("FATAL", String
.Format (message
, args
));
192 public void Fatal (Exception e
)
197 public bool IsDebugEnabled { get { return level >= LogLevel.Debug; }
}
198 public bool IsInfoEnabled { get { return level >= LogLevel.Info; }
}
199 public bool IsWarnEnabled { get { return level >= LogLevel.Warn; }
}
200 public bool IsErrorEnabled { get { return level >= LogLevel.Error;}
}
201 public bool IsFatalEnabled { get { return level >= LogLevel.Fatal; }
}
203 ////////////////////////////////////////////////////////////////////////////////
205 static private void PruneOldLogs (string path
, string instance
)
207 DateTime magic_date
= DateTime
.Now
.AddDays (-7);
208 DirectoryInfo dir
= new DirectoryInfo (path
);
210 foreach (FileInfo file
in dir
.GetFiles ()) {
211 if (file
.Name
.StartsWith ("current") || (! file
.Name
.EndsWith (instance
)))
214 int last_dash
= file
.Name
.LastIndexOf ("-");
216 continue; // skip strange-looking files
218 string date
= file
.Name
.Substring (0, last_dash
);
222 log_date
= DateTime
.ParseExact (date
, "yyyy-MM-dd-HH-mm-ss", null);
223 if (log_date
< magic_date
)
225 } catch (Exception e
) { }
229 static public void LogToFile (string path
, string name
, bool foreground_mode
)
231 defaultLogName
= name
;
232 if (defaultLogName
.Length
> 6)
233 defaultLogName
= defaultLogName
.Substring (0, 6);
235 defaultLogName
= defaultLogName
.PadRight (6);
237 string timestamped_name
= String
.Format ("{0:yyyy-MM-dd-HH-mm-ss}-{1}", DateTime
.Now
, name
);
238 string log_path
= Path
.Combine (path
, timestamped_name
);
239 string log_link
= Path
.Combine (path
, "current-" + name
);
241 // Delete old and obsolete log files
242 PruneOldLogs (path
, name
);
244 // Open the log file and set it as the default
245 // destination for log messages.
246 // Also redirect stdout and stderr to the same file.
247 FileStream log_stream
= new FileStream (log_path
,
251 TextWriter log_writer
= new StreamWriter (log_stream
);
253 File
.Delete (log_link
);
254 Mono
.Posix
.Syscall
.symlink (log_path
, log_link
);
256 Logger
.DefaultWriter
= log_writer
;
257 Logger
.DefaultEcho
= foreground_mode
;
259 if (! foreground_mode
) {
261 // Redirect stdout and stderr to the logfile
262 Console
.SetOut (Logger
.DefaultWriter
);
263 Console
.SetError (Logger
.DefaultWriter
);
265 // Redirect stdin to /dev/null
266 FileStream dev_null_stream
= new FileStream ("/dev/null",
269 FileShare
.ReadWrite
);
270 TextReader dev_null_reader
= new StreamReader (dev_null_stream
);
271 Console
.SetIn (dev_null_reader
);
275 ////////////////////////////////////////////////////////////////////////////////
279 // Parse the contents of the BEAGLE_DEBUG environment variable
280 // and adjust the default log levels accordingly.
281 string debug
= System
.Environment
.GetEnvironmentVariable ("BEAGLE_DEBUG");
283 string[] debugArgs
= debug
.Split (',');
284 foreach (string arg
in debugArgs
) {
285 if (arg
.Trim () == "all") {
286 Logger
.DefaultLevel
= LogLevel
.Debug
;
290 foreach (string arg_raw
in debugArgs
) {
291 string arg
= arg_raw
.Trim ();
293 if (arg
.Length
== 0 || arg
== "all")
297 string name
= arg
.Substring (1);
298 Logger log
= Logger
.Get (name
);
299 log
.Level
= LogLevel
.Info
;
301 Logger log
= Logger
.Get (arg
);
302 log
.Level
= LogLevel
.Debug
;