Skip to content

Commit 94269d4

Browse files
jschick04NikTilton
authored andcommitted
Added additional debug logging for event debugging
1 parent 9f9944d commit 94269d4

File tree

6 files changed

+209
-148
lines changed

6 files changed

+209
-148
lines changed

src/EventLogExpert.Eventing.Tests/EventResolvers/EventResolverBaseTests.cs

Lines changed: 43 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -170,45 +170,6 @@ public void ResolveEvent_WithFormattingCharacters_ShouldCleanupDescription()
170170
Assert.Contains("\t", displayEvent.Description);
171171
}
172172

173-
[Fact]
174-
public void ResolveEvent_WithTrailingPercentN_ShouldNotThrowIndexOutOfRange()
175-
{
176-
// Arrange
177-
var providerDetails = new ProviderDetails
178-
{
179-
ProviderName = Constants.TestProviderName,
180-
Events = [],
181-
Messages =
182-
[
183-
new MessageModel
184-
{
185-
ProviderName = Constants.TestProviderName,
186-
ShortId = 1001,
187-
Text = "Message ends with newline%n"
188-
}
189-
],
190-
Parameters = [],
191-
Keywords = new Dictionary<long, string>(),
192-
Tasks = new Dictionary<int, string>()
193-
};
194-
195-
var resolver = new TestEventResolver([providerDetails]);
196-
197-
var eventRecord = new EventRecord
198-
{
199-
ProviderName = Constants.TestProviderName,
200-
Id = 1001,
201-
Properties = []
202-
};
203-
204-
// Act - should not throw IndexOutOfRangeException
205-
var displayEvent = resolver.ResolveEvent(eventRecord);
206-
207-
// Assert
208-
Assert.NotNull(displayEvent);
209-
Assert.EndsWith("\r\n", displayEvent.Description);
210-
}
211-
212173
[Fact]
213174
public void ResolveEvent_WithHexPropertyType_ShouldFormatAsHex()
214175
{
@@ -735,6 +696,45 @@ public void ResolveEvent_WithTaskFallback_ShouldUseTaskFromMessages()
735696
Assert.Equal("MessageDerivedTask", displayEvent.TaskCategory);
736697
}
737698

699+
[Fact]
700+
public void ResolveEvent_WithTrailingPercentN_ShouldNotThrowIndexOutOfRange()
701+
{
702+
// Arrange
703+
var providerDetails = new ProviderDetails
704+
{
705+
ProviderName = Constants.TestProviderName,
706+
Events = [],
707+
Messages =
708+
[
709+
new MessageModel
710+
{
711+
ProviderName = Constants.TestProviderName,
712+
ShortId = 1001,
713+
Text = "Message ends with newline%n"
714+
}
715+
],
716+
Parameters = [],
717+
Keywords = new Dictionary<long, string>(),
718+
Tasks = new Dictionary<int, string>()
719+
};
720+
721+
var resolver = new TestEventResolver([providerDetails]);
722+
723+
var eventRecord = new EventRecord
724+
{
725+
ProviderName = Constants.TestProviderName,
726+
Id = 1001,
727+
Properties = []
728+
};
729+
730+
// Act - should not throw IndexOutOfRangeException
731+
var displayEvent = resolver.ResolveEvent(eventRecord);
732+
733+
// Assert
734+
Assert.NotNull(displayEvent);
735+
Assert.EndsWith("\r\n", displayEvent.Description);
736+
}
737+
738738
[Fact]
739739
public void ResolveEvent_WithXmlProperty_ShouldPreserveXml()
740740
{
@@ -790,19 +790,19 @@ public TestEventResolver(
790790
ITraceLogger? logger = null)
791791
: base(cache, logger)
792792
{
793-
providerDetailsList.ForEach(p => providerDetails.TryAdd(p.ProviderName, p));
793+
providerDetailsList.ForEach(p => ProviderDetails.TryAdd(p.ProviderName, p));
794794
}
795795

796-
public ConcurrentDictionary<string, ProviderDetails?> GetProviderDetails() => providerDetails;
796+
public ConcurrentDictionary<string, ProviderDetails?> GetProviderDetails() => ProviderDetails;
797797

798798
public void ResolveProviderDetails(EventRecord eventRecord)
799799
{
800-
if (providerDetails.ContainsKey(eventRecord.ProviderName))
800+
if (ProviderDetails.ContainsKey(eventRecord.ProviderName))
801801
{
802802
return;
803803
}
804804

805-
providerDetails.TryAdd(eventRecord.ProviderName, null);
805+
ProviderDetails.TryAdd(eventRecord.ProviderName, null);
806806
}
807807
}
808808
}

