getsentry / getsentry/sentry-dotnet
Sentry.Log4Net silently drops log property attributes on log4net 3.x
- 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
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