getsentry / getsentry/sentry-dotnet

Sentry.Log4Net silently drops log property attributes on log4net 3.x

Open Beginner friendly
#5,557 1 comment 0 reactions 0 assignees View on GitHub
.NET Bug log4net Logs
Dominant language
C#
Stars
770
Forks
248
Avg merge
2d 22h
Merged PRs (30d)
51

Description

## Description

`Sentry.Log4Net` is not compatible with **log4net 3.x**: every log4net event property is silently dropped from structured logs, so no `property.*` attributes are ever attached to a `SentryLog`. There is no exception and no warning — the attributes simply aren't there.

This affects the shipped package, not just the test suite. `Sentry.Log4Net` compiles against log4net 2.0.12, and log4net 3.x loads happily against that assembly, so any user on log4net 3.x with `EnableLogs` loses all their event properties today.

## Root cause

[`SentryAppender.Structured.cs:43-45`](https://github.com/getsentry/sentry-dotnet/blob/main/src/Sentry.Log4Net/SentryAppender.Structured.cs#L43-L45) enumerates the properties dictionary and pattern-matches each element as a `DictionaryEntry`:

```csharp
foreach (var property in properties)
{
if (property is DictionaryEntry { Key: string key, Value: { } value })
```

That shape changed between log4net majors. In 2.x, `log4net.Util.PropertiesDictionary` implements only the **non-generic** `IDictionary`, so `IEnumerable.GetEnumerator()` yields boxed `DictionaryEntry`. In 3.x it *additionally* implements `IDictionary`, and the non-generic enumerator now yields boxed `KeyValuePair`. Confirmed by reflecting over both packages:

```
log4net 2.0.12 PropertiesDictionary : ISerializable, IDictionary, ICollection, IEnumerable
IEnumerable.GetEnumerator() element -> System.Collections.DictionaryEntry

log4net 3.4.0 PropertiesDictionary : IEmptyInterface, IDictionary, ICollection, IEnumerable,
IDictionary, ICollection, IEnumerable
IEnumerable.GetEnumerator() element -> System.Collections.Generic.KeyValuePair
```

Because the already-compiled appender walks the non-generic enumerator, the `is DictionaryEntry` test never matches under 3.x, the loop body never runs, and no attribute is set.

Worth noting for whoever picks this up: **bumping the `PackageReference` alone doesn't fix it** — it converts the silent failure into a compile error, because `foreach (var property in properties)` then binds to the generic `IEnumerable>`:

```
error CS8121: An expression of type 'KeyValuePair' cannot be handled by a pattern of type 'DictionaryEntry'
```

The `SentryEvent` path is unaffected: [`GetLoggingEventProperties`](https://github.com/getsentry/sentry-dotnet/blob/main/src/Sentry.Log4Net/SentryAppender.cs#L186) reads via `GetKeys()` + the indexer, which behave identically on both majors.

## Reproduction

In a checkout of `main`, change `test/Sentry.Log4Net.Tests/Sentry.Log4Net.Tests.csproj` from `` to `Version="3.4.0"`, then:

```
dotnet test test/Sentry.Log4Net.Tests
```

Three tests fail (55 pass), all in the structured-logging path:

- `SentryAppenderTests.DoAppend_StructuredLogging_Properties` — *"Expected log.Attributes to contain a single item matching `attribute.Key.StartsWith("property.")`, but no such item was found."*
- `SentryAppenderTests.DoAppend_StructuredLogging_LogEvent(withActiveSpan: False)`
- `SentryAppenderTests.DoAppend_StructuredLogging_LogEvent(withActiveSpan: True)` — both fail asserting `property.Text-Property` via `test/Sentry.Testing/SentryAttributesExtensions.cs:7`.

## Suggested fix

Read the dictionary through `GetKeys()` + the indexer, the way the sibling `GetLoggingEventProperties` already does. That API is stable across both majors, so the appender stays version-agnostic and keeps working whether the consumer resolves log4net 2.x or 3.x.

Two follow-ups worth deciding at the same time:

- Add coverage for log4net 3.x (a test matrix over both majors, or a second test project) so this can't silently regress again.
- Decide whether `src/Sentry.Log4Net`'s own `PackageReference` floor should move off 2.0.12 — separate from the fix above, since the fix should make the appender work on both without raising the floor.

*Found while investigating log4net 3.x support; root cause verified locally against log4net 2.0.12 and 3.4.0 at `0004ef86`.*

Contributor guide

Open the contributing guide

Research direction

Start in src/Sentry.Log4Net/SentryAppender.Structured.cs at the property enumeration, then compare it with GetLoggingEventProperties in src/Sentry.Log4Net/SentryAppender.cs. Reproduce with log4net 3.4.0 using dotnet test test/Sentry.Log4Net.Tests, and check the three named structured-logging tests. Done means property.* attributes are preserved for log4net 3.x without breaking the existing 2.x behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
observability
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
88/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.