src/EventLogExpert.Eventing/EventResolvers/EventProviderDatabaseEventResolver.cs

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -29,23 +29,23 @@ internal EventProviderDatabaseEventResolver(
2929
{
3030
ArgumentNullException.ThrowIfNull(dbCollection);
3131

32-
logger?.Trace($"{nameof(EventProviderDatabaseEventResolver)} was instantiated at:\n{Environment.StackTrace}");
32+
Logger?.Trace($"{nameof(EventProviderDatabaseEventResolver)} was instantiated at:\n{Environment.StackTrace}");
3333

3434
LoadDatabases(dbCollection.ActiveDatabases);
3535
}
3636

3737
protected override void Dispose(bool disposing)
3838
{
39-
if (!disposing || disposed) { return; }
39+
if (!disposing) { return; }
4040

4141
ImmutableArray<EventProviderDbContext> contextsToDispose;
4242

4343
// Use EnterScope() for exception-safe lock management.
4444
// This ensures the lock is always released even if an exception occurs.
4545
using (_databaseAccessLock.EnterScope())
4646
{
47-
// Double-check disposed after acquiring lock for thread safety
48-
if (disposed)
47+
// Check if already disposed
48+
if (IsDisposed)
4949
{
5050
return;
5151
}
@@ -55,11 +55,6 @@ protected override void Dispose(bool disposing)
5555
// The lock synchronizes with ResolveProviderDetails to prevent use-after-dispose.
5656
contextsToDispose = _dbContexts;
5757
_dbContexts = [];
58-
59-
// Set disposed inside the lock before releasing it.
60-
// This prevents other threads from acquiring the lock and passing the disposed check,
61-
// reducing unnecessary lock contention.
62-
disposed = true;
6358
}
6459

6560
// Dispose contexts outside the lock to minimize lock hold time.
@@ -69,33 +64,32 @@ protected override void Dispose(bool disposing)
6964
context.Dispose();
7065
}
7166

72-
// Call base to dispose providerDetailsLock.
73-
// Base.Dispose() is idempotent (checks disposed flag which we already set).
67+
// Call base to dispose providerDetailsLock and set IsDisposed flag.
7468
base.Dispose(disposing);
7569
}
7670

