using System; using System.IO; using System.Security.AccessControl; namespace Semmle.Util.Logging { /// /// The severity of a log message. /// public enum Severity { Trace = 1, Debug = 2, Info = 3, Warning = 4, Error = 5 } /// /// Log verbosity level. /// public enum Verbosity { Off = 0, Error = 1, Warning = 2, Info = 3, Debug = 4, Trace = 5, All = 6 } /// /// A logger. /// public interface ILogger : IDisposable { /// /// Log the given text with the given severity. /// void Log(Severity s, string text); } public static class LoggerExtensions { /// /// Log the given text with the given severity. /// public static void Log(this ILogger logger, Severity s, string text, params object[] args) { logger.Log(s, string.Format(text, args)); } } /// /// A logger that outputs to a csharp.log /// file. /// public class FileLogger : ILogger { readonly StreamWriter writer; readonly Verbosity verbosity; public FileLogger(Verbosity verbosity, string outputFile) { this.verbosity = verbosity; try { var dir = Path.GetDirectoryName(outputFile); if (dir.Length > 0 && !System.IO.Directory.Exists(dir)) Directory.CreateDirectory(dir); writer = new PidStreamWriter(new FileStream(outputFile, FileMode.Append, FileAccess.Write, FileShare.ReadWrite, 8192)); writer.AutoFlush = true; } catch (Exception e) { Console.Error.WriteLine("SEMMLE: Couldn't initialise C# extractor output: " + e.Message + "\n" + e.StackTrace); Console.Error.Flush(); throw; } } public void Dispose() { writer.Dispose(); } static string GetSeverityPrefix(Severity s) { return "[" + s.ToString().ToUpper() + "] "; } public void Log(Severity s, string text) { if (verbosity.Includes(s)) writer.WriteLine(GetSeverityPrefix(s) + text); } } /// /// A logger that outputs to stdout/stderr. /// public class ConsoleLogger : ILogger { readonly Verbosity verbosity; public ConsoleLogger(Verbosity verbosity) { this.verbosity = verbosity; } public void Dispose() { } static TextWriter GetConsole(Severity s) { return s == Severity.Error ? Console.Error : Console.Out; } static string GetSeverityPrefix(Severity s) { switch (s) { case Severity.Trace: case Severity.Debug: case Severity.Info: return ""; case Severity.Warning: return "Warning: "; case Severity.Error: return "Error: "; default: throw new ArgumentOutOfRangeException("s"); } } public void Log(Severity s, string text) { if (verbosity.Includes(s)) GetConsole(s).WriteLine(GetSeverityPrefix(s) + text); } } /// /// A combined logger. /// public class CombinedLogger : ILogger { readonly ILogger logger1; readonly ILogger logger2; public CombinedLogger(ILogger logger1, ILogger logger2) { this.logger1 = logger1; this.logger2 = logger2; } public void Dispose() { logger1.Dispose(); logger2.Dispose(); } public void Log(Severity s, string text) { logger1.Log(s, text); logger2.Log(s, text); } } static class VerbosityExtensions { /// /// Whether a message with the given severity must be included /// for this verbosity level. /// public static bool Includes(this Verbosity v, Severity s) { switch (s) { case Severity.Trace: return v >= Verbosity.Trace; case Severity.Debug: return v >= Verbosity.Debug; case Severity.Info: return v >= Verbosity.Info; case Severity.Warning: return v >= Verbosity.Warning; case Severity.Error: return v >= Verbosity.Error; default: throw new ArgumentOutOfRangeException("s"); } } } }