Skip to content

Commit

Permalink
Merge 637e978 into 0485447
Browse files Browse the repository at this point in the history
  • Loading branch information
Anthony Piddubny committed Nov 20, 2018
2 parents 0485447 + 637e978 commit d3655b8
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 39 deletions.
7 changes: 4 additions & 3 deletions cloudshell/core/logger/qs_config.ini
@@ -1,6 +1,7 @@
[Logging]
LOG_LEVEL='DEBUG'
LOG_LEVEL='INFO'
LOG_FORMAT= '%(asctime)s [%(levelname)s]: %(name)s %(module)s - %(funcName)-20s %(message)s'
TIME_FORMAT= '%d-%b-%Y--%H-%M-%S'
LOG_PATH='../../Logs'
#LOG_PATH = 'x:/Logs/'
WINDOWS_LOG_PATH='{ALLUSERSPROFILE}\QualiSystems\logs'
UNIX_LOG_PATH='/var/log/qualisystems'
DEFAULT_LOG_PATH='../../Logs'
92 changes: 65 additions & 27 deletions cloudshell/core/logger/qs_logger.py
Expand Up @@ -24,9 +24,10 @@
# default settings
DEFAULT_FORMAT = '%(asctime)s [%(levelname)s]: %(name)s %(module)s - %(funcName)-20s %(message)s'
DEFAULT_TIME_FORMAT = '%Y%m%d%H%M%S'
DEFAULT_LEVEL = 'DEBUG'
DEFAULT_LEVEL = 'INFO'
# DEFAULT_LOG_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../', 'Logs')
LOG_SECTION = 'Logging'
WINDOWS_OS_FAMILY = "nt"

_LOGGER_CONTAINER = {}
_LOGGER_LOCK = threading.Lock()
Expand All @@ -47,9 +48,14 @@ def get_settings():
log_format = QSConfigParser.get_setting(LOG_SECTION, 'LOG_FORMAT') or DEFAULT_FORMAT
config['FORMAT'] = log_format

# log_path
log_path = QSConfigParser.get_setting(LOG_SECTION, 'LOG_PATH')
config['LOG_PATH'] = log_path
# UNIX log path
config['UNIX_LOG_PATH'] = QSConfigParser.get_setting(LOG_SECTION, 'UNIX_LOG_PATH')

# Windows log path
config['WINDOWS_LOG_PATH'] = QSConfigParser.get_setting(LOG_SECTION, 'WINDOWS_LOG_PATH')

# Default log path for all systems
config['DEFAULT_LOG_PATH'] = QSConfigParser.get_setting(LOG_SECTION, 'DEFAULT_LOG_PATH')

# Time format
time_format = QSConfigParser.get_setting(LOG_SECTION, 'TIME_FORMAT') or DEFAULT_TIME_FORMAT
Expand All @@ -58,47 +64,79 @@ def get_settings():
return config


