VMware ESXi and vSphere Cluster Management

ELMAH: Error Logging and Monitoring for ASP.NET Applications

Learn how to install, configure, secure, filter, store, and inspect ELMAH errors in classic ASP.NET Web Forms and MVC applications.

ELMAH means Error Logging Modules and Handlers. It is a diagnostic library for classic ASP.NET applications, including Web Forms and ASP.NET MVC applications running on the .NET Framework. ELMAH captures unhandled web-application exceptions, stores error details through a configurable provider, and exposes a browser-based error viewer.

This lesson covers installation, web.config setup, storage providers, security, filtering, explicit logging, ASP.NET error handling, and production operations.

What ELMAH Does—and Does Not Do

ELMAH observes the classic ASP.NET request pipeline. When an exception reaches the pipeline without being fully handled, its error-logging module can create an error record containing information such as the exception, request URL, HTTP method, status code, query string, form values, cookies, and server variables.

ELMAH is primarily diagnostic tooling. It is not a replacement for:

  • Application-level exception handling and recovery.
  • Safe, user-friendly error pages.
  • An alerting and on-call strategy.
  • Centralized structured logging.
  • Distributed tracing or application performance monitoring.

Use ELMAH to help an operator investigate failures. Decide separately how the application handles a failure, what the user sees, and how the team receives alerts.

ELMAH Architecture

An HTTP module is an ASP.NET pipeline component that can observe request processing. An HTTP handler serves a particular request endpoint. ELMAH uses both concepts.

ComponentPurposeTypical configuration locationOperational considerations
ErrorLogModuleObserves unhandled application errors and sends them to the configured error log.system.web/httpModules or system.webServer/modulesMust be registered in the correct IIS pipeline configuration.
ErrorLogAbstraction that persists and retrieves error records through a provider.elmah sectionProvider availability, permissions, retention, and capacity matter.
ErrorFilterModuleApplies rules that suppress selected errors.Module registration and filter configurationKeep filters narrow so real failures are not hidden.
ErrorLogPageFactoryCreates the ELMAH viewer and related error-detail handlers.system.web/httpHandlers or system.webServer/handlersProtect every exposed route, including alternate formats.
ErrorMailModuleOptional module for email notifications about errors.Module registration and ELMAH mail settingsEmail is not a substitute for durable logging or alert deduplication.

The normal flow is:

  1. A browser or other client sends a request.
  2. ASP.NET executes the request through its pipeline.
  3. An exception is not handled, or is allowed to continue to the pipeline.
  4. ErrorLogModule observes the error and creates an ELMAH error record.
  5. The configured ErrorLog provider writes the record to memory, files, or a database.
  6. An authorized operator opens the ELMAH handler to list and inspect records.

Automatic capture and explicit logging are different. Automatic capture concerns unhandled exceptions. Explicit logging is code that intentionally submits a caught exception because it still requires investigation.

Installation and Project Setup

ELMAH targets classic ASP.NET on the .NET Framework. Install the package using the project’s supported NuGet workflow:

Install-Package elmah

Some projects use a package variant or provider package appropriate to their target framework and storage engine. Confirm that the package assembly, configuration transforms, and provider dependencies are deployed to every environment.

After installation:

  1. Back up the existing web.config.
  2. Inspect any configuration changes made by NuGet.
  3. Choose a storage provider for the environment.
  4. Register the module and handlers if the package did not do so, or if your hosting mode requires explicit registration.
  5. Protect the viewer route before exposing the application outside a development machine.
  6. Deploy the provider assemblies, configuration, database objects, and file-directory permissions together.

In IIS Integrated pipeline mode, registration commonly uses system.webServer/modules and system.webServer/handlers. Classic pipeline applications commonly also require system.web/httpModules and system.web/httpHandlers. The exact assembly version and handler attributes depend on the package version, target framework, and IIS configuration.

Core web.config Configuration

The following is an illustrative classic ASP.NET configuration. Replace assembly versions, provider types, connection strings, and access rules with values supported by the package and environment.

