Skip to content

Commit efc1eea

Browse files
Merge pull request #67 from JaviCerveraIngram/CPS-43-logger-improvements
Cps 43 logger improvements
2 parents 97fb781 + 0b652b8 commit efc1eea

File tree

9 files changed

+97
-77
lines changed

9 files changed

+97
-77
lines changed

connect/logger/logger.py

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,38 +7,37 @@
77
import json
88
import logging
99
import os
10-
1110
from logging.config import dictConfig
12-
from connect.models.base import BaseModel
1311

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

1715
dictConfig(config['logging'])
16+
1817
logger = logging.getLogger()
1918

2019

21-
def log_request_data(args):
22-
if len(args) and isinstance(args[0], BaseModel):
23-
global logger
24-
base = " %(levelname)-6s; %(asctime)s; %(name)-6s; %(module)s:%(funcName)s:line"\
25-
"-%(lineno)d: %(message)s"
26-
sformat = args[0].id + base
27-
if hasattr(args[0], 'asset') and hasattr(args[0].asset, 'id'):
28-
sformat = args[0].asset.id + " " + sformat
20+
def function_log(custom_logger=None):
21+
if not custom_logger:
22+
custom_logger = logging.getLogger()
23+
sformat = " %(levelname)-6s; %(asctime)s; %(name)-6s; %(module)s:%(funcName)s:line" \
24+
"-%(lineno)d: %(message)s"
2925
[handler.setFormatter(logging.Formatter(sformat, "%I:%M:%S"))
30-
for handler in logger.handlers]
31-
32-
33-
def function_log(func):
34-
@wraps(func)
35-
def decorator(self, *args, **kwargs):
36-
log_request_data(args)
37-
logger.info('Entering: %s', func.__name__)
38-
logger.debug('Function params: {} {}'.format(args, kwargs))
39-
result = func(self, *args, **kwargs)
40-
logger.debug(
41-
'Function `{}.{}` return: {}'.format(self.__class__.__name__, func.__name__, result))
42-
return result
26+
for handler in custom_logger.handlers]
27+
28+
# noinspection PyUnusedLocal
29+
def decorator(func, **kwargs):
30+
# noinspection PyShadowingNames
31+
@wraps(func)
32+
def wrapper(self, *args, **kwargs):
33+
custom_logger.info('Entering: %s', func.__name__)
34+
custom_logger.debug('Function params: {} {}'.format(args, kwargs))
35+
result = func(self, *args, **kwargs)
36+
custom_logger.debug(
37+
'Function `{}.{}` return: {}'.format(
38+
self.__class__.__name__, func.__name__, result))
39+
return result
40+
41+
return wrapper
4342

4443
return decorator

