Skip to content

Commit

Permalink
Created EventDbTool logger to unify logging across solution
Browse files Browse the repository at this point in the history
  • Loading branch information
jschick04 authored and bill-long committed Nov 18, 2024
1 parent 5be0846 commit ef92069
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 252 deletions.
45 changes: 22 additions & 23 deletions src/EventLogExpert.EventDbTool/CreateDatabaseCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@
// // Licensed under the MIT License.

using EventLogExpert.Eventing.EventProviderDatabase;
using EventLogExpert.Eventing.Helpers;
using EventLogExpert.Eventing.Providers;
using Microsoft.Extensions.Logging;
using System.CommandLine;

namespace EventLogExpert.EventDbTool;

public class CreateDatabaseCommand : DbToolCommand
public sealed class CreateDatabaseCommand : DbToolCommand
{
private static readonly ITraceLogger s_logger = new TraceLogger(LogLevel.Information);

public static Command GetCommand()
{
var createDatabaseCommand = new Command(
Expand Down Expand Up @@ -54,26 +58,24 @@ public static void CreateDatabase(string path, string filter, bool verboseLoggin
return;
}

var skipProviderNames = new HashSet<string>();
HashSet<string> skipProviderNames = [];

if (!File.Exists(skipProvidersInFile))
{
Console.WriteLine($"File not found: {skipProvidersInFile}");
}

if (skipProvidersInFile != null)
using var skipDbContext = new EventProviderDbContext(skipProvidersInFile, readOnly: true);
foreach (var provider in skipDbContext.ProviderDetails)
{
if (!File.Exists(skipProvidersInFile))
{
Console.WriteLine($"File not found: {skipProvidersInFile}");
}

using var skipDbContext = new EventProviderDbContext(skipProvidersInFile, readOnly: true);
foreach (var provider in skipDbContext.ProviderDetails)
{
skipProviderNames.Add(provider.ProviderName);
}

Console.WriteLine($"Found {skipProviderNames.Count} providers in file {skipProvidersInFile}. " +
"These will not be included in the new database.");
skipProviderNames.Add(provider.ProviderName);
}

Console.WriteLine($"Found {skipProviderNames.Count} providers in file {skipProvidersInFile}. " +
"These will not be included in the new database.");

var providerNames = GetLocalProviderNames(filter);

if (!providerNames.Any())
{
Console.WriteLine($"No providers found matching filter {filter}.");
Expand All @@ -94,16 +96,13 @@ public static void CreateDatabase(string path, string filter, bool verboseLoggin

foreach (var providerName in providerNamesNotSkipped)
{
var provider = new EventMessageProvider(providerName, verboseLogging ? (s, log) => Console.WriteLine(s) : (s, log) => { });
var provider = new EventMessageProvider(providerName, verboseLogging ? s_logger : null);

var details = provider.LoadProviderDetails();
if (details != null)
{
dbContext.ProviderDetails.Add(details);

LogProviderDetails(details);
dbContext.ProviderDetails.Add(details);

details = null;
}
LogProviderDetails(details);
}

Console.WriteLine();
Expand Down
17 changes: 17 additions & 0 deletions src/EventLogExpert.EventDbTool/TraceLogger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// // Copyright (c) Microsoft Corporation.
// // Licensed under the MIT License.

using EventLogExpert.Eventing.Helpers;
using Microsoft.Extensions.Logging;

namespace EventLogExpert.EventDbTool;

public class TraceLogger(LogLevel loggingLevel) : ITraceLogger
{
public void Trace(string message, LogLevel level = LogLevel.Information)
{
if (level < loggingLevel) { return; }

Console.WriteLine($"[{DateTime.Now:o}] [{Environment.CurrentManagedThreadId}] [{level}] {message}");
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// // Copyright (c) Microsoft Corporation.
// // Licensed under the MIT License.

using EventLogExpert.Eventing.Helpers;
using EventLogExpert.Eventing.Models;
using EventLogExpert.Eventing.Providers;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System.Text.Json;

namespace EventLogExpert.Eventing.EventProviderDatabase;
Expand All @@ -13,20 +13,13 @@ public class EventProviderDbContext : DbContext
{
private readonly bool _readOnly;

private readonly Action<string, LogLevel> _tracer;
private readonly ITraceLogger? _logger;

public EventProviderDbContext(string path, bool readOnly, Action<string, LogLevel>? tracer = null)
public EventProviderDbContext(string path, bool readOnly, ITraceLogger? logger = null)
{
if (tracer != null)
{
_tracer = tracer;
}
else
{
_tracer = (s,log) => { };
}
_logger = logger;

_tracer($"Instantiating EventProviderDbContext. path: {path} readOnly: {readOnly}", LogLevel.Information);
_logger?.Trace($"Instantiating EventProviderDbContext. path: {path} readOnly: {readOnly}");

Name = System.IO.Path.GetFileNameWithoutExtension(path);
Path = path;
Expand Down Expand Up @@ -101,7 +94,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)

var needsUpgrade = needsV2Upgrade || needsV3Upgrade;

_tracer($"{nameof(EventProviderDbContext)}.{nameof(IsUpgradeNeeded)}() for database {Path}. needsV2Upgrade: {needsV2Upgrade} needsV3Upgrade: {needsV3Upgrade}", LogLevel.Information);
_logger?.Trace($"{nameof(EventProviderDbContext)}.{nameof(IsUpgradeNeeded)}() for database {Path}. needsV2Upgrade: {needsV2Upgrade} needsV3Upgrade: {needsV3Upgrade}");

return (needsV2Upgrade, needsV3Upgrade);
}
Expand All @@ -117,7 +110,7 @@ public void PerformUpgradeIfNeeded()

var size = new FileInfo(Path).Length;

_tracer($"EventProviderDbContext upgrading database. Size: {size} Path: {Path}", LogLevel.Information);
_logger?.Trace($"EventProviderDbContext upgrading database. Size: {size} Path: {Path}");

var connection = Database.GetDbConnection();
Database.OpenConnection();
Expand Down Expand Up @@ -183,6 +176,6 @@ public void PerformUpgradeIfNeeded()

size = new FileInfo(Path).Length;

_tracer($"EventProviderDbContext upgrade completed. Size: {size} Path: {Path}", LogLevel.Information);
_logger?.Trace($"EventProviderDbContext upgrade completed. Size: {size} Path: {Path}");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// // Licensed under the MIT License.

using EventLogExpert.Eventing.EventProviderDatabase;
using EventLogExpert.Eventing.Helpers;
using EventLogExpert.Eventing.Models;
using EventLogExpert.Eventing.Providers;
using Microsoft.Extensions.Logging;
using System.Collections.Immutable;
using System.Text.RegularExpressions;

Expand All @@ -16,11 +16,10 @@ public sealed partial class EventProviderDatabaseEventResolver : EventResolverBa

private ImmutableArray<EventProviderDbContext> _dbContexts = [];

public EventProviderDatabaseEventResolver(IDatabaseCollectionProvider dbCollection) : this(dbCollection, (s, log) => { }) { }

public EventProviderDatabaseEventResolver(IDatabaseCollectionProvider dbCollection, Action<string, LogLevel> tracer) : base(tracer)
public EventProviderDatabaseEventResolver(IDatabaseCollectionProvider dbCollection, ITraceLogger? logger = null) : base(logger)
{
tracer($"{nameof(EventProviderDatabaseEventResolver)} was instantiated at:\n{Environment.StackTrace}", LogLevel.Information);
logger?.Trace($"{nameof(EventProviderDatabaseEventResolver)} was instantiated at:\n{Environment.StackTrace}");

LoadDatabases(dbCollection.ActiveDatabases);
}

Expand All @@ -47,7 +46,7 @@ public void ResolveProviderDetails(EventRecord eventRecord, string owningLogName

if (details is null) { continue; }

tracer($"Resolved {eventRecord.ProviderName} provider from database {dbContext.Name}.", LogLevel.Information);
logger?.Trace($"Resolved {eventRecord.ProviderName} provider from database {dbContext.Name}.");
providerDetails.TryAdd(eventRecord.ProviderName, details);
}
}
Expand Down Expand Up @@ -124,11 +123,11 @@ private static IEnumerable<string> SortDatabases(IEnumerable<string> databasePat
/// </summary>
private void LoadDatabases(IEnumerable<string> databasePaths)
{
tracer($"{nameof(LoadDatabases)} was called with {databasePaths.Count()} {nameof(databasePaths)}.", LogLevel.Information);
logger?.Trace($"{nameof(LoadDatabases)} was called with {databasePaths.Count()} {nameof(databasePaths)}.");

foreach (var databasePath in databasePaths)
{
tracer($" {databasePath}", LogLevel.Information);
logger?.Trace($" {databasePath}");
}

foreach (var context in _dbContexts)
Expand All @@ -149,7 +148,7 @@ private void LoadDatabases(IEnumerable<string> databasePaths)
throw new FileNotFoundException(file);
}

var c = new EventProviderDbContext(file, readOnly: true, tracer);
var c = new EventProviderDbContext(file, readOnly: true, logger);
var (needsv2, needsv3) = c.IsUpgradeNeeded();
if (needsv2 || needsv3)
{
Expand Down
90 changes: 41 additions & 49 deletions src/EventLogExpert.Eventing/EventResolvers/EventResolverBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using EventLogExpert.Eventing.Helpers;
using EventLogExpert.Eventing.Models;
using EventLogExpert.Eventing.Providers;
using Microsoft.Extensions.Logging;
using System.Collections.Concurrent;
using System.Security.Principal;
using System.Text;
Expand Down Expand Up @@ -47,13 +46,13 @@ public partial class EventResolverBase

protected readonly ConcurrentDictionary<string, ProviderDetails?> providerDetails = new();
protected readonly ReaderWriterLockSlim providerDetailsLock = new();
protected readonly Action<string, LogLevel> tracer;
protected readonly ITraceLogger? logger;

private readonly Regex _sectionsToReplace = WildcardWithNumberRegex();

protected EventResolverBase(Action<string, LogLevel> tracer)
protected EventResolverBase(ITraceLogger? logger = null)
{
this.tracer = tracer ?? throw new ArgumentNullException(nameof(tracer));
this.logger = logger;
}

public IEnumerable<string> GetKeywordsFromBitmask(EventRecord eventRecord)
Expand Down Expand Up @@ -149,11 +148,11 @@ public string ResolveTaskName(EventRecord eventRecord)

if (potentialTaskNames.Count > 1)
{
tracer("More than one matching task ID was found.", LogLevel.Information);
tracer($" eventRecord.Task: {eventRecord.Task}", LogLevel.Information);
tracer(" Potential matches:", LogLevel.Information);
logger?.Trace("More than one matching task ID was found.");
logger?.Trace($" eventRecord.Task: {eventRecord.Task}");
logger?.Trace(" Potential matches:");

potentialTaskNames.ForEach(t => tracer($" {t.LogLink} {t.Text}", LogLevel.Information));
potentialTaskNames.ForEach(t => logger?.Trace($" {t.LogLink} {t.Text}"));
}
}
else
Expand Down Expand Up @@ -248,77 +247,71 @@ protected string FormatDescription(
}
catch (Exception ex)
{
tracer($"FormatDescription exception was caught: {ex}", LogLevel.Information);
logger?.Trace($"FormatDescription exception was caught: {ex}");

return "Failed to resolve description, see XML for more details.";
}
}

private static List<string> GetFormattedProperties(string? template, IList<object> properties)
private static List<string> GetFormattedProperties(string? template, IEnumerable<object> properties)
{
string[]? dataNodes = null;
List<string> providers = [];

if (!string.IsNullOrWhiteSpace(template))
if (!string.IsNullOrWhiteSpace(template) && !s_formattedPropertiesCache.TryGetValue(template, out dataNodes))
{
if (s_formattedPropertiesCache.TryGetValue(template, out var values))
{
dataNodes = values;
}
else
{
dataNodes = XElement.Parse(template)
.Descendants()
.Attributes()
.Where(a => a.Name == "outType")
.Select(a => a.Value)
.ToArray();

s_formattedPropertiesCache.TryAdd(template, dataNodes);
}
dataNodes = XElement.Parse(template)
.Descendants()
.Attributes()
.Where(a => a.Name == "outType")
.Select(a => a.Value)
.ToArray();

s_formattedPropertiesCache.TryAdd(template, dataNodes);
}

for (int i = 0; i < properties.Count; i++)
int index = 0;

foreach (object property in properties)
{
string? outType = dataNodes?[i];
string? outType = dataNodes?[index];

switch (properties[i])
switch (property)
{
case DateTime eventTime:
// Exactly match the format produced by EventRecord.FormatMessage().
// I have no idea why it includes Unicode LRM marks, but it does.
providers.Add(eventTime.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffffff00K"));
continue;

break;
case byte[] bytes:
providers.Add(Convert.ToHexString(bytes));
continue;

break;
case SecurityIdentifier sid:
providers.Add(sid.Value);
continue;

break;
default:
if (string.IsNullOrEmpty(outType))
{
providers.Add($"{properties[i]}");

continue;
providers.Add($"{property}");
}

if (s_displayAsHexTypes.Contains(outType, StringComparer.OrdinalIgnoreCase))
else if (s_displayAsHexTypes.Contains(outType, StringComparer.OrdinalIgnoreCase))
{
providers.Add($"0x{properties[i]:X}");
providers.Add($"0x{property:X}");
}
else if (string.Equals(outType, "win:HResult", StringComparison.OrdinalIgnoreCase) &&
properties[i] is int hResult)
else if (string.Equals(outType, "win:HResult", StringComparison.OrdinalIgnoreCase) && property is int hResult)
{
providers.Add(ResolverMethods.GetErrorMessage((uint)hResult));
}
else
{
providers.Add($"{properties[i]}");
providers.Add($"{property}");
}

continue;
break;
}

index++;
}

return providers;
Expand All @@ -343,7 +336,7 @@ private static List<string> GetFormattedProperties(string? template, IList<objec
{
// Try again forcing the long to a short and with no log name.
// This is needed for providers such as Microsoft-Windows-Complus
modernEvents = details.Events?
modernEvents = details.Events
.Where(e => (short)e.Id == eventRecord.Id && e.Version == eventRecord.Version).ToList();
}

Expand All @@ -357,13 +350,12 @@ private static List<string> GetFormattedProperties(string? template, IList<objec
return modernEvents[0];
}

tracer("Ambiguous modern event found:", LogLevel.Information);
logger?.Trace("Ambiguous modern event found:");

foreach (var modernEvent in modernEvents)
{
tracer($" Version: {modernEvent.Version} Id: {modernEvent.Id} " +
$"LogName: {modernEvent.LogName} Description: {modernEvent.Description}",
LogLevel.Information);
logger?.Trace($" Version: {modernEvent.Version} Id: {modernEvent.Id} " +
$"LogName: {modernEvent.LogName} Description: {modernEvent.Description}");
}

return modernEvents[0];
Expand Down
Loading

0 comments on commit ef92069

Please sign in to comment.