<configuration>
  <configSections>
    <sectionGroup name="elmah">
      <section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
      <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
    </sectionGroup>
  </configSections>

  <elmah>
    <security allowRemoteAccess="false" />
    <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="ElmahDb" />
  </elmah>

  <connectionStrings>
    <add name="ElmahDb" connectionString="Data Source=...;Initial Catalog=...;Integrated Security=...;" />
  </connectionStrings>

  <system.web>
    <httpModules>
      <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
    </httpModules>
    <httpHandlers>
      <add path="elmah.axd" verb="GET" type="Elmah.ErrorLogPageFactory, Elmah" />
    </httpHandlers>
  </system.web>

  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
    </modules>
    <handlers>
      <add name="Elmah" path="elmah.axd" verb="GET" type="Elmah.ErrorLogPageFactory, Elmah" resourceType="Unspecified" />
    </handlers>
  </system.webServer>
</configuration>

The elmah section selects the ErrorLog implementation. The module registration enables automatic capture. The handler registration maps a route such as /elmah.axd to ErrorLogPageFactory. Some deployments use a different route or package-specific handler mapping; keep the route, authorization rule, and tests consistent.

Optional filtering and email modules must also be registered when used. Do not copy both Integrated and Classic registrations blindly: duplicate module registration can cause duplicate processing. Inspect the effective configuration and IIS pipeline mode.

Error Storage Providers

The provider determines where records live and how they are retrieved.

ProviderPersistenceBest use caseAdvantagesLimitationsSecurity and maintenance considerations
In-memoryProcess memoryShort development testsNo external setup; fastLost on recycle; limited capacity; not suitable for multiple serversNothing durable is retained; never rely on it for production diagnosis.
XML fileFiles on the application hostDevelopment or low-volume single-server applicationsSimple and inexpensiveFile growth, concurrent access, local-disk dependency, weaker scale-out behaviorGrant write access only to the application identity and protect the directory from direct download.
SQL ServerRelational databaseProduction classic ASP.NET applicationsDurable, queryable, supports multiple application instancesRequires schema, connectivity, capacity, and maintenanceUse least-privilege credentials, encryption where appropriate, indexes, backups, and purge jobs.
SQLiteLocal database fileDevelopment or small deploymentsPortable and low operational overheadFile locking and write concurrency can limit scale-outProtect the database file and its directory; verify provider compatibility.
OracleOracle databaseOrganizations standardized on OracleUses existing database operationsProvider and schema setup require Oracle-specific dependenciesUse managed credentials and standard database retention controls.
PostgreSQLPostgreSQL databaseDeployments using a compatible PostgreSQL providerDurable and centralizedRequires a compatible provider package and schema setupApply database permissions, TLS, backups, and purge policies.

Provider names and type strings vary by ELMAH package. Select one through the errorLog element, for example:

<elmah>
  <errorLog type="Elmah.XmlFileErrorLog, Elmah" logPath="~/App_Data/Elmah" />
</elmah>

For SQL Server, create the ELMAH tables and indexes using the schema script or setup process supplied by the selected package/provider, then configure a protected connection string:

<connectionStrings>
  <add name="ElmahDb" connectionString="Data Source=SERVER;Initial Catalog=Elmah;Integrated Security=SSPI;" />
</connectionStrings>
<elmah>
  <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="ElmahDb" />
</elmah>

For file-backed storage, create the directory during deployment and grant write and modify permissions to the IIS application identity, while denying direct web access. For database-backed storage, test connectivity using the identity that actually runs the application, not only an administrator account.

Viewing and Inspecting Error Logs

The viewer is commonly exposed at /elmah.axd, although the configured route may differ. A list page normally shows timestamp, HTTP status, exception type, message, and request information. Select an item to inspect its detail page.

Depending on the provider and package version, details can include:

  • Exception type, message, inner exceptions, and stack trace.
  • Request URL, HTTP method, query string, and form values.
  • Cookies, server variables, client information, and authenticated identity.
  • Timestamp, status code, application path, and error detail.
  • Pagination and downloadable error information.
  • An RSS endpoint, when the package and handler configuration enable it.

Request metadata is sensitive. Query strings, form values, cookies, headers, and server variables can contain passwords, session identifiers, access tokens, email addresses, or internal hostnames. Treat the viewer and its RSS endpoint as privileged interfaces.

Securing the Error-Log Interface

Protecting the viewer is mandatory in production. Do not depend only on the allowRemoteAccess setting. Apply route-specific authorization and, where possible, network controls.

<location path="elmah.axd">
  <system.web>
    <authorization>
      <deny users="?" />
      <allow roles="Administrators" />
      <deny users="*" />
    </authorization>
  </system.web>
