Skip to content

Release v0.1.0: ship Wolfgang.Extensions.Logging.InMemoryLogger#32

Merged
Chris-Wolfgang merged 52 commits into
mainfrom
develop
Apr 30, 2026
Merged

Release v0.1.0: ship Wolfgang.Extensions.Logging.InMemoryLogger#32
Chris-Wolfgang merged 52 commits into
mainfrom
develop

Conversation

@Chris-Wolfgang

Copy link
Copy Markdown
Owner

Summary

First release of the library. Brings 45 commits of feature work from develop onto main. After this lands, publishing a v0.1.0 tag/release will trigger release.yaml to build, validate, pack, smoke-test, and push the NuGet package.

What's shipping (v0.1.0)

Public API

  • InMemoryLogger — non-generic ILogger that captures entries in a thread-safe in-memory list
  • InMemoryLogger<T> — thin generic wrapper around InMemoryLogger
  • InMemoryLoggerProviderILoggerProvider that creates and caches InMemoryLogger instances per category (ConcurrentDictionary)
  • InMemoryLoggerBuilderExtensions.AddInMemoryLogger(this ILoggingBuilder, InMemoryLoggerProvider) — DI registration

Features

  • Thread-safe entry storage
  • Configurable minimum log level (incl. LogLevel.None correctly disables all)
  • Configurable initial capacity
  • BeginScope with AsyncLocal-tracked active scopes and idempotent Dispose (Interlocked.CompareExchange)
  • Returns entries as IReadOnlyList<LogEntry<object>> for easy assertion

Target frameworks

net462;netstandard2.0;netstandard2.1;net8.0;net10.0

Verified

Test plan

  • CI validate-release job passes on Release config
  • CI pack-and-validate job produces a NuGet package
  • Smoke-test job confirms the package installs and the smoke-test app builds
  • After merge: tag v0.1.0 and publish a GitHub Release to trigger NuGet push

🤖 Generated with Claude Code

Chris-Wolfgang and others added 30 commits March 25, 2026 14:28
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add Setup-BranchRuleset.ps1, Setup-Labels.ps1, Setup-GitHubPages.ps1,
and format.ps1 scripts. These must be run manually after merge.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace feature_request.md with feature_request.yaml for structured
issue forms with validation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…yaml

- Add Fix-BranchRuleset.ps1: inspects, disables, and renames existing
  rulesets so Setup-BranchRuleset.ps1 can recreate them cleanly
- Update Setup-BranchRuleset.ps1 to match current repo-template with
  correct repository name and status check names
- Switch pr.yaml to pull_request_target for secure workflow execution
- Add explicit ref and persist-credentials: false to all checkout steps

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…uccess

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Exclude Claude Code local settings from version control.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…scripts

Add Fix-BranchRuleset.ps1 and update Setup-BranchRuleset.ps1
…-request-template

Update Repo - 007 - Upgrade feature request to GitHub Forms
PR #9 already merged a newer version of this script to develop.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add .gitattributes, .globalconfig, Directory.Build.props, and
BannedSymbols.txt from repo-template to standardize line endings,
analyzer configuration, and banned API enforcement.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add missing documentation infrastructure files for DocFX site generation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add weekly CodeQL scanning from repo-template. Runs on pushes to main,
PRs targeting main, and weekly Sunday schedule. Gracefully skips when
no C# source code is present.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ning' into develop

# Conflicts:
#	.github/workflows/pr.yaml
Chris-Wolfgang and others added 15 commits April 14, 2026 15:28
Source project:
- Fix PackageProjectUrl pointing to wrong repo
- Single-line TargetFrameworks (CI grep compat)
- Add missing TFMs: netstandard2.1 and net10.0
- Clean up ImplicitUsings condition (remove embedded CRLF escapes)
- Add SuppressTfmSupportBuildWarnings for older TFMs
- Fix FullName null safety (fallback to Name)
- Add thread safety via lock on log entry collection
- Fix BeginScope to return no-op disposable instead of null!
- Remove stale NotImplementedException XML doc from IsEnabled
- Fix ambiguous LogLevel cref in XML doc
- Add explicit null-forgiving operators on state boxing
- Change LogEntries to IReadOnlyList with snapshot copy
- Add InternalsVisibleTo for test project

