---
module: agent.win-app-events
title: Windows App Event Log Monitor — forwards Windows Application-log errors as HiveIQ incidents
tab: Claude
order: 40
audience: dev
---

> **Internal · agent reference.** Terse. Confirmed against `hiveops-module-win-app-events` source (`com.hiveops.winevents`) 2026-07-01.

## Identity
- Module name (`AgentModule.getName()`): **`win-app-events`**
- Maven artifact: **`hiveops-module-win-app-events`** (own version `1.0.1`; parent `hiveops-agent-parent` `4.4.3`)
- Entry class: `com.hiveops.winevents.WinAppEventModule` (SPI: `META-INF/services/com.hiveops.core.module.AgentModule`)
- Other classes: `WinAppEventPoller`, `WinAppEventParser`, `WinAppEvent`
- Log package (`getLogPackage()`): `com.hiveops.winevents`
- Dependencies: `getDependencies()` → **empty** (no ordering deps)
- Windows-only; Linux → `initialize()` no-ops (logs `not Windows, module inactive`)

## Config property keys (all `winevt.*`, from `hiveops.properties`)
| Key | Code default | Notes |
|---|---|---|
| `winevt.events.enabled` | **`false`** | Must be `true` to run. Javadoc claims default true — **code default is `false`**. |
| `winevt.events.levels` | `3` | Max level: 1=Critical, 2=Error, 3=Warning. Query is `Level>=1 and Level<=N`. |
| `winevt.events.sources` | `""` | CSV of Provider names; exact case-insensitive match; empty = all. |
| `winevt.events.poll.interval.sec` | `60` | Scheduler period (seconds). |
| `winevt.events.batch.size` | `50` | `wevtutil /c:` cap per call (NOT an HTTP batch). |
| `winevt.pattern.WIN_APP_EVENT_ERROR` | `""` | Regex, `.find()`, CASE_INSENSITIVE, on `"<provider> <eventId> <message>"`; empty/invalid = catch-all. |
| `winevt.events.suspended` | `false` | Hot-reload-only pause; poller keeps ticking, does nothing. |

- Endpoint/auth (not owned by this module): `agent.endpoint` (preferred) else `incident.endpoint` (fallback); prefix drives `HttpClientHelper.loadSettingsFromProperties(props, prefix)`.
- Disable via `modules.disabled=win-app-events` too.
- **Hot-reloadable (via `CONFIG_UPDATE` → `PatternReloadRegistry.trigger()`):** ONLY `winevt.pattern.WIN_APP_EVENT_ERROR` + `winevt.events.suspended`. Everything else needs an **agent restart** (captured in `initialize()`).

## Event emitted
- `EventType.WIN_APP_EVENT_ERROR` → `eventType = "WIN_APP_EVENT_ERROR"` (only event type this module emits)
- `eventSource = "HIVEOPS_AGENT_WINEVT"` (constant `EVENT_SOURCE`)
- `agentAtmId = <atmName>` (from `ModuleContext`)
- `eventDetails` format: `[Source: <provider>] [EventID: <id>] [Level: <Critical|Error|Warning|...>] <message>`
- No `IAT_*` events. No fleet-task status. Nothing else.

## Wire path
- `IncidentEventClient.sendEvents(list)` → loops `sendEvent` → **one** `POST {endpoint}/api/journal-events` **per event** (not batched).
- endpoint → `agent-proxy` → `hiveops-incident` journal-event ingest.

## wevtutil commands (exact)
- Anchor (1st tick): `wevtutil qe Application /rd:true /f:XML /c:1 /q:*[System[Level>=1 and Level<=<maxLevel>]]`
- Poll: `wevtutil qe Application /rd:false /f:XML /LNIFO:Message /c:<batchSize> /q:*[System[(Level>=1 and Level<=<maxLevel>) and (EventRecordID > <lastId>)]]`
- Channel is **Application** only. `/LNIFO:Message` renders provider-DLL message text.

## Filter order (per event)
1. Level — in the `wevtutil` XPath (`Level<=maxLevel`).
2. Source — `sourceFilter` non-empty → Provider name must case-insensitively equal an entry.
3. Pattern — `eventPattern != null` → regex `.find()` on `matchText()` = `"<provider> <eventId> <message>"`.
- Bookmark `lastEventRecordId` advances to max RecordID seen **even if all filtered**.

## Deployment
- Ships in the **`atm`** module set of `deployment/build-dist.sh` (default), NOT `srv`.
- Drop-in JAR `modules/hiveops-module-win-app-events.jar` (not in fat JAR).
- Retrofit: `INSTALL_MODULE` fleet task (drops JAR → restarts agent) or full standard-set update.

## Gotchas
- `winevt.events.enabled` defaults to **`false`** in code — module is OFF unless explicitly enabled. Do not trust the class Javadoc's "default true."
- First tick **anchors** to newest RecordID → **no historical replay**; only post-start events forward.
- Changing filters does **not** replay already-skipped RecordIDs (bookmark already advanced).
- `batch.size` bounds the `wevtutil` fetch, NOT the HTTP call — each event is a separate POST.
- Uses `os.name` + raw `ProcessBuilder`; does **not** use `PlatformService`/`SystemCommands`.
- Charset for `wevtutil` stdout = `file.encoding` system property; wrong code page → garbled messages.
- Only pattern + suspended hot-reload; `levels`/`sources`/`interval`/`batch` require restart.

## Do NOT
- Do NOT assume it's running by default — `winevt.events.enabled=true` is required (code default `false`).
- Do NOT expect historical/backfilled events after enable or restart — it anchors forward-only.
- Do NOT expect `IAT_*` or fleet-task-status output — it emits **only** `WIN_APP_EVENT_ERROR`.
- Do NOT treat `winevt.events.batch.size` as an HTTP batch size — POSTs are one-per-event.
- Do NOT expect `levels`/`sources`/`interval`/`batch` changes to hot-reload — only pattern + suspended do; restart otherwise.
- Do NOT look for a `PlatformService` code path — OS detection and `wevtutil` invocation are local to this module.
- Do NOT run it on Linux and expect activity — it silently no-ops off-Windows.
