-
Notifications
You must be signed in to change notification settings - Fork 6.1k
Fix redacting log article: pushed code out to snippets and added missing classes #55006
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a0b6fa1
9429c63
27f0d50
4c88c99
fd8322e
4dfef52
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| using Microsoft.Extensions.Logging; | ||
|
|
||
| namespace BasicUsage.Dynamic; | ||
|
|
||
| // <DynamicLogLevel> | ||
| public static partial class Log | ||
| { | ||
| [LoggerMessage( | ||
| EventId = 0, | ||
| Message = "Could not open socket to `{HostName}`")] | ||
| public static partial void CouldNotOpenSocket( | ||
| ILogger logger, | ||
| LogLevel level, | ||
| string hostName); | ||
| } | ||
| // </DynamicLogLevel> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| using Microsoft.Extensions.Logging; | ||
|
|
||
| namespace BasicUsage.Extension; | ||
|
|
||
| // <ExtensionLogMethod> | ||
| public static partial class Log | ||
| { | ||
| [LoggerMessage( | ||
| EventId = 0, | ||
| Level = LogLevel.Critical, | ||
| Message = "Could not open socket to `{HostName}`")] | ||
| public static partial void CouldNotOpenSocket( | ||
| this ILogger logger, string hostName); | ||
| } | ||
| // </ExtensionLogMethod> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| using Microsoft.Extensions.Logging; | ||
|
|
||
| namespace BasicUsage.InstanceField; | ||
|
|
||
| // <InstanceLogWithField> | ||
| public partial class InstanceLoggingExample | ||
| { | ||
| private readonly ILogger _logger; | ||
|
|
||
| public InstanceLoggingExample(ILogger logger) | ||
| { | ||
| _logger = logger; | ||
| } | ||
|
|
||
| [LoggerMessage( | ||
| EventId = 0, | ||
| Level = LogLevel.Critical, | ||
| Message = "Could not open socket to `{HostName}`")] | ||
| public partial void CouldNotOpenSocket(string hostName); | ||
| } | ||
| // </InstanceLogWithField> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| using Microsoft.Extensions.Logging; | ||
|
|
||
| namespace BasicUsage.PrimaryConstructor; | ||
|
|
||
| // <InstanceLogWithPrimaryCtor> | ||
| public partial class InstanceLoggingExample(ILogger logger) | ||
| { | ||
| [LoggerMessage( | ||
| EventId = 0, | ||
| Level = LogLevel.Critical, | ||
| Message = "Could not open socket to `{HostName}`")] | ||
| public partial void CouldNotOpenSocket(string hostName); | ||
| } | ||
| // </InstanceLogWithPrimaryCtor> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| using Microsoft.Extensions.Logging; | ||
|
|
||
| namespace BasicUsage.Static; | ||
|
|
||
| // <StaticLogMethod> | ||
| public static partial class Log | ||
| { | ||
| [LoggerMessage( | ||
| EventId = 0, | ||
| Level = LogLevel.Critical, | ||
| Message = "Could not open socket to `{HostName}`")] | ||
| public static partial void CouldNotOpenSocket( | ||
| ILogger logger, string hostName); | ||
| } | ||
| // </StaticLogMethod> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| using Microsoft.Extensions.Logging; | ||
|
|
||
| namespace LogMethodAnatomy; | ||
|
|
||
| // <CaseInsensitiveNames> | ||
| public partial class LoggingExample | ||
| { | ||
| private readonly ILogger _logger; | ||
|
|
||
| public LoggingExample(ILogger logger) | ||
| { | ||
| _logger = logger; | ||
| } | ||
|
|
||
| [LoggerMessage( | ||
| EventId = 10, | ||
| Level = LogLevel.Information, | ||
| Message = "Welcome to {City} {Province}!")] | ||
| public partial void LogMethodSupportsPascalCasingOfNames( | ||
| string city, string province); | ||
|
|
||
| public void TestLogging() | ||
| { | ||
| LogMethodSupportsPascalCasingOfNames("Vancouver", "BC"); | ||
| } | ||
| } | ||
| // </CaseInsensitiveNames> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| using Microsoft.Extensions.Logging; | ||
|
|
||
| namespace LogMethodAnatomy; | ||
|
|
||
| public static partial class IndeterminateOrderLog | ||
| { | ||
| // <IndeterminateParameterOrder> | ||
| [LoggerMessage( | ||
| EventId = 110, | ||
| Level = LogLevel.Debug, | ||
| Message = "M1 {Ex3} {Ex2}")] | ||
| static partial void LogMethod( | ||
| Exception ex, | ||
| Exception ex2, | ||
| Exception ex3, | ||
| ILogger logger); | ||
| // </IndeterminateParameterOrder> | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| using Microsoft.Extensions.Logging; | ||
|
|
||
| namespace LogMethodAnatomy; | ||
|
|
||
| public static partial class LogMethods | ||
| { | ||
| // <ValidLogMethod> | ||
| // This is a valid attribute usage | ||
| [LoggerMessage( | ||
| EventId = 110, Level = LogLevel.Debug, Message = "M1 {Ex3} {Ex2}")] | ||
| public static partial void ValidLogMethod( | ||
| ILogger logger, | ||
| Exception ex, | ||
| Exception ex2, | ||
| Exception ex3); | ||
| // </ValidLogMethod> | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| using Microsoft.Extensions.Logging; | ||
|
|
||
| namespace MoreLoggingExamples; | ||
|
|
||
| // <MoreLoggingExamples> | ||
| public partial class LoggingSample | ||
| { | ||
| private readonly ILogger _logger; | ||
|
|
||
| public LoggingSample(ILogger logger) | ||
| { | ||
| _logger = logger; | ||
| } | ||
|
|
||
| [LoggerMessage( | ||
| EventId = 20, | ||
| Level = LogLevel.Critical, | ||
| Message = "Value is {Value:E}")] | ||
| public static partial void UsingFormatSpecifier( | ||
| ILogger logger, double value); | ||
|
|
||
| [LoggerMessage( | ||
| EventId = 9, | ||
| Level = LogLevel.Trace, | ||
| Message = "Fixed message", | ||
| EventName = "CustomEventName")] | ||
| public partial void LogWithCustomEventName(); | ||
|
|
||
| [LoggerMessage( | ||
| EventId = 10, | ||
| Message = "Welcome to {City} {Province}!")] | ||
| public partial void LogWithDynamicLogLevel( | ||
| string city, LogLevel level, string province); | ||
|
|
||
| public void TestLogging() | ||
| { | ||
| LogWithCustomEventName(); | ||
|
|
||
| LogWithDynamicLogLevel("Vancouver", LogLevel.Warning, "BC"); | ||
| LogWithDynamicLogLevel("Vancouver", LogLevel.Information, "BC"); | ||
|
|
||
| UsingFormatSpecifier(_logger, 12345.6789); | ||
| } | ||
| } | ||
| // </MoreLoggingExamples> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Console.WriteLine("Hello, World!"); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| using Microsoft.Extensions.Compliance.Classification; | ||
| using Microsoft.Extensions.Compliance.Redaction; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
| using Microsoft.Extensions.Logging; | ||
|
|
||
| namespace RedactingSensitiveInformation; | ||
|
|
||
| // MyTaxonomyClassifications.Private serves two roles: | ||
| // - As a DataClassification value passed to SetRedactor(). | ||
| // - As [MyTaxonomyClassifications.Private] on logging parameters, resolved via the | ||
| // nested PrivateAttribute class (C# drops the "Attribute" suffix in attribute syntax). | ||
| public static class MyTaxonomyClassifications | ||
| { | ||
| private static string Name => "MyTaxonomy"; | ||
|
|
||
| public static DataClassification Private { get; } = new(Name, nameof(Private)); | ||
|
|
||
| // Accessible as [MyTaxonomyClassifications.Private] due to C# attribute name convention. | ||
| public sealed class PrivateAttribute : DataClassificationAttribute | ||
| { | ||
| public PrivateAttribute() : base(MyTaxonomyClassifications.Private) { } | ||
| } | ||
| } | ||
|
|
||
| public sealed class StarRedactor : Redactor | ||
| { | ||
| private const string Stars = "*****"; | ||
|
|
||
| public override int GetRedactedLength(ReadOnlySpan<char> input) => Stars.Length; | ||
|
|
||
| public override int Redact(ReadOnlySpan<char> source, Span<char> destination) | ||
| { | ||
| Stars.CopyTo(destination); | ||
| return Stars.Length; | ||
| } | ||
| } | ||
|
|
||
| // <LogPrivateInformation> | ||
| public static partial class LogRedactionExample | ||
| { | ||
| [LoggerMessage(0, LogLevel.Information, "User SSN: {SSN}")] | ||
| public static partial void LogPrivateInformation( | ||
| this ILogger logger, | ||
| [MyTaxonomyClassifications.Private] string SSN); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is incorrect as reported in #54570
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @laicasaane this does work, it's resolving to PrivateAttribute, even though you type in Private. We have a compiler running as an action that compiles the code snippets and blocks the PR if it won't compile. I think the reason why it didn't work for you was because you were working with an incomplete snippet and had to cobble it together and you were just missing the actual attribute definition. |
||
| } | ||
| // </LogPrivateInformation> | ||
|
|
||
| public static class RedactionSetupExample | ||
| { | ||
| public static void SetupServices() | ||
| { | ||
| // <RedactionSetup> | ||
| var services = new ServiceCollection(); | ||
| services.AddLogging(builder => | ||
| { | ||
| // Enable redaction. | ||
| builder.EnableRedaction(); | ||
| }); | ||
|
|
||
| services.AddRedaction(builder => | ||
| { | ||
| // Configure redactors for your data classifications. | ||
| builder.SetRedactor<StarRedactor>(MyTaxonomyClassifications.Private); | ||
| }); | ||
| // </RedactionSetup> | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| using Microsoft.Extensions.Compliance.Classification; | ||
| using Microsoft.Extensions.Compliance.Redaction; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
| using Microsoft.Extensions.Logging; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <TargetFramework>net10.0</TargetFramework> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| <Nullable>enable</Nullable> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup> | ||
| <PackageReference Include="Microsoft.Extensions.Compliance.Redaction" Version="10.8.0" /> | ||
| <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.10" /> | ||
| <PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.10" /> | ||
| <PackageReference Include="Microsoft.Extensions.Telemetry" Version="10.8.0" /> | ||
| </ItemGroup> | ||
|
|
||
| </Project> |
Uh oh!
There was an error while loading. Please reload this page.