diff --git a/Analogy.LogViewer.Serilog.UnitTests/Analogy.LogViewer.Serilog.UnitTests.csproj b/Analogy.LogViewer.Serilog.UnitTests/Analogy.LogViewer.Serilog.UnitTests.csproj
index 9e3c692..eb4c5d2 100644
--- a/Analogy.LogViewer.Serilog.UnitTests/Analogy.LogViewer.Serilog.UnitTests.csproj
+++ b/Analogy.LogViewer.Serilog.UnitTests/Analogy.LogViewer.Serilog.UnitTests.csproj
@@ -16,10 +16,6 @@
-
-
-
-
@@ -28,22 +24,25 @@
Always
-
+
+ Always
+
+
Always
-
+
Always
-
+
Always
-
+
Always
-
+
Always
-
+
Always
diff --git a/Analogy.LogViewer.Serilog.UnitTests/Analogy.Logserver.20200913.log b/Analogy.LogViewer.Serilog.UnitTests/Analogy.Logserver.20200913.log
deleted file mode 100644
index 4bb033e..0000000
--- a/Analogy.LogViewer.Serilog.UnitTests/Analogy.Logserver.20200913.log
+++ /dev/null
@@ -1,125 +0,0 @@
-{"Timestamp":"2020-09-13T17:53:07.1995663+03:00","Level":"Information","MessageTemplate":"Starting Analogy Log Server","Properties":{"MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":1}}
-{"Timestamp":"2020-09-13T17:53:07.6402546+03:00","Level":"Information","MessageTemplate":"Now listening on: {address}","Properties":{"address":"http://[::]:6000","SourceContext":"Microsoft.Hosting.Lifetime","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":9}}
-{"Timestamp":"2020-09-13T17:53:07.6440926+03:00","Level":"Information","MessageTemplate":"Application started. Hosting environment: {envName}; Content root path: {contentRoot}","Properties":{"envName":"Production","contentRoot":"C:\\Kalpa\\Utils\\Analogy.LogServer\\","SourceContext":"Microsoft.Hosting.Lifetime","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":9}}
-{"Timestamp":"2020-09-13T17:53:38.6748466+03:00","Level":"Information","MessageTemplate":"Client subscribe for sending messages","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HH4:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bbfd-402ce09a1cba64d4.","TraceId":"1ba1bbfd-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":14}}
-{"Timestamp":"2020-09-13T17:53:38.7803080+03:00","Level":"Information","MessageTemplate":"User profile is available. Using 'C:\\Windows\\system32\\config\\systemprofile\\AppData\\Local\\ASP.NET\\DataProtection-Keys' as key repository and Windows DPAPI to encrypt keys at rest.","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:53:38.9105668+03:00","Level":"Information","MessageTemplate":"Client subscribe for sending messages","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HH5:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bbfe-402ce09a1cba64d4.","TraceId":"1ba1bbfe-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":9}}
-{"Timestamp":"2020-09-13T17:53:38.9170541+03:00","Level":"Information","MessageTemplate":"Now listening on: http://[::]:5050","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:53:38.9462057+03:00","Level":"Information","MessageTemplate":"Application started. Hosting environment: Production; Content root path: C:\\Kalpa\\DBStoreService\\","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:53:39.3171088+03:00","Level":"Information","MessageTemplate":"Client subscribe for sending messages","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HH6:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bbff-402ce09a1cba64d4.","TraceId":"1ba1bbff-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":15}}
-{"Timestamp":"2020-09-13T17:53:39.3403059+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 17:53:39 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:53:39.3417190+03:00","Level":"Warning","MessageTemplate":"ElectrodeAcqServiceWorker worker is stopping at: 09/13/2020 17:53:39 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:53:39.5306026+03:00","Level":"Information","MessageTemplate":"User profile is available. Using 'C:\\Windows\\system32\\config\\systemprofile\\AppData\\Local\\ASP.NET\\DataProtection-Keys' as key repository and Windows DPAPI to encrypt keys at rest.","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:53:39.6818356+03:00","Level":"Information","MessageTemplate":"Now listening on: http://[::]:5060","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:53:39.6820378+03:00","Level":"Information","MessageTemplate":"Now listening on: http://localhost:5060","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:53:39.6977864+03:00","Level":"Information","MessageTemplate":"Application started. Hosting environment: Production; Content root path: C:\\Kalpa\\EcgAcquisitionService\\","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:53:39.9599219+03:00","Level":"Information","MessageTemplate":"Client subscribe for sending messages","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HH7:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bc00-402ce09a1cba64d4.","TraceId":"1ba1bc00-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":15}}
-{"Timestamp":"2020-09-13T17:53:40.0180022+03:00","Level":"Error","MessageTemplate":"Error: The operation was canceled.","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HH5:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bbfe-402ce09a1cba64d4.","TraceId":"1ba1bbfe-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":14}}
-{"Timestamp":"2020-09-13T17:53:40.0186052+03:00","Level":"Information","MessageTemplate":"Subscription finished.","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HH5:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bbfe-402ce09a1cba64d4.","TraceId":"1ba1bbfe-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":14}}
-{"Timestamp":"2020-09-13T17:53:40.0359596+03:00","Level":"Information","MessageTemplate":"HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms","Properties":{"RequestMethod":"POST","RequestPath":"/greet.Analogy/SubscribeForSendMessages","StatusCode":200,"Elapsed":1126.6294179405431,"SourceContext":"Serilog.AspNetCore.RequestLoggingMiddleware","RequestId":"0HM2NUJ664HH5:00000001","SpanId":"|1ba1bbfe-402ce09a1cba64d4.","TraceId":"1ba1bbfe-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":14},"Renderings":{"Elapsed":[{"Format":"0.0000","Rendering":"1126.6294"}]}}
-{"Timestamp":"2020-09-13T17:53:40.1773019+03:00","Level":"Information","MessageTemplate":"Application is shutting down...","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:53:40.1828188+03:00","Level":"Information","MessageTemplate":"User profile is available. Using 'C:\\Windows\\system32\\config\\systemprofile\\AppData\\Local\\ASP.NET\\DataProtection-Keys' as key repository and Windows DPAPI to encrypt keys at rest.","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:53:40.5890268+03:00","Level":"Information","MessageTemplate":"Now listening on: http://[::]:5020","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:53:40.6045426+03:00","Level":"Information","MessageTemplate":"Application started. Hosting environment: Production; Content root path: C:\\Kalpa\\procedureManagerService\\","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:53:40.6353745+03:00","Level":"Warning","MessageTemplate":"ServicesHealthCheckMonitorWorker worker is stopping at: 09/13/2020 17:53:40 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:53:40.6493477+03:00","Level":"Information","MessageTemplate":"Cancellation requested","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:53:40.6654067+03:00","Level":"Information","MessageTemplate":"Cancellation requested","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:53:40.6657719+03:00","Level":"Information","MessageTemplate":"Cancellation requested","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:53:40.7346441+03:00","Level":"Error","MessageTemplate":"Error: The operation was canceled.","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HH7:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bc00-402ce09a1cba64d4.","TraceId":"1ba1bc00-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":15}}
-{"Timestamp":"2020-09-13T17:53:40.7350281+03:00","Level":"Information","MessageTemplate":"Subscription finished.","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HH7:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bc00-402ce09a1cba64d4.","TraceId":"1ba1bc00-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":15}}
-{"Timestamp":"2020-09-13T17:53:40.7361367+03:00","Level":"Information","MessageTemplate":"HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms","Properties":{"RequestMethod":"POST","RequestPath":"/greet.Analogy/SubscribeForSendMessages","StatusCode":200,"Elapsed":776.784335862911,"SourceContext":"Serilog.AspNetCore.RequestLoggingMiddleware","RequestId":"0HM2NUJ664HH7:00000001","SpanId":"|1ba1bc00-402ce09a1cba64d4.","TraceId":"1ba1bc00-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":15},"Renderings":{"Elapsed":[{"Format":"0.0000","Rendering":"776.7843"}]}}
-{"Timestamp":"2020-09-13T17:53:53.3037835+03:00","Level":"Information","MessageTemplate":"Client subscribe for sending messages","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HH8:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bc01-402ce09a1cba64d4.","TraceId":"1ba1bc01-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":14}}
-{"Timestamp":"2020-09-13T17:53:53.7102845+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 17:53:53 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:53:54.5109192+03:00","Level":"Information","MessageTemplate":"Client subscribe for sending messages","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HH9:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bc02-402ce09a1cba64d4.","TraceId":"1ba1bc02-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":17}}
-{"Timestamp":"2020-09-13T17:53:54.7169480+03:00","Level":"Information","MessageTemplate":"User profile is available. Using 'C:\\Windows\\system32\\config\\systemprofile\\AppData\\Local\\ASP.NET\\DataProtection-Keys' as key repository and Windows DPAPI to encrypt keys at rest.","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:53:55.1360594+03:00","Level":"Information","MessageTemplate":"Now listening on: http://[::]:5020","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:53:55.1518416+03:00","Level":"Information","MessageTemplate":"Application started. Hosting environment: Production; Content root path: C:\\Kalpa\\procedureManagerService\\","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:54:00.2461881+03:00","Level":"Information","MessageTemplate":"change in HW check status: connected: True","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:54:00.8877165+03:00","Level":"Information","MessageTemplate":"PAQConnectionOk:Connection to PAQ restored","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:54:00.9634074+03:00","Level":"Information","MessageTemplate":"PAQHardwareConnectionOk:Connection to PAQ restored","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:54:00.9959271+03:00","Level":"Information","MessageTemplate":"System Event: SystemEventType: PAQConnectionOk, EventData: Connection to PAQ restored, IsError: False. TimeStamp: 1600008839882","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:54:00.9966118+03:00","Level":"Information","MessageTemplate":"System Event: SystemEventType: PAQHardwareConnectionOk, EventData: Connection to PAQ restored, IsError: False. TimeStamp: 1600008840236","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:54:31.7069384+03:00","Level":"Information","MessageTemplate":"Adding client with message: {message}","Properties":{"message":"client","SourceContext":"Analogy.LogServer.GRPCLogConsumer","RequestId":"0HM2NUJ664HHA:00000001","RequestPath":"/greet.Analogy/SubscribeForConsumeMessages","SpanId":"|1ba1bc03-402ce09a1cba64d4.","TraceId":"1ba1bc03-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":15}}
-{"Timestamp":"2020-09-13T17:54:39.7314852+03:00","Level":"Information","MessageTemplate":"Application is shutting down...","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:54:39.7621453+03:00","Level":"Warning","MessageTemplate":"ECGAcquisitionService worker is stopping at: 09/13/2020 17:54:39 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:54:39.8051848+03:00","Level":"Error","MessageTemplate":"Error: The operation was canceled.","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HH6:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bbff-402ce09a1cba64d4.","TraceId":"1ba1bbff-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":22}}
-{"Timestamp":"2020-09-13T17:54:39.8058126+03:00","Level":"Information","MessageTemplate":"Subscription finished.","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HH6:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bbff-402ce09a1cba64d4.","TraceId":"1ba1bbff-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":22}}
-{"Timestamp":"2020-09-13T17:54:39.8073368+03:00","Level":"Information","MessageTemplate":"HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms","Properties":{"RequestMethod":"POST","RequestPath":"/greet.Analogy/SubscribeForSendMessages","StatusCode":200,"Elapsed":60489.43756989482,"SourceContext":"Serilog.AspNetCore.RequestLoggingMiddleware","RequestId":"0HM2NUJ664HH6:00000001","SpanId":"|1ba1bbff-402ce09a1cba64d4.","TraceId":"1ba1bbff-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":22},"Renderings":{"Elapsed":[{"Format":"0.0000","Rendering":"60489.4376"}]}}
-{"Timestamp":"2020-09-13T17:54:41.9805161+03:00","Level":"Information","MessageTemplate":"Client subscribe for sending messages","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HHB:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bc04-402ce09a1cba64d4.","TraceId":"1ba1bc04-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":10}}
-{"Timestamp":"2020-09-13T17:54:42.2038555+03:00","Level":"Information","MessageTemplate":"User profile is available. Using 'C:\\Windows\\system32\\config\\systemprofile\\AppData\\Local\\ASP.NET\\DataProtection-Keys' as key repository and Windows DPAPI to encrypt keys at rest.","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:54:42.3560105+03:00","Level":"Information","MessageTemplate":"Now listening on: http://[::]:5060","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:54:42.3717003+03:00","Level":"Information","MessageTemplate":"Now listening on: http://localhost:5060","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:54:42.3867502+03:00","Level":"Information","MessageTemplate":"Application started. Hosting environment: Production; Content root path: C:\\Kalpa\\EcgAcquisitionService\\","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:54:53.6707194+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 17:54:53 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:55:53.7014220+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 17:55:53 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:56:53.7188489+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 17:56:53 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:57:17.9856789+03:00","Level":"Warning","MessageTemplate":"ElectrodeAcqServiceWorker worker is stopping at: 09/13/2020 17:57:17 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:57:18.0436499+03:00","Level":"Error","MessageTemplate":"Error: The operation was canceled.","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HH8:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bc01-402ce09a1cba64d4.","TraceId":"1ba1bc01-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":13}}
-{"Timestamp":"2020-09-13T17:57:18.0440019+03:00","Level":"Information","MessageTemplate":"Subscription finished.","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HH8:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bc01-402ce09a1cba64d4.","TraceId":"1ba1bc01-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":13}}
-{"Timestamp":"2020-09-13T17:57:18.0448841+03:00","Level":"Information","MessageTemplate":"HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms","Properties":{"RequestMethod":"POST","RequestPath":"/greet.Analogy/SubscribeForSendMessages","StatusCode":200,"Elapsed":204736.3889263087,"SourceContext":"Serilog.AspNetCore.RequestLoggingMiddleware","RequestId":"0HM2NUJ664HH8:00000001","SpanId":"|1ba1bc01-402ce09a1cba64d4.","TraceId":"1ba1bc01-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":13},"Renderings":{"Elapsed":[{"Format":"0.0000","Rendering":"204736.3889"}]}}
-{"Timestamp":"2020-09-13T17:57:20.0952845+03:00","Level":"Information","MessageTemplate":"Client subscribe for sending messages","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HHC:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bc05-402ce09a1cba64d4.","TraceId":"1ba1bc05-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":15}}
-{"Timestamp":"2020-09-13T17:57:20.4887340+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 17:57:20 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:57:20.4901740+03:00","Level":"Warning","MessageTemplate":"ElectrodeAcqServiceWorker worker is stopping at: 09/13/2020 17:57:20 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:57:20.5593288+03:00","Level":"Error","MessageTemplate":"Error: The operation was canceled.","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HHC:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bc05-402ce09a1cba64d4.","TraceId":"1ba1bc05-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":15}}
-{"Timestamp":"2020-09-13T17:57:20.5595636+03:00","Level":"Information","MessageTemplate":"Subscription finished.","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HHC:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bc05-402ce09a1cba64d4.","TraceId":"1ba1bc05-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":15}}
-{"Timestamp":"2020-09-13T17:57:20.5601050+03:00","Level":"Information","MessageTemplate":"HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms","Properties":{"RequestMethod":"POST","RequestPath":"/greet.Analogy/SubscribeForSendMessages","StatusCode":200,"Elapsed":465.36574100802494,"SourceContext":"Serilog.AspNetCore.RequestLoggingMiddleware","RequestId":"0HM2NUJ664HHC:00000001","SpanId":"|1ba1bc05-402ce09a1cba64d4.","TraceId":"1ba1bc05-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":15},"Renderings":{"Elapsed":[{"Format":"0.0000","Rendering":"465.3657"}]}}
-{"Timestamp":"2020-09-13T17:57:22.2388626+03:00","Level":"Information","MessageTemplate":"Client subscribe for sending messages","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HHD:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bc06-402ce09a1cba64d4.","TraceId":"1ba1bc06-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":21}}
-{"Timestamp":"2020-09-13T17:57:22.5019339+03:00","Level":"Error","MessageTemplate":"HW check failed for http://127.0.0.1:5000/ElectrodeAcqAPI/IsHardwareAlive. Reason: No connection could be made because the target machine actively refused it.","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:57:22.6725395+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 17:57:22 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:57:23.3442279+03:00","Level":"Information","MessageTemplate":"Application is shutting down...","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:57:23.3587878+03:00","Level":"Warning","MessageTemplate":"ServicesHealthCheckMonitorWorker worker is stopping at: 09/13/2020 17:57:23 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:57:23.3747952+03:00","Level":"Information","MessageTemplate":"Cancellation requested","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:57:23.3750712+03:00","Level":"Information","MessageTemplate":"Cancellation requested","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:57:23.3909277+03:00","Level":"Information","MessageTemplate":"Cancellation requested","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:57:25.1144051+03:00","Level":"Information","MessageTemplate":"Client subscribe for sending messages","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HHE:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bc07-402ce09a1cba64d4.","TraceId":"1ba1bc07-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":20}}
-{"Timestamp":"2020-09-13T17:57:25.3184487+03:00","Level":"Information","MessageTemplate":"User profile is available. Using 'C:\\Windows\\system32\\config\\systemprofile\\AppData\\Local\\ASP.NET\\DataProtection-Keys' as key repository and Windows DPAPI to encrypt keys at rest.","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:57:25.7346764+03:00","Level":"Information","MessageTemplate":"Now listening on: http://[::]:5020","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:57:25.7491362+03:00","Level":"Information","MessageTemplate":"Application started. Hosting environment: Production; Content root path: C:\\Kalpa\\procedureManagerService\\","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:57:30.8440117+03:00","Level":"Information","MessageTemplate":"change in HW check status: connected: True","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:57:31.4397414+03:00","Level":"Information","MessageTemplate":"System Event: SystemEventType: PAQConnectionOk, EventData: Connection to PAQ restored, IsError: False. TimeStamp: 1600009050481","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:57:31.4400412+03:00","Level":"Information","MessageTemplate":"System Event: SystemEventType: PAQHardwareConnectionOk, EventData: Connection to PAQ restored, IsError: False. TimeStamp: 1600009050840","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:57:31.9591055+03:00","Level":"Error","MessageTemplate":"Error: The operation was canceled.","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HH9:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bc02-402ce09a1cba64d4.","TraceId":"1ba1bc02-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":20}}
-{"Timestamp":"2020-09-13T17:57:31.9593634+03:00","Level":"Information","MessageTemplate":"Subscription finished.","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HH9:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bc02-402ce09a1cba64d4.","TraceId":"1ba1bc02-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":20}}
-{"Timestamp":"2020-09-13T17:57:31.9598813+03:00","Level":"Information","MessageTemplate":"HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms","Properties":{"RequestMethod":"POST","RequestPath":"/greet.Analogy/SubscribeForSendMessages","StatusCode":200,"Elapsed":217444.03517887727,"SourceContext":"Serilog.AspNetCore.RequestLoggingMiddleware","RequestId":"0HM2NUJ664HH9:00000001","SpanId":"|1ba1bc02-402ce09a1cba64d4.","TraceId":"1ba1bc02-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":20},"Renderings":{"Elapsed":[{"Format":"0.0000","Rendering":"217444.0352"}]}}
-{"Timestamp":"2020-09-13T17:57:40.0632237+03:00","Level":"Information","MessageTemplate":"PAQConnectionOk:Connection to PAQ restored","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:57:40.1713693+03:00","Level":"Information","MessageTemplate":"PAQHardwareConnectionOk:Connection to PAQ restored","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:58:22.6427428+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 17:58:22 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T17:59:22.6762891+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 17:59:22 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T18:00:22.7107079+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 18:00:22 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T18:01:22.7426555+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 18:01:22 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T18:02:22.7595771+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 18:02:22 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T18:03:22.7775015+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 18:03:22 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T18:04:22.8109108+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 18:04:22 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T18:05:22.8442910+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 18:05:22 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T18:06:22.8607775+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 18:06:22 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T18:07:22.8937813+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 18:07:22 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T18:08:22.9107554+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 18:08:22 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T18:09:22.9266093+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 18:09:22 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T18:10:22.9607018+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 18:10:22 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T18:11:22.9931798+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 18:11:22 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T18:12:23.0110080+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 18:12:22 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T18:13:23.0439273+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 18:13:23 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T18:14:23.0624190+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 18:14:23 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T18:15:23.0937823+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 18:15:23 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T18:16:23.1105840+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 18:16:23 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T18:17:23.1436375+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 18:17:23 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T18:18:23.1773589+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 18:18:23 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T18:19:23.2101612+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 18:19:23 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T18:20:23.2263506+03:00","Level":"Information","MessageTemplate":"ElectrodeAcqServiceWorker worker running at: 09/13/2020 18:20:23 +03:00","Properties":{"SourceContext":"Analogy.LogServer.MessagesContainer","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":6}}
-{"Timestamp":"2020-09-13T18:21:22.2446789+03:00","Level":"Information","MessageTemplate":"Application is shutting down...","Properties":{"SourceContext":"Microsoft.Hosting.Lifetime","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":21}}
-{"Timestamp":"2020-09-13T18:21:22.2518676+03:00","Level":"Information","MessageTemplate":"Cancellation requested","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":18}}
-{"Timestamp":"2020-09-13T18:21:23.2694087+03:00","Level":"Error","MessageTemplate":"Error receiving messages: System.InvalidOperationException: The collection has been marked as complete with regards to additions.\r\n at System.Collections.Concurrent.BlockingCollection`1.TryAddWithNoTimeValidation(T item, Int32 millisecondsTimeout, CancellationToken cancellationToken)\r\n at System.Collections.Concurrent.BlockingCollection`1.Add(T item)\r\n at Analogy.LogServer.MessagesContainer.AddMessage(AnalogyLogMessage m) in D:\\Git\\Analogy.LogViewer.gRPC\\Analogy.LogServer\\MessagesContainer.cs:line 45\r\n at Analogy.LogServer.Services.GreeterService.HandleClientActions(IAsyncStreamReader`1 requestStream, CancellationToken token) in D:\\Git\\Analogy.LogViewer.gRPC\\Analogy.LogServer\\Services\\GreeterService.cs:line 84","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HHD:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bc06-402ce09a1cba64d4.","TraceId":"1ba1bc06-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":71}}
-{"Timestamp":"2020-09-13T18:21:27.2478596+03:00","Level":"Error","MessageTemplate":"Error: The operation was canceled.","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HH4:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bbfd-402ce09a1cba64d4.","TraceId":"1ba1bbfd-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":71}}
-{"Timestamp":"2020-09-13T18:21:27.2478549+03:00","Level":"Error","MessageTemplate":"Error: The operation was canceled.","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HHE:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bc07-402ce09a1cba64d4.","TraceId":"1ba1bc07-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":15}}
-{"Timestamp":"2020-09-13T18:21:27.2480268+03:00","Level":"Information","MessageTemplate":"Subscription finished.","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HH4:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bbfd-402ce09a1cba64d4.","TraceId":"1ba1bbfd-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":71}}
-{"Timestamp":"2020-09-13T18:21:27.2479716+03:00","Level":"Error","MessageTemplate":"Error: The operation was canceled.","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HHB:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bc04-402ce09a1cba64d4.","TraceId":"1ba1bc04-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":23}}
-{"Timestamp":"2020-09-13T18:21:27.2481162+03:00","Level":"Information","MessageTemplate":"Subscription finished.","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HHE:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bc07-402ce09a1cba64d4.","TraceId":"1ba1bc07-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":15}}
-{"Timestamp":"2020-09-13T18:21:27.2481328+03:00","Level":"Error","MessageTemplate":"Error: The operation was canceled.","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HHD:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bc06-402ce09a1cba64d4.","TraceId":"1ba1bc06-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":76}}
-{"Timestamp":"2020-09-13T18:21:27.2482628+03:00","Level":"Information","MessageTemplate":"Subscription finished.","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HHB:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bc04-402ce09a1cba64d4.","TraceId":"1ba1bc04-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":23}}
-{"Timestamp":"2020-09-13T18:21:27.2483406+03:00","Level":"Information","MessageTemplate":"Subscription finished.","Properties":{"SourceContext":"Analogy.LogServer.Services.GreeterService","RequestId":"0HM2NUJ664HHD:00000001","RequestPath":"/greet.Analogy/SubscribeForSendMessages","SpanId":"|1ba1bc06-402ce09a1cba64d4.","TraceId":"1ba1bc06-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":76}}
-{"Timestamp":"2020-09-13T18:21:27.2487910+03:00","Level":"Information","MessageTemplate":"HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms","Properties":{"RequestMethod":"POST","RequestPath":"/greet.Analogy/SubscribeForSendMessages","StatusCode":200,"Elapsed":1668583.8953785494,"SourceContext":"Serilog.AspNetCore.RequestLoggingMiddleware","RequestId":"0HM2NUJ664HH4:00000001","SpanId":"|1ba1bbfd-402ce09a1cba64d4.","TraceId":"1ba1bbfd-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":71},"Renderings":{"Elapsed":[{"Format":"0.0000","Rendering":"1668583.8954"}]}}
-{"Timestamp":"2020-09-13T18:21:27.2487931+03:00","Level":"Information","MessageTemplate":"HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms","Properties":{"RequestMethod":"POST","RequestPath":"/greet.Analogy/SubscribeForSendMessages","StatusCode":200,"Elapsed":1442093.7996480402,"SourceContext":"Serilog.AspNetCore.RequestLoggingMiddleware","RequestId":"0HM2NUJ664HHE:00000001","SpanId":"|1ba1bc07-402ce09a1cba64d4.","TraceId":"1ba1bc07-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":15},"Renderings":{"Elapsed":[{"Format":"0.0000","Rendering":"1442093.7996"}]}}
-{"Timestamp":"2020-09-13T18:21:27.2487931+03:00","Level":"Information","MessageTemplate":"HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms","Properties":{"RequestMethod":"POST","RequestPath":"/greet.Analogy/SubscribeForSendMessages","StatusCode":200,"Elapsed":1605223.4427487934,"SourceContext":"Serilog.AspNetCore.RequestLoggingMiddleware","RequestId":"0HM2NUJ664HHB:00000001","SpanId":"|1ba1bc04-402ce09a1cba64d4.","TraceId":"1ba1bc04-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":23},"Renderings":{"Elapsed":[{"Format":"0.0000","Rendering":"1605223.4427"}]}}
-{"Timestamp":"2020-09-13T18:21:27.2487935+03:00","Level":"Information","MessageTemplate":"HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms","Properties":{"RequestMethod":"POST","RequestPath":"/greet.Analogy/SubscribeForSendMessages","StatusCode":200,"Elapsed":1444969.2674488472,"SourceContext":"Serilog.AspNetCore.RequestLoggingMiddleware","RequestId":"0HM2NUJ664HHD:00000001","SpanId":"|1ba1bc06-402ce09a1cba64d4.","TraceId":"1ba1bc06-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":76},"Renderings":{"Elapsed":[{"Format":"0.0000","Rendering":"1444969.2674"}]}}
-{"Timestamp":"2020-09-13T18:21:27.2504196+03:00","Level":"Information","MessageTemplate":"HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms","Properties":{"RequestMethod":"POST","RequestPath":"/greet.Analogy/SubscribeForConsumeMessages","StatusCode":200,"Elapsed":1615524.7498754456,"SourceContext":"Serilog.AspNetCore.RequestLoggingMiddleware","RequestId":"0HM2NUJ664HHA:00000001","SpanId":"|1ba1bc03-402ce09a1cba64d4.","TraceId":"1ba1bc03-402ce09a1cba64d4","ParentId":"","MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":70},"Renderings":{"Elapsed":[{"Format":"0.0000","Rendering":"1615524.7499"}]}}
-{"Timestamp":"2020-09-13T18:21:27.2564586+03:00","Level":"Fatal","MessageTemplate":"Error during application","Exception":"System.OperationCanceledException: The operation was canceled.\r\n at System.Threading.CancellationToken.ThrowOperationCanceledException()\r\n at Microsoft.Extensions.Hosting.Internal.Host.StopAsync(CancellationToken cancellationToken)\r\n at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.WaitForShutdownAsync(IHost host, CancellationToken token)\r\n at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)\r\n at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)\r\n at Analogy.LogServer.Program.Main() in D:\\Git\\Analogy.LogViewer.gRPC\\Analogy.LogServer\\Program.cs:line 31","Properties":{"MachineName":"DT-KAMA-LAB1","ProcessId":33100,"ThreadId":70}}
diff --git a/Analogy.LogViewer.Serilog.UnitTests/ClefTests.cs b/Analogy.LogViewer.Serilog.UnitTests/ClefTests.cs
deleted file mode 100644
index 7644654..0000000
--- a/Analogy.LogViewer.Serilog.UnitTests/ClefTests.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-using System;
-using System.IO;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Analogy.LogViewer.Serilog.UnitTests
-{
- [TestClass]
- public class ClefTests
- {
- private string folder { get; } = Environment.CurrentDirectory;
- [TestMethod]
- public async Task ClefParserTest()
- {
- ClefParser p = new ClefParser();
- CancellationTokenSource cts = new CancellationTokenSource();
- string fileName = Path.Combine(folder, "log files", "ClefExample1.clef");
- MessageHandlerForTesting forTesting = new MessageHandlerForTesting();
- var messages = await p.Process(fileName, cts.Token, forTesting);
- Assert.IsTrue(messages.Count() == 4);
- }
-
- // Test reading the (optional) source context
- [TestMethod]
- public async Task SourceContextTest()
- {
- ClefParser p = new ClefParser();
- CancellationTokenSource cts = new CancellationTokenSource();
- string fileName = Path.Combine(folder, "log files", "SourceContextTest.clef");
- MessageHandlerForTesting forTesting = new MessageHandlerForTesting();
-
- var messages = (await p.Process(fileName, cts.Token, forTesting)).ToList();
-
- Assert.AreEqual(2, messages.Count());
-
- // The first event doesn't have a source context
- var firstEvent = messages.ElementAt(0);
- Assert.AreEqual("Hello, Serilog!", firstEvent.Text);
- Assert.AreEqual(string.Empty, firstEvent.Source);
- Assert.AreEqual(1, firstEvent.ThreadId);
- Assert.IsNotNull(firstEvent.Module);
- Assert.IsNotNull(firstEvent.FileName);
- Assert.IsNotNull(firstEvent.Category);
- Assert.IsNotNull(firstEvent.User);
- Assert.IsNotNull(firstEvent.MethodName);
- // The second event should have a source context
- var secondEvent = messages.ElementAt(1);
- Assert.AreEqual("Contextual Log", secondEvent.Text);
- Assert.AreEqual("SerilogLogging.Program", secondEvent.Source);
- Assert.AreEqual(1, secondEvent.ThreadId);
- Assert.IsNotNull(secondEvent.Module);
- Assert.IsNotNull(secondEvent.FileName);
- Assert.IsNotNull(secondEvent.Category);
- Assert.IsNotNull(secondEvent.User);
- Assert.IsNotNull(secondEvent.MethodName);
- }
- }
-}
\ No newline at end of file
diff --git a/Analogy.LogViewer.Serilog.UnitTests/CompactJsonFormatTests.cs b/Analogy.LogViewer.Serilog.UnitTests/CompactJsonFormatTests.cs
new file mode 100644
index 0000000..a9da246
--- /dev/null
+++ b/Analogy.LogViewer.Serilog.UnitTests/CompactJsonFormatTests.cs
@@ -0,0 +1,126 @@
+using Analogy.LogViewer.Serilog.DataTypes;
+using Analogy.LogViewer.Serilog.IAnalogy;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Analogy.LogViewer.Serilog.UnitTests
+{
+ [TestClass]
+ public class CompactJsonFormatTests
+ {
+ private string Folder { get; } = Environment.CurrentDirectory;
+ [TestMethod]
+ [DataRow("CompactJsonFormat.clef",4, "2016-10-12T04:46:58.0554314Z")]
+ [DataRow("CompactJsonFormatSourceContextTest.clef",2, "2020-06-18T18:03:19.2248275Z")]
+ [DataRow("CompactJsonFormatTestColumns.clef",4, "2020-06-26T14:21:34.7233612Z")]
+ [DataRow("CompactJsonFormat.gz",4, "2016-10-12T04:46:58.0554314Z")]
+ public async Task OfflineProviderParserTimestampTest(string fileName,int numberOfMessages,string datetimeToParse)
+ {
+ OfflineDataProvider parser = new OfflineDataProvider();
+ CancellationTokenSource cts = new CancellationTokenSource();
+ string file = Path.Combine(Folder, "log files", fileName);
+ MessageHandlerForTesting forTesting = new MessageHandlerForTesting();
+ var messages = (await parser.Process(file, cts.Token, forTesting)).ToList();
+ DateTimeOffset dto = DateTimeOffset.Parse(datetimeToParse);
+ Assert.IsTrue(messages.Count == numberOfMessages);
+ Assert.IsTrue(messages[0].Date == dto.DateTime);
+ }
+
+
+ [TestMethod]
+ [DataRow("CompactJsonFormat.clef")]
+ [DataRow("CompactJsonFormatSourceContextTest.clef")]
+ [DataRow("CompactJsonFormatTestColumns.clef")]
+ [DataRow("CompactJsonFormat.gz")]
+ public void CompactJsonFormatTestAutomaticDetection(string fileName)
+ {
+ string file = Path.Combine(Folder, "log files", fileName);
+ var type = OfflineDataProvider.TryDetectFormat(file);
+ Assert.IsTrue(type == FileFormat.CompactJsonFormatPerLine);
+
+ }
+
+ [TestMethod]
+ public async Task CompactJsonFormatParserTest()
+ {
+ CompactJsonFormatParser parser = new CompactJsonFormatParser();
+ CancellationTokenSource cts = new CancellationTokenSource();
+ string fileName = Path.Combine(Folder, "log files", "CompactJsonFormat.clef");
+ MessageHandlerForTesting forTesting = new MessageHandlerForTesting();
+ var messages = (await parser.Process(fileName, cts.Token, forTesting)).ToList();
+ Assert.IsTrue(messages.Count == 4);
+ Assert.IsTrue(messages[0].Text == "Hello, { Name: \"nblumhardt\", Id: 101 }");
+ }
+
+ // Test reading the (optional) source context
+ [TestMethod]
+ public async Task CompactJsonFormatSourceContextTest()
+ {
+ CompactJsonFormatParser parser = new CompactJsonFormatParser();
+ CancellationTokenSource cts = new CancellationTokenSource();
+ string fileName = Path.Combine(Folder, "log files", "CompactJsonFormatSourceContextTest.clef");
+ MessageHandlerForTesting forTesting = new MessageHandlerForTesting();
+
+ var messages = (await parser.Process(fileName, cts.Token, forTesting)).ToList();
+
+ Assert.AreEqual(2, messages.Count());
+
+ // The first event doesn't have a source context
+ var firstEvent = messages.ElementAt(0);
+ Assert.AreEqual("Hello, Serilog!", firstEvent.Text);
+ Assert.AreEqual(string.Empty, firstEvent.Source);
+ Assert.AreEqual(1, firstEvent.ThreadId);
+ Assert.IsNotNull(firstEvent.Module);
+ Assert.IsNotNull(firstEvent.FileName);
+ Assert.IsNotNull(firstEvent.Category);
+ Assert.IsNotNull(firstEvent.User);
+ Assert.IsNotNull(firstEvent.MethodName);
+ // The second event should have a source context
+ var secondEvent = messages.ElementAt(1);
+ Assert.AreEqual("Contextual Log", secondEvent.Text);
+ Assert.AreEqual("SerilogLogging.Program", secondEvent.Source);
+ Assert.AreEqual(1, secondEvent.ThreadId);
+ Assert.IsNotNull(secondEvent.Module);
+ Assert.IsNotNull(secondEvent.FileName);
+ Assert.IsNotNull(secondEvent.Category);
+ Assert.IsNotNull(secondEvent.User);
+ Assert.IsNotNull(secondEvent.MethodName);
+ }
+
+
+ [TestMethod]
+ public async Task CompactJsonFormatTestColumns()
+ {
+ CompactJsonFormatParser parser = new CompactJsonFormatParser();
+ CancellationTokenSource cts = new CancellationTokenSource();
+ string fileName = Path.Combine(Folder, "log files", "CompactJsonFormatTestColumns.clef");
+ MessageHandlerForTesting forTesting = new MessageHandlerForTesting();
+ var messages = (await parser.Process(fileName, cts.Token, forTesting)).ToList();
+ Assert.AreEqual(4, messages.Count());
+ // The first event doesn't have a source context
+ Assert.IsTrue(messages[0].MachineName == "Test");
+ Assert.IsTrue(messages[1].AdditionalInformation["CustomProperty"] == "\"Custom Value\"");
+
+ }
+
+ [TestMethod]
+ public async Task CompactJsonFormatTestGZFile()
+ {
+ CompactJsonFormatParser parser = new CompactJsonFormatParser();
+ CancellationTokenSource cts = new CancellationTokenSource();
+ string fileName = Path.Combine(Folder, "log files", "CompactJsonFormat.gz");
+ MessageHandlerForTesting forTesting = new MessageHandlerForTesting();
+ var messages = (await parser.Process(fileName, cts.Token, forTesting)).ToList();
+ Assert.AreEqual(4, messages.Count());
+ // The first event doesn't have a source context
+ Assert.IsTrue(messages[2].AdditionalInformation["Tags"] == "[\"test\", \"orange\"]");
+
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/Analogy.LogViewer.Serilog.UnitTests/JsonFormatTests.cs b/Analogy.LogViewer.Serilog.UnitTests/JsonFormatTests.cs
new file mode 100644
index 0000000..1d4428d
--- /dev/null
+++ b/Analogy.LogViewer.Serilog.UnitTests/JsonFormatTests.cs
@@ -0,0 +1,85 @@
+using Analogy.LogViewer.Serilog.DataTypes;
+using Analogy.LogViewer.Serilog.IAnalogy;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Analogy.LogViewer.Serilog.UnitTests
+{
+ [TestClass]
+ public class JsonFormatTests
+ {
+ private string Folder { get; } = Environment.CurrentDirectory;
+
+ [TestMethod]
+ public async Task CompactJsonFormatFullFileTest()
+ {
+ JsonFileParser parser = new JsonFileParser(new CompactJsonFormatMessageFields());
+ CancellationTokenSource cts = new CancellationTokenSource();
+ string fileName = Path.Combine(Folder, "log files", "JsonFileCompactFormat.clef");
+ MessageHandlerForTesting forTesting = new MessageHandlerForTesting();
+ var messages = (await parser.Process(fileName, cts.Token, forTesting)).ToList();
+ Assert.IsTrue(messages.Count == 2);
+ Assert.IsTrue(messages[0].MachineName == "MY-MACHINE");
+ Assert.IsTrue(messages[1].Text.StartsWith("An unknown error occurred"));
+ Assert.IsTrue((messages[1].Module == "My process"));
+
+ }
+
+ [TestMethod]
+ public async Task JsonFilePerLineTest()
+ {
+ var p = new JsonFormatterParser(new JsonFormatMessageFields());
+ CancellationTokenSource cts = new CancellationTokenSource();
+ string fileName = Path.Combine(Folder, "log files", "JsonFormatPerLine.clef");
+ MessageHandlerForTesting forTesting = new MessageHandlerForTesting();
+ var messages = (await p.Process(fileName, cts.Token, forTesting)).ToList();
+ Assert.IsTrue(messages.Count == 2);
+ //Assert.IsTrue(messages[0].Text == "Hello, { Name: \"nblumhardt\", Tags: [1, 2, 3] }, 0000007b at 06/07/2016 06:44:57","got"+ messages[0].Text);
+ Assert.IsTrue(messages[0].User == "{ Name: \"nblumhardt\", Tags: [1, 2, 3] }");
+ }
+
+ [TestMethod]
+ public async Task JsonFilePerFileTest()
+ {
+ JsonFileParser parser = new JsonFileParser(new JsonFormatMessageFields());
+ CancellationTokenSource cts = new CancellationTokenSource();
+ string fileName = Path.Combine(Folder, "log files", "JsonFormatPerFile.clef");
+ MessageHandlerForTesting forTesting = new MessageHandlerForTesting();
+ var messages = (await parser.Process(fileName, cts.Token, forTesting)).ToList();
+ Assert.IsTrue(messages.Count == 2);
+ //Assert.IsTrue(messages[0].Text == "Hello, { Name: \"nblumhardt\", Tags: [1, 2, 3] }, 0000007b at 06/07/2016 06:44:57","got"+ messages[0].Text);
+ Assert.IsTrue(messages[0].User == "{ Name: \"nblumhardt\", Tags: [1, 2, 3] }");
+ }
+
+ [TestMethod]
+ [DataRow("JsonFileCompactFormat.clef", FileFormat.CompactJsonFormatPerFile)]
+ [DataRow("JsonFormatPerLine.clef", FileFormat.JsonFormatPerLine)]
+ public void CompactJsonFormatTestAutomaticDetection(string fileName, FileFormat format)
+ {
+ string file = Path.Combine(Folder, "log files", fileName);
+ var type = OfflineDataProvider.TryDetectFormat(file);
+ Assert.IsTrue(type == format);
+ }
+
+ [TestMethod]
+ public async Task JsonFilePerLineDateTimeWithOffsetTest()
+ {
+ var p = new JsonFormatterParser(new JsonFormatMessageFields());
+ CancellationTokenSource cts = new CancellationTokenSource();
+ string fileName = Path.Combine(Folder, "log files", "JsonFormatPerLine.clef");
+ MessageHandlerForTesting forTesting = new MessageHandlerForTesting();
+ var messages = (await p.Process(fileName, cts.Token, forTesting)).ToList();
+ Assert.IsTrue(messages.Count == 2);
+
+ Assert.IsTrue(messages[0].User == "{ Name: \"nblumhardt\", Tags: [1, 2, 3] }");
+
+ DateTimeOffset dto = DateTimeOffset.Parse("2020-06-07T13:44:57.8532799+10:00");
+ //Assert.IsTrue(messages[0].Date == dto.DateTime);
+ //Assert.IsTrue(messages[0].Text == "Hello, { Name: \"nblumhardt\", Tags: [1, 2, 3] }, 0000007b at 06/07/2016 06:44:57", "got" + messages[0].Text);
+ }
+ }
+}
diff --git a/Analogy.LogViewer.Serilog.UnitTests/JsonParserTests.cs b/Analogy.LogViewer.Serilog.UnitTests/JsonParserTests.cs
deleted file mode 100644
index 852f29b..0000000
--- a/Analogy.LogViewer.Serilog.UnitTests/JsonParserTests.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System;
-using System.IO;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Analogy.LogViewer.Serilog.UnitTests
-{
- [TestClass]
- public class JsonParserTests
- {
- private string folder { get; } = Environment.CurrentDirectory;
-
- [TestMethod]
- public async Task ClefJsonParserTest()
- {
- var p = new ClefParser();
- CancellationTokenSource cts = new CancellationTokenSource();
- string fileName = Path.Combine(folder, "log files", "SourceContextTest.clef");
- MessageHandlerForTesting forTesting = new MessageHandlerForTesting();
- var messages = await p.Process(fileName, cts.Token, forTesting);
- Assert.IsTrue(messages.Count() == 2);
- }
- }
-}
diff --git a/Analogy.LogViewer.Serilog.UnitTests/log files/ClefExample1.clef b/Analogy.LogViewer.Serilog.UnitTests/log files/CompactJsonFormat.clef
similarity index 100%
rename from Analogy.LogViewer.Serilog.UnitTests/log files/ClefExample1.clef
rename to Analogy.LogViewer.Serilog.UnitTests/log files/CompactJsonFormat.clef
diff --git a/Analogy.LogViewer.Serilog.UnitTests/log files/ClefExample1.clef.gz b/Analogy.LogViewer.Serilog.UnitTests/log files/CompactJsonFormat.gz
similarity index 100%
rename from Analogy.LogViewer.Serilog.UnitTests/log files/ClefExample1.clef.gz
rename to Analogy.LogViewer.Serilog.UnitTests/log files/CompactJsonFormat.gz
diff --git a/Analogy.LogViewer.Serilog.UnitTests/log files/SourceContextTest.clef b/Analogy.LogViewer.Serilog.UnitTests/log files/CompactJsonFormatSourceContextTest.clef
similarity index 100%
rename from Analogy.LogViewer.Serilog.UnitTests/log files/SourceContextTest.clef
rename to Analogy.LogViewer.Serilog.UnitTests/log files/CompactJsonFormatSourceContextTest.clef
diff --git a/Analogy.LogViewer.Serilog.UnitTests/log files/TestColumns.clef b/Analogy.LogViewer.Serilog.UnitTests/log files/CompactJsonFormatTestColumns.clef
similarity index 100%
rename from Analogy.LogViewer.Serilog.UnitTests/log files/TestColumns.clef
rename to Analogy.LogViewer.Serilog.UnitTests/log files/CompactJsonFormatTestColumns.clef
diff --git a/Analogy.LogViewer.Serilog.UnitTests/log files/testJson.clef b/Analogy.LogViewer.Serilog.UnitTests/log files/JsonFileCompactFormat.clef
similarity index 100%
rename from Analogy.LogViewer.Serilog.UnitTests/log files/testJson.clef
rename to Analogy.LogViewer.Serilog.UnitTests/log files/JsonFileCompactFormat.clef
diff --git a/Analogy.LogViewer.Serilog.UnitTests/log files/JsonFormatPerFile.clef b/Analogy.LogViewer.Serilog.UnitTests/log files/JsonFormatPerFile.clef
new file mode 100644
index 0000000..438ad1a
--- /dev/null
+++ b/Analogy.LogViewer.Serilog.UnitTests/log files/JsonFormatPerFile.clef
@@ -0,0 +1,44 @@
+[
+ {
+ "Timestamp": "2020-06-07T13:44:57.8532799+10:00",
+ "Level": "Information",
+ "MessageTemplate": "Hello, {@User}, {N:x8} at {Now}",
+ "Properties": {
+ "User": {
+ "Name": "nblumhardt",
+ "Tags": [ 1, 2, 3 ]
+ },
+ "N": 123,
+ "Now": "2016-06-07T13:44:57.8532799+10:00"
+ },
+ "Renderings": {
+ "N": [
+ {
+ "Format": "x8",
+ "Rendering": "0000007b"
+ }
+ ]
+ }
+ },
+ {
+ "Timestamp": "2016-06-07T13:44:57.8532799+10:00",
+ "Level": "Information",
+ "MessageTemplate": "Hello, {@User}, {N:x8} at {Now}",
+ "Properties": {
+ "User": {
+ "Name": "Lior",
+ "Tags": [ 1, 2, 3 ]
+ },
+ "N": 123,
+ "Now": "2016-06-07T13:44:57.8532799+10:00"
+ },
+ "Renderings": {
+ "N": [
+ {
+ "Format": "x8",
+ "Rendering": "0000007b"
+ }
+ ]
+ }
+ }
+]
\ No newline at end of file
diff --git a/Analogy.LogViewer.Serilog.UnitTests/log files/JsonFormatPerLine.clef b/Analogy.LogViewer.Serilog.UnitTests/log files/JsonFormatPerLine.clef
new file mode 100644
index 0000000..a0d8344
--- /dev/null
+++ b/Analogy.LogViewer.Serilog.UnitTests/log files/JsonFormatPerLine.clef
@@ -0,0 +1,2 @@
+{"Timestamp":"2020-06-07T13:44:57.8532799+10:00","Level":"Information","MessageTemplate":"Hello, {@User}, {N:x8} at {Now}","Properties":{"User":{"Name":"nblumhardt","Tags":[1,2,3]},"N":123,"Now":"2016-06-07T13:44:57.8532799+10:00"},"Renderings":{"N":[{"Format":"x8","Rendering":"0000007b"}]}}
+{"Timestamp":"2016-06-07T13:44:57.8532799+10:00","Level":"Information","MessageTemplate":"Hello, {@User}, {N:x8} at {Now}","Properties":{"User":{"Name":"Lior","Tags":[1,2,3]},"N":123,"Now":"2016-06-07T13:44:57.8532799+10:00"},"Renderings":{"N":[{"Format":"x8","Rendering":"0000007b"}]}}
\ No newline at end of file
diff --git a/Analogy.LogViewer.Serilog.UnitTests/log files/JsonFormatter.clef b/Analogy.LogViewer.Serilog.UnitTests/log files/JsonFormatter.clef
deleted file mode 100644
index 14256c3..0000000
--- a/Analogy.LogViewer.Serilog.UnitTests/log files/JsonFormatter.clef
+++ /dev/null
@@ -1 +0,0 @@
-{"Timestamp":"2016-06-07T13:44:57.8532799+10:00","Level":"Information","MessageTemplate":"Hello, {@User}, {N:x8} at {Now}","Properties":{"User":{"Name":"nblumhardt","Tags":[1,2,3]},"N":123,"Now":"2016-06-07T13:44:57.8532799+10:00"},"Renderings":{"N":[{"Format":"x8","Rendering":"0000007b"}]}}
\ No newline at end of file
diff --git a/Analogy.LogViewer.Serilog/Analogy.LogViewer.Serilog.csproj b/Analogy.LogViewer.Serilog/Analogy.LogViewer.Serilog.csproj
index 8fdf943..196e573 100644
--- a/Analogy.LogViewer.Serilog/Analogy.LogViewer.Serilog.csproj
+++ b/Analogy.LogViewer.Serilog/Analogy.LogViewer.Serilog.csproj
@@ -20,7 +20,7 @@
AnalogySerilog.png
true
- 1.3.6
+ 2.0.0
Analogy.LogViewer
true
diff --git a/Analogy.LogViewer.Serilog/ChangeLogList.cs b/Analogy.LogViewer.Serilog/ChangeLogList.cs
index 419bd89..fd15065 100644
--- a/Analogy.LogViewer.Serilog/ChangeLogList.cs
+++ b/Analogy.LogViewer.Serilog/ChangeLogList.cs
@@ -6,12 +6,17 @@ namespace Analogy.LogViewer.Serilog
{
public static class ChangeLogList
{
- public static IEnumerable GetChangeLog()
+ public static IEnumerable GetChangeLog()=>
+ new List()
{
- yield return new AnalogyChangeLog("Support for reading compressed files. #45", AnalogChangeLogType.Improvement, "Lior Banai", new DateTime(2020, 07, 22));
- yield return new AnalogyChangeLog("Duplicated/Extra columns with the dynamic columns feature. #44", AnalogChangeLogType.Improvement, "Lior Banai", new DateTime(2020, 07, 10));
- yield return new AnalogyChangeLog("Add dynamic columns per file properties. #43", AnalogChangeLogType.Improvement, "Lior Banai", new DateTime(2020, 07, 03));
- yield return new AnalogyChangeLog("Initial version", AnalogChangeLogType.None, "Lior Banai", new DateTime(2019, 12, 14));
- }
+ new AnalogyChangeLog("[V2.0.0] - Add Raw message data property and Json Viewer when relevant #109", AnalogChangeLogType.Improvement, "Lior Banai", new DateTime(2020, 09, 26)),
+ new AnalogyChangeLog("[V2.0.0] - Remove Regex parser from Serilog parser #112", AnalogChangeLogType.Improvement, "Lior Banai", new DateTime(2020, 09, 26)),
+ new AnalogyChangeLog("[V2.0.0] - Add Auto detect formatter used in log file so user won't need to define the formatter in the user settings #61", AnalogChangeLogType.Improvement, "Lior Banai", new DateTime(2020, 09, 26)),
+ new AnalogyChangeLog("[V2.0.0] - Add Additional Text Formatters (CompactJsonFormatter,JsonFormatter ) #6", AnalogChangeLogType.Improvement, "Lior Banai", new DateTime(2020, 09, 26)),
+ new AnalogyChangeLog("Support for reading compressed files. #45", AnalogChangeLogType.Improvement, "Lior Banai", new DateTime(2020, 07, 22)),
+ new AnalogyChangeLog("Duplicated/Extra columns with the dynamic columns feature. #44", AnalogChangeLogType.Improvement, "Lior Banai", new DateTime(2020, 07, 10)),
+ new AnalogyChangeLog("Add dynamic columns per file properties. #43", AnalogChangeLogType.Improvement, "Lior Banai", new DateTime(2020, 07, 03)),
+ new AnalogyChangeLog("Initial version", AnalogChangeLogType.None, "Lior Banai", new DateTime(2019, 12, 14))
+ };
}
}
diff --git a/Analogy.LogViewer.Serilog/CompactClef/ClefFields.cs b/Analogy.LogViewer.Serilog/CompactClef/ClefFields.cs
deleted file mode 100644
index 79ab253..0000000
--- a/Analogy.LogViewer.Serilog/CompactClef/ClefFields.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2013-2015 Serilog Contributors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using System.Linq;
-
-namespace Analogy.LogViewer.Serilog.CompactClef
-{
- static class ClefFields
- {
- public const string Timestamp = "@t";
- public const string MessageTemplate = "@mt";
- public const string Level = "@l";
- public const string Exception = "@x";
- public const string Renderings = "@r";
- public const string EventId = "@i";
- public const string Message = "@m";
-
- public static readonly string[] All = { Timestamp, MessageTemplate, Level, Exception, Renderings, EventId, Message };
-
- const string Prefix = "@";
- const string EscapedInitialAt = "@@";
-
- public static string Unescape(string name)
- {
- if (name.StartsWith(EscapedInitialAt))
- return name.Substring(1);
-
- return name;
- }
-
- public static bool IsUnrecognized(string name)
- {
- return !name.StartsWith(EscapedInitialAt) &&
- name.StartsWith(Prefix) &&
- !All.Contains(name);
- }
- }
-
-}
diff --git a/Analogy.LogViewer.Serilog/CompactClef/Rendering.cs b/Analogy.LogViewer.Serilog/CompactClef/Rendering.cs
deleted file mode 100644
index 3e9e3b0..0000000
--- a/Analogy.LogViewer.Serilog/CompactClef/Rendering.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2013-2015 Serilog Contributors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-namespace Analogy.LogViewer.Serilog.CompactClef
-{
- class Rendering
- {
- public string Name { get; }
- public string Format { get; }
- public string Rendered { get; }
-
- public Rendering(string name, string format, string rendered)
- {
- Name = name;
- Format = format;
- Rendered = rendered;
- }
- }
-}
\ No newline at end of file
diff --git a/Analogy.LogViewer.Serilog/DataTypes/Enums.cs b/Analogy.LogViewer.Serilog/DataTypes/Enums.cs
index 3cea8d1..d216513 100644
--- a/Analogy.LogViewer.Serilog/DataTypes/Enums.cs
+++ b/Analogy.LogViewer.Serilog/DataTypes/Enums.cs
@@ -1,15 +1,17 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Analogy.LogViewer.Serilog.DataTypes
+namespace Analogy.LogViewer.Serilog.DataTypes
{
- public enum LogFormat
+ public enum FileFormat
{
- Clef,
-
+ Unknown,
+ CompactJsonFormatPerLine,
+ JsonFormatPerLine,
+ CompactJsonFormatPerFile,
+ JsonFormatFile,
}
+ public enum FileFormatDetection
+ {
+ Automatic,
+ Manual
+ }
}
diff --git a/Analogy.LogViewer.Serilog/CompactClef/LogEventReader.cs b/Analogy.LogViewer.Serilog/DataTypes/LogEventReader.cs
similarity index 62%
rename from Analogy.LogViewer.Serilog/CompactClef/LogEventReader.cs
rename to Analogy.LogViewer.Serilog/DataTypes/LogEventReader.cs
index 4602efd..5329290 100644
--- a/Analogy.LogViewer.Serilog/CompactClef/LogEventReader.cs
+++ b/Analogy.LogViewer.Serilog/DataTypes/LogEventReader.cs
@@ -1,28 +1,15 @@
-// Copyright 2013-2015 Serilog Contributors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using Newtonsoft.Json;
+using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Serilog.Events;
using Serilog.Parsing;
using System;
+using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
-namespace Analogy.LogViewer.Serilog.CompactClef
+namespace Analogy.LogViewer.Serilog.DataTypes
{
///
/// Reads files produced by Serilog.Formatting.Compact.CompactJsonFormatter. Events
@@ -33,16 +20,18 @@ public class LogEventReader : IDisposable
static readonly MessageTemplateParser Parser = new MessageTemplateParser();
readonly TextReader _text;
readonly JsonSerializer _serializer;
-
+ private readonly IMessageFields _messageFields;
int _lineNumber;
///
/// Construct a .
///
/// Text to read from.
+ ///
/// If specified, a JSON serializer used when converting event documents.
- public LogEventReader(TextReader text, JsonSerializer serializer = null)
+ public LogEventReader(TextReader text, IMessageFields messageFields, JsonSerializer serializer = null)
{
+ _messageFields = messageFields;
_text = text ?? throw new ArgumentNullException(nameof(text));
_serializer = serializer ?? CreateSerializer();
}
@@ -75,11 +64,10 @@ public bool TryRead(out LogEvent evt)
}
var data = _serializer.Deserialize(new JsonTextReader(new StringReader(line)));
- var fields = data as JObject;
- if (fields == null)
+ if (!(data is JObject fields))
throw new InvalidDataException($"The data on line {_lineNumber} is not a complete JSON object.");
- evt = ReadFromJObject(_lineNumber, fields);
+ evt = ReadFromJObject(_lineNumber, fields,_messageFields);
return true;
}
@@ -89,13 +77,13 @@ public bool TryRead(out LogEvent evt)
/// The event in compact-JSON.
/// If specified, a JSON serializer used when converting event documents.
/// The log event.
- public static LogEvent ReadFromString(string document, JsonSerializer serializer = null)
+ public LogEvent ReadFromString(string document, JsonSerializer serializer = null)
{
if (document == null) throw new ArgumentNullException(nameof(document));
serializer = serializer ?? CreateSerializer();
var jObject = serializer.Deserialize(new JsonTextReader(new StringReader(document)));
- return ReadFromJObject(jObject);
+ return ReadFromJObject(jObject,_messageFields);
}
@@ -104,44 +92,45 @@ public static LogEvent ReadFromString(string document, JsonSerializer serializer
///
/// The deserialized compact-JSON event.
/// The log event.
- public static LogEvent ReadFromJObject(JObject jObject)
+ public static LogEvent ReadFromJObject(JObject jObject, IMessageFields messageFields)
{
if (jObject == null) throw new ArgumentNullException(nameof(jObject));
- return ReadFromJObject(1, jObject);
+ return ReadFromJObject(1, jObject,messageFields);
}
- static LogEvent ReadFromJObject(int lineNumber, JObject jObject)
+ private static LogEvent ReadFromJObject(int lineNumber, JObject jObject,IMessageFields messageFields)
{
- var timestamp = GetRequiredTimestampField(lineNumber, jObject, ClefFields.Timestamp);
+ var timestamp = GetRequiredTimestampField(lineNumber, jObject, messageFields.Timestamp);
string messageTemplate;
- if (TryGetOptionalField(lineNumber, jObject, ClefFields.MessageTemplate, out var mt))
+ if (TryGetOptionalField(lineNumber, jObject, messageFields.MessageTemplate, out var mt))
messageTemplate = mt;
- else if (TryGetOptionalField(lineNumber, jObject, ClefFields.Message, out var m))
+ else if (TryGetOptionalField(lineNumber, jObject, messageFields.Message, out var m))
messageTemplate = MessageTemplateSyntax.Escape(m);
else
messageTemplate = null;
var level = LogEventLevel.Information;
- if (TryGetOptionalField(lineNumber, jObject, ClefFields.Level, out string l))
+ if (TryGetOptionalField(lineNumber, jObject, messageFields.Level, out string l))
level = (LogEventLevel)Enum.Parse(typeof(LogEventLevel), l);
Exception exception = null;
- if (TryGetOptionalField(lineNumber, jObject, ClefFields.Exception, out string ex))
+ if (TryGetOptionalField(lineNumber, jObject, messageFields.Exception, out string ex))
{
exception = TryPopulateException(ex, exception, jObject);
}
- var parsedTemplate = messageTemplate == null ?
- new MessageTemplate(Enumerable.Empty()) :
- Parser.Parse(messageTemplate);
+ var parsedTemplate = messageTemplate == null
+ ? new MessageTemplate(Enumerable.Empty())
+ : Parser.Parse(messageTemplate);
var renderings = Enumerable.Empty();
- if (jObject.TryGetValue(ClefFields.Renderings, out JToken r))
+ if (jObject.TryGetValue(messageFields.Renderings, out JToken r))
{
var renderedByIndex = r as JArray;
if (renderedByIndex == null)
- throw new InvalidDataException($"The `{ClefFields.Renderings}` value on line {lineNumber} is not an array as expected.");
+ throw new InvalidDataException(
+ $"The `{messageFields.Renderings}` value on line {lineNumber} is not an array as expected.");
renderings = parsedTemplate.Tokens
.OfType()
@@ -150,23 +139,37 @@ static LogEvent ReadFromJObject(int lineNumber, JObject jObject)
.ToArray();
}
- var properties = jObject
- .Properties()
- .Where(f => !ClefFields.All.Contains(f.Name))
- .Select(f =>
- {
- var name = ClefFields.Unescape(f.Name);
- var renderingsByFormat = renderings.Where(rd => rd.Name == name);
- return PropertyFactory.CreateProperty(name, f.Value, renderingsByFormat);
- })
- .ToList();
-
- string eventId;
- if (TryGetOptionalField(lineNumber, jObject, ClefFields.EventId, out eventId)) // TODO; should support numeric ids.
+ List properties;
+ if (jObject.ContainsKey("Properties") && jObject["Properties"] is JObject props)
+ {
+ properties = props.Properties()
+ .Where(f => !messageFields.All.Contains(f.Name))
+ .Select(f =>
+ {
+ var name = messageFields.Unescape(f.Name);
+ var renderingsByFormat = renderings.Where(rd => rd.Name == name).ToList();
+ return PropertyFactory.CreateProperty(name, f.Value, renderingsByFormat);
+ })
+ .ToList();
+ }
+ else
+ {
+ properties = jObject
+ .Properties()
+ .Where(f => !messageFields.All.Contains(f.Name))
+ .Select(f =>
+ {
+ var name = messageFields.Unescape(f.Name);
+ var renderingsByFormat = renderings.Where(rd => rd.Name == name).ToList();
+ return PropertyFactory.CreateProperty(name, f.Value, renderingsByFormat);
+ })
+ .ToList();
+ }
+ if (TryGetOptionalField(lineNumber, jObject, messageFields.EventId, out var eventId)) // TODO; should support numeric ids.
{
properties.Add(new LogEventProperty("@i", new ScalarValue(eventId)));
}
-
+ properties.Add(new LogEventProperty("Raw Data",new ScalarValue(jObject.ToString())));
return new LogEvent(timestamp, level, exception, parsedTemplate, properties);
}
@@ -184,7 +187,7 @@ private static Exception TryPopulateException(string header, Exception exception
return new TextException(header);
}
- static bool TryGetOptionalField(int lineNumber, JObject data, string field, out string value)
+ private static bool TryGetOptionalField(int lineNumber, JObject data, string field, out string value)
{
JToken token;
if (!data.TryGetValue(field, out token) || token.Type == JTokenType.Null)
@@ -200,17 +203,16 @@ static bool TryGetOptionalField(int lineNumber, JObject data, string field, out
return true;
}
- static DateTimeOffset GetRequiredTimestampField(int lineNumber, JObject data, string field)
+ private static DateTimeOffset GetRequiredTimestampField(int lineNumber, JObject data, string field)
{
- JToken token;
- if (!data.TryGetValue(field, out token) || token.Type == JTokenType.Null)
+ if (!data.TryGetValue(field, out var token) || token.Type == JTokenType.Null)
throw new InvalidDataException($"The data on line {lineNumber} does not include the required `{field}` field.");
if (token.Type == JTokenType.Date)
{
var dt = token.Value().Value;
- if (dt is DateTimeOffset)
- return (DateTimeOffset)dt;
+ if (dt is DateTimeOffset offset)
+ return offset;
return (DateTime)dt;
}
@@ -222,7 +224,7 @@ static DateTimeOffset GetRequiredTimestampField(int lineNumber, JObject data, st
return DateTimeOffset.Parse(text);
}
- static JsonSerializer CreateSerializer()
+ private static JsonSerializer CreateSerializer()
{
return JsonSerializer.Create(new JsonSerializerSettings
{
diff --git a/Analogy.LogViewer.Serilog/DataTypes/MessageFields.cs b/Analogy.LogViewer.Serilog/DataTypes/MessageFields.cs
index dc17d18..e4d4829 100644
--- a/Analogy.LogViewer.Serilog/DataTypes/MessageFields.cs
+++ b/Analogy.LogViewer.Serilog/DataTypes/MessageFields.cs
@@ -1,12 +1,113 @@
using System;
-using System.Collections.Generic;
using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace Analogy.LogViewer.Serilog.DataTypes
{
- public class MessageFields
+ public interface IMessageFields
{
+ string Timestamp { get; }
+ string MessageTemplate { get; }
+ string Level { get; }
+ string Exception { get; }
+ string Renderings { get; }
+ string EventId { get; }
+ string Message { get; }
+ string[] All { get; }
+ string[] Required { get; }
+ string Unescape(string name);
+ bool IsUnrecognized(string name);
}
+
+ public class CompactJsonFormatMessageFields : IMessageFields
+ {
+ public string Timestamp { get; }
+ public string MessageTemplate { get; }
+ public string Level { get; }
+ public string Exception { get; }
+ public string Renderings { get; }
+ public string EventId { get; }
+ public string Message { get; }
+ public string[] Required { get; }
+ public string[] All { get; }
+ string Prefix = "@";
+ string EscapedInitialAt = "@@";
+
+ public CompactJsonFormatMessageFields()
+ {
+ Timestamp = "@t";
+ MessageTemplate = "@mt";
+ Level = "@l";
+ Exception = "@x";
+ Renderings = "@r";
+ EventId = "@i";
+ Message = "@m";
+ Prefix = "@";
+ EscapedInitialAt = "@@";
+ All = new[] { Timestamp, MessageTemplate, Level, Exception, Renderings, EventId, Message };
+ Required = new[] { Timestamp, MessageTemplate, Level, Exception, Renderings };
+
+ }
+ public string Unescape(string name)
+ {
+ if (name.StartsWith(EscapedInitialAt))
+ return name.Substring(1);
+
+ return name;
+ }
+
+ public bool IsUnrecognized(string name)
+ {
+ return !name.StartsWith(EscapedInitialAt) &&
+ name.StartsWith(Prefix) &&
+ !All.Contains(name);
+ }
+ }
+
+
+ public class JsonFormatMessageFields : IMessageFields
+ {
+ public string Timestamp { get; }
+ public string MessageTemplate { get; }
+ public string Level { get; }
+ public string Exception { get; }
+ public string Renderings { get; }
+ public string EventId { get; }
+ public string Message { get; }
+
+ public string[] All { get; }
+ public string[] Required { get; }
+ string Prefix = "@";
+ string EscapedInitialAt = "@@";
+
+ public JsonFormatMessageFields()
+ {
+ Timestamp = "Timestamp";
+ MessageTemplate = "MessageTemplate";
+ Level = "Level";
+ Exception = "Exception";
+ Renderings = "RenderedMessage";
+ EventId = "@i";
+ Message = "@m";
+ All = new[] { Timestamp, MessageTemplate, Level, Exception, Renderings, EventId, Message };
+ Required = new[] { Timestamp, MessageTemplate, Level, Exception, Renderings };
+
+ }
+ public string Unescape(string name)
+ {
+ if (name.StartsWith(EscapedInitialAt))
+ return name.Substring(1);
+
+ return name;
+ }
+
+ public bool IsUnrecognized(string name)
+ {
+ return !name.StartsWith(EscapedInitialAt) &&
+ name.StartsWith(Prefix) &&
+ !All.Contains(name);
+ }
+ }
+
+
}
+
diff --git a/Analogy.LogViewer.Serilog/CompactClef/MessageTemplateSyntax.cs b/Analogy.LogViewer.Serilog/DataTypes/MessageTemplateSyntax.cs
similarity index 85%
rename from Analogy.LogViewer.Serilog/CompactClef/MessageTemplateSyntax.cs
rename to Analogy.LogViewer.Serilog/DataTypes/MessageTemplateSyntax.cs
index c9e5746..7ed2e8c 100644
--- a/Analogy.LogViewer.Serilog/CompactClef/MessageTemplateSyntax.cs
+++ b/Analogy.LogViewer.Serilog/DataTypes/MessageTemplateSyntax.cs
@@ -1,6 +1,6 @@
using System;
-namespace Analogy.LogViewer.Serilog.CompactClef
+namespace Analogy.LogViewer.Serilog.DataTypes
{
static class MessageTemplateSyntax
{
diff --git a/Analogy.LogViewer.Serilog/CompactClef/PropertyFactory.cs b/Analogy.LogViewer.Serilog/DataTypes/PropertyFactory.cs
similarity index 93%
rename from Analogy.LogViewer.Serilog/CompactClef/PropertyFactory.cs
rename to Analogy.LogViewer.Serilog/DataTypes/PropertyFactory.cs
index 281e599..c4d97ff 100644
--- a/Analogy.LogViewer.Serilog/CompactClef/PropertyFactory.cs
+++ b/Analogy.LogViewer.Serilog/DataTypes/PropertyFactory.cs
@@ -12,23 +12,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-using Newtonsoft.Json.Linq;
-using Serilog.Events;
using System.Collections.Generic;
using System.Linq;
+using Newtonsoft.Json.Linq;
+using Serilog.Events;
-namespace Analogy.LogViewer.Serilog.CompactClef
+namespace Analogy.LogViewer.Serilog.DataTypes
{
static class PropertyFactory
{
const string TypeTagPropertyName = "$type";
- public static LogEventProperty CreateProperty(string name, JToken value, IEnumerable renderings)
+ public static LogEventProperty CreateProperty(string name, JToken value, List renderings)
{
return new LogEventProperty(name, CreatePropertyValue(value, renderings));
}
- static LogEventPropertyValue CreatePropertyValue(JToken value, IEnumerable renderings)
+ static LogEventPropertyValue CreatePropertyValue(JToken value, List renderings)
{
if (value.Type == JTokenType.Null)
return new ScalarValue(null);
diff --git a/Analogy.LogViewer.Serilog/CompactClef/RenderableScalarValue.cs b/Analogy.LogViewer.Serilog/DataTypes/RenderableScalarValue.cs
similarity index 52%
rename from Analogy.LogViewer.Serilog/CompactClef/RenderableScalarValue.cs
rename to Analogy.LogViewer.Serilog/DataTypes/RenderableScalarValue.cs
index 4bd7039..079126a 100644
--- a/Analogy.LogViewer.Serilog/CompactClef/RenderableScalarValue.cs
+++ b/Analogy.LogViewer.Serilog/DataTypes/RenderableScalarValue.cs
@@ -1,29 +1,15 @@
-// Copyright 2013-2015 Serilog Contributors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using Serilog.Events;
-using System;
+using System;
using System.Collections.Generic;
using System.IO;
+using Serilog.Events;
-namespace Analogy.LogViewer.Serilog.CompactClef
+namespace Analogy.LogViewer.Serilog.DataTypes
{
class RenderableScalarValue : ScalarValue
{
readonly Dictionary _renderings = new Dictionary();
- public RenderableScalarValue(object value, IEnumerable renderings)
+ public RenderableScalarValue(object value, List renderings)
: base(value)
{
if (renderings == null) throw new ArgumentNullException(nameof(renderings));
diff --git a/Analogy.LogViewer.Serilog/DataTypes/Rendering.cs b/Analogy.LogViewer.Serilog/DataTypes/Rendering.cs
new file mode 100644
index 0000000..1652ece
--- /dev/null
+++ b/Analogy.LogViewer.Serilog/DataTypes/Rendering.cs
@@ -0,0 +1,17 @@
+
+namespace Analogy.LogViewer.Serilog.DataTypes
+{
+ class Rendering
+ {
+ public string Name { get; }
+ public string Format { get; }
+ public string Rendered { get; }
+
+ public Rendering(string name, string format, string rendered)
+ {
+ Name = name;
+ Format = format;
+ Rendered = rendered;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Analogy.LogViewer.Serilog/CompactClef/TextException.cs b/Analogy.LogViewer.Serilog/DataTypes/TextException.cs
similarity index 95%
rename from Analogy.LogViewer.Serilog/CompactClef/TextException.cs
rename to Analogy.LogViewer.Serilog/DataTypes/TextException.cs
index 8ce81d8..7b853ac 100644
--- a/Analogy.LogViewer.Serilog/CompactClef/TextException.cs
+++ b/Analogy.LogViewer.Serilog/DataTypes/TextException.cs
@@ -14,7 +14,7 @@
using System;
-namespace Analogy.LogViewer.Serilog.CompactClef
+namespace Analogy.LogViewer.Serilog.DataTypes
{
class TextException : Exception
{
diff --git a/Analogy.LogViewer.Serilog/IAnalogy/DataProvidersFactory.cs b/Analogy.LogViewer.Serilog/IAnalogy/DataProvidersFactory.cs
index f650dd5..91bac30 100644
--- a/Analogy.LogViewer.Serilog/IAnalogy/DataProvidersFactory.cs
+++ b/Analogy.LogViewer.Serilog/IAnalogy/DataProvidersFactory.cs
@@ -1,10 +1,9 @@
-using Analogy.Interfaces;
-using Analogy.Interfaces.Factories;
-using Analogy.LogViewer.Serilog.IAnalogy;
-using System;
+using System;
using System.Collections.Generic;
+using Analogy.Interfaces;
+using Analogy.Interfaces.Factories;
-namespace Analogy.LogViewer.Serilog
+namespace Analogy.LogViewer.Serilog.IAnalogy
{
public class DataProvidersFactory : IAnalogyDataProvidersFactory
{
diff --git a/Analogy.LogViewer.Serilog/IAnalogy/OfflineDataProvider.cs b/Analogy.LogViewer.Serilog/IAnalogy/OfflineDataProvider.cs
index 4903f24..4014d47 100644
--- a/Analogy.LogViewer.Serilog/IAnalogy/OfflineDataProvider.cs
+++ b/Analogy.LogViewer.Serilog/IAnalogy/OfflineDataProvider.cs
@@ -1,11 +1,14 @@
using Analogy.Interfaces;
+using Analogy.LogViewer.Serilog.DataTypes;
using Analogy.LogViewer.Serilog.Managers;
-using Analogy.LogViewer.Serilog.Regex;
+using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
+using System.IO.Compression;
using System.Linq;
+using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -29,10 +32,10 @@ public class OfflineDataProvider : IAnalogyOfflineDataProvider
Directory.Exists(UserSettingsManager.UserSettings.Settings.Directory))
? UserSettingsManager.UserSettings.Settings.Directory
: Environment.CurrentDirectory;
- private ClefParser ClefParser { get; }
+ private CompactJsonFormatParser CompactFormatPerLineParser { get; }
+ private JsonFormatterParser JsonPerLineParser { get; }
+ private JsonFileParser CompactJsonFileParser { get; }
private JsonFileParser JsonFileParser { get; }
- private JsonFormatterParser JsonFormatterParser { get; }
- private Regex.RegexParser RegexParser { get; set; }
public bool UseCustomColors { get; set; } = false;
public IEnumerable<(string originalHeader, string replacementHeader)> GetReplacementHeaders()
@@ -42,33 +45,99 @@ public class OfflineDataProvider : IAnalogyOfflineDataProvider
=> (Color.Empty, Color.Empty);
public OfflineDataProvider()
{
- ClefParser = new ClefParser();
- JsonFileParser = new JsonFileParser();
- JsonFormatterParser=new JsonFormatterParser();
- RegexParser = new Regex.RegexParser(UserSettingsManager.UserSettings.Settings.RegexPatterns, false,
- LogManager.Instance);
+ CompactFormatPerLineParser = new CompactJsonFormatParser();
+ CompactJsonFileParser = new JsonFileParser(new CompactJsonFormatMessageFields());
+
+ JsonPerLineParser = new JsonFormatterParser(new JsonFormatMessageFields());
+ JsonFileParser = new JsonFileParser(new JsonFormatMessageFields());
}
public async Task> Process(string fileName, CancellationToken token, ILogMessageCreatedHandler messagesHandler)
{
if (CanOpenFile(fileName))
{
+ if (UserSettingsManager.UserSettings.Settings.FileFormatDetection==FileFormatDetection.Automatic ||
+ UserSettingsManager.UserSettings.Settings.Format == FileFormat.Unknown)
+ UserSettingsManager.UserSettings.Settings.Format = TryDetectFormat(fileName);
+
switch (UserSettingsManager.UserSettings.Settings.Format)
{
- case SerilogFileFormat.CLEF:
- return await ClefParser.Process(fileName, token, messagesHandler);
- case SerilogFileFormat.JSONFile:
+ case FileFormat.CompactJsonFormatPerLine:
+ return await CompactFormatPerLineParser.Process(fileName, token, messagesHandler);
+ case FileFormat.CompactJsonFormatPerFile:
+ return await CompactJsonFileParser.Process(fileName, token, messagesHandler);
+ case FileFormat.JsonFormatFile:
return await JsonFileParser.Process(fileName, token, messagesHandler);
- case SerilogFileFormat.JSONPerLine:
- return await JsonFormatterParser.Process(fileName, token, messagesHandler);
- case SerilogFileFormat.REGEX:
- RegexParser.SetRegexPatterns(UserSettingsManager.UserSettings.Settings.RegexPatterns);
- return await RegexParser.ParseLog(fileName, token, messagesHandler);
+ case FileFormat.JsonFormatPerLine:
+ return await JsonPerLineParser.Process(fileName, token, messagesHandler);
}
}
+ LogManager.Instance.LogError($"Unsupported File {fileName}", nameof(OfflineDataProvider));
return new List(0);
}
+ public static FileFormat TryDetectFormat(string fileName)
+ {
+ string jsonData = string.Empty;
+ if (fileName.EndsWith(".gz", StringComparison.InvariantCultureIgnoreCase))
+ {
+ using (var fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
+ {
+ using (var gzStream = new GZipStream(fileStream, CompressionMode.Decompress))
+ {
+ using (var streamReader = new StreamReader(gzStream, encoding: Encoding.UTF8))
+ {
+ jsonData = streamReader.ReadToEnd();
+ }
+ }
+ }
+ }
+
+ if (string.IsNullOrEmpty(jsonData))
+ jsonData = File.ReadAllText(fileName);
+ var format = TryParseAsFile(jsonData);
+ if (format == FileFormat.Unknown)
+ format = TryParsePerLine(jsonData);
+ return format;
+ }
+
+ private static FileFormat TryParsePerLine(string jsonData)
+ {
+ try
+ {
+ IMessageFields fields = new JsonFormatMessageFields();
+ if (jsonData.Contains(fields.Timestamp) && jsonData.Contains(fields.MessageTemplate))
+ return FileFormat.JsonFormatPerLine;
+ fields = new CompactJsonFormatMessageFields();
+ if (jsonData.Contains(fields.Timestamp) && jsonData.Contains(fields.MessageTemplate))
+ return FileFormat.CompactJsonFormatPerLine;
+ return FileFormat.Unknown;
+ }
+ catch (Exception)
+ {
+ return FileFormat.Unknown;
+ }
+ }
+
+ private static FileFormat TryParseAsFile(string jsonData)
+ {
+ try
+ {
+ var jsonObject = JsonConvert.DeserializeObject(jsonData);
+ IMessageFields fields = new JsonFormatMessageFields();
+ if (jsonData.Contains(fields.Timestamp) && jsonData.Contains(fields.MessageTemplate))
+ return FileFormat.JsonFormatFile;
+ fields = new CompactJsonFormatMessageFields();
+ if (jsonData.Contains(fields.Timestamp) && jsonData.Contains(fields.MessageTemplate))
+ return FileFormat.CompactJsonFormatPerFile;
+ return FileFormat.Unknown;
+ }
+ catch (Exception)
+ {
+ return FileFormat.Unknown;
+ }
+ }
+
public IEnumerable GetSupportedFiles(DirectoryInfo dirInfo, bool recursiveLoad)
=> GetSupportedFilesInternal(dirInfo, recursiveLoad);
diff --git a/Analogy.LogViewer.Serilog/JsonFormatterParser.cs b/Analogy.LogViewer.Serilog/JsonFormatterParser.cs
deleted file mode 100644
index 20ae12c..0000000
--- a/Analogy.LogViewer.Serilog/JsonFormatterParser.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Runtime.CompilerServices;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using Analogy.Interfaces;
-using Analogy.LogViewer.Serilog.CompactClef;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using Serilog;
-using Serilog.Formatting.Json;
-
-namespace Analogy.LogViewer.Serilog
-{
- public class JsonFormatterParser
- {
- public async Task> Process(string fileName, CancellationToken token,
- ILogMessageCreatedHandler messagesHandler)
- {
- var formatter = new JsonFormatter();
- List parsedMessages = new List();
- try
- {
- using (var analogy = new LoggerConfiguration().WriteTo.Analogy(formatter)
- .CreateLogger())
- {
- using (var fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
- using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
- {
- var json = await streamReader.ReadLineAsync().ConfigureAwait(false);
- var data = JsonConvert.DeserializeObject(json);
- if (data is JObject jo)
- {
- var m = ParserJObject(jo, analogy);
- parsedMessages.Add(m);
- }
- else if (data is JArray arr)
- {
- foreach (var obj in arr.ToList())
- {
- if (obj is JObject j)
- {
-
- var m = ParserJObject(j, analogy);
- parsedMessages.Add(m);
- }
- }
- }
- }
- }
-
- messagesHandler.AppendMessages(parsedMessages, fileName);
- return parsedMessages;
- }
-
- catch (Exception e)
- {
- AnalogyLogMessage empty = new AnalogyLogMessage($"Error reading file {fileName}: Error: {e.Message}", AnalogyLogLevel.Error, AnalogyLogClass.General, "Analogy", "None");
- empty.Source = nameof(ClefParser);
- empty.Module = "Analogy.LogViewer.Serilog";
- parsedMessages.Add(empty);
- messagesHandler.AppendMessages(parsedMessages, fileName);
- return parsedMessages;
- }
- }
-
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private AnalogyLogMessage ParserJObject(JObject jo, ILogger analogy)
- {
- var evt = LogEventReader.ReadFromJObject(jo);
- {
- analogy.Write(evt);
- return CommonParser.ParseLogEventProperties(evt);
-
- }
-
- }
-
- }
-}
\ No newline at end of file
diff --git a/Analogy.LogViewer.Serilog/CommonParser.cs b/Analogy.LogViewer.Serilog/Parsers/CommonParser.cs
similarity index 98%
rename from Analogy.LogViewer.Serilog/CommonParser.cs
rename to Analogy.LogViewer.Serilog/Parsers/CommonParser.cs
index db86406..eea68bd 100644
--- a/Analogy.LogViewer.Serilog/CommonParser.cs
+++ b/Analogy.LogViewer.Serilog/Parsers/CommonParser.cs
@@ -41,7 +41,7 @@ public static AnalogyLogMessage ParseLogEventProperties(LogEvent evt)
}
m.Date = evt.Timestamp.DateTime;
- m.Text = AnalogySink.output;
+ m.Text = AnalogySink.output;// evt.MessageTemplate.Text;
if (evt.Properties.TryGetValue(Constants.ProcessName, out var processName))
{
if (processName is ScalarValue scalarValue &&
diff --git a/Analogy.LogViewer.Serilog/ClefParser.cs b/Analogy.LogViewer.Serilog/Parsers/CompactJsonFormatParser.cs
similarity index 70%
rename from Analogy.LogViewer.Serilog/ClefParser.cs
rename to Analogy.LogViewer.Serilog/Parsers/CompactJsonFormatParser.cs
index 53ba43d..68eea72 100644
--- a/Analogy.LogViewer.Serilog/ClefParser.cs
+++ b/Analogy.LogViewer.Serilog/Parsers/CompactJsonFormatParser.cs
@@ -1,5 +1,5 @@
using Analogy.Interfaces;
-using Analogy.LogViewer.Serilog.CompactClef;
+using Analogy.LogViewer.Serilog.DataTypes;
using Serilog;
using System;
using System.Collections.Generic;
@@ -11,8 +11,14 @@
namespace Analogy.LogViewer.Serilog
{
- public class ClefParser
+ public class CompactJsonFormatParser
{
+ private static IMessageFields messageFields;
+
+ static CompactJsonFormatParser()
+ {
+ messageFields = new CompactJsonFormatMessageFields();
+ }
public async Task> Process(string fileName, CancellationToken token, ILogMessageCreatedHandler messagesHandler)
{
var messages = await Task>.Factory.StartNew(() =>
@@ -30,10 +36,10 @@ public async Task> Process(string fileName, Cance
{
using (var gzStream = new GZipStream(fileStream, CompressionMode.Decompress))
{
- using (var clef = new StreamReader(gzStream, encoding: Encoding.UTF8))
+ using (var streamReader = new StreamReader(gzStream, encoding: Encoding.UTF8))
{
- var reader = new LogEventReader(clef);
- while (reader.TryRead(out var evt))
+ var reader = new LogEventReader(streamReader, messageFields);
+ while (reader.TryRead(out var evt) && !token.IsCancellationRequested)
{
analogy.Write(evt);
AnalogyLogMessage m = CommonParser.ParseLogEventProperties(evt);
@@ -45,21 +51,19 @@ public async Task> Process(string fileName, Cance
}
}
}
- else
+
+ using (var streamReader = new StreamReader(fileStream, encoding: Encoding.UTF8))
{
- using (var clef = new StreamReader(fileStream, encoding: Encoding.UTF8))
+ var reader = new LogEventReader(streamReader, messageFields);
+ while (reader.TryRead(out var evt))
{
- var reader = new LogEventReader(clef);
- while (reader.TryRead(out var evt))
- {
- analogy.Write(evt);
- AnalogyLogMessage m = CommonParser.ParseLogEventProperties(evt);
- parsedMessages.Add(m);
- }
-
- messagesHandler.AppendMessages(parsedMessages, fileName);
- return parsedMessages;
+ analogy.Write(evt);
+ AnalogyLogMessage m = CommonParser.ParseLogEventProperties(evt);
+ parsedMessages.Add(m);
}
+
+ messagesHandler.AppendMessages(parsedMessages, fileName);
+ return parsedMessages;
}
}
}
@@ -69,7 +73,7 @@ public async Task> Process(string fileName, Cance
{
AnalogyLogMessage empty = new AnalogyLogMessage($"Error reading file {fileName}: Error: {e.Message}",
AnalogyLogLevel.Error, AnalogyLogClass.General, "Analogy", "None");
- empty.Source = nameof(ClefParser);
+ empty.Source = nameof(CompactJsonFormatParser);
empty.Module = "Analogy.LogViewer.Serilog";
parsedMessages.Add(empty);
messagesHandler.AppendMessages(parsedMessages, fileName);
diff --git a/Analogy.LogViewer.Serilog/JsonFileParser.cs b/Analogy.LogViewer.Serilog/Parsers/JsonFileParser.cs
similarity index 59%
rename from Analogy.LogViewer.Serilog/JsonFileParser.cs
rename to Analogy.LogViewer.Serilog/Parsers/JsonFileParser.cs
index 0b4b801..480a371 100644
--- a/Analogy.LogViewer.Serilog/JsonFileParser.cs
+++ b/Analogy.LogViewer.Serilog/Parsers/JsonFileParser.cs
@@ -1,14 +1,13 @@
using Analogy.Interfaces;
-using Analogy.LogViewer.Serilog.CompactClef;
+using Analogy.LogViewer.Serilog.DataTypes;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Serilog;
-using Serilog.Formatting;
using System;
using System.Collections.Generic;
using System.IO;
+using System.IO.Compression;
using System.Linq;
-using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -17,7 +16,12 @@ namespace Analogy.LogViewer.Serilog
{
public class JsonFileParser
{
- public static ITextFormatter textFormatter;
+ private IMessageFields messageFields;
+
+ public JsonFileParser(IMessageFields messageFields)
+ {
+ this.messageFields = messageFields;
+ }
public async Task> Process(string fileName, CancellationToken token, ILogMessageCreatedHandler messagesHandler)
{
var messages = await Task>.Factory.StartNew(() =>
@@ -30,14 +34,34 @@ public async Task> Process(string fileName, Cance
.CreateLogger())
{
using (var fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
- using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
{
- var json = streamReader.ReadToEnd();
- var data = JsonConvert.DeserializeObject(json);
+ string jsonData;
+ if (fileName.EndsWith(".gz", StringComparison.InvariantCultureIgnoreCase))
+ {
+ using (var gzStream = new GZipStream(fileStream, CompressionMode.Decompress))
+ {
+ using (var streamReader = new StreamReader(gzStream, encoding: Encoding.UTF8))
+ {
+ jsonData = streamReader.ReadToEnd();
+
+ }
+ }
+ }
+ else
+ using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
+ {
+ jsonData = streamReader.ReadToEnd();
+ }
+
+
+ var data = JsonConvert.DeserializeObject(jsonData);
if (data is JObject jo)
{
- var m = ParserJObject(jo, analogy);
+ var evt = LogEventReader.ReadFromJObject(jo, messageFields);
+ analogy.Write(evt);
+ AnalogyLogMessage m = CommonParser.ParseLogEventProperties(evt);
parsedMessages.Add(m);
+
}
else if (data is JArray arr)
{
@@ -45,8 +69,11 @@ public async Task> Process(string fileName, Cance
{
if (obj is JObject j)
{
- var m = ParserJObject(j, analogy);
+ var evt = LogEventReader.ReadFromJObject(j, messageFields);
+ analogy.Write(evt);
+ AnalogyLogMessage m = CommonParser.ParseLogEventProperties(evt);
parsedMessages.Add(m);
+
}
}
}
@@ -61,7 +88,7 @@ public async Task> Process(string fileName, Cance
{
AnalogyLogMessage empty = new AnalogyLogMessage($"Error reading file {fileName}: Error: {e.Message}",
AnalogyLogLevel.Error, AnalogyLogClass.General, "Analogy", "None");
- empty.Source = nameof(ClefParser);
+ empty.Source = nameof(CompactJsonFormatParser);
empty.Module = "Analogy.LogViewer.Serilog";
parsedMessages.Add(empty);
messagesHandler.AppendMessages(parsedMessages, fileName);
@@ -70,17 +97,5 @@ public async Task> Process(string fileName, Cance
});
return messages;
}
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private AnalogyLogMessage ParserJObject(JObject jo, ILogger analogy)
- {
- var evt = LogEventReader.ReadFromJObject(jo);
- {
- analogy.Write(evt);
- return CommonParser.ParseLogEventProperties(evt);
-
- }
-
- }
-
}
}
diff --git a/Analogy.LogViewer.Serilog/Parsers/JsonFormatterParser.cs b/Analogy.LogViewer.Serilog/Parsers/JsonFormatterParser.cs
new file mode 100644
index 0000000..cdea2ad
--- /dev/null
+++ b/Analogy.LogViewer.Serilog/Parsers/JsonFormatterParser.cs
@@ -0,0 +1,104 @@
+using Analogy.Interfaces;
+using Analogy.LogViewer.Serilog.DataTypes;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using Serilog;
+using Serilog.Formatting.Json;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.IO.Compression;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Analogy.LogViewer.Serilog
+{
+ public class JsonFormatterParser
+ {
+ private IMessageFields messageFields;
+ private JsonSerializerSettings JsonSerializerSettings;
+
+ public JsonFormatterParser(IMessageFields messageFields)
+ {
+ this.messageFields = messageFields;
+ JsonSerializerSettings = new JsonSerializerSettings
+ {
+ DateParseHandling=DateParseHandling.DateTimeOffset,
+ DateFormatHandling = DateFormatHandling.IsoDateFormat,
+ DateTimeZoneHandling = DateTimeZoneHandling.Utc,
+ };
+
+ }
+ public async Task> Process(string fileName, CancellationToken token,
+ ILogMessageCreatedHandler messagesHandler)
+ {
+ //var formatter = new JsonFormatter();
+ List parsedMessages = new List();
+ try
+ {
+ using (var analogy = new LoggerConfiguration().WriteTo.Analogy()
+ .CreateLogger())
+ {
+ using (var fileStream =
+ new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
+ {
+
+ if (fileName.EndsWith(".gz", StringComparison.InvariantCultureIgnoreCase))
+ {
+ using (var gzStream = new GZipStream(fileStream, CompressionMode.Decompress))
+ {
+ using (var streamReader = new StreamReader(gzStream, encoding: Encoding.UTF8))
+ {
+ string json;
+ while ((json = await streamReader.ReadLineAsync()) != null)
+ {
+
+ var data = JsonConvert.DeserializeObject(json, JsonSerializerSettings);
+ var evt = LogEventReader.ReadFromJObject(data as JObject, messageFields);
+ {
+ analogy.Write(evt);
+ AnalogyLogMessage m = CommonParser.ParseLogEventProperties(evt);
+ parsedMessages.Add(m);
+ }
+ }
+
+ }
+ }
+ }
+
+
+ using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
+ {
+ string json;
+ while ((json = await streamReader.ReadLineAsync()) != null)
+ {
+ var data = JsonConvert.DeserializeObject(json);
+ var evt = LogEventReader.ReadFromJObject(data as JObject, messageFields);
+ {
+ analogy.Write(evt);
+ AnalogyLogMessage m = CommonParser.ParseLogEventProperties(evt);
+ parsedMessages.Add(m);
+ }
+ }
+ }
+
+ }
+
+ messagesHandler.AppendMessages(parsedMessages, fileName);
+ return parsedMessages;
+ }
+ }
+ catch (Exception e)
+ {
+ AnalogyLogMessage empty = new AnalogyLogMessage($"Error reading file {fileName}: Error: {e.Message}",
+ AnalogyLogLevel.Error, AnalogyLogClass.General, "Analogy", "None");
+ empty.Source = nameof(CompactJsonFormatParser);
+ empty.Module = "Analogy.LogViewer.Serilog";
+ parsedMessages.Add(empty);
+ messagesHandler.AppendMessages(parsedMessages, fileName);
+ return parsedMessages;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Analogy.LogViewer.Serilog/Properties/Resources.Designer.cs b/Analogy.LogViewer.Serilog/Properties/Resources.Designer.cs
index d285231..097f4cd 100644
--- a/Analogy.LogViewer.Serilog/Properties/Resources.Designer.cs
+++ b/Analogy.LogViewer.Serilog/Properties/Resources.Designer.cs
@@ -90,6 +90,88 @@ internal static System.Drawing.Bitmap AnalogySerilog32x32 {
}
}
+ ///
+ /// Looks up a localized string similar to [
+ /// {
+ /// "@t": "2019-12-10T13:33:23.0970926Z",
+ /// "@mt": "An unknown error occurred",
+ /// "@l": "Error",
+ /// "@x": "Exception stack trace",
+ /// "SourceContext": "MySourceContext",
+ /// "Scope": [
+ /// "FirstScope",
+ /// 1850562557,
+ /// "198441851"
+ /// ],
+ /// "MachineName": "MY-MACHINE",
+ /// "EnvironmentUserName": "WORKGROUP\\SYSTEM",
+ /// "ExceptionDetail": {
+ /// "HResult": -2146233087,
+ /// "Message": "Internal Error",
+ /// "Source": "System.ServiceModel",
+ /// "Action": null,
+ /// [rest of string was truncated]";.
+ ///
+ internal static string CompactJsonFormatPerFile {
+ get {
+ return ResourceManager.GetString("CompactJsonFormatPerFile", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to {"@t":"2016-10-12T04:46:58.0554314Z","@mt":"Hello, {@User}","User":{"Name":"nblumhardt","Id":101}}
+ ///{"@t":"2016-10-12T04:46:58.0684369Z","@mt":"Number {N:x8}","@r":["0000002a"],"N":42}
+ ///{"@t":"2016-10-12T04:46:58.0724384Z","@mt":"Tags are {Tags}","@l":"Warning","Tags":["test","orange"]}
+ ///{"@t":"2016-10-12T04:46:58.0904378Z","@mt":"Something failed","@l":"Error", "@x":"System.DivideByZer...<snip>"}.
+ ///
+ internal static string CompactJsonFormatPerLine {
+ get {
+ return ResourceManager.GetString("CompactJsonFormatPerLine", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to [
+ /// {
+ /// "Timestamp": "2020-06-07T13:44:57.8532799+10:00",
+ /// "Level": "Information",
+ /// "MessageTemplate": "Hello, {@User}, {N:x8} at {Now}",
+ /// "Properties": {
+ /// "User": {
+ /// "Name": "nblumhardt",
+ /// "Tags": [ 1, 2, 3 ]
+ /// },
+ /// "N": 123,
+ /// "Now": "2016-06-07T13:44:57.8532799+10:00"
+ /// },
+ /// "Renderings": {
+ /// "N": [
+ /// {
+ /// "Format": "x8",
+ /// "Rendering": "0000007b"
+ /// }
+ /// ]
+ /// }
+ /// },
+ /// {
+ /// "Timestamp": "2016-06-07T13: [rest of string was truncated]";.
+ ///
+ internal static string JsonFormatFile {
+ get {
+ return ResourceManager.GetString("JsonFormatFile", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to {"Timestamp":"2020-06-07T13:44:57.8532799+10:00","Level":"Information","MessageTemplate":"Hello, {@User}, {N:x8} at {Now}","Properties":{"User":{"Name":"nblumhardt","Tags":[1,2,3]},"N":123,"Now":"2016-06-07T13:44:57.8532799+10:00"},"Renderings":{"N":[{"Format":"x8","Rendering":"0000007b"}]}}
+ ///{"Timestamp":"2016-06-07T13:44:57.8532799+10:00","Level":"Information","MessageTemplate":"Hello, {@User}, {N:x8} at {Now}","Properties":{"User":{"Name":"Lior","Tags":[1,2,3]},"N":123,"Now":"2016-06-07T13:44:57.8532799+ [rest of string was truncated]";.
+ ///
+ internal static string JsonFormatPerLine {
+ get {
+ return ResourceManager.GetString("JsonFormatPerLine", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized resource of type System.Drawing.Bitmap.
///
diff --git a/Analogy.LogViewer.Serilog/Properties/Resources.resx b/Analogy.LogViewer.Serilog/Properties/Resources.resx
index e785147..d091ea6 100644
--- a/Analogy.LogViewer.Serilog/Properties/Resources.resx
+++ b/Analogy.LogViewer.Serilog/Properties/Resources.resx
@@ -127,6 +127,145 @@
..\Resources\AnalogySerilog32x32.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+ [
+ {
+ "@t": "2019-12-10T13:33:23.0970926Z",
+ "@mt": "An unknown error occurred",
+ "@l": "Error",
+ "@x": "Exception stack trace",
+ "SourceContext": "MySourceContext",
+ "Scope": [
+ "FirstScope",
+ 1850562557,
+ "198441851"
+ ],
+ "MachineName": "MY-MACHINE",
+ "EnvironmentUserName": "WORKGROUP\\SYSTEM",
+ "ExceptionDetail": {
+ "HResult": -2146233087,
+ "Message": "Internal Error",
+ "Source": "System.ServiceModel",
+ "Action": null,
+ "Code": {
+ "IsPredefinedFault": true,
+ "IsSenderFault": true,
+ "IsReceiverFault": false,
+ "Namespace": "http://schemas.xmlsoap.org/soap/envelope/",
+ "Name": "Client",
+ "SubCode": null
+ },
+ "Reason": {
+ "Translations": [
+ {
+ "XmlLang": "",
+ "Text": "Internal Error"
+ }
+ ]
+ },
+ "Type": "System.ServiceModel.FaultException"
+ },
+ "AssemblyVersion": "2.1.0.1017"
+ },
+ {
+ "@t": "2019-12-10T13:33:23.0970926Z",
+ "@mt": "An unknown error occurred",
+ "@l": "Error",
+ "@x": "Exception stack trace",
+ "SourceContext": "MySourceContext",
+ "Scope": [
+ "FirstScope",
+ 1850562557,
+ "198441851"
+ ],
+ "MachineName": "MY-MACHINE",
+ "ProcessId": 11,
+ "ProcessName": "My process",
+ "ThreadId": 1,
+ "EnvironmentUserName": "WORKGROUP\\SYSTEM",
+ "ExceptionDetail": {
+ "HResult": -2146233087,
+ "Message": "Internal Error",
+ "Source": "System.ServiceModel",
+ "Action": null,
+ "Code": {
+ "IsPredefinedFault": true,
+ "IsSenderFault": true,
+ "IsReceiverFault": false,
+ "Namespace": "http://schemas.xmlsoap.org/soap/envelope/",
+ "Name": "Client",
+ "SubCode": null
+ },
+ "Reason": {
+ "Translations": [
+ {
+ "XmlLang": "",
+ "Text": "Internal Error"
+ }
+ ]
+ },
+ "Type": "System.ServiceModel.FaultException"
+ },
+ "AssemblyVersion": "2.1.0.1017"
+ }
+]
+
+
+ {"@t":"2016-10-12T04:46:58.0554314Z","@mt":"Hello, {@User}","User":{"Name":"nblumhardt","Id":101}}
+{"@t":"2016-10-12T04:46:58.0684369Z","@mt":"Number {N:x8}","@r":["0000002a"],"N":42}
+{"@t":"2016-10-12T04:46:58.0724384Z","@mt":"Tags are {Tags}","@l":"Warning","Tags":["test","orange"]}
+{"@t":"2016-10-12T04:46:58.0904378Z","@mt":"Something failed","@l":"Error", "@x":"System.DivideByZer...<snip>"}
+
+
+ [
+ {
+ "Timestamp": "2020-06-07T13:44:57.8532799+10:00",
+ "Level": "Information",
+ "MessageTemplate": "Hello, {@User}, {N:x8} at {Now}",
+ "Properties": {
+ "User": {
+ "Name": "nblumhardt",
+ "Tags": [ 1, 2, 3 ]
+ },
+ "N": 123,
+ "Now": "2016-06-07T13:44:57.8532799+10:00"
+ },
+ "Renderings": {
+ "N": [
+ {
+ "Format": "x8",
+ "Rendering": "0000007b"
+ }
+ ]
+ }
+ },
+ {
+ "Timestamp": "2016-06-07T13:44:57.8532799+10:00",
+ "Level": "Information",
+ "MessageTemplate": "Hello, {@User}, {N:x8} at {Now}",
+ "Properties": {
+ "User": {
+ "Name": "Lior",
+ "Tags": [ 1, 2, 3 ]
+ },
+ "N": 123,
+ "Now": "2016-06-07T13:44:57.8532799+10:00"
+ },
+ "Renderings": {
+ "N": [
+ {
+ "Format": "x8",
+ "Rendering": "0000007b"
+ }
+ ]
+ }
+ }
+]
+
+
+ {"Timestamp":"2020-06-07T13:44:57.8532799+10:00","Level":"Information","MessageTemplate":"Hello, {@User}, {N:x8} at {Now}","Properties":{"User":{"Name":"nblumhardt","Tags":[1,2,3]},"N":123,"Now":"2016-06-07T13:44:57.8532799+10:00"},"Renderings":{"N":[{"Format":"x8","Rendering":"0000007b"}]}}
+{"Timestamp":"2016-06-07T13:44:57.8532799+10:00","Level":"Information","MessageTemplate":"Hello, {@User}, {N:x8} at {Now}","Properties":{"User":{"Name":"Lior","Tags":[1,2,3]},"N":123,"Now":"2016-06-07T13:44:57.8532799+10:00"},"Renderings":{"N":[{"Format":"x8","Rendering":"0000007b"}]}}
+
..\Resources\Serilog_icon.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
diff --git a/Analogy.LogViewer.Serilog/Regex/RegexParser.cs b/Analogy.LogViewer.Serilog/Regex/RegexParser.cs
deleted file mode 100644
index ff0745a..0000000
--- a/Analogy.LogViewer.Serilog/Regex/RegexParser.cs
+++ /dev/null
@@ -1,405 +0,0 @@
-using Analogy.Interfaces;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Runtime.CompilerServices;
-using System.Text.RegularExpressions;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Analogy.LogViewer.Serilog.Regex
-{
- public class RegexParser
- {
- private AnalogyLogMessage _current;
- private RegexPattern _lastUsedPattern;
- private readonly List _messages = new List();
- private List _logPatterns;
- private readonly bool updateUIAfterEachParsedLine;
- private IAnalogyLogger Logger { get; }
-
- private IEnumerable LogPatterns
- {
- get
- {
- if (_lastUsedPattern != null)
- yield return _lastUsedPattern;
- var oldLastUsedPattern = _lastUsedPattern;
- foreach (var logPattern in _logPatterns)
- {
- //skip last used pattern (returned first)
- if (oldLastUsedPattern == logPattern) continue;
- _lastUsedPattern = logPattern;
- yield return _lastUsedPattern;
- }
- }
- }
-
- public static IEnumerable RegexMembers { get; }
- private static Dictionary regexMapper;
-
- static RegexParser()
- {
- var names = Enum.GetNames(typeof(AnalogyLogMessagePropertyName));
- RegexMembers = names;
- regexMapper = new Dictionary(names.Length);
- foreach (var name in names)
- {
- var enumValue = (AnalogyLogMessagePropertyName)Enum.Parse(typeof(AnalogyLogMessagePropertyName), name);
- regexMapper.Add(name, enumValue);
- }
- }
-
- public RegexParser(List logPatterns, bool updateUIAfterEachLine, IAnalogyLogger logger)
- {
- _logPatterns = logPatterns;
- Logger = logger;
- updateUIAfterEachParsedLine = updateUIAfterEachLine;
-
- }
-
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool TryParse(string line, RegexPattern regex, out AnalogyLogMessage message)
- {
- try
- {
- Match match = System.Text.RegularExpressions.Regex.Match(line, regex.Pattern,
- RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace);
- if (match.Success)
- {
- var m = new AnalogyLogMessage();
- foreach (var regexMember in regexMapper)
- {
- string value = match.Groups[regexMember.Key].Success
- ? match.Groups[regexMember.Key].Value
- : string.Empty;
- switch (regexMember.Value)
- {
- case AnalogyLogMessagePropertyName.Date:
- if (!string.IsNullOrEmpty(value) &&
- DateTime.TryParseExact(value, regex.DateTimeFormat, CultureInfo.InvariantCulture,
- DateTimeStyles.None, out var date))
- {
- m.Date = date;
- }
-
- continue;
- case AnalogyLogMessagePropertyName.Id:
- if (!string.IsNullOrEmpty(value) &&
- Guid.TryParseExact(value, regex.GuidFormat, out var guidValue))
- {
- m.Id = guidValue;
- }
-
- continue;
- case AnalogyLogMessagePropertyName.Text:
- m.Text = value;
- continue;
- case AnalogyLogMessagePropertyName.Category:
- m.Category = value;
- continue;
- case AnalogyLogMessagePropertyName.Source:
- m.Source = value;
- continue;
- case AnalogyLogMessagePropertyName.MachineName:
- m.MachineName = value;
- continue;
- case AnalogyLogMessagePropertyName.Module:
- m.Module = value;
- continue;
- case AnalogyLogMessagePropertyName.MethodName:
- m.MethodName = value;
- continue;
- case AnalogyLogMessagePropertyName.FileName:
- m.FileName = value;
- continue;
- case AnalogyLogMessagePropertyName.User:
- m.User = value;
- continue;
- case AnalogyLogMessagePropertyName.LineNumber:
- if (!string.IsNullOrEmpty(value) &&
- int.TryParse(value, out var lineNum))
- {
- m.LineNumber = lineNum;
- }
-
- continue;
- case AnalogyLogMessagePropertyName.ProcessId:
- if (!string.IsNullOrEmpty(value) &&
- int.TryParse(value, out var processNum))
- {
- m.ProcessId = processNum;
- }
-
- continue;
- case AnalogyLogMessagePropertyName.ThreadId:
- if (!string.IsNullOrEmpty(value) &&
- int.TryParse(value, out var threadNum))
- {
- m.ThreadId = threadNum;
- }
-
- continue;
- case AnalogyLogMessagePropertyName.Level:
- switch (value)
- {
- case "OFF":
- m.Level = AnalogyLogLevel.None;
- break;
- case "TRACE":
- m.Level = AnalogyLogLevel.Trace;
- break;
- case "DEBUG":
- m.Level = AnalogyLogLevel.Debug;
- break;
- case "INFO":
- m.Level = AnalogyLogLevel.Information;
- break;
- case "WARN":
- m.Level = AnalogyLogLevel.Warning;
- break;
- case "ERROR":
- m.Level = AnalogyLogLevel.Error;
- break;
- case "FATAL":
- m.Level = AnalogyLogLevel.Critical;
- break;
- default:
- m.Level = AnalogyLogLevel.Unknown;
- break;
- }
-
- continue;
- case AnalogyLogMessagePropertyName.Class:
- if (string.IsNullOrEmpty(value))
- m.Class = AnalogyLogClass.General;
- else
- {
- m.Class = Enum.TryParse(value, true, out AnalogyLogClass cls) &&
- Enum.IsDefined(typeof(AnalogyLogClass), cls)
- ? cls
- : AnalogyLogClass.General;
-
- }
-
- continue;
- default:
- throw new ArgumentOutOfRangeException();
- }
- }
-
- message = m;
- return true;
- }
-
- message = null;
- return false;
- }
- catch (Exception e)
- {
- string error = $"Error parsing line: {e.Message}";
- Logger?.LogException(error,e, nameof(RegexParser));
- message = new AnalogyLogMessage(error, AnalogyLogLevel.Error, AnalogyLogClass.General,
- nameof(RegexParser));
- return false;
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool CheckRegex(string line, RegexPattern regex, out AnalogyLogMessage message)
- {
- try
- {
- Match match = System.Text.RegularExpressions.Regex.Match(line, regex.Pattern,
- RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace);
- if (match.Success)
- {
- var m = new AnalogyLogMessage();
- foreach (var regexMember in regexMapper)
- {
- string value = match.Groups[regexMember.Key].Success
- ? match.Groups[regexMember.Key].Value
- : string.Empty;
- switch (regexMember.Value)
- {
- case AnalogyLogMessagePropertyName.Date:
- if (!string.IsNullOrEmpty(value) &&
- DateTime.TryParseExact(value, regex.DateTimeFormat, CultureInfo.InvariantCulture,
- DateTimeStyles.None, out var date))
- {
- m.Date = date;
- }
-
- break;
- case AnalogyLogMessagePropertyName.Id:
- if (!string.IsNullOrEmpty(value) &&
- Guid.TryParseExact(value, regex.GuidFormat, out var guidValue))
- {
- m.Id = guidValue;
- }
-
- break;
- case AnalogyLogMessagePropertyName.Text:
- m.Text = value;
- break;
- case AnalogyLogMessagePropertyName.Category:
- m.Category = value;
- break;
- case AnalogyLogMessagePropertyName.Source:
- m.Source = value;
- break;
- case AnalogyLogMessagePropertyName.Module:
- m.Module = value;
- break;
- case AnalogyLogMessagePropertyName.MethodName:
- m.MethodName = value;
- break;
- case AnalogyLogMessagePropertyName.FileName:
- m.FileName = value;
- break;
- case AnalogyLogMessagePropertyName.User:
- m.User = value;
- break;
- case AnalogyLogMessagePropertyName.LineNumber:
- if (!string.IsNullOrEmpty(value) &&
- int.TryParse(value, out var lineNum))
- {
- m.LineNumber = lineNum;
- }
-
- break;
- case AnalogyLogMessagePropertyName.ProcessId:
- if (!string.IsNullOrEmpty(value) &&
- int.TryParse(value, out var processNum))
- {
- m.ProcessId = processNum;
- }
-
- break;
- case AnalogyLogMessagePropertyName.ThreadId:
- if (!string.IsNullOrEmpty(value) &&
- int.TryParse(value, out var threadNum))
- {
- m.ThreadId = threadNum;
- }
-
- break;
- case AnalogyLogMessagePropertyName.Level:
- switch (value)
- {
- case "OFF":
- m.Level = AnalogyLogLevel.None;
- break;
- case "TRACE":
- m.Level = AnalogyLogLevel.Trace;
- break;
- case "DEBUG":
- m.Level = AnalogyLogLevel.Debug;
- break;
- case "INFO":
- m.Level = AnalogyLogLevel.Information;
- break;
- case "WARN":
- m.Level = AnalogyLogLevel.Warning;
- break;
- case "ERROR":
- m.Level = AnalogyLogLevel.Error;
- break;
- case "FATAL":
- m.Level = AnalogyLogLevel.Critical;
- break;
- default:
- m.Level = AnalogyLogLevel.Unknown;
- break;
- }
-
- break;
- case AnalogyLogMessagePropertyName.Class:
- if (string.IsNullOrEmpty(value))
- m.Class = AnalogyLogClass.General;
- else
- {
- m.Class = Enum.TryParse(value, true, out AnalogyLogClass cls) &&
- Enum.IsDefined(typeof(AnalogyLogClass), cls)
- ? cls
- : AnalogyLogClass.General;
-
- }
-
- break;
- default:
- throw new ArgumentOutOfRangeException();
- }
- }
-
- message = m;
- return true;
- }
-
- message = null;
- return false;
- }
- catch (Exception e)
- {
- string error = $"Error parsing line: {e.Message}";
- message = new AnalogyLogMessage(error, AnalogyLogLevel.Error, AnalogyLogClass.General,
- nameof(RegexParser));
- return false;
- }
- }
-
- public async Task> ParseLog(string fileName, CancellationToken token,
- ILogMessageCreatedHandler messagesHandler)
- {
- _messages.Clear();
- using (StreamReader reader = File.OpenText(fileName))
- {
- string line;
- while ((line = await reader.ReadLineAsync().ConfigureAwait(false)) != null)
- {
- AnalogyLogMessage entry = null;
- foreach (var logPattern in LogPatterns)
- {
- if (TryParse(line, logPattern, out entry))
- {
- break;
- }
- }
-
- if (entry != null)
- {
- if (updateUIAfterEachParsedLine)
- messagesHandler.AppendMessage(entry, fileName);
- _current = entry;
- _messages.Add(_current);
- }
- else
- {
- if (_current == null)
- {
- _current = new AnalogyLogMessage { Text = line };
- }
- else
- {
- _current.Text += Environment.NewLine + line;
- }
- }
-
- if (token.IsCancellationRequested)
- {
- messagesHandler.AppendMessages(_messages, fileName);
- return _messages;
- }
- }
- }
-
- if (!updateUIAfterEachParsedLine) //update only at the end
- messagesHandler.AppendMessages(_messages, fileName);
- return _messages;
- }
-
- public void SetRegexPatterns(List patterns) => _logPatterns = patterns;
- }
-}
diff --git a/Analogy.LogViewer.Serilog/Regex/RegexPattern.cs b/Analogy.LogViewer.Serilog/Regex/RegexPattern.cs
deleted file mode 100644
index 7c807d2..0000000
--- a/Analogy.LogViewer.Serilog/Regex/RegexPattern.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System;
-
-namespace Analogy.LogViewer.Serilog.Regex
-{
- [Serializable]
- public class RegexPattern
- {
- public string Pattern { get; set; }
- public string DateTimeFormat { get; set; }
- public string GuidFormat { get; set; }
- public bool IsSet => !string.IsNullOrEmpty(Pattern) && !string.IsNullOrEmpty(DateTimeFormat);
- public RegexPattern()
- {
- Pattern = string.Empty;
- DateTimeFormat = "yyyy-MM-dd HH:mm:ss,fff";
- GuidFormat = string.Empty;
-
- }
- public RegexPattern(string pattern, string dateTimeFormat, string guidFormat)
- {
- Pattern = pattern;
- DateTimeFormat = dateTimeFormat;
- GuidFormat = guidFormat;
- }
-
- public override string ToString() => $"Pattern: {Pattern}, DateTimeFormat: {DateTimeFormat}, GuidFormat: {GuidFormat}";
- }
-}
diff --git a/Analogy.LogViewer.Serilog/SerilogSettings.cs b/Analogy.LogViewer.Serilog/SerilogSettings.cs
index f16502a..33b3893 100644
--- a/Analogy.LogViewer.Serilog/SerilogSettings.cs
+++ b/Analogy.LogViewer.Serilog/SerilogSettings.cs
@@ -1,15 +1,10 @@
-using Analogy.LogViewer.Serilog.Regex;
+using Analogy.LogViewer.RegexParser;
+using Analogy.LogViewer.Serilog.DataTypes;
using System.Collections.Generic;
namespace Analogy.LogViewer.Serilog
{
- public enum SerilogFileFormat
- {
- CLEF,
- JSONPerLine,
- JSONFile,
- REGEX
- }
+
public class SerilogSettings
{
public string FileOpenDialogFilters { get; set; }
@@ -17,18 +12,20 @@ public class SerilogSettings
public List SupportFormats { get; set; }
public List RegexPatterns { get; set; }
public string Directory { get; set; }
- public SerilogFileFormat Format { get; set; }
+ public FileFormat Format { get; set; }
+ public FileFormatDetection FileFormatDetection { get; set; }
public List IgnoredAttributes { get; set; }
public SerilogSettings()
{
- Format = SerilogFileFormat.CLEF;
+ FileFormatDetection = FileFormatDetection.Automatic;
+ Format = FileFormat.Unknown;
Directory = string.Empty;
IgnoredAttributes = new List() { "N" };
FileOpenDialogFilters = "All Supported formats (*.Clef;*.log;*.gz)|*.clef;*.log;*.gz|Clef format (*.clef)|*.clef|Plain log text file (*.log)|*.log|GZIP file (*.gz)|*.gz";
SupportFormats = new List { "*.Clef", "*.log", "*.gz" };
RegexPatterns = new List();
- RegexPatterns.Add(new RegexPattern(@"\$(?\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2},\d{3})+\|+(?\d+)+\|(?\w+)+\|+(?