mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-04-23 17:28:55 +02:00
Add request / response logging (#151)
Add request / response logging (#151)
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using WireMock.Logging;
|
||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
using WireMock.RequestBuilders;
|
using WireMock.RequestBuilders;
|
||||||
using WireMock.ResponseBuilders;
|
using WireMock.ResponseBuilders;
|
||||||
@@ -28,7 +29,8 @@ namespace WireMock.Net.ConsoleApplication
|
|||||||
// SaveMapping = true
|
// SaveMapping = true
|
||||||
//},
|
//},
|
||||||
PreWireMockMiddlewareInit = app => { System.Console.WriteLine($"PreWireMockMiddlewareInit : {app.GetType()}"); },
|
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));
|
System.Console.WriteLine("FluentMockServer listening at {0}", string.Join(",", server.Urls));
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using log4net;
|
using log4net;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using WireMock.Admin.Requests;
|
||||||
using WireMock.Logging;
|
using WireMock.Logging;
|
||||||
|
|
||||||
namespace WireMock.Net.StandAlone.NETCoreApp
|
namespace WireMock.Net.StandAlone.NETCoreApp
|
||||||
@@ -26,5 +28,11 @@ namespace WireMock.Net.StandAlone.NETCoreApp
|
|||||||
{
|
{
|
||||||
Log.ErrorFormat(formatString, args);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using WireMock.Admin.Requests;
|
||||||
using WireMock.Logging;
|
using WireMock.Logging;
|
||||||
using WireMock.Net.StandAlone;
|
using WireMock.Net.StandAlone;
|
||||||
using WireMock.Settings;
|
using WireMock.Settings;
|
||||||
@@ -42,6 +43,12 @@ namespace WireMock.Net.WebApplication
|
|||||||
{
|
{
|
||||||
_logger.LogError(formatString, args);
|
_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)
|
public WireMockService(ILogger logger, IFluentMockServerSettings settings)
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Description>Lightweight StandAlone Http Mocking Server for .Net.</Description>
|
<Description>Lightweight StandAlone Http Mocking Server for .Net.</Description>
|
||||||
<AssemblyTitle>WireMock.Net.StandAlone</AssemblyTitle>
|
<AssemblyTitle>WireMock.Net.StandAlone</AssemblyTitle>
|
||||||
<Version>1.0.3.20</Version>
|
<Version>1.0.4.0</Version>
|
||||||
<Authors>Stef Heyenrath</Authors>
|
<Authors>Stef Heyenrath</Authors>
|
||||||
<TargetFrameworks>net452;net46;netstandard1.3;netstandard2.0</TargetFrameworks>
|
<TargetFrameworks>net452;net46;netstandard1.3;netstandard2.0</TargetFrameworks>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using WireMock.Admin.Requests;
|
||||||
|
|
||||||
namespace WireMock.Logging
|
namespace WireMock.Logging
|
||||||
{
|
{
|
||||||
@@ -43,5 +44,13 @@ namespace WireMock.Logging
|
|||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
[StringFormatMethod("formatString")]
|
[StringFormatMethod("formatString")]
|
||||||
void Error([NotNull] string formatString, [NotNull] params object[] args);
|
void Error([NotNull] string formatString, [NotNull] params object[] args);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the LogEntryModel (LogRequestModel, LogResponseModel and more).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="logEntryModel">The Request Log Model.</param>
|
||||||
|
/// <param name="isAdminrequest">Defines if this request is an admin request.</param>
|
||||||
|
[PublicAPI]
|
||||||
|
void DebugRequestResponse([NotNull] LogEntryModel logEntryModel, bool isAdminrequest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using WireMock.Admin.Requests;
|
||||||
|
|
||||||
namespace WireMock.Logging
|
namespace WireMock.Logging
|
||||||
{
|
{
|
||||||
@@ -8,6 +10,14 @@ namespace WireMock.Logging
|
|||||||
/// <seealso cref="IWireMockLogger" />
|
/// <seealso cref="IWireMockLogger" />
|
||||||
public class WireMockConsoleLogger : IWireMockLogger
|
public class WireMockConsoleLogger : IWireMockLogger
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="WireMockConsoleLogger"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public WireMockConsoleLogger()
|
||||||
|
{
|
||||||
|
Console.OutputEncoding = System.Text.Encoding.UTF8;
|
||||||
|
}
|
||||||
|
|
||||||
/// <see cref="IWireMockLogger.Debug"/>
|
/// <see cref="IWireMockLogger.Debug"/>
|
||||||
public void Debug(string formatString, params object[] args)
|
public void Debug(string formatString, params object[] args)
|
||||||
{
|
{
|
||||||
@@ -32,9 +42,16 @@ namespace WireMock.Logging
|
|||||||
Console.WriteLine(Format("Error", formatString, args));
|
Console.WriteLine(Format("Error", formatString, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <see cref="IWireMockLogger.DebugRequestResponse"/>
|
||||||
|
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)
|
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}";
|
return $"{DateTime.UtcNow} [{level}] : {message}";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
namespace WireMock.Logging
|
using WireMock.Admin.Requests;
|
||||||
|
|
||||||
|
namespace WireMock.Logging
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// WireMockNullLogger which does not log.
|
/// WireMockNullLogger which does not log.
|
||||||
@@ -25,5 +27,10 @@
|
|||||||
public void Error(string formatString, params object[] args)
|
public void Error(string formatString, params object[] args)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <see cref="IWireMockLogger.DebugRequestResponse"/>
|
||||||
|
public void DebugRequestResponse(LogEntryModel logEntryModel, bool isAdminRequest)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@ using WireMock.Matchers;
|
|||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using WireMock.Http;
|
using WireMock.Http;
|
||||||
|
using WireMock.Serialization;
|
||||||
#if !NETSTANDARD
|
#if !NETSTANDARD
|
||||||
using Microsoft.Owin;
|
using Microsoft.Owin;
|
||||||
#else
|
#else
|
||||||
@@ -153,6 +154,8 @@ namespace WireMock.Owin
|
|||||||
|
|
||||||
private void LogRequest(LogEntry entry, bool addRequest)
|
private void LogRequest(LogEntry entry, bool addRequest)
|
||||||
{
|
{
|
||||||
|
_options.Logger.DebugRequestResponse(LogEntryMapper.Map(entry), entry.RequestMessage.Path.StartsWith("/__admin/"));
|
||||||
|
|
||||||
if (addRequest)
|
if (addRequest)
|
||||||
{
|
{
|
||||||
_options.LogEntries.Add(entry);
|
_options.LogEntries.Add(entry);
|
||||||
|
|||||||
70
src/WireMock.Net/Serialization/LogEntryMapper.cs
Normal file
70
src/WireMock.Net/Serialization/LogEntryMapper.cs
Normal file
@@ -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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -457,7 +457,7 @@ namespace WireMock.Server
|
|||||||
return new ResponseMessage { StatusCode = 404, Body = "Request not found" };
|
return new ResponseMessage { StatusCode = 404, Body = "Request not found" };
|
||||||
}
|
}
|
||||||
|
|
||||||
var model = ToLogEntryModel(entry);
|
var model = LogEntryMapper.Map(entry);
|
||||||
|
|
||||||
return ToJson(model);
|
return ToJson(model);
|
||||||
}
|
}
|
||||||
@@ -478,71 +478,11 @@ namespace WireMock.Server
|
|||||||
{
|
{
|
||||||
var result = LogEntries
|
var result = LogEntries
|
||||||
.Where(r => !r.RequestMessage.Path.StartsWith("/__admin/"))
|
.Where(r => !r.RequestMessage.Path.StartsWith("/__admin/"))
|
||||||
.Select(ToLogEntryModel);
|
.Select(LogEntryMapper.Map);
|
||||||
|
|
||||||
return ToJson(result);
|
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)
|
private ResponseMessage RequestsDelete(RequestMessage requestMessage)
|
||||||
{
|
{
|
||||||
ResetLogEntries();
|
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);
|
return ToJson(result);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ namespace WireMock.Server
|
|||||||
settings.Logger = settings.Logger ?? new WireMockConsoleLogger();
|
settings.Logger = settings.Logger ?? new WireMockConsoleLogger();
|
||||||
_logger = settings.Logger;
|
_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));
|
_logger.Debug("WireMock.Net server settings {0}", JsonConvert.SerializeObject(settings, Formatting.Indented));
|
||||||
|
|
||||||
if (settings.Urls != null)
|
if (settings.Urls != null)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Description>Lightweight Http Mocking Server for .Net, inspired by WireMock from the Java landscape.</Description>
|
<Description>Lightweight Http Mocking Server for .Net, inspired by WireMock from the Java landscape.</Description>
|
||||||
<AssemblyTitle>WireMock.Net</AssemblyTitle>
|
<AssemblyTitle>WireMock.Net</AssemblyTitle>
|
||||||
<Version>1.0.3.20</Version>
|
<Version>1.0.4.0</Version>
|
||||||
<Authors>Stef Heyenrath</Authors>
|
<Authors>Stef Heyenrath</Authors>
|
||||||
<TargetFrameworks>net452;net46;netstandard1.3;netstandard2.0</TargetFrameworks>
|
<TargetFrameworks>net452;net46;netstandard1.3;netstandard2.0</TargetFrameworks>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
|||||||
Reference in New Issue
Block a user