1
0
mirror of https://github.com/akpaevj/OneSTools.TechLog.git synced 2024-12-06 08:16:09 +02:00

Полная перерабокта библиотеки, улучшение производительности, добавление проектов для экспорта ТЖ в сторонние БД

This commit is contained in:
Акпаев Евгений Александрович 2020-11-10 14:46:04 +03:00
parent 108fc8ea4b
commit d8cc243537
17 changed files with 582 additions and 228 deletions

View File

@ -0,0 +1,11 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace OneSTools.TechLog.Exporter.Core
{
public interface ITechLogFolderReader : IDisposable
{
Task StartAsync(string logFolder, int portion, bool liveMode = false, CancellationToken cancellationToken = default);
}
}

View File

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace OneSTools.TechLog.Exporter.Core
{
public interface ITechLogStorage
{
Task WriteItemsAsync(TechLogItem[] items);
}
}

View File

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
<PackageReference Include="System.Threading.Tasks.Dataflow" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OneSTools.TechLog\OneSTools.TechLog.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,41 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace OneSTools.TechLog.Exporter.Core
{
public class TechLogExporterService : BackgroundService
{
private IConfiguration _configuration;
private readonly ILogger<TechLogExporterService> _logger;
private readonly ITechLogFolderReader _techLogFolderReader;
private string _logFolder;
private int _portion;
public TechLogExporterService(IConfiguration configuration, ILogger<TechLogExporterService> logger, ITechLogFolderReader techLogFolderReader)
{
_configuration = configuration;
_logger = logger;
_techLogFolderReader = techLogFolderReader;
_logFolder = configuration.GetValue("Exporter:LogFolder", "");
if (_logFolder == "")
throw new Exception("Log folder's path is not set");
_portion = configuration.GetValue("Exporter", 10000);
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await _techLogFolderReader.StartAsync(_logFolder, _portion, true, stoppingToken);
}
}
}

View File

@ -0,0 +1,121 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
using Microsoft.Extensions.Logging;
using OneSTools.TechLog;
namespace OneSTools.TechLog.Exporter.Core
{
public class TechLogFolderReader : IDisposable, ITechLogFolderReader
{
private readonly ILogger<TechLogFolderReader> _logger;
private ITechLogStorage _techLogStorage;
private string _folder;
private bool _liveMode;
private ActionBlock<TechLogItem[]> _writeBlock;
private BatchBlock<TechLogItem> _batchBlock;
private TransformBlock<string, TechLogItem> _parseBlock;
private ActionBlock<string> _readBlock;
public TechLogFolderReader(ILogger<TechLogFolderReader> logger, ITechLogStorage techLogStorage)
{
_logger = logger;
_techLogStorage = techLogStorage;
}
public async Task StartAsync(string folder, int portion, bool liveMode = false, CancellationToken cancellationToken = default)
{
_folder = folder;
_liveMode = liveMode;
var maxDegree = Environment.ProcessorCount * 10;
_writeBlock = new ActionBlock<TechLogItem[]>(_techLogStorage.WriteItemsAsync, new ExecutionDataflowBlockOptions()
{
BoundedCapacity = 3,
CancellationToken = cancellationToken,
MaxDegreeOfParallelism = maxDegree,
});
_batchBlock = new BatchBlock<TechLogItem>(portion, new GroupingDataflowBlockOptions()
{
CancellationToken = cancellationToken,
BoundedCapacity = portion
});
_parseBlock = new TransformBlock<string, TechLogItem>(ParseItemData, new ExecutionDataflowBlockOptions()
{
MaxDegreeOfParallelism = maxDegree,
BoundedCapacity = portion / 2,
CancellationToken = cancellationToken
});
_readBlock = new ActionBlock<string>(str => ReadItemsData(str, _parseBlock), new ExecutionDataflowBlockOptions()
{
MaxDegreeOfParallelism = maxDegree,
CancellationToken = cancellationToken
}); ;
_parseBlock.LinkTo(_batchBlock);
_batchBlock.LinkTo(_writeBlock);
var logFiles = GetLogFiles();
foreach (var logFile in logFiles)
{
await _readBlock.SendAsync(logFile);
}
await _writeBlock.Completion;
}
private string[] GetLogFiles()
{
return Directory.GetFiles(_folder, "*.log", SearchOption.AllDirectories);
}
private void ReadItemsData(string logPath, ITargetBlock<string> nextblock)
{
var fileName = Path.GetFileNameWithoutExtension(logPath);
var fileDateTime = "20" +
fileName.Substring(0, 2) +
"-" +
fileName.Substring(2, 2) +
"-" +
fileName.Substring(4, 2) +
" " +
fileName.Substring(6, 2);
using var reader = new TechLogReader(logPath);
while (true)
{
var itemData = reader.ReadItemData();
if (itemData != null)
PostData(nextblock, fileDateTime + ":" + itemData);
}
}
private void PostData<T>(ITargetBlock<T> nextblock, T data)
{
while (true)
{
if (nextblock.Post(data))
break;
}
}
private TechLogItem ParseItemData(string itemData)
{
return TechLogReader.ParseItemData(itemData);
}
public void Dispose()
{
}
}
}

