edit : 기본 rest서버구조 추가

This commit is contained in:
2025-01-14 17:26:27 +09:00
parent e53282d7e7
commit bd28fcdca4
37 changed files with 4194 additions and 1 deletions

View File

@@ -0,0 +1,211 @@
"""The ColoredFormatter class."""
from __future__ import absolute_import
import logging
import sys
from .escape_codes import escape_codes, parse_colors
__all__ = ('escape_codes', 'default_log_colors', 'ColoredFormatter',
'LevelFormatter', 'TTYColoredFormatter')
# The default colors to use for the debug levels
default_log_colors = {
'DEBUG': 'white',
'INFO': 'green',
'WARNING': 'yellow',
'ERROR': 'red',
'CRITICAL': 'bold_red',
}
# The default format to use for each style
default_formats = {
'%': '%(log_color)s%(levelname)s:%(name)s:%(message)s',
'{': '{log_color}{levelname}:{name}:{message}',
'$': '${log_color}${levelname}:${name}:${message}'
}
class ColoredRecord(object):
"""
Wraps a LogRecord, adding named escape codes to the internal dict.
The internal dict is used when formatting the message (by the PercentStyle,
StrFormatStyle, and StringTemplateStyle classes).
"""
def __init__(self, record):
"""Add attributes from the escape_codes dict and the record."""
self.__dict__.update(escape_codes)
self.__dict__.update(record.__dict__)
# Keep a reference to the original record so ``__getattr__`` can
# access functions that are not in ``__dict__``
self.__record = record
def __getattr__(self, name):
return getattr(self.__record, name)
class ColoredFormatter(logging.Formatter):
"""
A formatter that allows colors to be placed in the format string.
Intended to help in creating more readable logging output.
"""
def __init__(self, fmt=None, datefmt=None, style='%',
log_colors=None, reset=True,
secondary_log_colors=None):
"""
Set the format and colors the ColoredFormatter will use.
The ``fmt``, ``datefmt`` and ``style`` args are passed on to the
``logging.Formatter`` constructor.
The ``secondary_log_colors`` argument can be used to create additional
``log_color`` attributes. Each key in the dictionary will set
``{key}_log_color``, using the value to select from a different
``log_colors`` set.
:Parameters:
- fmt (str): The format string to use
- datefmt (str): A format string for the date
- log_colors (dict):
A mapping of log level names to color names
- reset (bool):
Implicitly append a color reset to all records unless False
- style ('%' or '{' or '$'):
The format style to use. (*No meaning prior to Python 3.2.*)
- secondary_log_colors (dict):
Map secondary ``log_color`` attributes. (*New in version 2.6.*)
"""
if fmt is None:
if sys.version_info > (3, 2):
fmt = default_formats[style]
else:
fmt = default_formats['%']
if sys.version_info > (3, 2):
super(ColoredFormatter, self).__init__(fmt, datefmt, style)
elif sys.version_info > (2, 7):
super(ColoredFormatter, self).__init__(fmt, datefmt)
else:
logging.Formatter.__init__(self, fmt, datefmt)
self.log_colors = (
log_colors if log_colors is not None else default_log_colors)
self.secondary_log_colors = secondary_log_colors
self.reset = reset
def color(self, log_colors, level_name):
"""Return escape codes from a ``log_colors`` dict."""
return parse_colors(log_colors.get(level_name, ""))
def format(self, record):
"""Format a message from a record object."""
record = ColoredRecord(record)
record.log_color = self.color(self.log_colors, record.levelname)
# Set secondary log colors
if self.secondary_log_colors:
for name, log_colors in self.secondary_log_colors.items():
color = self.color(log_colors, record.levelname)
setattr(record, name + '_log_color', color)
# Format the message
if sys.version_info > (2, 7):
message = super(ColoredFormatter, self).format(record)
else:
message = logging.Formatter.format(self, record)
# Add a reset code to the end of the message
# (if it wasn't explicitly added in format str)
if self.reset and not message.endswith(escape_codes['reset']):
message += escape_codes['reset']
return message
class LevelFormatter(ColoredFormatter):
"""An extension of ColoredFormatter that uses per-level format strings."""
def __init__(self, fmt=None, datefmt=None, style='%',
log_colors=None, reset=True,
secondary_log_colors=None):
"""
Set the per-loglevel format that will be used.
Supports fmt as a dict. All other args are passed on to the
``colorlog.ColoredFormatter`` constructor.
:Parameters:
- fmt (dict):
A mapping of log levels (represented as strings, e.g. 'WARNING') to
different formatters. (*New in version 2.7.0)
(All other parameters are the same as in colorlog.ColoredFormatter)
Example:
formatter = colorlog.LevelFormatter(fmt={
'DEBUG':'%(log_color)s%(msg)s (%(module)s:%(lineno)d)',
'INFO': '%(log_color)s%(msg)s',
'WARNING': '%(log_color)sWARN: %(msg)s (%(module)s:%(lineno)d)',
'ERROR': '%(log_color)sERROR: %(msg)s (%(module)s:%(lineno)d)',
'CRITICAL': '%(log_color)sCRIT: %(msg)s (%(module)s:%(lineno)d)',
})
"""
if sys.version_info > (2, 7):
super(LevelFormatter, self).__init__(
fmt=fmt, datefmt=datefmt, style=style, log_colors=log_colors,
reset=reset, secondary_log_colors=secondary_log_colors)
else:
ColoredFormatter.__init__(
self, fmt=fmt, datefmt=datefmt, style=style,
log_colors=log_colors, reset=reset,
secondary_log_colors=secondary_log_colors)
self.style = style
self.fmt = fmt
def format(self, record):
"""Customize the message format based on the log level."""
if isinstance(self.fmt, dict):
self._fmt = self.fmt[record.levelname]
if sys.version_info > (3, 2):
# Update self._style because we've changed self._fmt
# (code based on stdlib's logging.Formatter.__init__())
if self.style not in logging._STYLES:
raise ValueError('Style must be one of: %s' % ','.join(
logging._STYLES.keys()))
self._style = logging._STYLES[self.style][0](self._fmt)
if sys.version_info > (2, 7):
message = super(LevelFormatter, self).format(record)
else:
message = ColoredFormatter.format(self, record)
return message
class TTYColoredFormatter(ColoredFormatter):
"""
Blanks all color codes if not running under a TTY.
This is useful when you want to be able to pipe colorlog output to a file.
"""
def __init__(self, *args, **kwargs):
"""Overwrite the `reset` argument to False if stream is not a TTY."""
self.stream = kwargs.pop('stream')
# Both `reset` and `isatty` must be true to insert reset codes.
kwargs['reset'] = kwargs.get('reset', True) and self.stream.isatty()
ColoredFormatter.__init__(self, *args, **kwargs)
def color(self, log_colors, level_name):
"""Only returns colors if STDOUT is a TTY."""
if not self.stream.isatty():
log_colors = {}
return ColoredFormatter.color(self, log_colors, level_name)

View File

@@ -0,0 +1,61 @@
"""
Generates a dictionary of ANSI escape codes.
http://en.wikipedia.org/wiki/ANSI_escape_code
Uses colorama as an optional dependency to support color on Windows
"""
try:
import colorama
except ImportError:
pass
else:
colorama.init()
__all__ = ('escape_codes', 'parse_colors')
# Returns escape codes from format codes
def esc(*x):
return '\033[' + ';'.join(x) + 'm'
# The initial list of escape codes
escape_codes = {
'reset': esc('0'),
'bold': esc('01'),
'thin': esc('02')
}
# The color names
COLORS = [
'black',
'red',
'green',
'yellow',
'blue',
'purple',
'cyan',
'white'
]
PREFIXES = [
# Foreground without prefix
('3', ''), ('01;3', 'bold_'), ('02;3', 'thin_'),
# Foreground with fg_ prefix
('3', 'fg_'), ('01;3', 'fg_bold_'), ('02;3', 'fg_thin_'),
# Background with bg_ prefix - bold/light works differently
('4', 'bg_'), ('10', 'bg_bold_'),
]
for prefix, prefix_name in PREFIXES:
for code, name in enumerate(COLORS):
escape_codes[prefix_name + name] = esc(prefix + str(code))
def parse_colors(sequence):
"""Return escape codes from a color sequence."""
return ''.join(escape_codes[n] for n in sequence.split(',') if n)

View File

@@ -0,0 +1,47 @@
"""Wrappers around the logging module."""
from __future__ import absolute_import
import functools
import logging
from .colorlog import ColoredFormatter
BASIC_FORMAT = "%(log_color)s%(levelname)s%(reset)s:%(name)s:%(message)s"
def basicConfig(**kwargs):
"""Call ``logging.basicConfig`` and override the formatter it creates."""
logging.basicConfig(**kwargs)
logging._acquireLock()
try:
stream = logging.root.handlers[0]
stream.setFormatter(
ColoredFormatter(
fmt=kwargs.get('format', BASIC_FORMAT),
datefmt=kwargs.get('datefmt', None)))
finally:
logging._releaseLock()
def ensure_configured(func):
"""Modify a function to call ``basicConfig`` first if no handlers exist."""
@functools.wraps(func)
def wrapper(*args, **kwargs):
if len(logging.root.handlers) == 0:
basicConfig()
return func(*args, **kwargs)
return wrapper
root = logging.root
getLogger = logging.getLogger
debug = ensure_configured(logging.debug)
info = ensure_configured(logging.info)
warning = ensure_configured(logging.warning)
error = ensure_configured(logging.error)
critical = ensure_configured(logging.critical)
log = ensure_configured(logging.log)
exception = ensure_configured(logging.exception)
StreamHandler = logging.StreamHandler

116
custom_logger/custom_log.py Normal file
View File

