Dictionary Validator Sample
Source code
using System;
using System.IO;
using System.Runtime.Serialization;
using NLog.Extensions.Logging;
using OnixS.Fix;
namespace DictionaryValidator
{
[Serializable]
public class CannotParseLogFileException : Exception
{
public CannotParseLogFileException(string message)
: base(message)
{
}
}
static class DictionaryValidator
{
private static string GetLicenseStoreFolder()
{
string path = Path.Join(AppContext.BaseDirectory, "../../../../../license");
if (Directory.Exists(path))
return path;
// expecting it run after dotnet publish using default paths
return Path.Join(AppContext.BaseDirectory, "../../../../../../license");
}
/// <summary>
/// The main entry point for the application.
/// </summary>
static int Main(string[] args)
{
if (0 == args.Length)
{
Console.WriteLine($"Usage: {nameof(DictionaryValidator)} FixLogFileToValidate.summary <DictionaryFile> [DictionaryId] \n");
return 2;
}
try
{
var settings = new EngineSettings()
{
DisableNetworkLevel = true,
LicenseStore = GetLicenseStoreFolder(),
ValidateRequiredFields = true,
ValidateUnknownFields = true,
ValidateRepeatingGroupEntryCount = true,
ValidateDuplicatedFields = true,
LoggerProvider = new NLogLoggerProvider()
};
if (args.Length > 1)
{
settings.Dictionary = args[1];
}
Engine.Init(settings);
IMessageInfoDictionary dictionary = null;
if (args.Length > 2)
{
dictionary = Engine.Instance.MessageInfoDictionaryManager[args[2]];
}
int numberOfProcessedMessages = ParseLogFile(args[0], dictionary);
Console.WriteLine($"Validated {numberOfProcessedMessages} message(s)");
}
catch (Exception ex)
{
Console.WriteLine("Exception: " + ex);
return 1;
}
finally
{
// From https://github.com/NLog/NLog/wiki/Tutorial:
// NET Application running on Mono / Linux are required to stop threads / timers before entering application shutdown phase.
// Failing to do this will cause unhandled exceptions and segmentation faults, and other unpredictable behavior.
NLog.LogManager.Shutdown(); // Flush and close down internal threads and timers
}
return 0;
}
static int ParseLogFile(string logFile, IMessageInfoDictionary dictionary)
{
int lineCounter = 0;
using (StreamReader sr = new StreamReader(logFile))
{
while (-1 != sr.Peek())
{
++lineCounter;
string line = sr.ReadLine();
line = line.Trim();
if (0 == line.Length)
{
continue;
}
int startOfFixMsgIndex = line.IndexOf("8=FIX");
if (-1 == startOfFixMsgIndex)
{
throw new CannotParseLogFileException("Cannot find the start of the FIX message (8=FIX) in line # " + lineCounter
+ " of " + logFile);
}
const char DelimChar = '\u0001';
const string CheckSumTagStr = "10";
const char TagValueSepChar = '=';
const int CheckSumValueLength = 6;
int startOfCheckSumTag = line.IndexOf(DelimChar+CheckSumTagStr+ TagValueSepChar, startOfFixMsgIndex, StringComparison.Ordinal);
if (-1 == startOfCheckSumTag)
{
throw new CannotParseLogFileException("Cannot find the checksum of the FIX message (10=***) in line # " + lineCounter
+ " of " + logFile);
}
line = line.Substring(startOfFixMsgIndex, startOfCheckSumTag + CheckSumValueLength + 2 - startOfFixMsgIndex);
try
{
Message message = null;
if (null == dictionary)
{
message = Message.Parse(line, Engine.Instance.MessageInfoDictionaryManager);
}
else
{
message = Message.Parse(line, dictionary);
}
message.Validate();
}
catch (Exception)
{
File.WriteAllText("Failed.summary", line);
throw;
}
}
}
return lineCounter;
}
}
}