connect/models/base.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,7 @@ def deserialize_json(cls, json_data):
5757
if error:
5858
raise TypeError(
5959
'Invalid structure for initialization of `{type}`. \n'
60-
'Error: {error}. \nJSON data: {data}'
61-
.format(
60+
'Error: {error}. \nJSON data: {data}'.format(
6261
type=cls.__name__,
6362
error=error,
6463
data=json_data),

connect/resources/automation_engine.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
# This file is part of the Ingram Micro Cloud Blue Connect SDK.
44
# Copyright (c) 2019 Ingram Micro. All Rights Reserved.
55

6+
import copy
7+
import logging
68
from typing import Any, Dict
79

8-
from connect.logger import function_log
10+
from connect.logger import function_log, logger as global_logger
911
from connect.models.activation_tile_response import ActivationTileResponse
1012
from connect.models.base import BaseModel
1113
from .base import BaseResource
@@ -14,6 +16,7 @@
1416

1517
class AutomationEngine(BaseResource):
1618
limit = 1000 # type: int
19+
logger = logging.getLogger()
1720

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

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

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

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

51-
@function_log
54+
@function_log(custom_logger=logger)
5255
def render_template(self, pk, template_id):
5356
# type: (str, str) -> ActivationTileResponse
5457
return TemplateResource(self.config).render(template_id, pk)
58+
59+
def _set_custom_logger(self, *args):
60+
handlers = [copy.copy(hdlr) for hdlr in global_logger.handlers]
61+
log_level = global_logger.level
62+
self.__class__.logger.setLevel(log_level)
63+
self.__class__.logger.propagate = False
64+
[self.__class__.logger.addHandler(hdlr) for hdlr in handlers]
65+
base = " %(levelname)-6s; %(asctime)s; %(name)-6s; %(module)s:%(funcName)s:line" \
66+
"-%(lineno)d: %(message)s"
67+
sformat = " ".join(args) + base
68+
[handler.setFormatter(logging.Formatter(sformat, "%I:%M:%S"))
69+
for handler in self.__class__.logger.handlers]

connect/resources/base.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@
44
# Copyright (c) 2019 Ingram Micro. All Rights Reserved.
55

66
import functools
7+
import logging
78
from typing import Any, List, Dict, Tuple
89

910
import requests
1011
from requests import compat
1112

1213
from connect.config import Config
1314
from connect.exceptions import ServerError
14-
from connect.logger import function_log, logger
15+
from connect.logger import function_log
1516
from connect.models.base import BaseModel
1617
from connect.models.server_error_response import ServerErrorResponse
1718

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

62-
@function_log
63+
@function_log()
6364
def get(self, path='', **kwargs):
6465
# type: (str, Any) -> Tuple[str, int]
6566
kwargs = self._fix_request_kwargs(path, kwargs)
6667
response = requests.get(**kwargs)
6768
return self._check_and_pack_response(response)
6869

69-
@function_log
70+
@function_log()
7071
def post(self, path='', **kwargs):
7172
# type: (str, Any) -> Tuple[str, int]
7273
kwargs = self._fix_request_kwargs(path, kwargs)
7374
response = requests.post(**kwargs)
7475
return self._check_and_pack_response(response)
7576

76-
@function_log
77+
@function_log()
7778
def put(self, path='', **kwargs):
7879
# type: (str, Any) -> Tuple[str, int]
7980
kwargs = self._fix_request_kwargs(path, kwargs)
@@ -123,6 +124,7 @@ class BaseResource(object):
123124
resource = None # type: str
124125
limit = 100 # type: int
125126
model_class = BaseModel
127+
logger = logging.getLogger()
126128

127129
def __init__(self, config=None):
128130
# Set client
@@ -156,6 +158,6 @@ def filters(self, **kwargs):
156158
def list(self, filters=None):
157159
# type: (Dict[str, Any]) -> List[Any]
158160
filters = filters or self.filters()
159-
logger.info('Get list request with filters - {}'.format(filters))
161+
self.logger.info('Get list request with filters - {}'.format(filters))
160162
response, _ = self._api.get(params=filters)
161163
return self.model_class.deserialize(response)

connect/resources/fulfillment_automation.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@
44
# Copyright (c) 2019 Ingram Micro. All Rights Reserved.
55

66
from abc import ABCMeta
7+
import logging
78

89
from deprecation import deprecated
910
from typing import Optional
1011

1112
from connect.exceptions import FailRequest, InquireRequest, SkipRequest
12-
from connect.logger import logger, function_log
13+
from connect.logger import function_log
1314
from connect.models.activation_template_response import ActivationTemplateResponse
1415
from connect.models.activation_tile_response import ActivationTileResponse
1516
from connect.models.param import Param
@@ -40,6 +41,7 @@ class FulfillmentAutomation(AutomationEngine):
4041
__metaclass__ = ABCMeta
4142
resource = 'requests'
4243
model_class = Fulfillment
44+
logger = logging.getLogger('Fullfilment.logger')
4345

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

75-
@function_log
77+
@function_log(custom_logger=logger)
7678
def dispatch(self, request):
7779
# type: (Fulfillment) -> str
80+
self._set_custom_logger(request.asset.id, request.id)
7881

7982
conversation = request.get_conversation(self.config)
8083

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

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

8992
if not process_result:
90-
logger.info('Method `process_request` did not return result')
93+
self.logger.info('Method `process_request` did not return result')
9194
return ''
9295

9396
if isinstance(process_result, ActivationTileResponse):
@@ -125,8 +128,8 @@ def dispatch(self, request):
125128
raise
126129

127130
except Exception as ex:
128-
logger.warning('Skipping request {} because an exception was raised: {}'
129-
.format(request.id, ex))
131+
self.logger.warning('Skipping request {} because an exception was raised: {}'
132+
.format(request.id, ex))
130133
return ''
131134

132135
def create_request(self, request):
@@ -167,7 +170,7 @@ def get_tier_config(self, tier_id, product_id):
167170
else:
168171
return None
169172

170-
@function_log
173+
@function_log(custom_logger=logger)
171174
def update_parameters(self, pk, params):
172175
""" Sends a list of Param objects to Connect for updating.
173176
@@ -179,18 +182,16 @@ def update_parameters(self, pk, params):
179182
list_dict = []
180183
for _ in params:
181184
list_dict.append(_.__dict__ if isinstance(_, Param) else _)
182-
183185
return self._api.put(
184186
path=pk,
185187
json={'asset': {'params': list_dict}},
186188
)[0]
187189

188-
@staticmethod
189-
def _update_conversation_if_exists(conversation, request_id, obj):
190+
def _update_conversation_if_exists(self, conversation, request_id, obj):
190191
# type: (Optional[Conversation], str, object) -> None
191192
if conversation:
192193
try:
193194
conversation.add_message(str(obj))
194195
except TypeError as ex:
195-
logger.error('Error updating conversation for request {}: {}'
196-
.format(request_id, ex))
196+
self.logger.error('Error updating conversation for request {}: {}'
197+
.format(request_id, ex))

connect/resources/tier_config_automation.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
# Copyright (c) 2019 Ingram Micro. All Rights Reserved.
55

66
from abc import ABCMeta
7+
import logging
78

89
from connect.exceptions import FailRequest, InquireRequest, SkipRequest
9-
from connect.logger import logger, function_log
10+
from connect.logger import function_log
1011
from connect.models.activation_template_response import ActivationTemplateResponse
1112
from connect.models.activation_tile_response import ActivationTileResponse
1213
from connect.models.param import Param
@@ -35,6 +36,7 @@ class TierConfigAutomation(AutomationEngine):
3536
__metaclass__ = ABCMeta
3637
resource = 'tier/config-requests'
3738
model_class = TierConfigRequest
39+
logger = logging.getLogger('Tier.logger')
3840

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

64-
@function_log
66+
@function_log(custom_logger=logger)
6567
def dispatch(self, request):
6668
# type: (TierConfigRequest) -> str
6769
try:
70+
self._set_custom_logger(request.id, request.configuration.id,
71+
request.configuration.account.id)
72+
6873
if self.config.products \
6974
and request.configuration.product.id not in self.config.products:
7075
return 'Invalid product'
7176

72-
logger.info(
77+
self.logger.info(
7378
'Start tier config request process / ID request - {}'.format(request.id))
7479
result = self.process_request(request)
7580

7681
if not result:
77-
logger.info('Method `process_request` did not return result')
82+
self.logger.info('Method `process_request` did not return result')
7883
return ''
7984

8085
params = {}
@@ -99,13 +104,13 @@ def dispatch(self, request):
99104
raise
100105

101106
except Exception as ex:
102-
logger.warning('Skipping request {} because an exception was raised: {}'
103-
.format(request.id, ex))
107+
self.logger.warning('Skipping request {} because an exception was raised: {}'
108+
.format(request.id, ex))
104109
return ''
105110

106111
return ''
107112

108-
@function_log
113+
@function_log(custom_logger=logger)
109114
def update_parameters(self, pk, params):
110115
""" Sends a list of Param objects to Connect for updating.
111116

0 commit comments

Comments
 (0)