View File

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk.Worker">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<UserSecretsId>dotnet-OneSTools.TechLog.Exporter.ElasticSearch-146D8E25-B976-4FAB-A231-A91F8DD2EEF5</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NEST" Version="7.9.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OneSTools.TechLog.Exporter.Core\OneSTools.TechLog.Exporter.Core.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using OneSTools.TechLog.Exporter.Core;
namespace OneSTools.TechLog.Exporter.ElasticSearch
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
var configuration = hostContext.Configuration;
var host = configuration.GetValue("ElasticSearch:Host", "");
var port = configuration.GetValue("ElasticSearch:Port", 9200);
var index = configuration.GetValue("ElasticSearch:Index", "");
var separation = configuration.GetValue("ElasticSearch:Separation", "");
services.AddSingleton<ITechLogStorage>(sp =>
{
var logger = sp.GetService<ILogger<TechLogStorage>>();
return new TechLogStorage(logger, host, port, index, separation);
});
services.AddSingleton<ITechLogFolderReader, TechLogFolderReader>();
services.AddHostedService<TechLogExporterService>();
});
}
}

View File

@ -0,0 +1,77 @@
using Microsoft.Extensions.Logging;
using Nest;
using OneSTools.TechLog.Exporter.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OneSTools.TechLog.Exporter.ElasticSearch
{
public class TechLogStorage : ITechLogStorage
{
private readonly ILogger<TechLogStorage> _logger;
private string _index;
private string _separation;
ElasticClient _client;
public TechLogStorage(ILogger<TechLogStorage> logger, string host, int port = 9200, string index = "", string separation = "")
{
_logger = logger;
var uri = new Uri($"{host}:{port}");
_index = $"{index}-tl";
var settings = new ConnectionSettings(uri);
settings.DefaultIndex(_index);
_separation = separation;
_client = new ElasticClient(settings);
var response = _client.Ping();
if (!response.IsValid)
throw response.OriginalException;
}
public async Task WriteItemsAsync(TechLogItem[] items)
{
var data = new List<(string IndexName, TechLogItem[] Items)>();
switch (_separation)
{
case "H":
var groups = items.GroupBy(c => c.DateTime.ToString("yyyyMMddhh")).OrderBy(c => c.Key);
foreach (IGrouping<string, TechLogItem> item in groups)
data.Add(($"{_index}-{item.Key}", item.ToArray()));
break;
case "D":
groups = items.GroupBy(c => c.DateTime.ToString("yyyyMMdd")).OrderBy(c => c.Key);
foreach (IGrouping<string, TechLogItem> item in groups)
data.Add(($"{_index}-{item.Key}", item.ToArray()));
break;
case "M":
groups = items.GroupBy(c => c.DateTime.ToString("yyyyMM")).OrderBy(c => c.Key);
foreach (IGrouping<string, TechLogItem> item in groups)
data.Add(($"{_index}-{item.Key}", item.ToArray()));
break;
default:
data.Add(($"{_index}-all", items));
break;
}
foreach ((string IndexName, TechLogItem[] Entities) item in data)
{
var responseItems = await _client.IndexManyAsync(item.Entities, item.IndexName);
if (!responseItems.IsValid)
{
throw responseItems.OriginalException;
}
_logger.LogInformation($"{DateTime.Now:hh:mm:ss:fffff} has written {item.Entities.Length}");
}
}
}
}

