Skip to content

Commit f860e25

Browse files
authored
Merge pull request #26 from dotnet-campus/t/lindexi/LoggerInterpolatedStringHandler
尝试减少日志过程中的字符串创建数量
2 parents 023780c + 7062a5d commit f860e25

17 files changed

+329
-10
lines changed

dotnetCampus.Logger.sln

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
21
Microsoft Visual Studio Solution File, Format Version 12.00
3-
# Visual Studio Version 16
4-
VisualStudioVersion = 16.0.30804.86
2+
# Visual Studio Version 17
3+
VisualStudioVersion = 17.10.35013.160
54
MinimumVisualStudioVersion = 15.0.26124.0
65
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnetCampus.Logger", "src\dotnetCampus.Logger\dotnetCampus.Logger.csproj", "{F7ED61F4-920C-49EB-8DC1-74B2BE6AF272}"
76
ProjectSection(ProjectDependencies) = postProject
@@ -18,21 +17,23 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{AFB0DF31
1817
Directory.Build.targets = Directory.Build.targets
1918
EndProjectSection
2019
EndProject
21-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LoggerSample.MainApp", "samples\LoggerSample.MainApp\LoggerSample.MainApp.csproj", "{C282F00B-0C42-491F-AC0D-967407E1C418}"
20+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LoggerSample.MainApp", "samples\LoggerSample.MainApp\LoggerSample.MainApp.csproj", "{C282F00B-0C42-491F-AC0D-967407E1C418}"
2221
EndProject
2322
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{34E3F27E-C7E2-45D7-8035-53C304F77E2A}"
2423
EndProject
25-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LoggerSample.LoggerDependentLibrary", "samples\LoggerSample.LoggerDependentLibrary\LoggerSample.LoggerDependentLibrary.csproj", "{0A1ACF06-FC64-4B5C-97E9-AA2CC307C899}"
24+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LoggerSample.LoggerDependentLibrary", "samples\LoggerSample.LoggerDependentLibrary\LoggerSample.LoggerDependentLibrary.csproj", "{0A1ACF06-FC64-4B5C-97E9-AA2CC307C899}"
2625
EndProject
27-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LoggerSample.LoggerIndependentLibrary", "samples\LoggerSample.LoggerIndependentLibrary\LoggerSample.LoggerIndependentLibrary.csproj", "{36367E21-BABC-4CC4-891E-CEAF56D66B68}"
26+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LoggerSample.LoggerIndependentLibrary", "samples\LoggerSample.LoggerIndependentLibrary\LoggerSample.LoggerIndependentLibrary.csproj", "{36367E21-BABC-4CC4-891E-CEAF56D66B68}"
2827
EndProject
2928
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{36852775-3A76-49CF-98CC-3067CE54A5AD}"
3029
EndProject
31-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dotnetCampus.Logger.Tests", "tests\dotnetCampus.Logger.Tests\dotnetCampus.Logger.Tests.csproj", "{D0ACB879-D49B-4ACD-9852-23D0E6D15DDB}"
30+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnetCampus.Logger.Tests", "tests\dotnetCampus.Logger.Tests\dotnetCampus.Logger.Tests.csproj", "{D0ACB879-D49B-4ACD-9852-23D0E6D15DDB}"
3231
EndProject
33-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dotnetCampus.Logger.Analyzer", "src\dotnetCampus.Logger.Analyzer\dotnetCampus.Logger.Analyzer.csproj", "{77F0A6B5-6C8B-4815-8C1E-4F97C24BFB36}"
32+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnetCampus.Logger.Analyzer", "src\dotnetCampus.Logger.Analyzer\dotnetCampus.Logger.Analyzer.csproj", "{77F0A6B5-6C8B-4815-8C1E-4F97C24BFB36}"
3433
EndProject
35-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LoggerSample.LoggerIndependentProject", "samples\LoggerSample.LoggerIndependentProject\LoggerSample.LoggerIndependentProject.csproj", "{E0DE93BF-AE07-4F92-A3FD-F4D661339BE0}"
34+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LoggerSample.LoggerIndependentProject", "samples\LoggerSample.LoggerIndependentProject\LoggerSample.LoggerIndependentProject.csproj", "{E0DE93BF-AE07-4F92-A3FD-F4D661339BE0}"
35+
EndProject
36+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnetCampus.Logger.Analyzer.Tests", "tests\dotnetCampus.Logger.Analyzer.Tests\dotnetCampus.Logger.Analyzer.Tests.csproj", "{62456A3B-33BC-475E-BC55-5134CF89127D}"
3637
EndProject
3738
Global
3839
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -44,6 +45,18 @@ Global
4445
Release|x86 = Release|x86
4546
EndGlobalSection
4647
GlobalSection(ProjectConfigurationPlatforms) = postSolution
48+
{62456A3B-33BC-475E-BC55-5134CF89127D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
49+
{62456A3B-33BC-475E-BC55-5134CF89127D}.Debug|Any CPU.Build.0 = Debug|Any CPU
50+
{62456A3B-33BC-475E-BC55-5134CF89127D}.Debug|x64.ActiveCfg = Debug|Any CPU
51+
{62456A3B-33BC-475E-BC55-5134CF89127D}.Debug|x64.Build.0 = Debug|Any CPU
52+
{62456A3B-33BC-475E-BC55-5134CF89127D}.Debug|x86.ActiveCfg = Debug|Any CPU
53+
{62456A3B-33BC-475E-BC55-5134CF89127D}.Debug|x86.Build.0 = Debug|Any CPU
54+
{62456A3B-33BC-475E-BC55-5134CF89127D}.Release|Any CPU.ActiveCfg = Release|Any CPU
55+
{62456A3B-33BC-475E-BC55-5134CF89127D}.Release|Any CPU.Build.0 = Release|Any CPU
56+
{62456A3B-33BC-475E-BC55-5134CF89127D}.Release|x64.ActiveCfg = Release|Any CPU
57+
{62456A3B-33BC-475E-BC55-5134CF89127D}.Release|x64.Build.0 = Release|Any CPU
58+
{62456A3B-33BC-475E-BC55-5134CF89127D}.Release|x86.ActiveCfg = Release|Any CPU
59+
{62456A3B-33BC-475E-BC55-5134CF89127D}.Release|x86.Build.0 = Release|Any CPU
4760
{F7ED61F4-920C-49EB-8DC1-74B2BE6AF272}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
4861
{F7ED61F4-920C-49EB-8DC1-74B2BE6AF272}.Debug|Any CPU.Build.0 = Debug|Any CPU
4962
{F7ED61F4-920C-49EB-8DC1-74B2BE6AF272}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -133,6 +146,7 @@ Global
133146
HideSolutionNode = FALSE
134147
EndGlobalSection
135148
GlobalSection(NestedProjects) = preSolution
149+
{62456A3B-33BC-475E-BC55-5134CF89127D} = {36852775-3A76-49CF-98CC-3067CE54A5AD}
136150
{C282F00B-0C42-491F-AC0D-967407E1C418} = {34E3F27E-C7E2-45D7-8035-53C304F77E2A}
137151
{0A1ACF06-FC64-4B5C-97E9-AA2CC307C899} = {34E3F27E-C7E2-45D7-8035-53C304F77E2A}
138152
{36367E21-BABC-4CC4-891E-CEAF56D66B68} = {34E3F27E-C7E2-45D7-8035-53C304F77E2A}

samples/LoggerSample.MainApp/LoggerSample.MainApp.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<OutputType>Exe</OutputType>
55
<TargetFramework>net8.0</TargetFramework>
66
<DCUseGeneratedLogger>preferReference</DCUseGeneratedLogger>
7+
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
78
</PropertyGroup>
89

910
<ItemGroup>

src/dotnetCampus.Logger.Analyzer/Assets/Templates/AggregateLoggerBridgeLinker.g.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ partial class AggregateLoggerBridgeLinker : GILoggerBridgeLinker
1919
/// </summary>
2020
public static AggregateLoggerBridgeLinker Default { get; } = new();
2121

22+
public bool IsEnabled(int logLevel)
23+
{
24+
var logger = _logger ?? GLog.Current;
25+
return logger.IsEnabled((GLogLevel)logLevel);
26+
}
27+
2228
private GILogger? _logger;
2329

2430
/// <summary>

src/dotnetCampus.Logger/Bridges/BridgeLogger.g.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,17 @@ namespace dotnetCampus.Logging.Bridges;
1010
/// </summary>
1111
internal class BridgeLogger : ILogger
1212
{
13+
public bool IsEnabled(LogLevel logLevel)
14+
{
15+
return
16+
#if NETCOREAPP3_0_OR_GREATER
17+
ILoggerBridge
18+
#else
19+
LoggerBridgeLinker
20+
#endif
21+
.Bridge?.IsEnabled((int)logLevel) ?? false;
22+
}
23+
1324
/// <inheritdoc />
1425
void ILogger.Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
1526
{

src/dotnetCampus.Logger/Bridges/ILoggerBridge.g.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ namespace dotnetCampus.Logging.Bridges;
1010
/// </summary>
1111
public interface ILoggerBridge
1212
{
13+
bool IsEnabled(int logLevel)
14+
#if NETCOREAPP3_0_OR_GREATER
15+
=> true
16+
#endif
17+
;
18+
1319
/// <summary>
1420
/// 写入日志条目。
1521
/// </summary>

src/dotnetCampus.Logger/CompositeLogger.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@ public LogLevel Level
2929
/// </summary>
3030
public required ImmutableArrayILogger Writers { get; init; }
3131

32+
public bool IsEnabled(LogLevel logLevel)
33+
{
34+
if (logLevel < Level)
35+
{
36+
return false;
37+
}
38+
39+
return true;
40+
}
41+
3242
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
3343
{
3444
if (logLevel < Level)

src/dotnetCampus.Logger/ILogger.g.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ namespace dotnetCampus.Logging;
1212
/// </remarks>
1313
public interface ILogger
1414
{
15+
/// <summary>
16+
/// 检查是否已启用给定的日志级别。
17+
/// </summary>
18+
/// <param name="logLevel"></param>
19+
/// <returns></returns>
20+
bool IsEnabled(LogLevel logLevel);
21+
1522
/// <summary>
1623
/// 写入日志条目。
1724
/// </summary>

src/dotnetCampus.Logger/Log.g.cs

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#nullable enable
22

3+
using global::System.Runtime.CompilerServices;
34
using global::System;
45
using global::System.Diagnostics.CodeAnalysis;
56

@@ -129,4 +130,77 @@ public static void Fatal(string message, Exception? exception = null)
129130
{
130131
Current.Log(LogLevel.Critical, default, message, null, static (s, ex) => s);
131132
}
132-
}
133+
134+
#if NET6_0_OR_GREATER
135+
/// <inheritdoc cref="Trace(string)"/>
136+
public static void Trace(LoggerInterpolatedStringHandler message)
137+
{
138+
if (!Current.IsEnabled(LogLevel.Trace))
139+
{
140+
message.Discard();
141+
return;
142+
}
143+
Trace(message.ToStringAndClear());
144+
}
145+
146+
/// <inheritdoc cref="Debug(string)"/>
147+
public static void Debug(LoggerInterpolatedStringHandler message)
148+
{
149+
if (!Current.IsEnabled(LogLevel.Debug))
150+
{
151+
message.Discard();
152+
return;
153+
}
154+
155+
Debug(message.ToStringAndClear());
156+
}
157+
158+
/// <inheritdoc cref="Info(string)"/>
159+
public static void Info(LoggerInterpolatedStringHandler message)
160+
{
161+
if (!Current.IsEnabled(LogLevel.Information))
162+
{
163+
message.Discard();
164+
return;
165+
}
166+
167+
Info(message.ToStringAndClear());
168+
}
169+
170+
/// <inheritdoc cref="Warn(string,Exception)"/>
171+
public static void Warn(LoggerInterpolatedStringHandler message, Exception? exception = null)
172+
{
173+
if (!Current.IsEnabled(LogLevel.Warning))
174+
{
175+
message.Discard();
176+
return;
177+
}
178+
179+
Warn(message.ToStringAndClear(), exception);
180+
}
181+
182+
/// <inheritdoc cref="Error(string,Exception)"/>
183+
public static void Error(LoggerInterpolatedStringHandler message, Exception? exception = null)
184+
{
185+
if (!Current.IsEnabled(LogLevel.Error))
186+
{
187+
message.Discard();
188+
return;
189+
}
190+
191+
Error(message.ToStringAndClear(), exception);
192+
}
193+
194+
/// <inheritdoc cref="Fatal(string,Exception)"/>
195+
public static void Fatal(LoggerInterpolatedStringHandler message, Exception? exception = null)
196+
{
197+
if (!Current.IsEnabled(LogLevel.Critical))
198+
{
199+
message.Discard();
200+
return;
201+
}
202+
203+
Fatal(message.ToStringAndClear(), exception);
204+
}
205+
#endif
206+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#if NET6_0_OR_GREATER
2+
using global::System.Runtime.CompilerServices;
3+
4+
namespace dotnetCampus.Logging;
5+
6+
[InterpolatedStringHandler]
7+
public ref struct LoggerInterpolatedStringHandler
8+
{
9+
public LoggerInterpolatedStringHandler(int literalLength, int formattedCount)
10+
{
11+
_handler = new DefaultInterpolatedStringHandler(literalLength, formattedCount);
12+
}
13+
14+
private readonly DefaultInterpolatedStringHandler _handler;
15+
16+
public void AppendLiteral(string s) => _handler.AppendLiteral(s);
17+
18+
public void AppendFormatted<T>(T value) => _handler.AppendFormatted(value);
19+
20+
public void AppendFormatted<T>(T value, string format) => _handler.AppendFormatted(value, format);
21+
22+
public string ToStringAndClear() => _handler.ToStringAndClear();
23+
24+
public override string ToString() => _handler.ToString();
25+
26+
/// <summary>
27+
/// 废弃掉此字符串
28+
/// </summary>
29+
public void Discard()
30+
{
31+
// 这里的 ToStringAndClear 其实只是取其 Clear 的功能
32+
// 暂时先使用 DefaultInterpolatedStringHandler 提供的能力,后续再考虑是否需要优化
33+
_handler.ToStringAndClear();
34+
}
35+
}
36+
37+
#endif

src/dotnetCampus.Logger/Writers/ConsoleLogger.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,16 @@ internal ConsoleLogger(ICoreLogWriter coreWriter, TagFilterManager? tagManager)
5252
/// </summary>
5353
private TagFilterManager? TagManager { get; }
5454

55+
public bool IsEnabled(LogLevel logLevel)
56+
{
57+
if (logLevel < Level)
58+
{
59+
return false;
60+
}
61+
62+
return true;
63+
}
64+
5565
/// <inheritdoc />
5666
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
5767
{

src/dotnetCampus.Logger/Writers/DebugLogger.g.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ namespace dotnetCampus.Logging.Writers;
1010
/// </summary>
1111
public class DebugLogger(ILogger realLogger) : ILogger
1212
{
13+
public bool IsEnabled(LogLevel logLevel)
14+
{
15+
// 在 debug 模式下,所有日志都是可用的
16+
return true;
17+
}
18+
1319
/// <inheritdoc />
1420
void ILogger.Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
1521
{

src/dotnetCampus.Logger/Writers/MemoryCacheLogger.g.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ internal class MemoryCacheLogger : ILogger
1313

1414
private readonly System.Collections.Concurrent.ConcurrentQueue<CachedLogItem> _queue = [];
1515

16+
public bool IsEnabled(LogLevel logLevel)
17+
{
18+
// 不知道到时候的真的日志是什么,所以只好全记录了
19+
return true;
20+
}
21+
1622
void ILogger.Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
1723
{
1824
if (_realLogger is { } logger)

src/dotnetCampus.Logger/Writers/NullLogger.g.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ namespace dotnetCampus.Logging.Writers;
99
/// </summary>
1010
internal class NullLogger : ILogger
1111
{
12+
public bool IsEnabled(LogLevel logLevel) => false;
13+
1214
/// <inheritdoc />
1315
void ILogger.Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
1416
{

src/dotnetCampus.Logger/Writers/TraceLogger.g.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ namespace dotnetCampus.Logging.Writers;
1010
/// </summary>
1111
public class TraceLogger(ILogger realLogger) : ILogger
1212
{
13+
public bool IsEnabled(LogLevel logLevel) => true;
14+
1315
/// <inheritdoc />
1416
void ILogger.Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
1517
{
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using dotnetCampus.Logger.Generators;
2+
3+
using Microsoft.CodeAnalysis.CSharp;
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Linq;
8+
using System.Text;
9+
using System.Threading.Tasks;
10+
using Microsoft.CodeAnalysis;
11+
12+
namespace dotnetCampus.Logger.Analyzer.Tests.Generators;
13+
14+
[TestClass]
15+
public class LoggerBridgeGeneratorTest
16+
{
17+
[TestMethod]
18+
public void TestGenerateLoggerBridge()
19+
{
20+
var loggerBridgeGenerator = new LoggerBridgeGenerator();
21+
GeneratorDriver driver = CSharpGeneratorDriver.Create(loggerBridgeGenerator);
22+
23+
var compilation = CSharpCompilation.Create
24+
(
25+
"Test",
26+
syntaxTrees:
27+
[
28+
CSharpSyntaxTree.ParseText
29+
(
30+
"""
31+
using System;
32+
using System.Diagnostics;
33+
using System.Threading;
34+
using System.Threading.Tasks;
35+
using dotnetCampus.Logging.Attributes;
36+
using dotnetCampus.Logging.Configurations;
37+
using dotnetCampus.Logging.Writers;
38+
39+
namespace LoggerSample.MainApp;
40+
41+
[ImportLoggerBridge<global::LoggerSample.LoggerIndependentLibrary.Logging.ILoggerBridge>]
42+
[ImportLoggerBridge<global::LoggerSample.LoggerIndependentProject.Logging.ILoggerBridge>]
43+
internal partial class LoggerBridgeLinker;
44+
"""
45+
)
46+
],
47+
references:
48+
new[]
49+
{
50+
MetadataReference.CreateFromFile(typeof(LoggerSample.LoggerIndependentProject.SourceReferenceTarget).Assembly.Location),
51+
MetadataReference.CreateFromFile(typeof(LoggerSample.LoggerIndependentLibrary.SourceReferenceTarget).Assembly.Location)
52+
} // 加上整个 dotnet 的基础库
53+
.Concat(MetadataReferenceProvider.GetDotNetMetadataReferenceList())
54+
);
55+
56+
driver = driver.RunGenerators(compilation);
57+
var result = driver.GetRunResult();
58+
Assert.IsNotNull(result);
59+
}
60+
}

0 commit comments

Comments
 (0)