108 lines
3.8 KiB
Python
108 lines
3.8 KiB
Python
import json
|
|
import subprocess
|
|
|
|
import click
|
|
from pathlib import PurePath, Path
|
|
import configparser
|
|
import logging
|
|
from logging.handlers import RotatingFileHandler
|
|
import sys
|
|
|
|
APP_NAME = 'iottb'
|
|
DB_NAME = 'iottb.db'
|
|
|
|
CONSOLE_LOG_FORMATS = {
|
|
0: '%(levelname)s - %(message)s',
|
|
1: '%(levelname)s - %(module)s - %(message)s',
|
|
2: '%(levelname)s - %(asctime)s - %(module)s - %(funcName)s - %(lineno)d - %(message)s'
|
|
}
|
|
|
|
LOGFILE_LOG_FORMAT = {
|
|
0: '%(levelname)s - %(asctime)s - %(module)s - %(message)s',
|
|
1: '%(levelname)s - %(asctime)s - %(module)s - %(funcName)s - %(message)s',
|
|
2: '%(levelname)s - %(asctime)s - %(module)s - %(funcName)s - %(lineno)d - %(message)s'
|
|
}
|
|
MAX_VERBOSITY = len(CONSOLE_LOG_FORMATS) - 1
|
|
assert len(LOGFILE_LOG_FORMAT) == len(CONSOLE_LOG_FORMATS), 'Log formats must be same size'
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def setup_logging(verbosity, debug):
|
|
""" Setup root logger for iottb """
|
|
log_level = logging.ERROR
|
|
handlers = []
|
|
date_format = '%Y-%m-%d %H:%M:%S'
|
|
if verbosity > 0:
|
|
log_level = logging.WARNING
|
|
if verbosity > MAX_VERBOSITY:
|
|
verbosity = MAX_VERBOSITY
|
|
log_level = logging.INFO
|
|
assert verbosity <= MAX_VERBOSITY, f'Verbosity must be <= {MAX_VERBOSITY}'
|
|
console_handler = logging.StreamHandler(sys.stdout)
|
|
console_handler.setFormatter(logging.Formatter(CONSOLE_LOG_FORMATS[verbosity], datefmt=date_format))
|
|
console_handler.setLevel(logging.DEBUG) # can keep at debug since it depends on global level?
|
|
handlers.append(console_handler)
|
|
|
|
if debug:
|
|
log_level = logging.DEBUG
|
|
|
|
# Logfile logs INFO+, no debugs though
|
|
file_handler = RotatingFileHandler(f'{APP_NAME}.log', maxBytes=10240, backupCount=5)
|
|
file_handler.setFormatter(logging.Formatter(LOGFILE_LOG_FORMAT[verbosity], datefmt=date_format))
|
|
file_handler.setLevel(logging.INFO)
|
|
|
|
# finnish root logger setup
|
|
handlers.append(file_handler)
|
|
# Force this config to be applied to root logger
|
|
logging.basicConfig(level=log_level, handlers=handlers, force=True)
|
|
|
|
|
|
def create_default_config(cfg_file):
|
|
"""Create default iottb config file."""
|
|
assert logger is not None, 'Logger must be initialized'
|
|
logger.info(f'Creating default config file at {cfg_file}')
|
|
# By default, create iottb.db in user home
|
|
defaults = {
|
|
'DefaultDatabase': DB_NAME,
|
|
'DatabaseLocations': {
|
|
DB_NAME: str(Path.home() / DB_NAME)
|
|
}
|
|
}
|
|
with open(cfg_file, 'w') as config_file:
|
|
json.dump(defaults, config_file)
|
|
return defaults
|
|
|
|
|
|
def load_config(ctx, param, value):
|
|
""" Try to load iottb config file.
|
|
If the file does not exist, it will be created with default values.`
|
|
Try to load the iottb config file from the given path.
|
|
If the file does not exist, it will be created with default values.
|
|
The only value set is the path to the iottb.db file.
|
|
"""
|
|
logger.info(f'Loading config from {value}')
|
|
cfg_file = value
|
|
if not cfg_file.is_file():
|
|
defaults = create_default_config(cfg_file)
|
|
else:
|
|
defaults = json.load(cfg_file)
|
|
|
|
ctx.obj['path']['cfg'] = cfg_file
|
|
ctx.obj['path']['db'] = defaults['DatabaseLocations'][defaults['DefaultDatabase']]
|
|
|
|
|
|
@click.group()
|
|
@click.option('-v', '--verbosity', type=click.IntRange(0, MAX_VERBOSITY), default=0,
|
|
help='Set verbosity')
|
|
@click.option('-d', '--debug', is_flag=True, default=False, help='Enable debug mode')
|
|
@click.option('--cfg-file', type=click.Path(), default=Path(click.get_app_dir(APP_NAME)).joinpath('iottb.cfg'),
|
|
envvar='IOTTB_CONF_HOME', is_eager=True, callback=load_config, help='Path to iottb config file')
|
|
@click.pass_context
|
|
def main(verbosity, debug):
|
|
setup_logging(verbosity, debug)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main(auto_envvar_prefix='IOTTB')
|