diff --git a/Influxer.Test/Influxer.Test.csproj b/Influxer.Test/Influxer.Test.csproj index 35724fb..83569c4 100644 --- a/Influxer.Test/Influxer.Test.csproj +++ b/Influxer.Test/Influxer.Test.csproj @@ -35,8 +35,12 @@ 4 - - ..\packages\AdysTech.InfluxDB.Client.Net.0.5.3\lib\net451\AdysTech.InfluxDB.Client.Net.dll + + ..\packages\AdysTech.InfluxDB.Client.Net.0.5.9.1\lib\net451\AdysTech.InfluxDB.Client.Net.dll + True + + + ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll True @@ -65,9 +69,7 @@ - - Always - + @@ -75,6 +77,9 @@ + + + diff --git a/Influxer.Test/InfluxerTest.orderedtest b/Influxer.Test/InfluxerTest.orderedtest deleted file mode 100644 index 497e52f..0000000 --- a/Influxer.Test/InfluxerTest.orderedtest +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/Influxer.Test/InfluxerTests.cs b/Influxer.Test/InfluxerTests.cs index 52feb0e..2fd52c3 100644 --- a/Influxer.Test/InfluxerTests.cs +++ b/Influxer.Test/InfluxerTests.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using AdysTech.Influxer; using System.IO; +using System.Diagnostics; namespace Influxer.Test { @@ -39,14 +40,29 @@ public string TestFilesPath } + private static async Task GetClientAsync (InfluxerConfigSection settings) + { + var client = new InfluxDBClient (settings.InfluxDB.InfluxUri, settings.InfluxDB.UserName, settings.InfluxDB.Password); + var dbNames = await client.GetInfluxDBNamesAsync (); + if (dbNames.Contains (settings.InfluxDB.DatabaseName)) + return client; + else + { + await client.CreateDatabaseAsync (settings.InfluxDB.DatabaseName); + return client; + } + } + [TestMethod] public async Task TestGenericHeaderless () { var settings = InfluxerConfigSection.Load (Path.Combine (TestFilesPath, "HeaderlessText.conf")); settings.InputFileName = Path.Combine (TestFilesPath, "HeaderlessText.txt"); var client = await GetClientAsync (settings); - var result = await new GenericFile ().ProcessGenericFile (settings.InputFileName, client); - Assert.IsTrue (result.ExitCode == ExitCode.Success || result.ExitCode == ExitCode.ProcessedWithErrors, "Processing a generic text file failed"); + var file = new GenericFile (); + var result = await file.ProcessGenericFile (settings.InputFileName, client); + //Debug.WriteLine (result.ToString ()); + Assert.IsTrue (result.ExitCode == ExitCode.ProcessedWithErrors && result.PointsFound == 1001 && result.PointsFailed == 29, "Processing a generic text file failed"); } [TestMethod] @@ -57,7 +73,8 @@ public async Task TestPerfmonFile () settings.InputFileName = Path.Combine (TestFilesPath, "Perfmon.csv"); var client = await GetClientAsync (settings); var result = await new PerfmonFile ().ProcessPerfMonLog (settings.InputFileName, client); - Assert.IsTrue (result.ExitCode == ExitCode.Success || result.ExitCode == ExitCode.ProcessedWithErrors, "Processing Perfmon file failed"); + //Debug.WriteLine (result.ToString ()); + Assert.IsTrue (result.ExitCode == ExitCode.ProcessedWithErrors && result.PointsFound == 144818 && result.PointsFailed == 0, "Processing Perfmon file failed"); } [TestMethod] @@ -71,7 +88,8 @@ public async Task TestPerfmonFileMultiMeasurement () settings.InputFileName = Path.Combine (TestFilesPath, "Perfmon.csv"); var client = await GetClientAsync (settings); var result = await new PerfmonFile ().ProcessPerfMonLog (settings.InputFileName, client); - Assert.IsTrue (result.ExitCode == ExitCode.Success || result.ExitCode == ExitCode.ProcessedWithErrors, "Processing Perfmon file failed"); + //Debug.WriteLine (result.ToString ()); + Assert.IsTrue (result.ExitCode == ExitCode.ProcessedWithErrors && result.PointsFound == 5347 && result.PointsFailed == 0, "Processing Perfmon file failed"); } [TestMethod] @@ -83,8 +101,10 @@ public async Task TestGenericSimple () settings.InfluxDB.RetentionPolicy = "autogen"; settings.GenericFile.TimeFormat = "yyyy-MM-dd m:ss"; var client = await GetClientAsync (settings); - var result = await new GenericFile ().ProcessGenericFile (settings.InputFileName, client); - Assert.IsTrue (result.ExitCode == ExitCode.Success || result.ExitCode == ExitCode.ProcessedWithErrors, "Processing a generic CSV file failed"); + var file = new GenericFile (); + var result = await file.ProcessGenericFile (settings.InputFileName, client); + //Debug.WriteLine (result.ToString ()); + Assert.IsTrue (result.ExitCode == ExitCode.ProcessedWithErrors && result.PointsFound == 4897 && result.PointsFailed == 1, "Processing a generic CSV file failed"); } [TestMethod] @@ -97,21 +117,25 @@ public async Task TestGenericSimple2 () settings.InfluxDB.RetentionPolicy = "autogen"; var client = await GetClientAsync (settings); var result = await new GenericFile ().ProcessGenericFile (settings.InputFileName, client); - Assert.IsTrue (result.ExitCode == ExitCode.Success || result.ExitCode == ExitCode.ProcessedWithErrors, "Processing a generic CSV file failed"); + //Debug.WriteLine (result.ToString ()); + Assert.IsTrue (result.ExitCode == ExitCode.Success && result.PointsFound == 226 && result.PointsFailed == 0, "Processing a generic CSV file failed"); } - - private static async Task GetClientAsync (InfluxerConfigSection settings) + [TestMethod] + public async Task TestGenericMicroSecPrecision () { - var client = new InfluxDBClient (settings.InfluxDB.InfluxUri, settings.InfluxDB.UserName, settings.InfluxDB.Password); - var dbNames = await client.GetInfluxDBNamesAsync (); - if (dbNames.Contains (settings.InfluxDB.DatabaseName)) - return client; - else - { - await client.CreateDatabaseAsync (settings.InfluxDB.DatabaseName); - return client; - } + var args = new string[] { "-input", Path.Combine (TestFilesPath, "MicroSecSemicolonSeperated.txt"), + "-format", "Generic", + "-TimeFormat", "yyyy-MM-dd-hh.mm.ss.ffffff", + "-Precision", "Microseconds", + "-splitter", ";" }; + InfluxerConfigSection settings; + CommandLineProcessor.ProcessArguments (args); + settings = CommandLineProcessor.Settings; + var client = await GetClientAsync (settings); + var result = await new GenericFile ().ProcessGenericFile (settings.InputFileName, client); + //Debug.WriteLine (result.ToString ()); + Assert.IsTrue (result.ExitCode == ExitCode.Success && result.PointsFound == 4 && result.PointsFailed == 0, "Processing a generic MicroSecSemicolonSeperated file failed"); } } } diff --git a/Influxer.Test/TestFiles/MicroSecSemicolonSeperated.txt b/Influxer.Test/TestFiles/MicroSecSemicolonSeperated.txt new file mode 100644 index 0000000..d6e29d1 --- /dev/null +++ b/Influxer.Test/TestFiles/MicroSecSemicolonSeperated.txt @@ -0,0 +1,5 @@ +SNAPSHOT_TIMESTAMP ; NUM_EXECUTIONS ;AVERAGE_EXECUTION_TIME_S;STMT_SORTS ;SORTS_PER_EXECUTION ;STMT_TEXT ;DBPARTITIONNUM +2016-09-21-10.49.33.803886; 2; 0; 4; 2;SOURCETYPE IN ('DECIMAL','INTEGER','SMALLINT','BIGINT') ; 0 +2016-09-21-10.49.33.803886; 1; 0; 0; 0;GRANT SELECT ON DBCFG TO ROLE ISODBScanRole ; 0 +2016-09-21-10.49.33.803886; 1; 0; 0; 0;SELECT COLCOUNT FROM INDEXES; 0 +2016-09-21-10.49.33.803886; 2; 0; 2; 1;SELECT * FROM SQLSTATISTICS ; 0 \ No newline at end of file diff --git a/Influxer.Test/TestSetup.ps1 b/Influxer.Test/TestSetup.ps1 new file mode 100644 index 0000000..a80299c --- /dev/null +++ b/Influxer.Test/TestSetup.ps1 @@ -0,0 +1,35 @@ +################################################################################################## +#This script downloads the latest nightly InfluxDB build, starts the db engine, and creates basic +#data structures so that 'show databases' query will not fail during tests if the query gets +#executed before CreateDatabase test +# +################################################################################################## + + $source = "https://dl.influxdata.com/influxdb/nightlies/influxdb-nightly_windows_amd64.zip" + $destination = "$env:Temp\influxdb-nightly_windows_amd64.zip" + $influx = "$env:Temp\influxdb" + $influxdata = "$env:UserProfile\.influxdb" + + if(!(test-path $destination) -or ((Get-ItemProperty -Path $destination -Name LastWriteTime).lastwritetime -lt $(get-date).AddDays(-1))) + { Invoke-WebRequest $source -OutFile $destination } + + if(test-path $influx) + { rmdir -recurse $influx} + + Add-Type -As System.IO.Compression.FileSystem + [System.IO.Compression.ZipFile]::ExtractToDirectory($destination,$influx) + $influxd = Get-ChildItem $influx -File -filter "influxd.exe" -Recurse | % { $_.FullName } + + #$x = 7z e $destination -o"$env:Temp\influxdb" -y + if(test-path $influxdata) + { rmdir -recurse "$env:UserProfile\.influxdb" } + + Start-Process -FilePath $influxd + #let the engine start + Start-Sleep -s 10 + + $r = Invoke-WebRequest -Method Post -Uri http://localhost:8086/query -Body "q=CREATE DATABASE prereq" + if($r.StatusCode -ne 200) + { + throw "Unable to create DB" + } \ No newline at end of file diff --git a/Influxer.Test/packages.config b/Influxer.Test/packages.config index 6e40c85..ec4c9ec 100644 --- a/Influxer.Test/packages.config +++ b/Influxer.Test/packages.config @@ -1,4 +1,5 @@  - + + \ No newline at end of file diff --git a/Influxer/Config/CommandLineProcessor.cs b/Influxer/Config/CommandLineProcessor.cs new file mode 100644 index 0000000..284cd1e --- /dev/null +++ b/Influxer/Config/CommandLineProcessor.cs @@ -0,0 +1,131 @@ +using AdysTech.Influxer.Logging; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace AdysTech.Influxer.Config +{ + public static class CommandLineProcessor + { + private static InfluxerConfigSection _settings; + public static InfluxerConfigSection Settings + { + get + { + return _settings; + } + } + + public static bool ProcessArguments (string[] args) + { + if (args.Length == 0) + { + throw new ArgumentException ("Command line arguments not valid, try --help to see valid ones!"); + } + #region Parse command line arguments + Dictionary cmdArgs = new Dictionary (); + Regex commandSwitch = new Regex ("^-[a-zA-Z+]|^/[a-zA-Z+]", RegexOptions.Compiled); + for (int i = 0; i < args.Length; i++) + { + if (commandSwitch.IsMatch (args[i])) + { + var key = args[i].ToLower (); + if (i + 1 < args.Length && !commandSwitch.IsMatch (args[i + 1])) + { + cmdArgs.Add (key.ToLower (), args[i + 1]); + i++; + } + else + cmdArgs.Add (key.ToLower (), "true"); + } + } + + var totalArguments = cmdArgs.Count; + + if (cmdArgs.ContainsKey ("--help") || cmdArgs.ContainsKey ("/help") || cmdArgs.ContainsKey ("/?")) + { + var help = new StringBuilder (); + help.AppendLine ("Influxer is an application to parse log files, push data to Influx for later visualization."); + help.AppendLine ("It currently supports Windows Perfmon and any generic delimited file formats"); + help.AppendLine ("It uses InfluxDB.Client.Net to interact with Influx."); + help.AppendLine (new String ('-', 180)); + help.AppendLine ("Supported command line arguments"); + help.AppendLine ("--help /? or /help shows this help text\n"); + help.AppendLine (); + help.AppendLine ("/export to print possible config section, pipe it to a file to edit and reuse the config"); + help.AppendLine (); + help.AppendLine ("-config to load the config file."); + help.AppendLine (); + help.AppendLine ("Any configuration entries can be overridden by command line switches shown below\n"); + help.AppendLine (new String ('-', 180)); + help.Append (InfluxerConfigSection.LoadDefault ().PrintHelpText ()); + Logger.Log (LogLevel.Info, help.ToString ()); + return false; + } + + if (cmdArgs.ContainsKey ("-config")) + { + try + { + var configFile = Path.GetFullPath (cmdArgs["-config"]); + _settings = InfluxerConfigSection.Load (configFile); + cmdArgs.Remove ("-config"); + totalArguments -= 1; + } + catch (Exception e) + { + throw new FileLoadException ($"Error Loading config file:{e.GetType ().Name},{e.Message}", e); + } + } + else + { + _settings = InfluxerConfigSection.LoadDefault (); + } + #endregion + + if (totalArguments >= 1) + { + if (!(cmdArgs.Count == 1 && cmdArgs.ContainsKey ("/export"))) + { + try + { + if (!_settings.ProcessCommandLineArguments (cmdArgs)) + { + throw new ArgumentException ("Invalid commandline arguments!! Use /help to see valid ones"); + } + } + catch (Exception e) + { + throw new ArgumentException ($"Error processing arguments :{e.GetType ().Name}, {e.Message}", e); + } + } + } + + if (cmdArgs.ContainsKey ("/export")) + { + if (cmdArgs.ContainsKey ("/autolayout")) + { + if (string.IsNullOrWhiteSpace (_settings.InputFileName)) + throw new ArgumentException ("No Input file name mentioned!!"); + + var g = new GenericFile (); + g.GetFileLayout (_settings.InputFileName); + g.ValidateData (_settings.InputFileName); + } + InfluxerConfigSection.Export (Console.OpenStandardOutput (), totalArguments > 1 ? false : true); + return false; + } + + + if (cmdArgs.Count > 0) + { + throw new ArgumentException ($"Unknown command line arguments: {String.Join (", ", cmdArgs.Select (c => c.Key))}"); + } + return true; + } + } +} diff --git a/Influxer/GenericFile.cs b/Influxer/GenericFile.cs index 6ac8e83..c0456fa 100644 --- a/Influxer/GenericFile.cs +++ b/Influxer/GenericFile.cs @@ -51,7 +51,7 @@ public async Task ProcessGenericFile (string InputFileName, Influ if (r.ExitCode != ExitCode.Success) return r; - InfluxDatabase dbStructure; + IInfluxDatabase dbStructure; if (settings.GenericFile.Filter != Filters.None) { var filterColumns = new List (); @@ -64,7 +64,7 @@ public async Task ProcessGenericFile (string InputFileName, Influ } dbStructure = await client.GetInfluxDBStructureAsync (settings.InfluxDB.DatabaseName); - ColumnHeaders = FilterGenericColumns (ColumnHeaders, filterColumns, dbStructure); + ColumnHeaders = FilterGenericColumns (ColumnHeaders, filterColumns, dbStructure as InfluxDatabase); } @@ -73,7 +73,7 @@ public async Task ProcessGenericFile (string InputFileName, Influ var failureReasons = new Dictionary (); List points = new List (), retryQueue = new List (); - InfluxRetentionPolicy policy = null; + IInfluxRetentionPolicy policy = null; if (settings.InfluxDB.RetentionDuration != 0 || !String.IsNullOrWhiteSpace (settings.InfluxDB.RetentionPolicy)) { diff --git a/Influxer/Influxer.csproj b/Influxer/Influxer.csproj index e94a74d..7c9fb0a 100644 --- a/Influxer/Influxer.csproj +++ b/Influxer/Influxer.csproj @@ -49,8 +49,12 @@ - - ..\packages\AdysTech.InfluxDB.Client.Net.0.5.3\lib\net451\AdysTech.InfluxDB.Client.Net.dll + + ..\packages\AdysTech.InfluxDB.Client.Net.0.5.9.1\lib\net451\AdysTech.InfluxDB.Client.Net.dll + True + + + ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll True @@ -64,24 +68,25 @@ + - - - - + + + + - + - - + + - - + + @@ -114,6 +119,7 @@ +