kopia lustrzana https://github.com/dl2alf/AirScout
309 wiersze
10 KiB
C#
309 wiersze
10 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Runtime.InteropServices;
|
|
using System.ComponentModel;
|
|
using System.Diagnostics;
|
|
|
|
|
|
namespace ScoutBase.Core
|
|
{
|
|
|
|
public static class LogLevel
|
|
{
|
|
public const int Nothing = 0;
|
|
public const int Info = 10;
|
|
public const int Warning = 20;
|
|
public const int Error = 30;
|
|
public const int Panic = 255;
|
|
}
|
|
|
|
/// <summary>
|
|
/// A Logging class implementing the Singleton pattern and an internal Queue to be flushed perdiodically.
|
|
/// It is designed to work in a multithreading environment
|
|
/// To use it simpy add the following to lines to your code
|
|
/// LogWriter writer = LogWriter.Instance;
|
|
/// writer.WriteToLog(message);
|
|
/// </summary>
|
|
public class LogWriter
|
|
{
|
|
private static LogWriter instance;
|
|
private static Queue<Log> logQueue;
|
|
|
|
private static DateTime LastFlushed = DateTime.MinValue; // be sure that the first message is written directly into the log
|
|
|
|
/// <summary>
|
|
/// Private constructor to prevent instance creation
|
|
/// </summary>
|
|
private LogWriter()
|
|
{
|
|
}
|
|
|
|
~LogWriter()
|
|
{
|
|
// flush the log regardless of queue size and age
|
|
FlushLog();
|
|
}
|
|
|
|
#region Properties
|
|
|
|
/// <summary>
|
|
/// An LogWriter instance that exposes a single instance
|
|
/// </summary>
|
|
public static LogWriter Instance
|
|
{
|
|
get
|
|
{
|
|
// If the instance is null then create one and init the Queue
|
|
if (instance == null)
|
|
{
|
|
instance = new LogWriter();
|
|
logQueue = new Queue<Log>();
|
|
}
|
|
return instance;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A string that exposes the log file directory
|
|
/// </summary>
|
|
public static string LogDirectory
|
|
{
|
|
get
|
|
{
|
|
// get string from settings
|
|
string logDirectory = Properties.Settings.Default.LogWriter_Directory;
|
|
// validate logfile directory --> use Windows Tmp directory if not
|
|
if (!SupportFunctions.ValidateDirectoryPath(logDirectory))
|
|
{
|
|
logDirectory = Path.GetTempPath();
|
|
}
|
|
// be sure that the directory exists --> create it if not
|
|
if (!Directory.Exists(logDirectory))
|
|
Directory.CreateDirectory(logDirectory);
|
|
return logDirectory;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A string that exposes the log filename format
|
|
/// Default: "log_{0:d}.log" representing a daily changing log file
|
|
/// </summary>
|
|
public static string LogFileFormat
|
|
{
|
|
get
|
|
{
|
|
string logFileFormat = Properties.Settings.Default.LogWriter_FileFormat;
|
|
if (String.IsNullOrEmpty(logFileFormat))
|
|
{
|
|
logFileFormat = "log_{0:d}.log";
|
|
}
|
|
// be sure that the resulting filename is valid
|
|
string filename = Path.Combine(LogDirectory, String.Format(logFileFormat, DateTime.UtcNow));
|
|
if (!SupportFunctions.ValidateFilePath(filename))
|
|
logFileFormat = "log_{0:d}.log";
|
|
return logFileFormat;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A string that exposes the log message format
|
|
/// Default: ""{0:t}: {1}" representing a "UTC timestamp: Messagetext" format
|
|
/// </summary>
|
|
public static string LogMessageFormat
|
|
{
|
|
get
|
|
{
|
|
string logMessageFormat = Properties.Settings.Default.LogWriter_MessageFormat;
|
|
if (String.IsNullOrEmpty(logMessageFormat))
|
|
{
|
|
logMessageFormat = "{0:t}: {1}";
|
|
}
|
|
// be sure that the resulting message format is valid
|
|
// creates a test message line
|
|
try
|
|
{
|
|
string line = String.Format(logMessageFormat, new object[] { DateTime.UtcNow, "Test" });
|
|
}
|
|
catch
|
|
{
|
|
logMessageFormat = "{0:t}: {1}";
|
|
}
|
|
return logMessageFormat;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// An integer that exposes the maximum age [seconds] of the que before writing into the logfile.
|
|
/// Minimum: 1s
|
|
/// Maxixum: 3600s
|
|
/// Default 10s
|
|
/// </summary>
|
|
public static int MaxLogAge
|
|
{
|
|
get
|
|
{
|
|
int maxLogAge = Properties.Settings.Default.LogWriter_MaxAge;
|
|
if (maxLogAge < 1)
|
|
maxLogAge = 1;
|
|
if (maxLogAge > 3600)
|
|
maxLogAge = 3600;
|
|
return maxLogAge;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// An integer that exposes the maximum number of queued entries before writing them into the logfile
|
|
/// Minimum: 1
|
|
/// Maxixum: 100
|
|
/// Default 10
|
|
/// </summary>
|
|
public static int QueueSize
|
|
{
|
|
get
|
|
{
|
|
int queueSize = Properties.Settings.Default.LogWriter_QueueSize;
|
|
if (queueSize < 1)
|
|
queueSize = 1;
|
|
if (queueSize > 100)
|
|
queueSize = 100;
|
|
return queueSize;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// An integer that exposes the log verbosity
|
|
/// Messages with error lever lower than verbosity are not written to the log
|
|
/// Minimum: 0
|
|
/// Maxixum: 255
|
|
/// Default 0
|
|
/// </summary>
|
|
public static int Verbosity
|
|
{
|
|
get
|
|
{
|
|
int verbosity = Properties.Settings.Default.LogWriter_Verbosity;
|
|
if (verbosity < 0)
|
|
verbosity = 0;
|
|
if (verbosity > 255)
|
|
verbosity = 255;
|
|
return verbosity;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// The single instance method that writes a message to the log file queue
|
|
/// </summary>
|
|
/// <param name="message">The message to write to the log</param>
|
|
public void WriteMessage(string message, int errorlevel = LogLevel.Info, bool debugdetails = true)
|
|
{
|
|
// return on errorlevel below verbosity threshold
|
|
if (errorlevel < Verbosity)
|
|
return;
|
|
// build the message
|
|
StackFrame stackFrame = new StackFrame(1, true);
|
|
string fileName = stackFrame.GetFileName();
|
|
string methodName = stackFrame.GetMethod().ToString();
|
|
int lineNumber = stackFrame.GetFileLineNumber();
|
|
|
|
string msg = "[" + errorlevel.ToString("000") + "]";
|
|
if (debugdetails)
|
|
{
|
|
try
|
|
{
|
|
msg = msg + "[" + methodName + " at " + fileName + ":" + lineNumber.ToString() + "]";
|
|
}
|
|
catch
|
|
{
|
|
msg = msg + "[unknown]";
|
|
}
|
|
}
|
|
msg = msg + ": " + message;
|
|
// force a one liner
|
|
msg = msg.Replace("\n", " ").Replace("\r", " ");
|
|
// Lock the queue while writing to prevent contention for the log file
|
|
lock (logQueue)
|
|
{
|
|
// Create the entry and push to the Queue
|
|
Log logEntry = new Log(msg);
|
|
logQueue.Enqueue(logEntry);
|
|
|
|
// If we have reached the Queue Size then flush the Queue
|
|
if (logQueue.Count >= QueueSize || DoPeriodicFlush())
|
|
{
|
|
FlushLog();
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool DoPeriodicFlush()
|
|
{
|
|
// returns true if max age of the queue is reached
|
|
TimeSpan logAge = DateTime.Now - LastFlushed;
|
|
if (logAge.TotalSeconds >= MaxLogAge)
|
|
{
|
|
LastFlushed = DateTime.Now;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Flushes the Queue to the physical log file
|
|
/// </summary>
|
|
public void FlushLog()
|
|
{
|
|
// not very efficient as opens and closes the stream on each entry
|
|
// but can handle queue at date change to ensure that each message goes to the right file
|
|
while (logQueue.Count > 0)
|
|
{
|
|
try
|
|
{
|
|
Log entry = logQueue.Dequeue();
|
|
string logfilename = Path.Combine(LogDirectory, String.Format(LogFileFormat, entry.Timestamp));
|
|
using (FileStream fs = File.Open(logfilename, FileMode.Append, FileAccess.Write))
|
|
{
|
|
using (StreamWriter log = new StreamWriter(fs))
|
|
{
|
|
// create the line
|
|
string line = String.Format(LogMessageFormat, new object[] { entry.Timestamp, entry.Message });
|
|
|
|
log.WriteLine(line);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// PANIC: writes a message to the console if something goes wrong with writing the log
|
|
Console.WriteLine("Error writing logfile: " + ex.Message);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A Log class to store the message and the Date and Time the log entry was created
|
|
/// </summary>
|
|
public class Log
|
|
{
|
|
|
|
public DateTime Timestamp { get; set; }
|
|
public string Message { get; set; }
|
|
|
|
public Log(string message)
|
|
{
|
|
Timestamp = DateTime.UtcNow;
|
|
Message = message;
|
|
}
|
|
}
|
|
}
|
|
|