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

Commit 4fe6a2a

Browse files
Add logging to ResourceManagerStringLocalizer
1 parent 241d2e4 commit 4fe6a2a

8 files changed

+216
-34
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using Microsoft.Extensions.Logging;
5+
using System;
6+
7+
namespace Microsoft.Extensions.Localization.Internal
8+
{
9+
internal static class ResourceManagerStringLocalizerLoggerExtensions
10+
{
11+
private static readonly Action<ILogger, string, string, Exception> _locationSearched;
12+
13+
static ResourceManagerStringLocalizerLoggerExtensions()
14+
{
15+
_locationSearched = LoggerMessage.Define<string, string>(
16+
LogLevel.Information,
17+
1,
18+
"ResourceManagerStringLocalizer searched for '{Key}' in '{LocationSearched}'.");
19+
}
20+
21+
public static void LocationSearched(this ILogger logger, string key, string locationSearched)
22+
{
23+
_locationSearched(logger, key, locationSearched, null);
24+
}
25+
}
26+
}

src/Microsoft.Extensions.Localization/Microsoft.Extensions.Localization.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
<ProjectReference Include="..\Microsoft.Extensions.Localization.Abstractions\Microsoft.Extensions.Localization.Abstractions.csproj" />
1616
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="1.2.0-*" />
1717
<PackageReference Include="Microsoft.Extensions.Options" Version="1.2.0-*" />
18+
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.2.0-*" />
1819
</ItemGroup>
1920

2021
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">

src/Microsoft.Extensions.Localization/ResourceManagerStringLocalizer.cs

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Reflection;
99
using System.Resources;
1010
using Microsoft.Extensions.Localization.Internal;
11+
using Microsoft.Extensions.Logging;
1112

1213
namespace Microsoft.Extensions.Localization
1314
{
@@ -23,6 +24,8 @@ public class ResourceManagerStringLocalizer : IStringLocalizer
2324
private readonly ResourceManager _resourceManager;
2425
private readonly IResourceStringProvider _resourceStringProvider;
2526
private readonly string _resourceBaseName;
27+
private readonly ILogger<ResourceManagerStringLocalizer> _logger;
28+
private readonly ILoggerFactory _loggerFactory;
2629

2730
/// <summary>
2831
/// Creates a new <see cref="ResourceManagerStringLocalizer"/>.
@@ -31,16 +34,19 @@ public class ResourceManagerStringLocalizer : IStringLocalizer
3134
/// <param name="resourceAssembly">The <see cref="Assembly"/> that contains the strings as embedded resources.</param>
3235
/// <param name="baseName">The base name of the embedded resource that contains the strings.</param>
3336
/// <param name="resourceNamesCache">Cache of the list of strings for a given resource assembly name.</param>
37+
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/> used to log about resources.</param>
3438
public ResourceManagerStringLocalizer(
3539
ResourceManager resourceManager,
3640
Assembly resourceAssembly,
3741
string baseName,
38-
IResourceNamesCache resourceNamesCache)
42+
IResourceNamesCache resourceNamesCache,
43+
ILoggerFactory loggerFactory)
3944
: this(
4045
resourceManager,
4146
new AssemblyWrapper(resourceAssembly),
4247
baseName,
43-
resourceNamesCache)
48+
resourceNamesCache,
49+
loggerFactory)
4450
{
4551
}
4652

@@ -51,12 +57,14 @@ public ResourceManagerStringLocalizer(
5157
ResourceManager resourceManager,
5258
AssemblyWrapper resourceAssemblyWrapper,
5359
string baseName,
54-
IResourceNamesCache resourceNamesCache)
60+
IResourceNamesCache resourceNamesCache,
61+
ILoggerFactory loggerFactory)
5562
: this(
5663
resourceManager,
5764
new AssemblyResourceStringProvider(resourceNamesCache, resourceAssemblyWrapper, baseName),
5865
baseName,
59-
resourceNamesCache)
66+
resourceNamesCache,
67+
loggerFactory)
6068
{
6169
}
6270