View File

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}

View File

@ -0,0 +1,18 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"Exporter": {
"LogFolder": "C:\\Users\\akpaev.e.ENTERPRISE\\Desktop\\TechLog"
},
"ElasticSearch": {
"Host": "http://192.168.0.95",
"Port": 9200,
"Index": "upp-main",
"Separation": "H" // H - hour, D - day, M - Month
}
}

View File

@ -5,7 +5,9 @@ VisualStudioVersion = 16.0.29318.209
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OneSTools.TechLog", "OneSTools.TechLog\OneSTools.TechLog.csproj", "{BC6E4DCE-2722-4E6F-BCBC-8945DE1127DD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OneSTools.TechLogConsoleApp", "OneSTools.TechLogConsoleApp\OneSTools.TechLogConsoleApp.csproj", "{8C9CA150-5813-4B2B-99B4-B471708DFE8C}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OneSTools.TechLog.Exporter.ElasticSearch", "OneSTools.TechLog.Exporter.ElasticSearch\OneSTools.TechLog.Exporter.ElasticSearch.csproj", "{6C61BC30-BA4E-428D-A805-1F3B7D9B4D00}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OneSTools.TechLog.Exporter.Core", "OneSTools.TechLog.Exporter.Core\OneSTools.TechLog.Exporter.Core.csproj", "{02C37C84-911F-4725-A1EC-B81FF8F16227}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -17,10 +19,14 @@ Global
{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
{8C9CA150-5813-4B2B-99B4-B471708DFE8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8C9CA150-5813-4B2B-99B4-B471708DFE8C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8C9CA150-5813-4B2B-99B4-B471708DFE8C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8C9CA150-5813-4B2B-99B4-B471708DFE8C}.Release|Any CPU.Build.0 = Release|Any CPU
{6C61BC30-BA4E-428D-A805-1F3B7D9B4D00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6C61BC30-BA4E-428D-A805-1F3B7D9B4D00}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6C61BC30-BA4E-428D-A805-1F3B7D9B4D00}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6C61BC30-BA4E-428D-A805-1F3B7D9B4D00}.Release|Any CPU.Build.0 = Release|Any CPU
{02C37C84-911F-4725-A1EC-B81FF8F16227}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{02C37C84-911F-4725-A1EC-B81FF8F16227}.Debug|Any CPU.Build.0 = Debug|Any CPU
{02C37C84-911F-4725-A1EC-B81FF8F16227}.Release|Any CPU.ActiveCfg = Release|Any CPU
{02C37C84-911F-4725-A1EC-B81FF8F16227}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -1,15 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netstandard2.1</TargetFramework>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Authors>Akpaev Evgeniy</Authors>
<Company>Akpaev Evgeniy</Company>
<Authors>Akpaev Evgeny</Authors>
<Company>Akpaev Evgeny</Company>
<RepositoryUrl>https://github.com/akpaevj/OneSTools.TechLog</RepositoryUrl>
<PackageProjectUrl></PackageProjectUrl>
<Copyright>Akpaev Evgeniy</Copyright>
<PackageProjectUrl>https://github.com/akpaevj/OneSTools.TechLog</PackageProjectUrl>
<Copyright>Akpaev Evgeny</Copyright>
<Description>Библиотека для парсинга технологического журнала 1С</Description>
<Version>1.0.4</Version>
<Version>2.0.0</Version>
<LangVersion>8.0</LangVersion>
<PackageIcon>onestools_icon_nuget.png</PackageIcon>
<PackageLicenseExpression></PackageLicenseExpression>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@ -19,7 +22,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Threading.Tasks.Dataflow" Version="4.10.0" />
<None Include="C:\Users\akpaev.e.ENTERPRISE\source\repos\onestools_icon_nuget.png">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>
</Project>

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
namespace OneSTools.TechLog
{
public class TechLogItem
{
public DateTime DateTime { get; set; }
public long Duration { get; set; }
public string Event { get; set; }
public int Level { get; set; }
public Dictionary<string, string> Properties { get; set; } = new Dictionary<string, string>();
}
}

