Skip to content

Commit 437a314

Browse files
Add comments and documentation
1 parent 969f959 commit 437a314

File tree

8 files changed

+177
-20
lines changed

8 files changed

+177
-20
lines changed

python_common_logger/__init__.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,29 @@
1+
"""
2+
Python Common Logger to log in JSON format with context data.
3+
4+
Check: https://simpplr.atlassian.net/wiki/spaces/SA/pages/2467365251/Logging+Strategy
5+
6+
Classes:
7+
Logger.ContextFilter
8+
DjangoMiddleware.ContextMiddleware
9+
ContextConstants.ExecutionContextType
10+
LoggingConstants.LoggerContextConfigKeys
11+
LoggingConstants.LoggerKeys
12+
RequestConstants.RequestHeaderKeys
13+
14+
Functions:
15+
Logger.initialise_console_logger(logger_name, service_name, level=logging.WARNING, context_config=None)
16+
ContextHandler.get_thread_execution_context(key='execution_context')
17+
ContextHandler.update_execution_context(execution_context, key='execution_context', reset=False)
18+
"""
19+
120
from .src import logger as Logger
221
from .src.context import context_handler as ContextHandler
322
from .src.django import middleware as DjangoMiddleware
423

24+
from .src.constants import context as ContextConstants
25+
from .src.constants import logger as LoggingConstants
26+
from .src.constants import request as RequestConstants
27+
528
from .src.context.execution_context import *
629

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
from enum import Enum
22

33
class ExecutionContextType(Enum):
4+
"""
5+
ExecutionContextType
6+
7+
Attributes
8+
----------
9+
CORRELATION_ID : str
10+
Correlation Id
11+
TENANT_ID : str
12+
Tenant Id
13+
USER_ID : str
14+
User Id
15+
"""
416
CORRELATION_ID = 'correlation_id'
517
TENANT_ID = 'tenant_id'
618
USER_ID = 'user_id'
Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,35 @@
11
from enum import Enum
22

3-
class ContextConfig(Enum):
3+
class LoggerContextConfigKeys(Enum):
4+
"""
5+
Context Config Keys
6+
7+
Attributes
8+
----------
9+
DISABLE_TID : str
10+
Disable Tenant Id
11+
DISABLE_UID : str
12+
Disable User Id
13+
DISABLE_CID : str
14+
Disable Correlation Id
15+
"""
416
DISABLE_TID = 'disable_tid'
517
DISABLE_UID = 'disable_uid'
618
DISABLE_CID = 'disable_cid'
719

820
class LoggerKeys(Enum):
21+
"""
22+
Logging Key
23+
24+
Attributes
25+
----------
26+
CORRELATION_ID : str
27+
Correlation Id
28+
TENANT_ID : str
29+
Tenant Id
30+
USER_ID : str
31+
User Id
32+
"""
933
CORRELATION_ID = 'cid'
1034
TENANT_ID = 'tid'
1135
USER_ID = 'uid'
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
from enum import Enum
22

33
class RequestHeaderKeys(Enum):
4+
"""
5+
Header keys
6+
7+
Attributes
8+
----------
9+
ACCOUNT_ID : str
10+
Account Id / Tenant ID
11+
USER_ID : str
12+
User Id
13+
CORRELATION_ID : str
14+
Correlation Id
15+
"""
416
ACCOUNT_ID = 'x-smtip-tid',
517
USER_ID = 'x-smtip-uid',
618
CORRELATION_ID = 'x-smtip-cid',

python_common_logger/src/context/context_handler.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,34 @@
44

55
_locals = local()
66

7-
def get_thread_execution_context() -> ExecutionContext:
8-
return getattr(_locals, 'execution_context', ExecutionContext({}))
7+
def get_thread_execution_context(key='execution_context') -> ExecutionContext:
8+
"""
9+
Fetches the execution context from the thread local. If absent, initialises and returns an empty one.
910
10-
def update_execution_context(execution_context: ExecutionContext, reset=False):
11+
Args:
12+
key (str, optional): key. Defaults to 'execution_context'.
13+
14+
Returns:
15+
ExecutionContext: Thread local execution context.
16+
"""
17+
return getattr(_locals, key, ExecutionContext({}))
18+
19+
def update_execution_context(execution_context: ExecutionContext, key='execution_context', reset=False) -> ExecutionContext:
20+
"""
21+
Updates the execution context.
22+
23+
Args:
24+
execution_context (ExecutionContext): Execution context to be updated.
25+
key (str, optional): key. Defaults to 'execution_context'.
26+
reset (bool, optional): Reset the entire context. Defaults to False.
27+
28+
Returns:
29+
ExecutionContext: Updated execution context
30+
"""
1131
current_execution_context: ExecutionContext = get_thread_execution_context()
1232

1333
current_execution_context.update(execution_context.get_context(), reset)
1434

15-
setattr(_locals, 'execution_context', current_execution_context)
35+
setattr(_locals, key, current_execution_context)
36+
1637
return current_execution_context

python_common_logger/src/context/execution_context.py

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,23 @@
44
from ..constants.context import ExecutionContextType
55

66
class ExecutionContext:
7+
"""
8+
Stores the Execution context and provides helper methods to manage it.
9+
10+
Methods
11+
-------
12+
update(execution_context:dict, reset:bool=False):
13+
Updates the Execution Context.
14+
15+
get_context_by_key(key:str):
16+
Returns the execution context stored for the provided key.
17+
18+
get_context() -> dict:
19+
Returns the entire execution context.
20+
21+
reset(key:str):
22+
Resets the context.
23+
"""
724
ALLOWED_KEYS = [e.value for e in ExecutionContextType]
825

