From 4ebe539ea8e7a6ddf00bc69b8155773441b2e199 Mon Sep 17 00:00:00 2001 From: Eric Fontana Date: Wed, 29 Apr 2015 08:35:07 -0400 Subject: [PATCH 1/4] All updates for 1.3.24.0 --- README.md | 3 +- .../Properties/AssemblyInfo.cs | 4 +- TimberWinR.TestGenerator/LogFileGenerator.cs | 2 +- TimberWinR.TestGenerator/results1.json | 4 +- TimberWinR.TestGenerator/results2.json | 4 +- TimberWinR.TestGenerator/test1.json | 2 +- TimberWinR/Codecs/JsonCodec.cs | 26 +++ TimberWinR/Codecs/PlainCodec.cs | 39 ++++ TimberWinR/Configuration.cs | 8 + TimberWinR/Filters/JsonFilter.cs | 5 + TimberWinR/Inputs/GeneratorInput.cs | 89 +++++++++ TimberWinR/Inputs/LogsFileDatabase.cs | 11 +- TimberWinR/Inputs/TailFileListener.cs | 175 +++++++++++------- TimberWinR/Manager.cs | 9 + TimberWinR/Parser.cs | 39 +++- TimberWinR/ReleaseNotes.md | 5 + TimberWinR/TimberWinR.csproj | 4 + TimberWinR/mdocs/Generator.md | 37 ++++ 18 files changed, 381 insertions(+), 85 deletions(-) create mode 100644 TimberWinR/Codecs/JsonCodec.cs create mode 100644 TimberWinR/Codecs/PlainCodec.cs create mode 100644 TimberWinR/Inputs/GeneratorInput.cs create mode 100644 TimberWinR/mdocs/Generator.md diff --git a/README.md b/README.md index 170204c..fdf50c7 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,8 @@ The current supported Input format sources are: 5. [Stdin](https://github.com/Cimpress-MCP/TimberWinR/blob/master/TimberWinR/mdocs/StdinInput.md) (Standard Input for Debugging) 6. [W3C](https://github.com/Cimpress-MCP/TimberWinR/blob/master/TimberWinR/mdocs/W3CInput.md)(Internet Information Services W3C Advanced/Custom Format) 7. [Udp](https://github.com/Cimpress-MCP/TimberWinR/blob/master/TimberWinR/mdocs/UdpInput.md) (listens for UDP on port for JSON messages) - 8. [TailFiles](https://github.com/Cimpress-MCP/TimberWinR/blob/master/TimberWinR/mdocs/TailFiles.md) (Tails log files efficiently *New*) + 8. [TailFiles](https://github.com/Cimpress-MCP/TimberWinR/blob/master/TimberWinR/mdocs/TailFiles.md) (Tails log files efficiently) + 8. [Generator](https://github.com/Cimpress-MCP/TimberWinR/blob/master/TimberWinR/mdocs/Generator.md) (Generate logs for testing *New*) ## Codecs The current list of supported codecs are: diff --git a/TimberWinR.ServiceHost/Properties/AssemblyInfo.cs b/TimberWinR.ServiceHost/Properties/AssemblyInfo.cs index 91f7b14..67ea23e 100644 --- a/TimberWinR.ServiceHost/Properties/AssemblyInfo.cs +++ b/TimberWinR.ServiceHost/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.3.23.0")] -[assembly: AssemblyFileVersion("1.3.23.0")] +[assembly: AssemblyVersion("1.3.24.0")] +[assembly: AssemblyFileVersion("1.3.24.0")] diff --git a/TimberWinR.TestGenerator/LogFileGenerator.cs b/TimberWinR.TestGenerator/LogFileGenerator.cs index f1b1936..be0b91d 100644 --- a/TimberWinR.TestGenerator/LogFileGenerator.cs +++ b/TimberWinR.TestGenerator/LogFileGenerator.cs @@ -65,7 +65,7 @@ namespace TimberWinR.TestGenerator // if it is not deleted. using (StreamWriter sw = File.AppendText(logFilePath)) { - sw.AutoFlush = true; + // sw.AutoFlush = true; for (int i = 0; i < parms.NumMessages; i++) { JObject o = new JObject diff --git a/TimberWinR.TestGenerator/results1.json b/TimberWinR.TestGenerator/results1.json index 0e887d1..e667f92 100644 --- a/TimberWinR.TestGenerator/results1.json +++ b/TimberWinR.TestGenerator/results1.json @@ -5,14 +5,14 @@ "taillog": { "test1: message sent count": "[messages] == 7404", "test2: average cpu": "[avgCpuUsage] <= 30", - "test3: maximum memory": "[maxMemUsage] <= 20" + "test3: maximum memory": "[maxMemUsage] <= 30" } }, { "udp": { "test1: message sent count": "[messages] == 1234", "test2: average cpu": "[avgCpuUsage] <= 30", - "test3: maximum memory": "[maxMemUsage] <= 20" + "test3: maximum memory": "[maxMemUsage] <= 30" } } ] diff --git a/TimberWinR.TestGenerator/results2.json b/TimberWinR.TestGenerator/results2.json index e20ac02..792cd5b 100644 --- a/TimberWinR.TestGenerator/results2.json +++ b/TimberWinR.TestGenerator/results2.json @@ -5,14 +5,14 @@ "taillog": { "test1: message sent count": "[messages] == 7404", "test2: average cpu": "[avgCpuUsage] <= 30", - "test3: maximum memory": "[maxMemUsage] <= 15" + "test3: maximum memory": "[maxMemUsage] <= 20" } }, { "udp": { "test1: message sent count": "[messages] == 1234", "test2: average cpu": "[avgCpuUsage] <= 30", - "test3: maximum memory": "[maxMemUsage] <= 15" + "test3: maximum memory": "[maxMemUsage] <= 20" } } ] diff --git a/TimberWinR.TestGenerator/test1.json b/TimberWinR.TestGenerator/test1.json index 1420bbf..2baccb0 100644 --- a/TimberWinR.TestGenerator/test1.json +++ b/TimberWinR.TestGenerator/test1.json @@ -8,7 +8,7 @@ "--numMessages": 1234, "--logLevel": "debug", "--udp-host": "localhost", - "--udp": "5140", + "--udp": "5140", "--jroll": ["r1.jlog", "r2.jlog"], "--json": ["1.jlog", "2.jlog", "3.jlog", "4.jlog"], "--resultsFile": "results1.json" diff --git a/TimberWinR/Codecs/JsonCodec.cs b/TimberWinR/Codecs/JsonCodec.cs new file mode 100644 index 0000000..1f2dcfb --- /dev/null +++ b/TimberWinR/Codecs/JsonCodec.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Newtonsoft.Json.Linq; +using TimberWinR.Parser; + +namespace TimberWinR.Codecs +{ + class JsonCodec : ICodec + { + private CodecArguments _codecArguments; + + public void Apply(string msg, Inputs.InputListener listener) + { + JObject jobject = JObject.Parse(msg); + listener.AddDefaultFields(jobject); + listener.ProcessJson(jobject); + } + + public JsonCodec(CodecArguments args) + { + _codecArguments = args; + } + } +} diff --git a/TimberWinR/Codecs/PlainCodec.cs b/TimberWinR/Codecs/PlainCodec.cs new file mode 100644 index 0000000..41f17dc --- /dev/null +++ b/TimberWinR/Codecs/PlainCodec.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Newtonsoft.Json.Linq; +using TimberWinR.Parser; + +namespace TimberWinR.Codecs +{ + public class PlainCodec : ICodec + { + private CodecArguments _codecArguments; + + public void Apply(string msg, Inputs.InputListener listener) + { + JObject json = new JObject(); + listener.AddDefaultFields(json); + json["message"] = ExpandField(msg, json); + listener.ProcessJson(json); + } + + protected string ExpandField(string fieldName, JObject json) + { + foreach (var token in json.Children()) + { + string replaceString = "%{" + token.Path + "}"; + fieldName = fieldName.Replace(replaceString, json[token.Path].ToString()); + } + return fieldName; + } + + + public PlainCodec(CodecArguments args) + { + _codecArguments = args; + } + + } +} diff --git a/TimberWinR/Configuration.cs b/TimberWinR/Configuration.cs index 3dfe485..cb37125 100644 --- a/TimberWinR/Configuration.cs +++ b/TimberWinR/Configuration.cs @@ -102,6 +102,12 @@ namespace TimberWinR get { return _stdins; } } + private List _generators = new List(); + public IEnumerable Generators + { + get { return _generators; } + } + private List _filters = new List(); public IEnumerable Filters @@ -239,6 +245,8 @@ namespace TimberWinR c._iisw3clogs.AddRange(x.TimberWinR.Inputs.IISW3CLogs.ToList()); if (x.TimberWinR.Inputs.Stdins != null) c._stdins.AddRange(x.TimberWinR.Inputs.Stdins.ToList()); + if (x.TimberWinR.Inputs.Generators != null) + c._generators.AddRange(x.TimberWinR.Inputs.Generators.ToList()); if (x.TimberWinR.Inputs.Logs != null) c._logs.AddRange(x.TimberWinR.Inputs.Logs.ToList()); if (x.TimberWinR.Inputs.TailFilesArguments != null) diff --git a/TimberWinR/Filters/JsonFilter.cs b/TimberWinR/Filters/JsonFilter.cs index b3a0314..1fb7f83 100644 --- a/TimberWinR/Filters/JsonFilter.cs +++ b/TimberWinR/Filters/JsonFilter.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using System.Threading; using System.Xml.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -12,6 +13,8 @@ namespace TimberWinR.Parser { public partial class Json : LogstashFilter { + private long _errorCount; + public Json() { RemoveSource = true; @@ -22,6 +25,7 @@ namespace TimberWinR.Parser new JProperty("json", new JObject( new JProperty("condition", Condition), + new JProperty("errors", _errorCount), new JProperty("source", Source), new JProperty("promote", Source), new JProperty("target", Target), @@ -102,6 +106,7 @@ namespace TimberWinR.Parser catch (Exception ex) { LogManager.GetCurrentClassLogger().Error(ex); + Interlocked.Increment(ref _errorCount); return true; } } diff --git a/TimberWinR/Inputs/GeneratorInput.cs b/TimberWinR/Inputs/GeneratorInput.cs new file mode 100644 index 0000000..3abb5e7 --- /dev/null +++ b/TimberWinR/Inputs/GeneratorInput.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using NLog; +using RestSharp.Extensions; +using TimberWinR.Codecs; +using TimberWinR.Parser; + + +namespace TimberWinR.Inputs +{ + public class GeneratorInput : InputListener + { + public override JObject ToJson() + { + JObject json = new JObject( + new JProperty("message", _params.Message), + new JProperty("messages", _sentMessages), + new JProperty("generator", "enabled")); + return json; + } + + private TimberWinR.Parser.GeneratorParameters _params; + private Thread _listenThread; + private ICodec _codec; + private int _sentMessages; + + public GeneratorInput(TimberWinR.Parser.GeneratorParameters parameters, CancellationToken cancelToken) + : base(cancelToken, "Win32-InputGen") + { + _params = parameters; + + if (_params.CodecArguments != null) + { + switch (_params.CodecArguments.Type) + { + case CodecArguments.CodecType.json: + _codec = new JsonCodec(_params.CodecArguments); + break; + case CodecArguments.CodecType.multiline: + _codec = new Multiline(_params.CodecArguments); + break; + case CodecArguments.CodecType.plain: + _codec = new PlainCodec(_params.CodecArguments); + break; + } + } + + _listenThread = new Thread(new ThreadStart(GenerateData)); + _listenThread.Start(); + } + + private void GenerateData() + { + LogManager.GetCurrentClassLogger().Info("Generator Creating {0} Lines", _params.Count); + + int numMessages = _params.Count; + if (numMessages == 0) + numMessages = int.MaxValue; + + for (int i = 0; i < numMessages; i++) + { + if (CancelToken.IsCancellationRequested) + break; + + string msg = ToPrintable(_params.Message); + + if (_codec != null) + _codec.Apply(msg, this); + else + { + JObject jo = new JObject(); + jo["Message"] = msg; + AddDefaultFields(jo); + ProcessJson(jo); + } + + Thread.Sleep(_params.Rate); + } + + Finished(); + } + } +} diff --git a/TimberWinR/Inputs/LogsFileDatabase.cs b/TimberWinR/Inputs/LogsFileDatabase.cs index 8fe5116..778aaa8 100644 --- a/TimberWinR/Inputs/LogsFileDatabase.cs +++ b/TimberWinR/Inputs/LogsFileDatabase.cs @@ -77,6 +77,7 @@ namespace TimberWinR.Inputs var fi = new FileInfo(logName); de.FileName = logName; de.LogFileExists = fi.Exists; + de.Previous = ""; de.NewFile = true; de.ProcessedFile = false; de.LastPosition = fi.Length; @@ -101,8 +102,10 @@ namespace TimberWinR.Inputs var creationTime = fi.CreationTimeUtc; if (dbe.LogFileExists && creationTime != dbe.CreationTimeUtc) - dbe.NewFile = true; - + { + dbe.NewFile = true; + dbe.Previous = ""; + } dbe.CreationTimeUtc = creationTime; return dbe; @@ -133,7 +136,8 @@ namespace TimberWinR.Inputs public static void Roll(LogsFileDatabaseEntry dbe) { dbe.ProcessedFile = false; - dbe.LastPosition = 0; + dbe.LastPosition = 0; + dbe.Previous = ""; Instance.UpdateEntry(dbe, 0); dbe.NewFile = true; } @@ -268,6 +272,7 @@ namespace TimberWinR.Inputs { Interlocked.Increment(ref _linesProcessed); } + public string Previous { get; set; } } } diff --git a/TimberWinR/Inputs/TailFileListener.cs b/TimberWinR/Inputs/TailFileListener.cs index 131d2fc..2b7748a 100644 --- a/TimberWinR/Inputs/TailFileListener.cs +++ b/TimberWinR/Inputs/TailFileListener.cs @@ -30,18 +30,19 @@ namespace TimberWinR.Inputs private int _pollingIntervalInSeconds; private TimberWinR.Parser.TailFileArguments _arguments; private long _receivedMessages; - + private long _errorCount; private CodecArguments _codecArguments; private ICodec _codec; - + public bool Stop { get; set; } - public TailFileListener(TimberWinR.Parser.TailFileArguments arguments, CancellationToken cancelToken) + public TailFileListener(TimberWinR.Parser.TailFileArguments arguments, + CancellationToken cancelToken) : base(cancelToken, "Win32-TailLog") - { + { Stop = false; - - EnsureRollingCaught(); + + EnsureRollingCaught(); _codecArguments = arguments.CodecArguments; if (_codecArguments != null && _codecArguments.Type == CodecArguments.CodecType.multiline) @@ -60,7 +61,9 @@ namespace TimberWinR.Inputs public override void Shutdown() { - LogManager.GetCurrentClassLogger().Info("{0}: Shutting Down {1} for {2}", Thread.CurrentThread.ManagedThreadId, InputType, _arguments.Location); + LogManager.GetCurrentClassLogger() + .Info("{0}: Shutting Down {1} for {2}", Thread.CurrentThread.ManagedThreadId, InputType, + _arguments.Location); Stop = true; base.Shutdown(); } @@ -71,6 +74,7 @@ namespace TimberWinR.Inputs new JProperty("taillog", new JObject( new JProperty("messages", _receivedMessages), + new JProperty("errors", _errorCount), new JProperty("type", InputType), new JProperty("location", _arguments.Location), new JProperty("logSource", _arguments.LogSource), @@ -103,73 +107,100 @@ namespace TimberWinR.Inputs private void TailFileContents(string fileName, long offset, LogsFileDatabaseEntry dbe) { - using (StreamReader reader = new StreamReader(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))) + const int bufSize = 16535; + long prevLen = offset; + + FileInfo fi = new FileInfo(fileName); + if (!fi.Exists) + return; + + LogManager.GetCurrentClassLogger().Trace(":{0} Tailing File: {1} as Pos: {2}", Thread.CurrentThread.ManagedThreadId, fileName, prevLen); + + using (var stream = new FileStream(fi.FullName, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite)) { - //start at the end of the file - long lastMaxOffset = offset; + stream.Seek(prevLen, SeekOrigin.Begin); - //if the file size has not changed, idle - if (reader.BaseStream.Length == lastMaxOffset) - return; - - //seek to the last max offset - LogManager.GetCurrentClassLogger().Trace("{0}: File: {1} Seek to: {2}", Thread.CurrentThread.ManagedThreadId, fileName, lastMaxOffset); - - var seekedTo = reader.BaseStream.Seek(lastMaxOffset, SeekOrigin.Begin); - - // We couldn't seek to the position, so remember what we have seeked to. - if (seekedTo != lastMaxOffset) + char[] buffer = new char[bufSize]; + StringBuilder current = new StringBuilder(); + using (StreamReader sr = new StreamReader(stream)) { - lastMaxOffset = seekedTo; - LogsFileDatabase.Update(dbe, true, lastMaxOffset); - } - - //read out of the file until the EOF - string line = ""; - long lineOffset = 0; - while ((line = reader.ReadLine()) != null) - { - if (string.IsNullOrEmpty(line)) - continue; - - long index = lastMaxOffset + lineOffset; - string text = line; - string logFileName = fileName; - var json = new JObject(); - - if (json["logSource"] == null) + int nRead; + do { - if (string.IsNullOrEmpty(_arguments.LogSource)) - json.Add(new JProperty("logSource", fileName)); - else - json.Add(new JProperty("logSource", _arguments.LogSource)); + // Read a buffered amount + nRead = sr.ReadBlock(buffer, 0, bufSize); + for (int i = 0; i < nRead; ++i) + { + // We need the terminator! + if (buffer[i] == '\n' || buffer[i] == '\r') + { + if (current.Length > 0) + { + string line = string.Concat(dbe.Previous, current); + var json = new JObject(); + + if (json["logSource"] == null) + { + if (string.IsNullOrEmpty(_arguments.LogSource)) + json.Add(new JProperty("logSource", fileName)); + else + json.Add(new JProperty("logSource", _arguments.LogSource)); + } + + //LogManager.GetCurrentClassLogger().Debug(":{0} File: {1}:{2} {3}", Thread.CurrentThread.ManagedThreadId, fileName, dbe.LinesProcessed, line); + + // We've processed the partial input + dbe.Previous = ""; + json["Text"] = line; + json["Index"] = dbe.LinesProcessed; + json["LogFileName"] = fileName; + if (_codecArguments != null && _codecArguments.Type == CodecArguments.CodecType.multiline) + { + try + { + _codec.Apply(line, this); + Interlocked.Increment(ref _receivedMessages); + dbe.IncrementLineCount(); + } + catch (Exception ex) + { + Interlocked.Increment(ref _errorCount); + LogManager.GetCurrentClassLogger().ErrorException("Filter Error", ex); + } + } + else + { + try + { + ProcessJson(json); + dbe.IncrementLineCount(); + Interlocked.Increment(ref _receivedMessages); + LogsFileDatabase.Update(dbe, true, sr.BaseStream.Position); + } + catch (Exception ex) + { + Interlocked.Increment(ref _errorCount); + LogManager.GetCurrentClassLogger().ErrorException("Process Error", ex); + } + } + + } + current = new StringBuilder(); + } + else // Copy character into the buffer + { + current.Append(buffer[i]); + } + } + } while (nRead > 0); + + // We didn't encounter the newline, so save it. + if (current.Length > 0) + { + dbe.Previous = current.ToString(); } - - json["Text"] = line; - json["Index"] = index; - json["LogFileName"] = fileName; - - - if (_codecArguments != null && _codecArguments.Type == CodecArguments.CodecType.multiline) - { - _codec.Apply(line, this); - Interlocked.Increment(ref _receivedMessages); - dbe.IncrementLineCount(); - } - else - { - ProcessJson(json); - Interlocked.Increment(ref _receivedMessages); - dbe.IncrementLineCount(); - //LogManager.GetCurrentClassLogger().Info("{0}: File: {1} {2} {3}", Thread.CurrentThread.ManagedThreadId, fileName, dbe.LinesProcessed, line); - } - - lineOffset += line.Length; } - //update the last max offset - lastMaxOffset = reader.BaseStream.Position; - LogsFileDatabase.Update(dbe, true, lastMaxOffset); - } + } } // One thread for each kind of file to watch, i.e. "*.log,*.txt" would be two separate // threads. @@ -203,13 +234,13 @@ namespace TimberWinR.Inputs foreach (string fileName in Directory.GetFiles(path, name, so)) { var dbe = LogsFileDatabase.LookupLogFile(fileName); - + // We only spin up 1 thread for a file we haven't yet seen. if (isWildcardPattern && !HaveSeenFile(fileName) && dbe.NewFile) { LogManager.GetCurrentClassLogger().Debug(":{0} Starting Thread Tailing File: {1}", Thread.CurrentThread.ManagedThreadId, dbe.FileName); LogsFileDatabase.Update(dbe, false, dbe.LastPosition); - + Task.Factory.StartNew(() => TailFileWatcher(fileName)); } else if (!isWildcardPattern) @@ -237,7 +268,7 @@ namespace TimberWinR.Inputs else { TailFileContents(dbe.FileName, dbe.LastPosition, dbe); - } + } } } } @@ -281,7 +312,7 @@ namespace TimberWinR.Inputs } } Finished(); - } + } } } diff --git a/TimberWinR/Manager.cs b/TimberWinR/Manager.cs index cdb68e4..035ef88 100644 --- a/TimberWinR/Manager.cs +++ b/TimberWinR/Manager.cs @@ -256,6 +256,15 @@ namespace TimberWinR output.Connect(elistner); } + foreach (var stdin in config.Generators) + { + var elistner = new GeneratorInput(stdin, cancelToken); + Listeners.Add(elistner); + foreach (var output in Outputs) + output.Connect(elistner); + } + + var computerName = System.Environment.MachineName + "." + Microsoft.Win32.Registry.LocalMachine.OpenSubKey( @"SYSTEM\CurrentControlSet\services\Tcpip\Parameters") diff --git a/TimberWinR/Parser.cs b/TimberWinR/Parser.cs index b7eebe9..324f709 100644 --- a/TimberWinR/Parser.cs +++ b/TimberWinR/Parser.cs @@ -263,12 +263,46 @@ namespace TimberWinR.Parser } } + public class GeneratorParameters : IValidateSchema + { + [JsonProperty(PropertyName = "type")] + public string Type { get; set; } + + [JsonProperty(PropertyName = "codec")] + public CodecArguments CodecArguments { get; set; } + + [JsonProperty(PropertyName = "message")] + public string Message { get; set; } + + [JsonProperty(PropertyName = "count")] + public int Count { get; set; } + + [JsonProperty(PropertyName = "rate")] + public int Rate { get; set; } + + public void Validate() + { + } + + public GeneratorParameters() + { + Count = 0; // Infinity messages + Rate = 10; // Milliseconds + Message = "Hello, world!"; + CodecArguments = new CodecArguments(); + CodecArguments.Type = CodecArguments.CodecType.plain; + } + } + + public class CodecArguments { public enum CodecType { singleline, - multiline + multiline, + json, + plain }; public enum WhatType @@ -668,6 +702,9 @@ namespace TimberWinR.Parser [JsonProperty("Stdin")] public Stdin[] Stdins { get; set; } + + [JsonProperty("Generator")] + public GeneratorParameters[] Generators { get; set; } } public partial class Grok : LogstashFilter, IValidateSchema diff --git a/TimberWinR/ReleaseNotes.md b/TimberWinR/ReleaseNotes.md index 4957f6a..27aa2ca 100644 --- a/TimberWinR/ReleaseNotes.md +++ b/TimberWinR/ReleaseNotes.md @@ -3,6 +3,11 @@ A Native Windows to Redis/Elasticsearch Logstash Agent which runs as a service. Version / Date +### 1.3.24.0 - 2015-04-29 +1. Fixed potential bug in TailFiles when tailing log files which are partially flushed + to disk, it now will not process the line until the \r\n has been seen. +2. Added Generator input. + ### 1.3.23.0 - 2015-04-23 1. Fixed bug with parsing a single json config file, rather than reading JSON files from a directory. diff --git a/TimberWinR/TimberWinR.csproj b/TimberWinR/TimberWinR.csproj index 6dbbcbe..0ad74d3 100644 --- a/TimberWinR/TimberWinR.csproj +++ b/TimberWinR/TimberWinR.csproj @@ -82,7 +82,9 @@ + + @@ -94,6 +96,7 @@ + @@ -137,6 +140,7 @@ + diff --git a/TimberWinR/mdocs/Generator.md b/TimberWinR/mdocs/Generator.md new file mode 100644 index 0000000..655b3c1 --- /dev/null +++ b/TimberWinR/mdocs/Generator.md @@ -0,0 +1,37 @@ +# Input: Generator + +The Generator input can be used to Generate log files for test purposes. + +## Parameters +The following parameters are allowed when configuring WindowsEvents. + +| Parameter | Type | Description | Details | Default | +| :---------------- |:---------------| :----------------------------------------------------------------------- | :--------------------------- | :-- | +| *type* | string |Message type | | Win32-InputGen | +| *message* | string |Message format to send | | Hello, World! | +| *count* | integer |Number of messages to generate | 0 - Infinite, otherwise that number | 0 | +| *rate* | integer |Sleep time between generated messages | Milliseconds | 10 | +| [codec](https://github.com/Cimpress-MCP/TimberWinR/blob/master/TimberWinR/mdocs/Codec.md) | object | Codec to use | + +Example: Generate 100000 "Hello Win32-InputGen" messages + +```json +{ + "TimberWinR": { + "Inputs": { + "Generator": [ + { + "message": "Hello %{type}", + "count": 100000 + } + ] + } + } +} +``` +## Fields +After a successful parse of an event, the following fields are added: + +| Name | Type | Description | +| ---- |:-----| :-----------| +| Message | STRING | Text line content | From 6db530b52662c4ec941204bb1ffa011fc74376eb Mon Sep 17 00:00:00 2001 From: Eric Fontana Date: Wed, 29 Apr 2015 09:51:40 -0400 Subject: [PATCH 2/4] Remove dead code --- TimberWinR/Manager.cs | 4 +--- chocolateyUninstall.ps1.template | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/TimberWinR/Manager.cs b/TimberWinR/Manager.cs index 035ef88..31746a0 100644 --- a/TimberWinR/Manager.cs +++ b/TimberWinR/Manager.cs @@ -22,9 +22,7 @@ namespace TimberWinR public class Manager { public Configuration Config { get; set; } - public List Outputs { get; set; } - public List Tcps { get; set; } - public List Udps { get; set; } + public List Outputs { get; set; } public List Listeners { get; set; } public bool LiveMonitor { get; set; } diff --git a/chocolateyUninstall.ps1.template b/chocolateyUninstall.ps1.template index 0b821b9..1827afd 100644 --- a/chocolateyUninstall.ps1.template +++ b/chocolateyUninstall.ps1.template @@ -2,8 +2,6 @@ $packageName = 'TimberWinR-${version}' # arbitrary name for the package, used in $installerType = 'msi' #only one of these: exe, msi, msu $scriptPath = $(Split-Path $MyInvocation.MyCommand.Path) $fileFullPath = Join-Path $scriptPath 'TimberWinR-${version}.0.msi' -$silentArgs = '${PROJECTGUID} /quiet' +$silentArgs = '{CC4DF908-07C4-4BD8-A9FA-6E6AC315E30B} /quiet' $validExitCodes = @(0) #please insert other valid exit codes here, exit codes for ms http://msdn.microsoft.com/en-us/library/aa368542(VS.85).aspx UnInstall-ChocolateyPackage "$packageName" "$installerType" "$silentArgs" "fileFullPath" -validExitCodes $validExitCodes - - From 091fe9e7e48d37e2d14e70ac7caf2914ff976902 Mon Sep 17 00:00:00 2001 From: Eric Fontana Date: Wed, 29 Apr 2015 09:55:47 -0400 Subject: [PATCH 3/4] Removed all usage of ForceFlush --- TimberWinR.TestGenerator/JsonLogFileGenerator.cs | 3 +-- TimberWinR.TestGenerator/LogFileGenerator.cs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/TimberWinR.TestGenerator/JsonLogFileGenerator.cs b/TimberWinR.TestGenerator/JsonLogFileGenerator.cs index cd85417..4b35cb3 100644 --- a/TimberWinR.TestGenerator/JsonLogFileGenerator.cs +++ b/TimberWinR.TestGenerator/JsonLogFileGenerator.cs @@ -63,8 +63,7 @@ namespace TimberWinR.TestGenerator // This text is always added, making the file longer over time // if it is not deleted. using (StreamWriter sw = File.AppendText(logFilePath)) - { - sw.AutoFlush = true; + { for (int i = 0; i < parms.NumMessages; i++) { JObject o = new JObject diff --git a/TimberWinR.TestGenerator/LogFileGenerator.cs b/TimberWinR.TestGenerator/LogFileGenerator.cs index be0b91d..31b49b3 100644 --- a/TimberWinR.TestGenerator/LogFileGenerator.cs +++ b/TimberWinR.TestGenerator/LogFileGenerator.cs @@ -64,8 +64,7 @@ namespace TimberWinR.TestGenerator // This text is always added, making the file longer over time // if it is not deleted. using (StreamWriter sw = File.AppendText(logFilePath)) - { - // sw.AutoFlush = true; + { for (int i = 0; i < parms.NumMessages; i++) { JObject o = new JObject From dcbb0791013bf2cbb5cbed15eef667bbdfef0fbe Mon Sep 17 00:00:00 2001 From: Eric Fontana Date: Wed, 29 Apr 2015 10:04:48 -0400 Subject: [PATCH 4/4] Doc tweaks from review and make infinite be infinite --- TimberWinR/Inputs/GeneratorInput.cs | 7 +++---- TimberWinR/mdocs/Generator.md | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/TimberWinR/Inputs/GeneratorInput.cs b/TimberWinR/Inputs/GeneratorInput.cs index 3abb5e7..e22cdb8 100644 --- a/TimberWinR/Inputs/GeneratorInput.cs +++ b/TimberWinR/Inputs/GeneratorInput.cs @@ -59,11 +59,10 @@ namespace TimberWinR.Inputs { LogManager.GetCurrentClassLogger().Info("Generator Creating {0} Lines", _params.Count); - int numMessages = _params.Count; - if (numMessages == 0) - numMessages = int.MaxValue; + int numMessages = _params.Count; - for (int i = 0; i < numMessages; i++) + // Infinite or until done. + for (int i = 0; (_params.Count == 0 || i < numMessages); i++) { if (CancelToken.IsCancellationRequested) break; diff --git a/TimberWinR/mdocs/Generator.md b/TimberWinR/mdocs/Generator.md index 655b3c1..a2cb660 100644 --- a/TimberWinR/mdocs/Generator.md +++ b/TimberWinR/mdocs/Generator.md @@ -3,7 +3,7 @@ The Generator input can be used to Generate log files for test purposes. ## Parameters -The following parameters are allowed when configuring WindowsEvents. +The following parameters are allowed when configuring the test log Generator. | Parameter | Type | Description | Details | Default | | :---------------- |:---------------| :----------------------------------------------------------------------- | :--------------------------- | :-- | @@ -30,7 +30,7 @@ Example: Generate 100000 "Hello Win32-InputGen" messages } ``` ## Fields -After a successful parse of an event, the following fields are added: +After a successful parse of the generated line, the following fields are added: | Name | Type | Description | | ---- |:-----| :-----------|