View File

@ -1,164 +0,0 @@
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 OneSTools.TechLog
{
/// <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; }
/// <summary>
/// Creates a new instance of TechLogParser class
/// </summary>
/// <param name="folder"></param>
/// <param name="eventHandler"></param>
public TechLogParser(string folder, Action<Dictionary<string, string>> eventHandler)
{
Folder = folder;
EventHandler = eventHandler;
readBlockOptions = new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = Environment.ProcessorCount
};
parseBlockOptions = new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = Environment.ProcessorCount,
BoundedCapacity = 10000
};
eventHandlerBlockOptions = new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = Environment.ProcessorCount,
BoundedCapacity = 10000
};
}
/// <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>((filePath) => ReadFile(filePath, parseEventBlock), readBlockOptions);
parseEventBlock.LinkTo(eventHandlerBlock);
var files = GetTechLogFiles();
foreach (var filePath in files)
{
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 void 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\.", RegexOptions.Compiled))
{
if (firstEvent)
{
firstEvent = false;
}
else
{
SendDataToNextBlock(fileDateTime + ":" + currentEvent.ToString(), nextBlock);
currentEvent.Clear();
}
currentEvent.AppendLine(currentLine);
}
else
{
currentEvent.AppendLine(currentLine);
}
}
while (!reader.EndOfStream);
SendDataToNextBlock(fileDateTime + ":" + currentEvent.ToString(), nextBlock);
}
}
private Dictionary<string, string> ParseEventData(string eventData)
{
var properties = new Dictionary<string, string>
{
["EventName"] = Regex.Match(eventData, @",.*?,", RegexOptions.Compiled).ToString().Trim(','),
["DateTime"] = Regex.Match(eventData, @"^.*?\.\d+", RegexOptions.Compiled).ToString(),
["Duration"] = Regex.Match(eventData, @"-\d+?,", RegexOptions.Compiled).ToString().Trim('-', ',')
};
var props = Regex.Matches(eventData, @",[\w:]+=.*?(?=(,[\w:]+=|$))", RegexOptions.ExplicitCapture | RegexOptions.Singleline | RegexOptions.Compiled);
for (int x = 0; x < props.Count; x++)
{
var propText = props[x].ToString();
var splInd = propText.IndexOf('=');
var propName = propText.Substring(0, splInd).Trim(',');
var propVal = propText.Substring(splInd + 1).Trim('\'', '"');
properties[propName] = propVal;
}
return properties;
}
private void SendDataToNextBlock<T>(T data, ITargetBlock<T> nextBlock)
{
while (!nextBlock.Post(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);
}
}
}

View File

