Compare commits
69 Commits
test_fixtu
...
rel-1.3.27
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a08e8ef65 | ||
|
|
435fa501f0 | ||
|
|
421a5b8e0b | ||
|
|
569b2711cc | ||
|
|
460aa3229e | ||
|
|
b9758affac | ||
|
|
c90869592b | ||
|
|
2c9d998794 | ||
|
|
7d43c2cb67 | ||
|
|
45e4e80488 | ||
|
|
097ffd34c3 | ||
|
|
147e243478 | ||
|
|
8694ede85d | ||
|
|
7cf1230d7a | ||
|
|
4fe5cec9e2 | ||
|
|
9308f91316 | ||
|
|
28d20199ab | ||
|
|
5692d2ec42 | ||
|
|
4dbb926698 | ||
|
|
92f23c1117 | ||
|
|
cd31cf47f5 | ||
|
|
8fe3b1815c | ||
|
|
58ae2db05c | ||
|
|
f1c4343cf6 | ||
|
|
3669acbb26 | ||
|
|
6600bb2b85 | ||
|
|
50473a1f5a | ||
|
|
dcbb079101 | ||
|
|
091fe9e7e4 | ||
|
|
6db530b526 | ||
|
|
4ebe539ea8 | ||
|
|
75619a239a | ||
|
|
fd67c271b5 | ||
|
|
1f3aaf90fd | ||
|
|
dcfdf73842 | ||
|
|
dcd104e4f4 | ||
|
|
2377d4ebd2 | ||
|
|
64979df012 | ||
|
|
5eb75ab143 | ||
|
|
3e9ef6ae88 | ||
|
|
7df4dede90 | ||
|
|
d9509757e3 | ||
|
|
edcac22ea0 | ||
|
|
e98ef89fe2 | ||
|
|
6461369d39 | ||
|
|
f5b2858c1c | ||
|
|
3d0bfc248d | ||
|
|
dbaa52a12e | ||
|
|
7e69175f19 | ||
|
|
baa70eebbc | ||
|
|
29308446a9 | ||
|
|
a0cccc0b7f | ||
|
|
ec2ec66915 | ||
|
|
98ef675f9c | ||
|
|
1468a6d0e6 | ||
|
|
44104f1e59 | ||
|
|
22baef9838 | ||
|
|
1b51fcd989 | ||
|
|
0b3204efe8 | ||
|
|
80f8f9ee0c | ||
|
|
9d08fc2b28 | ||
|
|
349b0bf031 | ||
|
|
8b431f92eb | ||
|
|
770ac1b7b1 | ||
|
|
5d07acad5b | ||
|
|
e4bd5be8b1 | ||
|
|
786b6b4777 | ||
|
|
51dc9ee54c | ||
|
|
796ca51f31 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -155,3 +155,4 @@ $RECYCLE.BIN/
|
|||||||
# Mac desktop service store files
|
# Mac desktop service store files
|
||||||
.DS_Store
|
.DS_Store
|
||||||
packages
|
packages
|
||||||
|
*.msi
|
||||||
|
|||||||
@@ -2,6 +2,6 @@
|
|||||||
<packages>
|
<packages>
|
||||||
<package id="Newtonsoft.Json" version="6.0.4" targetFramework="net40" />
|
<package id="Newtonsoft.Json" version="6.0.4" targetFramework="net40" />
|
||||||
<package id="NUnit.Runners" version="2.6.4" />
|
<package id="NUnit.Runners" version="2.6.4" />
|
||||||
<package id="RapidRegex.Core" version="1.0.0.2" targetFramework="net40" />
|
<package id="RapidRegex.Core" version="1.0.0.4" targetFramework="net40" />
|
||||||
<package id="System.Linq.Dynamic" version="1.0.4" targetFramework="net40" />
|
<package id="System.Linq.Dynamic" version="1.0.4" targetFramework="net40" />
|
||||||
</packages>
|
</packages>
|
||||||
12
README.md
12
README.md
@@ -16,7 +16,7 @@ TimberWinR uses a configuration file to control how the logs are collected, filt
|
|||||||
These are broken down into:
|
These are broken down into:
|
||||||
1. Inputs (Collect data from different sources)
|
1. Inputs (Collect data from different sources)
|
||||||
2. Filters (Are applied to all Inputs)
|
2. Filters (Are applied to all Inputs)
|
||||||
3. Outputs (Redis, Elasticsearch or Stdout)
|
3. Outputs (e.g. Redis, Elasticsearch, Stdout, StatsD)
|
||||||
|
|
||||||
### Support ###
|
### Support ###
|
||||||
Please use the TimberWinR Google Group for discussion and support:
|
Please use the TimberWinR Google Group for discussion and support:
|
||||||
@@ -25,7 +25,8 @@ https://groups.google.com/forum/#!forum/timberwinr
|
|||||||
|
|
||||||
Latest Build:
|
Latest Build:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
## Inputs
|
## Inputs
|
||||||
The current supported Input format sources are:
|
The current supported Input format sources are:
|
||||||
@@ -36,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)
|
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)
|
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)
|
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
|
## Codecs
|
||||||
The current list of supported codecs are:
|
The current list of supported codecs are:
|
||||||
@@ -105,6 +107,8 @@ represented as a JSON Property or Array.
|
|||||||
1. [Redis](https://github.com/Cimpress-MCP/TimberWinR/blob/master/TimberWinR/mdocs/RedisOutput.md)
|
1. [Redis](https://github.com/Cimpress-MCP/TimberWinR/blob/master/TimberWinR/mdocs/RedisOutput.md)
|
||||||
2. [Elasticsearch](https://github.com/Cimpress-MCP/TimberWinR/blob/master/TimberWinR/mdocs/ElasticsearchOutput.md)
|
2. [Elasticsearch](https://github.com/Cimpress-MCP/TimberWinR/blob/master/TimberWinR/mdocs/ElasticsearchOutput.md)
|
||||||
3. [Stdout](https://github.com/Cimpress-MCP/TimberWinR/blob/master/TimberWinR/mdocs/StdoutOutput.md)
|
3. [Stdout](https://github.com/Cimpress-MCP/TimberWinR/blob/master/TimberWinR/mdocs/StdoutOutput.md)
|
||||||
|
4. [File](https://github.com/Cimpress-MCP/TimberWinR/blob/master/TimberWinR/mdocs/FileOutput.md)
|
||||||
|
5. [StatsD](https://github.com/Cimpress-MCP/TimberWinR/blob/master/TimberWinR/mdocs/StatsD.md)
|
||||||
|
|
||||||
## Sample Configuration
|
## Sample Configuration
|
||||||
TimberWinR reads a JSON configuration file, an example file is shown here:
|
TimberWinR reads a JSON configuration file, an example file is shown here:
|
||||||
@@ -167,7 +171,7 @@ following options:
|
|||||||
TimberWinR.ServiceHost.exe -configFile:myconfig.json -logLevel:Debug
|
TimberWinR.ServiceHost.exe -configFile:myconfig.json -logLevel:Debug
|
||||||
```
|
```
|
||||||
|
|
||||||
## Automatic Installation via Chocolatey
|
## Automatic Installation via Chocolatey (embedded)
|
||||||
|
|
||||||
[TimbeWinR Chocolatey](https://chocolatey.org/packages/TimberWinR)
|
[TimbeWinR Chocolatey](https://chocolatey.org/packages/TimberWinR)
|
||||||
|
|
||||||
|
|||||||
@@ -25,14 +25,11 @@ namespace TimberWinR.ServiceHost
|
|||||||
{
|
{
|
||||||
const string KeyPath = @"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\TimberWinR";
|
const string KeyPath = @"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\TimberWinR";
|
||||||
const string KeyName = "ImagePath";
|
const string KeyName = "ImagePath";
|
||||||
|
|
||||||
private static void Main(string[] args)
|
private static void Main(string[] args)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Arguments arguments = new Arguments();
|
Arguments arguments = new Arguments();
|
||||||
|
|
||||||
HostFactory.Run(hostConfigurator =>
|
HostFactory.Run(hostConfigurator =>
|
||||||
{
|
{
|
||||||
string cmdLine = Environment.CommandLine;
|
string cmdLine = Environment.CommandLine;
|
||||||
@@ -48,7 +45,7 @@ namespace TimberWinR.ServiceHost
|
|||||||
hostConfigurator.AddCommandLineDefinition("configFile", c => arguments.ConfigFile = c);
|
hostConfigurator.AddCommandLineDefinition("configFile", c => arguments.ConfigFile = c);
|
||||||
hostConfigurator.AddCommandLineDefinition("logLevel", c => arguments.LogLevel = c);
|
hostConfigurator.AddCommandLineDefinition("logLevel", c => arguments.LogLevel = c);
|
||||||
hostConfigurator.AddCommandLineDefinition("logDir", c => arguments.LogfileDir = c);
|
hostConfigurator.AddCommandLineDefinition("logDir", c => arguments.LogfileDir = c);
|
||||||
hostConfigurator.AddCommandLineDefinition("diagnosticPort", c => arguments.DiagnosticPort = int.Parse(c));
|
hostConfigurator.AddCommandLineDefinition("diagnosticPort", c => arguments.DiagnosticPort = int.Parse(c));
|
||||||
|
|
||||||
hostConfigurator.ApplyCommandLine();
|
hostConfigurator.ApplyCommandLine();
|
||||||
hostConfigurator.RunAsLocalSystem();
|
hostConfigurator.RunAsLocalSystem();
|
||||||
@@ -59,7 +56,7 @@ namespace TimberWinR.ServiceHost
|
|||||||
hostConfigurator.SetServiceName("TimberWinR");
|
hostConfigurator.SetServiceName("TimberWinR");
|
||||||
|
|
||||||
hostConfigurator.AfterInstall(() =>
|
hostConfigurator.AfterInstall(() =>
|
||||||
{
|
{
|
||||||
var currentValue = Registry.GetValue(KeyPath, KeyName, "").ToString();
|
var currentValue = Registry.GetValue(KeyPath, KeyName, "").ToString();
|
||||||
if (!string.IsNullOrEmpty(currentValue))
|
if (!string.IsNullOrEmpty(currentValue))
|
||||||
{
|
{
|
||||||
@@ -75,18 +72,18 @@ namespace TimberWinR.ServiceHost
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void AddServiceParameter(string paramName, string value)
|
private static void AddServiceParameter(string paramName, string value)
|
||||||
{
|
{
|
||||||
string currentValue = Registry.GetValue(KeyPath, KeyName, "").ToString();
|
string currentValue = Registry.GetValue(KeyPath, KeyName, "").ToString();
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(paramName) && !currentValue.Contains(string.Format("{0} ", paramName)))
|
if (!string.IsNullOrEmpty(paramName) && !currentValue.Contains(string.Format("{0} ", paramName)))
|
||||||
{
|
{
|
||||||
currentValue += string.Format(" {0} \"{1}\"", paramName, value.Replace("\\\\", "\\"));
|
currentValue += string.Format(" {0} \"{1}\"", paramName, value.Replace("\\\\", "\\"));
|
||||||
Registry.SetValue(KeyPath, KeyName, currentValue);
|
Registry.SetValue(KeyPath, KeyName, currentValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AddServiceParameter(string paramName, int value)
|
private static void AddServiceParameter(string paramName, int value)
|
||||||
{
|
{
|
||||||
string currentValue = Registry.GetValue(KeyPath, KeyName, "").ToString();
|
string currentValue = Registry.GetValue(KeyPath, KeyName, "").ToString();
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(paramName) && !currentValue.Contains(string.Format("{0}:", paramName)))
|
if (!string.IsNullOrEmpty(paramName) && !currentValue.Contains(string.Format("{0}:", paramName)))
|
||||||
@@ -134,13 +131,15 @@ namespace TimberWinR.ServiceHost
|
|||||||
private readonly Arguments _args;
|
private readonly Arguments _args;
|
||||||
private TimberWinR.Diagnostics.Diagnostics _diags;
|
private TimberWinR.Diagnostics.Diagnostics _diags;
|
||||||
private TimberWinR.Manager _manager;
|
private TimberWinR.Manager _manager;
|
||||||
|
public bool StartingUp { get; set; }
|
||||||
|
public bool Started { get; set; }
|
||||||
|
|
||||||
public TimberWinRService(Arguments args)
|
public TimberWinRService(Arguments args)
|
||||||
{
|
{
|
||||||
_args = args;
|
_args = args;
|
||||||
_cancellationTokenSource = new CancellationTokenSource();
|
_cancellationTokenSource = new CancellationTokenSource();
|
||||||
_cancellationToken = _cancellationTokenSource.Token;
|
_cancellationToken = _cancellationTokenSource.Token;
|
||||||
_serviceTask = new Task(RunService, _cancellationToken);
|
_serviceTask = new Task(RunService, _cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
@@ -150,22 +149,41 @@ namespace TimberWinR.ServiceHost
|
|||||||
|
|
||||||
public void Stop()
|
public void Stop()
|
||||||
{
|
{
|
||||||
|
WaitForStartupToComplete();
|
||||||
|
|
||||||
_cancellationTokenSource.Cancel();
|
_cancellationTokenSource.Cancel();
|
||||||
if (_diags != null)
|
if (_diags != null)
|
||||||
_diags.Shutdown();
|
_diags.Shutdown();
|
||||||
|
|
||||||
if (_manager != null)
|
if (_manager != null)
|
||||||
_manager.Shutdown();
|
_manager.Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If you bounce the service too quickly, the shutdown can occur
|
||||||
|
// before the service has started, which results in a hang, this blocks until
|
||||||
|
// all thread have properly started (waiting up to 10 seconds max)
|
||||||
|
private void WaitForStartupToComplete()
|
||||||
|
{
|
||||||
|
int tries = 100; // 10 seconds max
|
||||||
|
if (StartingUp)
|
||||||
|
{
|
||||||
|
while (!Started && tries-- >= 0)
|
||||||
|
{
|
||||||
|
Thread.Sleep(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The Main body of the Service Worker Thread
|
/// The Main body of the Service Worker Thread
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void RunService()
|
private void RunService()
|
||||||
{
|
{
|
||||||
|
StartingUp = true;
|
||||||
_manager = new TimberWinR.Manager(_args.ConfigFile, _args.LogLevel, _args.LogfileDir, _args.LiveMonitor, _cancellationToken);
|
_manager = new TimberWinR.Manager(_args.ConfigFile, _args.LogLevel, _args.LogfileDir, _args.LiveMonitor, _cancellationToken);
|
||||||
if (_args.DiagnosticPort > 0)
|
if (_args.DiagnosticPort > 0)
|
||||||
_diags = new Diagnostics.Diagnostics(_manager, _cancellationToken, _args.DiagnosticPort);
|
_diags = new Diagnostics.Diagnostics(_manager, _cancellationToken, _args.DiagnosticPort);
|
||||||
|
Started = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
|||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("1.3.20.0")]
|
[assembly: AssemblyVersion("1.3.27.0")]
|
||||||
[assembly: AssemblyFileVersion("1.3.20.0")]
|
[assembly: AssemblyFileVersion("1.3.27.0")]
|
||||||
|
|||||||
@@ -38,9 +38,16 @@
|
|||||||
<ApplicationIcon>timberwinr.ico</ApplicationIcon>
|
<ApplicationIcon>timberwinr.ico</ApplicationIcon>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="RapidRegex.Core, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="RapidRegex.Core, Version=1.0.0.4, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\packages\RapidRegex.Core.1.0.0.2\lib\net40\RapidRegex.Core.dll</HintPath>
|
<HintPath>..\packages\RapidRegex.Core.1.0.0.4\lib\net40\RapidRegex.Core.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="StatsdClient, Version=1.0.0.19, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<SpecificVersion>False</SpecificVersion>
|
||||||
|
<HintPath>..\packages\StatsdClient.1.0.0.19\lib\net35\StatsdClient.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="StatsdClient.Configuration">
|
||||||
|
<HintPath>..\packages\StatsdClient.1.0.0.19\lib\net35\StatsdClient.Configuration.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Configuration.Install" />
|
<Reference Include="System.Configuration.Install" />
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
<package id="RapidRegex.Core" version="1.0.0.2" targetFramework="net40" />
|
<package id="RapidRegex.Core" version="1.0.0.4" targetFramework="net40" />
|
||||||
|
<package id="StatsdClient" version="1.0.0.19" targetFramework="net40" />
|
||||||
<package id="Topshelf" version="3.1.4" targetFramework="net40" />
|
<package id="Topshelf" version="3.1.4" targetFramework="net40" />
|
||||||
</packages>
|
</packages>
|
||||||
@@ -15,6 +15,9 @@ namespace TimberWinR.TestGenerator
|
|||||||
[Option("timberWinRConfig", DefaultValue = "default.json", HelpText = "Config file/directory to use")]
|
[Option("timberWinRConfig", DefaultValue = "default.json", HelpText = "Config file/directory to use")]
|
||||||
public string TimberWinRConfigFile { get; set; }
|
public string TimberWinRConfigFile { get; set; }
|
||||||
|
|
||||||
|
[Option("start", HelpText = "Start an instance of TimberWinR")]
|
||||||
|
public bool StartTimberWinR { get; set; }
|
||||||
|
|
||||||
[Option("testDir", DefaultValue = ".", HelpText = "Test directory to use (created if necessary)")]
|
[Option("testDir", DefaultValue = ".", HelpText = "Test directory to use (created if necessary)")]
|
||||||
public string TestDir { get; set; }
|
public string TestDir { get; set; }
|
||||||
|
|
||||||
@@ -24,6 +27,9 @@ namespace TimberWinR.TestGenerator
|
|||||||
[Option("resultsFile", HelpText = "Expected results Results json file")]
|
[Option("resultsFile", HelpText = "Expected results Results json file")]
|
||||||
public string ExpectedResultsFile { get; set; }
|
public string ExpectedResultsFile { get; set; }
|
||||||
|
|
||||||
|
[Option("totalMessages", DefaultValue = 0, HelpText = "The total number of messages to send to the output(s)")]
|
||||||
|
public int TotalMessages { get; set; }
|
||||||
|
|
||||||
[Option('n', "numMessages", DefaultValue = 1000, HelpText = "The number of messages to send to the output(s)")]
|
[Option('n', "numMessages", DefaultValue = 1000, HelpText = "The number of messages to send to the output(s)")]
|
||||||
public int NumMessages { get; set; }
|
public int NumMessages { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -63,8 +63,7 @@ namespace TimberWinR.TestGenerator
|
|||||||
// This text is always added, making the file longer over time
|
// This text is always added, making the file longer over time
|
||||||
// if it is not deleted.
|
// if it is not deleted.
|
||||||
using (StreamWriter sw = File.AppendText(logFilePath))
|
using (StreamWriter sw = File.AppendText(logFilePath))
|
||||||
{
|
{
|
||||||
sw.AutoFlush = true;
|
|
||||||
for (int i = 0; i < parms.NumMessages; i++)
|
for (int i = 0; i < parms.NumMessages; i++)
|
||||||
{
|
{
|
||||||
JObject o = new JObject
|
JObject o = new JObject
|
||||||
|
|||||||
@@ -64,8 +64,7 @@ namespace TimberWinR.TestGenerator
|
|||||||
// This text is always added, making the file longer over time
|
// This text is always added, making the file longer over time
|
||||||
// if it is not deleted.
|
// if it is not deleted.
|
||||||
using (StreamWriter sw = File.AppendText(logFilePath))
|
using (StreamWriter sw = File.AppendText(logFilePath))
|
||||||
{
|
{
|
||||||
sw.AutoFlush = true;
|
|
||||||
for (int i = 0; i < parms.NumMessages; i++)
|
for (int i = 0; i < parms.NumMessages; i++)
|
||||||
{
|
{
|
||||||
JObject o = new JObject
|
JObject o = new JObject
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using System.Diagnostics;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
|
using System.Net;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -55,7 +56,7 @@ namespace TimberWinR.TestGenerator
|
|||||||
|
|
||||||
ramCounter.CategoryName = "Memory";
|
ramCounter.CategoryName = "Memory";
|
||||||
ramCounter.CounterName = "% Committed Bytes In Use";
|
ramCounter.CounterName = "% Committed Bytes In Use";
|
||||||
|
|
||||||
Options = new CommandLineOptions();
|
Options = new CommandLineOptions();
|
||||||
|
|
||||||
if (CommandLine.Parser.Default.ParseArguments(args, Options))
|
if (CommandLine.Parser.Default.ParseArguments(args, Options))
|
||||||
@@ -86,7 +87,8 @@ namespace TimberWinR.TestGenerator
|
|||||||
var sw = Stopwatch.StartNew();
|
var sw = Stopwatch.StartNew();
|
||||||
|
|
||||||
// Startup TimberWinR
|
// Startup TimberWinR
|
||||||
StartTimberWinR(Options.TimberWinRConfigFile, Options.LogLevel, ".", false);
|
if (Options.StartTimberWinR)
|
||||||
|
StartTimberWinR(Options.TimberWinRConfigFile, Options.LogLevel, ".", false);
|
||||||
|
|
||||||
// Run the Generators
|
// Run the Generators
|
||||||
var arrayOfTasks = RunGenerators(Options);
|
var arrayOfTasks = RunGenerators(Options);
|
||||||
@@ -114,7 +116,16 @@ namespace TimberWinR.TestGenerator
|
|||||||
sw.Start();
|
sw.Start();
|
||||||
|
|
||||||
// Get all the stats
|
// Get all the stats
|
||||||
var jsonTimberWinr = ShutdownTimberWinR();
|
JObject jsonTimberWinr;
|
||||||
|
|
||||||
|
if (Options.StartTimberWinR)
|
||||||
|
jsonTimberWinr = ShutdownTimberWinR();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
jsonTimberWinr = GetDiagnosticsOutput();
|
||||||
|
if (jsonTimberWinr == null)
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
LogManager.GetCurrentClassLogger().Info("Finished Shutdown: " + sw.Elapsed);
|
LogManager.GetCurrentClassLogger().Info("Finished Shutdown: " + sw.Elapsed);
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
@@ -131,6 +142,30 @@ namespace TimberWinR.TestGenerator
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GET(string url)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
|
||||||
|
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
|
||||||
|
Stream stream = response.GetResponseStream();
|
||||||
|
StreamReader reader = new StreamReader(stream);
|
||||||
|
|
||||||
|
string data = reader.ReadToEnd();
|
||||||
|
|
||||||
|
reader.Close();
|
||||||
|
stream.Close();
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LogManager.GetCurrentClassLogger().ErrorException("Error in GET", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private static void CopySourceFile(string fileName, string outputDir)
|
private static void CopySourceFile(string fileName, string outputDir)
|
||||||
{
|
{
|
||||||
FileInfo fi = new FileInfo(fileName);
|
FileInfo fi = new FileInfo(fileName);
|
||||||
@@ -199,11 +234,18 @@ namespace TimberWinR.TestGenerator
|
|||||||
switch (inputProp.Name)
|
switch (inputProp.Name)
|
||||||
{
|
{
|
||||||
case "udp":
|
case "udp":
|
||||||
return VerifyConditions(json, new string[] { "udp" }, inputProp, jresult);
|
if (VerifyConditions(json, new string[] { "udp" }, inputProp, jresult) != 0)
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
case "tcp":
|
||||||
|
if (VerifyConditions(json, new string[] { "tcp" }, inputProp, jresult) != 0)
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
case "log":
|
case "log":
|
||||||
case "taillog":
|
case "taillog":
|
||||||
return VerifyConditions(json, new string[] { "log", "taillog" }, inputProp, jresult);
|
if (VerifyConditions(json, new string[] { "log", "taillog" }, inputProp, jresult) != 0)
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,13 +304,32 @@ namespace TimberWinR.TestGenerator
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static JObject GetDiagnosticsOutput()
|
||||||
|
{
|
||||||
|
if (Diagnostics != null)
|
||||||
|
return Diagnostics.DiagnosticsOutput();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var jsonDiag = GET("http://localhost:5141");
|
||||||
|
if (jsonDiag == null)
|
||||||
|
{
|
||||||
|
LogManager.GetCurrentClassLogger().Error("TimberWinR diagnostics port not responding.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return JObject.Parse(jsonDiag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Wait till all output has been transmitted.
|
// Wait till all output has been transmitted.
|
||||||
private static void WaitForOutputTransmission()
|
private static void WaitForOutputTransmission()
|
||||||
{
|
{
|
||||||
bool completed = false;
|
bool completed = false;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
var json = Diagnostics.DiagnosticsOutput();
|
var json = GetDiagnosticsOutput();
|
||||||
|
if (json == null)
|
||||||
|
return;
|
||||||
|
|
||||||
//Console.WriteLine(json.ToString(Formatting.Indented));
|
//Console.WriteLine(json.ToString(Formatting.Indented));
|
||||||
|
|
||||||
@@ -289,7 +350,7 @@ namespace TimberWinR.TestGenerator
|
|||||||
var mbc = outputToken["queuedMessageCount"].Value<int>();
|
var mbc = outputToken["queuedMessageCount"].Value<int>();
|
||||||
var smc = outputToken["sentMessageCount"].Value<int>();
|
var smc = outputToken["sentMessageCount"].Value<int>();
|
||||||
|
|
||||||
// LogManager.GetCurrentClassLogger().Info("Queued: {0}, Sent: {1}", mbc, smc);
|
//LogManager.GetCurrentClassLogger().Info("Output: {2} Queued: {0}, Sent: {1}", mbc, smc, outputToken.ToString());
|
||||||
|
|
||||||
completed = mbc == 0 && smc >= _totalMessagesToSend;
|
completed = mbc == 0 && smc >= _totalMessagesToSend;
|
||||||
}
|
}
|
||||||
@@ -330,21 +391,27 @@ namespace TimberWinR.TestGenerator
|
|||||||
|
|
||||||
private static JObject ShutdownTimberWinR()
|
private static JObject ShutdownTimberWinR()
|
||||||
{
|
{
|
||||||
_timberWinR.Shutdown();
|
if (_timberWinR != null)
|
||||||
|
{
|
||||||
|
// Cancel any/all other threads
|
||||||
|
_cancellationTokenSource.Cancel();
|
||||||
|
|
||||||
// Cancel any/all other threads
|
_timberWinR.Shutdown();
|
||||||
_cancellationTokenSource.Cancel();
|
|
||||||
|
|
||||||
var json = Diagnostics.DiagnosticsOutput();
|
var json = Diagnostics.DiagnosticsOutput();
|
||||||
|
|
||||||
LogManager.GetCurrentClassLogger()
|
LogManager.GetCurrentClassLogger()
|
||||||
.Info("Average CPU Usage: {0}%, Average RAM Usage: {1}MB, Max CPU: {2}%, Max Mem: {3}MB", _avgCpuUsage, _avgMemUsage, _maxCpuUsage, _maxMemUsage);
|
.Info("Average CPU Usage: {0}%, Average RAM Usage: {1}MB, Max CPU: {2}%, Max Mem: {3}MB",
|
||||||
|
_avgCpuUsage, _avgMemUsage, _maxCpuUsage, _maxMemUsage);
|
||||||
|
|
||||||
LogManager.GetCurrentClassLogger().Info(json.ToString());
|
LogManager.GetCurrentClassLogger().Info(json.ToString());
|
||||||
|
|
||||||
Diagnostics.Shutdown();
|
Diagnostics.Shutdown();
|
||||||
|
|
||||||
return json;
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new JObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void StartTimberWinR(string configFile, string logLevel, string logFileDir, bool enableLiveMonitor)
|
static void StartTimberWinR(string configFile, string logLevel, string logFileDir, bool enableLiveMonitor)
|
||||||
@@ -357,8 +424,6 @@ namespace TimberWinR.TestGenerator
|
|||||||
|
|
||||||
private static void TimberWinROnOnConfigurationProcessed(Configuration configuration)
|
private static void TimberWinROnOnConfigurationProcessed(Configuration configuration)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Processed Config: {0}", configuration.GetHashCode());
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Options.RedisHost) && configuration.RedisOutputs != null && configuration.RedisOutputs.Count() > 0)
|
if (!string.IsNullOrEmpty(Options.RedisHost) && configuration.RedisOutputs != null && configuration.RedisOutputs.Count() > 0)
|
||||||
{
|
{
|
||||||
foreach (var ro in configuration.RedisOutputs)
|
foreach (var ro in configuration.RedisOutputs)
|
||||||
@@ -439,6 +504,8 @@ namespace TimberWinR.TestGenerator
|
|||||||
|
|
||||||
static Task[] RunGenerators(CommandLineOptions options)
|
static Task[] RunGenerators(CommandLineOptions options)
|
||||||
{
|
{
|
||||||
|
_totalMessagesToSend = options.TotalMessages;
|
||||||
|
|
||||||
_monitorTask = Task.Factory.StartNew(() =>
|
_monitorTask = Task.Factory.StartNew(() =>
|
||||||
{
|
{
|
||||||
using (var syncHandle = new ManualResetEventSlim())
|
using (var syncHandle = new ManualResetEventSlim())
|
||||||
|
|||||||
@@ -99,6 +99,45 @@
|
|||||||
<Content Include="results2.json">
|
<Content Include="results2.json">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="test3.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="test3-tw.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="results3.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="test4-tw.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="results4.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="test4.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="test5-twconfig.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="test5.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="results5.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="test7-tw.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="test7.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="results7.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<None Include="sample-apache.log">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\TimberWinR\TimberWinR.csproj">
|
<ProjectReference Include="..\TimberWinR\TimberWinR.csproj">
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using System.Threading;
|
using System.Security.Cryptography;
|
||||||
|
using System.Threading;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NLog.Config;
|
using NLog.Config;
|
||||||
@@ -24,7 +26,7 @@ namespace TimberWinR.TestGenerator
|
|||||||
NumMessages = 100;
|
NumMessages = 100;
|
||||||
Port = 6379;
|
Port = 6379;
|
||||||
Host = "localhost";
|
Host = "localhost";
|
||||||
SleepTimeMilliseconds = 10;
|
SleepTimeMilliseconds = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,16 +50,37 @@ namespace TimberWinR.TestGenerator
|
|||||||
{
|
{
|
||||||
JObject o = new JObject
|
JObject o = new JObject
|
||||||
{
|
{
|
||||||
{"Application", "udp-generator"},
|
{"Application", "udp-generator"},
|
||||||
{"Host", hostName},
|
{"Executable", "VP.Common.SvcFrm.Services.Host, Version=29.7.0.0, Culture=neutral, PublicKeyToken=null"},
|
||||||
|
{"RenderedMessage", "Responding to RequestSchedule message from 10.1.230.36 with Ack because: PRJ byte array is null."},
|
||||||
|
{"Team", "Manufacturing Software"},
|
||||||
|
{"RecordNumber", i},
|
||||||
|
{"Host", hostName},
|
||||||
{"UtcTimestamp", DateTime.UtcNow.ToString("o")},
|
{"UtcTimestamp", DateTime.UtcNow.ToString("o")},
|
||||||
{"Type", "udp"},
|
{"Type", "VP.Fulfillment.Direct.Initialization.LogWrapper"},
|
||||||
{"Message", "Testgenerator udp message " + DateTime.UtcNow.ToString("o")},
|
{"Message", "Testgenerator udp message " + DateTime.UtcNow.ToString("o")},
|
||||||
{"Index", "logstash"}
|
{"Index", "logstash"}
|
||||||
};
|
};
|
||||||
byte[] sendbuf = Encoding.UTF8.GetBytes(o.ToString());
|
|
||||||
|
string hashedString = "";
|
||||||
|
foreach(var key in o)
|
||||||
|
{
|
||||||
|
hashedString += key.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
var source = ASCIIEncoding.ASCII.GetBytes(hashedString);
|
||||||
|
var md5 = new MD5CryptoServiceProvider().ComputeHash(source);
|
||||||
|
var hash = string.Concat(md5.Select(x => x.ToString("X2")));
|
||||||
|
|
||||||
|
o["md5"] = hash;
|
||||||
|
|
||||||
|
byte[] sendbuf = Encoding.UTF8.GetBytes(o.ToString(Formatting.None));
|
||||||
IPEndPoint ep = new IPEndPoint(broadcast, parms.Port);
|
IPEndPoint ep = new IPEndPoint(broadcast, parms.Port);
|
||||||
s.SendTo(sendbuf, ep);
|
s.SendTo(sendbuf, ep);
|
||||||
|
|
||||||
|
if (i % 1000 == 0)
|
||||||
|
LogManager.GetCurrentClassLogger().Info("Sent {0} of {1} messages", i, parms.NumMessages);
|
||||||
|
|
||||||
Thread.Sleep(parms.SleepTimeMilliseconds);
|
Thread.Sleep(parms.SleepTimeMilliseconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
"batch_count": 500,
|
"batch_count": 500,
|
||||||
"threads": 2,
|
"threads": 2,
|
||||||
"host": [
|
"host": [
|
||||||
"tstlexiceapp006.vistaprint.svc"
|
"tstlexiceapp006.mycompany.svc"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,14 +5,14 @@
|
|||||||
"taillog": {
|
"taillog": {
|
||||||
"test1: message sent count": "[messages] == 7404",
|
"test1: message sent count": "[messages] == 7404",
|
||||||
"test2: average cpu": "[avgCpuUsage] <= 30",
|
"test2: average cpu": "[avgCpuUsage] <= 30",
|
||||||
"test3: maximum memory": "[maxMemUsage] <= 20"
|
"test3: maximum memory": "[maxMemUsage] <= 30"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"udp": {
|
"udp": {
|
||||||
"test1: message sent count": "[messages] == 1234",
|
"test1: message sent count": "[messages] == 1234",
|
||||||
"test2: average cpu": "[avgCpuUsage] <= 30",
|
"test2: average cpu": "[avgCpuUsage] <= 30",
|
||||||
"test3: maximum memory": "[maxMemUsage] <= 20"
|
"test3: maximum memory": "[maxMemUsage] <= 30"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,14 +5,14 @@
|
|||||||
"taillog": {
|
"taillog": {
|
||||||
"test1: message sent count": "[messages] == 7404",
|
"test1: message sent count": "[messages] == 7404",
|
||||||
"test2: average cpu": "[avgCpuUsage] <= 30",
|
"test2: average cpu": "[avgCpuUsage] <= 30",
|
||||||
"test3: maximum memory": "[maxMemUsage] <= 15"
|
"test3: maximum memory": "[maxMemUsage] <= 20"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"udp": {
|
"udp": {
|
||||||
"test1: message sent count": "[messages] == 1234",
|
"test1: message sent count": "[messages] == 1234",
|
||||||
"test2: average cpu": "[avgCpuUsage] <= 30",
|
"test2: average cpu": "[avgCpuUsage] <= 30",
|
||||||
"test3: maximum memory": "[maxMemUsage] <= 15"
|
"test3: maximum memory": "[maxMemUsage] <= 20"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
20
TimberWinR.TestGenerator/results3.json
Normal file
20
TimberWinR.TestGenerator/results3.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"Results": {
|
||||||
|
"Inputs": [
|
||||||
|
{
|
||||||
|
"taillog": {
|
||||||
|
"test1: message sent count": "[messages] == 7404",
|
||||||
|
"test2: average cpu": "[avgCpuUsage] <= 30",
|
||||||
|
"test3: maximum memory": "[maxMemUsage] <= 15"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcp": {
|
||||||
|
"test4: message sent count": "[messages] == 1234",
|
||||||
|
"test5: average cpu": "[avgCpuUsage] <= 30",
|
||||||
|
"test6: maximum memory": "[maxMemUsage] <= 15"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
20
TimberWinR.TestGenerator/results4.json
Normal file
20
TimberWinR.TestGenerator/results4.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"Results": {
|
||||||
|
"Inputs": [
|
||||||
|
{
|
||||||
|
"taillog": {
|
||||||
|
"test1: message sent count": "[messages] == 7404",
|
||||||
|
"test2: average cpu": "[avgCpuUsage] <= 30",
|
||||||
|
"test3: maximum memory": "[maxMemUsage] <= 15"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcp": {
|
||||||
|
"test4: message sent count": "[messages] == 1234",
|
||||||
|
"test5: average cpu": "[avgCpuUsage] <= 30",
|
||||||
|
"test6: maximum memory": "[maxMemUsage] <= 15"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
13
TimberWinR.TestGenerator/results5.json
Normal file
13
TimberWinR.TestGenerator/results5.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"Results": {
|
||||||
|
"Inputs": [
|
||||||
|
{
|
||||||
|
"udp": {
|
||||||
|
"test1: message sent count": "[messages] == 80000",
|
||||||
|
"test2: average cpu": "[avgCpuUsage] <= 30",
|
||||||
|
"test3: maximum memory": "[maxMemUsage] <= 30"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
13
TimberWinR.TestGenerator/results7.json
Normal file
13
TimberWinR.TestGenerator/results7.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"Results": {
|
||||||
|
"Inputs": [
|
||||||
|
{
|
||||||
|
"udp": {
|
||||||
|
"test1: message sent count": "[messages] == 80000",
|
||||||
|
"test2: average cpu": "[avgCpuUsage] <= 30",
|
||||||
|
"test3: maximum memory": "[maxMemUsage] <= 30"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
2224
TimberWinR.TestGenerator/sample-apache.log
Normal file
2224
TimberWinR.TestGenerator/sample-apache.log
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,14 @@
|
|||||||
{
|
{
|
||||||
"TimberWinR": {
|
"TimberWinR": {
|
||||||
"Inputs": {
|
"Inputs": {
|
||||||
"Udp": [
|
"Udp": [
|
||||||
{
|
{
|
||||||
"_comment": "Output from NLog",
|
"_comment": "Output from NLog",
|
||||||
"port": 5140
|
"port": 5140
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"TailFiles": [
|
"TailFiles": [
|
||||||
{
|
{
|
||||||
"interval": 5,
|
"interval": 5,
|
||||||
"logSource": "log files",
|
"logSource": "log files",
|
||||||
"location": "*.jlog",
|
"location": "*.jlog",
|
||||||
@@ -25,6 +25,11 @@
|
|||||||
""
|
""
|
||||||
],
|
],
|
||||||
"drop": "true"
|
"drop": "true"
|
||||||
|
},
|
||||||
|
"json": {
|
||||||
|
"type": "Win32-TailFile",
|
||||||
|
"source": "Text",
|
||||||
|
"promote": "Text"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -34,9 +39,9 @@
|
|||||||
"_comment": "Change the host to your Redis instance",
|
"_comment": "Change the host to your Redis instance",
|
||||||
"port": 6379,
|
"port": 6379,
|
||||||
"batch_count": 500,
|
"batch_count": 500,
|
||||||
"threads": 2,
|
"threads": 1,
|
||||||
"host": [
|
"host": [
|
||||||
"tstlexiceapp006.vistaprint.svc"
|
"tstlexiceapp006.mycompany.svc"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
{
|
{
|
||||||
"test": "Test 1",
|
"test": "Test 1",
|
||||||
"arguments": {
|
"arguments": {
|
||||||
|
"--start": "",
|
||||||
"--testFile": "test1.json",
|
"--testFile": "test1.json",
|
||||||
"--testDir": "test1",
|
"--testDir": "test1",
|
||||||
"--timberWinRConfig": "test1-twconfig.json",
|
"--timberWinRConfig": "test1-twconfig.json",
|
||||||
"--numMessages": 1234,
|
"--numMessages": 1234,
|
||||||
"--logLevel": "debug",
|
"--logLevel": "debug",
|
||||||
"--udp-host": "::1",
|
"--udp-host": "localhost",
|
||||||
"--udp": "5140",
|
"--udp": "5140",
|
||||||
"--jroll": ["r1.jlog", "r2.jlog"],
|
"--jroll": ["r1.jlog", "r2.jlog"],
|
||||||
"--json": ["1.jlog", "2.jlog", "3.jlog", "4.jlog"],
|
"--json": ["1.jlog", "2.jlog", "3.jlog", "4.jlog"],
|
||||||
"--resultsFile": "results1.json"
|
"--resultsFile": "results1.json"
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
"batch_count": 500,
|
"batch_count": 500,
|
||||||
"threads": 2,
|
"threads": 2,
|
||||||
"host": [
|
"host": [
|
||||||
"tstlexiceapp006.vistaprint.svc"
|
"tstlexiceapp006.mycompany.svc"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"test": "Test 2",
|
"test": "Test 2",
|
||||||
"arguments": {
|
"arguments": {
|
||||||
|
"--start": "",
|
||||||
"--testFile": "test2.json",
|
"--testFile": "test2.json",
|
||||||
"--testDir": "test2",
|
"--testDir": "test2",
|
||||||
"--timberWinRConfig": "test2-tw.json",
|
"--timberWinRConfig": "test2-tw.json",
|
||||||
|
|||||||
50
TimberWinR.TestGenerator/test3-tw.json
Normal file
50
TimberWinR.TestGenerator/test3-tw.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"TimberWinR": {
|
||||||
|
"Inputs": {
|
||||||
|
"Udp": [
|
||||||
|
{
|
||||||
|
"_comment": "Output from NLog",
|
||||||
|
"port": 5140
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"TailFiles": [
|
||||||
|
{
|
||||||
|
"interval": 5,
|
||||||
|
"logSource": "log files",
|
||||||
|
"location": "d:\\logs\\sta\\sta.log",
|
||||||
|
"recurse": -1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Filters": [
|
||||||
|
{
|
||||||
|
"grok": {
|
||||||
|
"condition": "\"[EventTypeName]\" == \"Information Event\"",
|
||||||
|
"match": [
|
||||||
|
"Text",
|
||||||
|
""
|
||||||
|
],
|
||||||
|
"drop": "true"
|
||||||
|
},
|
||||||
|
"json": {
|
||||||
|
"type": "Win32-TailFile",
|
||||||
|
"source": "Text",
|
||||||
|
"promote": "Text"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Outputs": {
|
||||||
|
"Redis": [
|
||||||
|
{
|
||||||
|
"_comment": "Change the host to your Redis instance",
|
||||||
|
"port": 6379,
|
||||||
|
"batch_count": 500,
|
||||||
|
"threads": 2,
|
||||||
|
"host": [
|
||||||
|
"tstlexiceapp006.mycompany.svc"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12
TimberWinR.TestGenerator/test3.json
Normal file
12
TimberWinR.TestGenerator/test3.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"test": "Test 3",
|
||||||
|
"arguments": {
|
||||||
|
"--start": "",
|
||||||
|
"--testFile": "test3.json",
|
||||||
|
"--testDir": "test3",
|
||||||
|
"--timberWinRConfig": "test3-tw.json",
|
||||||
|
"--numMessages": 1234,
|
||||||
|
"--logLevel": "debug",
|
||||||
|
"--resultsFile": "results3.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
50
TimberWinR.TestGenerator/test4-tw.json
Normal file
50
TimberWinR.TestGenerator/test4-tw.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"TimberWinR": {
|
||||||
|
"Inputs": {
|
||||||
|
"Udp": [
|
||||||
|
{
|
||||||
|
"_comment": "Output from NLog",
|
||||||
|
"port": 5140
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"TailFiles": [
|
||||||
|
{
|
||||||
|
"interval": 5,
|
||||||
|
"logSource": "log files",
|
||||||
|
"location": "d:\\logs\\sta\\sta.log",
|
||||||
|
"recurse": -1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Filters": [
|
||||||
|
{
|
||||||
|
"grok": {
|
||||||
|
"condition": "\"[EventTypeName]\" == \"Information Event\"",
|
||||||
|
"match": [
|
||||||
|
"Text",
|
||||||
|
""
|
||||||
|
],
|
||||||
|
"drop": "true"
|
||||||
|
},
|
||||||
|
"json": {
|
||||||
|
"type": "Win32-TailFile",
|
||||||
|
"source": "Text",
|
||||||
|
"promote": "Text"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Outputs": {
|
||||||
|
"Redis": [
|
||||||
|
{
|
||||||
|
"_comment": "Change the host to your Redis instance",
|
||||||
|
"port": 6379,
|
||||||
|
"batch_count": 500,
|
||||||
|
"threads": 2,
|
||||||
|
"host": [
|
||||||
|
"tstlexiceapp006.mycompany.svc"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
TimberWinR.TestGenerator/test4.json
Normal file
11
TimberWinR.TestGenerator/test4.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"test": "Test 4",
|
||||||
|
"arguments": {
|
||||||
|
"--testFile": "test4.json",
|
||||||
|
"--testDir": "test4",
|
||||||
|
"--timberWinRConfig": "test4-tw.json",
|
||||||
|
"--numMessages": 1234,
|
||||||
|
"--logLevel": "debug",
|
||||||
|
"--resultsFile": "results4.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
36
TimberWinR.TestGenerator/test5-twconfig.json
Normal file
36
TimberWinR.TestGenerator/test5-twconfig.json
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"TimberWinR": {
|
||||||
|
"Inputs": {
|
||||||
|
"Udp": [
|
||||||
|
{
|
||||||
|
"_comment": "Output from NLog",
|
||||||
|
"port": 5140,
|
||||||
|
"add_field": [
|
||||||
|
"Environment",
|
||||||
|
"PLANT_TST_TIMBERWINR"
|
||||||
|
],
|
||||||
|
"rename": [
|
||||||
|
"Type",
|
||||||
|
"type"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"TailFiles": [
|
||||||
|
{
|
||||||
|
"interval": 5,
|
||||||
|
"logSource": "log files",
|
||||||
|
"location": "*.jlog",
|
||||||
|
"recurse": -1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Outputs": {
|
||||||
|
"File": [
|
||||||
|
{
|
||||||
|
"format": "indented",
|
||||||
|
"file_name": "test5_output.txt"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
TimberWinR.TestGenerator/test5.json
Normal file
15
TimberWinR.TestGenerator/test5.json
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"test": "Test 5",
|
||||||
|
"arguments": {
|
||||||
|
"--start": "",
|
||||||
|
"--testFile": "test5.json",
|
||||||
|
"--testDir": "test5",
|
||||||
|
"--timberWinRConfig": "test5-twconfig.json",
|
||||||
|
"--numMessages": 80000,
|
||||||
|
"--logLevel": "debug",
|
||||||
|
"--udp-host": "localhost",
|
||||||
|
"--udp": "5140",
|
||||||
|
"--udp-rate": 1,
|
||||||
|
"--resultsFile": "results5.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
37
TimberWinR.TestGenerator/test7-tw.json
Normal file
37
TimberWinR.TestGenerator/test7-tw.json
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"TimberWinR": {
|
||||||
|
"Inputs": {
|
||||||
|
"TailFiles": [
|
||||||
|
{
|
||||||
|
"interval": 5,
|
||||||
|
"logSource": "apache log files",
|
||||||
|
"location": "..\\sample-apache.log",
|
||||||
|
"recurse": -1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Filters": [
|
||||||
|
{
|
||||||
|
"grok": {
|
||||||
|
"type": "Win32-TailLog",
|
||||||
|
"match": [
|
||||||
|
"Text",
|
||||||
|
"%{COMBINEDAPACHELOG}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Outputs": {
|
||||||
|
"StatsD": [
|
||||||
|
{
|
||||||
|
"type": "Win32-TailLog",
|
||||||
|
"namespace": "timberwinrtest",
|
||||||
|
"port": 8125,
|
||||||
|
"host": "devlexicesnu003.mycompany.svc",
|
||||||
|
"increment": ["apache.response.%{response}"],
|
||||||
|
"count": ["apache.bytes", "%{bytes}"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
TimberWinR.TestGenerator/test7.json
Normal file
13
TimberWinR.TestGenerator/test7.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"test": "Test 7",
|
||||||
|
"arguments": {
|
||||||
|
"--totalMessages": 2223,
|
||||||
|
"--start": "",
|
||||||
|
"--testFile": "test7.json",
|
||||||
|
"--testDir": "test7",
|
||||||
|
"--timberWinRConfig": "test7-tw.json",
|
||||||
|
"--numMessages": 1234,
|
||||||
|
"--logLevel": "debug",
|
||||||
|
"--resultsFile": "results7.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -77,5 +77,56 @@ namespace TimberWinR.UnitTests
|
|||||||
Assert.IsNull(nostuff);
|
Assert.IsNull(nostuff);
|
||||||
Assert.AreEqual(6, jsonInputLine2.Count);
|
Assert.AreEqual(6, jsonInputLine2.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestRenameAndAdds()
|
||||||
|
{
|
||||||
|
JObject jsonInputLine1 = new JObject
|
||||||
|
{
|
||||||
|
{"type", "Win32-FileLog"},
|
||||||
|
{"ComputerName", "dev.mycompany.net"},
|
||||||
|
{"Text", "{\"log4net:Username\" : \"NT AUTHORITY\",\"Email\":\"james@example.com\",\"Active\":true,\"CreatedDate\":\"2013-01-20T00:00:00Z\",\"Roles\":[\"User\",\"Admin\"]}"}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
string jsonFilter = @"{
|
||||||
|
""TimberWinR"":{
|
||||||
|
""Filters"":[
|
||||||
|
{
|
||||||
|
""json"":{
|
||||||
|
""type"": ""Win32-FileLog"",
|
||||||
|
""source"": ""Text"",
|
||||||
|
""promote"": ""Text"",
|
||||||
|
""add_field"":[
|
||||||
|
""test1"",
|
||||||
|
""value1"",
|
||||||
|
""test2"",
|
||||||
|
""value2""
|
||||||
|
],
|
||||||
|
""rename"":[
|
||||||
|
""Active"",
|
||||||
|
""active"",
|
||||||
|
""log4net:Username"",
|
||||||
|
""lusername""
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}";
|
||||||
|
|
||||||
|
|
||||||
|
// Positive Tests
|
||||||
|
Configuration c = Configuration.FromString(jsonFilter);
|
||||||
|
Json jf = c.Filters.First() as Json;
|
||||||
|
Assert.IsTrue(jf.Apply(jsonInputLine1));
|
||||||
|
|
||||||
|
Assert.AreEqual("NT AUTHORITY", jsonInputLine1["lusername"].ToString());
|
||||||
|
Assert.AreEqual("True", jsonInputLine1["active"].ToString());
|
||||||
|
Assert.IsNotNull(jsonInputLine1["test1"]);
|
||||||
|
Assert.IsNotNull(jsonInputLine1["test2"]);
|
||||||
|
Assert.AreEqual("value1", jsonInputLine1["test1"].ToString());
|
||||||
|
Assert.AreEqual("value2", jsonInputLine1["test2"].ToString());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,4 +116,7 @@ Global
|
|||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
GlobalSection(Performance) = preSolution
|
||||||
|
HasPerformanceSessions = true
|
||||||
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
26
TimberWinR/Codecs/JsonCodec.cs
Normal file
26
TimberWinR/Codecs/JsonCodec.cs
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
39
TimberWinR/Codecs/PlainCodec.cs
Normal file
39
TimberWinR/Codecs/PlainCodec.cs
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,6 +39,12 @@ namespace TimberWinR
|
|||||||
get { return _events; }
|
get { return _events; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<StatsDOutputParameters> _statsdOutputs = new List<StatsDOutputParameters>();
|
||||||
|
public IEnumerable<StatsDOutputParameters> StatsDOutputs
|
||||||
|
{
|
||||||
|
get { return _statsdOutputs; }
|
||||||
|
}
|
||||||
|
|
||||||
private List<RedisOutputParameters> _redisOutputs = new List<RedisOutputParameters>();
|
private List<RedisOutputParameters> _redisOutputs = new List<RedisOutputParameters>();
|
||||||
public IEnumerable<RedisOutputParameters> RedisOutputs
|
public IEnumerable<RedisOutputParameters> RedisOutputs
|
||||||
{
|
{
|
||||||
@@ -58,6 +64,12 @@ namespace TimberWinR
|
|||||||
get { return _stdoutOutputs; }
|
get { return _stdoutOutputs; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<FileOutputParameters> _fileOutputs = new List<FileOutputParameters>();
|
||||||
|
public IEnumerable<FileOutputParameters> FileOutputs
|
||||||
|
{
|
||||||
|
get { return _fileOutputs; }
|
||||||
|
}
|
||||||
|
|
||||||
private List<TcpParameters> _tcps = new List<TcpParameters>();
|
private List<TcpParameters> _tcps = new List<TcpParameters>();
|
||||||
public IEnumerable<TcpParameters> Tcps
|
public IEnumerable<TcpParameters> Tcps
|
||||||
{
|
{
|
||||||
@@ -102,6 +114,12 @@ namespace TimberWinR
|
|||||||
get { return _stdins; }
|
get { return _stdins; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<GeneratorParameters> _generators = new List<GeneratorParameters>();
|
||||||
|
public IEnumerable<GeneratorParameters> Generators
|
||||||
|
{
|
||||||
|
get { return _generators; }
|
||||||
|
}
|
||||||
|
|
||||||
private List<LogstashFilter> _filters = new List<LogstashFilter>();
|
private List<LogstashFilter> _filters = new List<LogstashFilter>();
|
||||||
|
|
||||||
public IEnumerable<LogstashFilter> Filters
|
public IEnumerable<LogstashFilter> Filters
|
||||||
@@ -239,6 +257,8 @@ namespace TimberWinR
|
|||||||
c._iisw3clogs.AddRange(x.TimberWinR.Inputs.IISW3CLogs.ToList());
|
c._iisw3clogs.AddRange(x.TimberWinR.Inputs.IISW3CLogs.ToList());
|
||||||
if (x.TimberWinR.Inputs.Stdins != null)
|
if (x.TimberWinR.Inputs.Stdins != null)
|
||||||
c._stdins.AddRange(x.TimberWinR.Inputs.Stdins.ToList());
|
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)
|
if (x.TimberWinR.Inputs.Logs != null)
|
||||||
c._logs.AddRange(x.TimberWinR.Inputs.Logs.ToList());
|
c._logs.AddRange(x.TimberWinR.Inputs.Logs.ToList());
|
||||||
if (x.TimberWinR.Inputs.TailFilesArguments != null)
|
if (x.TimberWinR.Inputs.TailFilesArguments != null)
|
||||||
@@ -251,12 +271,16 @@ namespace TimberWinR
|
|||||||
|
|
||||||
if (x.TimberWinR.Outputs != null)
|
if (x.TimberWinR.Outputs != null)
|
||||||
{
|
{
|
||||||
|
if (x.TimberWinR.Outputs.StatsD != null)
|
||||||
|
c._statsdOutputs.AddRange(x.TimberWinR.Outputs.StatsD.ToList());
|
||||||
if (x.TimberWinR.Outputs.Redis != null)
|
if (x.TimberWinR.Outputs.Redis != null)
|
||||||
c._redisOutputs.AddRange(x.TimberWinR.Outputs.Redis.ToList());
|
c._redisOutputs.AddRange(x.TimberWinR.Outputs.Redis.ToList());
|
||||||
if (x.TimberWinR.Outputs.Elasticsearch != null)
|
if (x.TimberWinR.Outputs.Elasticsearch != null)
|
||||||
c._elasticsearchOutputs.AddRange(x.TimberWinR.Outputs.Elasticsearch.ToList());
|
c._elasticsearchOutputs.AddRange(x.TimberWinR.Outputs.Elasticsearch.ToList());
|
||||||
if (x.TimberWinR.Outputs.Stdout != null)
|
if (x.TimberWinR.Outputs.Stdout != null)
|
||||||
c._stdoutOutputs.AddRange(x.TimberWinR.Outputs.Stdout.ToList());
|
c._stdoutOutputs.AddRange(x.TimberWinR.Outputs.Stdout.ToList());
|
||||||
|
if (x.TimberWinR.Outputs.File != null)
|
||||||
|
c._fileOutputs.AddRange(x.TimberWinR.Outputs.File.ToList());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x.TimberWinR.Filters != null)
|
if (x.TimberWinR.Filters != null)
|
||||||
@@ -291,9 +315,11 @@ namespace TimberWinR
|
|||||||
_events = new List<WindowsEvent>();
|
_events = new List<WindowsEvent>();
|
||||||
_iisw3clogs = new List<IISW3CLogParameters>();
|
_iisw3clogs = new List<IISW3CLogParameters>();
|
||||||
_logs = new List<LogParameters>();
|
_logs = new List<LogParameters>();
|
||||||
|
_statsdOutputs = new List<StatsDOutputParameters>();
|
||||||
_redisOutputs = new List<RedisOutputParameters>();
|
_redisOutputs = new List<RedisOutputParameters>();
|
||||||
_elasticsearchOutputs = new List<ElasticsearchOutputParameters>();
|
_elasticsearchOutputs = new List<ElasticsearchOutputParameters>();
|
||||||
_stdoutOutputs = new List<StdoutOutputParameters>();
|
_stdoutOutputs = new List<StdoutOutputParameters>();
|
||||||
|
_fileOutputs = new List<FileOutputParameters>();
|
||||||
_tcps = new List<TcpParameters>();
|
_tcps = new List<TcpParameters>();
|
||||||
_udps = new List<UdpParameters>();
|
_udps = new List<UdpParameters>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using System.Threading;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq.Expressions;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
using NLog;
|
using NLog;
|
||||||
@@ -52,29 +52,48 @@ namespace TimberWinR.Diagnostics
|
|||||||
public JObject DiagnosticsOutput()
|
public JObject DiagnosticsOutput()
|
||||||
{
|
{
|
||||||
JObject json = new JObject(
|
JObject json = new JObject(
|
||||||
new JProperty("timberwinr",
|
new JProperty("timberwinr",
|
||||||
new JObject(
|
new JObject(
|
||||||
new JProperty("version", Assembly.GetEntryAssembly().GetName().Version.ToString()),
|
new JProperty("version", Assembly.GetEntryAssembly().GetName().Version.ToString()),
|
||||||
new JProperty("messages", Manager.NumMessages),
|
new JProperty("messages", Manager.NumMessages),
|
||||||
new JProperty("startedon", Manager.StartedOn),
|
new JProperty("startedon", Manager.StartedOn),
|
||||||
new JProperty("configfile", Manager.JsonConfig),
|
new JProperty("configfile", Manager.JsonConfig),
|
||||||
new JProperty("logdir", Manager.LogfileDir),
|
new JProperty("logdir", Manager.LogfileDir),
|
||||||
new JProperty("logginglevel", LogManager.GlobalThreshold.ToString()),
|
new JProperty("logginglevel", LogManager.GlobalThreshold.ToString())
|
||||||
new JProperty("inputs",
|
)));
|
||||||
new JArray(
|
AddDiagnosis(json);
|
||||||
from i in Manager.Listeners
|
|
||||||
select new JObject(i.ToJson()))),
|
|
||||||
new JProperty("filters",
|
|
||||||
new JArray(
|
|
||||||
from f in Manager.Config.Filters
|
|
||||||
select new JObject(f.ToJson()))),
|
|
||||||
new JProperty("outputs",
|
|
||||||
new JArray(
|
|
||||||
from o in Manager.Outputs
|
|
||||||
select new JObject(o.ToJson()))))));
|
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void AddDiagnosis(JObject wrapper)
|
||||||
|
{
|
||||||
|
wrapper.Add("inputs", GetDiagnosisByType("inputs", Manager.Listeners.ToList<IDiagnosable>()));
|
||||||
|
wrapper.Add("filters", GetDiagnosisByType("filters", Manager.Config.Filters.ToList<IDiagnosable>()));
|
||||||
|
wrapper.Add("outputs", GetDiagnosisByType("inputs", Manager.Outputs.ToList<IDiagnosable>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected JObject GetDiagnosisByType(String type, List<IDiagnosable> diags)
|
||||||
|
{
|
||||||
|
JObject category = new JObject();
|
||||||
|
foreach(IDiagnosable diag in diags)
|
||||||
|
{
|
||||||
|
JArray array = GetTypeArray(diag.GetType().Name.ToString(), category);
|
||||||
|
array.Add(diag.ToJson());
|
||||||
|
}
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected JArray GetTypeArray(String name, JObject category)
|
||||||
|
{
|
||||||
|
JArray ret = (JArray)category.GetValue(name);
|
||||||
|
if (ret == null)
|
||||||
|
{
|
||||||
|
ret = new JArray();
|
||||||
|
category.Add(new JProperty(name, ret));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
private void DiagnosticCallback(IAsyncResult result)
|
private void DiagnosticCallback(IAsyncResult result)
|
||||||
{
|
{
|
||||||
if (web == null)
|
if (web == null)
|
||||||
|
|||||||
13
TimberWinR/Diagnostics/IDiagnosable.cs
Normal file
13
TimberWinR/Diagnostics/IDiagnosable.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace TimberWinR.Diagnostics
|
||||||
|
{
|
||||||
|
public interface IDiagnosable
|
||||||
|
{
|
||||||
|
JObject ToJson();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,8 +30,6 @@ namespace TimberWinR.Parser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public partial class Grok : LogstashFilter
|
public partial class Grok : LogstashFilter
|
||||||
{
|
{
|
||||||
public override JObject ToJson()
|
public override JObject ToJson()
|
||||||
@@ -92,35 +90,37 @@ namespace TimberWinR.Parser
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test for any true matching condition(s)
|
||||||
private bool Matches(Newtonsoft.Json.Linq.JObject json)
|
private bool Matches(Newtonsoft.Json.Linq.JObject json)
|
||||||
{
|
{
|
||||||
string field = Match[0];
|
for (int i = 0; i < Match.Length; i += 2)
|
||||||
string expr = Match[1];
|
|
||||||
|
|
||||||
JToken token = null;
|
|
||||||
if (json.TryGetValue(field, out token))
|
|
||||||
{
|
{
|
||||||
string text = token.ToString();
|
string field = Match[i];
|
||||||
if (!string.IsNullOrEmpty(text))
|
string expr = Match[i + 1];
|
||||||
|
|
||||||
|
JToken token = null;
|
||||||
|
if (json.TryGetValue(field, out token))
|
||||||
{
|
{
|
||||||
var resolver = new RegexGrokResolver();
|
string text = token.ToString();
|
||||||
var pattern = resolver.ResolveToRegex(expr);
|
if (!string.IsNullOrEmpty(text))
|
||||||
var match = Regex.Match(text, pattern);
|
|
||||||
if (match.Success)
|
|
||||||
{
|
{
|
||||||
var regex = new Regex(pattern);
|
var resolver = new RegexGrokResolver();
|
||||||
var namedCaptures = regex.MatchNamedCaptures(text);
|
var pattern = resolver.ResolveToRegex(expr);
|
||||||
foreach (string fieldName in namedCaptures.Keys)
|
var match = Regex.Match(text, pattern);
|
||||||
|
if (match.Success)
|
||||||
{
|
{
|
||||||
AddOrModify(json, fieldName, namedCaptures[fieldName]);
|
var regex = new Regex(pattern);
|
||||||
|
var namedCaptures = regex.MatchNamedCaptures(text);
|
||||||
|
foreach (string fieldName in namedCaptures.Keys)
|
||||||
|
{
|
||||||
|
AddOrModify(json, fieldName, namedCaptures[fieldName]);
|
||||||
|
}
|
||||||
|
return true; // Yes!
|
||||||
}
|
}
|
||||||
return true; // Yes!
|
|
||||||
}
|
}
|
||||||
|
if (string.IsNullOrEmpty(expr))
|
||||||
|
return true; // Empty field is no match
|
||||||
}
|
}
|
||||||
if (string.IsNullOrEmpty(expr))
|
|
||||||
return true; // Empty field is no match
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return false; // Not specified is failure
|
return false; // Not specified is failure
|
||||||
}
|
}
|
||||||
@@ -136,7 +136,7 @@ namespace TimberWinR.Parser
|
|||||||
AddOrModify(json, fieldName, fieldValue);
|
AddOrModify(json, fieldName, fieldValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveFields(Newtonsoft.Json.Linq.JObject json)
|
private void RemoveFields(Newtonsoft.Json.Linq.JObject json)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
@@ -12,6 +13,8 @@ namespace TimberWinR.Parser
|
|||||||
{
|
{
|
||||||
public partial class Json : LogstashFilter
|
public partial class Json : LogstashFilter
|
||||||
{
|
{
|
||||||
|
private long _errorCount;
|
||||||
|
|
||||||
public Json()
|
public Json()
|
||||||
{
|
{
|
||||||
RemoveSource = true;
|
RemoveSource = true;
|
||||||
@@ -22,6 +25,7 @@ namespace TimberWinR.Parser
|
|||||||
new JProperty("json",
|
new JProperty("json",
|
||||||
new JObject(
|
new JObject(
|
||||||
new JProperty("condition", Condition),
|
new JProperty("condition", Condition),
|
||||||
|
new JProperty("errors", _errorCount),
|
||||||
new JProperty("source", Source),
|
new JProperty("source", Source),
|
||||||
new JProperty("promote", Source),
|
new JProperty("promote", Source),
|
||||||
new JProperty("target", Target),
|
new JProperty("target", Target),
|
||||||
@@ -88,9 +92,12 @@ namespace TimberWinR.Parser
|
|||||||
|
|
||||||
if (Rename != null && Rename.Length > 0)
|
if (Rename != null && Rename.Length > 0)
|
||||||
{
|
{
|
||||||
string oldName = ExpandField(Rename[0], json);
|
for (int i = 0; i < Rename.Length; i += 2)
|
||||||
string newName = ExpandField(Rename[1], json);
|
{
|
||||||
RenameProperty(json, oldName, newName);
|
string oldName = ExpandField(Rename[i], json);
|
||||||
|
string newName = ExpandField(Rename[i+1], json);
|
||||||
|
RenameProperty(json, oldName, newName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RemoveSource)
|
if (RemoveSource)
|
||||||
@@ -102,6 +109,7 @@ namespace TimberWinR.Parser
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
LogManager.GetCurrentClassLogger().Error(ex);
|
LogManager.GetCurrentClassLogger().Error(ex);
|
||||||
|
Interlocked.Increment(ref _errorCount);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
88
TimberWinR/Inputs/GeneratorInput.cs
Normal file
88
TimberWinR/Inputs/GeneratorInput.cs
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
// Infinite or until done.
|
||||||
|
for (int i = 0; (_params.Count == 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -135,8 +135,6 @@ namespace TimberWinR.Inputs
|
|||||||
rs.close();
|
rs.close();
|
||||||
GC.Collect();
|
GC.Collect();
|
||||||
}
|
}
|
||||||
if (!Stop)
|
|
||||||
syncHandle.Wait(TimeSpan.FromSeconds(_pollingIntervalInSeconds), CancelToken);
|
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
@@ -145,7 +143,18 @@ namespace TimberWinR.Inputs
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
LogManager.GetCurrentClassLogger().Error(ex);
|
LogManager.GetCurrentClassLogger().Error(ex);
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!Stop)
|
||||||
|
syncHandle.Wait(TimeSpan.FromSeconds(_pollingIntervalInSeconds), CancelToken);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,10 +8,11 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using TimberWinR.Diagnostics;
|
||||||
|
|
||||||
namespace TimberWinR.Inputs
|
namespace TimberWinR.Inputs
|
||||||
{
|
{
|
||||||
public abstract class InputListener
|
public abstract class InputListener: IDiagnosable
|
||||||
{
|
{
|
||||||
public CancellationToken CancelToken { get; set; }
|
public CancellationToken CancelToken { get; set; }
|
||||||
public event Action<JObject> OnMessageRecieved;
|
public event Action<JObject> OnMessageRecieved;
|
||||||
@@ -44,6 +45,11 @@ namespace TimberWinR.Inputs
|
|||||||
.ToString();
|
.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetTypeName(string newType)
|
||||||
|
{
|
||||||
|
_typeName = newType;
|
||||||
|
}
|
||||||
|
|
||||||
public bool HaveSeenFile(string fileName)
|
public bool HaveSeenFile(string fileName)
|
||||||
{
|
{
|
||||||
return Files.Contains(fileName);
|
return Files.Contains(fileName);
|
||||||
@@ -96,6 +102,34 @@ namespace TimberWinR.Inputs
|
|||||||
LogManager.GetCurrentClassLogger().Error(ex);
|
LogManager.GetCurrentClassLogger().Error(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void AddOrModify(JObject json, string fieldName, string fieldValue)
|
||||||
|
{
|
||||||
|
if (json[fieldName] == null)
|
||||||
|
json.Add(fieldName, fieldValue);
|
||||||
|
else
|
||||||
|
json[fieldName] = fieldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void RenameProperty(JObject json, string oldName, string newName)
|
||||||
|
{
|
||||||
|
JToken token = json[oldName];
|
||||||
|
if (token != null)
|
||||||
|
{
|
||||||
|
json.Add(newName, token.DeepClone());
|
||||||
|
json.Remove(oldName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected string ExpandField(string fieldName, JObject json)
|
||||||
|
{
|
||||||
|
foreach (var token in json.Children().ToList())
|
||||||
|
{
|
||||||
|
string replaceString = "%{" + token.Path + "}";
|
||||||
|
fieldName = fieldName.Replace(replaceString, json[token.Path].ToString());
|
||||||
|
}
|
||||||
|
return fieldName;
|
||||||
|
}
|
||||||
|
|
||||||
protected void EnsureRollingCaught()
|
protected void EnsureRollingCaught()
|
||||||
{
|
{
|
||||||
@@ -123,6 +157,7 @@ namespace TimberWinR.Inputs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public virtual void AddDefaultFields(JObject json)
|
public virtual void AddDefaultFields(JObject json)
|
||||||
{
|
{
|
||||||
if (json["type"] == null)
|
if (json["type"] == null)
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ namespace TimberWinR.Inputs
|
|||||||
var fi = new FileInfo(logName);
|
var fi = new FileInfo(logName);
|
||||||
de.FileName = logName;
|
de.FileName = logName;
|
||||||
de.LogFileExists = fi.Exists;
|
de.LogFileExists = fi.Exists;
|
||||||
|
de.Previous = "";
|
||||||
de.NewFile = true;
|
de.NewFile = true;
|
||||||
de.ProcessedFile = false;
|
de.ProcessedFile = false;
|
||||||
de.LastPosition = fi.Length;
|
de.LastPosition = fi.Length;
|
||||||
@@ -101,8 +102,10 @@ namespace TimberWinR.Inputs
|
|||||||
var creationTime = fi.CreationTimeUtc;
|
var creationTime = fi.CreationTimeUtc;
|
||||||
|
|
||||||
if (dbe.LogFileExists && creationTime != dbe.CreationTimeUtc)
|
if (dbe.LogFileExists && creationTime != dbe.CreationTimeUtc)
|
||||||
dbe.NewFile = true;
|
{
|
||||||
|
dbe.NewFile = true;
|
||||||
|
dbe.Previous = "";
|
||||||
|
}
|
||||||
dbe.CreationTimeUtc = creationTime;
|
dbe.CreationTimeUtc = creationTime;
|
||||||
|
|
||||||
return dbe;
|
return dbe;
|
||||||
@@ -133,7 +136,8 @@ namespace TimberWinR.Inputs
|
|||||||
public static void Roll(LogsFileDatabaseEntry dbe)
|
public static void Roll(LogsFileDatabaseEntry dbe)
|
||||||
{
|
{
|
||||||
dbe.ProcessedFile = false;
|
dbe.ProcessedFile = false;
|
||||||
dbe.LastPosition = 0;
|
dbe.LastPosition = 0;
|
||||||
|
dbe.Previous = "";
|
||||||
Instance.UpdateEntry(dbe, 0);
|
Instance.UpdateEntry(dbe, 0);
|
||||||
dbe.NewFile = true;
|
dbe.NewFile = true;
|
||||||
}
|
}
|
||||||
@@ -268,6 +272,7 @@ namespace TimberWinR.Inputs
|
|||||||
{
|
{
|
||||||
Interlocked.Increment(ref _linesProcessed);
|
Interlocked.Increment(ref _linesProcessed);
|
||||||
}
|
}
|
||||||
|
public string Previous { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ namespace TimberWinR.Inputs
|
|||||||
if (_codecArguments != null && _codecArguments.Type == CodecArguments.CodecType.multiline)
|
if (_codecArguments != null && _codecArguments.Type == CodecArguments.CodecType.multiline)
|
||||||
_codec = new Multiline(_codecArguments);
|
_codec = new Multiline(_codecArguments);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(arguments.Type))
|
||||||
|
SetTypeName(arguments.Type);
|
||||||
|
|
||||||
_receivedMessages = 0;
|
_receivedMessages = 0;
|
||||||
_arguments = arguments;
|
_arguments = arguments;
|
||||||
_pollingIntervalInSeconds = arguments.Interval;
|
_pollingIntervalInSeconds = arguments.Interval;
|
||||||
|
|||||||
@@ -30,23 +30,27 @@ namespace TimberWinR.Inputs
|
|||||||
private int _pollingIntervalInSeconds;
|
private int _pollingIntervalInSeconds;
|
||||||
private TimberWinR.Parser.TailFileArguments _arguments;
|
private TimberWinR.Parser.TailFileArguments _arguments;
|
||||||
private long _receivedMessages;
|
private long _receivedMessages;
|
||||||
|
private long _errorCount;
|
||||||
private CodecArguments _codecArguments;
|
private CodecArguments _codecArguments;
|
||||||
private ICodec _codec;
|
private ICodec _codec;
|
||||||
|
|
||||||
public bool Stop { get; set; }
|
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")
|
: base(cancelToken, "Win32-TailLog")
|
||||||
{
|
{
|
||||||
Stop = false;
|
Stop = false;
|
||||||
|
|
||||||
EnsureRollingCaught();
|
EnsureRollingCaught();
|
||||||
|
|
||||||
_codecArguments = arguments.CodecArguments;
|
_codecArguments = arguments.CodecArguments;
|
||||||
if (_codecArguments != null && _codecArguments.Type == CodecArguments.CodecType.multiline)
|
if (_codecArguments != null && _codecArguments.Type == CodecArguments.CodecType.multiline)
|
||||||
_codec = new Multiline(_codecArguments);
|
_codec = new Multiline(_codecArguments);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(arguments.Type))
|
||||||
|
SetTypeName(arguments.Type);
|
||||||
|
|
||||||
_receivedMessages = 0;
|
_receivedMessages = 0;
|
||||||
_arguments = arguments;
|
_arguments = arguments;
|
||||||
_pollingIntervalInSeconds = arguments.Interval;
|
_pollingIntervalInSeconds = arguments.Interval;
|
||||||
@@ -60,7 +64,9 @@ namespace TimberWinR.Inputs
|
|||||||
|
|
||||||
public override void Shutdown()
|
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;
|
Stop = true;
|
||||||
base.Shutdown();
|
base.Shutdown();
|
||||||
}
|
}
|
||||||
@@ -71,6 +77,7 @@ namespace TimberWinR.Inputs
|
|||||||
new JProperty("taillog",
|
new JProperty("taillog",
|
||||||
new JObject(
|
new JObject(
|
||||||
new JProperty("messages", _receivedMessages),
|
new JProperty("messages", _receivedMessages),
|
||||||
|
new JProperty("errors", _errorCount),
|
||||||
new JProperty("type", InputType),
|
new JProperty("type", InputType),
|
||||||
new JProperty("location", _arguments.Location),
|
new JProperty("location", _arguments.Location),
|
||||||
new JProperty("logSource", _arguments.LogSource),
|
new JProperty("logSource", _arguments.LogSource),
|
||||||
@@ -103,66 +110,100 @@ namespace TimberWinR.Inputs
|
|||||||
|
|
||||||
private void TailFileContents(string fileName, long offset, LogsFileDatabaseEntry dbe)
|
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
|
stream.Seek(prevLen, SeekOrigin.Begin);
|
||||||
long lastMaxOffset = offset;
|
|
||||||
|
|
||||||
//if the file size has not changed, idle
|
char[] buffer = new char[bufSize];
|
||||||
if (reader.BaseStream.Length == lastMaxOffset)
|
StringBuilder current = new StringBuilder();
|
||||||
return;
|
using (StreamReader sr = new StreamReader(stream))
|
||||||
|
|
||||||
//seek to the last max offset
|
|
||||||
LogManager.GetCurrentClassLogger().Trace("{0}: File: {1} Seek to: {2}", Thread.CurrentThread.ManagedThreadId, fileName, lastMaxOffset);
|
|
||||||
|
|
||||||
reader.BaseStream.Seek(lastMaxOffset, SeekOrigin.Begin);
|
|
||||||
|
|
||||||
//read out of the file until the EOF
|
|
||||||
string line = "";
|
|
||||||
long lineOffset = 0;
|
|
||||||
while ((line = reader.ReadLine()) != null)
|
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(line))
|
int nRead;
|
||||||
continue;
|
do
|
||||||
|
|
||||||
long index = lastMaxOffset + lineOffset;
|
|
||||||
string text = line;
|
|
||||||
string logFileName = fileName;
|
|
||||||
var json = new JObject();
|
|
||||||
|
|
||||||
if (json["logSource"] == null)
|
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(_arguments.LogSource))
|
// Read a buffered amount
|
||||||
json.Add(new JProperty("logSource", fileName));
|
nRead = sr.ReadBlock(buffer, 0, bufSize);
|
||||||
else
|
for (int i = 0; i < nRead; ++i)
|
||||||
json.Add(new JProperty("logSource", _arguments.LogSource));
|
{
|
||||||
|
// 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
|
// One thread for each kind of file to watch, i.e. "*.log,*.txt" would be two separate
|
||||||
// threads.
|
// threads.
|
||||||
@@ -202,12 +243,13 @@ namespace TimberWinR.Inputs
|
|||||||
{
|
{
|
||||||
LogManager.GetCurrentClassLogger().Debug(":{0} Starting Thread Tailing File: {1}", Thread.CurrentThread.ManagedThreadId, dbe.FileName);
|
LogManager.GetCurrentClassLogger().Debug(":{0} Starting Thread Tailing File: {1}", Thread.CurrentThread.ManagedThreadId, dbe.FileName);
|
||||||
LogsFileDatabase.Update(dbe, false, dbe.LastPosition);
|
LogsFileDatabase.Update(dbe, false, dbe.LastPosition);
|
||||||
SaveVisitedFileName(fileName);
|
|
||||||
Task.Factory.StartNew(() => TailFileWatcher(fileName));
|
Task.Factory.StartNew(() => TailFileWatcher(fileName));
|
||||||
}
|
}
|
||||||
else if (!isWildcardPattern)
|
else if (!isWildcardPattern)
|
||||||
{
|
{
|
||||||
FileInfo fi = new FileInfo(dbe.FileName);
|
FileInfo fi = new FileInfo(dbe.FileName);
|
||||||
|
SaveVisitedFileName(fileName);
|
||||||
|
|
||||||
//LogManager.GetCurrentClassLogger().Info("Located File: {0}, New: {1}", dbe.FileName, dbe.NewFile);
|
//LogManager.GetCurrentClassLogger().Info("Located File: {0}, New: {1}", dbe.FileName, dbe.NewFile);
|
||||||
long length = fi.Length;
|
long length = fi.Length;
|
||||||
@@ -219,7 +261,7 @@ namespace TimberWinR.Inputs
|
|||||||
LogsFileDatabase.Roll(dbe);
|
LogsFileDatabase.Roll(dbe);
|
||||||
}
|
}
|
||||||
// Log has rolled or this is a file we are seeing for the first time.
|
// Log has rolled or this is a file we are seeing for the first time.
|
||||||
bool processWholeFile = logHasRolled || !dbe.ProcessedFile;
|
bool processWholeFile = logHasRolled || !dbe.ProcessedFile || dbe.NewFile;
|
||||||
if (processWholeFile)
|
if (processWholeFile)
|
||||||
{
|
{
|
||||||
LogsFileDatabase.Update(dbe, true, 0);
|
LogsFileDatabase.Update(dbe, true, 0);
|
||||||
@@ -229,7 +271,7 @@ namespace TimberWinR.Inputs
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
TailFileContents(dbe.FileName, dbe.LastPosition, dbe);
|
TailFileContents(dbe.FileName, dbe.LastPosition, dbe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -273,7 +315,7 @@ namespace TimberWinR.Inputs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Finished();
|
Finished();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ namespace TimberWinR.Inputs
|
|||||||
private Thread _listenThreadV4;
|
private Thread _listenThreadV4;
|
||||||
private Thread _listenThreadV6;
|
private Thread _listenThreadV6;
|
||||||
private readonly int _port;
|
private readonly int _port;
|
||||||
|
private TimberWinR.Parser.TcpParameters _arguments;
|
||||||
private long _receivedMessages;
|
private long _receivedMessages;
|
||||||
|
private long _errorCount;
|
||||||
|
|
||||||
public override JObject ToJson()
|
public override JObject ToJson()
|
||||||
{
|
{
|
||||||
@@ -24,21 +26,25 @@ namespace TimberWinR.Inputs
|
|||||||
new JProperty("tcp",
|
new JProperty("tcp",
|
||||||
new JObject(
|
new JObject(
|
||||||
new JProperty("port", _port),
|
new JProperty("port", _port),
|
||||||
|
new JProperty("errors", _errorCount),
|
||||||
new JProperty("messages", _receivedMessages)
|
new JProperty("messages", _receivedMessages)
|
||||||
)));
|
)));
|
||||||
|
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TcpInputListener(CancellationToken cancelToken, int port = 5140)
|
public TcpInputListener(TimberWinR.Parser.TcpParameters arguments, CancellationToken cancelToken, int port = 5140)
|
||||||
: base(cancelToken, "Win32-Tcp")
|
: base(cancelToken, "Win32-Tcp")
|
||||||
{
|
{
|
||||||
_port = port;
|
_port = port;
|
||||||
|
_arguments = arguments;
|
||||||
|
|
||||||
LogManager.GetCurrentClassLogger().Info("Tcp Input(v4/v6) on Port {0} Ready", _port);
|
LogManager.GetCurrentClassLogger().Info("Tcp Input(v4/v6) on Port {0} Ready", _port);
|
||||||
|
|
||||||
_receivedMessages = 0;
|
if (!string.IsNullOrEmpty(arguments.Type))
|
||||||
|
SetTypeName(arguments.Type);
|
||||||
|
|
||||||
|
_receivedMessages = 0;
|
||||||
|
|
||||||
_tcpListenerV6 = new System.Net.Sockets.TcpListener(IPAddress.IPv6Any, port);
|
_tcpListenerV6 = new System.Net.Sockets.TcpListener(IPAddress.IPv6Any, port);
|
||||||
_tcpListenerV4 = new System.Net.Sockets.TcpListener(IPAddress.Any, port);
|
_tcpListenerV4 = new System.Net.Sockets.TcpListener(IPAddress.Any, port);
|
||||||
|
|
||||||
@@ -68,7 +74,6 @@ namespace TimberWinR.Inputs
|
|||||||
|
|
||||||
listener.Start();
|
listener.Start();
|
||||||
|
|
||||||
|
|
||||||
while (!CancelToken.IsCancellationRequested)
|
while (!CancelToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -79,7 +84,7 @@ namespace TimberWinR.Inputs
|
|||||||
// Wait for a client, spin up a thread.
|
// Wait for a client, spin up a thread.
|
||||||
var clientThread = new Thread(new ParameterizedThreadStart(HandleNewClient));
|
var clientThread = new Thread(new ParameterizedThreadStart(HandleNewClient));
|
||||||
clientThread.Start(client);
|
clientThread.Start(client);
|
||||||
}
|
}
|
||||||
catch (SocketException ex)
|
catch (SocketException ex)
|
||||||
{
|
{
|
||||||
if (ex.SocketErrorCode == SocketError.Interrupted)
|
if (ex.SocketErrorCode == SocketError.Interrupted)
|
||||||
@@ -90,6 +95,33 @@ namespace TimberWinR.Inputs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Renames, and AddFields
|
||||||
|
//
|
||||||
|
private void ApplyFilters(JObject json)
|
||||||
|
{
|
||||||
|
if (_arguments.Renames != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _arguments.Renames.Length; i += 2)
|
||||||
|
{
|
||||||
|
var oldName = ExpandField(_arguments.Renames[i], json);
|
||||||
|
var newName = ExpandField(_arguments.Renames[i + 1], json);
|
||||||
|
RenameProperty(json, oldName, newName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_arguments.AddFields != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _arguments.AddFields.Length; i += 2)
|
||||||
|
{
|
||||||
|
var fieldName = ExpandField(_arguments.AddFields[i], json);
|
||||||
|
var fieldValue = ExpandField(_arguments.AddFields[i + 1], json);
|
||||||
|
AddOrModify(json, fieldName, fieldValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void HandleNewClient(object client)
|
private void HandleNewClient(object client)
|
||||||
{
|
{
|
||||||
var tcpClient = (TcpClient)client;
|
var tcpClient = (TcpClient)client;
|
||||||
@@ -108,8 +140,9 @@ namespace TimberWinR.Inputs
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
JObject json = JObject.Load(reader);
|
JObject json = JObject.Load(reader);
|
||||||
|
ApplyFilters(json);
|
||||||
ProcessJson(json);
|
ProcessJson(json);
|
||||||
_receivedMessages++;
|
Interlocked.Increment(ref _receivedMessages);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -118,12 +151,16 @@ namespace TimberWinR.Inputs
|
|||||||
ProcessJson(jex1);
|
ProcessJson(jex1);
|
||||||
|
|
||||||
LogManager.GetCurrentClassLogger().Warn(ex);
|
LogManager.GetCurrentClassLogger().Warn(ex);
|
||||||
|
Interlocked.Increment(ref _errorCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch(OperationCanceledException)
|
||||||
|
{
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
LogManager.GetCurrentClassLogger().Error(ex);
|
LogManager.GetCurrentClassLogger().Error(ex);
|
||||||
|
|||||||
@@ -1,121 +1,201 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.Collections.Concurrent;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
|
||||||
namespace TimberWinR.Inputs
|
namespace TimberWinR.Inputs
|
||||||
{
|
{
|
||||||
public class UdpInputListener : InputListener
|
public class UdpInputListener : InputListener
|
||||||
{
|
{
|
||||||
private UdpClient _udpListenerV6;
|
private UdpClient _udpListenerV4;
|
||||||
private readonly Thread _listenThreadV6;
|
private IPEndPoint _udpEndpointV4;
|
||||||
|
private readonly BlockingCollection<byte[]> _unprocessedRawData;
|
||||||
|
private readonly Thread _rawDataProcessingThread;
|
||||||
private readonly int _port;
|
private readonly int _port;
|
||||||
private long _receivedMessages;
|
private long _receivedMessages;
|
||||||
private long _parsedErrors;
|
private long _parseErrors;
|
||||||
|
private long _receiveErrors;
|
||||||
|
private long _parsedMessages;
|
||||||
|
private TimberWinR.Parser.UdpParameters _arguments;
|
||||||
|
|
||||||
public override JObject ToJson()
|
public override JObject ToJson()
|
||||||
{
|
{
|
||||||
JObject json = new JObject(
|
var json =
|
||||||
new JProperty("udp",
|
new JObject(new JProperty("udp",
|
||||||
new JObject(
|
new JObject(new JProperty("port", _port),
|
||||||
new JProperty("port", _port),
|
new JProperty("receive_errors", _receiveErrors),
|
||||||
new JProperty("errors", _parsedErrors),
|
new JProperty("parse_errors", _parseErrors),
|
||||||
new JProperty("messages", _receivedMessages)
|
new JProperty("messages", _receivedMessages),
|
||||||
)));
|
new JProperty("parsed_messages", _parsedMessages),
|
||||||
|
new JProperty("unprocessed_messages", _unprocessedRawData.Count))));
|
||||||
|
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UdpInputListener(CancellationToken cancelToken, int port = 5140)
|
public UdpInputListener(TimberWinR.Parser.UdpParameters arguments, CancellationToken cancelToken, int port = 5140) : base(cancelToken, "Win32-Udp")
|
||||||
: base(cancelToken, "Win32-Udp")
|
|
||||||
{
|
{
|
||||||
_port = port;
|
_port = port;
|
||||||
|
|
||||||
|
|
||||||
_receivedMessages = 0;
|
_receivedMessages = 0;
|
||||||
|
_arguments = arguments;
|
||||||
|
|
||||||
_listenThreadV6 = new Thread(StartListener);
|
if (!string.IsNullOrEmpty(arguments.Type))
|
||||||
_listenThreadV6.Start();
|
SetTypeName(arguments.Type);
|
||||||
|
|
||||||
|
// setup raw data processor
|
||||||
|
_unprocessedRawData = new BlockingCollection<byte[]>();
|
||||||
|
_rawDataProcessingThread = new Thread(ProcessDataLoop) { Name = "Win32-Udp-DataProcessor"};
|
||||||
|
_rawDataProcessingThread.Start();
|
||||||
|
|
||||||
|
// start listing to udp port
|
||||||
|
StartListener();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override void Shutdown()
|
public override void Shutdown()
|
||||||
{
|
{
|
||||||
LogManager.GetCurrentClassLogger().Info("Shutting Down {0}", InputType);
|
LogManager.GetCurrentClassLogger().Info("Shutting Down {0}", InputType);
|
||||||
|
|
||||||
// close UDP listeners, which will end the listener threads
|
// close UDP listeners, which will end the listener threads
|
||||||
_udpListenerV6.Close();
|
_udpListenerV4.Close();
|
||||||
|
|
||||||
// wait for completion of the threads
|
|
||||||
_listenThreadV6.Join();
|
|
||||||
|
|
||||||
base.Shutdown();
|
base.Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartListener()
|
private void StartListener()
|
||||||
{
|
{
|
||||||
var groupV6 = new IPEndPoint(IPAddress.IPv6Any, _port);
|
_udpEndpointV4 = new IPEndPoint(IPAddress.Any, _port);
|
||||||
// Create the socket as IPv6
|
|
||||||
var dualModeSocket = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);
|
|
||||||
|
|
||||||
//
|
|
||||||
// Now, disable the IPV6only flag to make it compatable with both ipv4 and ipv6
|
|
||||||
// See: http://blogs.msdn.com/b/malarch/archive/2005/11/18/494769.aspx
|
|
||||||
//
|
|
||||||
dualModeSocket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, 0);
|
|
||||||
dualModeSocket.Bind(groupV6);
|
|
||||||
|
|
||||||
_udpListenerV6 = new UdpClient();
|
// setup listener
|
||||||
_udpListenerV6.Client = dualModeSocket;
|
_udpListenerV4 = new UdpClient(_port);
|
||||||
|
|
||||||
LogManager.GetCurrentClassLogger().Info("Udp Input on Port {0} Ready", groupV6);
|
// start listening on UDP port
|
||||||
|
StartReceiving();
|
||||||
|
|
||||||
|
// all started; log details
|
||||||
|
LogManager.GetCurrentClassLogger().Info("Udp Input on Port {0} Ready", _udpEndpointV4);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartReceiving()
|
||||||
|
{
|
||||||
|
if (!CancelToken.IsCancellationRequested)
|
||||||
|
_udpListenerV4.BeginReceive(DataReceived, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DataReceived(IAsyncResult result)
|
||||||
|
{
|
||||||
|
if (CancelToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
_unprocessedRawData.CompleteAdding();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
string lastMessage = "";
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
while (!CancelToken.IsCancellationRequested)
|
byte[] bytes = _udpListenerV4.EndReceive(result, ref _udpEndpointV4);
|
||||||
{
|
Interlocked.Increment(ref _receivedMessages);
|
||||||
try
|
StartReceiving();
|
||||||
{
|
_unprocessedRawData.Add(bytes);
|
||||||
byte[] bytes = _udpListenerV6.Receive(ref groupV6);
|
}
|
||||||
var data = Encoding.UTF8.GetString(bytes, 0, bytes.Length);
|
catch (SocketException)
|
||||||
lastMessage = data;
|
{
|
||||||
var json = JObject.Parse(data);
|
LogManager.GetCurrentClassLogger().Info("Socked exception. Ending UDP Listener.");
|
||||||
ProcessJson(json);
|
_unprocessedRawData.CompleteAdding();
|
||||||
Interlocked.Increment(ref _receivedMessages);
|
}
|
||||||
}
|
catch (ObjectDisposedException)
|
||||||
catch(SocketException)
|
{
|
||||||
{
|
LogManager.GetCurrentClassLogger().Info("Object disposed. Ending UDP Listener");
|
||||||
break;
|
_unprocessedRawData.CompleteAdding();
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var jex1 = LogErrors.LogException(string.Format("Invalid JSON: {0}", lastMessage), ex);
|
|
||||||
if (jex1 != null)
|
|
||||||
ProcessJson(jex1);
|
|
||||||
|
|
||||||
LogManager.GetCurrentClassLogger().Warn("Bad JSON: {0}", lastMessage);
|
|
||||||
LogManager.GetCurrentClassLogger().Warn(ex);
|
|
||||||
|
|
||||||
Interlocked.Increment(ref _parsedErrors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_udpListenerV6.Close();
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
if (!CancelToken.IsCancellationRequested)
|
LogManager.GetCurrentClassLogger().Warn("Error while receiving data.", ex);
|
||||||
LogManager.GetCurrentClassLogger().Error(ex);
|
|
||||||
|
Interlocked.Increment(ref _receiveErrors);
|
||||||
|
StartReceiving();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessDataLoop()
|
||||||
|
{
|
||||||
|
while (!_unprocessedRawData.IsCompleted)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ProcessData(_unprocessedRawData.Take());
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
// we are shutting down.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException)
|
||||||
|
{
|
||||||
|
// when the collection is marked as completed
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.GetCurrentClassLogger().ErrorException("Error while processing data", ex);
|
||||||
|
Thread.Sleep(100);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Finished();
|
Finished();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Renames, and AddFields
|
||||||
|
//
|
||||||
|
private void ApplyFilters(JObject json)
|
||||||
|
{
|
||||||
|
if (_arguments.Renames != null)
|
||||||
|
{
|
||||||
|
for (int i=0; i<_arguments.Renames.Length; i += 2)
|
||||||
|
{
|
||||||
|
var oldName = ExpandField(_arguments.Renames[i], json);
|
||||||
|
var newName = ExpandField(_arguments.Renames[i + 1], json);
|
||||||
|
RenameProperty(json, oldName, newName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_arguments.AddFields != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _arguments.AddFields.Length; i += 2)
|
||||||
|
{
|
||||||
|
var fieldName = ExpandField(_arguments.AddFields[i], json);
|
||||||
|
var fieldValue = ExpandField(_arguments.AddFields[i + 1], json);
|
||||||
|
AddOrModify(json, fieldName, fieldValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessData(byte[] bytes)
|
||||||
|
{
|
||||||
|
var data = Encoding.UTF8.GetString(bytes, 0, bytes.Length);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var json = JObject.Parse(data);
|
||||||
|
ApplyFilters(json);
|
||||||
|
ProcessJson(json);
|
||||||
|
_parsedMessages++;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var jex1 = LogErrors.LogException(string.Format("Invalid JSON: {0}", data), ex);
|
||||||
|
if (jex1 != null)
|
||||||
|
{
|
||||||
|
ProcessJson(jex1);
|
||||||
|
}
|
||||||
|
|
||||||
|
var msg = string.Format("Bad JSON: {0}", data);
|
||||||
|
LogManager.GetCurrentClassLogger().Warn(msg, ex);
|
||||||
|
|
||||||
|
_parseErrors++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,14 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Security.AccessControl;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.IO;
|
|
||||||
using Interop.MSUtil;
|
|
||||||
|
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using Newtonsoft.Json.Serialization;
|
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using TimberWinR.Parser;
|
||||||
using LogQuery = Interop.MSUtil.LogQueryClassClass;
|
using LogQuery = Interop.MSUtil.LogQueryClassClass;
|
||||||
using EventLogInputFormat = Interop.MSUtil.COMEventLogInputContextClassClass;
|
using EventLogInputFormat = Interop.MSUtil.COMEventLogInputContextClassClass;
|
||||||
using LogRecordSet = Interop.MSUtil.ILogRecordset;
|
using LogRecordSet = Interop.MSUtil.ILogRecordset;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace TimberWinR.Inputs
|
namespace TimberWinR.Inputs
|
||||||
{
|
{
|
||||||
@@ -23,13 +17,13 @@ namespace TimberWinR.Inputs
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class WindowsEvtInputListener : InputListener
|
public class WindowsEvtInputListener : InputListener
|
||||||
{
|
{
|
||||||
private int _pollingIntervalInSeconds = 1;
|
private readonly int _pollingIntervalInSeconds = 1;
|
||||||
private TimberWinR.Parser.WindowsEvent _arguments;
|
private readonly WindowsEvent _arguments;
|
||||||
private long _receivedMessages;
|
private long _receivedMessages;
|
||||||
private List<Thread> _tasks { get; set; }
|
private readonly List<Thread> _tasks;
|
||||||
public bool Stop { get; set; }
|
public bool Stop { get; set; }
|
||||||
|
|
||||||
public WindowsEvtInputListener(TimberWinR.Parser.WindowsEvent arguments, CancellationToken cancelToken)
|
public WindowsEvtInputListener(WindowsEvent arguments, CancellationToken cancelToken)
|
||||||
: base(cancelToken, "Win32-Eventlog")
|
: base(cancelToken, "Win32-Eventlog")
|
||||||
{
|
{
|
||||||
_arguments = arguments;
|
_arguments = arguments;
|
||||||
@@ -38,8 +32,7 @@ namespace TimberWinR.Inputs
|
|||||||
|
|
||||||
foreach (string eventHive in _arguments.Source.Split(','))
|
foreach (string eventHive in _arguments.Source.Split(','))
|
||||||
{
|
{
|
||||||
string hive = eventHive.Trim();
|
var thread = new Thread(EventWatcher) {Name = "Win32-Eventlog-" + eventHive};
|
||||||
var thread = new Thread(new ParameterizedThreadStart(EventWatcher));
|
|
||||||
_tasks.Add(thread);
|
_tasks.Add(thread);
|
||||||
thread.Start(eventHive);
|
thread.Start(eventHive);
|
||||||
}
|
}
|
||||||
@@ -48,7 +41,11 @@ namespace TimberWinR.Inputs
|
|||||||
public override void Shutdown()
|
public override void Shutdown()
|
||||||
{
|
{
|
||||||
Stop = true;
|
Stop = true;
|
||||||
LogManager.GetCurrentClassLogger().Info("Shutting Down {0}", InputType);
|
LogManager.GetCurrentClassLogger().Info("Shutting Down {0}", InputType);
|
||||||
|
foreach (var thread in _tasks)
|
||||||
|
{
|
||||||
|
thread.Join();
|
||||||
|
}
|
||||||
base.Shutdown();
|
base.Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,8 +73,6 @@ namespace TimberWinR.Inputs
|
|||||||
{
|
{
|
||||||
string location = ploc.ToString();
|
string location = ploc.ToString();
|
||||||
|
|
||||||
LogQuery oLogQuery = new LogQuery();
|
|
||||||
|
|
||||||
LogManager.GetCurrentClassLogger().Info("WindowsEvent Input Listener Ready");
|
LogManager.GetCurrentClassLogger().Info("WindowsEvent Input Listener Ready");
|
||||||
|
|
||||||
// Instantiate the Event Log Input Format object
|
// Instantiate the Event Log Input Format object
|
||||||
@@ -93,9 +88,7 @@ namespace TimberWinR.Inputs
|
|||||||
resolveSIDs = _arguments.ResolveSIDS
|
resolveSIDs = _arguments.ResolveSIDS
|
||||||
};
|
};
|
||||||
|
|
||||||
oLogQuery = null;
|
var logFileMaxRecords = new Dictionary<string, Int64>();
|
||||||
|
|
||||||
Dictionary<string, Int64> logFileMaxRecords = new Dictionary<string, Int64>();
|
|
||||||
|
|
||||||
using (var syncHandle = new ManualResetEventSlim())
|
using (var syncHandle = new ManualResetEventSlim())
|
||||||
{
|
{
|
||||||
@@ -105,12 +98,13 @@ namespace TimberWinR.Inputs
|
|||||||
// Execute the query
|
// Execute the query
|
||||||
if (!CancelToken.IsCancellationRequested)
|
if (!CancelToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
|
var oLogQuery = new LogQuery();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
oLogQuery = new LogQuery();
|
|
||||||
|
|
||||||
var qfiles = string.Format("SELECT Distinct [EventLog] FROM {0}", location);
|
var qfiles = string.Format("SELECT Distinct [EventLog] FROM {0}", location);
|
||||||
var rsfiles = oLogQuery.Execute(qfiles, iFmt);
|
var rsfiles = oLogQuery.Execute(qfiles, iFmt);
|
||||||
|
|
||||||
for (; !rsfiles.atEnd(); rsfiles.moveNext())
|
for (; !rsfiles.atEnd(); rsfiles.moveNext())
|
||||||
{
|
{
|
||||||
var record = rsfiles.getRecord();
|
var record = rsfiles.getRecord();
|
||||||
@@ -121,7 +115,7 @@ namespace TimberWinR.Inputs
|
|||||||
logName);
|
logName);
|
||||||
var rcount = oLogQuery.Execute(qcount, iFmt);
|
var rcount = oLogQuery.Execute(qcount, iFmt);
|
||||||
var qr = rcount.getRecord();
|
var qr = rcount.getRecord();
|
||||||
var lrn = (Int64)qr.getValueEx("MaxRecordNumber");
|
var lrn = (Int64) qr.getValueEx("MaxRecordNumber");
|
||||||
logFileMaxRecords[logName] = lrn;
|
logFileMaxRecords[logName] = lrn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,21 +139,20 @@ namespace TimberWinR.Inputs
|
|||||||
object v = record.getValue(field.Name);
|
object v = record.getValue(field.Name);
|
||||||
if (field.Name == "Data")
|
if (field.Name == "Data")
|
||||||
v = ToPrintable(v.ToString());
|
v = ToPrintable(v.ToString());
|
||||||
|
if ((field.Name == "TimeGenerated" || field.Name == "TimeWritten") &&
|
||||||
|
field.DataType == typeof (DateTime))
|
||||||
|
v = ((DateTime) v).ToUniversalTime();
|
||||||
json.Add(new JProperty(field.Name, v));
|
json.Add(new JProperty(field.Name, v));
|
||||||
}
|
}
|
||||||
|
|
||||||
var lrn = (Int64)record.getValueEx("RecordNumber");
|
var lrn = (Int64) record.getValueEx("RecordNumber");
|
||||||
logFileMaxRecords[fileName] = lrn;
|
logFileMaxRecords[fileName] = lrn;
|
||||||
|
|
||||||
record = null;
|
|
||||||
ProcessJson(json);
|
ProcessJson(json);
|
||||||
_receivedMessages++;
|
_receivedMessages++;
|
||||||
json = null;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
// Close the recordset
|
// Close the recordset
|
||||||
rs.close();
|
rs.close();
|
||||||
rs = null;
|
|
||||||
GC.Collect();
|
GC.Collect();
|
||||||
}
|
}
|
||||||
if (!Stop)
|
if (!Stop)
|
||||||
@@ -173,6 +166,24 @@ namespace TimberWinR.Inputs
|
|||||||
{
|
{
|
||||||
LogManager.GetCurrentClassLogger().Error(ex);
|
LogManager.GetCurrentClassLogger().Error(ex);
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
oLogQuery = null;
|
||||||
|
// Sleep
|
||||||
|
if (!Stop)
|
||||||
|
syncHandle.Wait(TimeSpan.FromSeconds(_pollingIntervalInSeconds), CancelToken);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
catch (Exception ex1)
|
||||||
|
{
|
||||||
|
LogManager.GetCurrentClassLogger().Warn(ex1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Finished();
|
Finished();
|
||||||
|
|||||||
@@ -22,11 +22,9 @@ namespace TimberWinR
|
|||||||
public class Manager
|
public class Manager
|
||||||
{
|
{
|
||||||
public Configuration Config { get; set; }
|
public Configuration Config { get; set; }
|
||||||
public List<OutputSender> Outputs { get; set; }
|
public List<OutputSender> Outputs { get; set; }
|
||||||
public List<TcpInputListener> Tcps { get; set; }
|
|
||||||
public List<TcpInputListener> Udps { get; set; }
|
|
||||||
public List<InputListener> Listeners { get; set; }
|
public List<InputListener> Listeners { get; set; }
|
||||||
public bool LiveMonitor { get; set; }
|
public bool LiveMonitor { get; set; }
|
||||||
|
|
||||||
public event Action<Configuration> OnConfigurationProcessed;
|
public event Action<Configuration> OnConfigurationProcessed;
|
||||||
|
|
||||||
@@ -49,7 +47,7 @@ namespace TimberWinR
|
|||||||
|
|
||||||
|
|
||||||
public void Shutdown()
|
public void Shutdown()
|
||||||
{
|
{
|
||||||
LogManager.GetCurrentClassLogger().Info("Shutting Down");
|
LogManager.GetCurrentClassLogger().Info("Shutting Down");
|
||||||
|
|
||||||
foreach (InputListener listener in Listeners)
|
foreach (InputListener listener in Listeners)
|
||||||
@@ -66,13 +64,13 @@ namespace TimberWinR
|
|||||||
|
|
||||||
public Manager()
|
public Manager()
|
||||||
{
|
{
|
||||||
LogsFileDatabase.Manager = this;
|
LogsFileDatabase.Manager = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Manager(string jsonConfigFile, string logLevel, string logfileDir, bool liveMonitor, CancellationToken cancelToken, bool processConfiguration = true)
|
public Manager(string jsonConfigFile, string logLevel, string logfileDir, bool liveMonitor, CancellationToken cancelToken, bool processConfiguration = true)
|
||||||
{
|
{
|
||||||
LogsFileDatabase.Manager = this;
|
LogsFileDatabase.Manager = this;
|
||||||
|
|
||||||
StartedOn = DateTime.UtcNow;
|
StartedOn = DateTime.UtcNow;
|
||||||
LiveMonitor = liveMonitor;
|
LiveMonitor = liveMonitor;
|
||||||
|
|
||||||
@@ -119,17 +117,9 @@ namespace TimberWinR
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Is it a directory?
|
var fi = new FileInfo(jsonConfigFile);
|
||||||
if (Directory.Exists(jsonConfigFile))
|
if (fi.Exists)
|
||||||
{
|
{
|
||||||
DirectoryInfo di = new DirectoryInfo(jsonConfigFile);
|
|
||||||
LogManager.GetCurrentClassLogger().Info("Initialized, Reading Configurations From {0}", di.FullName);
|
|
||||||
Config = Configuration.FromDirectory(jsonConfigFile, cancelToken, this);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var fi = new FileInfo(jsonConfigFile);
|
|
||||||
|
|
||||||
LogManager.GetCurrentClassLogger().Info("Initialized, Reading Configurations From File: {0}", fi.FullName);
|
LogManager.GetCurrentClassLogger().Info("Initialized, Reading Configurations From File: {0}", fi.FullName);
|
||||||
|
|
||||||
if (!fi.Exists)
|
if (!fi.Exists)
|
||||||
@@ -138,6 +128,12 @@ namespace TimberWinR
|
|||||||
LogManager.GetCurrentClassLogger().Info("Initialized, Reading Config: {0}", fi.FullName);
|
LogManager.GetCurrentClassLogger().Info("Initialized, Reading Config: {0}", fi.FullName);
|
||||||
Config = Configuration.FromFile(jsonConfigFile);
|
Config = Configuration.FromFile(jsonConfigFile);
|
||||||
}
|
}
|
||||||
|
else if (Directory.Exists(jsonConfigFile))
|
||||||
|
{
|
||||||
|
DirectoryInfo di = new DirectoryInfo(jsonConfigFile);
|
||||||
|
LogManager.GetCurrentClassLogger().Info("Initialized, Reading Configurations From {0}", di.FullName);
|
||||||
|
Config = Configuration.FromDirectory(jsonConfigFile, cancelToken, this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (JsonSerializationException jse)
|
catch (JsonSerializationException jse)
|
||||||
{
|
{
|
||||||
@@ -145,30 +141,39 @@ namespace TimberWinR
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
LogManager.GetCurrentClassLogger().Error(ex);
|
LogManager.GetCurrentClassLogger().Error(ex);
|
||||||
}
|
}
|
||||||
LogManager.GetCurrentClassLogger().Info("Log Directory {0}", logfileDir);
|
LogManager.GetCurrentClassLogger().Info("Log Directory {0}", logfileDir);
|
||||||
LogManager.GetCurrentClassLogger().Info("Logging Level: {0}", LogManager.GlobalThreshold);
|
LogManager.GetCurrentClassLogger().Info("Logging Level: {0}", LogManager.GlobalThreshold);
|
||||||
|
|
||||||
if (processConfiguration)
|
if (processConfiguration)
|
||||||
{
|
{
|
||||||
ProcessConfiguration(cancelToken, Config);
|
ProcessConfiguration(cancelToken, Config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start(CancellationToken cancelToken)
|
public void Start(CancellationToken cancelToken)
|
||||||
{
|
{
|
||||||
ProcessConfiguration(cancelToken, Config);
|
ProcessConfiguration(cancelToken, Config);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ProcessConfiguration(CancellationToken cancelToken, Configuration config)
|
public void ProcessConfiguration(CancellationToken cancelToken, Configuration config)
|
||||||
{
|
{
|
||||||
// Read the Configuration file
|
// Read the Configuration file
|
||||||
if (config != null)
|
if (config != null)
|
||||||
{
|
{
|
||||||
if (OnConfigurationProcessed != null)
|
if (OnConfigurationProcessed != null)
|
||||||
OnConfigurationProcessed(config);
|
OnConfigurationProcessed(config);
|
||||||
|
|
||||||
|
if (config.StatsDOutputs != null)
|
||||||
|
{
|
||||||
|
foreach (var ro in config.StatsDOutputs)
|
||||||
|
{
|
||||||
|
var output = new StatsDOutput(this, ro, cancelToken);
|
||||||
|
Outputs.Add(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (config.RedisOutputs != null)
|
if (config.RedisOutputs != null)
|
||||||
{
|
{
|
||||||
foreach (var ro in config.RedisOutputs)
|
foreach (var ro in config.RedisOutputs)
|
||||||
@@ -194,6 +199,15 @@ namespace TimberWinR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.FileOutputs != null)
|
||||||
|
{
|
||||||
|
foreach (var ro in config.FileOutputs)
|
||||||
|
{
|
||||||
|
var output = new FileOutput(this, ro, cancelToken);
|
||||||
|
Outputs.Add(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach (Parser.IISW3CLogParameters iisw3cConfig in config.IISW3C)
|
foreach (Parser.IISW3CLogParameters iisw3cConfig in config.IISW3C)
|
||||||
{
|
{
|
||||||
var elistner = new IISW3CInputListener(iisw3cConfig, cancelToken);
|
var elistner = new IISW3CInputListener(iisw3cConfig, cancelToken);
|
||||||
@@ -236,7 +250,7 @@ namespace TimberWinR
|
|||||||
|
|
||||||
foreach (var tcp in config.Tcps)
|
foreach (var tcp in config.Tcps)
|
||||||
{
|
{
|
||||||
var elistner = new TcpInputListener(cancelToken, tcp.Port);
|
var elistner = new TcpInputListener(tcp, cancelToken, tcp.Port);
|
||||||
Listeners.Add(elistner);
|
Listeners.Add(elistner);
|
||||||
foreach (var output in Outputs)
|
foreach (var output in Outputs)
|
||||||
output.Connect(elistner);
|
output.Connect(elistner);
|
||||||
@@ -244,7 +258,7 @@ namespace TimberWinR
|
|||||||
|
|
||||||
foreach (var udp in config.Udps)
|
foreach (var udp in config.Udps)
|
||||||
{
|
{
|
||||||
var elistner = new UdpInputListener(cancelToken, udp.Port);
|
var elistner = new UdpInputListener(udp, cancelToken, udp.Port);
|
||||||
Listeners.Add(elistner);
|
Listeners.Add(elistner);
|
||||||
foreach (var output in Outputs)
|
foreach (var output in Outputs)
|
||||||
output.Connect(elistner);
|
output.Connect(elistner);
|
||||||
@@ -258,6 +272,15 @@ namespace TimberWinR
|
|||||||
output.Connect(elistner);
|
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 + "." +
|
var computerName = System.Environment.MachineName + "." +
|
||||||
Microsoft.Win32.Registry.LocalMachine.OpenSubKey(
|
Microsoft.Win32.Registry.LocalMachine.OpenSubKey(
|
||||||
@"SYSTEM\CurrentControlSet\services\Tcpip\Parameters")
|
@"SYSTEM\CurrentControlSet\services\Tcpip\Parameters")
|
||||||
@@ -272,7 +295,7 @@ namespace TimberWinR
|
|||||||
new JObject(
|
new JObject(
|
||||||
new JProperty("version",
|
new JProperty("version",
|
||||||
Assembly.GetEntryAssembly().GetName().Version.ToString()),
|
Assembly.GetEntryAssembly().GetName().Version.ToString()),
|
||||||
//GetAssemblyByName("TimberWinR.ServiceHost").GetName().Version.ToString()),
|
//GetAssemblyByName("TimberWinR.ServiceHost").GetName().Version.ToString()),
|
||||||
new JProperty("host", computerName),
|
new JProperty("host", computerName),
|
||||||
new JProperty("output", output.Name),
|
new JProperty("output", output.Name),
|
||||||
new JProperty("initialized", DateTime.UtcNow)
|
new JProperty("initialized", DateTime.UtcNow)
|
||||||
@@ -280,7 +303,7 @@ namespace TimberWinR
|
|||||||
json.Add(new JProperty("type", "Win32-TimberWinR"));
|
json.Add(new JProperty("type", "Win32-TimberWinR"));
|
||||||
json.Add(new JProperty("host", computerName));
|
json.Add(new JProperty("host", computerName));
|
||||||
output.Startup(json);
|
output.Startup(json);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,10 @@ namespace TimberWinR.Outputs
|
|||||||
private long _sentMessages;
|
private long _sentMessages;
|
||||||
private long _errorCount;
|
private long _errorCount;
|
||||||
private readonly int _maxQueueSize;
|
private readonly int _maxQueueSize;
|
||||||
private readonly bool _queueOverflowDiscardOldest;
|
private readonly bool _queueOverflowDiscardOldest;
|
||||||
|
private readonly bool _disablePing;
|
||||||
|
private readonly int _pingTimeout;
|
||||||
|
|
||||||
private Parser.ElasticsearchOutputParameters _parameters;
|
private Parser.ElasticsearchOutputParameters _parameters;
|
||||||
public bool Stop { get; set; }
|
public bool Stop { get; set; }
|
||||||
|
|
||||||
@@ -61,6 +64,11 @@ namespace TimberWinR.Outputs
|
|||||||
var settings = new ConnectionSettings(pool)
|
var settings = new ConnectionSettings(pool)
|
||||||
.ExposeRawResponse();
|
.ExposeRawResponse();
|
||||||
|
|
||||||
|
if (_disablePing)
|
||||||
|
settings.DisablePing();
|
||||||
|
else if (_pingTimeout != 0)
|
||||||
|
settings.SetPingTimeout(_pingTimeout);
|
||||||
|
|
||||||
var client = new ElasticClient(settings);
|
var client = new ElasticClient(settings);
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
@@ -70,7 +78,7 @@ namespace TimberWinR.Outputs
|
|||||||
{
|
{
|
||||||
_sentMessages = 0;
|
_sentMessages = 0;
|
||||||
_errorCount = 0;
|
_errorCount = 0;
|
||||||
|
|
||||||
_parameters = parameters;
|
_parameters = parameters;
|
||||||
_flushSize = parameters.FlushSize;
|
_flushSize = parameters.FlushSize;
|
||||||
_idleFlushTimeSeconds = parameters.IdleFlushTimeInSeconds;
|
_idleFlushTimeSeconds = parameters.IdleFlushTimeInSeconds;
|
||||||
@@ -84,7 +92,8 @@ namespace TimberWinR.Outputs
|
|||||||
_numThreads = parameters.NumThreads;
|
_numThreads = parameters.NumThreads;
|
||||||
_maxQueueSize = parameters.MaxQueueSize;
|
_maxQueueSize = parameters.MaxQueueSize;
|
||||||
_queueOverflowDiscardOldest = parameters.QueueOverflowDiscardOldest;
|
_queueOverflowDiscardOldest = parameters.QueueOverflowDiscardOldest;
|
||||||
|
_disablePing = !parameters.EnablePing;
|
||||||
|
_pingTimeout = parameters.PingTimeout;
|
||||||
|
|
||||||
for (int i = 0; i < parameters.NumThreads; i++)
|
for (int i = 0; i < parameters.NumThreads; i++)
|
||||||
{
|
{
|
||||||
@@ -99,7 +108,7 @@ namespace TimberWinR.Outputs
|
|||||||
new JObject(
|
new JObject(
|
||||||
new JProperty("host", string.Join(",", _hosts)),
|
new JProperty("host", string.Join(",", _hosts)),
|
||||||
new JProperty("errors", _errorCount),
|
new JProperty("errors", _errorCount),
|
||||||
new JProperty("sentMmessageCount", _sentMessages),
|
new JProperty("messages", _sentMessages),
|
||||||
new JProperty("queuedMessageCount", _jsonQueue.Count),
|
new JProperty("queuedMessageCount", _jsonQueue.Count),
|
||||||
new JProperty("port", _port),
|
new JProperty("port", _port),
|
||||||
new JProperty("flushSize", _flushSize),
|
new JProperty("flushSize", _flushSize),
|
||||||
@@ -123,6 +132,10 @@ namespace TimberWinR.Outputs
|
|||||||
// Force an inital flush
|
// Force an inital flush
|
||||||
DateTime lastFlushTime = DateTime.MinValue;
|
DateTime lastFlushTime = DateTime.MinValue;
|
||||||
|
|
||||||
|
LogManager.GetCurrentClassLogger()
|
||||||
|
.Info("{0}: Elasticsarch Output To {1} Ready", Thread.CurrentThread.ManagedThreadId, string.Join(",", _hosts));
|
||||||
|
|
||||||
|
|
||||||
using (var syncHandle = new ManualResetEventSlim())
|
using (var syncHandle = new ManualResetEventSlim())
|
||||||
{
|
{
|
||||||
// Execute the query
|
// Execute the query
|
||||||
@@ -188,7 +201,7 @@ namespace TimberWinR.Outputs
|
|||||||
}
|
}
|
||||||
GC.Collect();
|
GC.Collect();
|
||||||
if (!Stop)
|
if (!Stop)
|
||||||
{
|
{
|
||||||
syncHandle.Wait(TimeSpan.FromMilliseconds(_interval), CancelToken);
|
syncHandle.Wait(TimeSpan.FromMilliseconds(_interval), CancelToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,6 +216,10 @@ namespace TimberWinR.Outputs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LogManager.GetCurrentClassLogger()
|
||||||
|
.Info("{0}: Elasticsarch Output To {1} Terminated", Thread.CurrentThread.ManagedThreadId, string.Join(",", _hosts));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
140
TimberWinR/Outputs/File.cs
Normal file
140
TimberWinR/Outputs/File.cs
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using NLog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace TimberWinR.Outputs
|
||||||
|
{
|
||||||
|
public class FileOutput : OutputSender
|
||||||
|
{
|
||||||
|
private TimberWinR.Manager _manager;
|
||||||
|
private readonly int _interval;
|
||||||
|
private readonly object _locker = new object();
|
||||||
|
private readonly List<JObject> _jsonQueue;
|
||||||
|
private long _sentMessages;
|
||||||
|
private Parser.FileOutputParameters _arguments;
|
||||||
|
public bool Stop { get; set; }
|
||||||
|
|
||||||
|
public FileOutput(TimberWinR.Manager manager, Parser.FileOutputParameters arguments, CancellationToken cancelToken)
|
||||||
|
: base(cancelToken, "File")
|
||||||
|
{
|
||||||
|
_arguments = arguments;
|
||||||
|
_sentMessages = 0;
|
||||||
|
_manager = manager;
|
||||||
|
_interval = arguments.Interval;
|
||||||
|
_jsonQueue = new List<JObject>();
|
||||||
|
|
||||||
|
var elsThread = new Task(FileSender, cancelToken);
|
||||||
|
elsThread.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override JObject ToJson()
|
||||||
|
{
|
||||||
|
JObject json = new JObject(
|
||||||
|
new JProperty("file-output",
|
||||||
|
new JObject(
|
||||||
|
new JProperty("queuedMessageCount", _jsonQueue.Count),
|
||||||
|
new JProperty("sentMessageCount", _sentMessages))));
|
||||||
|
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Pull off messages from the Queue, batch them up and send them all across
|
||||||
|
//
|
||||||
|
private void FileSender()
|
||||||
|
{
|
||||||
|
|
||||||
|
using (var syncHandle = new ManualResetEventSlim())
|
||||||
|
{
|
||||||
|
var fi = new FileInfo(_arguments.FileName);
|
||||||
|
if (File.Exists(_arguments.FileName))
|
||||||
|
File.Delete(_arguments.FileName);
|
||||||
|
|
||||||
|
LogManager.GetCurrentClassLogger().Info("File Output Sending To: {0}", fi.FullName);
|
||||||
|
|
||||||
|
using (StreamWriter sw = File.AppendText(_arguments.FileName))
|
||||||
|
{
|
||||||
|
// Execute the query
|
||||||
|
while (!Stop)
|
||||||
|
{
|
||||||
|
if (!CancelToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
JObject[] messages;
|
||||||
|
lock (_locker)
|
||||||
|
{
|
||||||
|
messages = _jsonQueue.Take(_jsonQueue.Count).ToArray();
|
||||||
|
_jsonQueue.RemoveRange(0, messages.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (messages.Length > 0)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (JObject obj in messages)
|
||||||
|
{
|
||||||
|
sw.WriteLine(obj.ToString(_arguments.ToFormat()));
|
||||||
|
_sentMessages++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.GetCurrentClassLogger().Error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!Stop)
|
||||||
|
syncHandle.Wait(TimeSpan.FromMilliseconds(_interval), CancelToken);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void MessageReceivedHandler(Newtonsoft.Json.Linq.JObject jsonMessage)
|
||||||
|
{
|
||||||
|
if (_manager.Config.Filters != null)
|
||||||
|
{
|
||||||
|
if (ApplyFilters(jsonMessage))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var message = jsonMessage.ToString();
|
||||||
|
|
||||||
|
lock (_locker)
|
||||||
|
{
|
||||||
|
_jsonQueue.Add(jsonMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ApplyFilters(JObject json)
|
||||||
|
{
|
||||||
|
bool drop = false;
|
||||||
|
|
||||||
|
foreach (var filter in _manager.Config.Filters)
|
||||||
|
{
|
||||||
|
if (!filter.Apply(json))
|
||||||
|
drop = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return drop;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -4,11 +4,12 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
using TimberWinR.Diagnostics;
|
||||||
using TimberWinR.Inputs;
|
using TimberWinR.Inputs;
|
||||||
|
|
||||||
namespace TimberWinR.Outputs
|
namespace TimberWinR.Outputs
|
||||||
{
|
{
|
||||||
public abstract class OutputSender
|
public abstract class OutputSender : IDiagnosable
|
||||||
{
|
{
|
||||||
public CancellationToken CancelToken { get; private set; }
|
public CancellationToken CancelToken { get; private set; }
|
||||||
private List<InputListener> _inputs;
|
private List<InputListener> _inputs;
|
||||||
|
|||||||
@@ -79,9 +79,11 @@ namespace TimberWinR.Outputs
|
|||||||
// Sample the queue and adjust the batch count if needed (ramp up slowly)
|
// Sample the queue and adjust the batch count if needed (ramp up slowly)
|
||||||
public int UpdateCurrentBatchCount(int queueSize, int currentBatchCount)
|
public int UpdateCurrentBatchCount(int queueSize, int currentBatchCount)
|
||||||
{
|
{
|
||||||
if (currentBatchCount < _maxBatchCount && currentBatchCount < queueSize && AverageQueueDepth() > currentBatchCount)
|
var avgQueueDepth = AverageQueueDepth();
|
||||||
|
|
||||||
|
if (currentBatchCount < _maxBatchCount && currentBatchCount < queueSize && avgQueueDepth > currentBatchCount)
|
||||||
{
|
{
|
||||||
currentBatchCount += Math.Max(_maxBatchCount / _batchCount, 1);
|
currentBatchCount += Math.Max(avgQueueDepth / _batchCount, _batchCount / 5);
|
||||||
if (currentBatchCount >= _maxBatchCount && !_warnedReachedMax)
|
if (currentBatchCount >= _maxBatchCount && !_warnedReachedMax)
|
||||||
{
|
{
|
||||||
LogManager.GetCurrentClassLogger().Warn("Maximum Batch Count of {0} reached.", currentBatchCount);
|
LogManager.GetCurrentClassLogger().Warn("Maximum Batch Count of {0} reached.", currentBatchCount);
|
||||||
@@ -130,6 +132,7 @@ namespace TimberWinR.Outputs
|
|||||||
private long _errorCount;
|
private long _errorCount;
|
||||||
private long _redisDepth;
|
private long _redisDepth;
|
||||||
private DateTime? _lastErrorTimeUTC;
|
private DateTime? _lastErrorTimeUTC;
|
||||||
|
private DateTime? _lastSentTimeUTC;
|
||||||
private readonly int _maxQueueSize;
|
private readonly int _maxQueueSize;
|
||||||
private readonly bool _queueOverflowDiscardOldest;
|
private readonly bool _queueOverflowDiscardOldest;
|
||||||
private BatchCounter _batchCounter;
|
private BatchCounter _batchCounter;
|
||||||
@@ -150,12 +153,13 @@ namespace TimberWinR.Outputs
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
RedisClient client = new RedisClient(_redisHosts[_redisHostIndex], _port);
|
RedisClient client = new RedisClient(_redisHosts[_redisHostIndex], _port);
|
||||||
client.SendTimeout = _timeout;
|
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
LogManager.GetCurrentClassLogger().Error(ex);
|
||||||
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -177,6 +181,7 @@ namespace TimberWinR.Outputs
|
|||||||
new JProperty("host", string.Join(",", _redisHosts)),
|
new JProperty("host", string.Join(",", _redisHosts)),
|
||||||
new JProperty("errors", _errorCount),
|
new JProperty("errors", _errorCount),
|
||||||
new JProperty("lastErrorTimeUTC", _lastErrorTimeUTC),
|
new JProperty("lastErrorTimeUTC", _lastErrorTimeUTC),
|
||||||
|
new JProperty("lastSentTimeUTC", _lastSentTimeUTC),
|
||||||
new JProperty("redisQueueDepth", _redisDepth),
|
new JProperty("redisQueueDepth", _redisDepth),
|
||||||
new JProperty("sentMessageCount", _sentMessages),
|
new JProperty("sentMessageCount", _sentMessages),
|
||||||
new JProperty("queuedMessageCount", _jsonQueue.Count),
|
new JProperty("queuedMessageCount", _jsonQueue.Count),
|
||||||
@@ -313,7 +318,14 @@ namespace TimberWinR.Outputs
|
|||||||
{
|
{
|
||||||
_batchCounter.SampleQueueDepth(_jsonQueue.Count);
|
_batchCounter.SampleQueueDepth(_jsonQueue.Count);
|
||||||
// Re-compute current batch size
|
// Re-compute current batch size
|
||||||
_currentBatchCount = _batchCounter.UpdateCurrentBatchCount(_jsonQueue.Count, _currentBatchCount);
|
|
||||||
|
LogManager.GetCurrentClassLogger()
|
||||||
|
.Trace("{0}: Average Queue Depth: {1}, Current Length: {2}",
|
||||||
|
Thread.CurrentThread.ManagedThreadId, _batchCounter.AverageQueueDepth(),
|
||||||
|
_jsonQueue.Count);
|
||||||
|
|
||||||
|
_currentBatchCount = _batchCounter.UpdateCurrentBatchCount(_jsonQueue.Count,
|
||||||
|
_currentBatchCount);
|
||||||
|
|
||||||
messages = _jsonQueue.Take(_currentBatchCount).ToArray();
|
messages = _jsonQueue.Take(_currentBatchCount).ToArray();
|
||||||
_jsonQueue.RemoveRange(0, messages.Length);
|
_jsonQueue.RemoveRange(0, messages.Length);
|
||||||
@@ -334,7 +346,9 @@ namespace TimberWinR.Outputs
|
|||||||
{
|
{
|
||||||
client.StartPipe();
|
client.StartPipe();
|
||||||
LogManager.GetCurrentClassLogger()
|
LogManager.GetCurrentClassLogger()
|
||||||
.Debug("{0}: Sending {1} Messages to {2}", Thread.CurrentThread.ManagedThreadId, messages.Length, client.Host);
|
.Debug("{0}: Sending {1} Messages to {2}",
|
||||||
|
Thread.CurrentThread.ManagedThreadId, messages.Length,
|
||||||
|
client.Host);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -342,6 +356,7 @@ namespace TimberWinR.Outputs
|
|||||||
Interlocked.Add(ref _sentMessages, messages.Length);
|
Interlocked.Add(ref _sentMessages, messages.Length);
|
||||||
client.EndPipe();
|
client.EndPipe();
|
||||||
sentSuccessfully = true;
|
sentSuccessfully = true;
|
||||||
|
_lastSentTimeUTC = DateTime.UtcNow;
|
||||||
if (messages.Length > 0)
|
if (messages.Length > 0)
|
||||||
_manager.IncrementMessageCount(messages.Length);
|
_manager.IncrementMessageCount(messages.Length);
|
||||||
}
|
}
|
||||||
@@ -385,9 +400,7 @@ namespace TimberWinR.Outputs
|
|||||||
_jsonQueue.InsertRange(0, messages);
|
_jsonQueue.InsertRange(0, messages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!Stop)
|
|
||||||
syncHandle.Wait(TimeSpan.FromMilliseconds(_interval), CancelToken);
|
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
@@ -403,6 +416,17 @@ namespace TimberWinR.Outputs
|
|||||||
Interlocked.Increment(ref _errorCount);
|
Interlocked.Increment(ref _errorCount);
|
||||||
LogManager.GetCurrentClassLogger().Error(ex);
|
LogManager.GetCurrentClassLogger().Error(ex);
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!Stop)
|
||||||
|
syncHandle.Wait(TimeSpan.FromMilliseconds(_interval), CancelToken);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
368
TimberWinR/Outputs/StatsD.cs
Normal file
368
TimberWinR/Outputs/StatsD.cs
Normal file
@@ -0,0 +1,368 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.Eventing.Reader;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using CSRedis;
|
||||||
|
using Nest;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using NLog;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using RapidRegex.Core;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Globalization;
|
||||||
|
using StatsdClient;
|
||||||
|
using TimberWinR.Parser;
|
||||||
|
|
||||||
|
namespace TimberWinR.Outputs
|
||||||
|
{
|
||||||
|
public class StatsDOutput : OutputSender
|
||||||
|
{
|
||||||
|
public int QueueDepth
|
||||||
|
{
|
||||||
|
get { return _jsonQueue.Count; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public long SentMessages
|
||||||
|
{
|
||||||
|
get { return _sentMessages; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private readonly int _port;
|
||||||
|
public string _host { get; set; }
|
||||||
|
|
||||||
|
private readonly int _interval;
|
||||||
|
private readonly object _locker = new object();
|
||||||
|
private readonly List<JObject> _jsonQueue;
|
||||||
|
private TimberWinR.Manager _manager;
|
||||||
|
private long _sentMessages;
|
||||||
|
private long _errorCount;
|
||||||
|
private readonly int _maxQueueSize;
|
||||||
|
private readonly bool _queueOverflowDiscardOldest;
|
||||||
|
private readonly int _flushSize;
|
||||||
|
private readonly int _idleFlushTimeSeconds;
|
||||||
|
private readonly int _numThreads;
|
||||||
|
private Parser.StatsDOutputParameters _params;
|
||||||
|
|
||||||
|
public bool Stop { get; set; }
|
||||||
|
|
||||||
|
public override JObject ToJson()
|
||||||
|
{
|
||||||
|
var json = new JObject(
|
||||||
|
new JProperty("statsd",
|
||||||
|
new JObject(
|
||||||
|
new JProperty("errors", _errorCount),
|
||||||
|
new JProperty("sentMessageCount", _sentMessages),
|
||||||
|
new JProperty("queuedMessageCount", _jsonQueue.Count),
|
||||||
|
new JProperty("port", _port),
|
||||||
|
new JProperty("threads", _numThreads),
|
||||||
|
new JProperty("flushSize", _flushSize),
|
||||||
|
new JProperty("idleFlushTime", _idleFlushTimeSeconds),
|
||||||
|
new JProperty("maxQueueSize", _maxQueueSize),
|
||||||
|
new JProperty("overflowDiscardOldest", _queueOverflowDiscardOldest),
|
||||||
|
new JProperty("interval", _interval),
|
||||||
|
new JProperty("host", _host)
|
||||||
|
)));
|
||||||
|
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StatsDOutput(TimberWinR.Manager manager, Parser.StatsDOutputParameters parameters, CancellationToken cancelToken)
|
||||||
|
: base(cancelToken, "StatsD")
|
||||||
|
{
|
||||||
|
_params = parameters;
|
||||||
|
_manager = manager;
|
||||||
|
_port = parameters.Port;
|
||||||
|
_host = parameters.Host;
|
||||||
|
_interval = parameters.Interval;
|
||||||
|
_flushSize = parameters.FlushSize;
|
||||||
|
_idleFlushTimeSeconds = parameters.IdleFlushTimeInSeconds;
|
||||||
|
_maxQueueSize = parameters.MaxQueueSize;
|
||||||
|
_queueOverflowDiscardOldest = parameters.QueueOverflowDiscardOldest;
|
||||||
|
_numThreads = parameters.NumThreads;
|
||||||
|
_jsonQueue = new List<JObject>();
|
||||||
|
|
||||||
|
var metricsConfig = new MetricsConfig
|
||||||
|
{
|
||||||
|
StatsdServerName = _host,
|
||||||
|
Prefix = parameters.Namespace,
|
||||||
|
};
|
||||||
|
|
||||||
|
StatsdClient.Metrics.Configure(metricsConfig);
|
||||||
|
|
||||||
|
for (int i = 0; i < _numThreads; i++)
|
||||||
|
{
|
||||||
|
Task.Factory.StartNew(StatsDSender, cancelToken, TaskCreationOptions.LongRunning, TaskScheduler.Current);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format("StatsD Host: {0} Port: {1}", _host, _port);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Forward on Json message to Redis Logstash queue
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="jsonMessage"></param>
|
||||||
|
protected override void MessageReceivedHandler(JObject jsonMessage)
|
||||||
|
{
|
||||||
|
if (_manager.Config.Filters != null)
|
||||||
|
{
|
||||||
|
if (ApplyFilters(jsonMessage))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var message = jsonMessage.ToString();
|
||||||
|
LogManager.GetCurrentClassLogger().Trace(message);
|
||||||
|
|
||||||
|
lock (_locker)
|
||||||
|
{
|
||||||
|
if (_jsonQueue.Count >= _maxQueueSize)
|
||||||
|
{
|
||||||
|
// If we've exceeded our queue size, and we're supposed to throw out the oldest objects first,
|
||||||
|
// then remove as many as necessary to get us under our limit
|
||||||
|
if (_queueOverflowDiscardOldest)
|
||||||
|
{
|
||||||
|
LogManager.GetCurrentClassLogger()
|
||||||
|
.Warn("Overflow discarding oldest {0} messages", _jsonQueue.Count - _maxQueueSize + 1);
|
||||||
|
|
||||||
|
_jsonQueue.RemoveRange(0, (_jsonQueue.Count - _maxQueueSize) + 1);
|
||||||
|
}
|
||||||
|
// Otherwise we're in a "discard newest" mode, and this is the newest message, so just ignore it
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogManager.GetCurrentClassLogger()
|
||||||
|
.Warn("Overflow discarding newest message: {0}", message);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_jsonQueue.Add(jsonMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ApplyFilters(JObject json)
|
||||||
|
{
|
||||||
|
bool drop = false;
|
||||||
|
foreach (var filter in _manager.Config.Filters)
|
||||||
|
{
|
||||||
|
if (!filter.Apply(json))
|
||||||
|
{
|
||||||
|
LogManager.GetCurrentClassLogger().Debug("{0}: Dropping: {1}", Thread.CurrentThread.ManagedThreadId, json.ToString());
|
||||||
|
drop = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check for matching type (if defined).
|
||||||
|
if (!drop && !string.IsNullOrEmpty(_params.InputType) && json["type"] != null)
|
||||||
|
{
|
||||||
|
string msgType = json["type"].ToString();
|
||||||
|
if (!string.IsNullOrEmpty(msgType) && msgType != _params.InputType)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return drop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Places messages back into the queue (for a future attempt)
|
||||||
|
private void interlockedInsert(List<JObject> messages)
|
||||||
|
{
|
||||||
|
lock (_locker)
|
||||||
|
{
|
||||||
|
Interlocked.Increment(ref _errorCount);
|
||||||
|
_jsonQueue.InsertRange(0, messages);
|
||||||
|
if (_jsonQueue.Count > _maxQueueSize)
|
||||||
|
{
|
||||||
|
LogManager.GetCurrentClassLogger().Warn("Exceeded maximum queue depth");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Pull off messages from the Queue, batch them up and send them all across
|
||||||
|
//
|
||||||
|
private void StatsDSender()
|
||||||
|
{
|
||||||
|
DateTime lastFlushTime = DateTime.MinValue;
|
||||||
|
|
||||||
|
using (var syncHandle = new ManualResetEventSlim())
|
||||||
|
{
|
||||||
|
// Execute the query
|
||||||
|
while (!Stop)
|
||||||
|
{
|
||||||
|
if (!CancelToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int messageCount = 0;
|
||||||
|
List<JObject> messages = new List<JObject>();
|
||||||
|
|
||||||
|
// Lets get whats in the queue
|
||||||
|
lock (_locker)
|
||||||
|
{
|
||||||
|
messageCount = _jsonQueue.Count;
|
||||||
|
|
||||||
|
// Time to flush?
|
||||||
|
if (messageCount >= _flushSize || (DateTime.UtcNow - lastFlushTime).Seconds >= _idleFlushTimeSeconds)
|
||||||
|
{
|
||||||
|
messages = _jsonQueue.Take(messageCount).ToList();
|
||||||
|
_jsonQueue.RemoveRange(0, messageCount);
|
||||||
|
if (messages.Count > 0)
|
||||||
|
_manager.IncrementMessageCount(messages.Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TransmitStats(messages);
|
||||||
|
|
||||||
|
if (!Stop)
|
||||||
|
syncHandle.Wait(TimeSpan.FromMilliseconds(_interval), CancelToken);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (ThreadAbortException)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Interlocked.Increment(ref _errorCount);
|
||||||
|
LogManager.GetCurrentClassLogger().Error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string BuildMetricPath(string metric, JObject json)
|
||||||
|
{
|
||||||
|
return string.Format("{0}.{1}", ExpandField(_params.Sender, json), ExpandField(metric, json));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TransmitStats(List<JObject> messages)
|
||||||
|
{
|
||||||
|
// We've got some to send.
|
||||||
|
if (messages.Count > 0)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int numMessages = messages.Count;
|
||||||
|
foreach (var m in messages)
|
||||||
|
{
|
||||||
|
SendMetrics(m);
|
||||||
|
}
|
||||||
|
messages.RemoveRange(0, numMessages);
|
||||||
|
Interlocked.Add(ref _sentMessages, numMessages);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.GetCurrentClassLogger().Error(ex);
|
||||||
|
|
||||||
|
interlockedInsert(messages); // Put the messages back into the queue
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (messages.Count > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process all the metrics for this json
|
||||||
|
private void SendMetrics(JObject m)
|
||||||
|
{
|
||||||
|
if (_params.Gauges != null && _params.Gauges.Length > 0)
|
||||||
|
DoGauges(m);
|
||||||
|
if (_params.Counts != null && _params.Counts.Length > 0)
|
||||||
|
DoCounts(m);
|
||||||
|
if (_params.Timings != null && _params.Timings.Length > 0)
|
||||||
|
DoTimings(m);
|
||||||
|
if (_params.Increments != null && _params.Increments.Length > 0)
|
||||||
|
DoIncrements(m);
|
||||||
|
if (_params.Decrements != null && _params.Decrements.Length > 0)
|
||||||
|
DoDecrements(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the Gauges
|
||||||
|
private void DoGauges(JObject json)
|
||||||
|
{
|
||||||
|
for (int i=0; i<_params.Gauges.Length; i += 2)
|
||||||
|
{
|
||||||
|
string metricPath = BuildMetricPath(_params.Gauges[i], json);
|
||||||
|
string gaugeName = ExpandField(_params.Gauges[i + 1], json);
|
||||||
|
int value;
|
||||||
|
if (int.TryParse(gaugeName, out value))
|
||||||
|
{
|
||||||
|
Metrics.Gauge(metricPath, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the Gauges
|
||||||
|
private void DoTimings(JObject json)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _params.Timings.Length; i += 2)
|
||||||
|
{
|
||||||
|
string metricPath = BuildMetricPath(_params.Timings[i], json);
|
||||||
|
string timingName = ExpandField(_params.Timings[i + 1], json);
|
||||||
|
int value;
|
||||||
|
if (int.TryParse(timingName, out value))
|
||||||
|
{
|
||||||
|
Metrics.Timer(metricPath, value, _params.SampleRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the Counts
|
||||||
|
private void DoCounts(JObject json)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _params.Counts.Length; i += 2)
|
||||||
|
{
|
||||||
|
string metricPath = BuildMetricPath(_params.Counts[i], json);
|
||||||
|
string countName = ExpandField(_params.Counts[i + 1], json);
|
||||||
|
int value;
|
||||||
|
if (int.TryParse(countName, out value))
|
||||||
|
{
|
||||||
|
Metrics.Counter(metricPath, value, _params.SampleRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Process the Increments
|
||||||
|
private void DoIncrements(JObject json)
|
||||||
|
{
|
||||||
|
foreach (var metric in _params.Increments)
|
||||||
|
{
|
||||||
|
string metricPath = BuildMetricPath(metric, json);
|
||||||
|
Metrics.Counter(metricPath, 1,_params.SampleRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the Increments
|
||||||
|
private void DoDecrements(JObject json)
|
||||||
|
{
|
||||||
|
foreach (var metric in _params.Increments)
|
||||||
|
{
|
||||||
|
string metricPath = BuildMetricPath(metric, json);
|
||||||
|
Metrics.Counter(metricPath, -1, _params.SampleRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,6 +34,7 @@ namespace TimberWinR.Outputs
|
|||||||
JObject json = new JObject(
|
JObject json = new JObject(
|
||||||
new JProperty("stdout",
|
new JProperty("stdout",
|
||||||
new JObject(
|
new JObject(
|
||||||
|
new JProperty("queuedMessageCount", _jsonQueue.Count),
|
||||||
new JProperty("sentMessageCount", _sentMessages))));
|
new JProperty("sentMessageCount", _sentMessages))));
|
||||||
|
|
||||||
return json;
|
return json;
|
||||||
@@ -67,7 +68,7 @@ namespace TimberWinR.Outputs
|
|||||||
foreach (JObject obj in messages)
|
foreach (JObject obj in messages)
|
||||||
{
|
{
|
||||||
Console.WriteLine(obj.ToString());
|
Console.WriteLine(obj.ToString());
|
||||||
_sentMessages++;
|
Interlocked.Increment(ref _sentMessages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
@@ -12,8 +12,10 @@ using Microsoft.SqlServer.Server;
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using NLog.Config;
|
||||||
using TimberWinR.Outputs;
|
using TimberWinR.Outputs;
|
||||||
using System.CodeDom.Compiler;
|
using System.CodeDom.Compiler;
|
||||||
|
using TimberWinR.Diagnostics;
|
||||||
|
|
||||||
namespace TimberWinR.Parser
|
namespace TimberWinR.Parser
|
||||||
{
|
{
|
||||||
@@ -25,7 +27,7 @@ namespace TimberWinR.Parser
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public abstract class LogstashFilter : IValidateSchema
|
public abstract class LogstashFilter : IValidateSchema, IDiagnosable
|
||||||
{
|
{
|
||||||
public abstract bool Apply(JObject json);
|
public abstract bool Apply(JObject json);
|
||||||
|
|
||||||
@@ -43,10 +45,8 @@ namespace TimberWinR.Parser
|
|||||||
JToken token = json[oldName];
|
JToken token = json[oldName];
|
||||||
if (token != null)
|
if (token != null)
|
||||||
{
|
{
|
||||||
|
json.Add(newName, token.DeepClone());
|
||||||
json.Remove(oldName);
|
json.Remove(oldName);
|
||||||
JToken newToken = json[newName];
|
|
||||||
if (newToken == null)
|
|
||||||
json.Add(newName, token);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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 class CodecArguments
|
||||||
{
|
{
|
||||||
public enum CodecType
|
public enum CodecType
|
||||||
{
|
{
|
||||||
singleline,
|
singleline,
|
||||||
multiline
|
multiline,
|
||||||
|
json,
|
||||||
|
plain
|
||||||
};
|
};
|
||||||
|
|
||||||
public enum WhatType
|
public enum WhatType
|
||||||
@@ -299,10 +333,12 @@ namespace TimberWinR.Parser
|
|||||||
|
|
||||||
public class TailFileArguments : IValidateSchema
|
public class TailFileArguments : IValidateSchema
|
||||||
{
|
{
|
||||||
|
[JsonProperty(PropertyName = "type")]
|
||||||
|
public string Type { get; set; }
|
||||||
[JsonProperty(PropertyName = "location")]
|
[JsonProperty(PropertyName = "location")]
|
||||||
public string Location { get; set; }
|
public string Location { get; set; }
|
||||||
[JsonProperty(PropertyName = "recurse")]
|
[JsonProperty(PropertyName = "recurse")]
|
||||||
public int Recurse { get; set; }
|
public int Recurse { get; set; }
|
||||||
[JsonProperty(PropertyName = "fields")]
|
[JsonProperty(PropertyName = "fields")]
|
||||||
public List<Field> Fields { get; set; }
|
public List<Field> Fields { get; set; }
|
||||||
[JsonProperty(PropertyName = "interval")]
|
[JsonProperty(PropertyName = "interval")]
|
||||||
@@ -329,6 +365,8 @@ namespace TimberWinR.Parser
|
|||||||
|
|
||||||
public class LogParameters : IValidateSchema
|
public class LogParameters : IValidateSchema
|
||||||
{
|
{
|
||||||
|
[JsonProperty(PropertyName = "type")]
|
||||||
|
public string Type { get; set; }
|
||||||
[JsonProperty(PropertyName = "location")]
|
[JsonProperty(PropertyName = "location")]
|
||||||
public string Location { get; set; }
|
public string Location { get; set; }
|
||||||
[JsonProperty(PropertyName = "iCodepage")]
|
[JsonProperty(PropertyName = "iCodepage")]
|
||||||
@@ -365,15 +403,21 @@ namespace TimberWinR.Parser
|
|||||||
{
|
{
|
||||||
[JsonProperty(PropertyName = "port")]
|
[JsonProperty(PropertyName = "port")]
|
||||||
public int Port { get; set; }
|
public int Port { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "type")]
|
||||||
|
public string Type { get; set; }
|
||||||
|
[JsonProperty("add_field")]
|
||||||
|
public string[] AddFields { get; set; }
|
||||||
|
[JsonProperty("rename")]
|
||||||
|
public string[] Renames { get; set; }
|
||||||
|
|
||||||
public TcpParameters()
|
public TcpParameters()
|
||||||
{
|
{
|
||||||
Port = 5140;
|
Port = 5140;
|
||||||
|
Type = "Win32-Tcp";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Validate()
|
public void Validate()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,15 +426,21 @@ namespace TimberWinR.Parser
|
|||||||
{
|
{
|
||||||
[JsonProperty(PropertyName = "port")]
|
[JsonProperty(PropertyName = "port")]
|
||||||
public int Port { get; set; }
|
public int Port { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "type")]
|
||||||
|
public string Type { get; set; }
|
||||||
|
[JsonProperty("add_field")]
|
||||||
|
public string[] AddFields { get; set; }
|
||||||
|
[JsonProperty("rename")]
|
||||||
|
public string[] Renames { get; set; }
|
||||||
|
|
||||||
public UdpParameters()
|
public UdpParameters()
|
||||||
{
|
{
|
||||||
Port = 5142;
|
Port = 5142;
|
||||||
|
Type = "Win32-Udp";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Validate()
|
public void Validate()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public class W3CLogParameters : IValidateSchema
|
public class W3CLogParameters : IValidateSchema
|
||||||
@@ -494,6 +544,88 @@ namespace TimberWinR.Parser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class StatsDOutputParameters : IValidateSchema
|
||||||
|
{
|
||||||
|
public class StatsDGaugeHashException : Exception
|
||||||
|
{
|
||||||
|
public StatsDGaugeHashException()
|
||||||
|
: base("StatsD output 'gauge' must be an array of pairs.")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class StatsDCountHashException : Exception
|
||||||
|
{
|
||||||
|
public StatsDCountHashException()
|
||||||
|
: base("StatsD output 'count' must be an array of pairs.")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[JsonProperty(PropertyName = "type")]
|
||||||
|
public string InputType { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "sender")]
|
||||||
|
public string Sender { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "namespace")]
|
||||||
|
public string Namespace { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "host")]
|
||||||
|
public string Host { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "port")]
|
||||||
|
public int Port { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "interval")]
|
||||||
|
public int Interval { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "flush_size")]
|
||||||
|
public int FlushSize { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "idle_flush_time")]
|
||||||
|
public int IdleFlushTimeInSeconds { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "max_queue_size")]
|
||||||
|
public int MaxQueueSize { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "queue_overflow_discard_oldest")]
|
||||||
|
public bool QueueOverflowDiscardOldest { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "threads")]
|
||||||
|
public int NumThreads { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "sample_rate")]
|
||||||
|
public double SampleRate { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "increment")] // Array: metric names
|
||||||
|
public string[] Increments { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "decrement")] // Array: metric names
|
||||||
|
public string[] Decrements { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "gauge")] // Hash: metric_name => gauge
|
||||||
|
public string[] Gauges { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "count")] // Hash: metric_name => count
|
||||||
|
public string[] Counts { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "timing")] // Hash: metric_name => count
|
||||||
|
public string[] Timings { get; set; }
|
||||||
|
|
||||||
|
public StatsDOutputParameters()
|
||||||
|
{
|
||||||
|
SampleRate = 1;
|
||||||
|
Port = 8125;
|
||||||
|
Host = "localhost";
|
||||||
|
Interval = 5000;
|
||||||
|
FlushSize = 5000;
|
||||||
|
IdleFlushTimeInSeconds = 10;
|
||||||
|
QueueOverflowDiscardOldest = true;
|
||||||
|
MaxQueueSize = 50000;
|
||||||
|
NumThreads = 1;
|
||||||
|
Namespace = "timberwinr";
|
||||||
|
Sender = System.Environment.MachineName.ToLower() + "." +
|
||||||
|
Microsoft.Win32.Registry.LocalMachine.OpenSubKey(
|
||||||
|
@"SYSTEM\CurrentControlSet\services\Tcpip\Parameters")
|
||||||
|
.GetValue("Domain", "")
|
||||||
|
.ToString().ToLower();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Validate()
|
||||||
|
{
|
||||||
|
if (Gauges != null && Gauges.Length % 2 != 0)
|
||||||
|
throw new StatsDGaugeHashException();
|
||||||
|
|
||||||
|
if (Counts != null && Counts.Length % 2 != 0)
|
||||||
|
throw new StatsDCountHashException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public class ElasticsearchOutputParameters
|
public class ElasticsearchOutputParameters
|
||||||
{
|
{
|
||||||
const string IndexDatePattern = "(%\\{(?<format>[^\\}]+)\\})";
|
const string IndexDatePattern = "(%\\{(?<format>[^\\}]+)\\})";
|
||||||
@@ -520,6 +652,10 @@ namespace TimberWinR.Parser
|
|||||||
public int MaxQueueSize { get; set; }
|
public int MaxQueueSize { get; set; }
|
||||||
[JsonProperty(PropertyName = "queue_overflow_discard_oldest")]
|
[JsonProperty(PropertyName = "queue_overflow_discard_oldest")]
|
||||||
public bool QueueOverflowDiscardOldest { get; set; }
|
public bool QueueOverflowDiscardOldest { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "enable_ping")]
|
||||||
|
public bool EnablePing { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "ping_timeout")]
|
||||||
|
public int PingTimeout { get; set; }
|
||||||
|
|
||||||
public ElasticsearchOutputParameters()
|
public ElasticsearchOutputParameters()
|
||||||
{
|
{
|
||||||
@@ -534,6 +670,8 @@ namespace TimberWinR.Parser
|
|||||||
Interval = 1000;
|
Interval = 1000;
|
||||||
QueueOverflowDiscardOldest = true;
|
QueueOverflowDiscardOldest = true;
|
||||||
MaxQueueSize = 50000;
|
MaxQueueSize = 50000;
|
||||||
|
EnablePing = false;
|
||||||
|
PingTimeout = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetIndexName(JObject json)
|
public string GetIndexName(JObject json)
|
||||||
@@ -605,8 +743,7 @@ namespace TimberWinR.Parser
|
|||||||
Index = "logstash";
|
Index = "logstash";
|
||||||
Host = new string[] { "localhost" };
|
Host = new string[] { "localhost" };
|
||||||
Timeout = 10000;
|
Timeout = 10000;
|
||||||
BatchCount = 50;
|
BatchCount = 200;
|
||||||
MaxBatchCount = BatchCount*10;
|
|
||||||
NumThreads = 1;
|
NumThreads = 1;
|
||||||
Interval = 5000;
|
Interval = 5000;
|
||||||
QueueOverflowDiscardOldest = true;
|
QueueOverflowDiscardOldest = true;
|
||||||
@@ -614,6 +751,8 @@ namespace TimberWinR.Parser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class StdoutOutputParameters
|
public class StdoutOutputParameters
|
||||||
{
|
{
|
||||||
[JsonProperty(PropertyName = "interval")]
|
[JsonProperty(PropertyName = "interval")]
|
||||||
@@ -625,6 +764,43 @@ namespace TimberWinR.Parser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class FileOutputParameters
|
||||||
|
{
|
||||||
|
public enum FormatKind
|
||||||
|
{
|
||||||
|
none, indented
|
||||||
|
};
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "interval")]
|
||||||
|
public int Interval { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "file_name")]
|
||||||
|
public string FileName { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "format")]
|
||||||
|
public FormatKind Format { get; set; }
|
||||||
|
|
||||||
|
public FileOutputParameters()
|
||||||
|
{
|
||||||
|
Format = FormatKind.none;
|
||||||
|
Interval = 1000;
|
||||||
|
FileName = "timberwinr.out";
|
||||||
|
}
|
||||||
|
|
||||||
|
public Newtonsoft.Json.Formatting ToFormat()
|
||||||
|
{
|
||||||
|
switch (Format)
|
||||||
|
{
|
||||||
|
case FormatKind.indented:
|
||||||
|
return Newtonsoft.Json.Formatting.Indented;
|
||||||
|
|
||||||
|
case FormatKind.none:
|
||||||
|
default:
|
||||||
|
return Newtonsoft.Json.Formatting.None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class OutputTargets
|
public class OutputTargets
|
||||||
{
|
{
|
||||||
[JsonProperty("Redis")]
|
[JsonProperty("Redis")]
|
||||||
@@ -635,6 +811,12 @@ namespace TimberWinR.Parser
|
|||||||
|
|
||||||
[JsonProperty("Stdout")]
|
[JsonProperty("Stdout")]
|
||||||
public StdoutOutputParameters[] Stdout { get; set; }
|
public StdoutOutputParameters[] Stdout { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("File")]
|
||||||
|
public FileOutputParameters[] File { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("StatsD")]
|
||||||
|
public StatsDOutputParameters[] StatsD { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class InputSources
|
public class InputSources
|
||||||
@@ -662,6 +844,9 @@ namespace TimberWinR.Parser
|
|||||||
|
|
||||||
[JsonProperty("Stdin")]
|
[JsonProperty("Stdin")]
|
||||||
public Stdin[] Stdins { get; set; }
|
public Stdin[] Stdins { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("Generator")]
|
||||||
|
public GeneratorParameters[] Generators { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class Grok : LogstashFilter, IValidateSchema
|
public partial class Grok : LogstashFilter, IValidateSchema
|
||||||
@@ -708,7 +893,7 @@ namespace TimberWinR.Parser
|
|||||||
|
|
||||||
public override void Validate()
|
public override void Validate()
|
||||||
{
|
{
|
||||||
if (Match == null || Match.Length != 2)
|
if (Match == null || Match.Length % 2 != 0)
|
||||||
throw new GrokFilterException();
|
throw new GrokFilterException();
|
||||||
|
|
||||||
if (AddTag != null && AddTag.Length % 2 != 0)
|
if (AddTag != null && AddTag.Length % 2 != 0)
|
||||||
@@ -849,7 +1034,7 @@ namespace TimberWinR.Parser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public partial class Json : LogstashFilter
|
public partial class Json : LogstashFilter
|
||||||
{
|
{
|
||||||
public class JsonMissingSourceException : Exception
|
public class JsonMissingSourceException : Exception
|
||||||
@@ -933,7 +1118,7 @@ namespace TimberWinR.Parser
|
|||||||
|
|
||||||
[JsonProperty("grokFilters")]
|
[JsonProperty("grokFilters")]
|
||||||
public Grok[] Groks { get; set; }
|
public Grok[] Groks { get; set; }
|
||||||
|
|
||||||
[JsonProperty("mutateFilters")]
|
[JsonProperty("mutateFilters")]
|
||||||
public Mutate[] Mutates { get; set; }
|
public Mutate[] Mutates { get; set; }
|
||||||
|
|
||||||
@@ -944,7 +1129,7 @@ namespace TimberWinR.Parser
|
|||||||
public Json[] Jsons { get; set; }
|
public Json[] Jsons { get; set; }
|
||||||
|
|
||||||
[JsonProperty("geoipFilters")]
|
[JsonProperty("geoipFilters")]
|
||||||
public GeoIP[] GeoIPs { get; set; }
|
public GeoIP[] GeoIPs { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TimberWinR
|
public class TimberWinR
|
||||||
|
|||||||
@@ -3,8 +3,38 @@
|
|||||||
A Native Windows to Redis/Elasticsearch Logstash Agent which runs as a service.
|
A Native Windows to Redis/Elasticsearch Logstash Agent which runs as a service.
|
||||||
|
|
||||||
Version / Date
|
Version / Date
|
||||||
|
### 1.3.26.0 - 2015-05-15
|
||||||
|
1. Added StatsD outputter
|
||||||
|
2. Fixed shutdown hang if shutdown was received before service was fully started up.
|
||||||
|
3. Closed issue [#36](https://github.com/Cimpress-MCP/TimberWinR/issues/36)
|
||||||
|
|
||||||
|
### 1.3.25.0 - 2015-04-30
|
||||||
|
1. Fixed Issue [#49](https://github.com/Cimpress-MCP/TimberWinR/issues/49)
|
||||||
|
2. Fixed potential non-thread safe when renaming properties
|
||||||
|
3. Added add_field, rename support to Udp/Tcp Input Listeners
|
||||||
|
4. Fixed issue with multiple renames (was previously only renaming the first one)
|
||||||
|
5. Added File outputter for testing.
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
2. Diabled elasticsearch outputter ping by default and parameterized the ping capability.
|
||||||
|
|
||||||
|
### 1.3.22.0 - 2015-04-14
|
||||||
|
1. Fixed minor bug with TailFiles and service re-starts not picking up
|
||||||
|
rolled files right away.
|
||||||
|
|
||||||
|
### 1.3.21.0 - 2015-04-13
|
||||||
|
1. Rolled Udp listener support to V4 only, too many issues with dual mode sockets
|
||||||
|
and hosts file. If we want to add this back, I will add a Udpv6 input.
|
||||||
|
|
||||||
|
### 1.3.20.0 - 2015-04-03
|
||||||
|
|
||||||
### 1.4.0.0 - 04/03/2015
|
|
||||||
1. A re-factoring of Logs and TailLogs to be more efficient and detect log rolling correctly,
|
1. A re-factoring of Logs and TailLogs to be more efficient and detect log rolling correctly,
|
||||||
this requires http://support.microsoft.com/en-us/kb/172190 which will be detected and
|
this requires http://support.microsoft.com/en-us/kb/172190 which will be detected and
|
||||||
set by TimberWinR, however, requires a reboot.
|
set by TimberWinR, however, requires a reboot.
|
||||||
@@ -12,11 +42,12 @@ Version / Date
|
|||||||
3. Created TimberWinR.TestGenerator for complete testing of TimberWinR
|
3. Created TimberWinR.TestGenerator for complete testing of TimberWinR
|
||||||
4. Fixed ipv4/ipv6 thread-safe issue with UdpInputListener which might lead to corrupted input data.
|
4. Fixed ipv4/ipv6 thread-safe issue with UdpInputListener which might lead to corrupted input data.
|
||||||
|
|
||||||
### 1.3.19.1 - 03/03/2015
|
### 1.3.19.1 - 2015-03-03
|
||||||
|
|
||||||
1. Added new Redis parameter _max\_batch\_count_ which increases the _batch\_count_ dynamically over time
|
1. Added new Redis parameter _max\_batch\_count_ which increases the _batch\_count_ dynamically over time
|
||||||
to handle input flooding. Default is _batch\_count_ * 10
|
to handle input flooding. Default is _batch\_count_ * 10
|
||||||
|
|
||||||
### 1.3.19.0 - 02/26/2015
|
### 1.3.19.0 - 2015-02-26
|
||||||
|
|
||||||
1. Added support for Multiline codecs for Stdin and Logs listeners, closes issue [#23](https://github.com/Cimpress-MCP/TimberWinR/issues/23)
|
1. Added support for Multiline codecs for Stdin and Logs listeners, closes issue [#23](https://github.com/Cimpress-MCP/TimberWinR/issues/23)
|
||||||
2. Added new TailFiles input type which uses a native implementation (more-efficient) than using LogParser's Log
|
2. Added new TailFiles input type which uses a native implementation (more-efficient) than using LogParser's Log
|
||||||
@@ -25,61 +56,60 @@ Version / Date
|
|||||||
5. Fixed bug when tailing non-existent log files which resulted in high cpu-usage.
|
5. Fixed bug when tailing non-existent log files which resulted in high cpu-usage.
|
||||||
6. Added feature to watch the configuration directory
|
6. Added feature to watch the configuration directory
|
||||||
|
|
||||||
### 1.3.18.0 - 12/22/2014
|
### 1.3.18.0 - 2014-12-22
|
||||||
|
|
||||||
1. Fixed bug introduced in 1.3.17.0 which changed the meaning of the delay for Elasticsearch, Redis and Stdout
|
1. Fixed bug introduced in 1.3.17.0 which changed the meaning of the delay for Elasticsearch, Redis and Stdout
|
||||||
intervals to be interpreted as seconds instead of milliseconds. 1.3.17.0 should not be used.
|
intervals to be interpreted as seconds instead of milliseconds. 1.3.17.0 should not be used.
|
||||||
2. Removed ability for installer to downgrade which was leading to leaving previous versions laying around (i.e. reverts 1.3.13.0 change)
|
2. Removed ability for installer to downgrade which was leading to leaving previous versions laying around (i.e. reverts 1.3.13.0 change)
|
||||||
|
|
||||||
### 1.3.17.0 - 12/19/2014
|
### 1.3.17.0 - 2014-12-19
|
||||||
|
|
||||||
1. Continued work improving shutdown time by using syncHandle.Wait instead of Thread.Sleep
|
1. Continued work improving shutdown time by using syncHandle.Wait instead of Thread.Sleep
|
||||||
|
|
||||||
### 1.3.16.0 - 12/19/2014
|
### 1.3.16.0 - 2014-12-19
|
||||||
|
|
||||||
1. Added logSource property to the Log input to facility the steering of log messages to different indices.
|
1. Added logSource property to the Log input to facility the steering of log messages to different indices.
|
||||||
|
|
||||||
### 1.3.15.0 - 12/12/2014
|
### 1.3.15.0 - 2014-12-12
|
||||||
|
|
||||||
1. Fixed bug whereby if the Udp or Tcp inputs receive an impropery formatted Json it caused the thread to terminate, and ignore
|
1. Fixed bug whereby if the Udp or Tcp inputs receive an impropery formatted Json it caused the thread to terminate, and ignore
|
||||||
future messages.
|
future messages.
|
||||||
|
|
||||||
### 1.3.14.0 - 12/11/2014
|
### 1.3.14.0 - 2014-12-11
|
||||||
|
|
||||||
1. Fixed bug with the Grok filter to match properly the value of the Text field against non-blank entries.
|
1. Fixed bug with the Grok filter to match properly the value of the Text field against non-blank entries.
|
||||||
|
|
||||||
### 1.3.13.0 - 12/02/2014
|
### 1.3.13.0 - 2014-12-02
|
||||||
|
|
||||||
1. Fixed MSI installer to allow downgrades.
|
1. Fixed MSI installer to allow downgrades.
|
||||||
|
|
||||||
### 1.3.12.0 - 11/25/2014
|
### 1.3.12.0 - 2014-11-25
|
||||||
|
|
||||||
1. Fixed all remaining memory leaks due to the COM Weak Surrogate which requires an explicit GC.Collect
|
1. Fixed all remaining memory leaks due to the COM Weak Surrogate which requires an explicit GC.Collect
|
||||||
|
|
||||||
### 1.3.11.0 - 11/21/2014
|
### 1.3.11.0 - 2014-11-21
|
||||||
|
|
||||||
1. Re-worked WindowsEvent listener to enable shutting down in a quicker fashion.
|
1. Re-worked WindowsEvent listener to enable shutting down in a quicker fashion.
|
||||||
|
|
||||||
### 1.3.10.0 - 11/18/2014
|
### 1.3.10.0 - 2014-11-18
|
||||||
|
|
||||||
1. Refactored Conditions handler to use non-leaking evaluator.
|
1. Refactored Conditions handler to use non-leaking evaluator.
|
||||||
|
|
||||||
### 1.3.9.0 - 11/11/2014
|
### 1.3.9.0 - 2014-11-11
|
||||||
|
|
||||||
1. Merged in pull request #9
|
1. Merged in pull request #9
|
||||||
2. Updated chocolately uninstall to preserve GUID
|
2. Updated chocolately uninstall to preserve GUID
|
||||||
|
|
||||||
### 1.3.8.0 - 11/06/2014
|
### 1.3.8.0 - 2014-11-06
|
||||||
|
|
||||||
1. Added interval parameter to WindowsEvent input listener
|
1. Added interval parameter to WindowsEvent input listener
|
||||||
2. Increased default value for interval to 60 seconds for polling WindowsEvents
|
2. Increased default value for interval to 60 seconds for polling WindowsEvents
|
||||||
|
|
||||||
### 1.3.7.0 - 10/21/2014
|
### 1.3.7.0 - 2014-10-21
|
||||||
|
|
||||||
1. Added additional information for diagnostics port
|
1. Added additional information for diagnostics port
|
||||||
2. Completed minor handling of Log rolling detection
|
2. Completed minor handling of Log rolling detection
|
||||||
|
|
||||||
### 1.3.6.0 - 10/16/2014
|
### 1.3.6.0 - 2014-10-16
|
||||||
|
|
||||||
1. Handle rolling of logs whereby the logfile remains the same, but the content resets back to 0 bytes.
|
1. Handle rolling of logs whereby the logfile remains the same, but the content resets back to 0 bytes.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -60,13 +60,21 @@
|
|||||||
<Reference Include="NLog">
|
<Reference Include="NLog">
|
||||||
<HintPath>..\packages\NLog.3.2.0.0\lib\net40\NLog.dll</HintPath>
|
<HintPath>..\packages\NLog.3.2.0.0\lib\net40\NLog.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="RapidRegex.Core">
|
<Reference Include="RapidRegex.Core, Version=1.0.0.4, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\RapidRegex.Core.1.0.0.2\lib\net40\RapidRegex.Core.dll</HintPath>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
|
<HintPath>..\packages\RapidRegex.Core.1.0.0.4\lib\net40\RapidRegex.Core.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="RestSharp">
|
<Reference Include="RestSharp">
|
||||||
<HintPath>..\packages\RestSharp.105.0.0\lib\net4\RestSharp.dll</HintPath>
|
<HintPath>..\packages\RestSharp.105.0.0\lib\net4\RestSharp.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="StatsdClient">
|
||||||
|
<HintPath>..\packages\StatsdClient.1.0.0.19\lib\net35\StatsdClient.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="StatsdClient.Configuration">
|
||||||
|
<HintPath>..\packages\StatsdClient.1.0.0.19\lib\net35\StatsdClient.Configuration.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.configuration" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="System.Linq.Dynamic">
|
<Reference Include="System.Linq.Dynamic">
|
||||||
<HintPath>..\packages\System.Linq.Dynamic.1.0.4\lib\net40\System.Linq.Dynamic.dll</HintPath>
|
<HintPath>..\packages\System.Linq.Dynamic.1.0.4\lib\net40\System.Linq.Dynamic.dll</HintPath>
|
||||||
@@ -82,10 +90,13 @@
|
|||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="Codecs\JsonCodec.cs" />
|
||||||
<Compile Include="Codecs\Multiline.cs" />
|
<Compile Include="Codecs\Multiline.cs" />
|
||||||
|
<Compile Include="Codecs\PlainCodec.cs" />
|
||||||
<Compile Include="Configuration.cs" />
|
<Compile Include="Configuration.cs" />
|
||||||
<Compile Include="ConfigurationErrors.cs" />
|
<Compile Include="ConfigurationErrors.cs" />
|
||||||
<Compile Include="Diagnostics\Diagnostics.cs" />
|
<Compile Include="Diagnostics\Diagnostics.cs" />
|
||||||
|
<Compile Include="Diagnostics\IDiagnosable.cs" />
|
||||||
<Compile Include="Filters\DateFilter.cs" />
|
<Compile Include="Filters\DateFilter.cs" />
|
||||||
<Compile Include="Filters\FilterBase.cs" />
|
<Compile Include="Filters\FilterBase.cs" />
|
||||||
<Compile Include="Filters\GrokFilter.cs" />
|
<Compile Include="Filters\GrokFilter.cs" />
|
||||||
@@ -94,6 +105,7 @@
|
|||||||
<Compile Include="Filters\MutateFilter.cs" />
|
<Compile Include="Filters\MutateFilter.cs" />
|
||||||
<Compile Include="ICodec.cs" />
|
<Compile Include="ICodec.cs" />
|
||||||
<Compile Include="Inputs\FieldDefinitions.cs" />
|
<Compile Include="Inputs\FieldDefinitions.cs" />
|
||||||
|
<Compile Include="Inputs\GeneratorInput.cs" />
|
||||||
<Compile Include="Inputs\IISW3CRowReader.cs" />
|
<Compile Include="Inputs\IISW3CRowReader.cs" />
|
||||||
<Compile Include="Inputs\LogsFileDatabase.cs" />
|
<Compile Include="Inputs\LogsFileDatabase.cs" />
|
||||||
<Compile Include="Inputs\TailFileListener.cs" />
|
<Compile Include="Inputs\TailFileListener.cs" />
|
||||||
@@ -111,7 +123,9 @@
|
|||||||
<Compile Include="Manager.cs" />
|
<Compile Include="Manager.cs" />
|
||||||
<Compile Include="Outputs\Elasticsearch.cs" />
|
<Compile Include="Outputs\Elasticsearch.cs" />
|
||||||
<Compile Include="Outputs\OutputSender.cs" />
|
<Compile Include="Outputs\OutputSender.cs" />
|
||||||
|
<Compile Include="Outputs\StatsD.cs" />
|
||||||
<Compile Include="Outputs\Redis.cs" />
|
<Compile Include="Outputs\Redis.cs" />
|
||||||
|
<Compile Include="Outputs\File.cs" />
|
||||||
<Compile Include="Outputs\Stdout.cs" />
|
<Compile Include="Outputs\Stdout.cs" />
|
||||||
<Compile Include="Parser.cs" />
|
<Compile Include="Parser.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
@@ -135,8 +149,11 @@
|
|||||||
</Content>
|
</Content>
|
||||||
<None Include="mdocs\Codec.md" />
|
<None Include="mdocs\Codec.md" />
|
||||||
<None Include="mdocs\DateFilter.md" />
|
<None Include="mdocs\DateFilter.md" />
|
||||||
|
<None Include="mdocs\StatsD.md" />
|
||||||
<None Include="mdocs\Filters.md" />
|
<None Include="mdocs\Filters.md" />
|
||||||
<None Include="mdocs\GeoIPFilter.md" />
|
<None Include="mdocs\GeoIPFilter.md" />
|
||||||
|
<None Include="mdocs\Generator.md" />
|
||||||
|
<None Include="mdocs\FileOutput.md" />
|
||||||
<None Include="mdocs\TailFiles.md" />
|
<None Include="mdocs\TailFiles.md" />
|
||||||
<None Include="mdocs\UdpInput.md" />
|
<None Include="mdocs\UdpInput.md" />
|
||||||
<None Include="mdocs\W3CInput.md" />
|
<None Include="mdocs\W3CInput.md" />
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
The Elasticsearch output passes on data directly to Elasticsearch.
|
The Elasticsearch output passes on data directly to Elasticsearch.
|
||||||
|
|
||||||
## Parameters
|
## Parameters
|
||||||
The following parameters are allowed when configuring the Redis output.
|
The following parameters are allowed when configuring the Elasticsearch output.
|
||||||
|
|
||||||
| Parameter | Type | Description | Details | Default |
|
| Parameter | Type | Description | Details | Default |
|
||||||
| :-------------|:---------|:------------------------------------------------------------| :--------------------------- | :-- |
|
| :-------------|:---------|:------------------------------------------------------------| :--------------------------- | :-- |
|
||||||
@@ -16,6 +16,8 @@ The following parameters are allowed when configuring the Redis output.
|
|||||||
| *port* | integer | Elasticsearch port number | This port must be open | 9200 |
|
| *port* | integer | Elasticsearch port number | This port must be open | 9200 |
|
||||||
| *queue_overflow_discard_oldest* | bool | If true, discard oldest messages when max_queue_size reached otherwise discard newest | | true |
|
| *queue_overflow_discard_oldest* | bool | If true, discard oldest messages when max_queue_size reached otherwise discard newest | | true |
|
||||||
| *threads* | [string] | Number of Threads | Number of worker threads processing messages | 1 |
|
| *threads* | [string] | Number of Threads | Number of worker threads processing messages | 1 |
|
||||||
|
| *enable_ping* | bool | If true, pings the server to test for keep alive | | false |
|
||||||
|
| *ping_timeout* | integer | Default ping timeout when enable_ping is true | milliseconds | 200 |
|
||||||
|
|
||||||
### Index parameter
|
### Index parameter
|
||||||
If you want to output your data everyday to a new index, use following index format: "index-%{yyyy.MM.dd}". Here date format could be any forwat which you need.
|
If you want to output your data everyday to a new index, use following index format: "index-%{yyyy.MM.dd}". Here date format could be any forwat which you need.
|
||||||
|
|||||||
27
TimberWinR/mdocs/FileOutput.md
Normal file
27
TimberWinR/mdocs/FileOutput.md
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Output: File
|
||||||
|
|
||||||
|
The File output passes on data into a text file.
|
||||||
|
|
||||||
|
## Parameters
|
||||||
|
The following parameters are allowed when configuring the File output.
|
||||||
|
|
||||||
|
| Parameter | Type | Description | Details | Default |
|
||||||
|
| :-------------|:---------|:------------------------------------------------------------| :--------------------------- | :-- |
|
||||||
|
| *interval* | integer | Interval in milliseconds to sleep before appending data | Interval | 1000 |
|
||||||
|
| *file_name* | string | Name of the file to be created | | timberwinr.out |
|
||||||
|
|
||||||
|
Example Input:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"TimberWinR": {
|
||||||
|
"Outputs": {
|
||||||
|
"File": [
|
||||||
|
{
|
||||||
|
"file_name": "foo.out",
|
||||||
|
"interval": 1000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
37
TimberWinR/mdocs/Generator.md
Normal file
37
TimberWinR/mdocs/Generator.md
Normal file
@@ -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 the test log Generator.
|
||||||
|
|
||||||
|
| 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 the generated line, the following fields are added:
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- |:-----| :-----------|
|
||||||
|
| Message | STRING | Text line content |
|
||||||
@@ -26,14 +26,14 @@ The following operations are allowed when mutating a field.
|
|||||||
|
|
||||||
| Operation | Type | Description
|
| Operation | Type | Description
|
||||||
| :---------------|:----------------|:-----------------------------------------------------------------------|
|
| :---------------|:----------------|:-----------------------------------------------------------------------|
|
||||||
| *type* | property:string |Type to which this filter applyes, if empty, applies to all types.
|
|
||||||
| *condition* | property:string |C# expression
|
|
||||||
| *rename* | property:array |Rename one or more fields
|
|
||||||
| *match* | property:string |Required field must match before any subsequent grok operations are executed.
|
|
||||||
| *add_field* | property:array |If the filter is successful, add an arbitrary field to this event. Field names can be dynamic and include parts of the event using the %{field} syntax. This property must be specified in pairs.
|
| *add_field* | property:array |If the filter is successful, add an arbitrary field to this event. Field names can be dynamic and include parts of the event using the %{field} syntax. This property must be specified in pairs.
|
||||||
| *remove_field* | property:array |If the filter is successful, remove arbitrary fields from this event. Field names can be dynamic and include parts of the event using the %{field} syntax.
|
|
||||||
| *add_tag* | property:array |If the filter is successful, add an arbitrary tag to this event. Tag names can be dynamic and include parts of the event using the %{field} syntax.
|
| *add_tag* | property:array |If the filter is successful, add an arbitrary tag to this event. Tag names can be dynamic and include parts of the event using the %{field} syntax.
|
||||||
|
| *condition* | property:string |C# expression
|
||||||
|
| *match* | property:array |Required field must match (any) before any subsequent grok operations are executed.
|
||||||
|
| *remove_field* | property:array |If the filter is successful, remove arbitrary fields from this event. Field names can be dynamic and include parts of the event using the %{field} syntax.
|
||||||
| *remove_tag* | property:array |If the filter is successful, remove arbitrary tags from this event. Field names can be dynamic and include parts of the event using the %{field} syntax.
|
| *remove_tag* | property:array |If the filter is successful, remove arbitrary tags from this event. Field names can be dynamic and include parts of the event using the %{field} syntax.
|
||||||
|
| *rename* | property:array |Rename one or more fields
|
||||||
|
| *type* | property:string |Type to which this filter applies, if empty, applies to all types.
|
||||||
|
|
||||||
## Operation Details
|
## Operation Details
|
||||||
### match
|
### match
|
||||||
@@ -67,6 +67,28 @@ Given this configuration
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Given this configuration
|
||||||
|
```json
|
||||||
|
"Filters": [
|
||||||
|
{
|
||||||
|
"grok": {
|
||||||
|
"matches": [
|
||||||
|
"message",
|
||||||
|
"%{IP:client} %{WORD:method} %{URIPATHPARAM:request} %{NUMBER:bytes} %{NUMBER:duration}"
|
||||||
|
],
|
||||||
|
"add_tag": [
|
||||||
|
"http_log"
|
||||||
|
],
|
||||||
|
"add_field": [
|
||||||
|
"verb", "%{method}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
And if the message matches, then 6 fields would be added to the event:
|
And if the message matches, then 6 fields would be added to the event:
|
||||||
1. client=55.3.244.1
|
1. client=55.3.244.1
|
||||||
2. method=GET
|
2. method=GET
|
||||||
|
|||||||
@@ -7,25 +7,27 @@ The following operations are allowed when mutating a field.
|
|||||||
|
|
||||||
| Operation | Type | Description
|
| Operation | Type | Description
|
||||||
| :---------------|:----------------|:-----------------------------------------------------------------------|
|
| :---------------|:----------------|:-----------------------------------------------------------------------|
|
||||||
| *type* | property:string |Type to which this filter applies, if empty, applies to all types.
|
|
||||||
| *condition* | property:string |C# expression, if the expression is true, continue, otherwise, ignore
|
|
||||||
| *remove_source* | property:bool |If true, the source property is removed, default: true
|
|
||||||
| *source* | property:string |Required field indicates which field contains the Json to be parsed
|
|
||||||
| *promote* | property:string |If supplied any properties named *promote* will be promoted to top-level
|
|
||||||
| *target* | property:string |If suppled, the parsed json will be contained underneath a propery named *target*
|
|
||||||
| *add_field* | property:array |If the filter is successful, add an arbitrary field to this event. Field names can be dynamic and include parts of the event using the %{field} syntax. This property must be specified in pairs.
|
| *add_field* | property:array |If the filter is successful, add an arbitrary field to this event. Field names can be dynamic and include parts of the event using the %{field} syntax. This property must be specified in pairs.
|
||||||
| *remove_field* | property:array |If the filter is successful, remove arbitrary fields from this event. Field names can be dynamic and include parts of the event using the %{field} syntax.
|
|
||||||
| *add_tag* | property:array |If the filter is successful, add an arbitrary tag to this event. Tag names can be dynamic and include parts of the event using the %{field} syntax.
|
| *add_tag* | property:array |If the filter is successful, add an arbitrary tag to this event. Tag names can be dynamic and include parts of the event using the %{field} syntax.
|
||||||
|
| *condition* | property:string |C# expression, if the expression is true, continue, otherwise, ignore
|
||||||
|
| *promote* | property:string |If supplied any properties named *promote* will be promoted to top-level
|
||||||
|
| *remove_field* | property:array |If the filter is successful, remove arbitrary fields from this event. Field names can be dynamic and include parts of the event using the %{field} syntax.
|
||||||
| *remove_tag* | property:array |If the filter is successful, remove arbitrary tags from this event. Field names can be dynamic and include parts of the event using the %{field} syntax.
|
| *remove_tag* | property:array |If the filter is successful, remove arbitrary tags from this event. Field names can be dynamic and include parts of the event using the %{field} syntax.
|
||||||
|
| *remove_source* | property:bool |If true, the source property is removed, default: true
|
||||||
|
| *rename* | property:array |Rename one or more fields
|
||||||
|
| *source* | property:string |Required field indicates which field contains the Json to be parsed
|
||||||
|
| *target* | property:string |If suppled, the parsed json will be contained underneath a propery named *target*
|
||||||
|
| *type* | property:string |Type to which this filter applies, if empty, applies to all types.
|
||||||
|
|
||||||
## Operation Details
|
## Operation Details
|
||||||
### source
|
### source
|
||||||
The match field is required, the first argument is the field to inspect, and compare to the expression specified by the second
|
The source field is required, and indicates what Field contains the target Json, In the
|
||||||
argument. In the below example, the message is spected to be something like this from a fictional sample log:
|
below example, the [Logs](https://github.com/Cimpress-MCP/TimberWinR/blob/master/TimberWinR/mdocs/Logs.md) input produces a Text field,
|
||||||
|
which contains a line to be parsed as Json.
|
||||||
|
|
||||||
Given this input configuration:
|
Given this input configuration:
|
||||||
|
|
||||||
Lets assume that a newline such as the following is appended to foo.jlog:
|
Lets assume that a new line such as the following is appended to foo.jlog:, this would end up being the Text field
|
||||||
```
|
```
|
||||||
{"Email":"james@example.com","Active":true,"CreatedDate":"2013-01-20T00:00:00Z","Roles":["User","Admin"]}
|
{"Email":"james@example.com","Active":true,"CreatedDate":"2013-01-20T00:00:00Z","Roles":["User","Admin"]}
|
||||||
```
|
```
|
||||||
@@ -54,7 +56,7 @@ Lets assume that a newline such as the following is appended to foo.jlog:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
In the above example, the file foo.jlog is being tailed, and when a newline is appended, it is assumed
|
In the above example, the file foo.jlog is being tailed, and when a new line is appended, it is assumed
|
||||||
to be Json and is parsed from the Text field, the parsed Json is then inserted underneath a property *stuff*
|
to be Json and is parsed from the Text field, the parsed Json is then inserted underneath a property *stuff*
|
||||||
|
|
||||||
The resulting output would be:
|
The resulting output would be:
|
||||||
@@ -84,8 +86,8 @@ The fields must be in pairs with oldname first and newname second.
|
|||||||
"target": "stuff",
|
"target": "stuff",
|
||||||
"source": "Text",
|
"source": "Text",
|
||||||
"rename": [
|
"rename": [
|
||||||
"Text",
|
"level",
|
||||||
"Data"
|
"Level"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,7 +98,9 @@ The fields must be in pairs with fieldName first and value second.
|
|||||||
```json
|
```json
|
||||||
"Filters": [
|
"Filters": [
|
||||||
{
|
{
|
||||||
"json": {
|
"json": {
|
||||||
|
"type": "Win32-FileLog",
|
||||||
|
"source": "Text",
|
||||||
"add_field": [
|
"add_field": [
|
||||||
"ComputerName", "Host",
|
"ComputerName", "Host",
|
||||||
"Username", "%{SID}"
|
"Username", "%{SID}"
|
||||||
@@ -112,7 +116,9 @@ Remove the fields. More than one field can be specified at a time.
|
|||||||
"Filters": [
|
"Filters": [
|
||||||
{
|
{
|
||||||
"json": {
|
"json": {
|
||||||
"remove_tag": [
|
"type": "Win32-FileLog",
|
||||||
|
"source": "Text",
|
||||||
|
"remove_field": [
|
||||||
"static_tag1",
|
"static_tag1",
|
||||||
"Computer_%{Host}"
|
"Computer_%{Host}"
|
||||||
]
|
]
|
||||||
@@ -128,6 +134,8 @@ Adds the tag(s) to the tag array.
|
|||||||
"Filters": [
|
"Filters": [
|
||||||
{
|
{
|
||||||
"json": {
|
"json": {
|
||||||
|
"type": "Win32-FileLog",
|
||||||
|
"source": "Text",
|
||||||
"add_tag": [
|
"add_tag": [
|
||||||
"foo_%{Host}",
|
"foo_%{Host}",
|
||||||
"static_tag1"
|
"static_tag1"
|
||||||
@@ -143,6 +151,8 @@ Remove the tag(s) to the tag array. More than one tag can be specified at a tim
|
|||||||
"Filters": [
|
"Filters": [
|
||||||
{
|
{
|
||||||
"json": {
|
"json": {
|
||||||
|
"type": "Win32-FileLog",
|
||||||
|
"source": "Text",
|
||||||
"remove_tag": [
|
"remove_tag": [
|
||||||
"static_tag1",
|
"static_tag1",
|
||||||
"Username"
|
"Username"
|
||||||
|
|||||||
@@ -7,11 +7,12 @@ The following parameters are allowed when configuring WindowsEvents.
|
|||||||
|
|
||||||
| Parameter | Type | Description | Details | Default |
|
| Parameter | Type | Description | Details | Default |
|
||||||
| :---------------- |:---------------| :----------------------------------------------------------------------- | :--------------------------- | :-- |
|
| :---------------- |:---------------| :----------------------------------------------------------------------- | :--------------------------- | :-- |
|
||||||
|
| *iCodepage* | integer |Codepage of the text file. | 0 is the system codepage, -1 is UNICODE. | 0 |
|
||||||
| *location* | string |Location of file(s) to monitor | Path to text file(s) including wildcards. | |
|
| *location* | string |Location of file(s) to monitor | Path to text file(s) including wildcards. | |
|
||||||
| *logSource* | string |Source name | Used for conditions | |
|
| *logSource* | string |Source name | Used for conditions | |
|
||||||
| *recurse* | integer |Max subdirectory recursion level. | 0 disables subdirectory recursion; -1 enables unlimited recursion. | 0 |
|
| *recurse* | integer |Max subdirectory recursion level. | 0 disables subdirectory recursion; -1 enables unlimited recursion. | 0 |
|
||||||
| *splitLongLines* | boolean |Behavior when event messages or event category names cannot be resolved. |When a text line is longer than 128K characters, the format truncates the line and either discards the remaining of the line (when this parameter is set to "false"), or processes the remainder of the line as a new line (when this parameter is set to "true").| false |
|
| *splitLongLines* | boolean |Behavior when event messages or event category names cannot be resolved. |When a text line is longer than 128K characters, the format truncates the line and either discards the remaining of the line (when this parameter is set to "false"), or processes the remainder of the line as a new line (when this parameter is set to "true").| false |
|
||||||
| *iCodepage* | integer |Codepage of the text file. | 0 is the system codepage, -1 is UNICODE. | 0 |
|
| *type* | string |Typename for this Input | | Win32-FileLog |
|
||||||
| [codec](https://github.com/Cimpress-MCP/TimberWinR/blob/master/TimberWinR/mdocs/Codec.md) | object | Codec to use |
|
| [codec](https://github.com/Cimpress-MCP/TimberWinR/blob/master/TimberWinR/mdocs/Codec.md) | object | Codec to use |
|
||||||
|
|
||||||
Example Input: Monitors all files (recursively) located at C:\Logs1\ matching *.log as a pattern. I.e. C:\Logs1\foo.log, C:\Logs1\Subdir\Log2.log, etc.
|
Example Input: Monitors all files (recursively) located at C:\Logs1\ matching *.log as a pattern. I.e. C:\Logs1\foo.log, C:\Logs1\Subdir\Log2.log, etc.
|
||||||
@@ -39,3 +40,4 @@ After a successful parse of an event, the following fields are added:
|
|||||||
| LogFilename | STRING |Full path of the file containing this line |
|
| LogFilename | STRING |Full path of the file containing this line |
|
||||||
| Index | INTEGER | Line number |
|
| Index | INTEGER | Line number |
|
||||||
| Text | STRING | Text line content |
|
| Text | STRING | Text line content |
|
||||||
|
| type | STRING | Win32-FileLog |
|
||||||
|
|||||||
@@ -7,15 +7,15 @@ The following parameters are allowed when configuring the Redis output.
|
|||||||
|
|
||||||
| Parameter | Type | Description | Details | Default |
|
| Parameter | Type | Description | Details | Default |
|
||||||
| :-------------|:---------|:------------------------------------------------------------| :--------------------------- | :-- |
|
| :-------------|:---------|:------------------------------------------------------------| :--------------------------- | :-- |
|
||||||
| *threads* | string | Location of log files(s) to monitor | Number of worker theads to send messages | 1 |
|
| *batch_count* | integer | Sent as a single message | Number of messages to aggregate | 200 |
|
||||||
| *batch_count* | integer | Sent as a single message | Number of messages to aggregate | 10 |
|
| *host* | string | The hostname(s) of your Redis server(s) | IP or DNS name | |
|
||||||
| *max_batch_count* | integer | Dynamically adjusted count maximum | Increases over time | batch_count*10 |
|
|
||||||
| *interval* | integer | Interval in milliseconds to sleep during batch sends | Interval | 5000 |
|
|
||||||
| *index* | string | The name of the redis list | logstash index name | logstash |
|
| *index* | string | The name of the redis list | logstash index name | logstash |
|
||||||
| *host* | [string] | The hostname(s) of your Redis server(s) | IP or DNS name | |
|
| *interval* | integer | Interval in milliseconds to sleep during batch sends | Interval | 5000 |
|
||||||
| *port* | integer | Redis port number | This port must be open | 6379 |
|
| *max_batch_count* | integer | Dynamically adjusted count maximum | Increases over time | batch_count * 10 |
|
||||||
| *max_queue_size* | integer | Maximum redis queue depth | | 50000 |
|
| *max_queue_size* | integer | Maximum redis queue depth | | 50000 |
|
||||||
|
| *port* | integer | Redis port number | This port must be open | 6379 |
|
||||||
| *queue_overflow_discard_oldest* | bool | If true, discard oldest messages when max_queue_size reached otherwise discard newest | | true |
|
| *queue_overflow_discard_oldest* | bool | If true, discard oldest messages when max_queue_size reached otherwise discard newest | | true |
|
||||||
|
| *threads* | string | Location of log files(s) to monitor | Number of worker theads to send messages | 1 |
|
||||||
|
|
||||||
Example Input:
|
Example Input:
|
||||||
```json
|
```json
|
||||||
|
|||||||
94
TimberWinR/mdocs/StatsD.md
Normal file
94
TimberWinR/mdocs/StatsD.md
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
# Output: StatsD
|
||||||
|
|
||||||
|
The StatsD output passes on data directly to StatsD. (https://github.com/etsy/statsd)
|
||||||
|
|
||||||
|
## Parameters
|
||||||
|
The following parameters are allowed when configuring the StatsD output.
|
||||||
|
|
||||||
|
| Parameter | Type | Description | Details | Default |
|
||||||
|
| :-------------|:---------|:------------------------------------------------------------| :--------------------------- | :-- |
|
||||||
|
| *count* | string | Array of (metric_name, gauge name) pairs counted | Must come in pairs | |
|
||||||
|
| *decrement* | string | Array of metrics to be decremented | | |
|
||||||
|
| *flush_size* | integer | Maximum number of messages before flushing | | 50000 |
|
||||||
|
| *gauge* | string | Array of (metric_name, gauge name) pairs gauged | Must come in pairs | |
|
||||||
|
| *host* | string | Hostname or IP of StatsD server | localhost | |
|
||||||
|
| *idle_flush_time* | integer | Maximum number of seconds elapsed before triggering a flush | | 10 |
|
||||||
|
| *increment* | string | Array of metrics to be incremented | | |
|
||||||
|
| *interval* | integer | Interval in milliseconds to sleep between sends | Interval | 5000 |
|
||||||
|
| *max_queue_size* | integer | Maximum StatsD queue depth | | 50000 |
|
||||||
|
| *namespace* | string | Namespace for stats | timberwinr | |
|
||||||
|
| *port* | integer | StatsD port number | This port must be open | 8125 |
|
||||||
|
| *queue_overflow_discard_oldest* | bool | If true, discard oldest messages when max_queue_size reached otherwise discard newest | | true |
|
||||||
|
| *sample_rate* | integer | StatsD sample rate | | 1 |
|
||||||
|
| *sender* | string | Sender name | FQDN | |
|
||||||
|
| *threads* | string | Number of Threads processing messages | | 1 |
|
||||||
|
| *timing* | string | Array of (metric_name, timing_name) pairs timed | Must come in pairs | |
|
||||||
|
| *type* | string |Type to which this filter applies, if empty, applies to all types.
|
||||||
|
|
||||||
|
### Example Usage
|
||||||
|
Example Input: Tail an apache log file, and record counts for bytes and increments for response codes.
|
||||||
|
|
||||||
|
sample-apache.log (snip)
|
||||||
|
```
|
||||||
|
180.76.5.25 - - [13/May/2015:17:02:26 -0700] "GET /frameset.htm HTTP/1.1" 404 89 "-" "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)" "www.redlug.com"
|
||||||
|
208.115.113.94 - - [13/May/2015:17:03:55 -0700] "GET /robots.txt HTTP/1.1" 200 37 "-" "Mozilla/5.0 (compatible; DotBot/1.1; http://www.opensiteexplorer.org/dotbot, help@moz.com)" "redlug.com"
|
||||||
|
208.115.113.94 - - [13/May/2015:17:03:55 -0700] "GET /robots.txt HTTP/1.1" 200 37 "-" "Mozilla/5.0 (compatible; DotBot/1.1; http://www.opensiteexplorer.org/dotbot, help@moz.com)" "www.redlug.com"
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: [COMBINEDAPACHELOG](https://github.com/elastic/logstash/blob/v1.4.2/patterns/grok-patterns) is a standard
|
||||||
|
Grok Pattern.
|
||||||
|
|
||||||
|
TimberWinR configuration
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"TimberWinR": {
|
||||||
|
"Inputs": {
|
||||||
|
"TailFiles": [
|
||||||
|
{
|
||||||
|
"interval": 5,
|
||||||
|
"logSource": "apache log files",
|
||||||
|
"location": "..\\sample-apache.log",
|
||||||
|
"recurse": -1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Filters": [
|
||||||
|
{
|
||||||
|
"grok": {
|
||||||
|
"type": "Win32-TailLog",
|
||||||
|
"match": [
|
||||||
|
"Text",
|
||||||
|
"%{COMBINEDAPACHELOG}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Outputs": {
|
||||||
|
"StatsD": [
|
||||||
|
{
|
||||||
|
"type": "Win32-TailLog",
|
||||||
|
"port": 8125,
|
||||||
|
"host": "stats.mycompany.svc",
|
||||||
|
"increment": ["apache.response.%{response}"],
|
||||||
|
"count": ["apache.bytes", "%{bytes}"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Assuming your FQDN is something like mymachine.mycompany.com, you should see the following in Graphite:
|
||||||
|
|
||||||
|
```
|
||||||
|
stats.counters.timberwinr.mymachine.mycompany.com.apache.bytes.count
|
||||||
|
stats.counters.timberwinr.mymachine.mycompany.com.apache.bytes.rate
|
||||||
|
stats.counters.timberwinr.mymachine.mycompany.com.apache.response.200.count
|
||||||
|
stats.counters.timberwinr.mymachine.mycompany.com.apache.response.200.rate
|
||||||
|
stats.counters.timberwinr.mymachine.mycompany.com.apache.response.404.count
|
||||||
|
stats.counters.timberwinr.mymachine.mycompany.com.apache.response.404.rate
|
||||||
|
...
|
||||||
|
...
|
||||||
|
```
|
||||||
@@ -8,6 +8,7 @@ The following parameters are allowed when configuring WindowsEvents.
|
|||||||
|
|
||||||
| Parameter | Type | Description | Details | Default |
|
| Parameter | Type | Description | Details | Default |
|
||||||
| :---------------- |:---------------| :----------------------------------------------------------------------- | :--------------------------- | :-- |
|
| :---------------- |:---------------| :----------------------------------------------------------------------- | :--------------------------- | :-- |
|
||||||
|
| *type* | string |Typename for this Input | | Win32-TailLog |
|
||||||
| *location* | string |Location of file(s) to monitor | Path to text file(s) including wildcards. | |
|
| *location* | string |Location of file(s) to monitor | Path to text file(s) including wildcards. | |
|
||||||
| *logSource* | string |Source name | Used for conditions | |
|
| *logSource* | string |Source name | Used for conditions | |
|
||||||
| *recurse* | integer |Max subdirectory recursion level. | 0 disables subdirectory recursion; -1 enables unlimited recursion. | 0 |
|
| *recurse* | integer |Max subdirectory recursion level. | 0 disables subdirectory recursion; -1 enables unlimited recursion. | 0 |
|
||||||
@@ -39,3 +40,4 @@ After a successful parse of an event, the following fields are added:
|
|||||||
| LogFilename | STRING |Full path of the file containing this line |
|
| LogFilename | STRING |Full path of the file containing this line |
|
||||||
| Index | INTEGER | Line number |
|
| Index | INTEGER | Line number |
|
||||||
| Text | STRING | Text line content |
|
| Text | STRING | Text line content |
|
||||||
|
| type | STRING | Win32-TailLog |
|
||||||
|
|||||||
@@ -5,9 +5,12 @@ The Tcp input will open a port and listen for properly formatted JSON and will f
|
|||||||
## Parameters
|
## Parameters
|
||||||
The following parameters are allowed when configuring the Tcp input.
|
The following parameters are allowed when configuring the Tcp input.
|
||||||
|
|
||||||
| Parameter | Type | Description | Details | Default |
|
| Parameter | Type | Description | Details | Default |
|
||||||
| :---------------- |:---------------| :----------------------------------------------------------------------- | :--------------------------- | :-- |
|
| :---------------- |:-----------------| :----------------------------------------------------------------------- | :--------------------------- | :-- |
|
||||||
| *port* | integer |Port number to open | Must be an available port | |
|
| *add_field* | property:array |Add field(s) to this event. Field names can be dynamic and include parts of the event using the %{field} syntax. This property must be specified in pairs. | |
|
||||||
|
| *port* | integer |Port number to open | Must be an available port | |
|
||||||
|
| *rename* | property:array |Rename one or more fields | | |
|
||||||
|
| *type* | string |Typename for this Input | | Win32-Tcp |
|
||||||
|
|
||||||
Example Input: Listen on Port 5140
|
Example Input: Listen on Port 5140
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,10 @@ The following parameters are allowed when configuring the Udp input.
|
|||||||
|
|
||||||
| Parameter | Type | Description | Details | Default |
|
| Parameter | Type | Description | Details | Default |
|
||||||
| :---------------- |:---------------| :----------------------------------------------------------------------- | :--------------------------- | :-- |
|
| :---------------- |:---------------| :----------------------------------------------------------------------- | :--------------------------- | :-- |
|
||||||
| *port* | integer |Port number to open | Must be an available port | |
|
| *add_field* | property:array |Add field(s) to this event. Field names can be dynamic and include parts of the event using the %{field} syntax. This property must be specified in pairs. | |
|
||||||
|
| *port* | integer |Port number to open | Must be an available port | |
|
||||||
|
| *rename* | property:array |Rename one or more fields | | |
|
||||||
|
| *type* | string |Typename for this Input | | Win32-Udp |
|
||||||
|
|
||||||
Example Input: Listen on Port 5142
|
Example Input: Listen on Port 5142
|
||||||
|
|
||||||
|
|||||||
@@ -65,3 +65,5 @@ After a successful parse of an event, the following fields are added:
|
|||||||
| Message | STRING | The full event message |
|
| Message | STRING | The full event message |
|
||||||
| Data | STRING | The binary data associated with the event |
|
| Data | STRING | The binary data associated with the event |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,9 @@
|
|||||||
<package id="NEST" version="1.3.1" targetFramework="net40" />
|
<package id="NEST" version="1.3.1" targetFramework="net40" />
|
||||||
<package id="Newtonsoft.Json" version="6.0.5" targetFramework="net40" />
|
<package id="Newtonsoft.Json" version="6.0.5" targetFramework="net40" />
|
||||||
<package id="NLog" version="3.2.0.0" targetFramework="net40" />
|
<package id="NLog" version="3.2.0.0" targetFramework="net40" />
|
||||||
<package id="RapidRegex.Core" version="1.0.0.2" targetFramework="net40" />
|
<package id="RapidRegex.Core" version="1.0.0.4" targetFramework="net40" />
|
||||||
<package id="RestSharp" version="105.0.0" targetFramework="net40" />
|
<package id="RestSharp" version="105.0.0" targetFramework="net40" />
|
||||||
|
<package id="StatsdClient" version="1.0.0.19" targetFramework="net40" />
|
||||||
<package id="System.Linq.Dynamic" version="1.0.4" targetFramework="net40" />
|
<package id="System.Linq.Dynamic" version="1.0.4" targetFramework="net40" />
|
||||||
<package id="Topshelf" version="3.1.4" targetFramework="net40" />
|
<package id="Topshelf" version="3.1.4" targetFramework="net40" />
|
||||||
</packages>
|
</packages>
|
||||||
@@ -49,9 +49,13 @@
|
|||||||
<File Id="TimberWinR.ServiceHost.exe.config" Source="$(var.TimberWinR.ServiceHost.TargetDir)\TimberWinR.ServiceHost.exe.config" />
|
<File Id="TimberWinR.ServiceHost.exe.config" Source="$(var.TimberWinR.ServiceHost.TargetDir)\TimberWinR.ServiceHost.exe.config" />
|
||||||
<File Id="Interop.MSUtil.dll" Source="$(var.TimberWinR.ServiceHost.TargetDir)\Interop.MSUtil.dll" />
|
<File Id="Interop.MSUtil.dll" Source="$(var.TimberWinR.ServiceHost.TargetDir)\Interop.MSUtil.dll" />
|
||||||
<File Id="csredis.dll" Source="$(var.TimberWinR.ServiceHost.TargetDir)\csredis.dll" />
|
<File Id="csredis.dll" Source="$(var.TimberWinR.ServiceHost.TargetDir)\csredis.dll" />
|
||||||
|
<File Id="Nest.dll" Source="$(var.TimberWinR.ServiceHost.TargetDir)\Nest.dll" />
|
||||||
|
<File Id="Elasticsearch.Net.dll" Source="$(var.TimberWinR.ServiceHost.TargetDir)\Elasticsearch.Net.dll" />
|
||||||
<File Id="default.json" Source="$(var.TimberWinR.ServiceHost.TargetDir)\default.json" />
|
<File Id="default.json" Source="$(var.TimberWinR.ServiceHost.TargetDir)\default.json" />
|
||||||
<File Id="Newtonsoft.Json.dll" Source="$(var.TimberWinR.ServiceHost.TargetDir)\Newtonsoft.Json.dll" />
|
<File Id="Newtonsoft.Json.dll" Source="$(var.TimberWinR.ServiceHost.TargetDir)\Newtonsoft.Json.dll" />
|
||||||
<File Id="Nlog.dll" Source="$(var.TimberWinR.ServiceHost.TargetDir)\Nlog.dll" />
|
<File Id="Nlog.dll" Source="$(var.TimberWinR.ServiceHost.TargetDir)\Nlog.dll" />
|
||||||
|
<File Id="StatsdClient.dll" Source="$(var.TimberWinR.ServiceHost.TargetDir)\StatsdClient.dll" />
|
||||||
|
<File Id="StatsdClient.Configuration.dll" Source="$(var.TimberWinR.ServiceHost.TargetDir)\StatsdClient.Configuration.dll" />
|
||||||
<File Id="RestSharp.dll" Source="$(var.TimberWinR.ServiceHost.TargetDir)\RestSharp.dll" />
|
<File Id="RestSharp.dll" Source="$(var.TimberWinR.ServiceHost.TargetDir)\RestSharp.dll" />
|
||||||
<File Id="RapidRegex.Core.dll" Source="$(var.TimberWinR.ServiceHost.TargetDir)\RapidRegex.Core.dll" />
|
<File Id="RapidRegex.Core.dll" Source="$(var.TimberWinR.ServiceHost.TargetDir)\RapidRegex.Core.dll" />
|
||||||
<File Id="TimberWinR.dll" Source="$(var.TimberWinR.ServiceHost.TargetDir)\TimberWinR.dll" />
|
<File Id="TimberWinR.dll" Source="$(var.TimberWinR.ServiceHost.TargetDir)\TimberWinR.dll" />
|
||||||
|
|||||||
@@ -98,10 +98,12 @@
|
|||||||
</CreateProperty>
|
</CreateProperty>
|
||||||
</Target>
|
</Target>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PostBuildEvent>$(SolutionDir)\TimberWinR.ExtractID\$(OutDir)\TimberWinR.ExtractID.exe $(TargetDir) $(SolutionDir)chocolateyUninstall.ps1.guid $(SolutionDir)chocolateyUninstall.ps1.template</PostBuildEvent>
|
<PreBuildEvent>mkdir $(SolutionDir)tools
|
||||||
|
cmd.exe /c copy $(SolutionDir)chocolateyUninstall.ps1.template.orig $(SolutionDir)chocolateyUninstall.ps1.template</PreBuildEvent>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PreBuildEvent>cmd.exe /c copy $(SolutionDir)chocolateyUninstall.ps1.template.orig $(SolutionDir)chocolateyUninstall.ps1.template</PreBuildEvent>
|
<PostBuildEvent>$(SolutionDir)\TimberWinR.ExtractID\$(OutDir)\TimberWinR.ExtractID.exe $(TargetDir) $(SolutionDir)chocolateyUninstall.ps1.guid $(SolutionDir)chocolateyUninstall.ps1.template
|
||||||
|
cmd.exe /c copy "$(TargetDir)%2a.msi" "$(SolutionDir)tools"</PostBuildEvent>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<!--
|
<!--
|
||||||
To modify your build process, add your task inside one of the targets below and uncomment it.
|
To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
|||||||
56
appveyor.yml
56
appveyor.yml
@@ -1,14 +1,50 @@
|
|||||||
version: 1.2.{build}
|
version: build_number_{build}
|
||||||
|
configuration: Release
|
||||||
build:
|
skip_tags: true
|
||||||
verbosity: minimal
|
init:
|
||||||
|
- ps: "$v = [regex]::match($env:APPVEYOR_REPO_BRANCH,'rel-(.*)').Groups[1].Value\nWrite-Host \"On branch $($env:APPVEYOR_REPO_BRANCH)\"\nIF($v) { \n $env:VERSION_FROM_BRANCH = \"$($v).$($env:APPVEYOR_BUILD_NUMBER)\"\n} else {\n $env:VERSION_FROM_BRANCH = \"0.0.0.$($env:APPVEYOR_BUILD_NUMBER)\"\n}\nWrite-Host \"Set version to $($env:VERSION_FROM_BRANCH)\""
|
||||||
assembly_info:
|
assembly_info:
|
||||||
patch: true
|
patch: true
|
||||||
file: AssemblyInfo.*
|
file: '**\AssemblyInfo.*'
|
||||||
assembly_version: "1.2.{build}"
|
assembly_version: $(VERSION_FROM_BRANCH)
|
||||||
assembly_file_version: "{version}"
|
assembly_file_version: $(VERSION_FROM_BRANCH)
|
||||||
assembly_informational_version: "{version}"
|
assembly_informational_version: $(VERSION_FROM_BRANCH)
|
||||||
|
before_build:
|
||||||
|
- ps: >-
|
||||||
|
mkdir tools
|
||||||
|
|
||||||
|
NuGet.exe restore TimberWinR.sln
|
||||||
|
build:
|
||||||
|
verbosity: normal
|
||||||
|
after_build:
|
||||||
|
- ps: >-
|
||||||
|
cat chocolateyInstall.ps1.template|%{$_-replace "\$\{version\}",$env:VERSION_FROM_BRANCH} > tools\chocolateyInstall.ps1
|
||||||
|
|
||||||
|
cat chocolateyUninstall.ps1.template|%{$_-replace "\$\{version\}",$env:VERSION_FROM_BRANCH} > tools\chocolateyUninstall.ps1
|
||||||
|
|
||||||
|
cat tools\chocolateyUninstall.ps1
|
||||||
|
|
||||||
|
cat timberwinr.nuspec.template|%{$_-replace "\$\{version\}",$env:VERSION_FROM_BRANCH} > timberwinr.nuspec
|
||||||
|
|
||||||
|
choco pack timberwinr.nuspec
|
||||||
artifacts:
|
artifacts:
|
||||||
- path: '**\*.msi'
|
- path: .\*.nupkg
|
||||||
|
name: NuGet
|
||||||
|
- path: TimberWinR.ServiceHost\bin\*\*.dll
|
||||||
|
name: Dlls
|
||||||
|
- path: TimberWinR.ServiceHost\bin\*\*.exe
|
||||||
|
name: Exes
|
||||||
|
- path: TimberWix\bin\*\*.msi
|
||||||
|
name: MSI
|
||||||
|
deploy:
|
||||||
|
- provider: NuGet
|
||||||
|
server: https://chocolatey.org/
|
||||||
|
skip_symbols: true
|
||||||
|
artifact: NuGet
|
||||||
|
on:
|
||||||
|
branch: /release/.*/
|
||||||
|
- provider: GitHub
|
||||||
|
release: $(VERSION_FROM_BRANCH)
|
||||||
|
artifact: Dlls, Exes, MSI
|
||||||
|
on:
|
||||||
|
branch: /release/.*/
|
||||||
@@ -1,8 +1,14 @@
|
|||||||
$packageName = 'TimberWinR-${version}'
|
$packageName = 'TimberWinR-${version}'
|
||||||
$installerType = 'msi'
|
$fileType = 'msi'
|
||||||
$url = 'http://www.ericfontana.com/TimberWinR/TimberWinR-${version}.0.msi'
|
|
||||||
$silentArgs = '/quiet'
|
$silentArgs = '/quiet'
|
||||||
$validExitCodes = @(0)
|
$scriptPath = $(Split-Path $MyInvocation.MyCommand.Path)
|
||||||
Install-ChocolateyPackage "$packageName" "$installerType" "$silentArgs" "$url" "$url64" -validExitCodes $validExitCodes
|
$fileFullPath = Join-Path $scriptPath 'TimberWinR-${version}.0.msi'
|
||||||
|
try {
|
||||||
|
Install-ChocolateyInstallPackage $packageName $fileType $silentArgs $fileFullPath
|
||||||
|
} catch {
|
||||||
|
Write-ChocolateyFailure $packageName $($_.Exception.Message)
|
||||||
|
throw
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
$packageName = 'TimberWinR-${version}' # arbitrary name for the package, used in messages
|
$packageName = 'TimberWinR-${version}' # arbitrary name for the package, used in messages
|
||||||
$installerType = 'msi' #only one of these: exe, msi, msu
|
$installerType = 'msi' #only one of these: exe, msi, msu
|
||||||
$url = 'http://www.ericfontana.com/TimberWinR/TimberWinR-${version}.0.msi' # download url
|
$scriptPath = $(Split-Path $MyInvocation.MyCommand.Path)
|
||||||
|
$fileFullPath = Join-Path $scriptPath 'TimberWinR-${version}.0.msi'
|
||||||
$silentArgs = '${PROJECTGUID} /quiet'
|
$silentArgs = '${PROJECTGUID} /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
|
$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" "$url" -validExitCodes $validExitCodes
|
UnInstall-ChocolateyPackage "$packageName" "$installerType" "$silentArgs" "fileFullPath" -validExitCodes $validExitCodes
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
$packageName = 'TimberWinR-${version}' # arbitrary name for the package, used in messages
|
$packageName = 'TimberWinR-${version}' # arbitrary name for the package, used in messages
|
||||||
$installerType = 'msi' #only one of these: exe, msi, msu
|
$installerType = 'msi' #only one of these: exe, msi, msu
|
||||||
$url = 'http://www.ericfontana.com/TimberWinR/TimberWinR-${version}.0.msi' # download url
|
$scriptPath = $(Split-Path $MyInvocation.MyCommand.Path)
|
||||||
$silentArgs = '{D066A694-B9F7-4B35-BB7D-D34CB88CA89F} /quiet'
|
$fileFullPath = Join-Path $scriptPath 'TimberWinR-${version}.0.msi'
|
||||||
|
$silentArgs = '{E001D138-669B-4604-88C5-02C756461C15} /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
|
$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" "$url" -validExitCodes $validExitCodes
|
UnInstall-ChocolateyPackage "$packageName" "$installerType" "$silentArgs" "fileFullPath" -validExitCodes $validExitCodes
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
$packageName = 'TimberWinR-${version}' # arbitrary name for the package, used in messages
|
$packageName = 'TimberWinR-${version}' # arbitrary name for the package, used in messages
|
||||||
$installerType = 'msi' #only one of these: exe, msi, msu
|
$installerType = 'msi' #only one of these: exe, msi, msu
|
||||||
$url = 'http://www.ericfontana.com/TimberWinR/TimberWinR-${version}.0.msi' # download url
|
$scriptPath = $(Split-Path $MyInvocation.MyCommand.Path)
|
||||||
|
$fileFullPath = Join-Path $scriptPath 'TimberWinR-${version}.0.msi'
|
||||||
$silentArgs = '${PROJECTGUID} /quiet'
|
$silentArgs = '${PROJECTGUID} /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
|
$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" "$url" -validExitCodes $validExitCodes
|
UnInstall-ChocolateyPackage "$packageName" "$installerType" "$silentArgs" "fileFullPath" -validExitCodes $validExitCodes
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user