from os import mkdir
from decouple import config
from os.path import exists
from pythonjsonlogger import jsonlogger
from opentelemetry import trace
from collections import OrderedDict
logFileBasePath = config('LOG_FILE_BASE_PATH', cast=str, default='/tmp')
if not exists(logFileBasePath):
mkdir(logFileBasePath)
class CustomJsonFormatter(jsonlogger.JsonFormatter):
# apply the trace id and span id to logging
def add_fields(self, log_record: OrderedDict, record, message_dict):
super().add_fields(log_record, record, message_dict)
log_record.update({'time': log_record.pop('asctime', None)})
log_record.update({'level': log_record.pop('levelname', None)})
# log_record.move_to_end('level', last=False)
# log_record.move_to_end('time', last=False)
span = trace.get_current_span()
if span is not None and span.is_recording():
ctx = span.get_span_context()
log_record['trace_id'] = format(ctx.trace_id, "032x")
log_record['span_id'] = format(ctx.span_id, "016x")
# formatting the log
LOGGING_CONFIG = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'default_formatter': {
'format': '[%(asctime)s - %(name)s] %(levelname)s : %(funcName)s:%(lineno)d — %(message)s',
'datefmt': '%Y-%m-%dT%H:%M:%SZ',
},
'JsonLoggerFormatter': {
'()': CustomJsonFormatter,
'format': '[%(asctime)s - %(name)s] %(levelname)s : %(funcName)s:%(lineno)d — %(message)s',
'datefmt': '%Y-%m-%dT%H:%M:%SZ',
}
},
'handlers': {
'stream_handler': {
'class': 'logging.StreamHandler',
'formatter': 'JsonLoggerFormatter',
},
'rotating_file_handler': {
'class': 'logging.handlers.RotatingFileHandler',
'formatter': 'JsonLoggerFormatter',
'filename': logFileBasePath + '/python-opentelemetry.log',
"maxBytes": config('LOG_FILE_ROTATE_BYTES_SIZE', cast=int, default=51200000),
"backupCount": config('LOG_FILE_MAX_FILE_HISTORY', cast=int, default=5),
}
},
'loggers': {
'': {
'handlers': ['stream_handler', 'rotating_file_handler'],
'level': config('LOG_LEVEL', cast=str, default='INFO'),
'propagate': True
}
}
}