프로그래밍OS

[linux] 서버 로그 자동 삭제 쉘스크립트 생성 예제 및 크론탭(crontab) 등록 예제

톰켓 was 서버에서 톰켓 로그가

/usr/local/logs/test_api/ 폴더에 아래와 같은 형식으로 쌓인다.

test-api-dev.log.2025-11-01.0.gz

test-api-dev.log.2025-11-01.1.gz

test-api-dev.log.2025-11-01.2.gz

test-api-dev.log.2025-11-02.0.gz

test-api-dev.log.2025-11-03.0.gz

계속 쌓이면 서버 용량을 많이 먹어서 주기적으로 삭제해야한다.

crontab에 등록할 수 있게 만들어보자

조건은 오늘 날짜 기준으로 15일 이전 파일은 모두 삭제하는 것이다.


요구사항을 정리하면 다음과 같다:

  • 로그 경로: /usr/local/logs/test_api/
  • 파일명 패턴: test-api-dev.log.YYYY-MM-DD.N.gz
  • 오늘 날짜 기준 15일 이전의 파일 삭제
  • crontab으로 자동 실행

1. 삭제 스크립트 (delete_old_logs.sh) 생성

먼저 아래 내용을 스크립트 파일로 저장합니다.

#!/bin/bash

LOG_DIR="/usr/local/logs/test_api"

# 15일 이전의 .gz 파일을 삭제
find "$LOG_DIR" -type f -name "test-api-dev.log.*.gz" -mtime +15 -exec rm -f {} \;

# 로그 남기고 싶다면 (선택사항)
# find "$LOG_DIR" -type f -name "test-api-dev.log.*.gz" -mtime +15 -exec rm -f {} \; -exec echo "Deleted: {}" >> /usr/local/logs/test_api/cleanup.log \;

설명

  • -type f : 파일만 대상
  • -name "test-api-dev.log.*.gz" : 해당 패턴의 로그 파일만 찾음
  • -mtime +15 : 수정된지 15일 초과된 파일
  • -exec rm -f {} \; : 찾은 파일 삭제

2. 실행 권한 부여

chmod +x /usr/local/logs/test_api/delete_old_logs.sh

3. crontab 등록

crontab -e

매일 새벽 3시에 실행되게 설정하려면 다음 줄을 추가한다.

0 3 * * * /usr/local/logs/test_api/delete_old_logs.sh >/dev/null 2>&1

4. (선택) 테스트 방법

오늘 기준으로 테스트하려면 -mtime +15 대신 예를 들어 -mtime +0으로 바꿔서 실행해본다.

bash /usr/local/logs/test_api/delete_old_logs.sh

추가적으로 “삭제 내역을 날짜별로 기록하는 버전”도 만들어보자
(예: /usr/local/logs/test_api/cleanup.log 에 어떤 파일이 언제 삭제됐는지 로그 남기기)

로그는 /usr/local/logs/test_api/cleanup.log 파일에 남긴다.

#!/bin/bash

LOG_DIR="/usr/local/logs/test_api"
LOG_FILE="$LOG_DIR/cleanup.log"
RETENTION_DAYS=15

# 현재 날짜 출력
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 🔍 로그 정리 시작 (기준: ${RETENTION_DAYS}일 이전)" >> "$LOG_FILE"

# 오래된 로그 파일 찾기
DELETED_FILES=$(find "$LOG_DIR" -type f -name "test-api-dev.log.*.gz" -mtime +$RETENTION_DAYS)

if [ -z "$DELETED_FILES" ]; then
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] ✅ 삭제할 파일 없음" >> "$LOG_FILE"
else
  # 파일 삭제 및 로그 기록
  echo "$DELETED_FILES" | while read -r FILE; do
    if [ -f "$FILE" ]; then
      rm -f "$FILE"
      echo "[$(date '+%Y-%m-%d %H:%M:%S')] 🗑️ 삭제됨: $FILE" >> "$LOG_FILE"
    fi
  done
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] ✅ ${RETENTION_DAYS}일 이전 로그 정리 완료" >> "$LOG_FILE"
fi

echo "" >> "$LOG_FILE"

설명

  • RETENTION_DAYS=15 : 삭제 기준일 (15일 이전 파일)
  • 삭제 내역이 cleanup.log에 아래처럼 남습니다 👇