@@ -67,7 +75,8 @@ public ResourceManagerStringLocalizer(
6775
ResourceManager resourceManager,
6876
IResourceStringProvider resourceStringProvider,
6977
string baseName,
70-
IResourceNamesCache resourceNamesCache)
78+
IResourceNamesCache resourceNamesCache,
79+
ILoggerFactory loggerFactory)
7180
{
7281
if (resourceManager == null)
7382
{
@@ -89,10 +98,17 @@ public ResourceManagerStringLocalizer(
8998
throw new ArgumentNullException(nameof(resourceNamesCache));
9099
}
91100

101+
if (loggerFactory == null)
102+
{
103+
throw new ArgumentNullException(nameof(loggerFactory));
104+
}
105+
92106
_resourceStringProvider = resourceStringProvider;
93107
_resourceManager = resourceManager;
94108
_resourceBaseName = baseName;
95109
_resourceNamesCache = resourceNamesCache;
110+
_loggerFactory = loggerFactory;
111+
_logger = loggerFactory.CreateLogger<ResourceManagerStringLocalizer>();
96112
}
97113

98114
/// <inheritdoc />
@@ -140,13 +156,15 @@ public IStringLocalizer WithCulture(CultureInfo culture)
140156
_resourceManager,
141157
_resourceStringProvider,
142158
_resourceBaseName,
143-
_resourceNamesCache)
159+
_resourceNamesCache,
160+
_loggerFactory)
144161
: new ResourceManagerWithCultureStringLocalizer(
145162
_resourceManager,
146163
_resourceStringProvider,
147164
_resourceBaseName,
148165
_resourceNamesCache,
149-
culture);
166+
culture,
167+
_loggerFactory);
150168
}
151169

152170
/// <inheritdoc />
@@ -193,6 +211,8 @@ protected string GetStringSafely(string name, CultureInfo culture)
193211

194212
var cacheKey = $"name={name}&culture={(culture ?? CultureInfo.CurrentUICulture).Name}";
195213

214+
_logger.LocationSearched(name, _resourceBaseName);
215+
196216
if (_missingManifestCache.ContainsKey(cacheKey))
197217
{
198218
return null;

src/Microsoft.Extensions.Localization/ResourceManagerStringLocalizerFactory.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Reflection;
88
using System.Resources;
99
using Microsoft.Extensions.Options;
10+
using Microsoft.Extensions.Logging;
1011

1112
namespace Microsoft.Extensions.Localization
1213
{
@@ -24,20 +25,30 @@ public class ResourceManagerStringLocalizerFactory : IStringLocalizerFactory
2425
private readonly ConcurrentDictionary<string, ResourceManagerStringLocalizer> _localizerCache =
2526
new ConcurrentDictionary<string, ResourceManagerStringLocalizer>();
2627
private readonly string _resourcesRelativePath;
28+
private readonly ILoggerFactory _loggerFactory;
2729

2830
/// <summary>
2931
/// Creates a new <see cref="ResourceManagerStringLocalizer"/>.
3032
/// </summary>
3133
/// <param name="localizationOptions">The <see cref="IOptions{LocalizationOptions}"/>.</param>
34+
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/> to use in creating <see cref="ResourceManagerStringLocalizer"/>'s.</param>
3235
public ResourceManagerStringLocalizerFactory(
33-
IOptions<LocalizationOptions> localizationOptions)
36+
IOptions<LocalizationOptions> localizationOptions,
37+
ILoggerFactory loggerFactory)
3438
{
3539
if (localizationOptions == null)
3640
{
3741
throw new ArgumentNullException(nameof(localizationOptions));
3842
}
3943

44+
if (loggerFactory == null)
45+
{
46+
throw new ArgumentNullException(nameof(loggerFactory));
47+
}
48+
4049
_resourcesRelativePath = localizationOptions.Value.ResourcesPath ?? string.Empty;
50+
_loggerFactory = loggerFactory;
51+
4152
if (!string.IsNullOrEmpty(_resourcesRelativePath))
4253
{
4354
_resourcesRelativePath = _resourcesRelativePath.Replace(Path.AltDirectorySeparatorChar, '.')
@@ -180,7 +191,8 @@ protected virtual ResourceManagerStringLocalizer CreateResourceManagerStringLoca
180191
new ResourceManager(baseName, assembly),
181192
assembly,
182193
baseName,
183-
_resourceNamesCache);
194+
_resourceNamesCache,
195+
_loggerFactory);
184196
}
185197

