Skip to content

Commit d5dbf72

Browse files
author
Bart Koelman
committed
Added JSON request/response logging
1 parent 6c2a659 commit d5dbf72

File tree

6 files changed

+76
-41
lines changed

6 files changed

+76
-41
lines changed

benchmarks/Query/QueryParserBenchmarks.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using JsonApiDotNetCore.Services;
1010
using Microsoft.AspNetCore.Http;
1111
using Microsoft.AspNetCore.WebUtilities;
12+
using Microsoft.Extensions.Logging.Abstractions;
1213

1314
namespace Benchmarks.Query
1415
{
@@ -44,7 +45,7 @@ private static QueryParameterParser CreateQueryParameterDiscoveryForSort(IResour
4445
sortService
4546
};
4647

47-
return new QueryParameterParser(options, queryStringAccessor, queryServices);
48+
return new QueryParameterParser(options, queryStringAccessor, queryServices, NullLoggerFactory.Instance);
4849
}
4950

5051
private static QueryParameterParser CreateQueryParameterDiscoveryForAll(IResourceGraph resourceGraph,
@@ -65,7 +66,7 @@ private static QueryParameterParser CreateQueryParameterDiscoveryForAll(IResourc
6566
omitNullService
6667
};
6768

68-
return new QueryParameterParser(options, queryStringAccessor, queryServices);
69+
return new QueryParameterParser(options, queryStringAccessor, queryServices, NullLoggerFactory.Instance);
6970
}
7071

7172
[Benchmark]

src/JsonApiDotNetCore/Formatters/JsonApiReader.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
using System.IO;
44
using System.Threading.Tasks;
55
using JsonApiDotNetCore.Exceptions;
6-
using JsonApiDotNetCore.Internal;
76
using JsonApiDotNetCore.Models;
87
using JsonApiDotNetCore.Serialization.Server;
8+
using Microsoft.AspNetCore.Http.Extensions;
99
using Microsoft.AspNetCore.Mvc.Formatters;
1010
using Microsoft.Extensions.Logging;
1111

@@ -22,8 +22,6 @@ public JsonApiReader(IJsonApiDeserializer deserializer,
2222
{
2323
_deserializer = deserializer;
2424
_logger = loggerFactory.CreateLogger<JsonApiReader>();
25-
26-
_logger.LogTrace("Executing constructor.");
2725
}
2826

2927
public async Task<InputFormatterResult> ReadAsync(InputFormatterContext context)
@@ -39,6 +37,9 @@ public async Task<InputFormatterResult> ReadAsync(InputFormatterContext context)
3937

4038
string body = await GetRequestBody(context.HttpContext.Request.Body);
4139

40+
string url = context.HttpContext.Request.GetEncodedUrl();
41+
_logger.LogTrace($"Received request at '{url}' with body: <<{body}>>");
42+
4243
object model;
4344
try
4445
{

src/JsonApiDotNetCore/Formatters/JsonApiWriter.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99
using JsonApiDotNetCore.Middleware;
1010
using JsonApiDotNetCore.Models.JsonApiDocuments;
1111
using JsonApiDotNetCore.Serialization.Server;
12+
using Microsoft.AspNetCore.Http.Extensions;
1213
using Microsoft.AspNetCore.Mvc;
1314
using Microsoft.AspNetCore.Mvc.Formatters;
15+
using Microsoft.Extensions.Logging;
1416
using Newtonsoft.Json;
1517

1618
namespace JsonApiDotNetCore.Formatters
@@ -23,11 +25,14 @@ public class JsonApiWriter : IJsonApiWriter
2325
{
2426
private readonly IJsonApiSerializer _serializer;
2527
private readonly IExceptionHandler _exceptionHandler;
28+
private readonly ILogger<JsonApiWriter> _logger;
2629

27-
public JsonApiWriter(IJsonApiSerializer serializer, IExceptionHandler exceptionHandler)
30+
public JsonApiWriter(IJsonApiSerializer serializer, IExceptionHandler exceptionHandler, ILoggerFactory loggerFactory)
2831
{
2932
_serializer = serializer;
3033
_exceptionHandler = exceptionHandler;
34+
35+
_logger = loggerFactory.CreateLogger<JsonApiWriter>();
3136
}
3237

3338
public async Task WriteAsync(OutputFormatterWriteContext context)
@@ -59,6 +64,9 @@ public async Task WriteAsync(OutputFormatterWriteContext context)
5964
}
6065
}
6166

67+
var url = context.HttpContext.Request.GetEncodedUrl();
68+
_logger.LogTrace($"Sending {response.StatusCode} response for request at '{url}' with body: <<{responseContent}>>");
69+
6270
await writer.WriteAsync(responseContent);
6371
await writer.FlushAsync();
6472
}

