Skip to content
This repository was archived by the owner on Nov 22, 2018. It is now read-only.

Commit 3b2a2eb

Browse files
committed
Add logging
1 parent 9e5dbee commit 3b2a2eb

File tree

9 files changed

+829
-115
lines changed

9 files changed

+829
-115
lines changed

src/Microsoft.AspNetCore.ResponseCaching/Internal/LoggerExtensions.cs

Lines changed: 300 additions & 0 deletions
Large diffs are not rendered by default.

src/Microsoft.AspNetCore.ResponseCaching/Internal/ResponseCacheContext.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Microsoft.AspNetCore.Http;
77
using Microsoft.AspNetCore.Http.Features;
88
using Microsoft.AspNetCore.Http.Headers;
9+
using Microsoft.Extensions.Logging;
910
using Microsoft.Net.Http.Headers;
1011

1112
namespace Microsoft.AspNetCore.ResponseCaching.Internal
@@ -23,10 +24,10 @@ public class ResponseCacheContext
2324
private DateTimeOffset? _responseExpires;
2425
private bool _parsedResponseExpires;
2526

26-
internal ResponseCacheContext(
27-
HttpContext httpContext)
27+
internal ResponseCacheContext(HttpContext httpContext, ILogger logger)
2828
{
2929
HttpContext = httpContext;
30+
Logger = logger;
3031
}
3132

3233
public HttpContext HttpContext { get; }
@@ -37,6 +38,8 @@ internal ResponseCacheContext(
3738

3839
public CachedVaryByRules CachedVaryByRules { get; internal set; }
3940

41+
internal ILogger Logger { get; }
42+
4043
internal bool ShouldCacheResponse { get; set; }
4144

4245
internal string BaseKey { get; set; }

src/Microsoft.AspNetCore.ResponseCaching/Internal/ResponseCachePolicyProvider.cs

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ public virtual bool IsRequestCacheable(ResponseCacheContext context)
1818
var request = context.HttpContext.Request;
1919
if (!HttpMethods.IsGet(request.Method) && !HttpMethods.IsHead(request.Method))
2020
{
21+
context.Logger.LogRequestMethodNotCacheable(request.Method);
2122
return false;
2223
}
2324

2425
// Verify existence of authorization headers
2526
if (!StringValues.IsNullOrEmpty(request.Headers[HeaderNames.Authorization]))
2627
{
28+
context.Logger.LogRequestWithAuthorizationNotCacheable();
2729
return false;
2830
}
2931

@@ -32,6 +34,7 @@ public virtual bool IsRequestCacheable(ResponseCacheContext context)
3234
{
3335
if (context.RequestCacheControlHeaderValue.NoCache)
3436
{
37+
context.Logger.LogRequestWithNoCacheNotCacheable();
3538
return false;
3639
}
3740
}
@@ -43,6 +46,7 @@ public virtual bool IsRequestCacheable(ResponseCacheContext context)
4346
{
4447
if (string.Equals("no-cache", directive, StringComparison.OrdinalIgnoreCase))
4548
{
49+
context.Logger.LogRequestWithPragmaNoCacheNotCacheable();
4650
return false;
4751
}
4852
}
@@ -56,18 +60,21 @@ public virtual bool IsResponseCacheable(ResponseCacheContext context)
5660
// Only cache pages explicitly marked with public
5761
if (!context.ResponseCacheControlHeaderValue.Public)
5862
{
63+
context.Logger.LogResponseWithoutPublicNotCacheable();
5964
return false;
6065
}
6166

6267
// Check no-store
6368
if (context.RequestCacheControlHeaderValue.NoStore || context.ResponseCacheControlHeaderValue.NoStore)
6469
{
70+
context.Logger.LogResponseWithNoStoreNotCacheable();
6571
return false;
6672
}
6773

6874
// Check no-cache
6975
if (context.ResponseCacheControlHeaderValue.NoCache)
7076
{
77+
context.Logger.LogResponseWithNoCacheNotCacheable();
7178
return false;
7279
}
7380

@@ -76,25 +83,29 @@ public virtual bool IsResponseCacheable(ResponseCacheContext context)
7683
// Do not cache responses with Set-Cookie headers
7784
if (!StringValues.IsNullOrEmpty(response.Headers[HeaderNames.SetCookie]))
7885
{
86+
context.Logger.LogResponseWithSetCookieNotCacheable();
7987
return false;
8088
}
8189

8290
// Do not cache responses varying by *
8391
var varyHeader = response.Headers[HeaderNames.Vary];
8492
if (varyHeader.Count == 1 && string.Equals(varyHeader, "*", StringComparison.OrdinalIgnoreCase))
8593
{
94+
context.Logger.LogResponseWithVaryStarNotCacheable();
8695
return false;
8796
}
8897

8998
// Check private
9099
if (context.ResponseCacheControlHeaderValue.Private)
91100
{
101+
context.Logger.LogResponseWithPrivateNotCacheable();
92102
return false;
93103
}
94104

95105
// Check response code
96106
if (response.StatusCode != StatusCodes.Status200OK)
97107
{
108+
context.Logger.LogResponseWithUnsuccessfulStatusCodeNotCacheable(response.StatusCode);
98109
return false;
99110
}
100111

@@ -105,6 +116,7 @@ public virtual bool IsResponseCacheable(ResponseCacheContext context)
105116
!context.ResponseCacheControlHeaderValue.MaxAge.HasValue &&
106117
context.ResponseTime.Value >= context.ResponseExpires)
107118
{
119+
context.Logger.LogExpirationExpiresExceeded(context.ResponseTime.Value, context.ResponseExpires.Value);
108120
return false;
109121
}
110122
}
@@ -113,22 +125,27 @@ public virtual bool IsResponseCacheable(ResponseCacheContext context)
113125
var age = context.ResponseTime.Value - context.ResponseDate.Value;
114126

