From 613faaf49f082d805a5ff7200e05da0a15ca8e7b Mon Sep 17 00:00:00 2001 From: Eric Fontana Date: Tue, 22 Jul 2014 10:26:04 -0400 Subject: [PATCH] Finished up log tailing. --- TimberWinR.ServiceHost/Program.cs | 34 ++- .../TimberWinR.ServiceHost.csproj | 5 + TimberWinR.ServiceHost/sampleconf.xml | 40 +++ TimberWinR.UnitTests/Configuration.cs | 2 +- .../TimberWinR.UnitTests.csproj | 3 - TimberWinR.UnitTests/testconf.xml | 2 +- TimberWinR.UnitTests/testconf.xsd | 236 ------------------ TimberWinR/Configuration.cs | 115 +++++++-- TimberWinR/Inputs/IISW3CInputListener.cs | 2 +- TimberWinR/Inputs/InputListener.cs | 12 +- TimberWinR/Inputs/TailFileInputListener.cs | 105 ++++++++ TimberWinR/Inputs/TcpInputListener.cs | 3 +- TimberWinR/Inputs/TextLine.cs | 19 -- TimberWinR/Inputs/WindowsEvtInputListener.cs | 2 +- TimberWinR/Outputs/OutputSender.cs | 3 +- TimberWinR/Outputs/Redis.cs | 89 +++++-- TimberWinR/TimberWinR.csproj | 9 +- TimberWinR/configSchema.xsd | 1 + .../lib/net40/RapidRegex.Core.dll | Bin 11264 -> 18432 bytes 19 files changed, 352 insertions(+), 330 deletions(-) create mode 100644 TimberWinR.ServiceHost/sampleconf.xml delete mode 100644 TimberWinR.UnitTests/testconf.xsd create mode 100644 TimberWinR/Inputs/TailFileInputListener.cs delete mode 100644 TimberWinR/Inputs/TextLine.cs diff --git a/TimberWinR.ServiceHost/Program.cs b/TimberWinR.ServiceHost/Program.cs index e234bd3..5dc2755 100644 --- a/TimberWinR.ServiceHost/Program.cs +++ b/TimberWinR.ServiceHost/Program.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text; @@ -20,9 +21,9 @@ namespace TimberWinR.ServiceHost private static void Main(string[] args) { Arguments arguments = new Arguments(); - + HostFactory.Run(hostConfigurator => - { + { string cmdLine = Environment.CommandLine; hostConfigurator.Service(serviceConfigurator => @@ -55,23 +56,23 @@ namespace TimberWinR.ServiceHost } } - + internal class TimberWinRService { readonly CancellationTokenSource _cancellationTokenSource; readonly CancellationToken _cancellationToken; readonly Task _serviceTask; private readonly Arguments _args; - private TcpInputListener _nlogListener; + private TcpInputListener _nlogListener; public TimberWinRService(Arguments args) { _args = args; _cancellationTokenSource = new CancellationTokenSource(); _cancellationToken = _cancellationTokenSource.Token; - _serviceTask = new Task(RunService, _cancellationToken); + _serviceTask = new Task(RunService, _cancellationToken); } - + public void Start() { _serviceTask.Start(); @@ -82,21 +83,16 @@ namespace TimberWinR.ServiceHost _cancellationTokenSource.Cancel(); _nlogListener.Shutdown(); } - + /// /// The Main body of the Service Worker Thread /// private void RunService() { TimberWinR.Manager manager = new TimberWinR.Manager(_args.ConfigFile); - - // logaggregator.vistaprint.svc - //var outputRedis = new RedisOutput(new string[] { "tstlexiceapp006.vistaprint.svc", "tstlexiceapp007.vistaprint.svc" }, _cancellationToken); + var outputRedis = new RedisOutput(manager, new string[] { "logaggregator.vistaprint.svc" }, _cancellationToken); - // var outputRedis = new RedisOutput(new string[] { "prdlexicelgs001.vistaprint.svc" }, _cancellationToken); - var outputRedis = new RedisOutput(new string[] { "logaggregator.vistaprint.svc" }, _cancellationToken); - _nlogListener = new TcpInputListener(_cancellationToken, 5140); outputRedis.Connect(_nlogListener); @@ -105,18 +101,18 @@ namespace TimberWinR.ServiceHost var elistner = new IISW3CInputListener(iisw3cConfig, _cancellationToken); outputRedis.Connect(elistner); } - + foreach (Configuration.WindowsEvent eventConfig in manager.Config.Events) { var elistner = new WindowsEvtInputListener(eventConfig, _cancellationToken); outputRedis.Connect(elistner); } - - //while (!_cancellationTokenSource.IsCancellationRequested) - //{ - // System.Threading.Thread.Sleep(1000); - //} + foreach (var logConfig in manager.Config.Logs) + { + var elistner = new TailFileInputListener(logConfig, _cancellationToken); + outputRedis.Connect(elistner); + } } } } diff --git a/TimberWinR.ServiceHost/TimberWinR.ServiceHost.csproj b/TimberWinR.ServiceHost/TimberWinR.ServiceHost.csproj index e94bcd8..98e50fb 100644 --- a/TimberWinR.ServiceHost/TimberWinR.ServiceHost.csproj +++ b/TimberWinR.ServiceHost/TimberWinR.ServiceHost.csproj @@ -60,6 +60,11 @@ TimberWinR + + + PreserveNewest + + + + + + + + + + + + + + MMM d HH:mm:ss + MMM dd HH:mm:ss + ISO8601 + + + MMM d HH:mm:ss + MMM dd HH:mm:ss + ISO8601 + + + + diff --git a/TimberWinR.UnitTests/Configuration.cs b/TimberWinR.UnitTests/Configuration.cs index a31dda9..ff93ddf 100644 --- a/TimberWinR.UnitTests/Configuration.cs +++ b/TimberWinR.UnitTests/Configuration.cs @@ -257,7 +257,7 @@ namespace TimberWinR.UnitTests bool splitLongLines = false; string iCheckpoint; - TimberWinR.Configuration.TextLog log = c.Logs.ToArray()[0]; + TimberWinR.Configuration.TailFileInput log = c.Logs.ToArray()[0]; Assert.AreEqual(name, log.Name); Assert.AreEqual(location, log.Location); diff --git a/TimberWinR.UnitTests/TimberWinR.UnitTests.csproj b/TimberWinR.UnitTests/TimberWinR.UnitTests.csproj index 0f2b2b6..0481388 100644 --- a/TimberWinR.UnitTests/TimberWinR.UnitTests.csproj +++ b/TimberWinR.UnitTests/TimberWinR.UnitTests.csproj @@ -47,9 +47,6 @@ - - Designer - diff --git a/TimberWinR.UnitTests/testconf.xml b/TimberWinR.UnitTests/testconf.xml index 156753b..7de93cc 100644 --- a/TimberWinR.UnitTests/testconf.xml +++ b/TimberWinR.UnitTests/testconf.xml @@ -17,7 +17,7 @@ - + diff --git a/TimberWinR.UnitTests/testconf.xsd b/TimberWinR.UnitTests/testconf.xsd deleted file mode 100644 index 6f9811a..0000000 --- a/TimberWinR.UnitTests/testconf.xsd +++ /dev/null @@ -1,236 +0,0 @@ - - - - - - - - - - - - - - iis - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/TimberWinR/Configuration.cs b/TimberWinR/Configuration.cs index a4d2f1b..2afb1c0 100644 --- a/TimberWinR/Configuration.cs +++ b/TimberWinR/Configuration.cs @@ -9,6 +9,7 @@ using System.IO; using System.Globalization; using TimberWinR.Inputs; using System.Xml.Schema; +using NLog; namespace TimberWinR { @@ -29,7 +30,7 @@ namespace TimberWinR public MissingRequiredAttributeException(XElement e, string attributeName) : base( string.Format("{0}:{1} Missing required attribute \"{2}\" for element <{3}>", e.Document.BaseUri, - ((IXmlLineInfo)e).LineNumber, attributeName, e.Name.ToString())) + ((IXmlLineInfo) e).LineNumber, attributeName, e.Name.ToString())) { } } @@ -39,7 +40,7 @@ namespace TimberWinR public InvalidAttributeNameException(XAttribute a) : base( string.Format("{0}:{1} Invalid Attribute Name <{2} {3}>", a.Document.BaseUri, - ((IXmlLineInfo)a).LineNumber, a.Parent.Name, a.Name.ToString())) + ((IXmlLineInfo) a).LineNumber, a.Parent.Name, a.Name.ToString())) { } } @@ -48,8 +49,10 @@ namespace TimberWinR { public InvalidAttributeDateValueException(XAttribute a) : base( - string.Format("{0}:{1} Invalid date format given for attribute. Format must be \"yyyy-MM-dd hh:mm:ss\". <{2} {3}>", a.Document.BaseUri, - ((IXmlLineInfo)a).LineNumber, a.Parent.Name, a.ToString())) + string.Format( + "{0}:{1} Invalid date format given for attribute. Format must be \"yyyy-MM-dd hh:mm:ss\". <{2} {3}>", + a.Document.BaseUri, + ((IXmlLineInfo) a).LineNumber, a.Parent.Name, a.ToString())) { } } @@ -59,7 +62,7 @@ namespace TimberWinR public InvalidAttributeIntegerValueException(XAttribute a) : base( string.Format("{0}:{1} Integer value not given for attribute. <{2} {3}>", a.Document.BaseUri, - ((IXmlLineInfo)a).LineNumber, a.Parent.Name, a.ToString())) + ((IXmlLineInfo) a).LineNumber, a.Parent.Name, a.ToString())) { } } @@ -69,7 +72,7 @@ namespace TimberWinR public InvalidAttributeValueException(XAttribute a) : base( string.Format("{0}:{1} Invalid Attribute Value <{2} {3}>", a.Document.BaseUri, - ((IXmlLineInfo)a).LineNumber, a.Parent.Name, a.ToString())) + ((IXmlLineInfo) a).LineNumber, a.Parent.Name, a.ToString())) { } } @@ -79,25 +82,45 @@ namespace TimberWinR public InvalidElementNameException(XElement e) : base( string.Format("{0}:{1} Invalid Element Name <{2}> <{3}>", e.Document.BaseUri, - ((IXmlLineInfo)e).LineNumber, e.Parent.Name, e.ToString())) + ((IXmlLineInfo) e).LineNumber, e.Parent.Name, e.ToString())) { } } private static List _events = new List(); - public IEnumerable Events { get { return _events; } } - private static List _logs = new List(); - public IEnumerable Logs { get { return _logs; } } + public IEnumerable Events + { + get { return _events; } + } + + private static List _logs = new List(); + + public IEnumerable Logs + { + get { return _logs; } + } private static List _iislogs = new List(); - public IEnumerable IIS { get { return _iislogs; } } + + public IEnumerable IIS + { + get { return _iislogs; } + } private static List _iisw3clogs = new List(); - public IEnumerable IISW3C { get { return _iisw3clogs; } } + + public IEnumerable IISW3C + { + get { return _iisw3clogs; } + } private static List _groks = new List(); - public IEnumerable Groks { get { return _groks; } } + + public IEnumerable Groks + { + get { return _groks; } + } public Configuration(string xmlConfFile) { @@ -107,23 +130,46 @@ namespace TimberWinR parseConfFilter(xmlConfFile); } - static void validateWithSchema(string xmlConfFile, string xsdSchema) + private static void validateWithSchema(string xmlConfFile, string xsdSchema) { XDocument config = XDocument.Load(xmlConfFile, LoadOptions.SetLineInfo | LoadOptions.SetBaseUri); // Ensure that the xml configuration file provided obeys the xsd schema. XmlSchemaSet schemas = new XmlSchemaSet(); schemas.Add("", XmlReader.Create(new StringReader(xsdSchema))); - - bool errors = false; + bool errorsFound = false; config.Validate(schemas, (o, e) => { - Console.WriteLine("{0}", e.Message); - errors = true; - }); - Console.WriteLine("The XML configuration file provided {0}", errors ? "did not validate." : "validated."); + errorsFound = true; + LogManager.GetCurrentClassLogger().Error(e.Message); + }, true); + + if (errorsFound) + DumpInvalidNodes(config.Root); } + static void DumpInvalidNodes(XElement el) + { + if (el.GetSchemaInfo().Validity != XmlSchemaValidity.Valid) + LogManager.GetCurrentClassLogger().Error("Invalid Element {0}", + el.AncestorsAndSelf() + .InDocumentOrder() + .Aggregate("", (s, i) => s + "/" + i.Name.ToString())); + foreach (XAttribute att in el.Attributes()) + if (att.GetSchemaInfo().Validity != XmlSchemaValidity.Valid) + LogManager.GetCurrentClassLogger().Error("Invalid Attribute {0}", + att + .Parent + .AncestorsAndSelf() + .InDocumentOrder() + .Aggregate("", + (s, i) => s + "/" + i.Name.ToString()) + "/@" + att.Name.ToString() + ); + foreach (XElement child in el.Elements()) + DumpInvalidNodes(child); + } + + static void parseConfInput(string xmlConfFile) { XDocument config = XDocument.Load(xmlConfFile, LoadOptions.SetLineInfo | LoadOptions.SetBaseUri); @@ -248,7 +294,7 @@ namespace TimberWinR // Parse parameters. Params_TextLog args = parseParams_Log(e.Attributes()); - TextLog log = new TextLog(name, location, fields, args); + TailFileInput log = new TailFileInput(name, location, fields, args); _logs.Add(log); } @@ -841,7 +887,19 @@ namespace TimberWinR throw new MissingRequiredAttributeException(e, attributeName); } p.WithMatch(val); + + attributeName = "field"; + try + { + val = e.Attribute(attributeName).Value; + } + catch + { + throw new MissingRequiredAttributeException(e, attributeName); + } + p.WithField(val); break; + case "AddField": string name, value; attributeName = "name"; @@ -964,7 +1022,7 @@ namespace TimberWinR } } - public class TextLog + public class TailFileInput { public string Name { get; private set; } public string Location { get; private set; } @@ -976,7 +1034,7 @@ namespace TimberWinR public bool SplitLongLines { get; private set; } public string ICheckpoint { get; private set; } - public TextLog(string name, string location, List fields, Params_TextLog args) + public TailFileInput(string name, string location, List fields, Params_TextLog args) { Name = name; Location = location; @@ -1421,6 +1479,7 @@ namespace TimberWinR public class Grok { public string Match { get; private set; } + public string Field { get; private set; } public Pair AddField { get; private set; } public bool DropIfMatch { get; private set; } public string RemoveField { get; private set; } @@ -1428,6 +1487,7 @@ namespace TimberWinR public Grok(Params_Grok args) { Match = args.Match; + Field = args.Field; AddField = args.AddField; DropIfMatch = args.DropIfMatch; RemoveField = args.RemoveField; @@ -1452,6 +1512,7 @@ namespace TimberWinR public class Params_Grok { public string Match { get; private set; } + public string Field { get; private set; } public Pair AddField { get; private set; } public bool DropIfMatch { get; private set; } public string RemoveField { get; private set; } @@ -1459,10 +1520,17 @@ namespace TimberWinR public class Builder { private string match; + private string field; private Pair addField; private bool dropIfMatch = false; private string removeField; + public Builder WithField(string value) + { + field = value; + return this; + } + public Builder WithMatch(string value) { match = value; @@ -1492,6 +1560,7 @@ namespace TimberWinR return new Params_Grok() { Match = match, + Field = field, AddField = addField, DropIfMatch = dropIfMatch, RemoveField = removeField diff --git a/TimberWinR/Inputs/IISW3CInputListener.cs b/TimberWinR/Inputs/IISW3CInputListener.cs index 4ff292a..1674e4d 100644 --- a/TimberWinR/Inputs/IISW3CInputListener.cs +++ b/TimberWinR/Inputs/IISW3CInputListener.cs @@ -92,7 +92,7 @@ namespace TimberWinR.Inputs json.Add(new JProperty(field.Name, v)); } json.Add(new JProperty("type", "Win32-IISLog")); - ProcessJson(json.ToString()); + ProcessJson(json); } } // Close the recordset diff --git a/TimberWinR/Inputs/InputListener.cs b/TimberWinR/Inputs/InputListener.cs index 0ad72ec..e0ef091 100644 --- a/TimberWinR/Inputs/InputListener.cs +++ b/TimberWinR/Inputs/InputListener.cs @@ -1,4 +1,5 @@ -using System; +using Newtonsoft.Json.Linq; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -9,7 +10,7 @@ namespace TimberWinR.Inputs public abstract class InputListener { public CancellationToken CancelToken { get; set; } - public event Action OnMessageRecieved; + public event Action OnMessageRecieved; public InputListener(CancellationToken token) @@ -17,10 +18,11 @@ namespace TimberWinR.Inputs this.CancelToken = token; } - protected void ProcessJson(string message) - { + + protected void ProcessJson(JObject json) + { if (OnMessageRecieved != null) - OnMessageRecieved(message); + OnMessageRecieved(json); } } } diff --git a/TimberWinR/Inputs/TailFileInputListener.cs b/TimberWinR/Inputs/TailFileInputListener.cs new file mode 100644 index 0000000..2d5c23f --- /dev/null +++ b/TimberWinR/Inputs/TailFileInputListener.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.IO; +using Interop.MSUtil; + +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Serialization; +using NLog; + +using LogQuery = Interop.MSUtil.LogQueryClassClass; +using TextLineInputFormat = Interop.MSUtil.COMTextLineInputContextClass; +using LogRecordSet = Interop.MSUtil.ILogRecordset; + +namespace TimberWinR.Inputs +{ + /// + /// Tail a file. + /// + public class TailFileInputListener : InputListener + { + private int _pollingIntervalInSeconds = 1; + private TimberWinR.Configuration.TailFileInput _arguments; + + public TailFileInputListener(TimberWinR.Configuration.TailFileInput arguments, CancellationToken cancelToken, int pollingIntervalInSeconds = 1) + : base(cancelToken) + { + _arguments = arguments; + _pollingIntervalInSeconds = pollingIntervalInSeconds; + var task = new Task(FileWatcher, cancelToken); + task.Start(); + } + + private void FileWatcher() + { + var oLogQuery = new LogQuery(); + + var checkpointFileName = Path.Combine(System.IO.Path.GetTempPath(), + string.Format("{0}.lpc", Guid.NewGuid().ToString())); + + var iFmt = new TextLineInputFormat() + { + iCodepage = _arguments.ICodepage, + splitLongLines = _arguments.SplitLongLines, + iCheckpoint = checkpointFileName, + recurse = _arguments.Recurse + }; + + // Create the query + var query = string.Format("SELECT * FROM {0}", _arguments.Location); + + var firstQuery = true; + // Execute the query + while (!CancelToken.IsCancellationRequested) + { + try + { + var rs = oLogQuery.Execute(query, iFmt); + Dictionary colMap = new Dictionary(); + for (int col=0; col - /// Tail a file. - /// - class TextLine - { - - } -} diff --git a/TimberWinR/Inputs/WindowsEvtInputListener.cs b/TimberWinR/Inputs/WindowsEvtInputListener.cs index e1d6b88..738dbc5 100644 --- a/TimberWinR/Inputs/WindowsEvtInputListener.cs +++ b/TimberWinR/Inputs/WindowsEvtInputListener.cs @@ -83,7 +83,7 @@ namespace TimberWinR.Inputs json.Add(new JProperty(field.Name, v)); } json.Add(new JProperty("type", "Win32-Eventlog")); - ProcessJson(json.ToString()); + ProcessJson(json); } } // Close the recordset diff --git a/TimberWinR/Outputs/OutputSender.cs b/TimberWinR/Outputs/OutputSender.cs index 9e1d459..8445cbb 100644 --- a/TimberWinR/Outputs/OutputSender.cs +++ b/TimberWinR/Outputs/OutputSender.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; +using Newtonsoft.Json.Linq; using TimberWinR.Inputs; namespace TimberWinR.Outputs @@ -23,6 +24,6 @@ namespace TimberWinR.Outputs listener.OnMessageRecieved += MessageReceivedHandler; } - protected abstract void MessageReceivedHandler(string jsonMessage); + protected abstract void MessageReceivedHandler(JObject jsonMessage); } } diff --git a/TimberWinR/Outputs/Redis.cs b/TimberWinR/Outputs/Redis.cs index 2672d38..b7c5961 100644 --- a/TimberWinR/Outputs/Redis.cs +++ b/TimberWinR/Outputs/Redis.cs @@ -6,14 +6,18 @@ using System.Net.Sockets; using System.Text; using System.Threading; using ctstone.Redis; +using Newtonsoft.Json.Linq; using NLog; using System.Threading.Tasks; +using RapidRegex.Core; +using System.Text.RegularExpressions; +using System.Globalization; namespace TimberWinR.Outputs { public class RedisOutput : OutputSender - { - private readonly string _logstashIndexName; + { + private readonly string _logstashIndexName; private readonly int _port; private readonly int _timeout; private readonly object _locker = new object(); @@ -21,6 +25,7 @@ namespace TimberWinR.Outputs readonly Task _consumerTask; private readonly string[] _redisHosts; private int _redisHostIndex; + private TimberWinR.Manager _manager; /// /// Get the next client @@ -30,36 +35,37 @@ namespace TimberWinR.Outputs { if (_redisHostIndex >= _redisHosts.Length) _redisHostIndex = 0; - + int numTries = 0; while (numTries < _redisHosts.Length) { try { RedisClient client = new RedisClient(_redisHosts[_redisHostIndex], _port, _timeout); - + _redisHostIndex++; if (_redisHostIndex >= _redisHosts.Length) _redisHostIndex = 0; - + return client; } catch (Exception ex) { - + } numTries++; - } + } return null; } - public RedisOutput(string[] redisHosts, CancellationToken cancelToken, string logstashIndexName = "logstash", int port = 6379, int timeout = 10000) + public RedisOutput(TimberWinR.Manager manager, string[] redisHosts, CancellationToken cancelToken, string logstashIndexName = "logstash", int port = 6379, int timeout = 10000) : base(cancelToken) { + _manager = manager; _redisHostIndex = 0; _redisHosts = redisHosts; - _jsonQueue = new List(); + _jsonQueue = new List(); _port = port; _timeout = timeout; _logstashIndexName = logstashIndexName; @@ -67,18 +73,69 @@ namespace TimberWinR.Outputs _consumerTask.Start(); } - + /// /// Forward on Json message to Redis Logstash queue /// /// - protected override void MessageReceivedHandler(string jsonMessage) + protected override void MessageReceivedHandler(JObject jsonMessage) { - LogManager.GetCurrentClassLogger().Info(jsonMessage); + if (_manager.Config.Groks != null) + ProcessGroks(jsonMessage); + + var message = jsonMessage.ToString(); + LogManager.GetCurrentClassLogger().Info(message); lock (_locker) { - _jsonQueue.Add(jsonMessage); + _jsonQueue.Add(message); + } + } + + private void ProcessGroks(JObject json) + { + foreach (var grok in _manager.Config.Groks) + { + JToken token = null; + if (json.TryGetValue(grok.Field, StringComparison.OrdinalIgnoreCase, out token)) + { + string text = token.ToString(); + if (!string.IsNullOrEmpty(text)) + { + string expr = grok.Match; + var resolver = new RegexGrokResolver(); + var pattern = resolver.ResolveToRegex(expr); + var match = Regex.Match(text, pattern); + if (match.Success) + { + var regex = new Regex(pattern); + var namedCaptures = regex.MatchNamedCaptures(text); + foreach (string fieldName in namedCaptures.Keys) + { + + if (fieldName == "timestamp") + { + string value = namedCaptures[fieldName]; + DateTime ts; + if (DateTime.TryParse(value, out ts)) + json.Add(fieldName, ts.ToUniversalTime()); + else if (DateTime.TryParseExact(value, new string[] + { + "MMM dd hh:mm:ss", + "MMM dd HH:mm:ss", + "MMM dd h:mm", + "MMM dd hh:mm", + }, CultureInfo.InvariantCulture, DateTimeStyles.None, out ts)) + json.Add(fieldName, ts.ToUniversalTime()); + else + json.Add(fieldName, (JToken)namedCaptures[fieldName]); + } + else + json.Add(fieldName, (JToken)namedCaptures[fieldName]); + } + } + } + } } } @@ -120,7 +177,7 @@ namespace TimberWinR.Outputs { } } - client.EndPipe(); + client.EndPipe(); break; } else @@ -131,9 +188,9 @@ namespace TimberWinR.Outputs } } } - catch(Exception ex) + catch (Exception ex) { - LogManager.GetCurrentClassLogger().Error(ex); + LogManager.GetCurrentClassLogger().Error(ex); } } } diff --git a/TimberWinR/TimberWinR.csproj b/TimberWinR/TimberWinR.csproj index 222dc8d..5a9d9c8 100644 --- a/TimberWinR/TimberWinR.csproj +++ b/TimberWinR/TimberWinR.csproj @@ -46,7 +46,8 @@ ..\packages\NLog.3.1.0.0\lib\net40\NLog.dll - + + False ..\packages\RapidRegex.Core.1.0.0.0\lib\net40\RapidRegex.Core.dll @@ -68,7 +69,7 @@ - + @@ -81,7 +82,9 @@ - + + PreserveNewest + diff --git a/TimberWinR/configSchema.xsd b/TimberWinR/configSchema.xsd index e4302ff..cd4bd01 100644 --- a/TimberWinR/configSchema.xsd +++ b/TimberWinR/configSchema.xsd @@ -260,6 +260,7 @@ + diff --git a/packages/RapidRegex.Core.1.0.0.0/lib/net40/RapidRegex.Core.dll b/packages/RapidRegex.Core.1.0.0.0/lib/net40/RapidRegex.Core.dll index e5e975d3b2875c9dfc1d4a0af72bf96ddef52b81..6ba5e8ecbfdb4bf679b481b4ebf180d9c31d36f3 100644 GIT binary patch literal 18432 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 b-T$X?O^d&sr5BwE_fMl&|GyXS(*yq-!MVW7 delta 4553 zcmZ`-dvH|M8UN0?_n!OM%}sVUPe{m;1h{0A@DxE_0j-GCk%&ATVue=5g5Z(_6-~o# zsv=fJ;-yv*EBGq)F<>(h9m`Dc&9t=Bj#h0)z_GT_85O4w)S=klckTx9k8bAt?)jeQ zJKy)6b9a;9Ci2U+ZK-=Ic6bpLKF3IojENXg0~jh|Zk^lr^b&vaT%x7SSV1(^=o^`e z=ZWH=Pqz|PhX-4m!mGp>Z+jhBX^e*OCn6(8hcAdRqA@%o>Z;bm1Ai{TkYv&6F_=^l z2^gOrE|it7OJq(emfcR+A49xa&qR}KSWW@c+xT*TsT#?mvQ{EUb@&DPWd zkrs1n)7cTM=W9L2@-tE^J;+MhvJ*k9&(=aM7kQAG92Q~oa@ox`*);noW*-qhVplB7 zj$}cJ7IYy-)r0*Zpa|I@YjQn?IINjPd4@PWHmg_a?NxY3;uD9qiap+MmK7n(&@T6m zI5H>?>&(f*4wss>!U=CS)1oST&>VdkyU-cERR*ZOCk^dR2E#yPhjV~jpGKn8cu5GD zV3Ckzk(SOSa_6b$I2H|KR<&CwTTd(;Z!OHF#tT9L2{l2TkgI65I;_J)c3QLt<07#%|0ZUbz9g9li-Mo6V`xGYZ93T@&Ca&#Vk-NdTQpfNf`bPAVoET^S&9;U%$IF1>1XBI?7kUI}#i9los z*-V(Oj@U|A%?HnQHmTrj?>Ei{&T*!)obZa^|2i8q;u&%pzbS+yv=4HyoDzl(PIe~| zxt<175L0xLxx!nZh!b;mck%L~%nhYp7n)GTY{%Wv!vf0cs|x6r;O+eWVwFs+U)mP86WhtSX%p7 z%!MENYSbhu2LscI7;sN;N63)&g9Px)VzgFh0D)bx1EiU=qAwtA#14$GsIDTng?b@* zn(hO>LN5Yu5ci>gJ4ClobP{t#o8?-m=y~}l@GXrWYcvh!)M%Wdu}$MzjZYYN7>Zuh z_=e^j)mUtvHWpDmLQ-@^&YWl}>IC|dFZtQyb6w@l-G-VgkHA@ch*E<~sD_7LC2Yo9He*@6-5@#@)bfdLGzIF98EO zs4-4Utw+#uORcBqed6So(kbgj%mbwNLz)kKADlt@TH`|Ur|mvqQJN+-bi7y4fu zw`<82U)Wy($@v->b4nE(vvE;O67Nt8-A#=3wBBf; z+vr{3Bw7xfPB#I&>36`C<_y<58I3VYfq$W%FVeW2wt{m#?(G)pqSuW%+W!iTd0_4x zxaY-oY1VFygBlNNd{yH|8V$k0r3LFB({qxVBYy)T^f&RB!i_N(PvaF%ET}+ z0+}2wW{Cyjc5x~v#>u;7%rMZ=c+cawv4EzaPN(SZ@{#f6_ zyc8FXqzd$hqB)% zy71ZNnO4gWHe@@)bxkZj^FQS5zqNfy)#PJ$;Z`q8x*{1*7U8`VO?@LxK7PIk zo(QRY12|$48-4+VLYGLp@}wnq=ICc4Q1Y-;bpwT$UxPfNn0WMSe2Q zKBWanEas`BA`?7TL(xgow&`HLnX^Z5#@ZK4ta&f~J4n{SG^lZsGy#F{E$$X!m$p18ve<%*yd|xDx zQ1sD4zF%F9NI3;6Et2`&zJ-YLPa>|Gi1W*c^PG*{rzj;VZKsg3{F61luje&>jqgYc zX+>t>EYgr1&+AIu!)4agBBO%E}JVpdJ=K+MMOeIHqdVVVumo?M6$!G^9FfxN*S zRuK3IFG_sEwubyCtF<)(li1IxsYTKFmWVmIG%hP6_ZD=y*ER_Rq(Y^8aP zGFzdbXZ@$O7ktYTJ~HDKHijJG3?=i2&=J}T+b369*js+L8yQ2VvP7b{Ak%$vb~hu0 z@?=uxcZb!pYr^@n|BjP8^e+{ON>`)Ym2)ugjp2$#7cCm`@PfKOzE?MIpwqggd1ZQr z?7zAdWpAI$CocMI;(5AnWVu{Fw{K)=_}HAa{ppLxi++FZKMl7v`oGJziT#O-KNEf9 G?f(H}3Zm2i