test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/CustomErrorHandlingTests.cs

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -76,40 +76,5 @@ public NoPermissionException(string customerCode) : base(new Error(HttpStatusCod
7676
CustomerCode = customerCode;
7777
}
7878
}
79-
80-
internal sealed class FakeLoggerFactory : ILoggerFactory
81-
{
82-
public FakeLogger Logger { get; }
83-
84-
public FakeLoggerFactory()
85-
{
86-
Logger = new FakeLogger();
87-
}
88-
89-
public ILogger CreateLogger(string categoryName) => Logger;
90-
91-
public void AddProvider(ILoggerProvider provider)
92-
{
93-
}
94-
95-
public void Dispose()
96-
{
97-
}
98-
99-
internal sealed class FakeLogger : ILogger
100-
{
101-
public List<(LogLevel LogLevel, string Text)> Messages = new List<(LogLevel, string)>();
102-
103-
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception,
104-
Func<TState, Exception, string> formatter)
105-
{
106-
var message = formatter(state, exception);
107-
Messages.Add((logLevel, message));
108-
}
109-
110-
public bool IsEnabled(LogLevel logLevel) => true;
111-
public IDisposable BeginScope<TState>(TState state) => null;
112-
}
113-
}
11479
}
11580
}

test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingDataTests.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Net.Http.Headers;
66
using System.Threading.Tasks;
77
using Bogus;
8+
using JsonApiDotNetCore.Formatters;
89
using JsonApiDotNetCore.Models;
910
using JsonApiDotNetCore.Models.JsonApiDocuments;
1011
using JsonApiDotNetCoreExample;
@@ -13,7 +14,9 @@
1314
using Microsoft.AspNetCore.Hosting;
1415
using Microsoft.AspNetCore.TestHost;
1516
using Microsoft.EntityFrameworkCore;
17+
using Microsoft.Extensions.Logging;
1618
using Newtonsoft.Json;
19+
using NLog.Extensions.Logging;
1720
using Xunit;
1821
using Person = JsonApiDotNetCoreExample.Models.Person;
1922

@@ -64,6 +67,16 @@ public async Task Response422IfUpdatingNotSettableAttribute()
6467
{
6568
// Arrange
6669
var builder = new WebHostBuilder().UseStartup<Startup>();
70+
71+
var loggerFactory = new FakeLoggerFactory();
72+
builder.ConfigureLogging(options =>
73+
{
74+
options.AddProvider(loggerFactory);
75+
options.SetMinimumLevel(LogLevel.Trace);
76+
options.AddFilter((category, level) => level == LogLevel.Trace &&
77+
(category == typeof(JsonApiReader).FullName || category == typeof(JsonApiWriter).FullName));
78+
});
79+
6780
var server = new TestServer(builder);
6881
var client = server.CreateClient();
6982

@@ -89,6 +102,12 @@ public async Task Response422IfUpdatingNotSettableAttribute()
89102
Assert.Equal(HttpStatusCode.UnprocessableEntity, error.StatusCode);
90103
Assert.Equal("Failed to deserialize request body.", error.Title);
91104
Assert.StartsWith("Property set method not found. - Request body: <<", error.Detail);
105+
106+
Assert.NotEmpty(loggerFactory.Logger.Messages);
107+
Assert.Contains(loggerFactory.Logger.Messages,
108+
x => x.Text.StartsWith("Received request at ") && x.Text.Contains("with body:"));
109+
Assert.Contains(loggerFactory.Logger.Messages,
110+
x => x.Text.StartsWith("Sending 422 response for request at ") && x.Text.Contains("Failed to deserialize request body."));
92111
}
93112

94113
[Fact]
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Microsoft.Extensions.Logging;
4+
5+
namespace JsonApiDotNetCoreExampleTests
6+
{
7+
internal sealed class FakeLoggerFactory : ILoggerFactory, ILoggerProvider
8+
{
9+
public FakeLogger Logger { get; }
10+
11+
public FakeLoggerFactory()
12+
{
13+
Logger = new FakeLogger();
14+
}
15+
16+
public ILogger CreateLogger(string categoryName) => Logger;
17+
18+
public void AddProvider(ILoggerProvider provider)
19+
{
20+
}
21+
22+
public void Dispose()
23+
{
24+
}
25+
26+
internal sealed class FakeLogger : ILogger
27+
{
28+
public List<(LogLevel LogLevel, string Text)> Messages = new List<(LogLevel, string)>();
29+
30+
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception,
31+
Func<TState, Exception, string> formatter)
32+
{
33+
var message = formatter(state, exception);
34+
Messages.Add((logLevel, message));
35+
}
36+
37+
public bool IsEnabled(LogLevel logLevel) => true;
38+
public IDisposable BeginScope<TState>(TState state) => null;
39+
}
40+
}
41+
}

0 commit comments

Comments
 (0)