115127
// Validate shared max age
116-
if (age >= context.ResponseCacheControlHeaderValue.SharedMaxAge)
128+
var sharedMaxAge = context.ResponseCacheControlHeaderValue.SharedMaxAge;
129+
if (age >= sharedMaxAge)
117130
{
131+
context.Logger.LogExpirationSharedMaxAgeExceeded(age, sharedMaxAge.Value);
118132
return false;
119133
}
120-
else if (!context.ResponseCacheControlHeaderValue.SharedMaxAge.HasValue)
134+
else if (!sharedMaxAge.HasValue)
121135
{
122136
// Validate max age
123-
if (age >= context.ResponseCacheControlHeaderValue.MaxAge)
137+
var maxAge = context.ResponseCacheControlHeaderValue.MaxAge;
138+
if (age >= maxAge)
124139
{
140+
context.Logger.LogExpirationMaxAgeExceeded(age, maxAge.Value);
125141
return false;
126142
}
127-
else if (!context.ResponseCacheControlHeaderValue.MaxAge.HasValue)
143+
else if (!maxAge.HasValue)
128144
{
129145
// Validate expiration
130146
if (context.ResponseTime.Value >= context.ResponseExpires)
131147
{
148+
context.Logger.LogExpirationExpiresExceeded(context.ResponseTime.Value, context.ResponseExpires.Value);
132149
return false;
133150
}
134151
}
@@ -144,41 +161,55 @@ public virtual bool IsCachedEntryFresh(ResponseCacheContext context)
144161
var cachedControlHeaders = context.CachedResponseHeaders.CacheControl ?? EmptyCacheControl;
145162

146163
// Add min-fresh requirements
147-
if (context.RequestCacheControlHeaderValue.MinFresh.HasValue)
164+
var minFresh = context.RequestCacheControlHeaderValue.MinFresh;
165+
if (minFresh.HasValue)
148166
{
149-
age += context.RequestCacheControlHeaderValue.MinFresh.Value;
167+
age += minFresh.Value;
168+
context.Logger.LogExpirationMinFreshAdded(minFresh.Value);
150169
}
151170

152171
// Validate shared max age, this overrides any max age settings for shared caches
153-
if (age >= cachedControlHeaders.SharedMaxAge)
172+
var sharedMaxAge = cachedControlHeaders.SharedMaxAge;
173+
if (age >= sharedMaxAge)
154174
{
155175
// shared max age implies must revalidate
176+
context.Logger.LogExpirationSharedMaxAgeExceeded(age, sharedMaxAge.Value);
156177
return false;
157178
}
158-
else if (!cachedControlHeaders.SharedMaxAge.HasValue)
179+
else if (!sharedMaxAge.HasValue)
159180
{
181+
var cachedMaxAge = cachedControlHeaders.MaxAge;
182+
var requestMaxAge = context.RequestCacheControlHeaderValue.MaxAge;
183+
var lowestMaxAge = cachedMaxAge < requestMaxAge ? cachedMaxAge : requestMaxAge ?? cachedMaxAge;
160184
// Validate max age
161-
if (age >= cachedControlHeaders.MaxAge || age >= context.RequestCacheControlHeaderValue.MaxAge)
185+
if (age >= lowestMaxAge)
162186
{
163187
// Must revalidate
164188
if (cachedControlHeaders.MustRevalidate)
165189
{
190+
context.Logger.LogExpirationMustRevalidate(age, lowestMaxAge.Value);
166191
return false;
167192
}
168193

169194
// Request allows stale values
170-
if (age < context.RequestCacheControlHeaderValue.MaxStaleLimit)
195+
var maxStaleLimit = context.RequestCacheControlHeaderValue.MaxStaleLimit;
196+
if (maxStaleLimit.HasValue && age - lowestMaxAge < maxStaleLimit)
171197
{
198+
context.Logger.LogExpirationMaxStaleSatisfied(age, lowestMaxAge.Value, maxStaleLimit.Value);
172199
return true;
173200
}
174201

202+
context.Logger.LogExpirationMaxAgeExceeded(age, lowestMaxAge.Value);
175203
return false;
176204
}
177-
else if (!cachedControlHeaders.MaxAge.HasValue && !context.RequestCacheControlHeaderValue.MaxAge.HasValue)
205+
else if (!cachedMaxAge.HasValue && !requestMaxAge.HasValue)
178206
{
179207
// Validate expiration
180-
if (context.ResponseTime.Value >= context.CachedResponseHeaders.Expires)
208+
var responseTime = context.ResponseTime.Value;
209+
var expires = context.CachedResponseHeaders.Expires;
210+
if (responseTime >= expires)
181211
{
212+
context.Logger.LogExpirationExpiresExceeded(responseTime, expires.Value);
182213
return false;
183214
}
184215
}

src/Microsoft.AspNetCore.ResponseCaching/ResponseCacheMiddleware.cs

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
using Microsoft.AspNetCore.Http.Headers;
1111
using Microsoft.AspNetCore.ResponseCaching.Internal;
1212
using Microsoft.Extensions.Internal;
13-
using Microsoft.Extensions.ObjectPool;
13+
using Microsoft.Extensions.Logging;
1414
using Microsoft.Extensions.Options;
1515
using Microsoft.Extensions.Primitives;
1616
using Microsoft.Net.Http.Headers;
@@ -22,15 +22,17 @@ public class ResponseCacheMiddleware
2222
private static readonly TimeSpan DefaultExpirationTimeSpan = TimeSpan.FromSeconds(10);
2323

2424
private readonly RequestDelegate _next;
25-
private readonly IResponseCacheStore _store;
2625
private readonly ResponseCacheOptions _options;
26+
private readonly ILogger _logger;
2727
private readonly IResponseCachePolicyProvider _policyProvider;
28+
private readonly IResponseCacheStore _store;
2829
private readonly IResponseCacheKeyProvider _keyProvider;
2930
private readonly Func<object, Task> _onStartingCallback;
3031

3132
public ResponseCacheMiddleware(
3233
RequestDelegate next,
3334
IOptions<ResponseCacheOptions> options,
35+
ILoggerFactory loggerFactory,
3436
IResponseCachePolicyProvider policyProvider,
3537
IResponseCacheStore store,
3638
IResponseCacheKeyProvider keyProvider)
@@ -39,34 +41,39 @@ public ResponseCacheMiddleware(
3941
{
4042
throw new ArgumentNullException(nameof(next));
4143
}
42-
if (store == null)
43-
{
44-
throw new ArgumentNullException(nameof(store));
45-
}
4644
if (options == null)
4745
{
4846
throw new ArgumentNullException(nameof(options));
4947
}
48+
if (loggerFactory == null)
49+
{
50+
throw new ArgumentNullException(nameof(loggerFactory));
51+
}
5052
if (policyProvider == null)
5153
{
5254
throw new ArgumentNullException(nameof(policyProvider));
5355
}
56+
if (store == null)
57+
{
58+
throw new ArgumentNullException(nameof(store));
59+
}
5460
if (keyProvider == null)
5561
{
5662
throw new ArgumentNullException(nameof(keyProvider));
5763
}
5864

5965
_next = next;
60-
_store = store;
6166
_options = options.Value;
67+
_logger = loggerFactory.CreateLogger<ResponseCacheMiddleware>();
6268
_policyProvider = policyProvider;
69+
_store = store;
6370
_keyProvider = keyProvider;
6471
_onStartingCallback = state => OnResponseStartingAsync((ResponseCacheContext)state);
6572
}
6673

6774
public async Task Invoke(HttpContext httpContext)
6875
{
69-
var context = new ResponseCacheContext(httpContext);
76+
var context = new ResponseCacheContext(httpContext, _logger);
7077

7178
// Should we attempt any caching logic?
7279
if (_policyProvider.IsRequestCacheable(context))
@@ -115,8 +122,9 @@ internal async Task<bool> TryServeCachedResponseAsync(ResponseCacheContext conte
115122
if (_policyProvider.IsCachedEntryFresh(context))
116123
{
117124
// Check conditional request rules
118-
if (ConditionalRequestSatisfied(context))
125+
if (ContentIsNotModified(context))
119126
{
127+
_logger.LogNotModifiedServed();
120128
context.HttpContext.Response.StatusCode = StatusCodes.Status304NotModified;
121129
}
122130
else
@@ -150,8 +158,8 @@ internal async Task<bool> TryServeCachedResponseAsync(ResponseCacheContext conte
150158
context.HttpContext.Abort();
151159
}
152160
}
161+
_logger.LogCachedResponseServed();
153162
}
154-
155163
return true;
156164
}
157165

@@ -183,13 +191,14 @@ internal async Task<bool> TryServeFromCacheAsync(ResponseCacheContext context)
183191
return true;
184192
}
185193

186-
187194
if (context.RequestCacheControlHeaderValue.OnlyIfCached)
188195
{
196+
_logger.LogGatewayTimeoutServed();
189197
context.HttpContext.Response.StatusCode = StatusCodes.Status504GatewayTimeout;
190198
return true;
191199
}
192200

201+
_logger.LogNoResponseServed();
193202
return false;
194203
}
195204

