Skip to content

Commit 5278009

Browse files
afernoelasticLove1
andauthored
Add logrotate to services (#137)
* Add logrotate to services * Disable logrotate service --------- Co-authored-by: Ekaterina Pantaz <katyapantaz@gmail.com>
1 parent 7b39d30 commit 5278009

6 files changed

Lines changed: 147 additions & 4 deletions

File tree

.woodpecker/e2e.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,6 +1071,7 @@ steps:
10711071
-e dexdo_image_tag=$CI_COMMIT_SHA
10721072
-e dexdo_seed_accounts=true
10731073
-e dexdo_seed_notes_src="$CI_WORKSPACE/$SEED_NOTES_WS"
1074+
-e dexdo_logrotate_enabled=false
10741075
10751076
assert_e2e_tests:
10761077
when:

deploy/ansible/README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,40 @@ roles/dexdo/
3737
compose.yml.j2 image-based compose (pulls from registry) -> <deploy_dir>/compose.yml
3838
api.yaml.j2 rendered to <deploy_dir>/config/api.<env>.yaml
3939
indexer.yaml.j2 rendered to <deploy_dir>/config/indexer.<env>.yaml
40+
logrotate.j2 rotation script for the logrotate sidecar -> <deploy_dir>/logrotate.sh
4041
```
4142

43+
## Logging
44+
45+
The api + indexer write their logs to files under `dexdo_logs_dir/<service>/`
46+
(bind-mounted to `/app/logs`). That dir defaults to `<deploy_dir>/logs`; point it
47+
at a separate disk/mount per env to keep logs off the system disk or surviving a
48+
redeploy. The services themselves
49+
rotate **daily** (`<service>.log.<date>` + `<service>.noise.log.<date>`
50+
via the `dodex-logging` crate, pruned to `LOG_MAX_FILES` days), so rotation is
51+
handled out of the box.
52+
53+
Daily rotation bounds age but not size. If you also need a **size** cap, the
54+
role ships an **optional `logrotate` sidecar** (off by default —
55+
`dexdo_logrotate_enabled`) that rotates the dated files by size with
56+
`copytruncate` (mandatory, since the services keep the files open), driven by
57+
busybox cron, in place; the app keeps appending to the current day's file.
58+
59+
Knobs (in `roles/dexdo/defaults/main.yml`, overridable per env):
60+
61+
- `dexdo_logs_dir` (default `<deploy_dir>/logs`) — host dir the logs are written
62+
to; point it at a data mount to keep logs off the system disk.
63+
- `dexdo_logrotate_enabled` (default `false`) — the app already rotates daily;
64+
turn on only when you also want a size cap on top.
65+
- `dexdo_logrotate_image` — image providing `logrotate` + `crond` + bash.
66+
- `dexdo_log_rotate_size` (default `2G`) / `dexdo_log_rotate_amount`
67+
(default `10`) — rotate at this size, keep this many compressed copies.
68+
- `dexdo_log_rotate_spec` (default `"*/5 *"`) — cron "minute hour" for the run
69+
(every 5 minutes).
70+
71+
For the app-side `LOG_DIR` / `LOG_MAX_FILES` knobs see
72+
[docs/deployment.md](../../docs/deployment.md#logs).
73+
4274
## Environments
4375

4476
Each environment is its own directory under `inventories/` — an inventory

deploy/ansible/roles/dexdo/defaults/main.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ dexdo_image_tag: latest-dev
2020

2121
# --- Host layout ------------------------------------------------------------
2222
dexdo_deploy_dir: /opt/dexdo
23+
# Where the services write their log files. Defaults under the deploy dir; break
24+
# it out to its own disk/mount per environment when you want logs off the system
25+
# disk or surviving a redeploy. Per-service subdirs `<dir>/api` and
26+
# `<dir>/indexer` are bind-mounted to /app/logs.
27+
dexdo_logs_dir: "{{ dexdo_deploy_dir }}/logs"
2328
# Run api + indexer with the host's network stack (network_mode: host) instead
2429
# of the compose bridge. Off by default. Turn on ONLY when the chain must be
2530
# reached over the host's 127.0.0.1 — e2e, where a co-located single-compose
@@ -89,5 +94,24 @@ dexdo_otel_endpoint: ""
8994
dexdo_otel_metrics_protocol: grpc
9095
dexdo_otel_service_name: dodex-indexer-test
9196

97+
# --- Logging & rotation -----------------------------------------------------
98+
# The api + indexer already write per-service, daily-rotated files under
99+
# `dexdo_logs_dir/<service>` (bind-mounted to /app/logs) via the dodex-logging
100+
# crate: <service>.log.<date> (+ .noise.log), pruned to LOG_MAX_FILES days — so
101+
# rotation is already handled and the logrotate sidecar below is OFF by default.
102+
# Optional logrotate sidecar: a tiny container that adds a SIZE cap on top of the
103+
# app's daily rotation (rotate by size, copytruncate since the services keep the
104+
# files open). Turn on per env only if you also need a size ceiling.
105+
dexdo_logrotate_enabled: false
106+
# Image providing `logrotate` + busybox `crond` + bash.
107+
dexdo_logrotate_image: docker.gosh.sh/logrotate:3.13.0
108+
# Rotate a log file once it reaches this size; keep this many rotated copies.
109+
dexdo_log_rotate_size: 2G
110+
dexdo_log_rotate_amount: 10
111+
# BusyBox crontab "minute hour" fields for the rotation run (the remaining
112+
# day/month/weekday fields are wildcarded). "*/5 *" -> every 5 minutes, so a
113+
# fast-growing log can't overshoot the size cap by much between checks.
114+
dexdo_log_rotate_spec: "*/5 *"
115+
92116
# --- Secrets (resolved from the env vault) ----------------------------------
93117
dexdo_kek_hex: "{{ vault_dexdo_kek_hex }}"

deploy/ansible/roles/dexdo/tasks/main.yml

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,19 @@
1717
loop:
1818
- "{{ dexdo_deploy_dir }}"
1919
- "{{ dexdo_deploy_dir }}/config"
20-
- "{{ dexdo_deploy_dir }}/logs/api"
21-
- "{{ dexdo_deploy_dir }}/logs/indexer"
20+
21+
# Logs live outside the deploy dir (see dexdo_logs_dir) so they can sit on their
22+
# own mount and survive a redeploy — one per-service subdir, bind-mounted to
23+
# /app/logs in each container.
24+
- name: Ensure log directories exist
25+
ansible.builtin.file:
26+
path: "{{ item }}"
27+
state: directory
28+
mode: "0750"
29+
loop:
30+
- "{{ dexdo_logs_dir }}"
31+
- "{{ dexdo_logs_dir }}/api"
32+
- "{{ dexdo_logs_dir }}/indexer"
2233

2334
- name: Render api config
2435
ansible.builtin.template:
@@ -58,6 +69,17 @@
5869
dest: "{{ dexdo_deploy_dir }}/compose.yml"
5970
mode: "0644"
6071

72+
# Rotation script for the logrotate sidecar (bind-mounted into it by the compose
73+
# file). Bind-mounts don't trigger a container recreate, so a script-only change
74+
# is applied by the explicit restart below rather than by `compose up`.
75+
- name: Render logrotate script (for the logrotate sidecar)
76+
ansible.builtin.template:
77+
src: logrotate.j2
78+
dest: "{{ dexdo_deploy_dir }}/logrotate.sh"
79+
mode: "0755"
80+
when: dexdo_logrotate_enabled | bool
81+
register: dexdo_logrotate_script
82+
6183
# Pulls the SHA-pinned images from the registry and (re)creates containers.
6284
# `--pull always` picks up a new tag; config-only changes are applied by the
6385
# "Restart dexdo stack" handler (bind-mounted YAML does not trigger a recreate).
@@ -67,3 +89,13 @@
6789
chdir: "{{ dexdo_deploy_dir }}"
6890
register: dexdo_compose_up
6991
changed_when: "'Started' in dexdo_compose_up.stderr or 'Recreated' in dexdo_compose_up.stderr or 'Created' in dexdo_compose_up.stderr or 'Pulled' in dexdo_compose_up.stderr"
92+
93+
# `compose up` above recreates the sidecar only when the compose file changed;
94+
# a change to logrotate.sh alone (bind-mounted) needs an explicit restart so the
95+
# running container re-reads it.
96+
- name: Restart logrotate sidecar when its script changed
97+
ansible.builtin.command:
98+
cmd: docker compose restart logrotate
99+
chdir: "{{ dexdo_deploy_dir }}"
100+
when: dexdo_logrotate_enabled | bool and dexdo_logrotate_script is changed
101+
changed_when: true

deploy/ansible/roles/dexdo/templates/compose.yml.j2

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ services:
7171
{% endif %}
7272
volumes:
7373
- ./config:/app/config:ro
74-
- ./logs/api:/app/logs
74+
- {{ dexdo_logs_dir }}/api:/app/logs
7575
restart: unless-stopped
7676
healthcheck:
7777
test: ["CMD", "curl", "-fsS", "http://127.0.0.1:{{ dexdo_api_port }}/readiness"]
@@ -100,5 +100,17 @@ services:
100100
LOG_DIR: /app/logs
101101
volumes:
102102
- ./config:/app/config:ro
103-
- ./logs/indexer:/app/logs
103+
- {{ dexdo_logs_dir }}/indexer:/app/logs
104104
restart: unless-stopped
105+
{% if dexdo_logrotate_enabled %}
106+
107+
logrotate:
108+
image: {{ dexdo_logrotate_image }}
109+
restart: unless-stopped
110+
volumes:
111+
- {{ dexdo_logs_dir }}:/logsdir
112+
- ./logrotate.sh:/logrotate.sh:ro
113+
command: ["/bin/bash", "/logrotate.sh"]
114+
init: true
115+
network_mode: "none"
116+
{% endif %}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#!/bin/bash
2+
# Rendered by Ansible (deploy/ansible/roles/dexdo/templates/logrotate.j2). Do NOT
3+
# edit on the host — it is overwritten on the next deploy; change the template.
4+
5+
set -e
6+
7+
# Guard: this rotates /etc/logrotate.d system-wide, so only ever run in a
8+
# container.
9+
if [[ -f /.dockerenv ]] || grep -Eq '(lxc|docker)' /proc/1/cgroup; then
10+
:
11+
else
12+
echo "Docker only!"
13+
exit 1
14+
fi
15+
16+
rm -f /etc/logrotate.d/*
17+
# Match the app's dated live files (<service>.log.<YYYY-MM-DD>, dodex-logging's
18+
# daily rotation) ONLY — the date is anchored so this does NOT also match
19+
# logrotate's own rotated output (<name>.1, .2.gz, ...), which would otherwise
20+
# be re-rotated on every run and defeat the retention count.
21+
cat >/etc/logrotate.d/dexdo <<EOF
22+
/logsdir/*/*.log.[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] {
23+
missingok
24+
rotate {{ dexdo_log_rotate_amount }}
25+
size {{ dexdo_log_rotate_size }}
26+
notifempty
27+
copytruncate
28+
compress
29+
delaycompress
30+
}
31+
EOF
32+
33+
cat /etc/logrotate.d/dexdo
34+
35+
chown 0:0 /etc/logrotate.d /etc/logrotate.d/dexdo
36+
chmod 755 /etc/logrotate.d
37+
chmod 644 /etc/logrotate.d/dexdo
38+
39+
echo "{{ dexdo_log_rotate_spec }} * * * /usr/sbin/logrotate -v /etc/logrotate.conf" > /etc/crontabs/root
40+
41+
echo "Starting crond"
42+
crond -f

0 commit comments

Comments
 (0)