diff --git a/pwnagotchi/defaults.yml b/pwnagotchi/defaults.yml index 72964598b..b57e47829 100644 --- a/pwnagotchi/defaults.yml +++ b/pwnagotchi/defaults.yml @@ -84,8 +84,6 @@ main: mon_start_cmd: /usr/bin/monstart mon_stop_cmd: /usr/bin/monstop mon_max_blind_epochs: 50 - # log file - log: /var/log/pwnagotchi.log # if true, will not restart the wifi module no_restart: false # access points to ignore @@ -94,6 +92,14 @@ main: - ANOTHER_EXAMPLE_NETWORK # if not null, filter access points by this regular expression filter: null + # logging + log: + # file to log to + path: /var/log/pwnagotchi.log + rotation: + enabled: true + # specify a maximum size to rotate ( format is 10/10B, 10K, 10M 10G ) + size: '10M' ai: # if false, only the default 'personality' will be used diff --git a/pwnagotchi/log.py b/pwnagotchi/log.py index 8ba77d5a7..78866905c 100644 --- a/pwnagotchi/log.py +++ b/pwnagotchi/log.py @@ -26,7 +26,7 @@ class LastSession(object): def __init__(self, config): self.config = config self.voice = Voice(lang=config['main']['lang']) - self.path = config['main']['log'] + self.path = config['main']['log']['path'] self.last_session = [] self.last_session_id = '' self.last_saved_session_id = '' diff --git a/pwnagotchi/utils.py b/pwnagotchi/utils.py index 4687f3e14..c3ad79304 100644 --- a/pwnagotchi/utils.py +++ b/pwnagotchi/utils.py @@ -3,11 +3,13 @@ import logging import glob import os +import re import time import subprocess import yaml import json import shutil +import gzip import pwnagotchi @@ -117,14 +119,80 @@ def load_config(args): return config +def parse_max_size(s): + parts = re.findall(r'(^\d+)([bBkKmMgG]?)', s) + if len(parts) != 1: + raise Exception("can't parse %s as a max size" % s) + + num, unit = parts[1] + num = int(num) + unit = unit.lower() + + if unit == 'k': + return num * 1024 + elif unit == 'm': + return num * 1024 * 1024 + elif unit == 'g': + return num * 1024 * 1024 * 1024 + else: + return num + + +def do_rotate(filename, stats, cfg): + base_path = os.path.dirname(filename) + name = os.path.splitext(os.path.basename(filename))[0] + archive_filename = os.path.join(base_path, "%s.gz" % name) + counter = 2 + + while os.path.exists(archive_filename): + archive_filename = os.path.join(base_path, "%s-%d.gz" % (name, counter)) + counter += 1 + + log_filename = archive_filename.replace('gz', 'log') + + print("%s is %d bytes big, rotating to %s ..." % (filename, stats.st_size, log_filename)) + + shutil.move(filename, log_filename) + + print("compressing to %s ..." % archive_filename) + + with open(log_filename, 'rb') as src: + with gzip.open(archive_filename, 'wb') as dst: + dst.writelines(src) + + +def log_rotation(filename, cfg): + rotation = cfg['rotation'] + if not rotation['enabled']: + return + elif not os.path.isfile(filename): + return + + stats = os.stat(filename) + # specify a maximum size to rotate ( format is 10/10B, 10K, 10M 10G ) + if rotation['size']: + max_size = parse_max_size(rotation['size']) + if stats.st_size >= max_size: + do_rotate(filename, stats, cfg) + else: + raise Exception("log rotation is enabled but log.rotation.size was not specified") + + def setup_logging(args, config): + cfg = config['main']['log'] + filename = cfg['path'] + formatter = logging.Formatter("[%(asctime)s] [%(levelname)s] %(message)s") root = logging.getLogger() root.setLevel(logging.DEBUG if args.debug else logging.INFO) - if config['main']['log']: - file_handler = logging.FileHandler(config['main']['log']) + if filename: + # since python default log rotation might break session data in different files, + # we need to do log rotation ourselves + log_rotation(filename, cfg) + + file_handler = logging.FileHandler(filename) file_handler.setFormatter(formatter) root.addHandler(file_handler) diff --git a/scripts/backup.sh b/scripts/backup.sh index 6fa178492..9934327a9 100755 --- a/scripts/backup.sh +++ b/scripts/backup.sh @@ -16,6 +16,7 @@ FILES_TO_BACKUP=( /root/peers /etc/pwnagotchi/ /var/log/pwnagotchi.log + /var/log/pwnagotchi*.gz /home/pi/.bashrc )