ASP.NET Core Error Management with elmah.io

This article shows how to use elmah.io error management with an ASP.NET Core application. The error, log data is added to elmah.io using different elmah.io nuget packages, directly from ASP.NET Core and also using an NLog elmah.io target.

Code: https://github.com/damienbod/AspNetCoreElmah

elmah.io is an error management system which can help you monitor, find and fix application problems fast. While structured logging is supported, the main focus of elmah.io is handling errors.

Getting started with Elmah.Io

Before you can start logging to elmah.io, you need to create an account and setup a log. Refer to the documentation here.

Logging exceptions, errors with Elmah.Io.AspNetCore and Elmah.Io.Extensions.Logging

You can add logs, exceptions to elmah.io directly from an ASP.NET Core application using the Elmah.Io.AspNetCore and the Elmah.Io.Extensions.Logging nuget packages. These packages can be added to the project using the nuget package manager.

Or you can just add the packages directly in the csproj file.

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp1.1</TargetFramework>
  </PropertyGroup>

  <PropertyGroup>
    <UserSecretsId>AspNetCoreElmah-c23d2237a4-eb8832a1-452ac4</UserSecretsId>
  </PropertyGroup>
  
  <ItemGroup>
    <Content Include="wwwroot\index.html" />
  </ItemGroup>
  <ItemGroup>
    <PackageReference Include="Elmah.Io.AspNetCore" Version="3.2.39-pre" />
    <PackageReference Include="Elmah.Io.Extensions.Logging" Version="3.1.22-pre" />
    <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.0.0" />
    <PackageReference Include="Microsoft.AspNetCore" Version="1.1.1" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.2" />
    <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="1.1.1" />
    <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.1" />
    <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="1.1.1" />
  </ItemGroup>
  <ItemGroup>
    <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="1.0.0" />
  </ItemGroup>

</Project>

The Elmah.Io.AspNetCore package is used to catch unhandled exceptions in the application. This is configured in the Startup class. The OnMessage method is used to set specific properties in the messages which are sent to elmah.io. Setting the Hostname and the Application properties are very useful when evaluating the logs in elmah.io.

app.UseElmahIo(
	_elmahAppKey, 
	new Guid(_elmahLogId),
	new ElmahIoSettings()
	{
		OnMessage = msg =>
		{
			msg.Version = "1.0.0";
			msg.Hostname = "dev";
			msg.Application = "AspNetCoreElmah";
		}
	});

The Elmah.Io.Extensions.Logging package is used to log messages using the built in ILoggerFactory. You should only send warning, errors, critical messages and not just log everything to elmah.io, but it is possible to do this. Again the OnMessage method can be used to set the Hostname and the Application name for each log.

loggerFactory.AddElmahIo(
	_elmahAppKey, 
	new Guid(_elmahLogId), 
	new FilterLoggerSettings
	{
		{"ValuesController", LogLevel.Information}
	},
	new ElmahIoProviderOptions
	{
		OnMessage = msg =>
		{
			msg.Version = "1.0.0";
			msg.Hostname = "dev";
			msg.Application = "AspNetCoreElmah";
		}
	});

Using User Secrets for the elmah.io API-KEY and LogID

ASP.NET Core user secrets can be used to set the elmah.io API-KEY and the LogID as you don’t want to commit these to your source. The AddUserSecrets method can be used to set this.

private string _elmahAppKey;
private string _elmahLogId;

public Startup(IHostingEnvironment env)
{
	var builder = new ConfigurationBuilder()
		.SetBasePath(env.ContentRootPath)
		.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
		.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
		.AddEnvironmentVariables();

	if (env.IsDevelopment())
	{
		builder.AddUserSecrets("AspNetCoreElmah-c23d2237a4-eb8832a1-452ac4");
	}

	Configuration = builder.Build();
}

The user secret properties can then be used in the ConfigureServices method.

 public void ConfigureServices(IServiceCollection services)
{
	_elmahAppKey = Configuration["ElmahAppKey"];
	_elmahLogId = Configuration["ElmahLogId"];
	// Add framework services.
	services.AddMvc();
}

A dummy exception is thrown in this example, which then sends the data to elmah.io.

[HttpGet("{id}")]
public string Get(int id)
{
	throw new System.Exception("something terrible bad here!");
	return "value";
}

Logging exceptions, errors to elmah.io using NLog

NLog using the Elmah.Io.NLog target can also be used in ASP.NET Core to send messages to elmah.io. This can be added using the nuget package manager.

Or you can just add it to the csproj file.

<PackageReference Include="Elmah.Io.NLog" Version="3.1.28-pre" />
<PackageReference Include="NLog.Web.AspNetCore" Version="4.3.1" />

NLog for ASP.NET Core applications can be configured in the Startup class. You need to set the target properties with the elmah.io API-KEY and also the LogId. You could also do this in the nlog.config file.

loggerFactory.AddNLog();
app.AddNLogWeb();