</location>

This denies anonymous users and allows only members of the Administrators role. Alternatives include Windows Authentication, named internal users, an authenticated operations group, IP allowlists, VPN-only access, or equivalent reverse-proxy policy. Use HTTPS. Apply separate, equally strict rules to RSS and any alternate or API-like endpoints.

ControlRisk addressedRecommended implementationVerification method
Deny anonymous accessPublic disclosure of stack traces and request dataRoute-specific ASP.NET authorizationRequest the route without credentials and expect denial.
Restrict roles or identitiesExcessive internal accessAllow a small operations or administrator groupTest both an authorized and unauthorized account.
Use HTTPSNetwork interceptionRequire HTTPS at IIS or the trusted proxyConfirm HTTP redirects or is rejected.
Protect RSS and alternate routesBypassing the main viewer’s controlsApply equivalent authorization and network rulesTest every configured endpoint.
Minimize sensitive dataCredential and PII exposureRedact or avoid secrets; review captured fieldsInspect representative records and run a security review.

Filtering Noise Without Hiding Failures

Exception filtering decides whether a captured event is excluded. The ErrorFilterModule can filter by exception type, HTTP status code, URL, host, and request context, depending on the filter package and syntax.

Error patternUsually log?ReasoningExample filter condition
Missing favicon requested by browsersOften noUsually harmless repetitive noiseURL ends with /favicon.ico and status is 404
Known health-check URLUsually no for expected probesExpected failures can obscure application failuresExact health-check path and known monitor identity
Known bot probe for a nonexistent fileSometimes noAutomated scans can produce high volumeNarrow URL pattern plus confirmed user agent or status
Unexpected application 500YesMay indicate a real defect or outageDo not broadly filter status 500
Authentication or authorization failureUsually yes or aggregate separatelyMay indicate attack activity or a broken clientFilter only a documented, harmless repetitive case

A filter syntax varies by ELMAH filtering extension. An illustrative rule might look like this:

<elmah>
  <errorFilter>
    <testExceptionType type="System.Web.HttpException" />
    <test statusCode="404" url="~/favicon.ico" />
  </errorFilter>
</elmah>

Verify the syntax against the installed package. Test a known filtered request and a genuine application exception. Never filter merely because the log is inconvenient; first determine whether the event represents an expected, controlled condition.

Programmatic Error Logging

Log a caught exception explicitly when the application recovers but operators still need to investigate—for example, a failed external-service call, a swallowed background-operation exception, or a fallback path with operational impact.

try
{
    var result = paymentClient.Authorize(order);
    return result;
}
catch (Exception ex)
{
    Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
    return FallbackResponse();
}

ErrorSignal.FromCurrentContext().Raise sends the exception through the application’s configured ELMAH logging pipeline when an HTTP context is available. For non-request code, use the configured ErrorLog directly according to the installed package and preserve useful context without inserting secrets.

Avoid duplicate entries. If you explicitly log an exception and then rethrow it, the later unhandled exception may also be captured automatically. Either handle it after explicit logging or establish a clear convention for identifying intentional duplicates.

ELMAH and ASP.NET Error Handling

Several layers influence what users see and what ELMAH can capture:

  • customErrors controls classic ASP.NET user-facing error behavior, especially local versus remote detail.
  • httpErrors controls IIS-generated HTTP error responses.
  • Application_Error in Global.asax can observe, log, redirect, or clear exceptions.
  • Framework or application handlers may catch exceptions before ELMAH sees them.
  • Debug settings can expose detailed errors and should not be enabled for normal production access.

A typical production objective is safe presentation plus private diagnostics:

<system.web>
  <customErrors mode="RemoteOnly" defaultRedirect="~/Error.aspx" />
  <compilation debug="false" />
</system.web>
<system.webServer>
  <httpErrors errorMode="Custom" existingResponse="Replace" />
</system.webServer>

The exact settings depend on whether the application returns MVC error views, Web Forms pages, or IIS-generated responses. Test both local and remote requests. Redirecting, clearing, or replacing an exception too early can prevent ELMAH from observing it. If Application_Error performs custom handling, verify that ELMAH still receives the exception, and do not expose the resulting stack trace to the client.

