You've already forked OneSTools.TechLog
mirror of
https://github.com/akpaevj/OneSTools.TechLog.git
synced 2025-07-12 22:40:19 +02:00
First sync
This commit is contained in:
25
OneSTechLog.sln
Normal file
25
OneSTechLog.sln
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 16
|
||||||
|
VisualStudioVersion = 16.0.29318.209
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OneSTechLog", "OneSTechLog\OneSTechLog.csproj", "{BC6E4DCE-2722-4E6F-BCBC-8945DE1127DD}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{BC6E4DCE-2722-4E6F-BCBC-8945DE1127DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{BC6E4DCE-2722-4E6F-BCBC-8945DE1127DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{BC6E4DCE-2722-4E6F-BCBC-8945DE1127DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{BC6E4DCE-2722-4E6F-BCBC-8945DE1127DD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {C6424545-BAD6-4AB9-9CEE-58A0157EF357}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
11
OneSTechLog/OneSTechLog.csproj
Normal file
11
OneSTechLog/OneSTechLog.csproj
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="System.Threading.Tasks.Dataflow" Version="4.10.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
186
OneSTechLog/TechLogParser.cs
Normal file
186
OneSTechLog/TechLogParser.cs
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Threading.Tasks.Dataflow;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace OneSTechLog
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents methods for the parsing of the 1C technological log
|
||||||
|
/// </summary>
|
||||||
|
public class TechLogParser
|
||||||
|
{
|
||||||
|
private string folder;
|
||||||
|
private Action<Dictionary<string, string>> eventHandler;
|
||||||
|
private ExecutionDataflowBlockOptions readBlockOptions;
|
||||||
|
private ExecutionDataflowBlockOptions parseBlockOptions;
|
||||||
|
private ExecutionDataflowBlockOptions eventHandlerBlockOptions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Folder of the technological log data
|
||||||
|
/// </summary>
|
||||||
|
public string Folder { get => folder; private set => folder = value; }
|
||||||
|
/// <summary>
|
||||||
|
/// Action for the event handling
|
||||||
|
/// </summary>
|
||||||
|
public Action<Dictionary<string, string>> EventHandler { get => eventHandler; set => eventHandler = value; }
|
||||||
|
|
||||||
|
public TechLogParser(
|
||||||
|
string folder,
|
||||||
|
Action<Dictionary<string, string>> eventHandler,
|
||||||
|
ExecutionDataflowBlockOptions readBlockOptions = null,
|
||||||
|
ExecutionDataflowBlockOptions parseBlockOptions = null,
|
||||||
|
ExecutionDataflowBlockOptions eventHandlerBlockOptions = null)
|
||||||
|
{
|
||||||
|
Folder = folder;
|
||||||
|
EventHandler = eventHandler;
|
||||||
|
|
||||||
|
if (readBlockOptions == null)
|
||||||
|
{
|
||||||
|
this.readBlockOptions = new ExecutionDataflowBlockOptions
|
||||||
|
{
|
||||||
|
MaxDegreeOfParallelism = Environment.ProcessorCount
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.readBlockOptions = readBlockOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parseBlockOptions == null)
|
||||||
|
{
|
||||||
|
this.parseBlockOptions = new ExecutionDataflowBlockOptions
|
||||||
|
{
|
||||||
|
MaxDegreeOfParallelism = Environment.ProcessorCount,
|
||||||
|
BoundedCapacity = 10000
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.parseBlockOptions = parseBlockOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eventHandlerBlockOptions == null)
|
||||||
|
{
|
||||||
|
this.eventHandlerBlockOptions = new ExecutionDataflowBlockOptions
|
||||||
|
{
|
||||||
|
MaxDegreeOfParallelism = Environment.ProcessorCount,
|
||||||
|
BoundedCapacity = 10000
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.eventHandlerBlockOptions = eventHandlerBlockOptions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Starts parsing of the technological log data
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task Parse()
|
||||||
|
{
|
||||||
|
var eventHandlerBlock = new ActionBlock<Dictionary<string, string>>(EventHandler, eventHandlerBlockOptions);
|
||||||
|
var parseEventBlock = new TransformBlock<string, Dictionary<string, string>>(ParseEventData, parseBlockOptions);
|
||||||
|
var readFileBlock = new ActionBlock<string>(async (filePath) => await ReadFile(filePath, parseEventBlock), readBlockOptions);
|
||||||
|
|
||||||
|
parseEventBlock.LinkTo(eventHandlerBlock);
|
||||||
|
|
||||||
|
var files = GetTechLogFiles();
|
||||||
|
|
||||||
|
foreach (var filePath in files)
|
||||||
|
{
|
||||||
|
await SendDataToNextBlock(filePath, readFileBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
var readBlockTask = readFileBlock.Completion.ContinueWith(c => parseEventBlock.Complete());
|
||||||
|
var parseEventBlockTask = parseEventBlock.Completion.ContinueWith(c => eventHandlerBlock.Complete());
|
||||||
|
|
||||||
|
readFileBlock.Complete();
|
||||||
|
|
||||||
|
await Task.WhenAll(readBlockTask, parseEventBlockTask, eventHandlerBlock.Completion);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ReadFile(string filePath, ITargetBlock<string> nextBlock)
|
||||||
|
{
|
||||||
|
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete))
|
||||||
|
using (var reader = new StreamReader(stream))
|
||||||
|
{
|
||||||
|
string fileDateTime = GetFileDateTime(filePath);
|
||||||
|
|
||||||
|
StringBuilder currentEvent = new StringBuilder();
|
||||||
|
bool firstEvent = true;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
var currentLine = reader.ReadLine();
|
||||||
|
|
||||||
|
if (Regex.IsMatch(currentLine, @"^\d\d:\d\d\.\d+", RegexOptions.Compiled))
|
||||||
|
{
|
||||||
|
if (firstEvent)
|
||||||
|
{
|
||||||
|
firstEvent = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await SendDataToNextBlock(fileDateTime + ":" + currentEvent.ToString(), nextBlock);
|
||||||
|
|
||||||
|
currentEvent.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
currentEvent.Append(currentLine);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentEvent.Append(currentLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!reader.EndOfStream);
|
||||||
|
|
||||||
|
await SendDataToNextBlock(fileDateTime + ":" + currentEvent.ToString(), nextBlock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private Dictionary<string, string> ParseEventData(string eventData)
|
||||||
|
{
|
||||||
|
var properties = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
["EventName"] = Regex.Match(eventData, @"(?<=^\d+-\d+-\d+\s\d+:\d+:\d+\.\d+-\d+,)\w+?(?=,)", RegexOptions.IgnoreCase | RegexOptions.Compiled).ToString(),
|
||||||
|
["DateTime"] = Regex.Match(eventData, @"^\d+-\d+-\d+\s\d+:\d+:\d+\.\d+", RegexOptions.IgnoreCase | RegexOptions.Compiled).ToString(),
|
||||||
|
["Duration"] = Regex.Match(eventData, @"(?<=^\d+-\d+-\d+\s\d+:\d+:\d+\.\d+-)\d+", RegexOptions.IgnoreCase | RegexOptions.Compiled).ToString()
|
||||||
|
};
|
||||||
|
|
||||||
|
var props = Regex.Matches(eventData, @"(?<=,)[\w:]+=.*?(?=(,[\w:]+=|$))", RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||||
|
|
||||||
|
foreach (var prop in props)
|
||||||
|
{
|
||||||
|
var propText = prop.ToString();
|
||||||
|
var splInd = propText.IndexOf('=');
|
||||||
|
var propName = propText.Substring(0, splInd);
|
||||||
|
var propVal = propText.Substring(splInd + 1);
|
||||||
|
if (propVal.StartsWith("'") || propVal.StartsWith("\"")) propVal = propVal.Substring(1, propVal.Length - 2);
|
||||||
|
|
||||||
|
properties[propName] = propVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
private async Task SendDataToNextBlock<T>(T data, ITargetBlock<T> nextBlock)
|
||||||
|
{
|
||||||
|
while (!await nextBlock.SendAsync(data)) ;
|
||||||
|
}
|
||||||
|
private string[] GetTechLogFiles()
|
||||||
|
{
|
||||||
|
return Directory.GetFiles(Folder, "*.log");
|
||||||
|
}
|
||||||
|
private string GetFileDateTime(string filePath)
|
||||||
|
{
|
||||||
|
var info = Path.GetFileNameWithoutExtension(filePath);
|
||||||
|
|
||||||
|
return "20" + info.Substring(0, 2) + "-" + info.Substring(2, 2) + "-" + info.Substring(4, 2) + " " + info.Substring(6, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user