Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
Comment thread
adegeo marked this conversation as resolved.

// 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);
}
// </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>
Loading
Loading