From 7a23fdc1ea509a6a1bcaafaaef862c023de35f2a Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Fri, 2 Nov 2018 11:09:59 +0000 Subject: [PATCH] Update logic for pre-flight check --- src/Umbraco.Core/Logging/Viewer/ILogViewer.cs | 4 +- .../Logging/Viewer/JsonLogViewer.cs | 82 ++++++++++--------- .../Logging/Viewer/LogViewerSourceBase.cs | 8 +- .../common/resources/logviewer.resource.js | 9 ++ .../views/logviewer/overview.controller.js | 19 ++++- .../src/views/logviewer/overview.html | 13 ++- .../src/views/logviewer/search.controller.js | 2 + .../Editors/LogViewerController.cs | 57 ++++--------- 8 files changed, 108 insertions(+), 86 deletions(-) diff --git a/src/Umbraco.Core/Logging/Viewer/ILogViewer.cs b/src/Umbraco.Core/Logging/Viewer/ILogViewer.cs index 1f23353608..73b518980c 100644 --- a/src/Umbraco.Core/Logging/Viewer/ILogViewer.cs +++ b/src/Umbraco.Core/Logging/Viewer/ILogViewer.cs @@ -44,7 +44,9 @@ namespace Umbraco.Core.Logging.Viewer /// IEnumerable GetMessageTemplates(DateTimeOffset startDate, DateTimeOffset endDate); - long GetLogSize(DateTimeOffset startDate, DateTimeOffset endDate); + bool CanHandleLargeLogs { get; } + + bool CheckCanOpenLogs(DateTimeOffset startDate, DateTimeOffset endDate); /// /// Returns the collection of logs diff --git a/src/Umbraco.Core/Logging/Viewer/JsonLogViewer.cs b/src/Umbraco.Core/Logging/Viewer/JsonLogViewer.cs index 4e887352d4..fdd833ae65 100644 --- a/src/Umbraco.Core/Logging/Viewer/JsonLogViewer.cs +++ b/src/Umbraco.Core/Logging/Viewer/JsonLogViewer.cs @@ -7,7 +7,47 @@ using Serilog.Formatting.Compact.Reader; namespace Umbraco.Core.Logging.Viewer { public partial class JsonLogViewer : LogViewerSourceBase - { + { + const int FileSizeCap = 100; + + public override bool CanHandleLargeLogs { get => false; } + + public override bool CheckCanOpenLogs(DateTimeOffset startDate, DateTimeOffset endDate) + { + //Open the JSON log file for the range of dates(and exclude machinename) Could be several for LB + var dateRange = endDate - startDate; + + //Log Directory + var logDirectory = $@"{AppDomain.CurrentDomain.BaseDirectory}\App_Data\Logs\"; + + //Number of entries + long fileSizeCount = 0; + + //foreach full day in the range - see if we can find one or more filenames that end with + //yyyyMMdd.json - Ends with due to MachineName in filenames - could be 1 or more due to load balancing + for (var day = startDate.Date; day.Date <= endDate.Date; day = day.AddDays(1)) + { + //Filename ending to search for (As could be multiple) + var filesToFind = $"*{day.ToString("yyyyMMdd")}.json"; + + var filesForCurrentDay = Directory.GetFiles(logDirectory, filesToFind); + + //Foreach file we find - open it + foreach (var filePath in filesForCurrentDay) + { + //Get the current filesize in bytes ! + var byteFileSize = new FileInfo(filePath).Length; + + fileSizeCount += byteFileSize; + } + } + + //The GetLogSize call on JsonLogViewer returns the total filesize in bytes + //Check if the logsize is not greater than 100Mb (FileSizeCap) + var logSizeAsMegabytes = fileSizeCount / 1024 / 1024; + return logSizeAsMegabytes <= FileSizeCap; + } + public override IEnumerable GetLogs(DateTimeOffset startDate, DateTimeOffset endDate, ILogFilter filter, int skip, int take) { var logs = new List(); @@ -68,44 +108,6 @@ namespace Umbraco.Core.Logging.Viewer return logs; } - - /// - /// This default JSON disk implementation here - returns the total filesize & NOT the count of entries - /// Other implementations we would expect to return the count of entries - /// We use this number to help prevent the logviewer killing the site with CPU/Memory if the number of items too big to handle - /// - public override long GetLogSize(DateTimeOffset startDate, DateTimeOffset endDate) - { - //Open the JSON log file for the range of dates (and exclude machinename) Could be several for LB - var dateRange = endDate - startDate; - - //Log Directory - var logDirectory = $@"{AppDomain.CurrentDomain.BaseDirectory}\App_Data\Logs\"; - - //Number of entries - long count = 0; - - //foreach full day in the range - see if we can find one or more filenames that end with - //yyyyMMdd.json - Ends with due to MachineName in filenames - could be 1 or more due to load balancing - for (var day = startDate.Date; day.Date <= endDate.Date; day = day.AddDays(1)) - { - //Filename ending to search for (As could be multiple) - var filesToFind = $"*{day.ToString("yyyyMMdd")}.json"; - - var filesForCurrentDay = Directory.GetFiles(logDirectory, filesToFind); - - //Foreach file we find - open it - foreach (var filePath in filesForCurrentDay) - { - //Get the current filesize in bytes ! - var byteFileSize = new FileInfo(filePath).Length; - - count += byteFileSize; - } - } - - //Count contains a combination of file sizes in bytes - return count; - } + } } diff --git a/src/Umbraco.Core/Logging/Viewer/LogViewerSourceBase.cs b/src/Umbraco.Core/Logging/Viewer/LogViewerSourceBase.cs index eed5fcc9ab..ee122317ff 100644 --- a/src/Umbraco.Core/Logging/Viewer/LogViewerSourceBase.cs +++ b/src/Umbraco.Core/Logging/Viewer/LogViewerSourceBase.cs @@ -14,9 +14,11 @@ namespace Umbraco.Core.Logging.Viewer private static readonly string SearchesConfigPath = IOHelper.MapPath("~/Config/logviewer.searches.config.js"); + public abstract bool CanHandleLargeLogs { get; } + public abstract IEnumerable GetLogs(DateTimeOffset startDate, DateTimeOffset endDate, ILogFilter filter, int skip, int take); - - public abstract long GetLogSize(DateTimeOffset startDate, DateTimeOffset endDate); + + public abstract bool CheckCanOpenLogs(DateTimeOffset startDate, DateTimeOffset endDate); public virtual IEnumerable GetSavedSearches() { @@ -139,5 +141,7 @@ namespace Umbraco.Core.Logging.Viewer Items = logMessages }; } + + } } diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/logviewer.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/logviewer.resource.js index 0d7270b937..75c23e7adf 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/logviewer.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/logviewer.resource.js @@ -91,6 +91,15 @@ "GetLogs", options)), 'Failed to retrieve common log messages'); + }, + + canViewLogs: function () { + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "logViewerApiBaseUrl", + "GetCanViewLogs")), + 'Failed to retrieve state if logs can be viewed'); } }; diff --git a/src/Umbraco.Web.UI.Client/src/views/logviewer/overview.controller.js b/src/Umbraco.Web.UI.Client/src/views/logviewer/overview.controller.js index d1eb73b2b3..c504d7caea 100644 --- a/src/Umbraco.Web.UI.Client/src/views/logviewer/overview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/logviewer/overview.controller.js @@ -5,6 +5,7 @@ var vm = this; vm.loading = false; + vm.canLoadLogs = false; vm.searches = []; vm.numberOfErrors = 0; vm.commonLogMessages = []; @@ -25,6 +26,22 @@ vm.searchLogQuery = searchLogQuery; vm.findMessageTemplate = findMessageTemplate; + function preFlightCheck(){ + vm.loading = true; + + //Do our pre-flight check (to see if we can view logs) + //IE the log file is NOT too big such as 1GB & crash the site + logViewerResource.canViewLogs().then(function(result){ + vm.loading = false; + vm.canLoadLogs = result; + + if(result){ + //Can view logs - so initalise + init(); + } + }); + } + function init() { @@ -96,7 +113,7 @@ searchLogQuery(logQuery); } - init(); + preFlightCheck(); } diff --git a/src/Umbraco.Web.UI.Client/src/views/logviewer/overview.html b/src/Umbraco.Web.UI.Client/src/views/logviewer/overview.html index 12dc459189..45ee3d5382 100644 --- a/src/Umbraco.Web.UI.Client/src/views/logviewer/overview.html +++ b/src/Umbraco.Web.UI.Client/src/views/logviewer/overview.html @@ -13,7 +13,18 @@ -
+ +
+ + + +