186198
/// <summary>

src/Microsoft.Extensions.Localization/ResourceManagerWithCultureStringLocalizer.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Reflection;
88
using System.Resources;
99
using Microsoft.Extensions.Localization.Internal;
10+
using Microsoft.Extensions.Logging;
1011

1112
namespace Microsoft.Extensions.Localization
1213
{
@@ -26,13 +27,15 @@ public class ResourceManagerWithCultureStringLocalizer : ResourceManagerStringLo
2627
/// <param name="baseName">The base name of the embedded resource that contains the strings.</param>
2728
/// <param name="resourceNamesCache">Cache of the list of strings for a given resource assembly name.</param>
2829
/// <param name="culture">The specific <see cref="CultureInfo"/> to use.</param>
30+
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/> used to log about resources.</param>
2931
internal ResourceManagerWithCultureStringLocalizer(
3032
ResourceManager resourceManager,
3133
IResourceStringProvider resourceStringProvider,
3234
string baseName,
3335
IResourceNamesCache resourceNamesCache,
34-
CultureInfo culture)
35-
: base(resourceManager, resourceStringProvider, baseName, resourceNamesCache)
36+
CultureInfo culture,
37+
ILoggerFactory loggerFactory)
38+
: base(resourceManager, resourceStringProvider, baseName, resourceNamesCache, loggerFactory)
3639
{
3740
if (resourceManager == null)
3841
{
@@ -70,13 +73,15 @@ internal ResourceManagerWithCultureStringLocalizer(
7073
/// <param name="baseName">The base name of the embedded resource that contains the strings.</param>
7174
/// <param name="resourceNamesCache">Cache of the list of strings for a given resource assembly name.</param>
7275
/// <param name="culture">The specific <see cref="CultureInfo"/> to use.</param>
76+
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/> used to log about resources.</param>
7377
public ResourceManagerWithCultureStringLocalizer(
7478
ResourceManager resourceManager,
7579
Assembly resourceAssembly,
7680
string baseName,
7781
IResourceNamesCache resourceNamesCache,
78-
CultureInfo culture)
79-
: base(resourceManager, resourceAssembly, baseName, resourceNamesCache)
82+
CultureInfo culture,
83+
ILoggerFactory loggerFactory)
84+
: base(resourceManager, resourceAssembly, baseName, resourceNamesCache, loggerFactory)
8085
{
8186
if (resourceManager == null)
8287
{

test/Microsoft.AspNetCore.Localization.Tests/Microsoft.AspNetCore.Localization.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<ItemGroup>
1010
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Localization\Microsoft.AspNetCore.Localization.csproj" />
1111
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="1.2.0-*" />
12+
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.2.0-*" />
1213
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0-*" />
1314
<PackageReference Include="xunit" Version="2.2.0-*" />
1415
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0-*" />

test/Microsoft.Extensions.Localization.Tests/ResourceManagerStringLocalizerFactoryTest.cs

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Microsoft.Extensions.Options;
88
using Moq;
99
using Xunit;
10+
using Microsoft.Extensions.Logging;
1011

1112
namespace Microsoft.Extensions.Localization.Tests
1213
{
@@ -19,8 +20,9 @@ public class TestResourceManagerStringLocalizerFactory : ResourceManagerStringLo
1920

2021
public TestResourceManagerStringLocalizerFactory(
2122
IOptions<LocalizationOptions> localizationOptions,
22-
ResourceLocationAttribute resourceLocationAttribute)
23-
: base(localizationOptions)
23+
ResourceLocationAttribute resourceLocationAttribute,
24+
ILoggerFactory loggerFactory)
25+
: base(localizationOptions, loggerFactory)
2426
{
2527
_resourceLocationAttribute = resourceLocationAttribute;
2628
}
@@ -50,12 +52,15 @@ public void Create_OverloadsProduceSameResult()
5052
options.Setup(o => o.Value).Returns(locOptions);
5153

5254
var resourceLocationAttribute = new ResourceLocationAttribute(Path.Combine("My", "Resources"));
55+
var loggerFactory = GetLoggerFactory();
5356
var typeFactory = new TestResourceManagerStringLocalizerFactory(
5457
options.Object,
55-
resourceLocationAttribute);
58+
resourceLocationAttribute,
59+
loggerFactory);
5660
var stringFactory = new TestResourceManagerStringLocalizerFactory(
5761
options.Object,
58-
resourceLocationAttribute);
62+
resourceLocationAttribute,
63+
loggerFactory);
5964
var type = typeof(ResourceManagerStringLocalizerFactoryTest);
6065
var assemblyName = new AssemblyName(type.GetTypeInfo().Assembly.FullName);
6166

@@ -75,7 +80,8 @@ public void Create_FromType_ReturnsCachedResultForSameType()
7580
var locOptions = new LocalizationOptions();
7681
var options = new Mock<IOptions<LocalizationOptions>>();
7782
options.Setup(o => o.Value).Returns(locOptions);
78-
var factory = new ResourceManagerStringLocalizerFactory(localizationOptions: options.Object);
83+
var loggerFactory = GetLoggerFactory();
84+
var factory = new ResourceManagerStringLocalizerFactory(localizationOptions: options.Object, loggerFactory: loggerFactory);
7985

8086
// Act
8187
var result1 = factory.Create(typeof(ResourceManagerStringLocalizerFactoryTest));
@@ -92,7 +98,8 @@ public void Create_FromType_ReturnsNewResultForDifferentType()
9298
var locOptions = new LocalizationOptions();
9399
var options = new Mock<IOptions<LocalizationOptions>>();
94100
options.Setup(o => o.Value).Returns(locOptions);
95-
var factory = new ResourceManagerStringLocalizerFactory(localizationOptions: options.Object);
101+
var loggerFactory = GetLoggerFactory();
102+
var factory = new ResourceManagerStringLocalizerFactory(localizationOptions: options.Object, loggerFactory: loggerFactory);
96103

97104
// Act
98105
var result1 = factory.Create(typeof(ResourceManagerStringLocalizerFactoryTest));
@@ -110,9 +117,11 @@ public void Create_FromType_ResourcesPathDirectorySeperatorToDot()
110117
locOptions.ResourcesPath = Path.Combine("My", "Resources");
111118
var options = new Mock<IOptions<LocalizationOptions>>();
112119
options.Setup(o => o.Value).Returns(locOptions);
120+
var loggerFactory = GetLoggerFactory();
113121
var factory = new TestResourceManagerStringLocalizerFactory(
114122
options.Object,
115-
resourceLocationAttribute: null);
123+
resourceLocationAttribute: null,
124+
loggerFactory: loggerFactory);
116125

117126
// Act
118127
factory.Create(typeof(ResourceManagerStringLocalizerFactoryTest));
@@ -128,7 +137,8 @@ public void Create_FromNameLocation_ReturnsCachedResultForSameNameLocation()
128137
var locOptions = new LocalizationOptions();
129138
var options = new Mock<IOptions<LocalizationOptions>>();
130139
options.Setup(o => o.Value).Returns(locOptions);
131-
var factory = new ResourceManagerStringLocalizerFactory(localizationOptions: options.Object);
140+
var loggerFactory = GetLoggerFactory();
141+
var factory = new ResourceManagerStringLocalizerFactory(localizationOptions: options.Object, loggerFactory: loggerFactory);
132142
var location = typeof(ResourceManagerStringLocalizer).GetTypeInfo().Assembly.FullName;
133143

134144
// Act
@@ -146,7 +156,8 @@ public void Create_FromNameLocation_ReturnsNewResultForDifferentName()
146156
var locOptions = new LocalizationOptions();
147157
var options = new Mock<IOptions<LocalizationOptions>>();
148158
options.Setup(o => o.Value).Returns(locOptions);
149-
var factory = new ResourceManagerStringLocalizerFactory(localizationOptions: options.Object);
159+
var loggerFactory = GetLoggerFactory();
160+
var factory = new ResourceManagerStringLocalizerFactory(localizationOptions: options.Object, loggerFactory: loggerFactory);
150161
var location = typeof(ResourceManagerStringLocalizer).GetTypeInfo().Assembly.FullName;
151162

152163
// Act
@@ -164,7 +175,8 @@ public void Create_FromNameLocation_ReturnsNewResultForDifferentLocation()
164175
var locOptions = new LocalizationOptions();
165176
var options = new Mock<IOptions<LocalizationOptions>>();
166177
options.Setup(o => o.Value).Returns(locOptions);
167-
var factory = new ResourceManagerStringLocalizerFactory(localizationOptions: options.Object);
178+
var loggerFactory = GetLoggerFactory();
179+
var factory = new ResourceManagerStringLocalizerFactory(localizationOptions: options.Object, loggerFactory: loggerFactory);
168180
var location1 = new AssemblyName(typeof(ResourceManagerStringLocalizer).GetTypeInfo().Assembly.FullName).Name;
169181
var location2 = new AssemblyName(typeof(ResourceManagerStringLocalizerFactoryTest).GetTypeInfo().Assembly.FullName).Name;
170182

@@ -184,9 +196,11 @@ public void Create_FromNameLocation_ResourcesPathDirectorySeparatorToDot()
184196
locOptions.ResourcesPath = Path.Combine("My", "Resources");
185197
var options = new Mock<IOptions<LocalizationOptions>>();
186198
options.Setup(o => o.Value).Returns(locOptions);
199+
var loggerFactory = GetLoggerFactory();
187200
var factory = new TestResourceManagerStringLocalizerFactory(
188201
options.Object,
189-
resourceLocationAttribute: null);
202+
resourceLocationAttribute: null,
203+
loggerFactory: loggerFactory);
190204

