diff --git a/monkey/monkey_island/cc/island_logger.py b/monkey/monkey_island/cc/island_logger.py new file mode 100644 index 000000000..8fbef1e0e --- /dev/null +++ b/monkey/monkey_island/cc/island_logger.py @@ -0,0 +1,26 @@ +import os +import json +import logging.config + + +__author__ = 'Maor.Rayzin' + + +def json_setup_logging(default_path='logging.json', default_level=logging.INFO, env_key='LOG_CFG'): + """ + Setup the logging configuration + :param default_path: the default log configuration file path + :param default_level: Default level to log from + :param env_key: SYS ENV key to use for external configuration file path + :return: + """ + path = default_path + value = os.getenv(env_key, None) + if value: + path = value + if os.path.exists(path): + with open(path, 'rt') as f: + config = json.load(f) + logging.config.dictConfig(config) + else: + logging.basicConfig(level=default_level) diff --git a/monkey/monkey_island/cc/island_logger_default_config.json b/monkey/monkey_island/cc/island_logger_default_config.json new file mode 100644 index 000000000..e41ca3d9b --- /dev/null +++ b/monkey/monkey_island/cc/island_logger_default_config.json @@ -0,0 +1,33 @@ +{ + "version": 1, + "disable_existing_loggers": false, + "formatters": { + "simple": { + "format": "%(asctime)s - %(filename)s:%(lineno)s - %(funcName)10s() - %(levelname)s - %(message)s" + } + }, + + "handlers": { + "console": { + "class": "logging.StreamHandler", + "level": "DEBUG", + "formatter": "simple", + "stream": "ext://sys.stdout" + }, + + "info_file_handler": { + "class": "logging.handlers.RotatingFileHandler", + "level": "INFO", + "formatter": "simple", + "filename": "info.log", + "maxBytes": 10485760, + "backupCount": 20, + "encoding": "utf8" + } + }, + + "root": { + "level": "INFO", + "handlers": ["console", "info_file_handler"] + } +} \ No newline at end of file diff --git a/monkey/monkey_island/cc/resources/island_logs.py b/monkey/monkey_island/cc/resources/island_logs.py new file mode 100644 index 000000000..971306c14 --- /dev/null +++ b/monkey/monkey_island/cc/resources/island_logs.py @@ -0,0 +1,19 @@ +import logging + +import flask_restful + +from cc.auth import jwt_required +from cc.services.island_logs import IslandLogService + +__author__ = "Maor.Rayzin" + +logger = logging.getLogger(__name__) + + +class IslandLog(flask_restful.Resource): + @jwt_required() + def get(self): + try: + return IslandLogService.get_log_file() + except Exception as e: + logger.error('Monkey Island logs failed to download', exc_info=True) diff --git a/monkey/monkey_island/cc/services/island_logs.py b/monkey/monkey_island/cc/services/island_logs.py new file mode 100644 index 000000000..77b28bdd4 --- /dev/null +++ b/monkey/monkey_island/cc/services/island_logs.py @@ -0,0 +1,32 @@ +import logging +__author__ = "Maor.Rayzin" + +logger = logging.getLogger(__name__) + + +class IslandLogService: + def __init__(self): + pass + + @staticmethod + def get_log_file(): + """ + This static function is a helper function for the monkey island log download function. + It finds the logger handlers and checks if one of them is a fileHandler of any kind by checking if the handler + has the property handler.baseFilename. + :return: + a dict with the log file content. + """ + logger_handlers = logger.parent.handlers + for handler in logger_handlers: + if hasattr(handler, 'baseFilename'): + logger.info('Log file found: {0}'.format(handler.baseFilename)) + log_file_path = handler.baseFilename + with open(log_file_path, 'rt') as f: + log_file = f.read() + return { + 'log_file': log_file + } + + logger.warning('No log file could be found, check logger config.') + return None