Test project:
- Update xunit to 2.9.3, xunit.runner.visualstudio to 2.8.2
- Update coverlet.collector to 6.0.4, Microsoft.NET.Test.Sdk to 17.12.0
- Add multi-TFM: net462 through net481, net5.0 through net10.0
- Suppress NU1701 for xunit runner TFM compat
- Fix test naming to MethodUnderTest_when_condition_result pattern
- Remove dead commented-out test code
- Add BeginScope test

Solution/docs:
- Delete duplicate Solution.slnx (template leftover)
- Update .slnx references (fix feature_request.md -> .yaml, add new files)
- Replace template README with project-specific content

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- IsEnabled: return false when logLevel is LogLevel.None
- Capacity: acquire lock for thread safety
- PackageReadmeFile: include root README.md via None item for NuGet pack
- Add IsEnabled_when_logLevel_is_None_returns_false test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Source project:
- Fix PackageProjectUrl pointing to wrong repo
- Single-line TargetFrameworks (CI grep compat)
- Add missing TFMs: netstandard2.1 and net10.0
- Clean up ImplicitUsings condition (remove embedded CRLF escapes)
- Add SuppressTfmSupportBuildWarnings for older TFMs
- Fix FullName null safety (fallback to Name)
- Add thread safety via lock on log entry collection
- Fix BeginScope to return no-op disposable instead of null!
- Remove stale NotImplementedException XML doc from IsEnabled
- Fix ambiguous LogLevel cref in XML doc
- Add explicit null-forgiving operators on state boxing
- Change LogEntries to IReadOnlyList with snapshot copy
- Add InternalsVisibleTo for test project

Test project:
- Update xunit to 2.9.3, xunit.runner.visualstudio to 2.8.2
- Update coverlet.collector to 6.0.4, Microsoft.NET.Test.Sdk to 17.12.0
- Add multi-TFM: net462 through net481, net5.0 through net10.0
- Suppress NU1701 for xunit runner TFM compat
- Fix test naming to MethodUnderTest_when_condition_result pattern
- Remove dead commented-out test code
- Add BeginScope test

Solution/docs:
- Delete duplicate Solution.slnx (template leftover)
- Update .slnx references (fix feature_request.md -> .yaml, add new files)
- Replace template README with project-specific content

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- IsEnabled: return false when logLevel is LogLevel.None
- Capacity: acquire lock for thread safety
- PackageReadmeFile: include root README.md via None item for NuGet pack
- Add IsEnabled_when_logLevel_is_None_returns_false test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Feature 1: Non-generic InMemoryLogger
- Takes a category string instead of type parameter
- Same thread-safe implementation as InMemoryLogger<T>
- InMemoryLogger<T> now delegates to InMemoryLogger internally

Feature 2: InMemoryLoggerProvider
- Implements ILoggerProvider for DI integration
- Creates and caches InMemoryLogger instances per category
- Exposes LogEntries (all entries across all loggers) and Loggers dictionary

Feature 3: AddInMemoryLogger extension method
- ILoggingBuilder.AddInMemoryLogger(provider) for DI registration
- Adds Microsoft.Extensions.Logging package reference

Feature 4: Scope tracking
- BeginScope pushes state onto AsyncLocal<ScopeStack>
- Dispose pops the scope (thread-safe via Interlocked)
- Scopes property returns active scopes outermost to innermost

52 tests pass on net462 and net10.0. 0 build warnings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…-infrastructure

# Conflicts:
#	src/Wolfgang.Extensions.Logging.InMemoryLogger/InMemoryLogger.cs
#	src/Wolfgang.Extensions.Logging.InMemoryLogger/Wolfgang.Extensions.Logging.InMemoryLogger.csproj
#	tests/Wolfgang.Extensions.Logging.InMemoryLogger.Tests.Unit/InMemoryLoggerOfTTests.cs
#	tests/Wolfgang.Extensions.Logging.InMemoryLogger.Tests.Unit/Wolfgang.Extensions.Logging.InMemoryLogger.Tests.Unit.csproj
…emblies

- CreateLogger: add null check for categoryName
- ScopeDisposable.Dispose: guard against out-of-order disposal
- LogEntries: fix doc to note ordering is not guaranteed across categories
- Add Microsoft.NETFramework.ReferenceAssemblies for net462 CI builds

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ructure

Add non-generic logger, provider, DI extension, and scope tracking
Brings in: CI workflow upgrades (pr.yaml v3 gated, expanded release.yaml,
DocFX deploy), MIT LICENSE, REPO-INSTRUCTIONS.md, refreshed scripts,
docfx_project structure refresh, and placeholder fills.

