feat(logging): wire LOG_DIR through env and align systemd helper
- logger uses config/env for LOG_DIR and LOG_LEVEL (single source of truth) - Document absolute LOG_DIR for wipe/redeploy (Jenkins) in env and .env.example - setup-kord-user-log-file.sh reads LOG_DIR from KORD_HOME/.env and syncs StandardOutput/StandardError/ExecStartPre mkdir to the same path Made-with: Cursor
This commit is contained in:
parent
5280f1987b
commit
dbadd936ca
|
|
@ -9,5 +9,6 @@ DATABASE_URL="postgresql://kord:password@localhost:5432/kord_db?schema=public"
|
|||
# Logging (log4js — file only under LOG_DIR, no console appender)
|
||||
# Levels: trace, debug, info, warn, error, fatal
|
||||
LOG_LEVEL=info
|
||||
# Daily log files; keep 7 rotated days (see logger.ts). Directory is created at startup if missing.
|
||||
# Log directory (kord.log + dated rotations). Relative = from process cwd; use an absolute path on servers
|
||||
# if the deploy directory is wiped (e.g. Jenkins): LOG_DIR=/var/lib/kord/logs
|
||||
LOG_DIR=logs
|
||||
|
|
@ -1,12 +1,35 @@
|
|||
#!/usr/bin/env bash
|
||||
# Run ON THE SERVER as the same user that runs kord (e.g. psa), after: ssh psa@server
|
||||
# Switches kord user service from journal-only to append logs under ~/kord/logs/kord.log
|
||||
# Switches kord user service from journal-only to append stdout/stderr under LOG_DIR/kord.log
|
||||
# LOG_DIR is read from $KORD_HOME/.env (LOG_DIR=...) when present, else $KORD_HOME/logs.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
KORD_HOME="${KORD_HOME:-$HOME/kord}"
|
||||
ENV_FILE="${KORD_ENV_FILE:-$KORD_HOME/.env}"
|
||||
UNIT="${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user/kord.service"
|
||||
LOG_DIR="$HOME/kord/logs"
|
||||
LOG_FILE="$LOG_DIR/kord.log"
|
||||
|
||||
# Last LOG_DIR= line from .env; strip quotes and ~ ; relative paths are under KORD_HOME
|
||||
resolve_log_dir() {
|
||||
local default="${KORD_HOME}/logs" line raw
|
||||
[[ -f "$ENV_FILE" ]] || { echo "$default"; return; }
|
||||
line="$(grep -E '^[[:space:]]*LOG_DIR[[:space:]]*=' "$ENV_FILE" | tail -n1 || true)"
|
||||
[[ -z "$line" ]] && { echo "$default"; return; }
|
||||
raw="${line#*=}"
|
||||
raw="$(printf '%s' "$raw" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' -e $'s/\r$//')"
|
||||
if [[ "$raw" =~ ^\".*\"$ ]]; then raw="${raw#\"}"; raw="${raw%\"}"; fi
|
||||
if [[ "$raw" =~ ^\'.*\'$ ]]; then raw="${raw#\'}"; raw="${raw%\'}"; fi
|
||||
raw="${raw//\~/$HOME}"
|
||||
[[ -z "$raw" ]] && { echo "$default"; return; }
|
||||
if [[ "$raw" = /* ]]; then
|
||||
echo "$raw"
|
||||
else
|
||||
echo "${KORD_HOME}/${raw#./}"
|
||||
fi
|
||||
}
|
||||
|
||||
LOG_DIR="$(resolve_log_dir)"
|
||||
LOG_FILE="${LOG_DIR}/kord.log"
|
||||
|
||||
mkdir -p "$LOG_DIR"
|
||||
|
||||
|
|
@ -17,17 +40,28 @@ fi
|
|||
|
||||
cp -a "$UNIT" "${UNIT}.bak.$(date +%Y%m%d%H%M%S)"
|
||||
|
||||
# Replace journal with file append (idempotent if already set)
|
||||
# Point journal or any previous append paths at the log file derived from .env LOG_DIR
|
||||
sed -i \
|
||||
-e 's|^StandardOutput=journal|StandardOutput=append:'"$LOG_FILE"'|' \
|
||||
-e 's|^StandardError=journal|StandardError=append:'"$LOG_FILE"'|' \
|
||||
-e "s|^StandardOutput=journal|StandardOutput=append:${LOG_FILE}|" \
|
||||
-e "s|^StandardError=journal|StandardError=append:${LOG_FILE}|" \
|
||||
"$UNIT"
|
||||
sed -i \
|
||||
-e "s|^StandardOutput=append:.*|StandardOutput=append:${LOG_FILE}|" \
|
||||
-e "s|^StandardError=append:.*|StandardError=append:${LOG_FILE}|" \
|
||||
"$UNIT"
|
||||
|
||||
# systemd opens StandardOutput=append before ExecStart; if ~/kord/logs was deleted,
|
||||
# the service fails with (code=exited, status=209/STDOUT). Ensure the dir exists first.
|
||||
if ! grep -qE '^ExecStartPre=.*mkdir.*kord/logs' "$UNIT"; then
|
||||
sed -i '/^ExecStart=/i ExecStartPre=-/usr/bin/mkdir -p %h/kord/logs' "$UNIT"
|
||||
fi
|
||||
# systemd opens StandardOutput=append before ExecStart; missing parent dir → status 209/STDOUT
|
||||
sed -i '/^ExecStartPre=-\/usr\/bin\/mkdir -p /d' "$UNIT"
|
||||
tmp="$(mktemp)"
|
||||
inserted=0
|
||||
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||
if [[ "$line" =~ ^ExecStart= ]] && [[ "$inserted" -eq 0 ]]; then
|
||||
printf '%s\n' "ExecStartPre=-/usr/bin/mkdir -p ${LOG_DIR}"
|
||||
inserted=1
|
||||
fi
|
||||
printf '%s\n' "$line"
|
||||
done <"$UNIT" >"$tmp"
|
||||
mv "$tmp" "$UNIT"
|
||||
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user restart kord
|
||||
|
|
@ -43,4 +77,5 @@ else
|
|||
fi
|
||||
|
||||
echo
|
||||
echo "LOG_DIR=$LOG_DIR"
|
||||
echo "Follow logs: tail -f $LOG_FILE"
|
||||
|
|
|
|||
|
|
@ -18,7 +18,11 @@ export const env = {
|
|||
VOICE_CATEGORY_ID: process.env.VOICE_CATEGORY_ID || '',
|
||||
/** log4js level: trace | debug | info | warn | error | fatal */
|
||||
LOG_LEVEL: process.env.LOG_LEVEL || 'info',
|
||||
/** Directory for rotated kord.log (see src/utils/logger.ts) */
|
||||
/**
|
||||
* Directory for log4js `kord.log` (created at startup). Relative paths resolve from `process.cwd()`.
|
||||
* For Jenkins or wipe-and-redeploy flows, set an absolute path **outside** the deploy tree (e.g. `/var/lib/kord/logs`)
|
||||
* so logs survive redeploys and match `StandardOutput=append` in systemd if you point it at the same file.
|
||||
*/
|
||||
LOG_DIR: process.env.LOG_DIR || 'logs',
|
||||
INSTANCE_ID: generateInstanceId(),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,19 +1,25 @@
|
|||
import { mkdirSync } from 'fs';
|
||||
import { config } from 'dotenv';
|
||||
import log4js from 'log4js';
|
||||
import { resolve } from 'path';
|
||||
|
||||
// Load .env before reading LOG_LEVEL / LOG_DIR (same rule as config/env.ts).
|
||||
config({ path: process.env.DOTENV_CONFIG_PATH || resolve(process.cwd(), '.env') });
|
||||
import { env } from '../config/env';
|
||||
|
||||
const LOG_LEVELS = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'] as const;
|
||||
type LogLevel = (typeof LOG_LEVELS)[number];
|
||||
|
||||
function resolveLogLevel(): LogLevel {
|
||||
const raw = (process.env.LOG_LEVEL || 'info').toLowerCase();
|
||||
const raw = env.LOG_LEVEL.toLowerCase();
|
||||
return (LOG_LEVELS as readonly string[]).includes(raw) ? (raw as LogLevel) : 'info';
|
||||
}
|
||||
|
||||
/** Resolves LOG_DIR from .env: absolute paths unchanged; relative paths from cwd. */
|
||||
function resolveLogDir(raw: string): string {
|
||||
const trimmed = raw.trim();
|
||||
if (!trimmed) {
|
||||
return resolve('logs');
|
||||
}
|
||||
return resolve(trimmed);
|
||||
}
|
||||
|
||||
function ensureLogDir(dir: string): void {
|
||||
try {
|
||||
mkdirSync(dir, { recursive: true });
|
||||
|
|
@ -24,7 +30,7 @@ function ensureLogDir(dir: string): void {
|
|||
}
|
||||
}
|
||||
|
||||
const logDir = resolve((process.env.LOG_DIR || 'logs').trim());
|
||||
const logDir = resolveLogDir(env.LOG_DIR);
|
||||
const level = resolveLogLevel();
|
||||
|
||||
ensureLogDir(logDir);
|
||||
|
|
|
|||
Loading…
Reference in New Issue