# return accessable log path or None
def get_accessible_log_path(reservation_id='Autoload', handler='default'):
"""Generate log path for the logger and verify that it's accessible using LOG_PATH/reservation_id/handler-%timestamp%.log
def _get_log_path_config(config):
"""Get log path based on the environment variable or Windows/Unix config setting
:param reservation_id: part of log path
:param handler: handler name for logger
:return: generated log path
:param dict[str] config:
:rtype: str
"""

accessible_log_path = None
config = get_settings()

if 'LOG_PATH' in os.environ:
log_path = os.environ['LOG_PATH']
elif 'LOG_PATH' in config and config['LOG_PATH']:
log_path = config['LOG_PATH']
return os.environ['LOG_PATH']

if os.name == WINDOWS_OS_FAMILY:
tpl = config.get('WINDOWS_LOG_PATH')
if tpl:
try:
return tpl.format(**os.environ)
except KeyError:
print "Environment variable is not defined in the template {}".format(tpl)
else:
return None
return config.get('UNIX_LOG_PATH')

if log_path.startswith('..'):
log_path = os.path.join(os.path.dirname(__file__), log_path)

time_format = config['TIME_FORMAT'] or DEFAULT_TIME_FORMAT
def _prepare_log_path(log_path, log_file_name):
"""Create logs directory if needed and return full path to the log file
log_file_name = '{0}--{1}.log'.format(handler, datetime.now().strftime(time_format))
log_path = os.path.join(log_path, reservation_id)
:param str log_path:
:param str log_file_name:
:rtype: str
"""
if log_path.startswith('..'):
log_path = os.path.join(os.path.dirname(__file__), log_path)

log_file = os.path.join(log_path, log_file_name)
# print(log_file)

if os.path.isdir(log_path):
if os.access(log_path, os.W_OK):
accessible_log_path = log_file
return log_file
else:
try:
os.makedirs(log_path)
accessible_log_path = log_file
return log_file
except:
pass

return accessible_log_path

# return accessable log path or None
def get_accessible_log_path(reservation_id='Autoload', handler='default'):
"""Generate log path for the logger and verify that it's accessible using LOG_PATH/reservation_id/handler-%timestamp%.log
:param reservation_id: part of log path
:param handler: handler name for logger
:return: generated log path
"""
config = get_settings()
time_format = config['TIME_FORMAT'] or DEFAULT_TIME_FORMAT
log_file_name = '{0}--{1}.log'.format(handler, datetime.now().strftime(time_format))

log_path = _get_log_path_config(config)

if log_path:
env_folder = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", "..", "..", "..")
shell_name = os.path.basename(os.path.abspath(env_folder))
log_path = os.path.join(log_path, reservation_id, shell_name)
path = _prepare_log_path(log_path=log_path,
log_file_name=log_file_name)
if path:
return path

default_log_path = config.get('DEFAULT_LOG_PATH')

if default_log_path:
default_log_path = os.path.join(default_log_path, reservation_id)
return _prepare_log_path(log_path=default_log_path,
log_file_name=log_file_name)


def log_execution_info(logger_hdlr, exec_info):
Expand All @@ -113,7 +151,7 @@ def log_execution_info(logger_hdlr, exec_info):
logger_hdlr.info('-----------------------------------------------------------\n')


def get_qs_logger(log_group='Ungrouped', log_category ='QS', log_file_prefix='QS'):
def get_qs_logger(log_group='Ungrouped', log_category='QS', log_file_prefix='QS'):
"""Create cloudshell specific singleton logger
:param log_group: This folder will be grouped under this name. The default implementation of the group is a folder
Expand Down
4 changes: 3 additions & 1 deletion tests/core/logger/config/test_qs_config.ini
Expand Up @@ -2,4 +2,6 @@
LOG_LEVEL='INFO'
LOG_FORMAT= '%(asctime)s [%(levelname)s]: %(name)s %(module)s - %(funcName)-20s %(message)s'
TIME_FORMAT= '%d-%b-%Y--%H-%M-%S'
LOG_PATH='../../Logs'
WINDOWS_LOG_PATH='{ALLUSERSPROFILE}\QualiSystems\logs'
UNIX_LOG_PATH='/var/log/qualisystems'
DEFAULT_LOG_PATH='../../Logs'
4 changes: 3 additions & 1 deletion tests/core/logger/test_qs_config_parser.py
Expand Up @@ -14,7 +14,9 @@
class TestQSConfigParser(TestCase):
exp_response = {'Logging':
{'time_format': '%d-%b-%Y--%H-%M-%S',
'log_path': '../../Logs',
'windows_log_path': r'{ALLUSERSPROFILE}\QualiSystems\logs',
'unix_log_path': '/var/log/qualisystems',
'default_log_path': '../../Logs',
'log_format': '%(asctime)s [%(levelname)s]: %(name)s %(module)s - %(funcName)-20s %(message)s',
'log_level': 'INFO'}}

Expand Down
48 changes: 42 additions & 6 deletions tests/core/logger/test_qs_logger.py
Expand Up @@ -10,6 +10,7 @@
import shutil

from mock import MagicMock
import mock
from unittest import TestCase