Today's log file is too large to be viewed and would cause performance problems.

+

If you need to view the log files, try opening them manually

+
+
+
+ +
diff --git a/src/Umbraco.Web.UI.Client/src/views/logviewer/search.controller.js b/src/Umbraco.Web.UI.Client/src/views/logviewer/search.controller.js index e2f159199c..74395ffb25 100644 --- a/src/Umbraco.Web.UI.Client/src/views/logviewer/search.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/logviewer/search.controller.js @@ -159,6 +159,8 @@ vm.logsLoading = false; setLogTypeColor(vm.logItems.items); + }, function(err){ + vm.logsLoading = false; }); } diff --git a/src/Umbraco.Web/Editors/LogViewerController.cs b/src/Umbraco.Web/Editors/LogViewerController.cs index ab6ae40c5c..e5c75926f6 100644 --- a/src/Umbraco.Web/Editors/LogViewerController.cs +++ b/src/Umbraco.Web/Editors/LogViewerController.cs @@ -5,6 +5,7 @@ using Umbraco.Core.Logging.Viewer; using Umbraco.Core.Models; using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Web.Mvc; +using Umbraco.Web.WebApi; namespace Umbraco.Web.Editors { @@ -23,53 +24,27 @@ namespace Umbraco.Web.Editors private bool CanViewLogs() { - //Check if the ILogViewer is our JSON file - var isJsonLogViewer = _logViewer is JsonLogViewer; - - //Don't WARN or check if it's not our JSON disk file approach - if (isJsonLogViewer == false) - { + //Can the interface deal with Large Files + if (_logViewer.CanHandleLargeLogs) return true; - } - //Go & fetch the number of log entries OR - var logSize = _logViewer.GetLogSize(startDate: DateTime.Now.AddDays(-1), endDate: DateTime.Now); - - //The GetLogSize call on JsonLogViewer returns the total filesize in bytes - //Check if the logsize is not greater than 200Mb - //TODO: Convert the bytes to Megabytes and check less than 200Mb - if (logSize >= 10) - { - return true; - } - - //TODO: It may need to be an Umbraco request with errow/warning notification?! - //Depends how best to bubble up to UI - with some custom JS promise error that is caught - return false; + //Interface CheckCanOpenLogs + return _logViewer.CheckCanOpenLogs(startDate: DateTime.Now.AddDays(-1), endDate: DateTime.Now); } [HttpGet] - public IHttpActionResult GetCanViewLogs() + public bool GetCanViewLogs() { - //Returns 200 OK if the logs can be viewed - if (CanViewLogs() == true) - { - return Ok(); - } - - //TODO: It may need to be an Umbraco request with errow/warning notification?! - //Depends how best to bubble up to UI - with some custom JS promise error that is caught - return BadRequest(); - + return CanViewLogs(); } [HttpGet] public int GetNumberOfErrors() { - //TODO: We will need to stop the request if trying to do this on a 1GB file - if(CanViewLogs() == false) + //We will need to stop the request if trying to do this on a 1GB file + if (CanViewLogs() == false) { - //Throw err + throw new HttpResponseException(Request.CreateNotificationValidationErrorResponse("Unable to view logs, due to size")); } return _logViewer.GetNumberOfErrors(startDate: DateTime.Now.AddDays(-1), endDate: DateTime.Now); @@ -78,10 +53,10 @@ namespace Umbraco.Web.Editors [HttpGet] public LogLevelCounts GetLogLevelCounts() { - //TODO: We will need to stop the request if trying to do this on a 1GB file + //We will need to stop the request if trying to do this on a 1GB file if (CanViewLogs() == false) { - //Throw err + throw new HttpResponseException(Request.CreateNotificationValidationErrorResponse("Unable to view logs, due to size")); } return _logViewer.GetLogLevelCounts(startDate: DateTime.Now.AddDays(-1), endDate: DateTime.Now); @@ -90,10 +65,10 @@ namespace Umbraco.Web.Editors [HttpGet] public IEnumerable GetMessageTemplates() { - //TODO: We will need to stop the request if trying to do this on a 1GB file + //We will need to stop the request if trying to do this on a 1GB file if (CanViewLogs() == false) { - //Throw err + throw new HttpResponseException(Request.CreateNotificationValidationErrorResponse("Unable to view logs, due to size")); } return _logViewer.GetMessageTemplates(startDate: DateTime.Now.AddDays(-1), endDate: DateTime.Now); @@ -102,10 +77,10 @@ namespace Umbraco.Web.Editors [HttpGet] public PagedResult GetLogs(string orderDirection = "Descending", int pageNumber = 1, string filterExpression = null, [FromUri]string[] logLevels = null) { - //TODO: We will need to stop the request if trying to do this on a 1GB file + //We will need to stop the request if trying to do this on a 1GB file if (CanViewLogs() == false) { - //Throw err + throw new HttpResponseException(Request.CreateNotificationValidationErrorResponse("Unable to view logs, due to size")); } var direction = orderDirection == "Descending" ? Direction.Descending : Direction.Ascending;