Conflict resolution:
- workflows, scripts, BannedSymbols.txt: take main (latest CI infra)
- README.md: keep develop (project-specific content, not scaffolding)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Merge main into develop (template-sync catch-up)
Release builds now run 'dotnet build -c Release' with TreatWarningsAsErrors,
which surfaced existing analyzer findings that Debug builds didn't enforce.

src:
- InMemoryLoggerBuilderExtensions.AddInMemoryLogger: add <exception> XML doc
  for ArgumentNullException (RCS1140)
- InMemoryLoggerProvider.CreateLogger: add <exception> XML doc for
  ArgumentNullException (RCS1140)
- InMemoryLoggerProvider: mark sealed (CA1063, S3881). The class has no
  overridable members and the existing no-op Dispose doesn't justify the
  full Dispose(bool) pattern.

tests:
- InMemoryLogger{,OfT}Tests.Log_when_called_adds_entry_to_LogEntries:
  - Name the 'exception' parameter explicitly (MA0003)
  - Discard unused 'exception' parameter in the formatter delegate
    (RCS1163, S3257)
  - Use indexer on IReadOnlyList instead of First() (CA1826)

Verified locally: Release build 0/0, 52 tests pass on all TFMs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…-errors

Fix Release-build analyzer errors blocking develop -> main release
Brings the Dependabot exemption for the protected-configuration-files guard
in pr.yaml from main onto develop. No source code changes, no conflicts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…lop-pr29

Merge main into develop (PR #29 Dependabot exemption catch-up)
@github-advanced-security

Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

CI's pr.yaml fetches .editorconfig from main before building (the
'protected configuration files' guard). Locally, our .editorconfig sets
several rules to 'suggestion' so they don't fail the build, but on CI
the file appears to be ignored (the fetch step writes UTF-8 with BOM,
which can prevent the analyzer from picking it up). Either way, the
findings are real, so fix them at the source rather than leaning on
.editorconfig overrides.

src:
- InMemoryLogger / InMemoryLogger<T>: suppress MA0049 (type name matches
  containing namespace) on each class with a SuppressMessage attribute and
  justification - the package, namespace, and primary type intentionally
  share a name.
- InMemoryLogger: use System.Threading.Lock on net9+ (MA0158) via
  conditional compilation; keep object-based lock on older TFMs.
- InMemoryLogger.ScopeDisposable.Dispose: merge nested ifs (S1066).
- InMemoryLoggerProvider.LogEntries / Loggers: suppress S2365 (properties
  copying collections) - this is a deliberate test-helper API; cost is
  documented in <remarks>.
- InMemoryLoggerProvider.Loggers: pass StringComparer.Ordinal to the
  Dictionary copy constructor (MA0002), matching the inner
  ConcurrentDictionary.

tests:
- InMemoryLoggerOfTTests.Ctor_when_default_parameters_creates_instance:
  Assert.NotNull(sut) instead of relying on a ReSharper comment to silence
  S1481/S2699.
- InMemoryLoggerProviderTests.Dispose_does_not_throw: capture and assert
  on Record.Exception so the test has a real assertion (S2699).

Verified locally: build clean both with and without .editorconfig present
(simulating CI), 52/52 tests pass on net462, net47, net471, net472, net48,
net481, net6.0, net7.0, net8.0, net9.0, net10.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Chris-Wolfgang and others added 5 commits April 27, 2026 11:57
…zer-errors

Fix CI Release-build analyzer errors
- actions/download-artifact: v4 -> v8.0.1
- softprops/action-gh-release: v2.5.0 -> v3.0.0 (SHA b4309332)
- Add 3.1.x to dotnet-version in all 3 setup-dotnet blocks

Bundles two related release-workflow fixes (Node 24 mirrors ETL-Test-Kit#54;
3.1 mirrors ETL-Json#54). Test projects target netcoreapp3.1 and need
the 3.1 SDK to restore/test in release.yaml.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…add-netcore31

Upgrade release workflow actions to Node 24 and add .NET Core 3.1
@Chris-Wolfgang Chris-Wolfgang merged commit 5ed2844 into main Apr 30, 2026
8 checks passed
@Chris-Wolfgang Chris-Wolfgang deleted the develop branch April 30, 2026 02:11
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.

2 participants