[2025-11-13 03:00:00] 🔍 로그 정리 시작 (기준: 15일 이전)
[2025-11-13 03:00:00] 🗑️ 삭제됨: /usr/local/logs/test_api/test-api-dev.log.2025-10-20.0.gz
[2025-11-13 03:00:00] 🗑️ 삭제됨: /usr/local/logs/test_api/test-api-dev.log.2025-10-20.1.gz
[2025-11-13 03:00:00] ✅ 15일 이전 로그 정리 완료

권한 및 cron 등록

chmod +x /usr/local/logs/test_api/delete_old_logs.sh
crontab -e
0 3 * * * /usr/local/logs/test_api/delete_old_logs.sh >> /usr/local/logs/test_api/cleanup_cron.log 2>&1

cleanup_cron.log에는 스크립트 실행 중 에러나 출력이 기록됩니다.
cleanup.log는 실제 어떤 파일이 삭제됐는지 기록됩니다.

“cleanup.log를 30일 이상 되면 자동 압축 or 삭제” 되도록 함께 관리하는 추가 스크립트도 만들어보자
(즉, 정리 로그도 무한히 쌓이지 않게 하는 버전이)

최종 버전: /usr/local/logs/test_api/delete_old_logs.sh

#!/bin/bash

LOG_DIR="/usr/local/logs/test_api"
LOG_FILE="$LOG_DIR/cleanup.log"
RETENTION_DAYS=15          # 로그 파일 삭제 기준일
CLEANUP_LOG_ROTATE_DAYS=30 # cleanup.log 관리 기준일

# 로그 시작
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 🔍 로그 정리 시작 (기준: ${RETENTION_DAYS}일 이전)" >> "$LOG_FILE"

# 오래된 로그 파일 삭제
DELETED_FILES=$(find "$LOG_DIR" -type f -name "test-api-dev.log.*.gz" -mtime +$RETENTION_DAYS)

if [ -z "$DELETED_FILES" ]; then
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] ✅ 삭제할 파일 없음" >> "$LOG_FILE"
else
  echo "$DELETED_FILES" | while read -r FILE; do
    if [ -f "$FILE" ]; then
      rm -f "$FILE"
      echo "[$(date '+%Y-%m-%d %H:%M:%S')] 🗑️ 삭제됨: $FILE" >> "$LOG_FILE"
    fi
  done
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] ✅ ${RETENTION_DAYS}일 이전 로그 정리 완료" >> "$LOG_FILE"
fi

# cleanup.log 자체 관리 (30일 지난 경우)
if [ -f "$LOG_FILE" ]; then
  FILE_DATE=$(date -r "$LOG_FILE" +%s)
  NOW_DATE=$(date +%s)
  AGE_DAYS=$(( (NOW_DATE - FILE_DATE) / 86400 ))

  if [ $AGE_DAYS -ge $CLEANUP_LOG_ROTATE_DAYS ]; then
    ARCHIVE_FILE="$LOG_DIR/cleanup_$(date '+%Y-%m-%d').log.gz"
    gzip -c "$LOG_FILE" > "$ARCHIVE_FILE"
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] 📦 cleanup.log 압축됨 → $ARCHIVE_FILE" >> "$LOG_FILE"
    # cleanup.log 초기화
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] 🔄 cleanup.log 파일 리셋" > "$LOG_FILE"
  fi
fi

echo "" >> "$LOG_FILE"

동작 요약

기능설명
🗑️ 로그 삭제test-api-dev.log.*.gz 파일 중 15일 이상 된 것 삭제
📦 cleanup.log 압축cleanup.log 파일이 마지막 수정된 지 30일 이상이면 gzip 압축
🔄 cleanup.log 리셋압축 후 새 cleanup.log로 초기화
📅 로그 기록모든 실행 내역이 cleanup.log에 남음

권한 설정

chmod +x /usr/local/logs/test_api/delete_old_logs.sh

crontab 설정 (매일 새벽 3시 실행)

crontab -e
0 3 * * * /usr/local/logs/test_api/delete_old_logs.sh >> /usr/local/logs/test_api/cleanup_cron.log 2>&1

결과 예시

cleanup.log

[2025-11-13 03:00:00] 🔍 로그 정리 시작 (기준: 15일 이전)
[2025-11-13 03:00:00] 🗑️ 삭제됨: /usr/local/logs/test_api/test-api-dev.log.2025-10-20.0.gz
[2025-11-13 03:00:00] ✅ 15일 이전 로그 정리 완료
[2025-11-13 03:00:00] 📦 cleanup.log 압축됨 → /usr/local/logs/test_api/cleanup_2025-11-13.log.gz
[2025-11-13 03:00:00] 🔄 cleanup.log 파일 리셋