@ -0,0 +1,183 @@
using System;
using System.Data;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
namespace OneSTools.TechLog
{
public class TechLogReader : IDisposable
{
private string _logPath;
private string _fileName;
private FileStream _fileStream;
private StreamReader _streamReader;
private StringBuilder _currentData = new StringBuilder();
public TechLogReader(string logPath)
{
_logPath = logPath;
_fileName = Path.GetFileNameWithoutExtension(_logPath);
}
public TechLogItem ReadNextItem(CancellationToken cancellationToken = default)
{
InitializeStream();
var itemData = ReadItemData(cancellationToken);
if (itemData == null)
return null;
return ParseItemData(itemData, cancellationToken);
}
public string ReadItemData(CancellationToken cancellationToken = default)
{
InitializeStream();
var currentLine = "";
while (!cancellationToken.IsCancellationRequested)
{
currentLine = _streamReader.ReadLine();
if (currentLine == null)
{
if (_currentData.Length > 0)
break;
else
return null;
}
if (currentLine == null || _currentData.Length > 0 && Regex.IsMatch(currentLine, @"^\d\d:\d\d\.", RegexOptions.Compiled))
break;
else
_currentData.AppendLine(currentLine);
}
var _strData = _currentData.ToString().Trim();
_currentData.Clear();
if (currentLine != null)
_currentData.AppendLine(currentLine);
return _strData;
}
public static TechLogItem ParseItemData(string itemData, CancellationToken cancellationToken = default)
{
var data = new TechLogItem();
int startPosition = 0;
var dtd = ReadNextPropertyWithoutName(itemData, ref startPosition, ',');
var dtdLength = dtd.Length;
var dtEndIndex = dtd.LastIndexOf('-');
data.DateTime = DateTime.Parse(dtd.Substring(0, dtEndIndex));
startPosition -= dtdLength - dtEndIndex;
data.Duration = long.Parse(ReadNextPropertyWithoutName(itemData, ref startPosition, ','));
data.Event = ReadNextPropertyWithoutName(itemData, ref startPosition, ',');
data.Level = int.Parse(ReadNextPropertyWithoutName(itemData, ref startPosition, ','));
while (!cancellationToken.IsCancellationRequested)
{
var (Name, Value) = ReadNextProperty(itemData, ref startPosition);
if (data.Properties.ContainsKey(Name))
{
data.Properties.Add(GetPropertyName(data, Name, 0), Value);
}
else
data.Properties.Add(Name, Value);
if (startPosition >= itemData.Length)
break;
}
return data;
}
private static string GetPropertyName(TechLogItem item, string name, int number = 0)
{
var currentName = $"{name}{number}";
if (!item.Properties.ContainsKey(currentName))
return currentName;
else
{
return GetPropertyName(item, name, number + 1);
}
}
private static string ReadNextPropertyWithoutName(string strData, ref int startPosition, char delimiter = ',')
{
var endPosition = strData.IndexOf(delimiter, startPosition);
var value = strData.Substring(startPosition, endPosition - startPosition);
startPosition = endPosition + 1;
return value;
}
private static (string Name, string Value) ReadNextProperty(string strData, ref int startPosition)
{
var equalPosition = strData.IndexOf('=', startPosition);
var name = strData.Substring(startPosition, equalPosition - startPosition);
startPosition = equalPosition + 1;
if (startPosition == strData.Length)
return (name, "");
var nextChar = strData[startPosition];
int endPosition;
switch (nextChar)
{
case '\'':
endPosition = strData.IndexOf("\',", startPosition);
break;
case ',':
startPosition++;
return (name, "");
case '"':
endPosition = strData.IndexOf("\",", startPosition);
break;
default:
endPosition = strData.IndexOf(',', startPosition);
break;
}
if (endPosition < 0)
endPosition = strData.Length;
var value = strData.Substring(startPosition, endPosition - startPosition);
startPosition = endPosition + 1;
return (name, value);
}
private void InitializeStream()
{
if (_fileStream == null)
{
_fileStream = new FileStream(_logPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
_streamReader = new StreamReader(_fileStream);
}
}
public void Dispose()
{
if (_fileStream == null)
{
_streamReader.Dispose();
_fileStream = null;
_streamReader = null;
}
}
}
}

View File

@ -1,12 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\OneSTools.TechLog\OneSTools.TechLog.csproj" />
</ItemGroup>
</Project>

View File

@ -1,40 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OneSTools.TechLog;
using System.Diagnostics;
namespace OneSTools.TechLogConsoleApp
{
class Program
{
static object locker = new object();
static int i = 0;
static async Task Main(string[] args)
{
var parser = new TechLogParser(@"C:\Users\akpaev.e.ENTERPRISE\Desktop\ExpertTools\tl", EventHandler);
var watch = new Stopwatch();
watch.Start();
await parser.Parse();
watch.Stop();
Console.WriteLine($"Считано событий: {i}");
Console.WriteLine($"Время выполнения: {watch.Elapsed}");
Console.ReadKey();
}
private static void EventHandler(Dictionary<string, string> eventData)
{
lock (locker)
{
i++;
}
}
}
}