191205
// Act
192206
var result1 = factory.Create("baseName", location: "Microsoft.Extensions.Localization.Tests");
@@ -202,10 +216,22 @@ public void Create_FromNameLocation_NullLocationThrows()
202216
var locOptions = new LocalizationOptions();
203217
var options = new Mock<IOptions<LocalizationOptions>>();
204218
options.Setup(o => o.Value).Returns(locOptions);
205-
var factory = new ResourceManagerStringLocalizerFactory(localizationOptions: options.Object);
219+
var loggerFactory = GetLoggerFactory();
220+
var factory = new ResourceManagerStringLocalizerFactory(localizationOptions: options.Object, loggerFactory: loggerFactory);
206221

207222
// Act & Assert
208223
Assert.Throws<ArgumentNullException>(() => factory.Create("baseName", location: null));
209224
}
225+
226+
private ILoggerFactory GetLoggerFactory()
227+
{
228+
var logger = new Mock<ILogger>();
229+
logger.Setup(l => l.Log(LogLevel.Information, It.IsAny<EventId>(), new object(), It.IsAny<Exception>(), It.IsAny<Func<object, Exception, string>>()));
230+
231+
var mock = new Mock<ILoggerFactory>();
232+
mock.Setup(f => f.CreateLogger(It.IsAny<string>())).Returns(logger.Object);
233+
234+
return mock.Object;
235+
}
210236
}
211237
}

0 commit comments

Comments
 (0)