diff --git a/examples/WireMock.Net.ConsoleApplication/MainApp.cs b/examples/WireMock.Net.ConsoleApplication/MainApp.cs index 30cea771..b9acbcd9 100644 --- a/examples/WireMock.Net.ConsoleApplication/MainApp.cs +++ b/examples/WireMock.Net.ConsoleApplication/MainApp.cs @@ -1,6 +1,7 @@ using System; using System.Net; using Newtonsoft.Json; +using WireMock.Logging; using WireMock.Matchers; using WireMock.RequestBuilders; using WireMock.ResponseBuilders; @@ -28,7 +29,8 @@ namespace WireMock.Net.ConsoleApplication // SaveMapping = true //}, PreWireMockMiddlewareInit = app => { System.Console.WriteLine($"PreWireMockMiddlewareInit : {app.GetType()}"); }, - PostWireMockMiddlewareInit = app => { System.Console.WriteLine($"PostWireMockMiddlewareInit : {app.GetType()}"); } + PostWireMockMiddlewareInit = app => { System.Console.WriteLine($"PostWireMockMiddlewareInit : {app.GetType()}"); }, + Logger = new WireMockConsoleLogger() }); System.Console.WriteLine("FluentMockServer listening at {0}", string.Join(",", server.Urls)); diff --git a/examples/WireMock.Net.StandAlone.NETCoreApp/WireMockLog4NetLogger.cs b/examples/WireMock.Net.StandAlone.NETCoreApp/WireMockLog4NetLogger.cs index 6762c063..354128a0 100644 --- a/examples/WireMock.Net.StandAlone.NETCoreApp/WireMockLog4NetLogger.cs +++ b/examples/WireMock.Net.StandAlone.NETCoreApp/WireMockLog4NetLogger.cs @@ -1,4 +1,6 @@ using log4net; +using Newtonsoft.Json; +using WireMock.Admin.Requests; using WireMock.Logging; namespace WireMock.Net.StandAlone.NETCoreApp @@ -26,5 +28,11 @@ namespace WireMock.Net.StandAlone.NETCoreApp { Log.ErrorFormat(formatString, args); } + + public void DebugRequestResponse(LogEntryModel logEntryModel, bool isAdminRequest) + { + string message = JsonConvert.SerializeObject(logEntryModel, Formatting.Indented); + Log.DebugFormat("Admin[{0}] {1}", isAdminRequest, message); + } } } \ No newline at end of file diff --git a/examples/WireMock.Net.WebApplication/WireMockService.cs b/examples/WireMock.Net.WebApplication/WireMockService.cs index 5fc67432..97dfb5d9 100644 --- a/examples/WireMock.Net.WebApplication/WireMockService.cs +++ b/examples/WireMock.Net.WebApplication/WireMockService.cs @@ -1,6 +1,7 @@ using System.Threading; using Microsoft.Extensions.Logging; using Newtonsoft.Json; +using WireMock.Admin.Requests; using WireMock.Logging; using WireMock.Net.StandAlone; using WireMock.Settings; @@ -42,6 +43,12 @@ namespace WireMock.Net.WebApplication { _logger.LogError(formatString, args); } + + public void DebugRequestResponse(LogEntryModel logEntryModel, bool isAdminrequest) + { + string message = JsonConvert.SerializeObject(logEntryModel, Formatting.Indented); + _logger.LogDebug("Admin[{0}] {1}", isAdminrequest, message); + } } public WireMockService(ILogger logger, IFluentMockServerSettings settings) diff --git a/src/WireMock.Net.StandAlone/WireMock.Net.StandAlone.csproj b/src/WireMock.Net.StandAlone/WireMock.Net.StandAlone.csproj index d0674fff..2ef36595 100644 --- a/src/WireMock.Net.StandAlone/WireMock.Net.StandAlone.csproj +++ b/src/WireMock.Net.StandAlone/WireMock.Net.StandAlone.csproj @@ -1,9 +1,9 @@ - + Lightweight StandAlone Http Mocking Server for .Net. WireMock.Net.StandAlone - 1.0.3.20 + 1.0.4.0 Stef Heyenrath net452;net46;netstandard1.3;netstandard2.0 true diff --git a/src/WireMock.Net/Logging/IWireMockLogger.cs b/src/WireMock.Net/Logging/IWireMockLogger.cs index 048144d6..41486d8b 100644 --- a/src/WireMock.Net/Logging/IWireMockLogger.cs +++ b/src/WireMock.Net/Logging/IWireMockLogger.cs @@ -1,4 +1,5 @@ using JetBrains.Annotations; +using WireMock.Admin.Requests; namespace WireMock.Logging { @@ -43,5 +44,13 @@ namespace WireMock.Logging [PublicAPI] [StringFormatMethod("formatString")] void Error([NotNull] string formatString, [NotNull] params object[] args); + + /// + /// Writes the LogEntryModel (LogRequestModel, LogResponseModel and more). + /// + /// The Request Log Model. + /// Defines if this request is an admin request. + [PublicAPI] + void DebugRequestResponse([NotNull] LogEntryModel logEntryModel, bool isAdminrequest); } } \ No newline at end of file diff --git a/src/WireMock.Net/Logging/WireMockConsoleLogger.cs b/src/WireMock.Net/Logging/WireMockConsoleLogger.cs index c7ba5b57..ea38fffc 100644 --- a/src/WireMock.Net/Logging/WireMockConsoleLogger.cs +++ b/src/WireMock.Net/Logging/WireMockConsoleLogger.cs @@ -1,4 +1,6 @@ using System; +using Newtonsoft.Json; +using WireMock.Admin.Requests; namespace WireMock.Logging { @@ -8,6 +10,14 @@ namespace WireMock.Logging /// public class WireMockConsoleLogger : IWireMockLogger { + /// + /// Initializes a new instance of the class. + /// + public WireMockConsoleLogger() + { + Console.OutputEncoding = System.Text.Encoding.UTF8; + } + /// public void Debug(string formatString, params object[] args) { @@ -32,9 +42,16 @@ namespace WireMock.Logging Console.WriteLine(Format("Error", formatString, args)); } + /// + public void DebugRequestResponse(LogEntryModel logEntryModel, bool isAdminRequest) + { + string message = JsonConvert.SerializeObject(logEntryModel, Formatting.Indented); + Console.WriteLine(Format("DebugRequestResponse", "Admin[{0}] {1}", isAdminRequest, message)); + } + private static string Format(string level, string formatString, params object[] args) { - string message = string.Format(formatString, args); + var message = args.Length > 0 ? string.Format(formatString, args) : formatString; return $"{DateTime.UtcNow} [{level}] : {message}"; } diff --git a/src/WireMock.Net/Logging/WireMockNullLogger.cs b/src/WireMock.Net/Logging/WireMockNullLogger.cs index 16995c02..f2fea811 100644 --- a/src/WireMock.Net/Logging/WireMockNullLogger.cs +++ b/src/WireMock.Net/Logging/WireMockNullLogger.cs @@ -1,4 +1,6 @@ -namespace WireMock.Logging +using WireMock.Admin.Requests; + +namespace WireMock.Logging { /// /// WireMockNullLogger which does not log. @@ -25,5 +27,10 @@ public void Error(string formatString, params object[] args) { } + + /// + public void DebugRequestResponse(LogEntryModel logEntryModel, bool isAdminRequest) + { + } } } \ No newline at end of file diff --git a/src/WireMock.Net/Owin/WireMockMiddleware.cs b/src/WireMock.Net/Owin/WireMockMiddleware.cs index dbfc24c6..321c2ad5 100644 --- a/src/WireMock.Net/Owin/WireMockMiddleware.cs +++ b/src/WireMock.Net/Owin/WireMockMiddleware.cs @@ -7,6 +7,7 @@ using WireMock.Matchers; using WireMock.Util; using Newtonsoft.Json; using WireMock.Http; +using WireMock.Serialization; #if !NETSTANDARD using Microsoft.Owin; #else @@ -153,6 +154,8 @@ namespace WireMock.Owin private void LogRequest(LogEntry entry, bool addRequest) { + _options.Logger.DebugRequestResponse(LogEntryMapper.Map(entry), entry.RequestMessage.Path.StartsWith("/__admin/")); + if (addRequest) { _options.LogEntries.Add(entry); diff --git a/src/WireMock.Net/Serialization/LogEntryMapper.cs b/src/WireMock.Net/Serialization/LogEntryMapper.cs new file mode 100644 index 00000000..cfa27736 --- /dev/null +++ b/src/WireMock.Net/Serialization/LogEntryMapper.cs @@ -0,0 +1,70 @@ +using System.Linq; +using WireMock.Admin.Mappings; +using WireMock.Admin.Requests; +using WireMock.Logging; + +namespace WireMock.Serialization +{ + internal static class LogEntryMapper + { + public static LogEntryModel Map(LogEntry logEntry) + { + return new LogEntryModel + { + Guid = logEntry.Guid, + Request = new LogRequestModel + { + DateTime = logEntry.RequestMessage.DateTime, + ClientIP = logEntry.RequestMessage.ClientIP, + Path = logEntry.RequestMessage.Path, + AbsoluteUrl = logEntry.RequestMessage.Url, + Query = logEntry.RequestMessage.Query, + Method = logEntry.RequestMessage.Method, + Body = logEntry.RequestMessage.Body, + BodyAsJson = logEntry.RequestMessage.BodyAsJson, + BodyAsBytes = logEntry.RequestMessage.BodyAsBytes, + Headers = logEntry.RequestMessage.Headers, + Cookies = logEntry.RequestMessage.Cookies, + BodyEncoding = logEntry.RequestMessage.BodyEncoding != null ? new EncodingModel + { + EncodingName = logEntry.RequestMessage.BodyEncoding.EncodingName, + CodePage = logEntry.RequestMessage.BodyEncoding.CodePage, + WebName = logEntry.RequestMessage.BodyEncoding.WebName + } : null + }, + Response = new LogResponseModel + { + StatusCode = logEntry.ResponseMessage.StatusCode, + BodyDestination = logEntry.ResponseMessage.BodyDestination, + Body = logEntry.ResponseMessage.Body, + BodyAsJson = logEntry.ResponseMessage.BodyAsJson, + BodyAsBytes = logEntry.ResponseMessage.BodyAsBytes, + BodyOriginal = logEntry.ResponseMessage.BodyOriginal, + BodyAsFile = logEntry.ResponseMessage.BodyAsFile, + BodyAsFileIsCached = logEntry.ResponseMessage.BodyAsFileIsCached, + Headers = logEntry.ResponseMessage.Headers, + BodyEncoding = logEntry.ResponseMessage.BodyEncoding != null ? new EncodingModel + { + EncodingName = logEntry.ResponseMessage.BodyEncoding.EncodingName, + CodePage = logEntry.ResponseMessage.BodyEncoding.CodePage, + WebName = logEntry.ResponseMessage.BodyEncoding.WebName + } : null + }, + MappingGuid = logEntry.MappingGuid, + MappingTitle = logEntry.MappingTitle, + RequestMatchResult = logEntry.RequestMatchResult != null ? new LogRequestMatchModel + { + TotalScore = logEntry.RequestMatchResult.TotalScore, + TotalNumber = logEntry.RequestMatchResult.TotalNumber, + IsPerfectMatch = logEntry.RequestMatchResult.IsPerfectMatch, + AverageTotalScore = logEntry.RequestMatchResult.AverageTotalScore, + MatchDetails = logEntry.RequestMatchResult.MatchDetails.Select(x => new + { + Name = x.Key.Name.Replace("RequestMessage", string.Empty), + Score = x.Value + } as object).ToList() + } : null + }; + } + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Server/FluentMockServer.Admin.cs b/src/WireMock.Net/Server/FluentMockServer.Admin.cs index 40cd60b7..1038b0b8 100644 --- a/src/WireMock.Net/Server/FluentMockServer.Admin.cs +++ b/src/WireMock.Net/Server/FluentMockServer.Admin.cs @@ -457,7 +457,7 @@ namespace WireMock.Server return new ResponseMessage { StatusCode = 404, Body = "Request not found" }; } - var model = ToLogEntryModel(entry); + var model = LogEntryMapper.Map(entry); return ToJson(model); } @@ -478,71 +478,11 @@ namespace WireMock.Server { var result = LogEntries .Where(r => !r.RequestMessage.Path.StartsWith("/__admin/")) - .Select(ToLogEntryModel); + .Select(LogEntryMapper.Map); return ToJson(result); } - private LogEntryModel ToLogEntryModel(LogEntry logEntry) - { - return new LogEntryModel - { - Guid = logEntry.Guid, - Request = new LogRequestModel - { - DateTime = logEntry.RequestMessage.DateTime, - ClientIP = logEntry.RequestMessage.ClientIP, - Path = logEntry.RequestMessage.Path, - AbsoluteUrl = logEntry.RequestMessage.Url, - Query = logEntry.RequestMessage.Query, - Method = logEntry.RequestMessage.Method, - Body = logEntry.RequestMessage.Body, - BodyAsJson = logEntry.RequestMessage.BodyAsJson, - BodyAsBytes = logEntry.RequestMessage.BodyAsBytes, - Headers = logEntry.RequestMessage.Headers, - Cookies = logEntry.RequestMessage.Cookies, - BodyEncoding = logEntry.RequestMessage.BodyEncoding != null ? new EncodingModel - { - EncodingName = logEntry.RequestMessage.BodyEncoding.EncodingName, - CodePage = logEntry.RequestMessage.BodyEncoding.CodePage, - WebName = logEntry.RequestMessage.BodyEncoding.WebName - } : null - }, - Response = new LogResponseModel - { - StatusCode = logEntry.ResponseMessage.StatusCode, - BodyDestination = logEntry.ResponseMessage.BodyDestination, - Body = logEntry.ResponseMessage.Body, - BodyAsJson = logEntry.ResponseMessage.BodyAsJson, - BodyAsBytes = logEntry.ResponseMessage.BodyAsBytes, - BodyOriginal = logEntry.ResponseMessage.BodyOriginal, - BodyAsFile = logEntry.ResponseMessage.BodyAsFile, - BodyAsFileIsCached = logEntry.ResponseMessage.BodyAsFileIsCached, - Headers = logEntry.ResponseMessage.Headers, - BodyEncoding = logEntry.ResponseMessage.BodyEncoding != null ? new EncodingModel - { - EncodingName = logEntry.ResponseMessage.BodyEncoding.EncodingName, - CodePage = logEntry.ResponseMessage.BodyEncoding.CodePage, - WebName = logEntry.ResponseMessage.BodyEncoding.WebName - } : null - }, - MappingGuid = logEntry.MappingGuid, - MappingTitle = logEntry.MappingTitle, - RequestMatchResult = logEntry.RequestMatchResult != null ? new LogRequestMatchModel - { - TotalScore = logEntry.RequestMatchResult.TotalScore, - TotalNumber = logEntry.RequestMatchResult.TotalNumber, - IsPerfectMatch = logEntry.RequestMatchResult.IsPerfectMatch, - AverageTotalScore = logEntry.RequestMatchResult.AverageTotalScore, - MatchDetails = logEntry.RequestMatchResult.MatchDetails.Select(x => new - { - Name = x.Key.Name.Replace("RequestMessage", string.Empty), - Score = x.Value - } as object).ToList() - } : null - }; - } - private ResponseMessage RequestsDelete(RequestMessage requestMessage) { ResetLogEntries(); @@ -568,7 +508,7 @@ namespace WireMock.Server } } - var result = dict.OrderBy(x => x.Value.AverageTotalScore).Select(x => x.Key).Select(ToLogEntryModel); + var result = dict.OrderBy(x => x.Value.AverageTotalScore).Select(x => x.Key).Select(LogEntryMapper.Map); return ToJson(result); } diff --git a/src/WireMock.Net/Server/FluentMockServer.cs b/src/WireMock.Net/Server/FluentMockServer.cs index 66036f7c..11e66aa1 100644 --- a/src/WireMock.Net/Server/FluentMockServer.cs +++ b/src/WireMock.Net/Server/FluentMockServer.cs @@ -161,6 +161,7 @@ namespace WireMock.Server settings.Logger = settings.Logger ?? new WireMockConsoleLogger(); _logger = settings.Logger; + _logger.Info("WireMock.Net by Stef Heyenrath (https://github.com/WireMock-Net/WireMock.Net)"); _logger.Debug("WireMock.Net server settings {0}", JsonConvert.SerializeObject(settings, Formatting.Indented)); if (settings.Urls != null) diff --git a/src/WireMock.Net/WireMock.Net.csproj b/src/WireMock.Net/WireMock.Net.csproj index e73113e4..97dfeffd 100644 --- a/src/WireMock.Net/WireMock.Net.csproj +++ b/src/WireMock.Net/WireMock.Net.csproj @@ -3,7 +3,7 @@ Lightweight Http Mocking Server for .Net, inspired by WireMock from the Java landscape. WireMock.Net - 1.0.3.20 + 1.0.4.0 Stef Heyenrath net452;net46;netstandard1.3;netstandard2.0 true