#!/usr/bin/env python3
# Copyright 2026 SigmaSRC, Inc. All Rights Reserved.

"""Log rotation script.

Usage: %prog

There are no options or arguments.

This program deletes old log files.  All log files reside in
$AVDATA/log/.  There are two types of log files:

- log.YYYY-MM-DD.txt; these are structured log files written by the
  standard Python logging module.  Each log entry starts with a
  timestamp, an indication of the module that logged the entry, and a
  logging level (usually INFO, WARNING or ERROR), followed by a
  message.  The YYYY-MM-DD in the filename is the date pertaining to
  the log messages; a new log file is started each day by the logging
  code.

- debug.YYYY-MM-DD.txt; these are debugging log files, connected to
  stdout and stderr of the scheduler and all tasks run by the
  scheduler.  This file should contain very little output; you might
  see Python tracebacks here if the scheduler or a task died of an
  unhandled exception (this is always a bug), and you might see output
  here from the Poliwall (which does not use the Python logging
  package, but is normally completely quiet).  The YYYY-MM-DD in the
  filename is the date that the file was created; a new log file is
  only started when the scheduler is restarted.  (So, unlike for the
  structured log files, you may find current output in a debugging log
  file dated several days ago, if the scheduler has been up since that
  date.)

Files that do not match either of these patterns are left alone.

There's a configuration parameter, log-keep-days, specifying the
number of past log files of each type to keep; the default is 9 files.
The most recent log file of each type is never deleted.  Note that on
Unix, removing the current debugging log file does not free up the
space used by this file if a process is still writing to it; the only
way to recycle this disk space is to kill all processes that are
writing to it; normally stopping the agent should take care of this.

Note: logging uses local time.  The first line of the structured log
file show the UTC time it was started and the hostname.  The scheduler
writes a separator and the current date and time to the debugging log
file each time it is started.

"""

import os
import sys
import glob
import time
import shutil
import logging
import optparse

from sigma.util import avalog, config
from sigma.util.errors import usage, error

parser = optparse.OptionParser(usage=__doc__.strip())
logger = logging.getLogger("logrotate")
options = config.Options()
logdir = options.agentlogs

def main(args=None):
    opts, args = parser.parse_args(args)
    if args:
        return usage("This program takes no arguments")
    avalog.setupLogging()
    cleanup(options.log_prefix)
    cleanup(options.debug_prefix)
    cleanup(options.action_prefix, ".xml")

def cleanup(prefix, suffix=".txt"):
    # Remove excess files
    names = glob.glob(os.path.join(logdir, prefix + ".????-??-??" + suffix))
    names = list(map(os.path.normpath, names))
    names.sort()
    days = max(options.log_keep_days or 0, 0)
    days += 1 # Always keep the most recent one
    nremoves = 0
    if len(names) > days:
        for name in names[:len(names)-days]:
            try:
                os.remove(name)
            except os.error as err:
                logger.warn("Can't remote %s: %s", name, err)
            else:
                logger.info("Removed %s", name)
            nremoves += 1
    if not nremoves:
        logger.info("No %s files removed today", prefix)
    else:
        logger.info("Removed %d %s files", nremoves, prefix)

if __name__ == "__main__":
    sys.exit(main())
