66using EventLogExpert . Eventing . Models ;
77using EventLogExpert . Eventing . Providers ;
88using Microsoft . EntityFrameworkCore ;
9+ using System . Collections . Concurrent ;
910using System . Collections . Immutable ;
1011using System . Text . RegularExpressions ;
1112
@@ -20,9 +21,11 @@ namespace EventLogExpert.Eventing.EventResolvers;
2021public sealed partial class EventResolver : EventResolverBase , IEventResolver
2122{
2223 private readonly Lock _databaseAccessLock = new ( ) ;
24+ private readonly ConcurrentDictionary < string , bool > _providerFromNonLocal = new ( StringComparer . OrdinalIgnoreCase ) ;
25+ private readonly ConcurrentDictionary < string , ProviderDetails ? > _supplementalDetails = new ( StringComparer . OrdinalIgnoreCase ) ;
2326
2427 private ImmutableArray < EventProviderDbContext > _dbContexts = [ ] ;
25- private IReadOnlyList < string > ? _metadataPaths ;
28+ private ImmutableArray < string > _metadataPaths = [ ] ;
2629
2730 public EventResolver (
2831 IDatabaseCollectionProvider ? dbCollection = null ,
@@ -37,6 +40,13 @@ public EventResolver(
3740 Logger ? . Debug ( $ "{ nameof ( EventResolver ) } was instantiated.") ;
3841 }
3942
43+ public override DisplayEventModel ResolveEvent ( EventRecord eventRecord )
44+ {
45+ ResolveProviderDetails ( eventRecord ) ;
46+
47+ return base . ResolveEvent ( eventRecord ) ;
48+ }
49+
4050 public void ResolveProviderDetails ( EventRecord eventRecord )
4151 {
4252 ObjectDisposedException . ThrowIf ( IsDisposed , nameof ( EventResolver ) ) ;
@@ -49,7 +59,7 @@ public void ResolveProviderDetails(EventRecord eventRecord)
4959 if ( ProviderDetails . ContainsKey ( eventRecord . ProviderName ) ) { return ; }
5060
5161 // 1. Try MTA locale metadata files (primary source for exported logs)
52- if ( _metadataPaths is { Count : > 0 } && TryResolveFromMta ( eventRecord ) )
62+ if ( _metadataPaths . Length > 0 && TryResolveFromMta ( eventRecord ) )
5363 {
5464 return ;
5565 }
@@ -65,11 +75,7 @@ public void ResolveProviderDetails(EventRecord eventRecord)
6575 }
6676 }
6777
68- /// <summary>
69- /// Sets the MTA locale metadata file paths for exported log resolution. Must be called before any events are
70- /// resolved.
71- /// </summary>
72- public void SetMetadataPaths ( IReadOnlyList < string > metadataPaths ) => _metadataPaths = metadataPaths ;
78+ public void SetMetadataPaths ( IReadOnlyList < string > metadataPaths ) => _metadataPaths = [ .. metadataPaths ] ;
7379
7480 /// <summary>
7581 /// If the database file name ends in a year or a number, such as Exchange 2019 or Windows 2016, we want to sort
@@ -144,6 +150,21 @@ protected override void Dispose(bool disposing)
144150 base . Dispose ( disposing ) ;
145151 }
146152
153+ protected override ProviderDetails ? TryGetSupplementalDetails ( EventRecord eventRecord )
154+ {
155+ // Only supplement providers that were loaded from MTA/DB
156+ if ( ! _providerFromNonLocal . ContainsKey ( eventRecord . ProviderName ) ) { return null ; }
157+
158+ return _supplementalDetails . GetOrAdd (
159+ eventRecord . ProviderName ,
160+ name =>
161+ {
162+ Logger ? . Debug ( $ "Loading supplemental local provider for { name } ") ;
163+
164+ return new EventMessageProvider ( name , Logger ) . LoadProviderDetails ( ) ;
165+ } ) ;
166+ }
167+
147168 [ GeneratedRegex ( "^(.+) (\\ S+)$" ) ]
148169 private static partial Regex SplitProductAndVersionRegex ( ) ;
149170
@@ -228,6 +249,7 @@ private bool TryResolveFromDatabase(EventRecord eventRecord)
228249
229250 Logger ? . Debug ( $ "Resolved { eventRecord . ProviderName } from database { dbContext . Name } .") ;
230251 ProviderDetails . TryAdd ( eventRecord . ProviderName , details ) ;
252+ _providerFromNonLocal . TryAdd ( eventRecord . ProviderName , true ) ;
231253
232254 return true ;
233255 }
@@ -244,12 +266,13 @@ private bool TryResolveFromMta(EventRecord eventRecord)
244266 _metadataPaths ,
245267 Logger ) . LoadProviderDetails ( ) ;
246268
247- if ( details . Events . Count == 0 && details . Keywords . Count == 0 )
269+ if ( details . Events . Count == 0 && details . Keywords . Count == 0 && details . Messages . Count == 0 )
248270 {
249271 return false ;
250272 }
251273
252274 ProviderDetails . TryAdd ( eventRecord . ProviderName , details ) ;
275+ _providerFromNonLocal . TryAdd ( eventRecord . ProviderName , true ) ;
253276
254277 return true ;
255278 }
0 commit comments