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.
| Component | Purpose | Typical configuration location | Operational considerations |
|---|---|---|---|
ErrorLogModule | Observes unhandled application errors and sends them to the configured error log. | system.web/httpModules or system.webServer/modules | Must be registered in the correct IIS pipeline configuration. |
ErrorLog | Abstraction that persists and retrieves error records through a provider. | elmah section | Provider availability, permissions, retention, and capacity matter. |
ErrorFilterModule | Applies rules that suppress selected errors. | Module registration and filter configuration | Keep filters narrow so real failures are not hidden. |
ErrorLogPageFactory | Creates the ELMAH viewer and related error-detail handlers. | system.web/httpHandlers or system.webServer/handlers | Protect every exposed route, including alternate formats. |
ErrorMailModule | Optional module for email notifications about errors. | Module registration and ELMAH mail settings | Email is not a substitute for durable logging or alert deduplication. |
The normal flow is:
- A browser or other client sends a request.
- ASP.NET executes the request through its pipeline.
- An exception is not handled, or is allowed to continue to the pipeline.
ErrorLogModuleobserves the error and creates an ELMAH error record.- The configured
ErrorLogprovider writes the record to memory, files, or a database. - 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 elmahSome 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:
- Back up the existing
web.config. - Inspect any configuration changes made by NuGet.
- Choose a storage provider for the environment.
- Register the module and handlers if the package did not do so, or if your hosting mode requires explicit registration.
- Protect the viewer route before exposing the application outside a development machine.
- 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.
| Provider | Persistence | Best use case | Advantages | Limitations | Security and maintenance considerations |
|---|---|---|---|---|---|
| In-memory | Process memory | Short development tests | No external setup; fast | Lost on recycle; limited capacity; not suitable for multiple servers | Nothing durable is retained; never rely on it for production diagnosis. |
| XML file | Files on the application host | Development or low-volume single-server applications | Simple and inexpensive | File growth, concurrent access, local-disk dependency, weaker scale-out behavior | Grant write access only to the application identity and protect the directory from direct download. |
| SQL Server | Relational database | Production classic ASP.NET applications | Durable, queryable, supports multiple application instances | Requires schema, connectivity, capacity, and maintenance | Use least-privilege credentials, encryption where appropriate, indexes, backups, and purge jobs. |
| SQLite | Local database file | Development or small deployments | Portable and low operational overhead | File locking and write concurrency can limit scale-out | Protect the database file and its directory; verify provider compatibility. |
| Oracle | Oracle database | Organizations standardized on Oracle | Uses existing database operations | Provider and schema setup require Oracle-specific dependencies | Use managed credentials and standard database retention controls. |
| PostgreSQL | PostgreSQL database | Deployments using a compatible PostgreSQL provider | Durable and centralized | Requires a compatible provider package and schema setup | Apply 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.
| Control | Risk addressed | Recommended implementation | Verification method |
|---|---|---|---|
| Deny anonymous access | Public disclosure of stack traces and request data | Route-specific ASP.NET authorization | Request the route without credentials and expect denial. |
| Restrict roles or identities | Excessive internal access | Allow a small operations or administrator group | Test both an authorized and unauthorized account. |
| Use HTTPS | Network interception | Require HTTPS at IIS or the trusted proxy | Confirm HTTP redirects or is rejected. |
| Protect RSS and alternate routes | Bypassing the main viewer’s controls | Apply equivalent authorization and network rules | Test every configured endpoint. |
| Minimize sensitive data | Credential and PII exposure | Redact or avoid secrets; review captured fields | Inspect 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 pattern | Usually log? | Reasoning | Example filter condition |
|---|---|---|---|
| Missing favicon requested by browsers | Often no | Usually harmless repetitive noise | URL ends with /favicon.ico and status is 404 |
| Known health-check URL | Usually no for expected probes | Expected failures can obscure application failures | Exact health-check path and known monitor identity |
| Known bot probe for a nonexistent file | Sometimes no | Automated scans can produce high volume | Narrow URL pattern plus confirmed user agent or status |
| Unexpected application 500 | Yes | May indicate a real defect or outage | Do not broadly filter status 500 |
| Authentication or authorization failure | Usually yes or aggregate separately | May indicate attack activity or a broken client | Filter 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:
customErrorscontrols classic ASP.NET user-facing error behavior, especially local versus remote detail.httpErrorscontrols IIS-generated HTTP error responses.Application_ErrorinGlobal.asaxcan 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
| Approach | Primary purpose | Best fit | Key limitation |
|---|---|---|---|
| ELMAH | Capture and browse classic ASP.NET errors | Existing Web Forms or MVC applications | Targets classic ASP.NET and provides limited modern observability. |
| Structured logging with log4net, NLog, or Serilog | Record application events with structured fields | Business events, diagnostics, and custom context | Requires deliberate instrumentation and a log destination. |
| Centralized log aggregation | Search and correlate logs from many hosts and services | Distributed or multi-server systems | Requires ingestion, access control, retention, and operating cost. |
| APM and distributed tracing | Measure performance and follow work across services | Latency, dependency, and production performance analysis | More complex and not a complete replacement for application logs. |
| Error-notification service | Alert operators about selected failures | Incident response and ownership workflows | Alerts can be noisy and do not replace durable diagnostic records. |
| ASP.NET Core logging alternatives | Diagnostics for ASP.NET Core applications | Newer .NET applications | Classic 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
- Install the compatible ELMAH package and deploy its assemblies.
- Choose memory, XML, SQL Server, SQLite, Oracle, PostgreSQL, or another supported provider.
- Configure the provider and its connection, schema, or file permissions.
- Register the module and handler for the actual hosting pipeline.
- Protect the viewer and RSS endpoint from anonymous access.
- Trigger a controlled unhandled exception in a safe environment.
- Confirm the viewer shows the exception, URL, status, stack trace, and timestamp.
- Confirm remote users receive a safe error page rather than detailed diagnostics.
- Test a deliberately filtered request and a real unfiltered exception.
- Restart the application and verify durable storage when using a persistent provider.
- Document retention, purge, backup, access review, and logger-health procedures.
For a focused reference, see ELMAH error logging for classic ASP.NET.