7771
public void ResolveProviderDetails(EventRecord eventRecord)
7872
{
79-
providerDetailsLock.EnterUpgradeableReadLock();
73+
ProviderDetailsLock.EnterUpgradeableReadLock();
8074

8175
try
8276
{
8377
// Early disposed check for fail-fast behavior. This is a defensive check only;
8478
// the authoritative check is inside _databaseAccessLock below.
8579
// A race window exists here, but it's handled by the check inside the lock.
86-
ObjectDisposedException.ThrowIf(disposed, nameof(EventProviderDatabaseEventResolver));
80+
ObjectDisposedException.ThrowIf(IsDisposed, nameof(EventProviderDatabaseEventResolver));
8781

88-
if (providerDetails.ContainsKey(eventRecord.ProviderName))
82+
if (ProviderDetails.ContainsKey(eventRecord.ProviderName))
8983
{
9084
return;
9185
}
9286

93-
providerDetailsLock.EnterWriteLock();
87+
ProviderDetailsLock.EnterWriteLock();
9488

9589
try
9690
{
9791
// Double-check after acquiring write lock - another thread may have added this provider
98-
if (providerDetails.ContainsKey(eventRecord.ProviderName))
92+
if (ProviderDetails.ContainsKey(eventRecord.ProviderName))
9993
{
10094
return;
10195
}
@@ -105,7 +99,7 @@ public void ResolveProviderDetails(EventRecord eventRecord)
10599
{
106100
// Check disposed inside the database lock to prevent race with Dispose().
107101
// This ensures we don't proceed if Dispose() has swapped out _dbContexts.
108-
ObjectDisposedException.ThrowIf(disposed, nameof(EventProviderDatabaseEventResolver));
102+
ObjectDisposedException.ThrowIf(IsDisposed, nameof(EventProviderDatabaseEventResolver));
109103

110104
foreach (var dbContext in _dbContexts)
111105
{
@@ -119,8 +113,8 @@ public void ResolveProviderDetails(EventRecord eventRecord)
119113

120114
if (details is null) { continue; }
121115

122-
logger?.Trace($"Resolved {eventRecord.ProviderName} provider from database {dbContext.Name}.");
123-
providerDetails.TryAdd(eventRecord.ProviderName, details);
116+
Logger?.Trace($"Resolved {eventRecord.ProviderName} provider from database {dbContext.Name}.");
117+
ProviderDetails.TryAdd(eventRecord.ProviderName, details);
124118

125119
// Exit after first match - databases are sorted by priority (SortDatabases),
126120
// so the first database containing the provider is the preferred source.
@@ -131,17 +125,17 @@ public void ResolveProviderDetails(EventRecord eventRecord)
131125
}
132126
finally
133127
{
134-
providerDetailsLock.ExitWriteLock();
128+
ProviderDetailsLock.ExitWriteLock();
135129
}
136130

137-
if (!providerDetails.ContainsKey(eventRecord.ProviderName))
131+
if (!ProviderDetails.ContainsKey(eventRecord.ProviderName))
138132
{
139-
providerDetails.TryAdd(eventRecord.ProviderName, new ProviderDetails { ProviderName = eventRecord.ProviderName });
133+
ProviderDetails.TryAdd(eventRecord.ProviderName, new ProviderDetails { ProviderName = eventRecord.ProviderName });
140134
}
141135
}
142136
finally
143137
{
144-
providerDetailsLock.ExitUpgradeableReadLock();
138+
ProviderDetailsLock.ExitUpgradeableReadLock();
145139
}
146140
}
147141

@@ -213,11 +207,11 @@ internal static IEnumerable<string> SortDatabases(IEnumerable<string> databasePa
213207
/// </summary>
214208
private void LoadDatabases(IEnumerable<string> databasePaths)
215209
{
216-
logger?.Trace($"{nameof(LoadDatabases)} was called with {databasePaths.Count()} {nameof(databasePaths)}.");
210+
Logger?.Trace($"{nameof(LoadDatabases)} was called with {databasePaths.Count()} {nameof(databasePaths)}.");
217211

218212
foreach (var databasePath in databasePaths)
219213
{
220-
logger?.Trace($" {databasePath}");
214+
Logger?.Trace($" {databasePath}");
221215
}
222216

223217
foreach (var context in _dbContexts)
@@ -238,7 +232,7 @@ private void LoadDatabases(IEnumerable<string> databasePaths)
238232
throw new FileNotFoundException(file);
239233
}
240234

241-
var c = new EventProviderDbContext(file, readOnly: true, logger);
235+
var c = new EventProviderDbContext(file, readOnly: true, Logger);
242236
var (needsv2, needsv3) = c.IsUpgradeNeeded();
243237
if (needsv2 || needsv3)
244238
{

0 commit comments

Comments
 (0)