@@ -229,6 +238,7 @@ internal async Task FinalizeCacheHeadersAsync(ResponseCacheContext context)
229238
}
230239

231240
// Always overwrite the CachedVaryByRules to update the expiry information
241+
_logger.LogVaryByRulesUpdated(normalizedVaryHeaders, normalizedVaryQueryKeys);
232242
await _store.SetAsync(context.BaseKey, context.CachedVaryByRules, context.CachedResponseValidFor);
233243

234244
context.StorageVaryKey = _keyProvider.CreateStorageVaryByKey(context);
@@ -272,8 +282,17 @@ internal async Task FinalizeCacheBodyAsync(ResponseCacheContext context)
272282
if (!contentLength.HasValue || contentLength == bufferStream.Length)
273283
{
274284
context.CachedResponse.Body = bufferStream;
285+
_logger.LogResponseCached();
275286
await _store.SetAsync(context.StorageVaryKey ?? context.BaseKey, context.CachedResponse, context.CachedResponseValidFor);
276287
}
288+
else
289+
{
290+
_logger.LogResponseContentLengthMismatchNotCached();
291+
}
292+
}
293+
else
294+
{
295+
_logger.LogResponseNotCached();
277296
}
278297
}
279298

@@ -320,7 +339,7 @@ internal static void UnshimResponseStream(ResponseCacheContext context)
320339
context.HttpContext.RemoveResponseCacheFeature();
321340
}
322341