원하신다면 이 스크립트를 서버 여러 경로에 적용할 수 있는 범용 버전(예: 여러 로그 폴더 관리용 LOG_DIRS=("path1" "path2") 배열 지원 버전)으로 만들어드릴 수도 있어요.

“여러 로그 경로”를 한 번에 관리할 수 있는 범용 자동 정리 스크립트 버전을 만들어드릴게요.
이 버전은 복수의 로그 디렉터리를 지정하면, 각각에 대해 15일 이상된 로그를 삭제하고, cleanup 로그도 30일 단위로 압축/초기화합니다.

범용 버전: /usr/local/logs/delete_old_logs_all.sh

#!/bin/bash

# ==========================================================
# 🔧 설정 영역
# ==========================================================

# 로그 디렉토리 여러 개 지정 가능
LOG_DIRS=(
  "/usr/local/logs/test_api"
  "/usr/local/logs/another_service"
  "/usr/local/logs/sample_app"
)

RETENTION_DAYS=15          # 각 서비스 로그 삭제 기준일
CLEANUP_LOG_ROTATE_DAYS=30 # cleanup.log 관리 기준일

# ==========================================================
# 🚀 실행 로직
# ==========================================================

for LOG_DIR in "${LOG_DIRS[@]}"; do
  LOG_FILE="$LOG_DIR/cleanup.log"

  # 디렉토리 존재 여부 확인
  if [ ! -d "$LOG_DIR" ]; then
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] ⚠️ 경로 없음: $LOG_DIR"
    continue
  fi

  echo "[$(date '+%Y-%m-%d %H:%M:%S')] 🔍 로그 정리 시작 (디렉토리: $LOG_DIR, 기준: ${RETENTION_DAYS}일 이전)" >> "$LOG_FILE"

  # 오래된 .gz 로그 삭제
  DELETED_FILES=$(find "$LOG_DIR" -type f -name "*.log.*.gz" -mtime +$RETENTION_DAYS)

  if [ -z "$DELETED_FILES" ]; then
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] ✅ 삭제할 파일 없음" >> "$LOG_FILE"
  else
    echo "$DELETED_FILES" | while read -r FILE; do
      if [ -f "$FILE" ]; then
        rm -f "$FILE"
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] 🗑️ 삭제됨: $FILE" >> "$LOG_FILE"
      fi
    done
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] ✅ ${RETENTION_DAYS}일 이전 로그 정리 완료" >> "$LOG_FILE"
  fi

  # cleanup.log 관리
  if [ -f "$LOG_FILE" ]; then
    FILE_DATE=$(date -r "$LOG_FILE" +%s)
    NOW_DATE=$(date +%s)
    AGE_DAYS=$(( (NOW_DATE - FILE_DATE) / 86400 ))

    if [ $AGE_DAYS -ge $CLEANUP_LOG_ROTATE_DAYS ]; then
      ARCHIVE_FILE="$LOG_DIR/cleanup_$(date '+%Y-%m-%d').log.gz"
      gzip -c "$LOG_FILE" > "$ARCHIVE_FILE"
      echo "[$(date '+%Y-%m-%d %H:%M:%S')] 📦 cleanup.log 압축됨 → $ARCHIVE_FILE" >> "$LOG_FILE"
      echo "[$(date '+%Y-%m-%d %H:%M:%S')] 🔄 cleanup.log 파일 리셋" > "$LOG_FILE"
    fi
  fi

  echo "" >> "$LOG_FILE"
done

설정 방법

파일 저장 및 권한 부여

sudo vi /usr/local/logs/delete_old_logs_all.sh
sudo chmod +x /usr/local/logs/delete_old_logs_all.sh

LOG_DIRS 수정

관리할 로그 경로를 배열에 넣기만 하면 됩니다 👇

LOG_DIRS=(
  "/usr/local/logs/test_api"
  "/usr/local/logs/other_api"
  "/usr/local/logs/myapp"
)

crontab 등록 (매일 새벽 3시)

crontab -e
0 3 * * * /usr/local/logs/delete_old_logs_all.sh >> /usr/local/logs/cleanup_cron.log 2>&1

결과 예시

각 로그 폴더에 다음과 같은 로그 파일이 생성됩니다 👇

/usr/local/logs/test_api/cleanup.log

[2025-11-13 03:00:00] 🔍 로그 정리 시작 (디렉토리: /usr/local/logs/test_api, 기준: 15일 이전)
[2025-11-13 03:00:00] 🗑️ 삭제됨: /usr/local/logs/test_api/test-api-dev.log.2025-10-20.0.gz
[2025-11-13 03:00:00] ✅ 15일 이전 로그 정리 완료

