feat: add logging to file & -v (verbosity option)

This commit is contained in:
cuqmbr 2022-08-18 20:24:01 +03:00
parent 2748647eb3
commit 0c410e6451
6 changed files with 189 additions and 62 deletions

View File

@ -1,4 +1,5 @@
using Microsoft.EntityFrameworkCore;
using netxml2kml.Methods;
using netxml2kml.Models;
namespace netxml2kml.Data;
@ -13,8 +14,7 @@ public sealed class DatabaseContext : DbContext
public DatabaseContext(string dbName = "netxml2kml.sqlite3.db")
{
var folder = Environment.SpecialFolder.LocalApplicationData;
var path = Path.Join(Environment.GetFolderPath(folder), "netxml2kml");
var path = Path.Join(RuntimeStorage.AppFolder, "netxml2kml");
if (!Directory.Exists(path))
{

View File

@ -2,81 +2,109 @@ using System.Xml.Linq;
using Microsoft.EntityFrameworkCore;
using netxml2kml.Data;
using netxml2kml.Models;
using Serilog;
namespace netxml2kml.Methods;
public static class CliOptionsHandlers
{
public static void UniversalHandler(FileInfo? inputFile,
public static Task<int> UniversalHandler(FileInfo? inputFile,
FileInfo? outputFile, bool useDatabase, string? sqlQuery,
IEnumerable<FileInfo>? concatFiles)
IEnumerable<FileInfo>? concatFiles, bool isVerbose)
{
// Run some logic based on options combination
if (inputFile != null && outputFile != null)
Log.Information("Handler started with options: " +
"-i: {input}; -o {output}; -d {useDatabase}; " +
"-q: {sqlQuery}; -c: {concatFiles}; -v: {verbosityLevel}.",
inputFile!, outputFile!, useDatabase,
sqlQuery!, concatFiles!, isVerbose);
try
{
var wirelessNetworks = Helpers.DeserializeXml(inputFile);
if (useDatabase)
// Run some logic based on options combination
if (inputFile != null && outputFile != null)
{
var wirelessNetworks = Helpers.DeserializeXml(inputFile);
if (useDatabase)
{
AddWirelessNetworksToDatabase(wirelessNetworks);
}
if (sqlQuery != null)
{
FilterWirelessNetworksInMemory(ref wirelessNetworks,
sqlQuery);
}
var kmlString = GetKmlString(wirelessNetworks,
$"WiFi Map - {outputFile.Name}");
Helpers.WriteStringToFile(kmlString, outputFile);
}
else if (inputFile != null && outputFile == null && useDatabase)
{
var wirelessNetworks = Helpers.DeserializeXml(inputFile);
if (sqlQuery != null)
{
FilterWirelessNetworksInMemory(ref wirelessNetworks,
sqlQuery);
}
AddWirelessNetworksToDatabase(wirelessNetworks);
}
if (sqlQuery != null)
else if (inputFile == null && outputFile != null && useDatabase)
{
FilterWirelessNetworksInMemory(ref wirelessNetworks, sqlQuery);
}
string kmlString;
var kmlString = GetKmlString(wirelessNetworks,
$"WiFi Map - {outputFile.Name}");
Helpers.WriteStringToFile(kmlString, outputFile);
}
else if (inputFile != null && outputFile == null && useDatabase)
{
var wirelessNetworks = Helpers.DeserializeXml(inputFile);
if (sqlQuery != null)
{
kmlString = GetKmlString(
FilterWirelessNetworksFromDatabase(sqlQuery),
$"WiFi Map - {outputFile.Name}");
}
else
{
kmlString = GetKmlString(
FilterWirelessNetworksFromDatabase(
"SELECT * FROM WirelessNetworks"),
$"WiFi Map - {outputFile.Name}");
}
if (sqlQuery != null)
{
FilterWirelessNetworksInMemory(ref wirelessNetworks, sqlQuery);
Helpers.WriteStringToFile(kmlString, outputFile);
}
AddWirelessNetworksToDatabase(wirelessNetworks);
}
else if (inputFile == null && outputFile != null && useDatabase)
{
string kmlString;
if (sqlQuery != null)
else if (inputFile == null && outputFile == null && useDatabase &&
sqlQuery != null)
{
kmlString = GetKmlString(
FilterWirelessNetworksFromDatabase(sqlQuery),
$"WiFi Map - {outputFile.Name}");
using var dbContext = new DatabaseContext();
Console.WriteLine(dbContext.Database.ExecuteSqlRaw(sqlQuery));
}
else if (concatFiles != null && outputFile != null)
{
var inputFiles =
concatFiles as FileInfo[] ?? concatFiles.ToArray();
var kmlString = ConcatKml(inputFiles);
Helpers.WriteStringToFile(kmlString, outputFile);
}
else
{
kmlString = GetKmlString(
FilterWirelessNetworksFromDatabase("SELECT * FROM WirelessNetworks"),
$"WiFi Map - {outputFile.Name}");
Log.Warning("Options combination is unsupported.");
}
Helpers.WriteStringToFile(kmlString, outputFile);
}
else if (inputFile == null && outputFile == null && useDatabase &&
sqlQuery != null)
catch (Exception e)
{
using var dbContext = new DatabaseContext();
Console.WriteLine(dbContext.Database.ExecuteSqlRaw(sqlQuery));
Log.Fatal(e, "Program ended unexpectedly. " +
"Run command with -v option and see logs in {logsFold}" +
"to troubleshoot the error.",
RuntimeStorage.LogsFolder);
return Task.FromResult(1);
}
else if (concatFiles != null && outputFile != null)
finally
{
var inputFiles = concatFiles as FileInfo[] ?? concatFiles.ToArray();
var kmlString = ConcatKml(inputFiles);
Helpers.WriteStringToFile(kmlString, outputFile);
}
else
{
Console.WriteLine("Options combination is unsupported or some option lacks an argument." +
"\nUse --help to see use case examples.");
Log.CloseAndFlush();
}
Log.Information("Options handling completed successfully.");
return Task.FromResult(0);
}
private static string GetKmlString(IEnumerable<WirelessNetwork> wirelessNetworks,
@ -84,6 +112,8 @@ public static class CliOptionsHandlers
string description = $"Autogenerated by a tool." +
$"\nhttps://github.com/cuqmbr/netxml2kml")
{
Log.Information("Generating kml...");
var kmlTree = new XDocument();
var kml = new XElement("kml");
@ -145,6 +175,8 @@ public static class CliOptionsHandlers
kml.Add(document);
kmlTree.Add(kml);
Log.Information("Kml generated.");
return kmlTree.ToString();
void AddWirelessNetworkPlacemark(XElement parent, WirelessNetwork wn)
@ -165,6 +197,8 @@ public static class CliOptionsHandlers
private static void AddWirelessNetworksToDatabase(IEnumerable<WirelessNetwork> wirelessNetworks)
{
Log.Information("Adding wireless networks to the database...");
using var dbContext = new DatabaseContext();
foreach (var wirelessNetwork in wirelessNetworks)
@ -276,11 +310,16 @@ public static class CliOptionsHandlers
}
dbContext.SaveChanges();
Log.Information("Wireless networks added successfully.");
}
private static void FilterWirelessNetworksInMemory(
ref WirelessNetwork[] wirelessNetworks, string sqlQuery)
{
Log.Information("Filtering wireless network using {query}...",
sqlQuery);
using var dbContext = new DatabaseContext("InMemoryFiltering.sqlite3.db");
dbContext.WirelessNetworks.AddRange(wirelessNetworks);
@ -288,16 +327,27 @@ public static class CliOptionsHandlers
wirelessNetworks = dbContext.WirelessNetworks.FromSqlRaw(sqlQuery).ToArray();
dbContext.Database.EnsureDeleted();
Log.Information("Networks are filtered.");
}
private static WirelessNetwork[] FilterWirelessNetworksFromDatabase(string sqlQuery)
{
Log.Information("Filtering wireless network using {query}...",
sqlQuery);
using var dbContext = new DatabaseContext();
return dbContext.WirelessNetworks.FromSqlRaw(sqlQuery).ToArray();
var wirelessNetworks = dbContext.WirelessNetworks.FromSqlRaw(sqlQuery);
Log.Information("Networks are filtered.");
return wirelessNetworks.ToArray();
}
private static string ConcatKml(IEnumerable<FileInfo> inputFiles)
{
Log.Information("Concatenating kml...");
var inFs = inputFiles.ToArray();
var result = XDocument.Load(inFs[0].FullName);
@ -333,6 +383,8 @@ public static class CliOptionsHandlers
.ForEach(p => unknownFolder?.Add(p));
}
Log.Information("Concatenating successfully.");
return result.ToString();
}
}

View File

@ -1,5 +1,6 @@
using System.Xml.Linq;
using netxml2kml.Models;
using Serilog;
namespace netxml2kml.Methods;
@ -7,6 +8,8 @@ public static class Helpers
{
public static WirelessNetwork[] DeserializeXml(FileInfo inputFile)
{
Log.Debug("Deserializing xml...");
var srcTree = XDocument.Load(inputFile.OpenRead());
var srcNets = srcTree.Root!.Elements("wireless-network")
.Where(wn => wn.Attribute("type")!.Value != "probe").ToList();
@ -60,6 +63,8 @@ public static class Helpers
wirelessNetworks[i].WirelessConnections = wirelessConnections;
}
Log.Debug("Xml deserialized.");
return wirelessNetworks.ToArray();
}
@ -81,6 +86,8 @@ public static class Helpers
{"Dec", 12},
};
Log.Debug("Converting string {dateString} to date...", dateString);
var year = Int32.Parse(dateString.Split(" ")[4]);
var month = monthNameNumber[dateString.Split(" ")[1]];
var day = Int32.Parse(dateString.Split(" ")[2]);
@ -88,13 +95,19 @@ public static class Helpers
var minute = Int32.Parse(dateString.Split(" ")[3].Split(":")[1]);
var second = Int32.Parse(dateString.Split(" ")[3].Split(":")[2]);
Log.Debug("String converted successfully.");
return new DateTime(year, month, day, hour, minute, second);
}
public static void WriteStringToFile(string str, FileInfo file)
{
Log.Debug("Saving kml to file...");
var writer = new StreamWriter(file.Open(FileMode.Create));
writer.Write(str);
writer.Close();
Log.Debug("Kml saved to {file}.", file);
}
}

