using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;
namespace Mullivan.Logging
{
public static class ProductLog
{
private const string CLOSEDOCUMENT = "</entries>";
private const string CLOSEENTRY = "\t</entry>\r\n";
private static DateTime currentDate;
private const string DECLARATION = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\r\n";
private static string directoryPath;
private const string FILENAMEEXTENSION = ".log";
private const string FILENAMEFORMAT = "MMddyyyy";
private const string FILENAMEPREFIX = "ML";
private const int MAXATTEMPTS = 5;
private const string MESSAGE = "\t\t<message>\r\n\t\t\t{0}\r\n\t\t</message>\r\n";
private const string OPENDOCUMENT = "<entries>\r\n";
private const string OPENENTRY = "\t<entry entryData=\"{0}\" componentName=\"{1}\" machineName=\"{2}\" category=\"{3}\">\r\n";
private const string STACKTRACE = "\t\t<stackTrace>\r\n\t\t\t{0}\r\n\t\t</stackTrace>\r\n";
private const string TRACETEMPLATE = "Logging Error:\r\n\r\n\tMessage: {0}\r\n\tStack Trace: {1}\r\n\r\n\r\nCould not write the following to log file:\r\n\r\n\tEntry Date: {2}\r\n\tComponent Name: {3}\r\n\tMachine Name: {4}\r\n\tCategory: {5}\r\n\tMessage: {6}\r\n\tStack Trace: {7}";
static ProductLog()
{
directoryPath = Path.GetFullPath("Logs");
currentDate = DateTime.MinValue;
}
public static string DirectoryPath
{
get
{
return directoryPath;
}
set
{
directoryPath = Path.GetFullPath(value);
}
}
public static string GetLogFilePath(DateTime logDate)
{
return Path.Combine(directoryPath, FILENAMEPREFIX + logDate.ToString("MMddyyyy") + ".log");
}
public static void WriteEntry(string componentName, ProductLogCategory category, Exception ex)
{
WriteEntry(componentName, category, ex.Message, ex.StackTrace);
}
public static void WriteEntry(string componentName, ProductLogCategory category, string message)
{
WriteEntry(componentName, category, message, string.Empty);
}
public static void WriteEntry(string componentName, ProductLogCategory category, string message, string stackTrace)
{
AttemptEntry(1, componentName, category, message, stackTrace);
}
private static void AttemptEntry(int attempt, string componentName, ProductLogCategory category, string message, string stackTrace)
{
try
{
try
{
string logFilePath = GetLogFilePath(DateTime.Today);
string directoryName = Path.GetDirectoryName(logFilePath);
if (!Directory.Exists(directoryName))
{
Directory.CreateDirectory(directoryName);
}
using (FileStream stream = new FileStream(logFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
if (stream.Length == 0L)
{
WriteToStream(stream, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\r\n");
WriteToStream(stream, "<entries>\r\n");
}
else
{
int length = "</entries>".Length;
if (stream.Length >= length)
{
stream.Seek((long)-length, SeekOrigin.End);
}
}
WriteToStream(stream, string.Format("\t<entry entryData=\"{0}\" componentName=\"{1}\" machineName=\"{2}\" category=\"{3}\">\r\n", new object[] { DateTime.Now.ToString(), componentName, Environment.MachineName, category.ToString() }));
if (message.Length > 0)
{
WriteToStream(stream, string.Format("\t\t<message>\r\n\t\t\t{0}\r\n\t\t</message>\r\n", Escape(message)));
}
if (stackTrace.Length > 0)
{
WriteToStream(stream, string.Format("\t\t<stackTrace>\r\n\t\t\t{0}\r\n\t\t</stackTrace>\r\n", Escape(stackTrace)));
}
WriteToStream(stream, string.Format("\t</entry>\r\n", new object[0]));
WriteToStream(stream, "</entries>");
}
}
catch (IOException)
{
if (attempt > 5)
{
throw;
}
AttemptEntry(++attempt, componentName, category, message, stackTrace);
}
}
catch (Exception exception)
{
Trace.WriteLine(string.Format("Logging Error:\r\n\r\n\tMessage: {0}\r\n\tStack Trace: {1}\r\n\r\n\r\nCould not write the following to log file:\r\n\r\n\tEntry Date: {2}\r\n\tComponent Name: {3}\r\n\tMachine Name: {4}\r\n\tCategory: {5}\r\n\tMessage: {6}\r\n\tStack Trace: {7}", new object[] { exception.Message, exception.StackTrace, DateTime.Now.ToString(), componentName, Environment.MachineName, category.ToString(), message, stackTrace }));
}
}
private static string Escape(string str)
{
StringBuilder builder = new StringBuilder();
if (str != null)
{
int startIndex = 0;
for (int i = 0; i < str.Length; i++)
{
switch (str[i])
{
case '&':
builder.Append(str.Substring(startIndex, i - startIndex));
builder.Append("&");
startIndex = i + 1;
break;
case '\'':
builder.Append(str.Substring(startIndex, i - startIndex));
builder.Append("'");
startIndex = i + 1;
break;
case '"':
builder.Append(str.Substring(startIndex, i - startIndex));
builder.Append(""");
startIndex = i + 1;
break;
case '<':
builder.Append(str.Substring(startIndex, i - startIndex));
builder.Append("<");
startIndex = i + 1;
break;
case '>':
builder.Append(str.Substring(startIndex, i - startIndex));
builder.Append(">");
startIndex = i + 1;
break;
}
}
builder.Append(str.Substring(startIndex, str.Length - startIndex));
}
return builder.ToString();
}
private static void WriteToStream(FileStream fs, string text)
{
fs.Write(Encoding.UTF8.GetBytes(text), 0, Encoding.UTF8.GetByteCount(text));
}
}
}