Skip to content

Commit d9e7e9e

Browse files
Make logging more friendly for docker (#19818)
* Cleanup obsoleted methods * Add a way to disable UmbracoFile default sink * Abstract LogViewService so only UmbracoFile sink related things are in the default interface implementation. * Abstract LogViewRepository so only UmbracoFile sink related things are in the default interface implementation. * Move GetGlobalLogLevelEventMinLevel to base * Removed unused internal class and obsoleted its base * Added missing XML header comments and resolved warnings in service and repository classes. * Made private method static. * Addressed issues raised in code review. * Expose repository from the service base class. * Restored further obsoleted code we can't remove yet. * Removed log viewer tests on removed class. We have integration tests for the new service. * Obsoleted ILogViewer interface. --------- Co-authored-by: Andy Butland <[email protected]>
1 parent a1d1c54 commit d9e7e9e

File tree

13 files changed

+420
-710
lines changed

13 files changed

+420
-710
lines changed

src/Umbraco.Core/Services/ILogViewerRepository.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
using Umbraco.Cms.Core.Logging;
1+
using Umbraco.Cms.Core.Logging;
22
using Umbraco.Cms.Core.Logging.Viewer;
33

44
namespace Umbraco.Cms.Core.Services;
55

6+
/// <summary>
7+
/// Represents a repository for viewing logs in Umbraco.
8+
/// </summary>
69
public interface ILogViewerRepository
710
{
811
/// <summary>
Lines changed: 18 additions & 219 deletions
Original file line numberDiff line numberDiff line change
@@ -1,212 +1,58 @@
1-
using System.Collections.ObjectModel;
21
using Umbraco.Cms.Core.Logging;
32
using Umbraco.Cms.Core.Logging.Viewer;
4-
using Umbraco.Cms.Core.Models;
53
using Umbraco.Cms.Core.Persistence.Repositories;
64
using Umbraco.Cms.Core.Scoping;
75
using Umbraco.Cms.Core.Services.OperationStatus;
8-
using Umbraco.Extensions;
9-
using LogLevel = Umbraco.Cms.Core.Logging.LogLevel;
106

117
namespace Umbraco.Cms.Core.Services;
128

13-
public class LogViewerService : ILogViewerService
9+
/// <summary>
10+
/// Represents a service for viewing logs in Umbraco.
11+
/// </summary>
12+
public class LogViewerService : LogViewerServiceBase
1413
{
1514
private const int FileSizeCap = 100;
16-
private readonly ILogViewerQueryRepository _logViewerQueryRepository;
17-
private readonly ICoreScopeProvider _provider;
1815
private readonly ILoggingConfiguration _loggingConfiguration;
19-
private readonly ILogViewerRepository _logViewerRepository;
2016

17+
/// <summary>
18+
/// Initializes a new instance of the <see cref="LogViewerService"/> class.
19+
/// </summary>
2120
public LogViewerService(
2221
ILogViewerQueryRepository logViewerQueryRepository,
2322
ICoreScopeProvider provider,
2423
ILoggingConfiguration loggingConfiguration,
2524
ILogViewerRepository logViewerRepository)
25+
: base(
26+
logViewerQueryRepository,
27+
provider,
28+
logViewerRepository)
2629
{
27-
_logViewerQueryRepository = logViewerQueryRepository;
28-
_provider = provider;
2930
_loggingConfiguration = loggingConfiguration;
30-
_logViewerRepository = logViewerRepository;
31-
}
32-
33-
/// <inheritdoc/>
34-
public Task<Attempt<PagedModel<ILogEntry>?, LogViewerOperationStatus>> GetPagedLogsAsync(
35-
DateTimeOffset? startDate,
36-
DateTimeOffset? endDate,
37-
int skip,
38-
int take,
39-
Direction orderDirection = Direction.Descending,
40-
string? filterExpression = null,
41-
string[]? logLevels = null)
42-
{
43-
LogTimePeriod logTimePeriod = GetTimePeriod(startDate, endDate);
44-
45-
// We will need to stop the request if trying to do this on a 1GB file
46-
if (CanViewLogs(logTimePeriod) == false)
47-
{
48-
return Task.FromResult(Attempt.FailWithStatus<PagedModel<ILogEntry>?, LogViewerOperationStatus>(
49-
LogViewerOperationStatus.CancelledByLogsSizeValidation,
50-
null));
51-
}
52-
53-
54-
PagedModel<ILogEntry> filteredLogs = GetFilteredLogs(logTimePeriod, filterExpression, logLevels, orderDirection, skip, take);
55-
56-
return Task.FromResult(Attempt.SucceedWithStatus<PagedModel<ILogEntry>?, LogViewerOperationStatus>(
57-
LogViewerOperationStatus.Success,
58-
filteredLogs));
5931
}
6032

6133
/// <inheritdoc/>
62-
public Task<PagedModel<ILogViewerQuery>> GetSavedLogQueriesAsync(int skip, int take)
63-
{
64-
using ICoreScope scope = _provider.CreateCoreScope(autoComplete: true);
65-
ILogViewerQuery[] savedLogQueries = _logViewerQueryRepository.GetMany().ToArray();
66-
var pagedModel = new PagedModel<ILogViewerQuery>(savedLogQueries.Length, savedLogQueries.Skip(skip).Take(take));
67-
return Task.FromResult(pagedModel);
68-
}
34+
protected override string LoggerName => "UmbracoFile";
6935

7036
/// <inheritdoc/>
71-
public Task<ILogViewerQuery?> GetSavedLogQueryByNameAsync(string name)
37+
public override Task<Attempt<bool, LogViewerOperationStatus>> CanViewLogsAsync(LogTimePeriod logTimePeriod)
7238
{
73-
using ICoreScope scope = _provider.CreateCoreScope(autoComplete: true);
74-
return Task.FromResult(_logViewerQueryRepository.GetByName(name));
75-
}
76-
77-
/// <inheritdoc/>
78-
public async Task<Attempt<ILogViewerQuery?, LogViewerOperationStatus>> AddSavedLogQueryAsync(string name, string query)
79-
{
80-
ILogViewerQuery? logViewerQuery = await GetSavedLogQueryByNameAsync(name);
81-
82-
if (logViewerQuery is not null)
83-
{
84-
return Attempt.FailWithStatus<ILogViewerQuery?, LogViewerOperationStatus>(LogViewerOperationStatus.DuplicateLogSearch, null);
85-
}
86-
87-
logViewerQuery = new LogViewerQuery(name, query);
88-
89-
using ICoreScope scope = _provider.CreateCoreScope(autoComplete: true);
90-
_logViewerQueryRepository.Save(logViewerQuery);
91-
92-
return Attempt.SucceedWithStatus<ILogViewerQuery?, LogViewerOperationStatus>(LogViewerOperationStatus.Success, logViewerQuery);
93-
}
94-
95-
/// <inheritdoc/>
96-
public async Task<Attempt<ILogViewerQuery?, LogViewerOperationStatus>> DeleteSavedLogQueryAsync(string name)
97-
{
98-
ILogViewerQuery? logViewerQuery = await GetSavedLogQueryByNameAsync(name);
99-
100-
if (logViewerQuery is null)
101-
{
102-
return Attempt.FailWithStatus<ILogViewerQuery?, LogViewerOperationStatus>(LogViewerOperationStatus.NotFoundLogSearch, null);
103-
}
104-
105-
using ICoreScope scope = _provider.CreateCoreScope(autoComplete: true);
106-
_logViewerQueryRepository.Delete(logViewerQuery);
107-
108-
return Attempt.SucceedWithStatus<ILogViewerQuery?, LogViewerOperationStatus>(LogViewerOperationStatus.Success, logViewerQuery);
109-
}
110-
111-
/// <inheritdoc/>
112-
public Task<Attempt<bool, LogViewerOperationStatus>> CanViewLogsAsync(DateTimeOffset? startDate, DateTimeOffset? endDate)
113-
{
114-
LogTimePeriod logTimePeriod = GetTimePeriod(startDate, endDate);
11539
bool isAllowed = CanViewLogs(logTimePeriod);
11640

11741
if (isAllowed == false)
11842
{
119-
return Task.FromResult(Attempt.FailWithStatus(LogViewerOperationStatus.CancelledByLogsSizeValidation, isAllowed));
120-
}
121-
122-
return Task.FromResult(Attempt.SucceedWithStatus(LogViewerOperationStatus.Success, isAllowed));
123-
}
124-
125-
/// <inheritdoc/>
126-
public Task<Attempt<LogLevelCounts?, LogViewerOperationStatus>> GetLogLevelCountsAsync(DateTimeOffset? startDate, DateTimeOffset? endDate)
127-
{
128-
LogTimePeriod logTimePeriod = GetTimePeriod(startDate, endDate);
129-
130-
// We will need to stop the request if trying to do this on a 1GB file
131-
if (CanViewLogs(logTimePeriod) == false)
132-
{
133-
return Task.FromResult(Attempt.FailWithStatus<LogLevelCounts?, LogViewerOperationStatus>(
43+
return Task.FromResult(Attempt.FailWithStatus(
13444
LogViewerOperationStatus.CancelledByLogsSizeValidation,
135-
null));
136-
}
137-
138-
LogLevelCounts counter = _logViewerRepository.GetLogCount(logTimePeriod);
139-
140-
return Task.FromResult(Attempt.SucceedWithStatus<LogLevelCounts?, LogViewerOperationStatus>(
141-
LogViewerOperationStatus.Success,
142-
counter));
143-
}
144-
145-
/// <inheritdoc/>
146-
public Task<Attempt<PagedModel<LogTemplate>, LogViewerOperationStatus>> GetMessageTemplatesAsync(DateTimeOffset? startDate, DateTimeOffset? endDate, int skip, int take)
147-
{
148-
LogTimePeriod logTimePeriod = GetTimePeriod(startDate, endDate);
149-
150-
// We will need to stop the request if trying to do this on a 1GB file
151-
if (CanViewLogs(logTimePeriod) == false)
152-
{
153-
return Task.FromResult(Attempt.FailWithStatus<PagedModel<LogTemplate>, LogViewerOperationStatus>(
154-
LogViewerOperationStatus.CancelledByLogsSizeValidation,
155-
null!));
156-
}
157-
158-
LogTemplate[] messageTemplates = _logViewerRepository.GetMessageTemplates(logTimePeriod);
159-
160-
return Task.FromResult(Attempt.SucceedWithStatus(
161-
LogViewerOperationStatus.Success,
162-
new PagedModel<LogTemplate>(messageTemplates.Length, messageTemplates.Skip(skip).Take(take))));
163-
}
164-
165-
/// <inheritdoc/>
166-
public ReadOnlyDictionary<string, LogLevel> GetLogLevelsFromSinks()
167-
{
168-
var configuredLogLevels = new Dictionary<string, LogLevel>
169-
{
170-
{ "Global", GetGlobalMinLogLevel() },
171-
{ "UmbracoFile", _logViewerRepository.RestrictedToMinimumLevel() },
172-
};
173-
174-
return configuredLogLevels.AsReadOnly();
175-
}
176-
177-
/// <inheritdoc/>
178-
public LogLevel GetGlobalMinLogLevel() => _logViewerRepository.GetGlobalMinLogLevel();
179-
180-
/// <summary>
181-
/// Returns a <see cref="LogTimePeriod" /> representation from a start and end date for filtering log files.
182-
/// </summary>
183-
/// <param name="startDate">The start date for the date range (can be null).</param>
184-
/// <param name="endDate">The end date for the date range (can be null).</param>
185-
/// <returns>The LogTimePeriod object used to filter logs.</returns>
186-
private LogTimePeriod GetTimePeriod(DateTimeOffset? startDate, DateTimeOffset? endDate)
187-
{
188-
if (startDate is null || endDate is null)
189-
{
190-
DateTime now = DateTime.Now;
191-
if (startDate is null)
192-
{
193-
startDate = now.AddDays(-1);
194-
}
195-
196-
if (endDate is null)
197-
{
198-
endDate = now;
199-
}
45+
isAllowed));
20046
}
20147

202-
return new LogTimePeriod(startDate.Value.LocalDateTime, endDate.Value.LocalDateTime);
48+
return Task.FromResult(Attempt.SucceedWithStatus(LogViewerOperationStatus.Success, isAllowed));
20349
}
20450

20551
/// <summary>
20652
/// Returns a value indicating whether to stop a GET request that is attempting to fetch logs from a 1GB file.
20753
/// </summary>
20854
/// <param name="logTimePeriod">The time period to filter the logs.</param>
209-
/// <returns>The value whether or not you are able to view the logs.</returns>
55+
/// <returns>Whether you are able to view the logs.</returns>
21056
private bool CanViewLogs(LogTimePeriod logTimePeriod)
21157
{
21258
// Number of entries
@@ -230,52 +76,5 @@ private bool CanViewLogs(LogTimePeriod logTimePeriod)
23076
return logSizeAsMegabytes <= FileSizeCap;
23177
}
23278

233-
private PagedModel<ILogEntry> GetFilteredLogs(
234-
LogTimePeriod logTimePeriod,
235-
string? filterExpression,
236-
string[]? logLevels,
237-
Direction orderDirection,
238-
int skip,
239-
int take)
240-
{
241-
IEnumerable<ILogEntry> logs = _logViewerRepository.GetLogs(logTimePeriod, filterExpression).ToArray();
242-
243-
// This is user used the checkbox UI to toggle which log levels they wish to see
244-
// If an empty array or null - its implied all levels to be viewed
245-
if (logLevels?.Length > 0)
246-
{
247-
var logsAfterLevelFilters = new List<ILogEntry>();
248-
var validLogType = true;
249-
foreach (var level in logLevels)
250-
{
251-
// Check if level string is part of the LogEventLevel enum
252-
if (Enum.IsDefined(typeof(LogLevel), level))
253-
{
254-
validLogType = true;
255-
logsAfterLevelFilters.AddRange(logs.Where(x =>
256-
string.Equals(x.Level.ToString(), level, StringComparison.InvariantCultureIgnoreCase)));
257-
}
258-
else
259-
{
260-
validLogType = false;
261-
}
262-
}
263-
264-
if (validLogType)
265-
{
266-
logs = logsAfterLevelFilters;
267-
}
268-
}
269-
270-
return new PagedModel<ILogEntry>
271-
{
272-
Total = logs.Count(),
273-
Items = logs
274-
.OrderBy(l => l.Timestamp, orderDirection)
275-
.Skip(skip)
276-
.Take(take),
277-
};
278-
}
279-
280-
private string GetSearchPattern(DateTime day) => $"*{day:yyyyMMdd}*.json";
79+
private static string GetSearchPattern(DateTime day) => $"*{day:yyyyMMdd}*.json";
28180
}

0 commit comments

Comments
 (0)