926
def __init__(self, execution_context: dict):
@@ -16,21 +33,48 @@ def __init__(self, execution_context: dict):
1633
self._context[key] = execution_context[key]
1734

1835
def update(self, execution_context: dict, reset=False):
36+
"""
37+
Updates the execution context.
38+
39+
Args:
40+
execution_context (dict): Execution context to be updated.
41+
reset (bool, optional): If True, replaces the entire context. If False, updates only the provided values. Defaults to False.
42+
43+
Raises:
44+
ValidationException: If an invalid key is provided.
45+
"""
1946
if reset:
2047
self.reset()
2148

2249
for key in execution_context.keys():
2350
if key not in self.ALLOWED_KEYS:
24-
# TODO: Create Validation error
2551
raise ValidationException(f'Invalid execution context type: {key}')
2652
else:
2753
self._context[key] = execution_context[key]
2854

2955
def get_context_by_key(self, key: str) -> str:
56+
"""
57+
Returns the execution context for the specified key
58+
59+
Args:
60+
key (str): key
61+
62+
Returns:
63+
any: Execution Context
64+
"""
3065
return copy.deepcopy(self._context[key])
3166

3267
def get_context(self) -> dict:
68+
"""
69+
Returns the execution context.
70+
71+
Returns:
72+
dict: Entire execution context
73+
"""
3374
return copy.deepcopy(self._context)
3475

3576
def reset(self):
77+
"""
78+
Resets the execution context.
79+
"""
3680
self._context = {}

python_common_logger/src/django/middleware.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
from ..constants.context import ExecutionContextType
77

88
class ContextMiddleware():
9+
"""
10+
Django Context Middle. Extracts the headers from the request and populates the execution context
11+
in thread local data.
12+
"""
913
def __init__(self, get_response):
1014
self.get_response = get_response
1115

python_common_logger/src/logger.py

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@
55
from .context.context_handler import get_thread_execution_context
66
from .context.execution_context import ExecutionContext, ExecutionContextType
77

8-
from .constants.logger import LoggerKeys, ContextConfig
8+
from .constants.logger import LoggerKeys, LoggerContextConfigKeys
99
from .constants.context import ExecutionContextType
1010

1111
class ContextFilter(logging.Filter):
12+
"""
13+
Log filter to extract the execution context from thread locals and populate it in the log record
14+
"""
15+
1216
def filter(self, record):
1317
execution_context: ExecutionContext = get_thread_execution_context()
1418

@@ -21,15 +25,27 @@ def filter(self, record):
2125
setattr(record, key, '')
2226
return True
2327

24-
def initialise_console_logger(service_name, level=logging.WARNING, context_config=None):
25-
logger = logging.getLogger(service_name)
28+
def initialise_console_logger(logger_name, service_name, level=logging.WARNING, context_config=None):
29+
"""
30+
Initialises the logger with the handler, formatter and filter to log context data along with message
31+
in JSON format on the console.
32+
33+
Args:
34+
logger_name (string): Name of the logger to be initialised
35+
service_name (string): Service name that appears as the source in the logs
36+
level (int, optional): Log level. Defaults to logging.WARNING.
37+
context_config (dict, optional): Context config to configure logging parameters See LoggerContextConfigKeys for list of allowed params. Defaults to None.
38+
39+
Returns:
40+
Logger: Initialised logger
41+
"""
42+
logger = logging.getLogger(logger_name)
2643

2744
# Create handlers
28-
c_handler = logging.StreamHandler(sys.stdout)
45+
log_handler = logging.StreamHandler(sys.stdout)
2946

30-
# Populate Context Filter in Record
3147
log_format = {
32-
"source": "%(name)s",
48+
"source": f"{service_name}",
3349
"time": "%(asctime)s",
3450
"log": {
3551
"message": "%(message)s"
@@ -40,23 +56,24 @@ def initialise_console_logger(service_name, level=logging.WARNING, context_confi
4056
if not context_config:
4157
context_config = {}
4258

43-
if not context_config.get(ContextConfig.DISABLE_CID.value):
59+
if not context_config.get(LoggerContextConfigKeys.DISABLE_CID.value):
4460
log_format[LoggerKeys.CORRELATION_ID.value] = f"%({ExecutionContextType.CORRELATION_ID.value})s"
4561

46-
if not context_config.get(ContextConfig.DISABLE_TID.value):
62+
if not context_config.get(LoggerContextConfigKeys.DISABLE_TID.value):
4763
log_format[LoggerKeys.TENANT_ID.value] = f"%({ExecutionContextType.TENANT_ID.value})s"
4864

49-
if not context_config.get(ContextConfig.DISABLE_UID.value):
65+
if not context_config.get(LoggerContextConfigKeys.DISABLE_UID.value):
5066
log_format[LoggerKeys.USER_ID.value] = f"%({ExecutionContextType.USER_ID.value})s"
5167

5268
# Create formatters and add it to handlers
53-
c_format = logging.Formatter(json.dumps(log_format), datefmt='%Y-%m-%dT%H:%M:%S%z')
69+
log_formatter = logging.Formatter(json.dumps(log_format), datefmt='%Y-%m-%dT%H:%M:%S%z')
70+
log_handler.setFormatter(log_formatter)
71+
72+
# Populate Context Filter in Record
73+
log_handler.addFilter(ContextFilter())
5474

55-
c_handler.setFormatter(c_format)
56-
c_handler.addFilter(ContextFilter())
75+
logger.addHandler(log_handler)
5776

58-
# Add handlers to the logger
59-
logger.addHandler(c_handler)
6077
logger.setLevel(level)
6178

6279
return logger

0 commit comments

Comments
 (0)