aspnet/Logging

Using ILoggerFactory.AddEventLog() + ILogger.LogInformation() produces Windows Event entries with "the message resource is present but the message is not found in the string/message table" messages | missing EventLogMessages.dll message file

Eilon opened this issue · 6 comments

Eilon commented

From @fulte004 on July 11, 2018 17:1

Following documentation found at https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-2.1#log-category, I configured my ASP.NET Core 2.1 MVC app as follows:

public void Configure (IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) {
      if (env.IsDevelopment ()) {
        app.UseDeveloperExceptionPage ();
        app.UseWebpackDevMiddleware (new WebpackDevMiddlewareOptions {
          HotModuleReplacement = true,
          HotModuleReplacementEndpoint = "/dist/__webpack_hmr"
        });
      } else {
        app.UseExceptionHandler ("/Home/Error");
      }
      app.UseAuthentication ();

      app.UseStaticFiles ();

      loggerFactory.AddEventSourceLogger();
      loggerFactory.AddEventLog(new EventLogSettings {
        SourceName = Configuration["Application:Name"],
        Filter = (x, y) => y > LogLevel.Debug
      });
      ApplicationLogging.LoggerFactory = loggerFactory;
      ApplicationLogging.Log = ApplicationLogging.CreateLogger(Configuration["Application:Name"]);
      loggerFactory.AddConsole (Configuration.GetSection ("Logging"));
      loggerFactory.AddDebug ();
      if (!EventLog.SourceExists(Configuration["Application:Name"]))
      {
          EventLog.CreateEventSource(Configuration["Application:Name"], "Application");
      }

      app.UseSession ();

      app.UseMvc (routes => {
        routes.MapRoute (
          name: "default",
          template: "{controller=Home}/{action=Index}/{id?}");
        routes.MapRoute (
          name: "signout",
          template: "{controller=Home}/{action=SignOut}/{id?}");
        // a special route for our index page
        routes.MapSpaFallbackRoute (
          name: "spa-fallback",
          defaults : new { controller = "Home", action = "index" });
      });
    }

Note that it is using a static class to provide direct reference to the ILogger object reference.

I'm then calling the logger as follows from an attribute class that I decorate my controllers with to log all API requests from each user:

    public class LogAttribute : Attribute, IActionFilter
    {
      public LogAttribute() {}

      public void OnActionExecuted(ActionExecutedContext context)
      {
      }

      public void OnActionExecuting(ActionExecutingContext context)
      {
        var ctx = context.HttpContext;
        var sub = (from c in ctx.User.Claims where c.Type == "sub"
                  select c).FirstOrDefault ().Value;

        ApplicationLogging.Log.LogInformation($"User: {sub}\nRequest: {ctx.Request.Path.Value}");
      }
    }

The resulting output in the Windows Event Application log looks like the following:

The description for Event ID 0 from source MyAppName cannot be found. Either the component that raises this event is not installed on your local computer or the installation is corrupted. You can install or repair the component on the local computer.

If the event originated on another computer, the display information had to be saved with the event.

The following information was included with the event:

MyAppName [from Configuration]
User: USERNAME
Request: /api/Controller/Method

the message resource is present but the message is not found in the string/message table

The EventLog.CreateEventSource(Configuration["Application:Name"], "Application"); call creates a registry entry for the application under \HKLM\SYSTEM\CurrentControlSet\services\eventlog\Application\MyAppName as I would expect, however, the EventMessageFile value is referencing "C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.1.0\EventLogMessages.dll", which is a non-existent DLL in any of the .NET Core versions that I have installed all the way to 2.0.0.

Since other incarnations of the .NET Framework all seem to include a similar EventLogMessages.dll file, I am assuming this reference to be erroneous.

Is there currently a way for System Event logging to be conveyed cleanly without being polluted with the boilerplate "the message resource is present but the message is not found in the string/message table" messages in each event entry? The official documentation does not address this.

Note: One blog I ran accross at http://blog.ablikim.com/post/7-things-worth-knowing-about-asp-net-core-logging suggested injecting ILogger into a controller using ILogger<DebugLogger>, however that just uses the "Microsoft.Extensions.Logging.Debug.DebugLogger" source instead of "MyAppName" and did not help clean up the entries. I have tried substituting existing EventLogMessages.dll files in the registry entry for my application such as the one for .NET Framework 4.0, but I still get the same messages. I even went through the pains of creating my own event messages DLL based on the Microsoft documentation for MC file format and using the technique found at this link: https://www.codeproject.com/Articles/4153/Getting-the-most-out-of-Event-Viewer

This did not help either.

Copied from original issue: dotnet/core#1776

I face the same issue also. Whats the update on this?

I am using .net core 2.1

Eilon commented

@nabilasheikh sorry we have not yet had a chance to investigate. We will update this issue when we have more info.

I've ran into this exact issue. As @fulte004 mentioned, EventLogMessages.dll doesn't exist in the .NET Core installs, however I tried doing a copy and paste from C:\Windows\Microsoft.NET\Framework64\v4.0.30319\EventLogMessages.dll (not ideal as the next .NET Core version probably won't have it either) and it DID work after closing the Event Viewer entirely and reopening it. Another alternative work-around would be to update the path in the Registry (which won't work on a Windows Server core installation where no .NET Framework or only .NET Core is installed).

For my situation, Using PowerShell (and .NET Framework v4.0x) I just created a separate Log and Log Source:

[System.Diagnostics.EventLog]::CreateEventSource("mySource", "myLog")

The created log ended up using the following Event Message File:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\EventLogMessages.dll

Then in Program.cs (I'm using .CreateDefaultBuilder() in .Net Core 2.1.3 so you may need to adapt the syntax for your implementation):

logging.AddEventLog(new EventLogSettings() { LogName = "myLog", SourceName = "mySource" });

But I agree this needs a fix some how. Perhaps EventLogMessages.dll can be included with the Microsoft.Extensions.Logging.EventLog NuGet package or something and then that path gets referenced as opposed to the targeted framework's path.

@Madison-Smith Thanks for your comments. An alternative solution might be to create a default log source for all .NET Core applications (which would point to the correct EventLogMessages.dll) and be shared.

Then the EventLogSettings class could be modified and the default values for LogName & SourceName could be set to .NET Core & the app namespace respectively (so it wouldn't even need to be specified).