Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ The key incantations are:

`-z` Path to a config file that defines all of the above, and much much more! See below for more details. Give it `-z generate` to generate a sample config file called `.\default.toml`.

`-t` Type of log you would like to output. Currently supported options are plain and JSON. Defaults to plain.
`-t` Type of log you would like to output. Currently supported options are plain, JSON, and HTML. Defaults to plain.

`-x` Max number of threads to use. Don't set it below 4 or shit will break.

Expand Down
7 changes: 6 additions & 1 deletion SnaffCore/Concurrency/SnafflerMessageType.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
namespace SnaffCore.Concurrency
using System.ComponentModel;

namespace SnaffCore.Concurrency
{
public enum SnafflerMessageType
{
Error,
[Description("Share")]
ShareResult,
[Description("Dir")]
DirResult,
[Description("File")]
FileResult,
Finish,
Info,
Expand Down
3 changes: 2 additions & 1 deletion SnaffCore/Config/Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ namespace SnaffCore.Config
public enum LogType
{
Plain = 0,
JSON = 1
JSON = 1,
HTML = 2
}

public partial class Options
Expand Down
4 changes: 4 additions & 0 deletions Snaffler/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@ private static Options ParseImpl(string[] args)
{
parsedConfig.LogType = LogType.JSON;
}
else if (logType.Value.ToLower() == "html")
{
parsedConfig.LogType = LogType.HTML;
}
else
{
Mq.Info("Invalid type argument passed (" + logType.Value + ") defaulting to plaintext");
Expand Down
103 changes: 103 additions & 0 deletions Snaffler/SnaffleRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using System.Threading;
using System.ComponentModel;

namespace Snaffler
{
Expand Down Expand Up @@ -185,6 +186,10 @@ public void Run(string[] args)
};
logfile.Layout = jsonLayout;
}
else if (Options.LogType == LogType.HTML)
{
logfile.Layout = "<tr><td>${longdate}</td><td>${event-properties:htmlFields:objectPath=DateTime}</td><td>${level}</td><td>${event-properties:htmlFields:objectPath=Type}</td><td>${message}</td></tr>";
}
}

// Apply config
Expand Down Expand Up @@ -247,6 +252,10 @@ private bool HandleOutput()
{
ProcessMessageJSON(message);
}
else if (Options.LogType == LogType.HTML)
{
ProcessMessageHTML(message);
}

// catch terminating messages and bail out of the master 'while' loop
if ((message.Type == SnafflerMessageType.Fatal) || (message.Type == SnafflerMessageType.Finish))
Expand Down Expand Up @@ -364,6 +373,73 @@ private void ProcessMessageJSON(SnafflerMessage message)
}
}

private void ProcessMessageHTML(SnafflerMessage message)
{
// standardized time formatting, UTC
string datetime = String.Format("{1}{0}{2:u}{0}", Options.Separator, hostString(), message.DateTime.ToUniversalTime());

// get a more user friendly name for a type variant if provided
var typeVariantField = message.Type.GetType().GetField(message.Type.ToString());
var typeVariantAttribute = (DescriptionAttribute)Attribute.GetCustomAttribute(typeVariantField, typeof(DescriptionAttribute));
string userReadableType = typeVariantAttribute == null ? message.Type.ToString() : typeVariantAttribute.Description;

var htmlFields = new { DateTime = datetime, Type = userReadableType };

switch (message.Type)
{
case SnafflerMessageType.Trace:
//Logger.Trace(message);
Logger.WithProperty("htmlFields", htmlFields).Trace(message.Message);
break;
case SnafflerMessageType.Degub:
//Logger.Debug(message);
Logger.WithProperty("htmlFields", htmlFields).Debug(message.Message);
break;
case SnafflerMessageType.Info:
//Logger.Info(message);
Logger.WithProperty("htmlFields", htmlFields).Info(message.Message);
break;
case SnafflerMessageType.FileResult:
//Logger.Warn(message);
Logger.WithProperty("htmlFields", htmlFields).Warn(FileResultLogFromMessage(message));
break;
case SnafflerMessageType.DirResult:
//Logger.Warn(message);
Logger.WithProperty("htmlFields", htmlFields).Warn(DirResultLogFromMessage(message));
break;
case SnafflerMessageType.ShareResult:
//Logger.Warn(message);
Logger.WithProperty("htmlFields", htmlFields).Warn(ShareResultLogFromMessage(message));
break;
case SnafflerMessageType.Error:
//Logger.Error(message);
Logger.WithProperty("htmlFields", htmlFields).Error(message.Message);
break;
case SnafflerMessageType.Fatal:
//Logger.Fatal(message);
Logger.WithProperty("htmlFields", htmlFields).Fatal(message.Message);
if (Debugger.IsAttached)
{
Console.ReadKey();
}
break;
case SnafflerMessageType.Finish:
Logger.Info("Snaffler out.");

if (Debugger.IsAttached)
{
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
if (Options.LogType == LogType.HTML)
{
Logger.Info("Normalising output, please wait...");
FixHTMLOutput();
}
break;
}
}

public string ShareResultLogFromMessage(SnafflerMessage message)
{
string sharePath = message.ShareResult.SharePath;
Expand Down Expand Up @@ -579,5 +655,32 @@ private void FixJSONOutput()
//Delete the temporary file.
File.Delete(Options.LogFilePath + ".tmp");
}

private void FixHTMLOutput()
{
//Rename the log file temporarily
File.Move(Options.LogFilePath, Options.LogFilePath + ".tmp");

//Prepare the normalised file
using (StreamWriter file = new StreamWriter(Options.LogFilePath))
{
//Write the start of the surrounding template that we need
file.Write("<!doctypehtml><html lang=en><meta charset=UTF-8><meta content=\"width=device-width,initial-scale=1\"name=viewport><title>Snaffler Logs</title><style>table{border-collapse:collapse}td,th{border:2px solid #000;padding:5px;vertical-align:text-top}</style><div><table><thead><tr><th>Timestamp<th>DateTime<th>Level<th>Type<th>Message<tbody>");

//Open the original file
using (FileStream sourceStream = new FileStream(Options.LogFilePath + ".tmp", FileMode.Open, FileAccess.Read))
using (StreamReader sourceReader = new StreamReader(sourceStream))
{
//Write the original content
file.Write(sourceReader.ReadToEnd());
}

//Write the end of the surrounding template that we need
file.Write("</table></div>");
}

//Delete the temporary file
File.Delete(Options.LogFilePath + ".tmp");
}
}
}