View File

@ -0,0 +1,27 @@
using Serilog;
using Serilog.Events;
namespace netxml2kml.Methods;
public static class RuntimeStorage
{
public static string AppFolder = Path.Join(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"netxml2kml");
public static string LogsFolder = Path.Join(AppFolder, "logs");
public static bool IsVerbose = false;
public static void ConfigureLogger()
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Verbose()
.WriteTo.Console(IsVerbose ? LogEventLevel.Verbose : LogEventLevel.Fatal,
outputTemplate: "{Message:lj}{NewLine}{Exception}")
.WriteTo.File(Path.Join(LogsFolder, "log.txt"),
restrictedToMinimumLevel: IsVerbose ? LogEventLevel.Verbose : LogEventLevel.Warning,
rollingInterval: RollingInterval.Day)
.CreateLogger();
}
}

View File

@ -6,7 +6,7 @@ namespace netxml2kml;
class Program
{
static int Main(string[] args)
static async Task<int> Main(string[] args)
{
/*-------------------------Input Option----------------------------*/
@ -23,7 +23,8 @@ class Program
if (inputFile == null)
{
result.ErrorMessage = "Argument for input option is not specified.";
result.ErrorMessage =
"Argument for input option is not specified.";
return;
}
@ -87,7 +88,8 @@ class Program
if (outputFile == null)
{
result.ErrorMessage = "Argument for output option is not specified.";
result.ErrorMessage =
"Argument for output option is not specified.";
return;
}
@ -114,7 +116,8 @@ class Program
if (inputFiles == null)
{
result.ErrorMessage = "Argument for concat option is not specified.";
result.ErrorMessage =
"Argument for concat option is not specified.";
return;
}
@ -124,15 +127,18 @@ class Program
{
if (!inputFile.Exists)
{
result.ErrorMessage = $"File {inputFile.FullName} doesen't exist.";
result.ErrorMessage =
$"File {inputFile.FullName} doesen't exist.";
return;
}
}
// Validate that inputted files have the same format
if (fileInfos.Any(fi => XDocument.Load(fi.FullName).Root?.Name != "kml"))
if (fileInfos.Any(fi =>
XDocument.Load(fi.FullName).Root?.Name != "kml"))
{
result.ErrorMessage = "Some files passed to concat option have invalid content.";
result.ErrorMessage =
"Some files passed to concat option have invalid content.";
return;
}
});
@ -155,7 +161,23 @@ class Program
{
Arity = ArgumentArity.ZeroOrOne
};
/*----------------------Verbosity Option---------------------------*/
var verbosityOption = new Option<bool>(
aliases: new[] {"-v", "--verbosity"},
description: "Set console output verbosity level.")
{
Arity = ArgumentArity.ZeroOrOne
};
verbosityOption.AddValidator(result =>
{
RuntimeStorage.IsVerbose = result.GetValueForOption(verbosityOption);
});
RuntimeStorage.ConfigureLogger();
/*----------------------Root Command Setup-------------------------*/
var rootCommand =
@ -165,15 +187,25 @@ class Program
rootCommand.AddOption(databaseOption);
rootCommand.AddOption(queryOption);
rootCommand.AddOption(concatOption);
rootCommand.AddOption(verbosityOption);
/*----------------------Handlers Setup-----------------------------*/
rootCommand.SetHandler(CliOptionsHandlers.UniversalHandler,
inputOption, outputOption, databaseOption, queryOption,
concatOption);
concatOption, verbosityOption);
/*----------------------------------------------------------------*/
return rootCommand.Invoke(args);
try
{
return await rootCommand.InvokeAsync(args);
}
catch (Exception e)
{
Console.WriteLine(e);
}
return 0;
}
}

View File

@ -21,6 +21,9 @@
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="6.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.8" />
<PackageReference Include="Serilog" Version="2.11.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
</ItemGroup>