Skip to content

feat: log4net appender no longer initializes the SDK - #5592

Draft
jamescrosswell wants to merge 9 commits into
feat/no-init-from-logging-nlog-5245from
feat/no-init-from-logging-log4net-5245
Draft

jamescrosswell wants to merge 9 commits into
feat/no-init-from-logging-nlog-5245from
feat/no-init-from-logging-log4net-5245

Conversation

@jamescrosswell

@jamescrosswell jamescrosswell commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

The log4net portion of #5245, stacked on #5585 (NLog) and following the same design. The Sentry appender for log4net now only sends log events to Sentry; Sentry has to be initialized separately via SentrySdk.Init, UseSentry, etc.

Part of #5245

Breaking changes

  • The appender no longer initializes the SDK on the first append. SentryAppender.Dsn remains as a tombstone — [Obsolete(..., error: true)] with a setter that throws NotSupportedException carrying migration guidance, matching feat(serilog): configuring a DSN on the sink now fails with a migration error #5611 (Serilog) and feat: NLog target no longer initializes the SDK #5585 (NLog).
  • SentryAppender.Environment is removed. Events and structured logs take the environment from the options used to initialize Sentry.
  • SentryAppender no longer overrides OnClose. It only existed to dispose the SDK the appender had initialized, so closing the log4net repository no longer flushes Sentry; disposing the handle from SentrySdk.Init does.

Before:

<appender name="SentryAppender" type="Sentry.Log4Net.SentryAppender, Sentry.Log4Net">
  <Dsn value="https://key@sentry.io/1" />
  <Environment value="dev" />
</appender>

After:

using var _ = SentrySdk.Init(o =>
{
    o.Dsn = "https://key@sentry.io/1";
    o.Environment = "dev";
});
<appender name="SentryAppender" type="Sentry.Log4Net.SentryAppender, Sentry.Log4Net" />

The tombstone behaves differently here than in Serilog and NLog

log4net cannot be made to fail configuration loading. XmlHierarchyConfigurator.SetParameter catches exceptions thrown while setting a parameter, so the throwing setter does not propagate: the config still loads and the appender is still attached. Verified, rather than assumed:

scenario before this PR after
app.config with <Dsn value="…" /> log4net:ERROR … Cannot find Property [Dsn] to set object on [Sentry.Log4Net.SentryAppender], config loads, appender attached log4net:ERROR Failed to set parameter [Dsn] … NotSupportedException: <migration message>, config loads, appender attached
appender.Dsn = "…" in code CS1061: SentryAppender does not contain a definition for 'Dsn' CS0619 carrying the migration message
app.config without <Dsn> works works, unchanged

So the gain is a better message on the XML path and a compile error carrying migration guidance on the code path — not the hard startup failure Serilog and NLog get. Both messages go to Console.Error via log4net's internal logging unless quiet mode is on.

If a hard failure matters more than keeping the appender working, the alternative is to record the attempt in the setter and throw from ActivateOptions. ParseAppender catches that too, but it drops the appender entirely, so nothing reaches Sentry at all — worse for anyone who initializes correctly but leaves a stale <Dsn> behind. I went with the setter; say the word if you'd rather have the louder one.

Notes for review

  • On a disabled hub the appender now returns immediately. That's the same path the old code took when no Dsn was set.
  • The unit test fixture now uses an enabled hub. Previously the substitute hub reported IsEnabled == false, and events were only captured because the mocked init had run.
  • Environment gets no tombstone, following feat: NLog target no longer initializes the SDK #5585, which tombstoned only the SDK-init settings. It's a one-line addition if you'd rather it carried a message too — log4net reports the removal either way, just less usefully.
  • Like NLog, log4net needs no UseLog4Net(): identity and properties are applied by the appender to the events and logs it creates.
  • ApiApprovalTests.Run.Net4_8 and DotNet10_0 are copies of the regenerated DotNet11_0 snapshot, which all three matched byte-for-byte beforehand. Net4_8 can't regenerate on macOS, and DotNet10_0 isn't run at all since the test project only targets the latest TFM.

🤖 Generated with Claude Code

The Sentry appender for log4net now only sends log events to Sentry.
Sentry must be initialized separately (SentrySdk.Init, UseSentry, etc).

- Remove SentryAppender.Dsn and the lazy SDK initialization on first append
- Remove SentryAppender.Environment; events take the environment from the
  options used to initialize Sentry
- Remove the OnClose override, which only disposed the SDK the appender
  had initialized

Part of #5245

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jamescrosswell jamescrosswell added Breaking Change Binary/Source/Behavioral Breaking Changes. log4net labels Sep 17, 2026
@codecov

codecov Bot commented Sep 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.88889% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 74.60%. Comparing base (a8a1ea9) to head (ba78b29).

Files with missing lines Patch % Lines
src/Sentry.Log4Net/SentryAppender.cs 87.50% 1 Missing ⚠️
Additional details and impacted files
@@                           Coverage Diff                           @@
##           feat/no-init-from-logging-nlog-5245    #5592      +/-   ##
=======================================================================
- Coverage                                74.64%   74.60%   -0.04%     
=======================================================================
  Files                                      514      514              
  Lines                                    18760    18732      -28     
  Branches                                  3647     3640       -7     
=======================================================================
- Hits                                     14003    13975      -28     
  Misses                                    3889     3889              
  Partials                                   868      868              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread samples/Sentry.Samples.Log4Net/app.config Outdated
Comment thread samples/Sentry.Samples.Log4Net/Program.cs Outdated
// Honor the appender-level settings, overriding the scope/options defaults, to match the SentryEvent path.
if (!string.IsNullOrWhiteSpace(environment))
{
log.SetAttribute("sentry.environment", environment!);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This gets handled here now (just a couple of lines up):

log.SetDefaultAttributes(options, scope, Sdk);

jamescrosswell and others added 8 commits September 22, 2026 18:09
Sdk.Name should identify the integration that initialised the hub, which after
this change can no longer be a logging integration. The appender identifies
itself through the log origin (auto.log.log4net) instead.
See #5497.

Events are no longer stamped with sentry.dotnet.log4net, and structured logs no
longer carry it as sentry.sdk.name; both now report the SDK that initialised
Sentry.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…245' into feat/no-init-from-logging-log4net-5245
…ion error

Brings back SentryAppender.Dsn as a tombstone: [Obsolete(error: true)] with
a setter that throws NotSupportedException carrying migration guidance, so
code callers get a compile error and XML configs report the message instead
of log4net's "Cannot find Property [Dsn]".

Unlike Serilog and NLog, this cannot fail configuration loading: log4net
catches exceptions thrown while setting a parameter, so the appender is
still attached and the message surfaces through log4net's internal logging.

Part of #5245

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…245' into feat/no-init-from-logging-log4net-5245
Co-authored-by: James Crosswell <jamescrosswell@users.noreply.github.com>
…245' into feat/no-init-from-logging-log4net-5245
…t-5245' into feat/no-init-from-logging-log4net-5245

This branch has not been deployed

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

Labels

Breaking Change Binary/Source/Behavioral Breaking Changes. log4net

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant