0

I'm having an issue configuring logging for multiple objects.

Presently, I have two classes representing a server and a coordinator. These are composed such that a coordinator has a server as in instance variable.

See below:

class Coordinator(object):
    def __init__(self):
        self.scheduler = asyncio.get_event_loop()
        self.server = Server(..)


class Server(object):
    def __init__(self, scheduler, host, port):

        ...

        # Configure WebSocket logging
        self.logger = logging.getLogger('websockets')
        self.logger.setLevel(logging.DEBUG)
        self.logger.addHandler(logging.StreamHandler())

        ...

Before I added the coordinator class the logging in the server class was able to extract the websockets values and display the output.

This no longer works. How can I resolve this issue, and add an additional logger to the Coordinator class?

I'm using python 3.6.8

Thanks

Hasan
  • 1,243
  • 12
  • 27

1 Answers1

0

It's unclear from your code snippet exactly how you intend for your classes to be initialized (order, how many copies, etc). My guess would be your issue is you are trying to configure a separate stream handler for each class logger.

In general to use python logging you want to do the following:

1) Configure logging near your main entry point

This consists of setting up any handlers to control where the log messages will go and what levels of messages. The easiest way to do this is call logging.basicConfig(..). You want to ensure this is done once and only once. Also you want it to happen before any of your logging calls, so typically this will be one of the first things in your main(..) function.

2) Create and use loggers at their location

You can create as many loggers as you want and give them whatever name you want. Creating one per module using log = logging.getLogger(__name__) is a good way to start, but you can do per class instead if you prefer.

Example:

import logging


class Coordinator(object):
    def __init__(self):
        self.logger = logging.getLogger('Coordinator')
        self.server = Server()

    def do_whatever(self):
        self.logger.warn("In coordinator")
        self.server.do_whatever()


class Server(object):
    def __init__(self):
        self.logger = logging.getLogger('Server')

    def do_whatever(self):
        self.logger.warn("in server")


if __name__ == '__main__':
    # Logs to stderr by default all messages DEBUG or higher
    logging.basicConfig(level=logging.DEBUG)

    # Set the logging level specifically for the websockets log object
    logging.getLogger('websockets').setLevel(logging.INFO)

    c = Coordinator()
    c.do_whatever()

Which logs to stderr:

WARNING:Coordinator:In coordinator
WARNING:Server:in server
INFO:websockets:...whatever this library logs...
Ryan Widmaier
  • 7,948
  • 2
  • 30
  • 32
  • Thank you for your answer. I need to get the logs from the [websocket](https://websockets.readthedocs.io/en/stable/cheatsheet.html#debugging). How can I achieve this with your code? – Garry Herns Feb 06 '19 at 20:32
  • Ah I see now, I didn't fully understand your question. I'll add to my example, but if you want to change the logging level for just a specific logger (like one in a library) you can do that like they show in their example. You should still leave the config of the handlers to the top of your main function. – Ryan Widmaier Feb 06 '19 at 20:38
  • Thank you very much Ryan – Garry Herns Feb 06 '19 at 21:07