-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Sanitize control/format characters in console logger output across all formatters #128741
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
Merged
rosebyte
merged 29 commits into
main
from
copilot/sanitize-console-logger-control-characters
Jun 26, 2026
Merged
Changes from 5 commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
9933fd5
Initial plan
Copilot 85172bc
Sanitize control characters in console formatter output
Copilot 8e2eaec
fix the pr
0268f1d
use ValueStringBuilder
f112ef0
implement PR feedback
fa0ca04
Merge branch 'main' into copilot/sanitize-console-logger-control-char…
rosebyte 8b81df2
clean up
4c8e0fa
implement PR comments
750109f
Potential fix for pull request finding
rosebyte d7946d5
Merge branch 'main' into copilot/sanitize-console-logger-control-char…
rosebyte 2381a01
Update src/libraries/Microsoft.Extensions.Logging.Console/src/Console…
rosebyte 2970f91
vectorize the search
c63a776
use AppendSpan
6f749fd
implement PR comment
7651455
Merge branch 'main' into copilot/sanitize-console-logger-control-char…
rosebyte 3820270
Merge branch 'main' into copilot/sanitize-console-logger-control-char…
rosebyte db6837a
narrow to systemd and OpenSSH set
558ce0d
Potential fix for pull request finding
rosebyte 1c03a2c
Potential fix for pull request finding
rosebyte 447b406
Merge branch 'main' into copilot/sanitize-console-logger-control-char…
rosebyte 77853c5
Potential fix for pull request finding
rosebyte ac2a04e
Potential fix for pull request finding
rosebyte f7c0ea3
Merge branch 'main' into copilot/sanitize-console-logger-control-char…
rosebyte 44f743e
Merge branch 'main' into copilot/sanitize-console-logger-control-char…
rosebyte e8850f6
Merge branch 'main' into copilot/sanitize-console-logger-control-char…
rosebyte 51a094e
Update src/libraries/Microsoft.Extensions.Logging.Console/src/Console…
rosebyte fbc5149
Merge branch 'main' into copilot/sanitize-console-logger-control-char…
rosebyte 4feee1d
Merge branch 'main' into copilot/sanitize-console-logger-control-char…
rosebyte acc7d84
Merge branch 'main' into copilot/sanitize-console-logger-control-char…
rosebyte File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
102 changes: 102 additions & 0 deletions
102
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleControlCharacterSanitizer.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System; | ||
| using System.Text; | ||
|
|
||
| namespace Microsoft.Extensions.Logging.Console | ||
| { | ||
| internal static class ConsoleControlCharacterSanitizer | ||
| { | ||
| public static string? Sanitize(string? value) | ||
| { | ||
| if (string.IsNullOrEmpty(value)) | ||
| { | ||
| return value; | ||
| } | ||
|
|
||
| int firstEscapedCharacterIndex = GetFirstEscapedCharacterIndex(value); | ||
| if (firstEscapedCharacterIndex < 0) | ||
| { | ||
| return value; | ||
| } | ||
|
|
||
| var sanitized = new ValueStringBuilder(stackalloc char[256]); | ||
| sanitized.Append(value.AsSpan(0, firstEscapedCharacterIndex)); | ||
|
|
||
| for (int i = firstEscapedCharacterIndex; i < value.Length; i++) | ||
| { | ||
| char current = value[i]; | ||
| if (ShouldEscape(current)) | ||
| { | ||
| sanitized.Append('\\'); | ||
| sanitized.Append('u'); | ||
| int codePoint = current; | ||
| Span<char> hex = sanitized.AppendSpan(4); | ||
| hex[0] = ToHexChar(codePoint >> 12); | ||
| hex[1] = ToHexChar((codePoint >> 8) & 0xF); | ||
| hex[2] = ToHexChar((codePoint >> 4) & 0xF); | ||
| hex[3] = ToHexChar(codePoint & 0xF); | ||
|
svick marked this conversation as resolved.
Outdated
rosebyte marked this conversation as resolved.
Outdated
|
||
| } | ||
| else | ||
| { | ||
| sanitized.Append(current); | ||
| } | ||
| } | ||
|
|
||
| return sanitized.ToString(); | ||
| } | ||
|
|
||
| private static char ToHexChar(int value) => | ||
| (char)(value < 10 ? '0' + value : 'A' + value - 10); | ||
|
|
||
| private static int GetFirstEscapedCharacterIndex(string value) | ||
| { | ||
| for (int i = 0; i < value.Length; i++) | ||
| { | ||
| if (ShouldEscape(value[i])) | ||
| { | ||
| return i; | ||
| } | ||
| } | ||
|
|
||
| return -1; | ||
| } | ||
|
|
||
| private static bool ShouldEscape(char c) | ||
| { | ||
| return c switch | ||
| { | ||
| '\u0000' => true, // NUL - can truncate log lines in syslog/journald pipelines | ||
|
rosebyte marked this conversation as resolved.
Outdated
|
||
| '\u0007' => true, // BEL - terminal bell | ||
| '\u0008' => true, // BS - backspace | ||
| '\u000E' => true, // SO - shift out (invokes alternate character set) | ||
| '\u000F' => true, // SI - shift in | ||
| '\u001B' => true, // ESC - ANSI escape sequences | ||
| '\u007F' => true, // DEL - delete | ||
| '\u0090' => true, // DCS - device control string (8-bit) | ||
| '\u009B' => true, // CSI - control sequence introducer (8-bit) | ||
| '\u009C' => true, // ST - string terminator (8-bit) | ||
| '\u009D' => true, // OSC - operating system command (8-bit) | ||
| '\u0098' => true, // SOS - start of string (8-bit) | ||
| '\u009E' => true, // PM - privacy message (8-bit) | ||
| '\u009F' => true, // APC - application program command (8-bit) | ||
| '\u200B' => true, // zero-width space | ||
| '\u200C' => true, // zero-width non-joiner | ||
| '\u200D' => true, // zero-width joiner | ||
| '\u200E' => true, // left-to-right mark | ||
| '\u200F' => true, // right-to-left mark | ||
| '\u202A' => true, // left-to-right embedding | ||
| '\u202B' => true, // right-to-left embedding | ||
| '\u202C' => true, // pop directional formatting | ||
| '\u202D' => true, // left-to-right override | ||
| '\u202E' => true, // right-to-left override | ||
| '\u2066' => true, // left-to-right isolate | ||
| '\u2067' => true, // right-to-left isolate | ||
| '\u2068' => true, // first strong isolate | ||
| '\u2069' => true, // pop directional isolate | ||
| _ => false, | ||
|
rosebyte marked this conversation as resolved.
Outdated
rosebyte marked this conversation as resolved.
Outdated
|
||
| }; | ||
|
rosebyte marked this conversation as resolved.
Outdated
|
||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.