/usr/local/logs/sample_app/cleanup.log

[2025-11-13 03:00:00] 🔍 로그 정리 시작 (디렉토리: /usr/local/logs/sample_app, 기준: 15일 이전)
[2025-11-13 03:00:00] ✅ 삭제할 파일 없음

보너스 옵션 (선택)

원하면 아래처럼 옵션을 줄 수도 있습니다.

옵션설명
RETENTION_DAYS=10로그 삭제 기준을 10일로 단축
CLEANUP_LOG_ROTATE_DAYS=7cleanup.log를 1주일마다 압축/리셋
-name "*.gz"모든 gzip 로그 포함 (서비스명 상관없이)

원하시면 이 스크립트를 /etc/logrotate.d 방식으로 통합해서, 시스템 표준 logrotate 정책에 맞게 관리하는 버전도 만들 수 있다.
(즉, cron 없이 logrotate 만으로 자동 압축/삭제/로테이션 수행)

파일이 아래처럼 되어 있는 SLOT_YYYYMMDD_NN.log 형식의 일반 로그 파일의 경우에는 좀 더 복잡하다.

SLOT_20251101_01.log

SLOT_20251101_02.log

SLOT_20251102_01.log

SLOT_20251103_01.log

즉, 날짜는 파일명 중간(SLOT_YYYYMMDD_)에 포함되어 있고, 파일 수정일(mtime)이 아니라 파일명 기준으로 날짜 판단해야 하는 상황이죠.

핵심 아이디어

  1. 파일명에서 날짜 부분(YYYYMMDD) 추출
  2. 현재 날짜(YYYYMMDD)와 비교
  3. 15일 이전이면 삭제

예제 스크립트 (날짜 파싱 기반)

#!/bin/bash

LOG_DIR="/usr/local/logs/test_api"
LOG_FILE="$LOG_DIR/cleanup.log"
RETENTION_DAYS=15

# 현재 날짜 기준 (초 단위)
CURRENT_TS=$(date +%s)

echo "[$(date '+%Y-%m-%d %H:%M:%S')] 🔍 SLOT 로그 정리 시작 (기준: ${RETENTION_DAYS}일 이전)" >> "$LOG_FILE"

# SLOT_YYYYMMDD_*.log 파일 반복 처리
for FILE in "$LOG_DIR"/SLOT_*.log; do
  # 파일이 없을 경우 스킵
  [ -e "$FILE" ] || continue

  # 파일명에서 날짜 부분 추출 (예: SLOT_20251101_01.log → 20251101)
  BASENAME=$(basename "$FILE")
  FILE_DATE=$(echo "$BASENAME" | grep -oE '[0-9]{8}' | head -1)

  # 날짜가 없는 파일은 스킵
  if [ -z "$FILE_DATE" ]; then
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] ⚠️ 날짜 추출 실패: $BASENAME" >> "$LOG_FILE"
    continue
  fi

  # 날짜를 초단위 timestamp로 변환
  FILE_TS=$(date -d "$FILE_DATE" +%s 2>/dev/null)

  # 변환 실패 (잘못된 날짜 형식)
  if [ -z "$FILE_TS" ]; then
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] ⚠️ 날짜 변환 실패: $BASENAME" >> "$LOG_FILE"
    continue
  fi

  # (현재 - 파일날짜) → 일수 계산
  AGE_DAYS=$(( (CURRENT_TS - FILE_TS) / 86400 ))

  # 기준 초과시 삭제
  if [ $AGE_DAYS -gt $RETENTION_DAYS ]; then
    rm -f "$FILE"
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] 🗑️ ${AGE_DAYS}일 경과 → 삭제됨: $BASENAME" >> "$LOG_FILE"
  fi
done

echo "[$(date '+%Y-%m-%d %H:%M:%S')] ✅ 정리 완료" >> "$LOG_FILE"
echo "" >> "$LOG_FILE"

작동 예시

현재 날짜가 2025-11-13일 때:

파일명날짜일수 경과처리결과
SLOT_20251101_01.log2025-11-0112일유지
SLOT_20251025_01.log2025-10-2519일✅ 삭제
SLOT_20251015_01.log2025-10-1529일✅ 삭제

crontab 등록 (매일 새벽 3시 실행)

0 3 * * * /usr/local/logs/test_api/cleanup_slot_logs.sh >> /usr/local/logs/test_api/cleanup_cron.log 2>&1

확장 가능 버전

