import dataclasses import datetime import logging import os import pprint import time import traceback import typing import orjson as json from izihawa_utils.exceptions import BaseError DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S.%f' class BaseFormatter(logging.Formatter): def _prepare(self, record): if isinstance(record.msg, BaseError): return record.msg.as_internal_dict() elif isinstance(record.msg, typing.Dict) or dataclasses.is_dataclass(record.msg): return record.msg else: return dict(message=super().format(record)) def format(self, record): log_record = self._prepare(record) return json.dumps(log_record).decode() class DefaultHttpFormatter(BaseFormatter): def _prepare(self, record): log_record = super()._prepare(record) timestamp = time.time() formatted_datetime = datetime.datetime.fromtimestamp(timestamp).strftime(DATETIME_FORMAT) user_ip = getattr(record, 'user_ip', None) request_id = getattr(record, 'request_id', None) method = getattr(record, 'method', None) path = getattr(record, 'path', None) log_record.update( unixtime=int(timestamp), timestamp=int(timestamp * 1_000_000), datetime=formatted_datetime, process=os.getpid(), ) if user_ip: log_record['user_ip'] = user_ip if request_id: log_record['request_id'] = request_id if method: log_record['method'] = method if path: log_record['path'] = path return log_record def format(self, record): log_record = self._prepare(record) return json.dumps(log_record).decode() class DefaultFormatter(BaseFormatter): def _prepare(self, record): log_record = super()._prepare(record) timestamp = time.time() formatted_datetime = datetime.datetime.fromtimestamp(timestamp).strftime(DATETIME_FORMAT) log_record.update( unixtime=int(timestamp), timestamp=int(timestamp * 1_000_000), datetime=formatted_datetime, process=os.getpid(), ) return log_record def format(self, record): log_record = self._prepare(record) return json.dumps(log_record).decode() class TracebackFormatter(DefaultFormatter): def format(self, record): log_record = self._prepare(record) value = pprint.pformat(log_record, indent=2) if traceback.sys.exc_info()[0] is not None: value += '\n' + traceback.format_exc() return value default_formatter = DefaultFormatter() default_traceback_formatter = TracebackFormatter()