New Backoffice: Log viewer controller (#13648)
* Fixing a few nullable reference types for log viewer (#13634) (cherry picked from commitb4ca2a6636) * Adding LogControllerBase * Migrating GetLogLevels() * Migrating GetNumberOfErrors() * Migrating GetLogLevelCounts() * Migrating GetCanViewLogs() * Migrating GetMessageTemplates() * Migrating GetLogs() * Migrating GetSavedSearches() * Migrating PostSavedSearch() * Migrating DeleteSavedSearch() * Adding LoggerViewModel * Adding LogViewModelMapDefinition * Update OpenApi.json * Cleanup * V12: Change nullability for the log searches (#13647) * Changing nullability * Obsolete DeleteSavedSearch since the query param is not used * Fix a bit more referenced * Add default implementation for the new overload of DeleteSavedSearch (cherry picked from commit5e06f5a8a0) * Updates based on nullability fix * Adding GetSavedSearchByName * Implementing ByName endpoint * Refactoring Delete endpoint based on GetSavedSearchByName * Refactoring Create endpoint to return the item's location * Suppress new GetSavedSearchByName in ILogViewer interfaces * Update OpenApi.json * Adding github initials to FIXME * Renaming * Moving files to Core proj * Adding GetLogs with skip and take * Introducing ILogViewerService * Supressing xml for ILogViewer.GetLogsAsPagedModel() * Changing to our own Enum representation of LogLevel * Creating ILogEntry needed for GetPagedLogs() * Refactoring controllers to use the new logViewerService * Removing base class methods since those have been moved to the new service * Removing ErrorCountLogViewerController since the result can be calculated from another endpoint * Refactoring the MapDefinition because of the new return types from the service * Update OpenApi.json * Obsoleting old methods in favor of the ILogViewerService * Cleanup * Fixing enum representation as strings for Swagger * Adding documentation * Changing enum representation to string in OpenApi.OpenApi.json * Fix FIXME (use CreatedAtAction) * Removing JsonStringEnumConverter as there should be another way to fix enum representation for Swagger * Removing MappingBuilderExtensions and making specific LogViewerBuilderExtensions * Changes to the .sln file * Take only the result in the response * Register the LogViewer extensions * Update OpenApi.json * Fix the supressions.xml * Add inheritdoc * Remove GetSavedSearchByName as it isn't necessary to introduce it anymore * Obsolete interfaces * Rename ViewPermission controller to ValidateLogFileSize * Make rest of the methods async * Route name change * Remove methods obsoletion * Introduce the "attempt" pattern * Refactoring of ILogViewerService * Refactoring controllers * Another OpenApi.json update * Adding fixme * Re-add new client project Co-authored-by: nikolajlauridsen <nikolajlauridsen@protonmail.ch>
This commit is contained in:
committed by
GitHub
parent
0fd90c1294
commit
aa90efa5b7
@@ -0,0 +1,63 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.LogViewer;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Logging.Viewer;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.New.Cms.Core.Models;
|
||||
using LogLevel = Umbraco.Cms.Core.Logging.LogLevel;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.LogViewer;
|
||||
|
||||
public class AllLogViewerController : LogViewerControllerBase
|
||||
{
|
||||
private readonly ILogViewerService _logViewerService;
|
||||
private readonly IUmbracoMapper _umbracoMapper;
|
||||
|
||||
public AllLogViewerController(ILogViewerService logViewerService, IUmbracoMapper umbracoMapper)
|
||||
{
|
||||
_logViewerService = logViewerService;
|
||||
_umbracoMapper = umbracoMapper;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a paginated list of all logs for a specific date range.
|
||||
/// </summary>
|
||||
/// <param name="skip">The amount of items to skip.</param>
|
||||
/// <param name="take">The amount of items to take.</param>
|
||||
/// <param name="orderDirection">
|
||||
/// By default this will be ordered descending (newest items first).
|
||||
/// </param>
|
||||
/// <param name="filterExpression">The query expression to filter on (can be null).</param>
|
||||
/// <param name="logLevels">The log levels for which to retrieve the log messages (can be null).</param>
|
||||
/// <param name="startDate">The start date for the date range (can be null).</param>
|
||||
/// <param name="endDate">The end date for the date range (can be null).</param>
|
||||
/// <returns>The paged result of the logs from the given time period.</returns>
|
||||
[HttpGet("log")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(PagedViewModel<LogMessageViewModel>), StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> AllLogs(
|
||||
int skip = 0,
|
||||
int take = 100,
|
||||
Direction orderDirection = Direction.Descending,
|
||||
string? filterExpression = null,
|
||||
[FromQuery(Name = "logLevel")] LogLevel[]? logLevels = null,
|
||||
DateTime? startDate = null,
|
||||
DateTime? endDate = null)
|
||||
{
|
||||
var levels = logLevels?.Select(l => l.ToString()).ToArray();
|
||||
|
||||
Attempt<PagedModel<ILogEntry>?, LogViewerOperationStatus> logsAttempt =
|
||||
await _logViewerService.GetPagedLogsAsync(startDate, endDate, skip, take, orderDirection, filterExpression, levels);
|
||||
|
||||
if (logsAttempt.Success)
|
||||
{
|
||||
return Ok(_umbracoMapper.Map<PagedViewModel<LogMessageViewModel>>(logsAttempt.Result));
|
||||
}
|
||||
|
||||
return LogViewerOperationStatusResult(logsAttempt.Status);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.LogViewer;
|
||||
using Umbraco.Cms.Core.Logging;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.LogViewer;
|
||||
|
||||
public class AllSinkLevelLogViewerController : LogViewerControllerBase
|
||||
{
|
||||
private readonly ILogViewerService _logViewerService;
|
||||
private readonly IUmbracoMapper _umbracoMapper;
|
||||
|
||||
public AllSinkLevelLogViewerController(ILogViewerService logViewerService, IUmbracoMapper umbracoMapper)
|
||||
{
|
||||
_logViewerService = logViewerService;
|
||||
_umbracoMapper = umbracoMapper;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a paginated list of all loggers' levels.
|
||||
/// </summary>
|
||||
/// <param name="skip">The amount of items to skip.</param>
|
||||
/// <param name="take">The amount of items to take.</param>
|
||||
/// <returns>The paged result of the configured loggers and their level.</returns>
|
||||
[HttpGet("level")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(PagedViewModel<LoggerViewModel>), StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<PagedViewModel<LoggerViewModel>>> AllLogLevels(int skip = 0, int take = 100)
|
||||
{
|
||||
IEnumerable<KeyValuePair<string, LogLevel>> logLevels = _logViewerService
|
||||
.GetLogLevelsFromSinks()
|
||||
.Skip(skip)
|
||||
.Take(take);
|
||||
|
||||
return await Task.FromResult(Ok(_umbracoMapper.Map<PagedViewModel<LoggerViewModel>>(logLevels)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.LogViewer;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Logging.Viewer;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.LogViewer;
|
||||
|
||||
public class LogLevelCountLogViewerController : LogViewerControllerBase
|
||||
{
|
||||
private readonly ILogViewerService _logViewerService;
|
||||
private readonly IUmbracoMapper _umbracoMapper;
|
||||
|
||||
public LogLevelCountLogViewerController(ILogViewerService logViewerService, IUmbracoMapper umbracoMapper)
|
||||
{
|
||||
_logViewerService = logViewerService;
|
||||
_umbracoMapper = umbracoMapper;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the count for each log level from the logs for a specific date range.
|
||||
/// </summary>
|
||||
/// <param name="startDate">The start date for the date range (can be null).</param>
|
||||
/// <param name="endDate">The end date for the date range (can be null).</param>
|
||||
/// <returns>The log level counts from the (filtered) logs.</returns>
|
||||
[HttpGet("level-count")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> LogLevelCounts(DateTime? startDate = null, DateTime? endDate = null)
|
||||
{
|
||||
Attempt<LogLevelCounts?, LogViewerOperationStatus> logLevelCountsAttempt =
|
||||
await _logViewerService.GetLogLevelCountsAsync(startDate, endDate);
|
||||
|
||||
if (logLevelCountsAttempt.Success)
|
||||
{
|
||||
return Ok(_umbracoMapper.Map<LogLevelCountsViewModel>(logLevelCountsAttempt.Result));
|
||||
}
|
||||
|
||||
return LogViewerOperationStatusResult(logLevelCountsAttempt.Status);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.Builders;
|
||||
using Umbraco.Cms.Api.Management.Routing;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.LogViewer;
|
||||
|
||||
[ApiController]
|
||||
[VersionedApiBackOfficeRoute("log-viewer")]
|
||||
[ApiExplorerSettings(GroupName = "Log Viewer")]
|
||||
[ApiVersion("1.0")]
|
||||
public abstract class LogViewerControllerBase : ManagementApiControllerBase
|
||||
{
|
||||
protected IActionResult LogViewerOperationStatusResult(LogViewerOperationStatus status) =>
|
||||
status switch
|
||||
{
|
||||
LogViewerOperationStatus.NotFoundLogSearch => NotFound("The log search could not be found"),
|
||||
LogViewerOperationStatus.DuplicateLogSearch => BadRequest(new ProblemDetailsBuilder()
|
||||
.WithTitle("Duplicate log search name")
|
||||
.WithDetail("Another log search already exists with the attempted name.")
|
||||
.Build()),
|
||||
LogViewerOperationStatus.CancelledByLogsSizeValidation => BadRequest(new ProblemDetailsBuilder()
|
||||
.WithTitle("Cancelled due to log file size")
|
||||
.WithDetail("The log file size for the requested date range prevented the operation.")
|
||||
.Build()),
|
||||
_ => StatusCode(StatusCodes.Status500InternalServerError, "Unknown log viewer operation status")
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.LogViewer;
|
||||
using Umbraco.Cms.Core.Logging.Viewer;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.LogViewer;
|
||||
|
||||
public class MessageTemplateLogViewerController : LogViewerControllerBase
|
||||
{
|
||||
private readonly ILogViewerService _logViewerService;
|
||||
private readonly IUmbracoMapper _umbracoMapper;
|
||||
|
||||
public MessageTemplateLogViewerController(ILogViewerService logViewerService, IUmbracoMapper umbracoMapper)
|
||||
{
|
||||
_logViewerService = logViewerService;
|
||||
_umbracoMapper = umbracoMapper;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a paginated list of all log message templates for a specific date range.
|
||||
/// </summary>
|
||||
/// <param name="skip">The amount of items to skip.</param>
|
||||
/// <param name="take">The amount of items to take.</param>
|
||||
/// <param name="startDate">The start date for the date range (can be null).</param>
|
||||
/// <param name="endDate">The end date for the date range (can be null).</param>
|
||||
/// <returns>The paged result of the log message templates from the given time period.</returns>
|
||||
[HttpGet("message-template")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(typeof(PagedViewModel<LogTemplateViewModel>), StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> AllMessageTemplates(
|
||||
int skip = 0,
|
||||
int take = 100,
|
||||
DateTime? startDate = null,
|
||||
DateTime? endDate = null)
|
||||
{
|
||||
Attempt<IEnumerable<LogTemplate>, LogViewerOperationStatus> messageTemplatesAttempt = await _logViewerService.GetMessageTemplatesAsync(startDate, endDate);
|
||||
|
||||
if (messageTemplatesAttempt.Success)
|
||||
{
|
||||
IEnumerable<LogTemplate> messageTemplates = messageTemplatesAttempt
|
||||
.Result
|
||||
.Skip(skip)
|
||||
.Take(take);
|
||||
|
||||
return Ok(_umbracoMapper.Map<PagedViewModel<LogTemplateViewModel>>(messageTemplates));
|
||||
}
|
||||
|
||||
return LogViewerOperationStatusResult(messageTemplatesAttempt.Status);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.LogViewer;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.LogViewer.SavedSearch;
|
||||
|
||||
public class AllSavedSearchLogViewerController : SavedSearchLogViewerControllerBase
|
||||
{
|
||||
private readonly ILogViewerService _logViewerService;
|
||||
private readonly IUmbracoMapper _umbracoMapper;
|
||||
|
||||
public AllSavedSearchLogViewerController(ILogViewerService logViewerService, IUmbracoMapper umbracoMapper)
|
||||
{
|
||||
_logViewerService = logViewerService;
|
||||
_umbracoMapper = umbracoMapper;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a paginated list of all saved log searches.
|
||||
/// </summary>
|
||||
/// <param name="skip">The amount of items to skip.</param>
|
||||
/// <param name="take">The amount of items to take.</param>
|
||||
/// <returns>The paged result of the saved log searches.</returns>
|
||||
[HttpGet]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(PagedViewModel<SavedLogSearchViewModel>), StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<PagedViewModel<SavedLogSearchViewModel>>> AllSavedSearches(int skip = 0, int take = 100)
|
||||
{
|
||||
IReadOnlyList<ILogViewerQuery> savedLogQueries = await _logViewerService.GetSavedLogQueriesAsync();
|
||||
|
||||
return Ok(_umbracoMapper.Map<PagedViewModel<SavedLogSearchViewModel>>(savedLogQueries.Skip(skip).Take(take)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.LogViewer;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.LogViewer.SavedSearch;
|
||||
|
||||
public class ByNameSavedSearchLogViewerController : SavedSearchLogViewerControllerBase
|
||||
{
|
||||
private readonly ILogViewerService _logViewerService;
|
||||
private readonly IUmbracoMapper _umbracoMapper;
|
||||
|
||||
public ByNameSavedSearchLogViewerController(ILogViewerService logViewerService, IUmbracoMapper umbracoMapper)
|
||||
{
|
||||
_logViewerService = logViewerService;
|
||||
_umbracoMapper = umbracoMapper;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a saved log search by name.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the saved log search.</param>
|
||||
/// <returns>The saved log search or not found result.</returns>
|
||||
[HttpGet("{name}")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(NotFoundResult), StatusCodes.Status404NotFound)]
|
||||
[ProducesResponseType(typeof(SavedLogSearchViewModel), StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<SavedLogSearchViewModel>> ByName(string name)
|
||||
{
|
||||
ILogViewerQuery? savedLogQuery = await _logViewerService.GetSavedLogQueryByNameAsync(name);
|
||||
|
||||
if (savedLogQuery is null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
return Ok(_umbracoMapper.Map<SavedLogSearchViewModel>(savedLogQuery));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.LogViewer;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.LogViewer.SavedSearch;
|
||||
|
||||
public class CreateSavedSearchLogViewerController : SavedSearchLogViewerControllerBase
|
||||
{
|
||||
private readonly ILogViewerService _logViewerService;
|
||||
|
||||
public CreateSavedSearchLogViewerController(ILogViewerService logViewerService) => _logViewerService = logViewerService;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a saved log search.
|
||||
/// </summary>
|
||||
/// <param name="savedSearch">The log search to be saved.</param>
|
||||
/// <returns>The location of the saved log search after the creation.</returns>
|
||||
[HttpPost]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status201Created)]
|
||||
public async Task<IActionResult> Create(SavedLogSearchViewModel savedSearch)
|
||||
{
|
||||
Attempt<ILogViewerQuery?, LogViewerOperationStatus> result =
|
||||
await _logViewerService.AddSavedLogQueryAsync(savedSearch.Name, savedSearch.Query);
|
||||
|
||||
if (result.Success)
|
||||
{
|
||||
return CreatedAtAction<ByNameSavedSearchLogViewerController>(
|
||||
controller => nameof(controller.ByName), savedSearch.Name);
|
||||
}
|
||||
|
||||
return LogViewerOperationStatusResult(result.Status);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.LogViewer.SavedSearch;
|
||||
|
||||
public class DeleteSavedSearchLogViewerController : SavedSearchLogViewerControllerBase
|
||||
{
|
||||
private readonly ILogViewerService _logViewerService;
|
||||
|
||||
public DeleteSavedSearchLogViewerController(ILogViewerService logViewerService) => _logViewerService = logViewerService;
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a saved log search with a given name.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the saved log search.</param>
|
||||
/// <returns>The result of the deletion.</returns>
|
||||
[HttpDelete("{name}")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(NotFoundResult), StatusCodes.Status404NotFound)]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> Delete(string name)
|
||||
{
|
||||
Attempt<ILogViewerQuery?, LogViewerOperationStatus> result = await _logViewerService.DeleteSavedLogQueryAsync(name);
|
||||
|
||||
if (result.Success)
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
|
||||
return LogViewerOperationStatusResult(result.Status);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Management.Routing;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.LogViewer.SavedSearch;
|
||||
|
||||
[ApiController]
|
||||
[VersionedApiBackOfficeRoute("log-viewer/saved-search")]
|
||||
[ApiExplorerSettings(GroupName = "Log Viewer")]
|
||||
[ApiVersion("1.0")]
|
||||
public class SavedSearchLogViewerControllerBase : LogViewerControllerBase
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.LogViewer;
|
||||
|
||||
public class ValidateLogFileSizeLogViewerController : LogViewerControllerBase
|
||||
{
|
||||
private readonly ILogViewerService _logViewerService;
|
||||
|
||||
public ValidateLogFileSizeLogViewerController(ILogViewerService logViewerService) => _logViewerService = logViewerService;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether or not you are able to view logs for a specified date range.
|
||||
/// </summary>
|
||||
/// <param name="startDate">The start date for the date range (can be null).</param>
|
||||
/// <param name="endDate">The end date for the date range (can be null).</param>
|
||||
/// <returns>The boolean result.</returns>
|
||||
[HttpGet("validate-logs-size")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> CanViewLogs(DateTime? startDate = null, DateTime? endDate = null)
|
||||
{
|
||||
Attempt<bool, LogViewerOperationStatus> result = await _logViewerService.CanViewLogsAsync(startDate, endDate);
|
||||
|
||||
if (result.Success)
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
|
||||
return LogViewerOperationStatusResult(result.Status);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Linq.Expressions;
|
||||
using System.Linq.Expressions;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.Filters;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
@@ -22,6 +22,19 @@ public class ManagementApiControllerBase : Controller
|
||||
return base.CreatedAtAction(actionName, controllerName, new { key = key }, null);
|
||||
}
|
||||
|
||||
protected CreatedAtActionResult CreatedAtAction<T>(Expression<Func<T, string>> action, string name)
|
||||
{
|
||||
if (action.Body is not ConstantExpression constantExpression)
|
||||
{
|
||||
throw new ArgumentException("Expression must be a constant expression.");
|
||||
}
|
||||
|
||||
var controllerName = ManagementApiRegexes.ControllerTypeToNameRegex().Replace(typeof(T).Name, string.Empty);
|
||||
var actionName = constantExpression.Value?.ToString() ?? throw new ArgumentException("Expression does not have a value.");
|
||||
|
||||
return base.CreatedAtAction(actionName, controllerName, new { name = name }, null);
|
||||
}
|
||||
|
||||
protected static int CurrentUserId(IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
|
||||
=> backOfficeSecurityAccessor.BackOfficeSecurity?.CurrentUser?.Id ?? Core.Constants.Security.SuperUserId;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
using Umbraco.Cms.Api.Management.Mapping.LogViewer;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.DependencyInjection;
|
||||
|
||||
internal static class LogViewerBuilderExtensions
|
||||
{
|
||||
internal static IUmbracoBuilder AddLogViewer(this IUmbracoBuilder builder)
|
||||
{
|
||||
builder.WithCollectionBuilder<MapDefinitionCollectionBuilder>().Add<LogViewerViewModelMapDefinition>();
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,7 @@ public class ManagementApiComposer : IComposer
|
||||
.AddTrackedReferences()
|
||||
.AddDataTypes()
|
||||
.AddTemplates()
|
||||
.AddLogViewer()
|
||||
.AddBackOfficeAuthentication()
|
||||
.AddApiVersioning()
|
||||
.AddSwaggerGen();
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.LogViewer;
|
||||
using Umbraco.Cms.Core.Logging;
|
||||
using Umbraco.Cms.Core.Logging.Viewer;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.New.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Mapping.LogViewer;
|
||||
|
||||
public class LogViewerViewModelMapDefinition : IMapDefinition
|
||||
{
|
||||
public void DefineMaps(IUmbracoMapper mapper)
|
||||
{
|
||||
mapper.Define<LogLevelCounts, LogLevelCountsViewModel>((source, context) => new LogLevelCountsViewModel(), Map);
|
||||
mapper.Define<KeyValuePair<string, string?>, LogMessagePropertyViewModel>(
|
||||
(source, context) => new LogMessagePropertyViewModel() { Name = string.Empty }, Map);
|
||||
mapper.Define<KeyValuePair<string, LogLevel>, LoggerViewModel>((source, context) => new LoggerViewModel() { Name = string.Empty }, Map);
|
||||
mapper.Define<ILogViewerQuery, SavedLogSearchViewModel>(
|
||||
(source, context) => new SavedLogSearchViewModel()
|
||||
{
|
||||
Name = string.Empty,
|
||||
Query = string.Empty
|
||||
},
|
||||
Map);
|
||||
mapper.Define<LogTemplate, LogTemplateViewModel>((source, context) => new LogTemplateViewModel(), Map);
|
||||
mapper.Define<ILogEntry, LogMessageViewModel>((source, context) => new LogMessageViewModel(), Map);
|
||||
mapper.Define<IEnumerable<KeyValuePair<string, LogLevel>>, PagedViewModel<LoggerViewModel>>((source, context) => new PagedViewModel<LoggerViewModel>(), Map);
|
||||
mapper.Define<IEnumerable<ILogViewerQuery>, PagedViewModel<SavedLogSearchViewModel>>((source, context) => new PagedViewModel<SavedLogSearchViewModel>(), Map);
|
||||
mapper.Define<IEnumerable<LogTemplate>, PagedViewModel<LogTemplateViewModel>>((source, context) => new PagedViewModel<LogTemplateViewModel>(), Map);
|
||||
mapper.Define<PagedModel<ILogEntry>, PagedViewModel<LogMessageViewModel>>((source, context) => new PagedViewModel<LogMessageViewModel>(), Map);
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll
|
||||
private static void Map(LogLevelCounts source, LogLevelCountsViewModel target, MapperContext context)
|
||||
{
|
||||
target.Information = source.Information;
|
||||
target.Debug = source.Debug;
|
||||
target.Warning = source.Warning;
|
||||
target.Error = source.Error;
|
||||
target.Fatal = source.Fatal;
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll
|
||||
private static void Map(KeyValuePair<string, string?> source, LogMessagePropertyViewModel target, MapperContext context)
|
||||
{
|
||||
target.Name = source.Key;
|
||||
target.Value = source.Value;
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll
|
||||
private static void Map(KeyValuePair<string, LogLevel> source, LoggerViewModel target, MapperContext context)
|
||||
{
|
||||
target.Name = source.Key;
|
||||
target.Level = source.Value;
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll
|
||||
private static void Map(ILogViewerQuery source, SavedLogSearchViewModel target, MapperContext context)
|
||||
{
|
||||
target.Name = source.Name;
|
||||
target.Query = source.Query;
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll
|
||||
private static void Map(LogTemplate source, LogTemplateViewModel target, MapperContext context)
|
||||
{
|
||||
target.MessageTemplate = source.MessageTemplate;
|
||||
target.Count = source.Count;
|
||||
}
|
||||
|
||||
|
||||
// Umbraco.Code.MapAll
|
||||
private static void Map(ILogEntry source, LogMessageViewModel target, MapperContext context)
|
||||
{
|
||||
target.Timestamp = source.Timestamp;
|
||||
target.Level = source.Level;
|
||||
target.MessageTemplate = source.MessageTemplateText;
|
||||
target.RenderedMessage = source.RenderedMessage;
|
||||
target.Properties = context.MapEnumerable<KeyValuePair<string, string?>, LogMessagePropertyViewModel>(source.Properties);
|
||||
target.Exception = source.Exception;
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll
|
||||
private static void Map(IEnumerable<KeyValuePair<string, LogLevel>> source, PagedViewModel<LoggerViewModel> target, MapperContext context)
|
||||
{
|
||||
target.Items = context.MapEnumerable<KeyValuePair<string, LogLevel>, LoggerViewModel>(source);
|
||||
target.Total = source.Count();
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll
|
||||
private static void Map(IEnumerable<ILogViewerQuery> source, PagedViewModel<SavedLogSearchViewModel> target, MapperContext context)
|
||||
{
|
||||
target.Items = context.MapEnumerable<ILogViewerQuery, SavedLogSearchViewModel>(source);
|
||||
target.Total = source.Count();
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll
|
||||
private static void Map(IEnumerable<LogTemplate> source, PagedViewModel<LogTemplateViewModel> target, MapperContext context)
|
||||
{
|
||||
target.Items = context.MapEnumerable<LogTemplate, LogTemplateViewModel>(source);
|
||||
target.Total = source.Count();
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll
|
||||
private static void Map(PagedModel<ILogEntry> source, PagedViewModel<LogMessageViewModel> target, MapperContext context)
|
||||
{
|
||||
target.Items = context.MapEnumerable<ILogEntry, LogMessageViewModel>(source.Items);
|
||||
target.Total = source.Total;
|
||||
}
|
||||
}
|
||||
@@ -638,6 +638,48 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": [
|
||||
"Dictionary"
|
||||
],
|
||||
"operationId": "DeleteDictionaryByKey",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "key",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success"
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"tags": [
|
||||
"Dictionary"
|
||||
@@ -688,38 +730,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": [
|
||||
"Dictionary"
|
||||
],
|
||||
"operationId": "DeleteDictionaryByKey",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "key",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success"
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/dictionary/export/{key}": {
|
||||
@@ -826,7 +836,7 @@
|
||||
],
|
||||
"operationId": "PostDictionaryUpload",
|
||||
"requestBody": {
|
||||
"content": { }
|
||||
"content": {}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
@@ -2092,6 +2102,415 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/log-viewer/level": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Log Viewer"
|
||||
],
|
||||
"operationId": "GetLogViewerLevel",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "skip",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "take",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 100
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PagedLogger"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/log-viewer/level-count": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Log Viewer"
|
||||
],
|
||||
"operationId": "GetLogViewerLevelCount",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "startDate",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "endDate",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"200": {
|
||||
"description": "Success"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/log-viewer/log": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Log Viewer"
|
||||
],
|
||||
"operationId": "GetLogViewerLog",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "skip",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "take",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 100
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "orderDirection",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Direction"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "filterExpression",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "logLevel",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/LogLevel"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "startDate",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "endDate",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PagedLogMessage"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/log-viewer/message-template": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Log Viewer"
|
||||
],
|
||||
"operationId": "GetLogViewerMessageTemplate",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "skip",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "take",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 100
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "startDate",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "endDate",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PagedLogTemplate"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/log-viewer/saved-search": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Log Viewer"
|
||||
],
|
||||
"operationId": "GetLogViewerSavedSearch",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "skip",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "take",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 100
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PagedSavedLogSearch"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"tags": [
|
||||
"Log Viewer"
|
||||
],
|
||||
"operationId": "PostLogViewerSavedSearch",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SavedLogSearch"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"201": {
|
||||
"description": "Created"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/log-viewer/saved-search/{name}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Log Viewer"
|
||||
],
|
||||
"operationId": "GetLogViewerSavedSearchByName",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "name",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/NotFoundResult"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SavedLogSearch"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": [
|
||||
"Log Viewer"
|
||||
],
|
||||
"operationId": "DeleteLogViewerSavedSearchByName",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "name",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/NotFoundResult"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"200": {
|
||||
"description": "Success"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/log-viewer/validate-logs-size": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Log Viewer"
|
||||
],
|
||||
"operationId": "GetLogViewerValidateLogsSize",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "startDate",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "endDate",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"200": {
|
||||
"description": "Success"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/tree/media-type/children": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -5216,6 +5635,14 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Direction": {
|
||||
"enum": [
|
||||
"Ascending",
|
||||
"Descending"
|
||||
],
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"DocumentBlueprintTreeItem": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -5902,7 +6329,7 @@
|
||||
},
|
||||
"providerProperties": {
|
||||
"type": "object",
|
||||
"additionalProperties": { },
|
||||
"additionalProperties": {},
|
||||
"nullable": true
|
||||
}
|
||||
},
|
||||
@@ -5987,6 +6414,88 @@
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"LogLevel": {
|
||||
"enum": [
|
||||
"Verbose",
|
||||
"Debug",
|
||||
"Information",
|
||||
"Warning",
|
||||
"Error",
|
||||
"Fatal"
|
||||
],
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"LogMessage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"level": {
|
||||
"$ref": "#/components/schemas/LogLevel"
|
||||
},
|
||||
"messageTemplate": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"renderedMessage": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"properties": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/LogMessageProperty"
|
||||
}
|
||||
},
|
||||
"exception": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"LogMessageProperty": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"LogTemplate": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"messageTemplate": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"count": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Logger": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"level": {
|
||||
"$ref": "#/components/schemas/LogLevel"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"MemberInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -6771,6 +7280,66 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PagedLogMessage": {
|
||||
"required": [
|
||||
"items",
|
||||
"total"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"total": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/LogMessage"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PagedLogTemplate": {
|
||||
"required": [
|
||||
"items",
|
||||
"total"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"total": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/LogTemplate"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PagedLogger": {
|
||||
"required": [
|
||||
"items",
|
||||
"total"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"total": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Logger"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PagedRecycleBinItem": {
|
||||
"required": [
|
||||
"items",
|
||||
@@ -6851,6 +7420,26 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PagedSavedLogSearch": {
|
||||
"required": [
|
||||
"items",
|
||||
"total"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"total": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/SavedLogSearch"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PagedSearchResult": {
|
||||
"required": [
|
||||
"items",
|
||||
@@ -7022,7 +7611,7 @@
|
||||
"nullable": true
|
||||
}
|
||||
},
|
||||
"additionalProperties": { }
|
||||
"additionalProperties": {}
|
||||
},
|
||||
"ProfilingStatus": {
|
||||
"type": "object",
|
||||
@@ -7296,6 +7885,18 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SavedLogSearch": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"query": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SearchResult": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -8368,7 +8969,7 @@
|
||||
"authorizationCode": {
|
||||
"authorizationUrl": "/umbraco/management/api/v1.0/security/back-office/authorize",
|
||||
"tokenUrl": "/umbraco/management/api/v1.0/security/back-office/token",
|
||||
"scopes": { }
|
||||
"scopes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8376,7 +8977,7 @@
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"OAuth": [ ]
|
||||
"OAuth": []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.LogViewer;
|
||||
|
||||
public class LogLevelCountsViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the Information level count.
|
||||
/// </summary>
|
||||
public int Information { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Debug level count.
|
||||
/// </summary>
|
||||
public int Debug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Warning level count.
|
||||
/// </summary>
|
||||
public int Warning { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Error level count.
|
||||
/// </summary>
|
||||
public int Error { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Fatal level count.
|
||||
/// </summary>
|
||||
public int Fatal { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.LogViewer;
|
||||
|
||||
public class LogMessagePropertyViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the log message property.
|
||||
/// </summary>
|
||||
public required string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value of the log message property (can be null).
|
||||
/// </summary>
|
||||
public string? Value { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using LogLevel = Umbraco.Cms.Core.Logging.LogLevel;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.LogViewer;
|
||||
|
||||
public class LogMessageViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the time at which the log event occurred.
|
||||
/// </summary>
|
||||
public DateTimeOffset Timestamp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the level of the event.
|
||||
/// </summary>
|
||||
public LogLevel Level { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the message template describing the log event (can be null).
|
||||
/// </summary>
|
||||
public string? MessageTemplate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the message template filled with the log event properties (can be null).
|
||||
/// </summary>
|
||||
public string? RenderedMessage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the properties associated with the log event, including those presented in MessageTemplate.
|
||||
/// </summary>
|
||||
public IEnumerable<LogMessagePropertyViewModel> Properties { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an exception associated with the log event (can be null).
|
||||
/// </summary>
|
||||
public string? Exception { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.LogViewer;
|
||||
|
||||
public class LogTemplateViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the message template.
|
||||
/// </summary>
|
||||
public string? MessageTemplate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the count.
|
||||
/// </summary>
|
||||
public int Count { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Umbraco.Cms.Core.Logging;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.LogViewer;
|
||||
|
||||
public class LoggerViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the log event sink.
|
||||
/// </summary>
|
||||
public required string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the log event level (can be null).
|
||||
/// </summary>
|
||||
public LogLevel Level { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.LogViewer;
|
||||
|
||||
public class SavedLogSearchViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the saved search.
|
||||
/// </summary>
|
||||
public required string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the query of the saved search.
|
||||
/// </summary>
|
||||
public required string Query { get; set; }
|
||||
}
|
||||
34
src/Umbraco.Core/Logging/Viewer/ILogEntry.cs
Normal file
34
src/Umbraco.Core/Logging/Viewer/ILogEntry.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
namespace Umbraco.Cms.Core.Logging.Viewer;
|
||||
|
||||
public interface ILogEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the time at which the log event occurred.
|
||||
/// </summary>
|
||||
DateTimeOffset Timestamp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the level of the log event.
|
||||
/// </summary>
|
||||
LogLevel Level { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the message template describing the log event.
|
||||
/// </summary>
|
||||
string? MessageTemplateText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the message template filled with the log event properties.
|
||||
/// </summary>
|
||||
string? RenderedMessage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the properties associated with the log event.
|
||||
/// </summary>
|
||||
IReadOnlyDictionary<string, string?> Properties { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an exception associated with the log event, or null.
|
||||
/// </summary>
|
||||
string? Exception { get; set; }
|
||||
}
|
||||
34
src/Umbraco.Core/Logging/Viewer/LogEntry.cs
Normal file
34
src/Umbraco.Core/Logging/Viewer/LogEntry.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
namespace Umbraco.Cms.Core.Logging.Viewer;
|
||||
|
||||
public class LogEntry : ILogEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the time at which the log event occurred.
|
||||
/// </summary>
|
||||
public DateTimeOffset Timestamp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the level of the log event.
|
||||
/// </summary>
|
||||
public LogLevel Level { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the message template describing the log event.
|
||||
/// </summary>
|
||||
public string? MessageTemplateText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the message template filled with the log event properties.
|
||||
/// </summary>
|
||||
public string? RenderedMessage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the properties associated with the log event.
|
||||
/// </summary>
|
||||
public IReadOnlyDictionary<string, string?> Properties { get; set; } = new Dictionary<string, string?>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an exception associated with the log event, or null.
|
||||
/// </summary>
|
||||
public string? Exception { get; set; }
|
||||
}
|
||||
94
src/Umbraco.Core/Services/ILogViewerService.cs
Normal file
94
src/Umbraco.Core/Services/ILogViewerService.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using Umbraco.Cms.Core.Logging;
|
||||
using Umbraco.Cms.Core.Logging.Viewer;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.New.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services;
|
||||
|
||||
public interface ILogViewerService : IService
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets all logs as a paged model. The attempt will fail if the log files
|
||||
/// for the given time period are too large (more than 1GB).
|
||||
/// </summary>
|
||||
/// <param name="startDate">The start date for the date range.</param>
|
||||
/// <param name="endDate">The end date for the date range.</param>
|
||||
/// <param name="skip">The amount of items to skip.</param>
|
||||
/// <param name="take">The amount of items to take.</param>
|
||||
/// <param name="orderDirection">
|
||||
/// The direction in which the log entries are to be ordered.
|
||||
/// </param>
|
||||
/// <param name="filterExpression">The query expression to filter on.</param>
|
||||
/// <param name="logLevels">The log levels for which to retrieve the log messages.</param>
|
||||
Task<Attempt<PagedModel<ILogEntry>?, LogViewerOperationStatus>> GetPagedLogsAsync(
|
||||
DateTime? startDate,
|
||||
DateTime? endDate,
|
||||
int skip,
|
||||
int take,
|
||||
Direction orderDirection = Direction.Descending,
|
||||
string? filterExpression = null,
|
||||
string[]? logLevels = null);
|
||||
|
||||
/// <summary>
|
||||
/// Get all saved log queries from your chosen data source.
|
||||
/// </summary>
|
||||
Task<IReadOnlyList<ILogViewerQuery>> GetSavedLogQueriesAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a saved log query by name from your chosen data source.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the saved log query.</param>
|
||||
Task<ILogViewerQuery?> GetSavedLogQueryByNameAsync(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new saved log query to your chosen data source.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the new saved log query.</param>
|
||||
/// <param name="query">The query of the new saved log query.</param>
|
||||
Task<Attempt<ILogViewerQuery?, LogViewerOperationStatus>> AddSavedLogQueryAsync(string name, string query);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a saved log query to your chosen data source.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the saved log search.</param>
|
||||
Task<Attempt<ILogViewerQuery?, LogViewerOperationStatus>> DeleteSavedLogQueryAsync(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether the log files for the given time
|
||||
/// period are not too large to view (more than 1GB).
|
||||
/// </summary>
|
||||
/// <param name="startDate">The start date for the date range.</param>
|
||||
/// <param name="endDate">The end date for the date range.</param>
|
||||
/// <returns>The value whether or not you are able to view the logs.</returns>
|
||||
Task<Attempt<bool, LogViewerOperationStatus>> CanViewLogsAsync(DateTime? startDate, DateTime? endDate);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a number of the different log level entries.
|
||||
/// The attempt will fail if the log files for the given
|
||||
/// time period are too large (more than 1GB).
|
||||
/// </summary>
|
||||
/// <param name="startDate">The start date for the date range.</param>
|
||||
/// <param name="endDate">The end date for the date range.</param>
|
||||
Task<Attempt<LogLevelCounts?, LogViewerOperationStatus>> GetLogLevelCountsAsync(DateTime? startDate, DateTime? endDate);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of all unique message templates and their counts.
|
||||
/// The attempt will fail if the log files for the given
|
||||
/// time period are too large (more than 1GB).
|
||||
/// </summary>
|
||||
/// <param name="startDate">The start date for the date range.</param>
|
||||
/// <param name="endDate">The end date for the date range.</param>
|
||||
Task<Attempt<IEnumerable<LogTemplate>, LogViewerOperationStatus>> GetMessageTemplatesAsync(DateTime? startDate, DateTime? endDate);
|
||||
|
||||
/// <summary>
|
||||
/// Get the log level values of the global minimum and the UmbracoFile one from the config file.
|
||||
/// </summary>
|
||||
ReadOnlyDictionary<string, LogLevel> GetLogLevelsFromSinks();
|
||||
|
||||
/// <summary>
|
||||
/// Get the minimum log level value from the config file.
|
||||
/// </summary>
|
||||
LogLevel GetGlobalMinLogLevel();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
public enum LogViewerOperationStatus
|
||||
{
|
||||
Success,
|
||||
NotFoundLogSearch,
|
||||
DuplicateLogSearch,
|
||||
CancelledByLogsSizeValidation
|
||||
}
|
||||
@@ -1,5 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Umbraco.Cms.Core.Logging.Viewer.LogLevelCounts</Target>
|
||||
<Left>lib/net7.0/Umbraco.Infrastructure.dll</Left>
|
||||
<Right>lib/net7.0/Umbraco.Infrastructure.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Umbraco.Cms.Core.Logging.Viewer.LogTemplate</Target>
|
||||
<Left>lib/net7.0/Umbraco.Infrastructure.dll</Left>
|
||||
<Right>lib/net7.0/Umbraco.Infrastructure.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Umbraco.Cms.Core.Logging.Viewer.LogTimePeriod</Target>
|
||||
<Left>lib/net7.0/Umbraco.Infrastructure.dll</Left>
|
||||
<Right>lib/net7.0/Umbraco.Infrastructure.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Umbraco.Cms.Infrastructure.Migrations.PostMigrations.ClearCsrfCookies</Target>
|
||||
@@ -126,6 +147,13 @@
|
||||
<Right>lib/net7.0/Umbraco.Infrastructure.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0006</DiagnosticId>
|
||||
<Target>M:Umbraco.Cms.Core.Logging.Viewer.ILogViewer.GetLogsAsPagedModel(Umbraco.Cms.Core.Logging.Viewer.LogTimePeriod,System.Int32,System.Int32,Umbraco.Cms.Core.Direction,System.String,System.String[])</Target>
|
||||
<Left>lib/net7.0/Umbraco.Infrastructure.dll</Left>
|
||||
<Right>lib/net7.0/Umbraco.Infrastructure.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0006</DiagnosticId>
|
||||
<Target>M:Umbraco.Cms.Core.Migrations.IMigrationPlanExecutor.ExecutePlan(Umbraco.Cms.Infrastructure.Migrations.MigrationPlan,System.String)</Target>
|
||||
|
||||
@@ -32,6 +32,7 @@ using Umbraco.Cms.Core.Runtime;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.Implement;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Cms.Core.Templates;
|
||||
using Umbraco.Cms.Core.Trees;
|
||||
@@ -232,6 +233,7 @@ public static partial class UmbracoBuilderExtensions
|
||||
factory.GetRequiredService<ILoggingConfiguration>(),
|
||||
factory.GetRequiredService<ILogLevelLoader>(),
|
||||
Log.Logger));
|
||||
builder.Services.AddSingleton<ILogViewerService, LogViewerService>();
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using Serilog.Events;
|
||||
|
||||
namespace Umbraco.Cms.Core.Logging.Viewer;
|
||||
|
||||
[Obsolete("Use ILogViewerService instead. Scheduled for removal in Umbraco 15.")]
|
||||
public interface ILogLevelLoader
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.New.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Core.Logging.Viewer;
|
||||
|
||||
@@ -9,16 +10,19 @@ public interface ILogViewer
|
||||
/// <summary>
|
||||
/// Get all saved searches from your chosen data source
|
||||
/// </summary>
|
||||
[Obsolete("Use ILogViewerService.GetSavedLogQueriesAsync instead. Scheduled for removal in Umbraco 15.")]
|
||||
IReadOnlyList<SavedLogSearch> GetSavedSearches();
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new saved search to chosen data source and returns the updated searches
|
||||
/// </summary>
|
||||
[Obsolete("Use ILogViewerService.AddSavedLogQueryAsync instead. Scheduled for removal in Umbraco 15.")]
|
||||
IReadOnlyList<SavedLogSearch> AddSavedSearch(string name, string query);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a saved search to chosen data source and returns the remaining searches
|
||||
/// </summary>
|
||||
[Obsolete("Use ILogViewerService.DeleteSavedLogQueryAsync instead. Scheduled for removal in Umbraco 15.")]
|
||||
IReadOnlyList<SavedLogSearch> DeleteSavedSearch(string name) => DeleteSavedSearch(name, string.Empty);
|
||||
|
||||
[Obsolete("Use the overload that only takes a 'name' parameter instead. This will be removed in Umbraco 14.")]
|
||||
@@ -33,18 +37,22 @@ public interface ILogViewer
|
||||
/// <summary>
|
||||
/// Returns a number of the different log level entries
|
||||
/// </summary>
|
||||
[Obsolete("Use ILogViewerService.GetLogLevelCounts instead. Scheduled for removal in Umbraco 15.")]
|
||||
LogLevelCounts GetLogLevelCounts(LogTimePeriod logTimePeriod);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of all unique message templates and their counts
|
||||
/// </summary>
|
||||
[Obsolete("Use ILogViewerService.GetMessageTemplates instead. Scheduled for removal in Umbraco 15.")]
|
||||
IEnumerable<LogTemplate> GetMessageTemplates(LogTimePeriod logTimePeriod);
|
||||
|
||||
[Obsolete("Use ILogViewerService.CanViewLogsAsync instead. Scheduled for removal in Umbraco 15.")]
|
||||
bool CheckCanOpenLogs(LogTimePeriod logTimePeriod);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the collection of logs
|
||||
/// </summary>
|
||||
[Obsolete("Use ILogViewerService.GetPagedLogs instead. Scheduled for removal in Umbraco 15.")]
|
||||
PagedResult<LogMessage> GetLogs(
|
||||
LogTimePeriod logTimePeriod,
|
||||
int pageNumber = 1,
|
||||
@@ -52,4 +60,13 @@ public interface ILogViewer
|
||||
Direction orderDirection = Direction.Descending,
|
||||
string? filterExpression = null,
|
||||
string[]? logLevels = null);
|
||||
|
||||
[Obsolete("Use ILogViewerService.GetPagedLogs instead. Scheduled for removal in Umbraco 15.")]
|
||||
PagedModel<LogMessage> GetLogsAsPagedModel(
|
||||
LogTimePeriod logTimePeriod,
|
||||
int skip,
|
||||
int take,
|
||||
Direction orderDirection = Direction.Descending,
|
||||
string? filterExpression = null,
|
||||
string[]? logLevels = null);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
namespace Umbraco.Cms.Core.Logging.Viewer;
|
||||
|
||||
[Obsolete("Use ILogViewerService instead. Scheduled for removal in Umbraco 15.")]
|
||||
public interface ILogViewerConfig
|
||||
{
|
||||
IReadOnlyList<SavedLogSearch> GetSavedSearches();
|
||||
|
||||
@@ -14,6 +14,7 @@ public class LogLevelLoader : ILogLevelLoader
|
||||
/// <summary>
|
||||
/// Get the Serilog level values of the global minimum and the UmbracoFile one from the config file.
|
||||
/// </summary>
|
||||
[Obsolete("Use ILogViewerService.GetLogLevelsFromSinks instead. Scheduled for removal in Umbraco 15.")]
|
||||
public ReadOnlyDictionary<string, LogEventLevel?> GetLogLevelsFromSinks()
|
||||
{
|
||||
var configuredLogLevels = new Dictionary<string, LogEventLevel?>
|
||||
@@ -27,6 +28,7 @@ public class LogLevelLoader : ILogLevelLoader
|
||||
/// <summary>
|
||||
/// Get the Serilog minimum-level value from the config file.
|
||||
/// </summary>
|
||||
[Obsolete("Use ILogViewerService.GetGlobalMinLogLevel instead. Scheduled for removal in Umbraco 15.")]
|
||||
public LogEventLevel? GetGlobalMinLogLevel()
|
||||
{
|
||||
LogEventLevel? logLevel = Enum.GetValues(typeof(LogEventLevel)).Cast<LogEventLevel>().Where(Log.IsEnabled)
|
||||
|
||||
@@ -5,6 +5,7 @@ using Serilog.Events;
|
||||
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||
namespace Umbraco.Cms.Core.Logging.Viewer;
|
||||
|
||||
[Obsolete("Use ILogEntry instead. Scheduled for removal in Umbraco 15.")]
|
||||
public class LogMessage
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -16,6 +16,7 @@ public class LogViewerConfig : ILogViewerConfig
|
||||
_scopeProvider = scopeProvider;
|
||||
}
|
||||
|
||||
[Obsolete("Use ILogViewerService.GetSavedLogQueriesAsync instead. Scheduled for removal in Umbraco 15.")]
|
||||
public IReadOnlyList<SavedLogSearch> GetSavedSearches()
|
||||
{
|
||||
using IScope scope = _scopeProvider.CreateScope(autoComplete: true);
|
||||
@@ -24,6 +25,7 @@ public class LogViewerConfig : ILogViewerConfig
|
||||
return result;
|
||||
}
|
||||
|
||||
[Obsolete("Use ILogViewerService.AddSavedLogQueryAsync instead. Scheduled for removal in Umbraco 15.")]
|
||||
public IReadOnlyList<SavedLogSearch> AddSavedSearch(string name, string query)
|
||||
{
|
||||
using IScope scope = _scopeProvider.CreateScope(autoComplete: true);
|
||||
@@ -35,6 +37,7 @@ public class LogViewerConfig : ILogViewerConfig
|
||||
[Obsolete("Use the overload that only takes a 'name' parameter instead. This will be removed in Umbraco 14.")]
|
||||
public IReadOnlyList<SavedLogSearch> DeleteSavedSearch(string name, string query) => DeleteSavedSearch(name);
|
||||
|
||||
[Obsolete("Use ILogViewerService.DeleteSavedLogQueryAsync instead. Scheduled for removal in Umbraco 15.")]
|
||||
public IReadOnlyList<SavedLogSearch> DeleteSavedSearch(string name)
|
||||
{
|
||||
using IScope scope = _scopeProvider.CreateScope(autoComplete: true);
|
||||
|
||||
@@ -26,6 +26,7 @@ internal class SerilogJsonLogViewer : SerilogLogViewerSourceBase
|
||||
|
||||
public override bool CanHandleLargeLogs => false;
|
||||
|
||||
[Obsolete("Use ILogViewerService.CanViewLogsAsync instead. Scheduled for removal in Umbraco 15.")]
|
||||
public override bool CheckCanOpenLogs(LogTimePeriod logTimePeriod)
|
||||
{
|
||||
// Log Directory
|
||||
|
||||
@@ -3,6 +3,7 @@ using Serilog;
|
||||
using Serilog.Events;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Extensions;
|
||||
using Umbraco.New.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Core.Logging.Viewer;
|
||||
|
||||
@@ -19,11 +20,14 @@ public abstract class SerilogLogViewerSourceBase : ILogViewer
|
||||
|
||||
public abstract bool CanHandleLargeLogs { get; }
|
||||
|
||||
[Obsolete("Use ILogViewerService.CanViewLogsAsync instead. Scheduled for removal in Umbraco 15.")]
|
||||
public abstract bool CheckCanOpenLogs(LogTimePeriod logTimePeriod);
|
||||
|
||||
[Obsolete("Use ILogViewerService.GetSavedLogQueriesAsync instead. Scheduled for removal in Umbraco 15.")]
|
||||
public virtual IReadOnlyList<SavedLogSearch> GetSavedSearches()
|
||||
=> _logViewerConfig.GetSavedSearches();
|
||||
|
||||
[Obsolete("Use ILogViewerService.AddSavedLogQueryAsync instead. Scheduled for removal in Umbraco 15.")]
|
||||
public virtual IReadOnlyList<SavedLogSearch> AddSavedSearch(string name, string query)
|
||||
=> _logViewerConfig.AddSavedSearch(name, query);
|
||||
|
||||
@@ -31,6 +35,7 @@ public abstract class SerilogLogViewerSourceBase : ILogViewer
|
||||
public virtual IReadOnlyList<SavedLogSearch> DeleteSavedSearch(string name, string query)
|
||||
=> DeleteSavedSearch(name);
|
||||
|
||||
[Obsolete("Use ILogViewerService.DeleteSavedLogQueryAsync instead. Scheduled for removal in Umbraco 15.")]
|
||||
public virtual IReadOnlyList<SavedLogSearch> DeleteSavedSearch(string name)
|
||||
=> _logViewerConfig.DeleteSavedSearch(name);
|
||||
|
||||
@@ -41,6 +46,7 @@ public abstract class SerilogLogViewerSourceBase : ILogViewer
|
||||
return errorCounter.Count;
|
||||
}
|
||||
|
||||
[Obsolete("Use ILogViewerService.GetLogLevelCounts instead. Scheduled for removal in Umbraco 15.")]
|
||||
public LogLevelCounts GetLogLevelCounts(LogTimePeriod logTimePeriod)
|
||||
{
|
||||
var counter = new CountingFilter();
|
||||
@@ -48,6 +54,7 @@ public abstract class SerilogLogViewerSourceBase : ILogViewer
|
||||
return counter.Counts;
|
||||
}
|
||||
|
||||
[Obsolete("Use ILogViewerService.GetMessageTemplates instead. Scheduled for removal in Umbraco 15.")]
|
||||
public IEnumerable<LogTemplate> GetMessageTemplates(LogTimePeriod logTimePeriod)
|
||||
{
|
||||
var messageTemplates = new MessageTemplateFilter();
|
||||
@@ -60,6 +67,7 @@ public abstract class SerilogLogViewerSourceBase : ILogViewer
|
||||
return templates;
|
||||
}
|
||||
|
||||
[Obsolete("Use ILogViewerService.GetPagedLogs instead. Scheduled for removal in Umbraco 15.")]
|
||||
public PagedResult<LogMessage> GetLogs(
|
||||
LogTimePeriod logTimePeriod,
|
||||
int pageNumber = 1,
|
||||
@@ -67,6 +75,72 @@ public abstract class SerilogLogViewerSourceBase : ILogViewer
|
||||
Direction orderDirection = Direction.Descending,
|
||||
string? filterExpression = null,
|
||||
string[]? logLevels = null)
|
||||
{
|
||||
IReadOnlyList<LogEvent> filteredLogs = GetFilteredLogs(logTimePeriod, filterExpression, logLevels);
|
||||
long totalRecords = filteredLogs.Count;
|
||||
|
||||
// Order By, Skip, Take & Select
|
||||
IEnumerable<LogMessage> logMessages = filteredLogs
|
||||
.OrderBy(l => l.Timestamp, orderDirection)
|
||||
.Skip(pageSize * (pageNumber - 1))
|
||||
.Take(pageSize)
|
||||
.Select(x => new LogMessage
|
||||
{
|
||||
Timestamp = x.Timestamp,
|
||||
Level = x.Level,
|
||||
MessageTemplateText = x.MessageTemplate.Text,
|
||||
Exception = x.Exception?.ToString(),
|
||||
Properties = x.Properties,
|
||||
RenderedMessage = x.RenderMessage(),
|
||||
});
|
||||
|
||||
return new PagedResult<LogMessage>(totalRecords, pageNumber, pageSize) { Items = logMessages };
|
||||
}
|
||||
|
||||
[Obsolete("Use ILogViewerService.GetPagedLogs instead. Scheduled for removal in Umbraco 15.")]
|
||||
public PagedModel<LogMessage> GetLogsAsPagedModel(
|
||||
LogTimePeriod logTimePeriod,
|
||||
int skip,
|
||||
int take,
|
||||
Direction orderDirection = Direction.Descending,
|
||||
string? filterExpression = null,
|
||||
string[]? logLevels = null)
|
||||
{
|
||||
IReadOnlyList<LogEvent> filteredLogs = GetFilteredLogs(logTimePeriod, filterExpression, logLevels);
|
||||
|
||||
// Order By, Skip, Take & Select
|
||||
IEnumerable<LogMessage> logMessages = filteredLogs
|
||||
.OrderBy(l => l.Timestamp, orderDirection)
|
||||
.Skip(skip)
|
||||
.Take(take)
|
||||
.Select(x => new LogMessage
|
||||
{
|
||||
Timestamp = x.Timestamp,
|
||||
Level = x.Level,
|
||||
MessageTemplateText = x.MessageTemplate.Text,
|
||||
Exception = x.Exception?.ToString(),
|
||||
Properties = x.Properties,
|
||||
RenderedMessage = x.RenderMessage(),
|
||||
});
|
||||
|
||||
return new PagedModel<LogMessage>(logMessages.Count(), logMessages);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the Serilog minimum-level and UmbracoFile-level values from the config file.
|
||||
/// </summary>
|
||||
[Obsolete("Use ILogViewerService.GetLogLevelsFromSinks instead. Scheduled for removal in Umbraco 15.")]
|
||||
public ReadOnlyDictionary<string, LogEventLevel?> GetLogLevels() => _logLevelLoader.GetLogLevelsFromSinks();
|
||||
|
||||
/// <summary>
|
||||
/// Get all logs from your chosen data source back as Serilog LogEvents
|
||||
/// </summary>
|
||||
protected abstract IReadOnlyList<LogEvent> GetLogs(LogTimePeriod logTimePeriod, ILogFilter filter, int skip, int take);
|
||||
|
||||
private IReadOnlyList<LogEvent> GetFilteredLogs(
|
||||
LogTimePeriod logTimePeriod,
|
||||
string? filterExpression,
|
||||
string[]? logLevels)
|
||||
{
|
||||
var expression = new ExpressionFilter(filterExpression);
|
||||
IReadOnlyList<LogEvent> filteredLogs = GetLogs(logTimePeriod, expression, 0, int.MaxValue);
|
||||
@@ -98,33 +172,6 @@ public abstract class SerilogLogViewerSourceBase : ILogViewer
|
||||
}
|
||||
}
|
||||
|
||||
long totalRecords = filteredLogs.Count;
|
||||
|
||||
// Order By, Skip, Take & Select
|
||||
IEnumerable<LogMessage> logMessages = filteredLogs
|
||||
.OrderBy(l => l.Timestamp, orderDirection)
|
||||
.Skip(pageSize * (pageNumber - 1))
|
||||
.Take(pageSize)
|
||||
.Select(x => new LogMessage
|
||||
{
|
||||
Timestamp = x.Timestamp,
|
||||
Level = x.Level,
|
||||
MessageTemplateText = x.MessageTemplate.Text,
|
||||
Exception = x.Exception?.ToString(),
|
||||
Properties = x.Properties,
|
||||
RenderedMessage = x.RenderMessage(),
|
||||
});
|
||||
|
||||
return new PagedResult<LogMessage>(totalRecords, pageNumber, pageSize) { Items = logMessages };
|
||||
return filteredLogs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the Serilog minimum-level and UmbracoFile-level values from the config file.
|
||||
/// </summary>
|
||||
public ReadOnlyDictionary<string, LogEventLevel?> GetLogLevels() => _logLevelLoader.GetLogLevelsFromSinks();
|
||||
|
||||
/// <summary>
|
||||
/// Get all logs from your chosen data source back as Serilog LogEvents
|
||||
/// </summary>
|
||||
protected abstract IReadOnlyList<LogEvent> GetLogs(LogTimePeriod logTimePeriod, ILogFilter filter, int skip, int take);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
using Serilog.Events;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using Umbraco.Cms.Core.Logging.Viewer;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Persistence.Repositories;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.Extensions;
|
||||
using Umbraco.New.Cms.Core.Models;
|
||||
using LogLevel = Umbraco.Cms.Core.Logging.LogLevel;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services.Implement;
|
||||
|
||||
// FIXME: Get rid of ILogViewer and ILogLevelLoader dependencies (as they are obsolete)
|
||||
// and fix the implementation of the methods using it
|
||||
public class LogViewerService : ILogViewerService
|
||||
{
|
||||
private readonly ILogViewerQueryRepository _logViewerQueryRepository;
|
||||
private readonly ILogViewer _logViewer;
|
||||
private readonly ILogLevelLoader _logLevelLoader;
|
||||
private readonly ICoreScopeProvider _provider;
|
||||
|
||||
public LogViewerService(
|
||||
ILogViewerQueryRepository logViewerQueryRepository,
|
||||
ILogViewer logViewer,
|
||||
ILogLevelLoader logLevelLoader,
|
||||
ICoreScopeProvider provider)
|
||||
{
|
||||
_logViewerQueryRepository = logViewerQueryRepository;
|
||||
_logViewer = logViewer;
|
||||
_logLevelLoader = logLevelLoader;
|
||||
_provider = provider;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<Attempt<PagedModel<ILogEntry>?, LogViewerOperationStatus>> GetPagedLogsAsync(
|
||||
DateTime? startDate,
|
||||
DateTime? endDate,
|
||||
int skip,
|
||||
int take,
|
||||
Direction orderDirection = Direction.Descending,
|
||||
string? filterExpression = null,
|
||||
string[]? logLevels = null)
|
||||
{
|
||||
LogTimePeriod logTimePeriod = GetTimePeriod(startDate, endDate);
|
||||
|
||||
// We will need to stop the request if trying to do this on a 1GB file
|
||||
if (CanViewLogs(logTimePeriod) == false)
|
||||
{
|
||||
return Attempt.FailWithStatus<PagedModel<ILogEntry>?, LogViewerOperationStatus>(
|
||||
LogViewerOperationStatus.CancelledByLogsSizeValidation,
|
||||
null);
|
||||
}
|
||||
|
||||
PagedModel<LogMessage> logMessages =
|
||||
_logViewer.GetLogsAsPagedModel(logTimePeriod, skip, take, orderDirection, filterExpression, logLevels);
|
||||
|
||||
var logEntries = new PagedModel<ILogEntry>(logMessages.Total, logMessages.Items.Select(x => ToLogEntry(x)));
|
||||
|
||||
return Attempt.SucceedWithStatus<PagedModel<ILogEntry>?, LogViewerOperationStatus>(
|
||||
LogViewerOperationStatus.Success,
|
||||
logEntries);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<IReadOnlyList<ILogViewerQuery>> GetSavedLogQueriesAsync()
|
||||
{
|
||||
using ICoreScope scope = _provider.CreateCoreScope(autoComplete: true);
|
||||
return await Task.FromResult(_logViewerQueryRepository.GetMany().ToList());
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<ILogViewerQuery?> GetSavedLogQueryByNameAsync(string name)
|
||||
{
|
||||
using ICoreScope scope = _provider.CreateCoreScope(autoComplete: true);
|
||||
return await Task.FromResult(_logViewerQueryRepository.GetByName(name));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<Attempt<ILogViewerQuery?, LogViewerOperationStatus>> AddSavedLogQueryAsync(string name, string query)
|
||||
{
|
||||
ILogViewerQuery? logViewerQuery = await GetSavedLogQueryByNameAsync(name);
|
||||
|
||||
if (logViewerQuery is not null)
|
||||
{
|
||||
return Attempt.FailWithStatus<ILogViewerQuery?, LogViewerOperationStatus>(LogViewerOperationStatus.DuplicateLogSearch, null);
|
||||
}
|
||||
|
||||
logViewerQuery = new LogViewerQuery(name, query);
|
||||
|
||||
using ICoreScope scope = _provider.CreateCoreScope(autoComplete: true);
|
||||
_logViewerQueryRepository.Save(logViewerQuery);
|
||||
|
||||
return Attempt.SucceedWithStatus<ILogViewerQuery?, LogViewerOperationStatus>(LogViewerOperationStatus.Success, logViewerQuery);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<Attempt<ILogViewerQuery?, LogViewerOperationStatus>> DeleteSavedLogQueryAsync(string name)
|
||||
{
|
||||
ILogViewerQuery? logViewerQuery = await GetSavedLogQueryByNameAsync(name);
|
||||
|
||||
if (logViewerQuery is null)
|
||||
{
|
||||
return Attempt.FailWithStatus<ILogViewerQuery?, LogViewerOperationStatus>(LogViewerOperationStatus.NotFoundLogSearch, null);
|
||||
}
|
||||
|
||||
using ICoreScope scope = _provider.CreateCoreScope(autoComplete: true);
|
||||
_logViewerQueryRepository.Delete(logViewerQuery);
|
||||
|
||||
return Attempt.SucceedWithStatus<ILogViewerQuery?, LogViewerOperationStatus>(LogViewerOperationStatus.Success, logViewerQuery);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<Attempt<bool, LogViewerOperationStatus>> CanViewLogsAsync(DateTime? startDate, DateTime? endDate)
|
||||
{
|
||||
LogTimePeriod logTimePeriod = GetTimePeriod(startDate, endDate);
|
||||
bool isAllowed = CanViewLogs(logTimePeriod);
|
||||
|
||||
if (isAllowed == false)
|
||||
{
|
||||
return Attempt.FailWithStatus(LogViewerOperationStatus.CancelledByLogsSizeValidation, isAllowed);
|
||||
}
|
||||
|
||||
return Attempt.SucceedWithStatus(LogViewerOperationStatus.Success, isAllowed);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<Attempt<LogLevelCounts?, LogViewerOperationStatus>> GetLogLevelCountsAsync(DateTime? startDate, DateTime? endDate)
|
||||
{
|
||||
LogTimePeriod logTimePeriod = GetTimePeriod(startDate, endDate);
|
||||
|
||||
// We will need to stop the request if trying to do this on a 1GB file
|
||||
if (CanViewLogs(logTimePeriod) == false)
|
||||
{
|
||||
return Attempt.FailWithStatus<LogLevelCounts?, LogViewerOperationStatus>(
|
||||
LogViewerOperationStatus.CancelledByLogsSizeValidation,
|
||||
null);
|
||||
}
|
||||
|
||||
return Attempt.SucceedWithStatus<LogLevelCounts?, LogViewerOperationStatus>(
|
||||
LogViewerOperationStatus.Success,
|
||||
_logViewer.GetLogLevelCounts(logTimePeriod));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<Attempt<IEnumerable<LogTemplate>, LogViewerOperationStatus>> GetMessageTemplatesAsync(DateTime? startDate, DateTime? endDate)
|
||||
{
|
||||
LogTimePeriod logTimePeriod = GetTimePeriod(startDate, endDate);
|
||||
|
||||
// We will need to stop the request if trying to do this on a 1GB file
|
||||
if (CanViewLogs(logTimePeriod) == false)
|
||||
{
|
||||
return Attempt.FailWithStatus(
|
||||
LogViewerOperationStatus.CancelledByLogsSizeValidation,
|
||||
Enumerable.Empty<LogTemplate>());
|
||||
}
|
||||
|
||||
return Attempt.SucceedWithStatus(
|
||||
LogViewerOperationStatus.Success,
|
||||
_logViewer.GetMessageTemplates(logTimePeriod));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ReadOnlyDictionary<string, LogLevel> GetLogLevelsFromSinks()
|
||||
{
|
||||
ReadOnlyDictionary<string, LogEventLevel?> configuredLogLevels = _logLevelLoader.GetLogLevelsFromSinks();
|
||||
|
||||
return configuredLogLevels.ToDictionary(logLevel => logLevel.Key, logLevel => Enum.Parse<LogLevel>(logLevel.Value!.ToString()!)).AsReadOnly();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public LogLevel GetGlobalMinLogLevel()
|
||||
{
|
||||
LogEventLevel? serilogLogLevel = _logLevelLoader.GetGlobalMinLogLevel();
|
||||
|
||||
return Enum.Parse<LogLevel>(serilogLogLevel!.ToString()!);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="LogTimePeriod" /> representation from a start and end date for filtering log files.
|
||||
/// </summary>
|
||||
/// <param name="startDate">The start date for the date range (can be null).</param>
|
||||
/// <param name="endDate">The end date for the date range (can be null).</param>
|
||||
/// <returns>The LogTimePeriod object used to filter logs.</returns>
|
||||
private LogTimePeriod GetTimePeriod(DateTime? startDate, DateTime? endDate)
|
||||
{
|
||||
if (startDate is null || endDate is null)
|
||||
{
|
||||
DateTime now = DateTime.Now;
|
||||
if (startDate is null)
|
||||
{
|
||||
startDate = now.AddDays(-1);
|
||||
}
|
||||
|
||||
if (endDate is null)
|
||||
{
|
||||
endDate = now;
|
||||
}
|
||||
}
|
||||
|
||||
return new LogTimePeriod(startDate.Value, endDate.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether to stop a GET request that is attempting to fetch logs from a 1GB file.
|
||||
/// </summary>
|
||||
/// <param name="logTimePeriod">The time period to filter the logs.</param>
|
||||
/// <returns>The value whether or not you are able to view the logs.</returns>
|
||||
private bool CanViewLogs(LogTimePeriod logTimePeriod)
|
||||
{
|
||||
// Check if the interface can deal with large files
|
||||
if (_logViewer.CanHandleLargeLogs)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return _logViewer.CheckCanOpenLogs(logTimePeriod);
|
||||
}
|
||||
|
||||
private ILogEntry ToLogEntry(LogMessage logMessage)
|
||||
{
|
||||
return new LogEntry()
|
||||
{
|
||||
Timestamp = logMessage.Timestamp,
|
||||
Level = Enum.Parse<LogLevel>(logMessage.Level.ToString()),
|
||||
MessageTemplateText = logMessage.MessageTemplateText,
|
||||
RenderedMessage = logMessage.RenderedMessage,
|
||||
Properties = MapLogMessageProperties(logMessage.Properties),
|
||||
Exception = logMessage.Exception
|
||||
};
|
||||
}
|
||||
|
||||
private IReadOnlyDictionary<string, string?> MapLogMessageProperties(IReadOnlyDictionary<string, LogEventPropertyValue>? properties)
|
||||
{
|
||||
var result = new Dictionary<string, string?>();
|
||||
|
||||
if (properties is not null)
|
||||
{
|
||||
foreach (KeyValuePair<string, LogEventPropertyValue> property in properties)
|
||||
{
|
||||
string? value;
|
||||
|
||||
if (property.Value is ScalarValue scalarValue)
|
||||
{
|
||||
value = scalarValue.Value?.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
// When polymorphism is implemented, this should be changed
|
||||
value = JsonSerializer.Serialize(property.Value as object);
|
||||
}
|
||||
|
||||
result.Add(property.Key, value);
|
||||
}
|
||||
}
|
||||
|
||||
return result.AsReadOnly();
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Serilog.Events;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Logging.Viewer;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Web.Common.Attributes;
|
||||
|
||||
@@ -181,8 +181,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Cms.Imaging.ImageSh
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{05878304-40EB-4F84-B40B-91BDB70DE094}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Umbraco.Web.UI.New", "src\Umbraco.Web.UI.New\Umbraco.Web.UI.New.csproj", "{C55CA725-9F4E-4618-9435-6B8AE05DA14D}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Umbraco.Cms.Api.Common", "src\Umbraco.Cms.Api.Common\Umbraco.Cms.Api.Common.csproj", "{D48B5D6B-82FF-4235-986C-CDE646F41DEC}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Web.UI.New", "src\Umbraco.Web.UI.New\Umbraco.Web.UI.New.csproj", "{C55CA725-9F4E-4618-9435-6B8AE05DA14D}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Cms.Api.Common", "src\Umbraco.Cms.Api.Common\Umbraco.Cms.Api.Common.csproj", "{D48B5D6B-82FF-4235-986C-CDE646F41DEC}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
||||
Reference in New Issue
Block a user