---
title: Search application error logs
summary: Builds a dynamic filtered query over App_Error and returns up to 300 rows plus a matching total count.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-07-30
library: SAIF.Application.LogView
reference_type: package
operation_id: OP-LV-04
trigger: Caller invokes a clsAppErrorCollection.GetAppErrorCollection overload with zero or more filters
---

# Search application error logs

`clsAppErrorCollection` exposes three `GetAppErrorCollection` factory overloads that all converge on the same criteria-driven retrieve: an optional date or date-range filter, optional machine/app/environment/user filters, and an optional full-text search term are assembled into a dynamic `WHERE` clause, then executed as a paired row query (capped at 300 rows) and count query.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-LV-04 |
| **Trigger** | Caller calls `GetAppErrorCollection(inDataportal, inErrorDate)`, `GetAppErrorCollection(inCriteria)`, or `GetAppErrorCollection(inDataportal, inErrorDate, inMachineName, inEnvironment, inAppName, inUserName)` |
| **Inputs** | `IDataPortalInfo`; optional `ErrorDate`, `StartDate`/`EndDate` range, `MachineName`, `AppName`, `Environment`, `UserName`, `SearchText`, `OrderByField`, `OrderByDir` on the `Criteria` object |
| **Outputs** | `clsAppErrorCollection` populated with up to 300 `clsAppError` child objects; `TotalCount` set to the full matching row count |
| **Primary components** | `clsAppErrorCollection.GetAppErrorCollection` (three overloads), `clsAppErrorCollection.Criteria.BuildWhere`, `clsAppErrorCollection.Criteria.BuildOrder`, `clsAppErrorCollection.Criteria.GetSearchValue`, `clsAppErrorCollection.BeforeRetrieve`, `clsAppErrorCollection.AfterRetrieve` |
| **Entry point** | `Application\SAIF.Application.LogView\clsAppErrorCollection.vb` |

## Steps

