human
I am working on the file "2020/2020-02-29/MetaProgramming In Python.ipynb".
The first task is:
Pattern 4 : Logging using Metaclasses
Can you write Python program for it?

Write me a the Python program you requested?
assistant
#Here is the Python program you requested.

import logging

logging.basicConfig(filename='example.log', level=logging.INFO)
logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too')

class MyLogSingletonMeta(type):
    logger = logging.getLogger('abc')

    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            instance = super(MyLogSingletonMeta, cls).__call__(*args)
            cls._instances[cls] = instance

            instance.__dict__['logger'] = logging.getLogger('abc')
        return cls._instances[cls]

class MyLogEnabledClass(metaclass=MyLogSingletonMeta):
    def test_function(self):
        self.logger.info('Inside test_function method of Log Enabled class')
        pass    

lec_instance1 = MyLogEnabledClass()
lec_instance2 = MyLogEnabledClass()
lec_instance1.test_function()

print(id(lec_instance1), id(lec_instance2))


!cat example.log

class MyLogger:    
    def __init__(self, logger=None):
        self.logger = logger
        
    def __call__(self, func):
        def wrapper(*args, **kwargs):
            if self.logger is None:
                print(str(func) + " is called")
            else:
                self.logger.info(str(func) + " is called")
            return func(*args, **kwargs)
        return wrapper 

class MyLoggingMeta(type):
    
    def __new__(cls, name, bases, attrs):        
        for item, value in attrs.items():
            if callable(value):
                print("Function item :" + str(item), str(value), type(value))
                attrs[item] = MyLogger()(value)
            else: 
                print(str(item), str(value), type(value))
        return super(MyLoggingMeta, cls).__new__(cls, name, bases, attrs)

class MyClass1(metaclass=MyLoggingMeta):
    def test_m1(self):
        pass
    
    def test_m2(self):
        pass

a= MyClass1()

a.test_m2()

a.test_m1()