// Copyright © WireMock.Net using System.Diagnostics; using System.Linq; using WireMock.Logging; using WireMock.Owin.ActivityTracing; using WireMock.Serialization; using WireMock.Util; namespace WireMock.Owin; internal class WireMockMiddlewareLogger( IWireMockMiddlewareOptions _options, LogEntryMapper _logEntryMapper, IGuidUtils _guidUtils ) : IWireMockMiddlewareLogger { public void LogRequestAndResponse(bool logRequest, RequestMessage request, IResponseMessage? response, MappingMatcherResult? match, MappingMatcherResult? partialMatch, Activity? activity) { var logEntry = new LogEntry { Guid = _guidUtils.NewGuid(), RequestMessage = request, ResponseMessage = response, MappingGuid = match?.Mapping?.Guid, MappingTitle = match?.Mapping?.Title, RequestMatchResult = match?.RequestMatchResult, PartialMappingGuid = partialMatch?.Mapping?.Guid, PartialMappingTitle = partialMatch?.Mapping?.Title, PartialMatchResult = partialMatch?.RequestMatchResult }; WireMockActivitySource.EnrichWithLogEntry(activity, logEntry, _options.ActivityTracingOptions); activity?.Dispose(); LogLogEntry(logEntry, logRequest); try { if (_options.SaveUnmatchedRequests == true && match?.RequestMatchResult is not { IsPerfectMatch: true }) { var filename = $"{logEntry.Guid}.LogEntry.json"; _options.FileSystemHandler?.WriteUnmatchedRequest(filename, JsonUtils.Serialize(logEntry)); } } catch { // Empty catch } } public void LogLogEntry(LogEntry entry, bool addRequest) { _options.Logger.DebugRequestResponse(_logEntryMapper.Map(entry), entry.RequestMessage?.Path.StartsWith("/__admin/") == true); // If addRequest is set to true and MaxRequestLogCount is null or does have a value greater than 0, try to add a new request log. if (addRequest && _options.MaxRequestLogCount is null or > 0) { TryAddLogEntry(entry); } // In case MaxRequestLogCount has a value greater than 0, try to delete existing request logs based on the count. if (_options.MaxRequestLogCount is > 0) { var logEntries = _options.LogEntries.ToList(); foreach (var logEntry in logEntries .OrderBy(le => le.RequestMessage?.DateTime ?? le.ResponseMessage?.DateTime) .Take(logEntries.Count - _options.MaxRequestLogCount.Value)) { TryRemoveLogEntry(logEntry); } } // In case RequestLogExpirationDuration has a value greater than 0, try to delete existing request logs based on the date. if (_options.RequestLogExpirationDuration is > 0) { var logEntries = _options.LogEntries.ToList(); var checkTime = DateTime.UtcNow.AddHours(-_options.RequestLogExpirationDuration.Value); foreach (var logEntry in logEntries.Where(le => le.RequestMessage?.DateTime < checkTime || le.ResponseMessage?.DateTime < checkTime)) { TryRemoveLogEntry(logEntry); } } } private void TryAddLogEntry(LogEntry logEntry) { try { _options.LogEntries.Add(logEntry); } catch { // Ignore exception (can happen during stress testing) } } private void TryRemoveLogEntry(LogEntry logEntry) { try { _options.LogEntries.Remove(logEntry); } catch { // Ignore exception (can happen during stress testing) } } }