@@ -0,0 +1,116 @@
# -*- coding: utf-8 -*-
"""
@file : custom_log.py
@author: hsj100
@license: DAOOLDNS
@brief:
@section Modify History
- 2024-05-08 오후 2:33 hsj100 base
"""
# import ai_config
import datetime
import os
import logging
from custom_logger.colorlog.colorlog import ColoredFormatter
custom_logger = None
_now = datetime.datetime.now()
LOGGER_NAME = 'dk'
LOGGER_LEVEL = logging.INFO
LOGGER_DIR = "log/"
LOGGER_FILE_NAME = f'{_now.strftime("%Y-%m-%d %H_%M_%S")}_{LOGGER_NAME}.log'
__LOGGER_FILE_PATH = LOGGER_DIR + LOGGER_FILE_NAME
# __LOGGER_FILE_PATH = None
def logger_init(logger,
level=logging.DEBUG,
# color_log_format = "%(log_color)s%(levelname)s [%(asctime)s] [%(module)s::%(funcName)s()] %(message)s",
color_log_format='%(log_color)s%(levelname)s: [%(module)s::%(funcName)s()] %(message)s',
file_log_path=None,
file_log_format='[%(levelname)s][%(asctime)s][%(module)s::%(funcName)s()] %(message)s'):
"""
로그 정보 초기화
:param logger: 로거 객체
:param level: 스트림 로그 출력 레벨 (지정 레벨 이상의 로그 정보만 출력됨)
:param color_log_format: 스트림 로그 출력 형식
:param file_log_path: 파일 로그 저장 경로 (경로 지정이 없을 경우에는 파일로그는 기록되지 않음)
:param file_log_format: 파일 로그 출력 형식
:return:
"""
# stream handler
color_stream_handler = logging.StreamHandler()
color_stream_handler.setLevel(level)
formatter = ColoredFormatter(
color_log_format,
datefmt=None,
reset=True,
log_colors={
'DEBUG': 'cyan',
'INFO': 'white,bold',
'INFOV': 'cyan,bold',
'WARNING': 'yellow',
'ERROR': 'red,bold',
'CRITICAL': 'red,bg_white',
},
secondary_log_colors={},
style='%'
)
color_stream_handler.setFormatter(formatter)
logger.setLevel(level)
logger.handlers = [] # No duplicated handlers
logger.propagate = False # workaround for duplicated logs in ipython
logger.addHandler(color_stream_handler)
logging.addLevelName(logging.INFO + 1, 'INFOV')
# file handler
if file_log_path:
file_handler = logging.FileHandler(file_log_path)
formatter = logging.Formatter(file_log_format)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
# def _infov(self, msg, *args, **kwargs):
# self.log(logging.INFO + 1, msg, *args, **kwargs)
def get_logger():
"""
로거 객체 반환
로거 객체가 없을 경우에는 로그 초기화를 진행하고 생성된 로그 객체를 반환함
:return: 로그 객체
"""
if not custom_logger.handlers:
logger_init(custom_logger)
return custom_logger
if custom_logger is None:
custom_logger = logging.getLogger(LOGGER_NAME)
if not os.path.exists(LOGGER_DIR):
os.makedirs(LOGGER_DIR)
if not __LOGGER_FILE_PATH:
logger_init(custom_logger, level=LOGGER_LEVEL)
else:
if not os.path.exists(LOGGER_DIR):
os.makedirs(LOGGER_DIR)
logger_init(custom_logger, level=LOGGER_LEVEL, file_log_path=__LOGGER_FILE_PATH)
def test():
custom_logger.info('Module: custom_log.py')
if __name__ == '__main__':
test()

View File

@@ -0,0 +1,46 @@
import json
import copy
from datetime import timedelta, datetime
def router_logger(logger_object, request, request_body=None, error=None):
"""
router 로깅
* 안면인식의 경우 이미지데이터가 너무 커서 길이로 return
:param logger_object: logger
:param request: request info
:param request_body: request body info, defaults to None
:param error: traceback, defaults to None
"""
_fr_api_name = "/api/services/AE/FR-Recognize"
time_format = '%Y/%m/%d %H:%M:%S'
request_body_dict = copy.deepcopy(request_body.dict()) if request_body else None
if request.url.path == _fr_api_name:
# NOTE 타겟이 하나일 경우 기준
_detect_dict = {
"id": request_body_dict["targets"]["detect_list"][0]["id"],
"worker_image": str(len(request_body_dict["targets"]["detect_list"][0]["worker_image"])),
"target_image": str(len(request_body_dict["targets"]["detect_list"][0]["target_image"]))
}
_detect_list = [_detect_dict]
request_body_dict["targets"]["detect_list"] = _detect_list
log_dict = dict(
api = request.url.path,
datetimeKST = (datetime.utcnow() + timedelta(hours=9)).strftime(time_format),
clientIP = request.state.ip,
request = request_body_dict,
errorDetail = f"{error.format_exc()}" if error else None
)
if error :
logger_object.error(json.dumps(log_dict, ensure_ascii=False))
else:
logger_object.info(json.dumps(log_dict, ensure_ascii=False))