1. **Select an entry overload.** The simplest overload takes only an `ErrorDate` and wraps it in a new `Criteria`; the caller-supplied-criteria overload passes a pre-built `Criteria` straight through; the five-filter overload constructs a `Criteria` and assigns `ErrorDate`, `MachineName`, `Environment`, `AppName`, and `UserName` before retrieving. All three ultimately call `inDataportal.DataAccessLayer.RetrieveObject(...)` with a `Criteria` instance.
2. **Build the `WHERE` clause (`BuildWhere`).**
   - Date filtering: if both `StartDate` and `EndDate` are set (greater than `Date.MinValue`), add an inclusive range predicate `Error_Date >= '<StartDate 00:00>' and Error_Date <= '<EndDate 23:59>'` built by direct string formatting (not a bound parameter). Otherwise, if a single `ErrorDate` is set, add `cast(cast(Error_Date as varchar(11)) as datetime) = @ErrorDate` to match on the date portion only.
   - Machine/app filters: if `MachineName` or `AppName` is non-empty and does not contain the literal `[ALL]`, add an equality predicate for that field ([BR-002](../business-rules.md#br-002-all-sentinel-suppresses-selected-filters)).
   - Environment filter: if `Environment` is non-empty and not `[ALL]`, split on `;` and build the value directly into a quoted `IN (...)` list ([BR-003](../business-rules.md#br-003-semicolon-delimited-filters-expand-to-sql-in-lists)).
   - User filter: if `UserName` contains `;`, split it the same way into an `IN (...)` list; otherwise add a single `like @UserName` predicate.
   - Full-text filter: if `SearchText` is non-empty, append `CONTAINS((Error_Info, State_Info, Error_Source), @SEARCHTEXT)` ([BR-004](../business-rules.md#br-004-search-text-is-normalized-for-full-text-queries)).
   - Any leading `AND` produced by the assembly is trimmed from the final string.
3. **Normalize the search text (`GetSearchValue`), when `SearchText` is supplied.**
   - Strip double and single quotes from the raw search text.
   - Split the remaining text on spaces, commas, and semicolons.
   - If the original text contains any of the logic-operator tokens (`" AND "`, `"&"`, `" OR "`, `"|"`, `"&!"`), preserve each recognized operator token unquoted and wrap every other token in double quotes.
   - Otherwise, wrap every token in double quotes and join them with `AND`.
   - The resulting expression is bound to `@SEARCHTEXT` on both the row query and the count query.
4. **Build the sort clause (`BuildOrder`), row query only.** If `OrderByField` is set, look it up (case-insensitively, by property name or column name) in the `SortableFields` dictionary (`AppName`, `DeletedFlag`, `Environment`, `ErrorDate`, `MachineName`, `PageName`, `UserName`, `ErrorSource`) and append `ASC` or `DESC` per `OrderByDir` (default `Descending`). If `OrderByField` is empty, default to `ORDER BY Error_Date DESC`.
   - If `OrderByField` does not match any known field, the LINQ lookup returns an empty string and the resulting `ORDER BY` clause has no column before the sort direction, which is not valid SQL syntax as constructed.*
5. **Configure the retrieve requests (`BeforeRetrieve`).** Two data requests are queued in the same call: a `ResultSet` request using `RetrieveSQL` (`SELECT TOP 300 ...` plus the built `WHERE`/`ORDER BY`) ([SQL-005](../sql/SQL-005-saif-application-logview.md), [App_Error](../database-tables.md#app_error)) ([BR-001](../business-rules.md#br-001-search-results-are-capped-at-300-rows)), and a `Scalar` request using `RetrieveSQLCount` (`SELECT Count(*) ...` with the same `WHERE`) ([SQL-006](../sql/SQL-006-saif-application-logview.md), [App_Error](../database-tables.md#app_error)). Both bind `@ErrorDate` (only when in range), `@MachineName`, `@Username`, `@AppName`, and `@SEARCHTEXT` (only when `SearchText` is non-empty).
6. **Load the results (`AfterRetrieve`).** For every row in the first result set, create a new `clsAppError`, call `Load(...)` on it (which fills fields and marks the object old), and add it to the collection via `MyBase.Add`. Set `TotalCount` from the second (scalar count) request. Clear `MyCriteria.IsDirty`.

## Process flow

The following diagram visualizes the filter-build, execute, and load sequence.

```mermaid
flowchart TD
	Start([Caller calls GetAppErrorCollection]) --> Build[BuildWhere: date, machine,<br>app, environment, user, search-text predicates]
	Build --> Search{SearchText supplied?}
	Search -->|Yes| Normalize[GetSearchValue: strip quotes,<br>tokenize, preserve logic operators]
	Search -->|No| Order
	Normalize --> Order[BuildOrder: map OrderByField<br>via SortableFields or default Error_Date DESC]
	Order --> Rows[Execute TOP 300 row query]
	Rows --> Count[Execute matching COUNT query]
	Count --> Load[Load each row into a<br>new clsAppError; set TotalCount]
	Load --> Done([Collection and TotalCount returned])
```

## Failure and edge-case behavior

- The row query is hard-capped at 300 rows ([BR-001](../business-rules.md#br-001-search-results-are-capped-at-300-rows)) even when `TotalCount` reports more matches, so a caller filtering on a broad range never sees the full result set through the row query alone.
- The start/end date range predicate is built by direct string concatenation of formatted dates rather than a bound parameter, unlike every other filter in `BuildWhere`.*
- An unrecognized `OrderByField` value produces a syntactically incomplete `ORDER BY` clause (no column name before the sort direction), which would fail at execution rather than silently falling back to the default sort.*
- `UserName` filtering branches on whether the value contains `;`: a single value uses `like @UserName` (partial match), while multiple semicolon-delimited values use an exact `IN (...)` list — the matching semantics differ between the single- and multi-value cases.*
- `SearchText` normalization strips all quote characters from the raw input before tokenizing, so a search phrase intended to be treated as a single literal loses any caller-supplied quoting.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [SQL catalog](../sql/index.md)
- [Database tables](../database-tables.md)

> **Note:** Statements marked with `*` were inferred from code structure, naming
> conventions, or contextual evidence where direct confirmation was not available
> in source artifacts.

## Sources
- `Application\SAIF.Application.LogView\clsAppErrorCollection.vb`
- `Application\SAIF.Application.LogView\modLogViewExtensions.vb`