Operational Practices

  • Define retention limits and remove old records or files automatically.
  • For SQL Server, plan table growth, indexes, backups, database capacity, and purge jobs.
  • Keep production connection strings and access policies in environment-specific configuration or protected deployment secrets, not ordinary source control.
  • Protect log data like other sensitive operational data.
  • Monitor the logger itself. A provider write failure must not silently eliminate the evidence needed to diagnose an outage.
  • After deployment, generate a controlled test exception and verify capture, storage, viewer authorization, user-facing response, and cleanup behavior.
  • For multiple application instances, prefer shared durable storage rather than local memory or unshared files.

Troubleshooting ELMAH

The viewer returns 404

Check the effective web.config, confirm that the ELMAH assembly is deployed, and inspect IIS handler mappings. Confirm that the requested route matches the configured application path and that Integrated versus Classic pipeline registration is appropriate.

Exceptions occur but no records appear

Verify ErrorLogModule registration, test with an intentional unhandled exception in a non-production environment, and review filter rules. Then check file permissions, database connectivity, schema objects, and provider-specific inner exceptions. An exception handled, cleared, or redirected before ELMAH observes it may not be captured.

The viewer returns an authorization error

This may be the intended result. Verify the authenticated identity, role membership, route-specific rules, IIS authentication, and reverse-proxy behavior. Test with a designated administrator account and an unauthorized account.

SQL-backed logging fails

Validate the connection string using the deployed application identity, confirm that the ELMAH schema exists, check database permissions, and ensure the selected provider package matches the database engine.

404 or bot traffic overwhelms the log

Group records by URL and status code, identify confirmed benign patterns, and add narrow filters. Continue recording unexpected routes and server errors.

Sensitive data appears in records

Restrict the viewer immediately, review form values, query strings, cookies, and server variables, reduce or redact sensitive collection where supported, and rotate exposed credentials or tokens.

Users see detailed exceptions

Test as a remote unauthenticated user. Review customErrors, httpErrors, debug settings, and differences between local development hosting and deployed IIS. Correct the response behavior while verifying that ELMAH logging remains enabled.

ELMAH Compared with Related Diagnostic Approaches

ApproachPrimary purposeBest fitKey limitation
ELMAHCapture and browse classic ASP.NET errorsExisting Web Forms or MVC applicationsTargets classic ASP.NET and provides limited modern observability.
Structured logging with log4net, NLog, or SerilogRecord application events with structured fieldsBusiness events, diagnostics, and custom contextRequires deliberate instrumentation and a log destination.
Centralized log aggregationSearch and correlate logs from many hosts and servicesDistributed or multi-server systemsRequires ingestion, access control, retention, and operating cost.
APM and distributed tracingMeasure performance and follow work across servicesLatency, dependency, and production performance analysisMore complex and not a complete replacement for application logs.
Error-notification serviceAlert operators about selected failuresIncident response and ownership workflowsAlerts can be noisy and do not replace durable diagnostic records.
ASP.NET Core logging alternativesDiagnostics for ASP.NET Core applicationsNewer .NET applicationsClassic ELMAH packages are generally not the correct integration model.

ELMAH is a reasonable fit when maintaining a classic ASP.NET application and needing a quick, familiar error store and viewer. ASP.NET Core applications generally use the built-in logging abstractions, compatible services such as ELMAH.io where appropriate, or modern structured logging stacks. Centralized logging, tracing, APM, and alerting are often better complements—or replacements—when the system spans services or requires correlation and proactive detection.

Practical Verification Checklist

  1. Install the compatible ELMAH package and deploy its assemblies.
  2. Choose memory, XML, SQL Server, SQLite, Oracle, PostgreSQL, or another supported provider.
  3. Configure the provider and its connection, schema, or file permissions.
  4. Register the module and handler for the actual hosting pipeline.
  5. Protect the viewer and RSS endpoint from anonymous access.
  6. Trigger a controlled unhandled exception in a safe environment.
  7. Confirm the viewer shows the exception, URL, status, stack trace, and timestamp.
  8. Confirm remote users receive a safe error page rather than detailed diagnostics.
  9. Test a deliberately filtered request and a real unfiltered exception.
  10. Restart the application and verify durable storage when using a persistent provider.
  11. Document retention, purge, backup, access review, and logger-health procedures.

For a focused reference, see ELMAH error logging for classic ASP.NET.