logyard_deploy¶
Deploys the Logyard core platform on Ubuntu:
Loki single-binary runtime in Docker Compose
explicit Loki retention policy
Grafana datasource + dashboard provisioning into the shared Graphyard Grafana instance
local JSON health endpoint for Nyxmon health and ingest-freshness checks
Features¶
installs Docker Engine + Compose if needed
supports
rsyncandgitdeploy methods for the leanlogyardservice reporuns Loki as
grafana/lokiwith filesystem-backed TSDB storageenforces retention with Loki compactor (
retention_enabled: true)creates a shared Docker network so Graphyard Grafana can query Loki by container name
copies Logyard dashboard assets into the shared Grafana provisioning tree
exposes
/.well-known/logyardon loopback for Nyxmon-compatible JSON checks
Required Variables¶
logyard_enabled: true
logyard_deploy_method: rsync
logyard_source_path: "/Users/jochen/projects/logyard"
When logyard_deploy_method is git, set:
logyard_git_repo: "https://github.com/ephes/logyard.git"
logyard_git_version: "main"
Key Variables¶
logyard_loki_image: "grafana/loki:3.5.11"
logyard_loki_host_port: 3101
logyard_retention_period: "336h"
logyard_grafana_enabled: true
logyard_grafana_container_name: "graphyard-grafana"
logyard_grafana_datasource_uid: "logyard-loki"
logyard_grafana_datasource_path: "/opt/apps/graphyard/site/deploy/grafana/provisioning/datasources/logyard.yaml"
logyard_health_enabled: true
logyard_health_port: 9105
logyard_health_path: "/.well-known/logyard"
logyard_health_selector: '{host="macmini",source_type="journald"}'
logyard_health_warning_window_seconds: 900
logyard_health_critical_window_seconds: 3600
See defaults/main.yml for the full variable set.
Retention¶
This role expects retention to be a real product decision, not an operator afterthought.
Default:
logyard_retention_period: "336h"(14d)
The rendered Loki config enables the compactor and retention deletion path.
Health Endpoint Contract¶
The role installs a tiny JSON endpoint for Nyxmon at:
http://127.0.0.1:9105/.well-known/logyard
Response shape includes:
statusloki.readyingest.warning_window_entriesingest.critical_window_entriesingest.warning_freshingest.critical_freshunits.<id>(only for units listed inlogyard_health_units)
Producer unit state¶
Ingest freshness only tells you that logs stopped arriving, and it cannot say so
until the freshness window runs dry (15 minutes for the warning window, 60 for the
critical one). logyard_health_units reports systemd unit state directly, so a
dead log producer is detected on the next poll instead:
logyard_health_units:
- id: vector
unit: vector.service
Each entry produces a units.<id> object:
{
"units": {
"vector": {
"unit": "vector.service",
"exists": true,
"load_state": "loaded",
"active_state": "active",
"sub_state": "running",
"result": "success",
"error": null
}
}
}
Notes:
The key set is stable. If the
systemctlprobe itself fails or times out, every field is still present but set tonullanderrorcarries the detail. In that caseexistsisnull, notfalse— a failed query means existence is unknown, not disproved. Anexists == trueassertion fails either way, which is intended.idis required and must not contain a dot, because monitoring check paths are dot-delimited —units.vector.active_stateis addressable,units.vector.service.active_statewould be ambiguous. There is no implicit fallback to the unit name, since unit names contain dots.idandunitmust both be strings. YAML turnsid: yesinto a boolean, which is rejected rather than coerced into the key"True".Entries that are malformed, missing
id/unit, carry a dotted or duplicateid, or fail to parse are reported underunits_rejected(present only when non-empty) rather than dropped. A misconfigured entry is then visible in the payload instead of silently monitoring nothing. Reasons:invalid_base64,invalid_json,not_a_list,not_an_object,missing_unit,missing_id,id_contains_dot,duplicate_id.The unit list reaches the service base64-encoded (
LOGYARD_HEALTH_UNITS_B64). systemd resolves%specifiers and backslash escapes insideEnvironment=values, so a raw JSON payload could be silently corrupted.existsis derived fromLoadState, not the exit code:systemctl showexits 0 even for a unit that does not exist. Assertexists == truealongsideactive_state == "active"so a typo in the unit name fails loudly rather than silently reportinginactiveforever.unitsis always present (possibly empty), so check paths have a stable shape.Unit state deliberately does not feed into the top-level
statusfield.statusdescribes Logyard’s own ingest health; producer liveness is a separate signal with its own check.The endpoint runs as the unprivileged
logyarduser.systemctl showis a read-only query and needs no elevation.The default is
[], since the producer is not necessarily colocated with the Logyard server. Set it per host.
Example Playbook¶
- hosts: macmini
become: true
roles:
- role: local.ops_library.logyard_deploy
vars:
logyard_enabled: true
logyard_deploy_method: rsync
logyard_source_path: "/Users/jochen/projects/logyard"
logyard_health_selector: '{host="macmini",source_type="journald"}'
Validation¶
systemctl status logyard
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}' | grep logyard-loki
curl -fsS http://127.0.0.1:3101/ready
curl -fsS http://127.0.0.1:9105/.well-known/logyard | jq .