323-
internal static bool ConditionalRequestSatisfied(ResponseCacheContext context)
342+
internal static bool ContentIsNotModified(ResponseCacheContext context)
324343
{
325344
var cachedResponseHeaders = context.CachedResponseHeaders;
326345
var ifNoneMatchHeader = context.TypedRequestHeaders.IfNoneMatch;
@@ -329,6 +348,7 @@ internal static bool ConditionalRequestSatisfied(ResponseCacheContext context)
329348
{
330349
if (ifNoneMatchHeader.Count == 1 && ifNoneMatchHeader[0].Equals(EntityTagHeaderValue.Any))
331350
{
351+
context.Logger.LogNotModifiedIfNoneMatchStar();
332352
return true;
333353
}
334354

@@ -338,6 +358,7 @@ internal static bool ConditionalRequestSatisfied(ResponseCacheContext context)
338358
{
339359
if (cachedResponseHeaders.ETag.Compare(tag, useStrongComparison: false))
340360
{
361+
context.Logger.LogNotModifiedIfNoneMatchMatched(tag);
341362
return true;
342363
}
343364
}
@@ -346,9 +367,14 @@ internal static bool ConditionalRequestSatisfied(ResponseCacheContext context)
346367
else
347368
{
348369
var ifUnmodifiedSince = context.TypedRequestHeaders.IfUnmodifiedSince;
349-
if (ifUnmodifiedSince != null && (cachedResponseHeaders.LastModified ?? cachedResponseHeaders.Date) <= ifUnmodifiedSince)
370+
if (ifUnmodifiedSince != null)
350371
{
351-
return true;
372+
var lastModified = cachedResponseHeaders.LastModified ?? cachedResponseHeaders.Date;
373+
if (lastModified <= ifUnmodifiedSince)
374+
{
375+
context.Logger.LogNotModifiedIfUnmodifiedSinceSatisfied(lastModified.Value, ifUnmodifiedSince.Value);
376+
return true;
377+
}
352378
}
353379
}
354380

0 commit comments

Comments
 (0)