from cloudshell.core.logger import qs_logger
Expand Down Expand Up @@ -66,18 +67,53 @@ def tearDown(self):

def test_get_settings(self):
""" Test suite for get_settings method """
exp_response = {'LOG_PATH': '../../Logs',
exp_response = {'WINDOWS_LOG_PATH': r'{ALLUSERSPROFILE}\QualiSystems\logs',
'UNIX_LOG_PATH': '/var/log/qualisystems',
'DEFAULT_LOG_PATH': '../../Logs',
'TIME_FORMAT': '%d-%b-%Y--%H-%M-%S',
'LOG_LEVEL': 'INFO',
'FORMAT': '%(asctime)s [%(levelname)s]: %(name)s %(module)s - %(funcName)-20s %(message)s'}

self.assertEqual(qs_logger.get_settings(), exp_response)

@mock.patch("cloudshell.core.logger.qs_logger.os")
def test_get_log_path_config_from_environment_variable(self, os):
"""Check that method will primarily return log path from the environment variable if such exists"""
config = {}
expected_path = MagicMock()
os.environ = {'LOG_PATH': expected_path}
# act
result = qs_logger._get_log_path_config(config=config)
# verify
self.assertEqual(result, expected_path)

@mock.patch("cloudshell.core.logger.qs_logger.os")
def test_get_log_path_config_for_windows_os(self, os):
"""Check that method will return windows log path setting with substituted environment variables"""
os.name = qs_logger.WINDOWS_OS_FAMILY
os.environ = {"SOME_EN_VARIABLE": "C:\\some_path"}
expected_path = "{SOME_EN_VARIABLE}\\qualisystems\\logs\\commands"
config = {"WINDOWS_LOG_PATH": expected_path}
# act
result = qs_logger._get_log_path_config(config=config)
# verify
self.assertEqual(result, "C:\\some_path\\qualisystems\\logs\\commands")

@mock.patch("cloudshell.core.logger.qs_logger.os")
def test_get_log_path_config_for_unix_os(self, os):
"""Check that method will return unix log path setting for posix OS"""
os.name = "posix"
expected_path = MagicMock()
config = {"UNIX_LOG_PATH": expected_path}
# act
result = qs_logger._get_log_path_config(config=config)
# verify
self.assertEqual(result, expected_path)

def test_get_accessible_log_path_default_params(self):
""" Test suite for get_accessible_log_path method """

path = qs_logger.get_accessible_log_path()
self.assertTrue(re.search(r"Logs[\\/]Autoload[\\/]default--\d{2}-\w+-\d{4}--\d{2}-\d{2}-\d{2}\.log", path))
self.assertRegexpMatches(path, r"Logs[\\/]Autoload[\\/](.*[\\/])?default--\d{2}-\w+-\d{4}--\d{2}-\d{2}-\d{2}\.log")
self.assertTrue(os.path.dirname(path))

def test_get_accessible_log_path_path_creation(self):
Expand All @@ -88,9 +124,9 @@ def test_get_accessible_log_path_path_creation(self):

def test_get_accessible_log_path(self):
""" Test suite for get_accessible_log_path method """

path = qs_logger.get_accessible_log_path(qs_logger.get_accessible_log_path("reservation_id", "handler_name"))
self.assertTrue(re.search(r"Logs[\\/]reservation_id[\\/]handler_name--\d{2}-\w+-\d{4}--\d{2}-\d{2}-\d{2}\.log", path))
path = qs_logger.get_accessible_log_path("reservation_id", "handler_name")
self.assertRegexpMatches(path, r"Logs[\\/]reservation_id[\\/](.*[\\/])?"
r"handler_name--\d{2}-\w+-\d{4}--\d{2}-\d{2}-\d{2}\.log")

def test_get_accessible_log_path_log_path_setting_missing(self):
""" Test suite for get_accessible_log_path method """
Expand Down
2 changes: 1 addition & 1 deletion version.txt
@@ -1 +1 @@
1.0.1
2.2.180

0 comments on commit d3655b8

Please sign in to comment.