LogManager.Configuration.Variables["configDir"] = "C:\\git\\damienbod\\AspNetCoreElmah\\Logs";

foreach (ElmahIoTarget target in LogManager.Configuration.AllTargets.Where(t => t is ElmahIoTarget))
{
	target.ApiKey = _elmahAppKey;
	target.LogId = _elmahLogId;
}

LogManager.ReconfigExistingLoggers();

The IHttpContextAccessor and the HttpContextAccessor also need to be registered to the default IoC in ASP.NET Core to get the extra information from the web requests.

public void ConfigureServices(IServiceCollection services)
{
	services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

	_elmahAppKey = Configuration["ElmahAppKey"];
	_elmahLogId = Configuration["ElmahLogId"];

	// Add framework services.
	services.AddMvc();
}

The nlog.config file can then be configured for the target with the elmah.io type. The application property is also set which is useful in elmah.io.

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      autoReload="true"
      internalLogLevel="Warn"
      internalLogFile="C:\git\damienbod\AspNetCoreElmah\Logs\internal-nlog.txt">

  <extensions>
    <add assembly="NLog.Web.AspNetCore"/>
    <add assembly="Elmah.Io.NLog"/>    
  </extensions>

  
  <targets>
    <target name="elmahio" type="elmah.io" apiKey="API_KEY" logId="LOG_ID" application="AspNetCoreElmahUI"/>
    
    <target xsi:type="File" name="allfile" fileName="${var:configDir}\nlog-all.log"
                layout="${longdate}|${event-properties:item=EventId.Id}|${logger}|${uppercase:${level}}|TraceId=${aspnet-traceidentifier}| url: ${aspnet-request-url} | action: ${aspnet-mvc-action} |${message} ${exception}" />

    <target xsi:type="File" name="ownFile-web" fileName="${var:configDir}\nlog-own.log"
             layout="${longdate}|${event-properties:item=EventId.Id}|${logger}|${uppercase:${level}}|TraceId=${aspnet-traceidentifier}| url: ${aspnet-request-url} | action: ${aspnet-mvc-action} | ${message} ${exception}" />

    <target xsi:type="Null" name="blackhole" />

  </targets>

  <rules>
    <logger name="*" minlevel="Warn" writeTo="elmahio" />
    <!--All logs, including from Microsoft-->
    <logger name="*" minlevel="Trace" writeTo="allfile" />

    <!--Skip Microsoft logs and so log only own logs-->
    <logger name="Microsoft.*" minlevel="Trace" writeTo="blackhole" final="true" />
    <logger name="*" minlevel="Trace" writeTo="ownFile-web" />
  </rules>
</nlog>


The About method calls the AspNetCoreElmah application method which throws the dummy exception, so we send exceptions from both applications.

public async Task<IActionResult> About()
{
	_logger.LogInformation("HomeController About called");
	// throws exception
	HttpClient _client = new HttpClient();
	var response = await _client.GetAsync("http://localhost:37209/api/values/1");
	response.EnsureSuccessStatusCode();
	var responseString = System.Text.Encoding.UTF8.GetString(
		await response.Content.ReadAsByteArrayAsync()
	);
	ViewData["Message"] = "Your application description page.";

	return View();
}

Now both applications can be started, and the errors can be viewed in the elmah.io dashboard.

Where you open the dashboard in elmah.io and access you logs, you can view the exceptions.

Here’s the log sent from the AspNetCoreElmah application.

Here’s the log sent from the AspNetCoreElmahUI application using NLog with Elmah.Io.


Links

https://elmah.io/

https://github.com/elmahio/elmah.io.nlog

http://nlog-project.org/

13 comments

  1. […] ASP.NET Core Error Management with elmah.io (Damien Bowden) […]

  2. […] Damien also posted on how to integrate elmah.io (ELMAH stands for Error Logging Modules and Handlers) : https://damienbod.com/2017/03/16/asp-net-core-error-management-with-elmah-io/ […]

    1. Hi Dominique

      thanks for the link and the blog

      Greetings Damien

  3. […] Asp.Net Core Error Management With Elmah.Io by Damien Bowden […]

  4. […] La gestion des erreurs ASP.NET Core avec Elmah.io. […]

  5. You should also check out exceptionless (http://github.com/exceptionless/exceptionless) with is similar and also open source :).

    1. Will do, thanks for the link, Greetings Damien

  6. Mary P · · Reply

    Io by Damien Bowden […] […] Damien also posted on how to integrate elmah.

  7. Operating Systems · · Reply

    Io by Damien Bowden […] […] Damien also posted on how to integrate elmah. Io by Damien Bowden […]

  8. Io by Damien Bowden […] Io by Damien Bowden […] […] Damien also posted on how to integrate elmah.

  9. Io by Damien Bowden […] […] Damien also posted on how to integrate elmah. Io by Damien Bowden […]

  10. Thanks a lot, great guide to get started with Elmah.io!

  11. […] ASP.NET Core Error Management with elmah.io by Damien Bowden. […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: