Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
a8307e4
Custom logger every type of automation
Adrian-IM Sep 19, 2019
c5db43d
Add call to self logger
Adrian-IM Sep 19, 2019
05caada
Decorator parameters and generic global loger (deprecated)
Adrian-IM Sep 20, 2019
105ce21
Remove unused imports
Adrian-IM Sep 20, 2019
531bd1e
Pass arguments in correct way and preserve global log
Adrian-IM Sep 20, 2019
6314f87
Get handlers from global log
Adrian-IM Sep 24, 2019
98f1ad0
Add stdout as handler for logging
Adrian-IM Sep 24, 2019
dcf6f6f
Copy handler objects
Adrian-IM Sep 24, 2019
ae23145
Add Parent root logger and avoid to propagate info to this root logger
Adrian-IM Sep 24, 2019
b6525da
Merge remote-tracking branch 'javi/master' into CPS-43-Logger-improve…
Adrian-IM Sep 25, 2019
d6002a6
Code format
Adrian-IM Sep 26, 2019
6d1f610
Add correct id's to formatters
Adrian-IM Sep 26, 2019
f87ad2a
Merge pull request #2 from Adrian-IM/CPS-43-Logger-improvements
JaviCerveraIngram Sep 26, 2019
fed7f5d
Test & flake8 fixes.
JaviCerveraIngram Sep 26, 2019
7ccdb8b
Add common customizator to logger
Adrian-IM Sep 27, 2019
11f657c
Fix tier id to get TA
Adrian-IM Sep 27, 2019
c82afc9
Remove unused imports
Adrian-IM Sep 27, 2019
240e2f8
Remove unused imports
Adrian-IM Sep 27, 2019
efb15f5
Merge pull request #3 from Adrian-IM/CPS-43-Logger-improvements
JaviCerveraIngram Oct 2, 2019
2f6bb94
Merge remote-tracking branch 'upstream/master' into CPS-43-logger-imp…
JaviCerveraIngram Oct 2, 2019
d669d97
Flake8 fixes
JaviCerveraIngram Oct 2, 2019
0b652b8
Merge remote-tracking branch 'upstream/master' into CPS-43-logger-imp…
JaviCerveraIngram Oct 3, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 22 additions & 23 deletions connect/logger/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,37 @@
import json
import logging
import os

from logging.config import dictConfig
from connect.models.base import BaseModel

with open(os.path.join(os.path.dirname(__file__), 'config.json')) as config_file:
config = json.load(config_file)

dictConfig(config['logging'])

logger = logging.getLogger()


def log_request_data(args):
if len(args) and isinstance(args[0], BaseModel):
global logger
base = " %(levelname)-6s; %(asctime)s; %(name)-6s; %(module)s:%(funcName)s:line"\
"-%(lineno)d: %(message)s"
sformat = args[0].id + base
if hasattr(args[0], 'asset') and hasattr(args[0].asset, 'id'):
sformat = args[0].asset.id + " " + sformat
def function_log(custom_logger=None):
if not custom_logger:
custom_logger = logging.getLogger()
sformat = " %(levelname)-6s; %(asctime)s; %(name)-6s; %(module)s:%(funcName)s:line" \
"-%(lineno)d: %(message)s"
[handler.setFormatter(logging.Formatter(sformat, "%I:%M:%S"))
for handler in logger.handlers]


def function_log(func):
@wraps(func)
def decorator(self, *args, **kwargs):
log_request_data(args)
logger.info('Entering: %s', func.__name__)
logger.debug('Function params: {} {}'.format(args, kwargs))
result = func(self, *args, **kwargs)
logger.debug(
'Function `{}.{}` return: {}'.format(self.__class__.__name__, func.__name__, result))
return result
for handler in custom_logger.handlers]

# noinspection PyUnusedLocal
def decorator(func, **kwargs):
# noinspection PyShadowingNames
@wraps(func)
def wrapper(self, *args, **kwargs):
custom_logger.info('Entering: %s', func.__name__)
custom_logger.debug('Function params: {} {}'.format(args, kwargs))
result = func(self, *args, **kwargs)
custom_logger.debug(
'Function `{}.{}` return: {}'.format(
self.__class__.__name__, func.__name__, result))
return result

return wrapper