이걸 아까 만든 multi-directory 범용 버전에도 통합할 수 있습니다.
즉, 각 경로별로 "패턴:보관일:형식" 이런 식으로 관리하도록요.
예시

LOG_CONFIGS=(
  "/usr/local/logs/test_api:SLOT_*.log:15:filename"
  "/usr/local/logs/payment:*.gz:30:mtime"
)

원하신다면 이 “혼합형 (mtime + 파일명 날짜 둘 다 지원)” 버전으로 만들어드릴까요?
즉, 어떤 디렉터리는 mtime 기준, 어떤 곳은 파일명 날짜 기준으로 자동 구분 삭제하는 통합 스크립트입니다.

SLOT_20251101_01.log 파일처럼

API_20251101_01.log

DEV__20251101_01.log 여러개 파일 경우에는?

  • 로그 파일명이 다양함 SLOT_20251101_01.log API_20251101_01.log DEV__20251101_01.log
  • 공통 규칙: 파일명 어딘가에 날짜(YYYYMMDD)가 들어있다.
  • 이 날짜를 기준으로 오늘 기준 N일(예: 15일) 이전 파일은 삭제해야 함.

즉, 이제 SLOT, API, DEV__ 등 prefix가 달라도 날짜만 잘 뽑으면 삭제 로직은 동일해야 해요.


통합 버전: cleanup_by_filename_date.sh

#!/bin/bash

LOG_DIR="/usr/local/logs/test_api"
LOG_FILE="$LOG_DIR/cleanup.log"
RETENTION_DAYS=15

CURRENT_TS=$(date +%s)

echo "[$(date '+%Y-%m-%d %H:%M:%S')] 🔍 파일명 날짜 기반 로그 정리 시작 (기준: ${RETENTION_DAYS}일 이전)" >> "$LOG_FILE"

# 모든 .log 파일 순회
for FILE in "$LOG_DIR"/*.log; do
  [ -e "$FILE" ] || continue

  BASENAME=$(basename "$FILE")

  # 파일명에서 날짜 추출 (YYYYMMDD)
  FILE_DATE=$(echo "$BASENAME" | grep -oE '[0-9]{8}' | head -1)

  # 날짜 없는 파일은 스킵
  if [ -z "$FILE_DATE" ]; then
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] ⚠️ 날짜 추출 실패 → $BASENAME" >> "$LOG_FILE"
    continue
  fi

  # 날짜 유효성 검사 (존재하지 않는 날짜 방지)
  if ! date -d "$FILE_DATE" >/dev/null 2>&1; then
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] ⚠️ 잘못된 날짜 형식 → $BASENAME" >> "$LOG_FILE"
    continue
  fi

  FILE_TS=$(date -d "$FILE_DATE" +%s)
  AGE_DAYS=$(( (CURRENT_TS - FILE_TS) / 86400 ))

  # 기준 초과시 삭제
  if [ $AGE_DAYS -gt $RETENTION_DAYS ]; then
    rm -f "$FILE"
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] 🗑️ ${AGE_DAYS}일 경과 → 삭제됨: $BASENAME" >> "$LOG_FILE"
  fi
done

echo "[$(date '+%Y-%m-%d %H:%M:%S')] ✅ 파일명 날짜 기반 정리 완료" >> "$LOG_FILE"
echo "" >> "$LOG_FILE"

동작 방식

파일명추출된 날짜경과 일수처리 결과
SLOT_20251101_01.log2025110112일유지
API_20251020_03.log2025102024일✅ 삭제
DEV__20251010_01.log2025101034일✅ 삭제

✅ 스크립트 요약

  • grep -oE '[0-9]{8}' : 파일명에서 8자리 숫자(YYYYMMDD) 추출
  • date -d "$FILE_DATE" : 날짜 유효성 검사
  • ((CURRENT_TS - FILE_TS) / 86400) : 경과 일수 계산
  • rm -f : 15일 초과 시 삭제

crontab 자동 실행 (매일 새벽 3시)

0 3 * * * /usr/local/logs/test_api/cleanup_by_filename_date.sh >> /usr/local/logs/test_api/cleanup_cron.log 2>&1

확장할 수 있는 버전 예시

만약 여러 경로를 관리하려면 아래처럼 LOG_DIRS 배열 버전으로 바꿀 수 있습니다 👇

LOG_DIRS=(
  "/usr/local/logs/test_api"
  "/usr/local/logs/payment"
  "/usr/local/logs/dev"
)

for DIR in "${LOG_DIRS[@]}"; do
  # 위에서 작성한 파일명 기반 삭제 로직 반복
done

error: Content is protected !!