---
module: agent.log
title: Agent Log — self-log upload & error-to-incident monitoring
tab: Claude
order: 40
audience: dev
---

> **Internal · agent reference.** Terse. Confirmed against `hiveops-module-log` source (`com.hiveops.logs`) 2026-07-01.

## Identity
- Maven artifact: **`hiveops-module-log`** (own version `1.0.0`; parent `hiveops-agent-parent` `4.4.3`)
- Drop-in JAR: **`modules/hiveops-module-log.jar`** (finalName = artifactId; NOT in fat JAR)
- SPI file `META-INF/services/com.hiveops.core.module.AgentModule` registers **two** modules:
  - `com.hiveops.logs.LogUploadModule` → `AgentModule.getName()` = **`log-upload`** (no deps)
  - `com.hiveops.logs.LogMonitorModule` → `AgentModule.getName()` = **`log-monitor`** (depends on `log-upload`)
- Upload helper: `com.hiveops.logs.AgentLogUploader` — lives in **`hiveops-agent-journal`**, not this jar (provided scope).
- `getLogPackage()` NOT overridden → own logging goes to root **`logs/hiveops-agent.log`** (no `logs/modules/log*.log`).
- `isHealthy()` NOT overridden → always `true` (watchdog won't catch a dead scheduler).
- Monitored/uploaded file: `logs/hiveops-agent.log` under sysprop `hiveops-agent.log` base, else `{startedFromDir}/logs/hiveops-agent.log`.

## Config property keys (exact)
| Key | Default | Module |
|---|---|---|
| `incident.log.upload.enabled` | `true` | log-upload master switch |
| `log.upload.interval.minutes` | `15` | log-upload cadence (also fires once on start) |
| `incident.log.monitor.enabled` | `true` | log-monitor master switch |
| `log.monitor.interval.minutes` | `5` | log-monitor scan cadence (first scan delayed 1 interval) |
| `log.monitor.cooldown.minutes` | `120` | min gap between error reports |
| `log.monitor.error.threshold` | `1` | min errors in a scan to report |
| `log.monitor.max.samples` | `5` | max sample error lines sent (each ≤200 chars) |
| `agent.endpoint` (pref) / `incident.endpoint` (fallback) | — | HTTP base URL; if both blank → both modules self-disable |
| `agent.*` / `incident.*` client settings | — | auth token / host header via `HttpClientHelper.loadSettingsFromProperties(props, "agent"\|"incident")` |
| `modules.disabled` | — | comma list; include `log-upload` and/or `log-monitor` to disable |

- `isEnabled()` = endpoint set **AND** the module's own `enabled` flag true **AND** settings built.
- No `getDefaultConfiguration()` override — defaults are the inline `getProperty(key, default)` values above only.

## Events / reports emitted
- **NO journal `EventType` / `IAT_*` events.** Does not call `IncidentEventClient`. Does NOT report fleet task status.
- **log-upload:** multipart `POST {endpoint}/api/agent/{country}/{atm}/log/upload` — boundary `----HiveOpsLogUploadBoundary`, part `file`, filename `hiveops-agent.log`, `text/plain`. (matches agent-proxy `AgentLogController`.)
- **log-monitor:** JSON `POST {endpoint}/atm/log-error?country={c}&name={n}` — body `{"errorCount":N,"warnCount":N,"sampleErrors":[...]}`. Backend → **`SOFTWARE_ERROR`** incident (dedup + parked/OOS suppression in `IncidentAutoCreationService`).

## Error-line detection
- Regex: `^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}[.,]\d+\s+(ERROR|FATAL|WARN)\s+(.+)$`
- `ERROR`+`FATAL` → `errorCount`; `WARN` → `warnCount` (counted, not reported as errors).
- Tails via `RandomAccessFile.seek(lastCheckedPosition)`; re-decodes each line ISO-8859-1 bytes → UTF-8.
- Rotation handling: if file size < last offset → reset offset to 0. Offsets are **in-memory only** (restart re-reads whole current file).

## Deployment
- In **BOTH** `atm` and `srv` module sets of `deployment/build-dist.sh` → ships in every install/patch ZIP.
- On by default on any device with an endpoint set.
- Disable: `modules.disabled=log-upload,log-monitor` via `CONFIG_UPDATE` fleet task.
- Retrofit: `INSTALL_MODULE` fleet task (drops jar, restarts agent) or full agent update.
- Upload cap: agent-proxy rejects >**50 MB** with `413`.

## Gotchas
- **Monitor endpoint mismatch:** module POSTs `/atm/log-error?country=&name=`, but agent-proxy's error route is `/api/agent/{country}/{atm}/log/errors`. Whether a rewrite bridges them / whether error-to-incident currently works is **unverified** — check live agent-proxy + nginx before trusting it. (Upload path is fine — it matches.)
- Two module names, one jar — `modules.disabled` must name `log-upload` and/or `log-monitor`, NOT `hiveops-module-log` / `log`.
- Only the **single current** `hiveops-agent.log` is uploaded on schedule — rotated `.gz` files are NOT (those come via the separate `LOG_COLLECT`/`LOG_COLLECT_PATH` fleet commands through the same `AgentLogUploader`).
- First error scan is delayed one full `log.monitor.interval.minutes` after start; a startup error burst won't report until then.
- Sample lines truncated to 200 chars; only up to `max.samples` errors sent — the count is full, the samples are not.
- Cooldown + backend dedup mean a chronically-failing agent yields **one** `SOFTWARE_ERROR` incident, not a stream.
- `AgentLogUploader` is in `hiveops-agent-journal` (atm set), not this jar — srv-set classpath carrying it is **unverified**.

## Do NOT
- Do NOT expect journal/hardware events (`IAT_*`, `CARD_READER_*`, `CASSETTE_*`, any `EventType`) from this module — self-log only.
- Do NOT expect fleet task status reports — this module reports none.
- Do NOT invent extra property namespaces — only the `incident.log.*` / `log.upload.*` / `log.monitor.*` keys above exist.
- Do NOT assume error-to-incident works without verifying the `/atm/log-error` vs `/api/agent/.../log/errors` routing on the live proxy.
- Do NOT disable via `modules.disabled=log` — use the exact names `log-upload` / `log-monitor`.
- Do NOT look for a `logs/modules/log*.log` — this module logs to the root `hiveops-agent.log`.