return decorator
3 changes: 1 addition & 2 deletions connect/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ def deserialize_json(cls, json_data):
if error:
raise TypeError(
'Invalid structure for initialization of `{type}`. \n'
'Error: {error}. \nJSON data: {data}'
.format(
'Error: {error}. \nJSON data: {data}'.format(
type=cls.__name__,
error=error,
data=json_data),
Expand Down
25 changes: 20 additions & 5 deletions connect/resources/automation_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
# This file is part of the Ingram Micro Cloud Blue Connect SDK.
# Copyright (c) 2019 Ingram Micro. All Rights Reserved.

import copy
import logging
from typing import Any, Dict

from connect.logger import function_log
from connect.logger import function_log, logger as global_logger
from connect.models.activation_tile_response import ActivationTileResponse
from connect.models.base import BaseModel
from .base import BaseResource
Expand All @@ -14,6 +16,7 @@

class AutomationEngine(BaseResource):
limit = 1000 # type: int
logger = logging.getLogger()

def filters(self, status='pending', **kwargs):
# type: (str, Dict[str, Any]) -> Dict[str, Any]
Expand All @@ -33,22 +36,34 @@ def process_request(self, request):
raise NotImplementedError('Please implement `{}.process_request` method'
.format(self.__class__.__name__))

@function_log
@function_log(custom_logger=logger)
def approve(self, pk, data):
# type: (str, dict) -> str
return self._api.post(path=pk + '/approve/', json=data)[0]

@function_log
@function_log(custom_logger=logger)
def inquire(self, pk):
# type: (str) -> str
return self._api.post(path=pk + '/inquire/', json={})[0]

@function_log
@function_log(custom_logger=logger)
def fail(self, pk, reason):
# type: (str, str) -> str
return self._api.post(path=pk + '/fail/', json={'reason': reason})[0]

@function_log
@function_log(custom_logger=logger)
def render_template(self, pk, template_id):
# type: (str, str) -> ActivationTileResponse
return TemplateResource(self.config).render(template_id, pk)

def _set_custom_logger(self, *args):
handlers = [copy.copy(hdlr) for hdlr in global_logger.handlers]
log_level = global_logger.level
self.__class__.logger.setLevel(log_level)
self.__class__.logger.propagate = False
[self.__class__.logger.addHandler(hdlr) for hdlr in handlers]
base = " %(levelname)-6s; %(asctime)s; %(name)-6s; %(module)s:%(funcName)s:line" \
"-%(lineno)d: %(message)s"
sformat = " ".join(args) + base
[handler.setFormatter(logging.Formatter(sformat, "%I:%M:%S"))
for handler in self.__class__.logger.handlers]
12 changes: 7 additions & 5 deletions connect/resources/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
# Copyright (c) 2019 Ingram Micro. All Rights Reserved.

import functools
import logging
from typing import Any, List, Dict, Tuple

import requests
from requests import compat

from connect.config import Config
from connect.exceptions import ServerError
from connect.logger import function_log, logger
from connect.logger import function_log
from connect.models.base import BaseModel
from connect.models.server_error_response import ServerErrorResponse

Expand Down Expand Up @@ -59,21 +60,21 @@ def urljoin(*args):
lambda a, b: compat.urljoin(a + ('' if a.endswith('/') else '/'), b) if b else a,
args)

@function_log
@function_log()
def get(self, path='', **kwargs):
# type: (str, Any) -> Tuple[str, int]
kwargs = self._fix_request_kwargs(path, kwargs)
response = requests.get(**kwargs)
return self._check_and_pack_response(response)

@function_log
@function_log()
def post(self, path='', **kwargs):
# type: (str, Any) -> Tuple[str, int]
kwargs = self._fix_request_kwargs(path, kwargs)
response = requests.post(**kwargs)
return self._check_and_pack_response(response)

@function_log
@function_log()
def put(self, path='', **kwargs):
# type: (str, Any) -> Tuple[str, int]
kwargs = self._fix_request_kwargs(path, kwargs)
Expand Down Expand Up @@ -123,6 +124,7 @@ class BaseResource(object):
resource = None # type: str
limit = 100 # type: int
model_class = BaseModel
logger = logging.getLogger()

def __init__(self, config=None):
# Set client
Expand Down Expand Up @@ -156,6 +158,6 @@ def filters(self, **kwargs):
def list(self, filters=None):
# type: (Dict[str, Any]) -> List[Any]
filters = filters or self.filters()
logger.info('Get list request with filters - {}'.format(filters))
self.logger.info('Get list request with filters - {}'.format(filters))
response, _ = self._api.get(params=filters)
return self.model_class.deserialize(response)
25 changes: 13 additions & 12 deletions connect/resources/fulfillment_automation.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
# Copyright (c) 2019 Ingram Micro. All Rights Reserved.

from abc import ABCMeta
import logging

from deprecation import deprecated
from typing import Optional

from connect.exceptions import FailRequest, InquireRequest, SkipRequest
from connect.logger import logger, function_log
from connect.logger import function_log
from connect.models.activation_template_response import ActivationTemplateResponse
from connect.models.activation_tile_response import ActivationTileResponse
from connect.models.param import Param
Expand Down Expand Up @@ -40,6 +41,7 @@ class FulfillmentAutomation(AutomationEngine):
__metaclass__ = ABCMeta
resource = 'requests'
model_class = Fulfillment
logger = logging.getLogger('Fullfilment.logger')

def filters(self, status='pending', **kwargs):
""" Returns the default set of filters for Fulfillment request, plus any others that you
Expand Down Expand Up @@ -72,9 +74,10 @@ def filters(self, status='pending', **kwargs):
filters['asset.product.id__in'] = ','.join(self.config.products)
return filters

@function_log
@function_log(custom_logger=logger)
def dispatch(self, request):
# type: (Fulfillment) -> str
self._set_custom_logger(request.asset.id, request.id)

conversation = request.get_conversation(self.config)

Expand All @@ -83,11 +86,11 @@ def dispatch(self, request):
and request.asset.product.id not in self.config.products:
return 'Invalid product'

logger.info('Start request process / ID request - {}'.format(request.id))
self.logger.info('Start request process / ID request - {}'.format(request.id))
process_result = self.process_request(request)

if not process_result:
logger.info('Method `process_request` did not return result')
self.logger.info('Method `process_request` did not return result')
return ''

if isinstance(process_result, ActivationTileResponse):
Expand Down Expand Up @@ -125,8 +128,8 @@ def dispatch(self, request):
raise

except Exception as ex:
logger.warning('Skipping request {} because an exception was raised: {}'
.format(request.id, ex))
self.logger.warning('Skipping request {} because an exception was raised: {}'
.format(request.id, ex))
return ''

def create_request(self, request):
Expand Down Expand Up @@ -167,7 +170,7 @@ def get_tier_config(self, tier_id, product_id):
else:
return None

@function_log
@function_log(custom_logger=logger)
def update_parameters(self, pk, params):
""" Sends a list of Param objects to Connect for updating.

Expand All @@ -179,18 +182,16 @@ def update_parameters(self, pk, params):
list_dict = []
for _ in params:
list_dict.append(_.__dict__ if isinstance(_, Param) else _)

return self._api.put(
path=pk,
json={'asset': {'params': list_dict}},
)[0]

@staticmethod
def _update_conversation_if_exists(conversation, request_id, obj):
def _update_conversation_if_exists(self, conversation, request_id, obj):
# type: (Optional[Conversation], str, object) -> None
if conversation:
try:
conversation.add_message(str(obj))
except TypeError as ex:
logger.error('Error updating conversation for request {}: {}'
.format(request_id, ex))
self.logger.error('Error updating conversation for request {}: {}'
.format(request_id, ex))
19 changes: 12 additions & 7 deletions connect/resources/tier_config_automation.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
# Copyright (c) 2019 Ingram Micro. All Rights Reserved.

from abc import ABCMeta
import logging

from connect.exceptions import FailRequest, InquireRequest, SkipRequest
from connect.logger import logger, function_log
from connect.logger import function_log
from connect.models.activation_template_response import ActivationTemplateResponse
from connect.models.activation_tile_response import ActivationTileResponse
from connect.models.param import Param
Expand Down Expand Up @@ -35,6 +36,7 @@ class TierConfigAutomation(AutomationEngine):
__metaclass__ = ABCMeta
resource = 'tier/config-requests'
model_class = TierConfigRequest
logger = logging.getLogger('Tier.logger')

def filters(self, status='pending', **kwargs):
""" Returns the default set of filters for Tier Config request, plus any others that you
Expand All @@ -61,20 +63,23 @@ def filters(self, status='pending', **kwargs):
filters['configuration__product__id'] = ','.join(self.config.products)
return filters

@function_log
@function_log(custom_logger=logger)
def dispatch(self, request):
# type: (TierConfigRequest) -> str
try:
self._set_custom_logger(request.id, request.configuration.id,
request.configuration.account.id)

if self.config.products \
and request.configuration.product.id not in self.config.products:
return 'Invalid product'

logger.info(
self.logger.info(
'Start tier config request process / ID request - {}'.format(request.id))
result = self.process_request(request)

if not result:
logger.info('Method `process_request` did not return result')
self.logger.info('Method `process_request` did not return result')
return ''

params = {}
Expand All @@ -99,13 +104,13 @@ def dispatch(self, request):
raise

except Exception as ex:
logger.warning('Skipping request {} because an exception was raised: {}'
.format(request.id, ex))
self.logger.warning('Skipping request {} because an exception was raised: {}'
.format(request.id, ex))
return ''

return ''

@function_log
@function_log(custom_logger=logger)
def update_parameters(self, pk, params):
""" Sends a list of Param objects to Connect for updating.

Expand Down
Loading