1

I'm using the logging library and I want to call a function whenever any event is logged. Something like this:

import logging

#logging config here

async def on_log(message, level): #call this whenever something is logged
    print(level, ":", message)

logging.debug("Hello world")

Edit: on_log is a coroutine

Edit2: I tried implementing one of your suggestions but I'm not 100% sure about how to add it to my current logging configuration.

from logging import *
import datetime
import sys

class MyLogger(Handler):
    def emit(*args):
        for item in args:
            print(item)

time = datetime.datetime.today()
logtime = f"{time.year}-{time.month}-{time.day}__{time.hour}h-{time.minute}m-{time.second}s"

file_handler = FileHandler(filename=f'./logs/{logtime}.log')  # File output
stdout_handler = StreamHandler(sys.stdout)  # Console output

basicConfig(
    format=f'[%(asctime)s][%(levelname)s] %(message)s',
    datefmt='%H:%M:%S',
    level=DEBUG,
    handlers=[file_handler, stdout_handler, MyLogger]
)

I get this error: AttributeError: type object 'MyLogger' has no attribute 'formatter'

6
  • Does this answer your question? How to write custom python logging handler? Commented Jun 27, 2020 at 8:41
  • This similar question - stackoverflow.com/questions/46354908/… - doesn't currently have an answer but looks like it has a potentially useful comment. Commented Jun 27, 2020 at 8:41
  • Add a logging handler to the logging configuration. Commented Jun 27, 2020 at 8:41
  • I've taken a look at the other questions, but I still don't really get how to add a custom log handler. Commented Jun 27, 2020 at 8:58
  • Where did you get stuck? Commented Jun 27, 2020 at 9:12

2 Answers 2

7

The comments recommend using a custom handler but I would advise against it since there is a way to do this that is also proposed in the official documentation by using filters. In the specific case here it would work like this:

import logging

def on_log(record):
    print(record.levelname, ":", record.getMessage())
    return True

logging.root.addFilter(on_log)

logging.warning('some log')

Sign up to request clarification or add additional context in comments.

1 Comment

Is it possible to do this when on_log is a coroutine?
0

It is minimal working code

import logging

# --- classes ---

class MyLogger():

    #level = logging.NOTSET
    level = logging.DEBUG

    def handle(*args):
        print('--- args ---')
        for item in args:
            print(item)
        print('---')

# --- main ---

logger = logging.getLogger('test')
logger.setLevel(logging.DEBUG) 
#logger.setLevel(logging.INFO) 

my_logger = MyLogger()
#my_logger.level = logging.DEBUG

logger.addHandler(my_logger)

# --- test ---

logger.debug("DEBUG: Hello world")
logger.info("INFO: Hello world")

It can't be function but class with method handle and in variable level because every handler has own level. This way some handlers can be executed always, other only for debug message.


EDIT:

The same using class Handler which already has variable level and you have to only rewrite method handle. But is better to rewrite method emit which is executed by handle after filtering.

You can set level when you create instance.

import logging

# --- classes ---

class MyLogger(logging.Handler):
    
    #def handle(*args):
    def emit(*args):
        print('--- args ---')
        for item in args:
            print(item)
        print('---')
        
# --- main ---

logger = logging.getLogger('test')
logger.setLevel(logging.DEBUG) 
#logger.setLevel(logging.INFO) 

my_logger = MyLogger(logging.DEBUG)

logger.addHandler(my_logger)

# --- test ---

logger.debug("DEBUG: Hello world")
logger.info("INFO: Hello world")

1 Comment

I'm not really sure how to add add this to my current logging configuration (I edited the post)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.