Skip to content

Add optional logging scope support#86

Open
Arithmomaniac wants to merge 2 commits into
nreco:masterfrom
Arithmomaniac:arithmomaniac-support-logging-scopes
Open

Add optional logging scope support#86
Arithmomaniac wants to merge 2 commits into
nreco:masterfrom
Arithmomaniac:arithmomaniac-support-logging-scopes

Conversation

@Arithmomaniac

@Arithmomaniac Arithmomaniac commented Jul 24, 2026

Copy link
Copy Markdown

This pull request was created by GitHub Copilot, which wrote the code with human supervision

This adds opt-in logging scope support as requested in #77. Setting IncludeScopes adds active scopes as a tab-separated field before the message, formatted in ConsoleLogger-style outer-to-inner order: => Outer => Inner. Scopes are disabled by default, and entries without active scopes retain the existing output. Scope context is also included on exception-only entries.

The main technical constraint is that IExternalScopeProvider exposes scopes only through its callback-based ForEachScope API, while the existing low-allocation ValueStringBuilder is a ref struct and cannot be captured or passed as callback state. Scopes are therefore collected into a reusable list and then appended directly to the final buffer, which also keeps the exact output length known up front so the buffer is still rented once. The list holds one entry per active scope, so its capacity stays as small as the scope nesting. It is checked out while in use so logging from a scope's ToString() cannot corrupt another entry being formatted on the same thread.

FileLoggerProvider implements ISupportExternalScope, allowing LoggerFactory to supply the shared provider that tracks BeginScope() state across nesting, disposal, and asynchronous flow. FileLogger.BeginScope() delegates to it for direct logger usage. Custom FormatLogEntry delegates continue receiving the unchanged LogMessage and do not include scopes automatically.

Documentation and tests cover configuration, scope ordering and lifetime, exceptions, custom formatting, long and null scopes, and logging during scope formatting. The library, tests, and examples build successfully, and all 47 tests pass on net481, net8.0, and net10.0.

Fixes #77

Arithmomaniac and others added 2 commits July 24, 2026 15:15
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f918226d-1eb0-4d36-9d9a-397347a05d4a
Avoids the StringBuilder-to-ValueStringBuilder copy and its netstandard2.0 fallback.
The list holds one entry per active scope, so it needs no capacity trimming.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f918226d-1eb0-4d36-9d9a-397347a05d4a
@VitaliyMF

Copy link
Copy Markdown
Contributor

@Arithmomaniac looks good!
I have only one question: in FileLogger this code is used when custom log entry formatter is specified (FileLoggerOptions.FormatLogEntry):

			if (LoggerPrv.FormatLogEntry != null) {
				LoggerPrv.WriteEntry(LoggerPrv.FormatLogEntry(
					new LogMessage(logName, logLevel, eventId, message, exception)));
			}

Do I understand correctly that the new FileLoggerOptions.IncludeScopes option enables scopes only when the default formatter is used (LowAllocLogEntryFormat)? Maybe IExternalScopeProvider should also be included in LogMessage to allow custom formatters to handle scopes as well?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for scopes

2 participants