What is the singleton pattern

Multiple initializations that return only the same object are called singletons

Why use the singleton pattern

  1. Some objects in your code, such as log objects, can use singleton mode to prevent multiple initializations
  2. Some model objects are bulky and slow to load, so singleton patterns must be used

A thread-safe implementation of Python singleton

import threading

class SingletonType(type) :
    _instance_lock = threading.Lock()
    def __call__(cls, *args, **kwargs) :
        if not hasattr(cls, "_instance") :with SingletonType._instance_lock:
                if not hasattr(cls, "_instance"):
                    cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)
        return cls._instance

class Foo(metaclass=SingletonType) :
    def __init__(self,name) :
        self.name = name
        print(name)


obj1 = Foo('name2')
obj2 = Foo('name1')
print(obj1,obj2)

The init function is executed only once
# python3 singlon.py 
# name2
# <__main__.Foo object at 0x7f7cd9b04860> <__main__.Foo object at 0x7f7cd9b04860>

Copy the code

Use singletons to encapsulate log objects

  1. Implement log singletons
  2. Implement log hierarchical output files
  3. Implement weekly log file saving

Singleton.py Singleton base class

#! /usr/bin/python
# -*- coding:utf-8 -*-
"" @file: singleton.py @time: 2020/12/14 14:17:11@author: lmk@version: 1.0"

import threading

class SingletonType(type) :
    _instance_lock = threading.Lock()
    def __call__(cls, *args, **kwargs) :
        if not hasattr(cls, "_instance") :with SingletonType._instance_lock:
                if not hasattr(cls, "_instance"):
                    cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)
        return cls._instance

if __name__ == '__main__':
    pass
Copy the code

Singleton_log. py Changes the log file every midnight

#! /usr/bin/python
# -*- coding:utf-8 -*-
"@file: singleton_log.py @time: 2020/12/14 14:26:05@author: lmk@version: 1.0"


from scripts.Singleton import SingletonType
from logging import Logger
import logging  # Introduce the logging module
import logging.handlers
import os
import time

from gen_log.a_log_config import info_log_path,err_log_path


class singleLogger(metaclass=SingletonType) :
    def __init__(self) :
        Step 1, create a Logger
        self.logger = logging.getLogger()
        self.logger.setLevel(logging.INFO)  # Log level master switch

        Step 2 create a handler for writing to the log file
        # fh = logging.FileHandler(info_log_path,mode="w")
        info_fh = logging.handlers.TimedRotatingFileHandler(info_log_path,when="midnight")

        # fh.setlevel (logging.debug) # Switch the log level of output to file
        # Set the log filter
        info_filter = logging.Filter()
        info_filter.filter = lambda record: record.levelno <= logging.WARNING # set filter level
        info_fh.setLevel(logging.INFO)
        info_fh.addFilter(info_filter)


        # fh = logging.FileHandler(info_log_path,mode="w")
        err_fh = logging.handlers.TimedRotatingFileHandler(err_log_path,when="midnight")


        # fh.setlevel (logging.debug) # Switch the log level of output to file
        err_filter = logging.Filter()
        err_filter.filter = lambda record: record.levelno > logging.WARNING
        err_fh.setLevel(logging.ERROR)
        err_fh.addFilter(err_filter)
       

        Step 3: Define the output format of this handler
        formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: \n%(message)s\n")
        info_fh.setFormatter(formatter)
        err_fh.setFormatter(formatter)
        Step 4: Add logger to handler
        self.logger.addHandler(info_fh)
        self.logger.addHandler(err_fh)

logger = singleLogger().logger

Copy the code

A_log_config. py Log configuration

#! /usr/bin/python
# -*- coding:utf-8 -*-
"" @file: a_log_config.py @time: 2020/12/14 13:28:02@author: lmk@version: 1.0"


import os 
import time

opdn = os.path.dirname
dirpath = opdn(opdn(__file__))

logs_dir_path = os.path.join(dirpath,"Logs")

Message log path
# info_log_name = time.strftime('info_%Y%m%d.log', time.localtime(time.time()))
info_log_name = time.strftime('info.log', time.localtime(time.time()))
info_log_path = os.path.join(logs_dir_path,info_log_name)

Error log path
# err_log_name = time.strftime('err_%Y%m%d.log', time.localtime(time.time()))
err_log_name = time.strftime('err.log', time.localtime(time.time()))
err_log_path = os.path.join(logs_dir_path,err_log_name)



if __name__ == '__main__':
    pass
Copy the code

Finally, exceptions can be written to the log at the project entry

main.py s = traceback.format_exc() logger.error(s)

Extract and log the exception call stack information


Start processing authorization files periodically
@my_decorator.while_do
def grant_auth() :
    try:
        global count
        count+=1
        deal_temp_grant()
        raise(Exception("err {}".format(count)))
    except:
        s = traceback.format_exc()
        logger.error(s)
        
Copy the code