How to log messages _only once_ from all modules ?

B

Barak, Ron

Hi,

I'm trying to add the logging module to my application, but I seem to be missing something.
My application (a wxPython one) has a main script that calls various helper classes.
I want the log messages from all modules to go to one central log file.

When I implement logging, I think that due to preparation, I get the same message more than once.

Here's an example:

$ cat -n server.py
1 import logging
2 import logging.handlers
3
4 class Server():
5 def __init__(self):
6 self.client_logger = logging.getLogger("client")
7 self.client_logger.setLevel(logging.DEBUG)
8 h = logging.FileHandler("client.log")
9 h.setLevel(logging.DEBUG)
10 formatter = logging.Formatter("%(asctime)s %(name)-12s %(levelname)-8s %(message)s")
11 h.setFormatter(formatter)
12 self.client_logger.addHandler(h)
13
14 def util(self):
15 self.client_logger.warning('This message comes from Server module')

$ cat -n client.py
1 import logging
2 import logging.handlers
3 from server import Server
4
5 class Client():
6 def __init__(self):
7 self.client_logger = logging.getLogger("client")
8 self.client_logger.setLevel(logging.DEBUG)
9 h = logging.FileHandler("client.log")
10 h.setLevel(logging.DEBUG)
11 formatter = logging.Formatter("%(asctime)s %(name)-12s %(levelname)-8s %(message)s")
12 h.setFormatter(formatter)
13 self.client_logger.addHandler(h)
14
15 def client_test(self):
16 self.client_logger.warning("This message comes from Client module")
17
18 if __name__ == "__main__":
19 ser = Server()
20 cli = Client()
21 ser.util()
22 cli.client_test()
$ rm client.log ; python client.py ; cat client.log
2009-11-24 14:40:39,762 client WARNING This message comes from Server module
2009-11-24 14:40:39,762 client WARNING This message comes from Server module
2009-11-24 14:40:39,762 client WARNING This message comes from Client module
2009-11-24 14:40:39,762 client WARNING This message comes from Client module
Googling and reading http://docs.python.org/library/logging.html didn't enlighten me.

Could you suggest what should I change in the above scripts so that the log messages would appear only once ?

Thanks,
Ron.
 
R

Ron Barak

Barak, Ron pisze:













Have a look athttp://docs.python.org/library/logging.html#logger-objects
First thing mentioned is Logger.propagate which is, what I believe, you're
looking for ;)

--
Soltys

"Free software is a matter of liberty not price"- Hide quoted text -

- Show quoted text -

Hi Soltys,
I actually tried that, without any noticeable effects, viz.:

$ cat server.py
import logging
import logging.handlers

class Server():
def __init__(self):
self.client_logger = logging.getLogger("client")
self.client_logger.setLevel(logging.DEBUG)
h = logging.FileHandler("client.log")
h.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(asctime)s %(name)-12s %
(levelname)-8s %(message)s")
h.setFormatter(formatter)
self.client_logger.addHandler(h)
self.client_logger.propagate = 0

def util(self):
self.client_logger.warning('This message comes from Server
module')

$ cat client.py
import logging
import logging.handlers
from server import Server

class Client():
def __init__(self):
self.client_logger = logging.getLogger("client")
self.client_logger.setLevel(logging.DEBUG)
h = logging.FileHandler("client.log")
h.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(asctime)s %(name)-12s %
(levelname)-8s %(message)s")
h.setFormatter(formatter)
self.client_logger.addHandler(h)
self.client_logger.propagate = 0

def client_test(self):
self.client_logger.warning("This message comes from Client
module")

if __name__ == "__main__":
ser = Server()
cli = Client()
ser.util()
cli.client_test()

$ rm client.log ; python client.py ; cat client.log
2009-11-24 16:06:35,710 client WARNING This message comes from
Server module
2009-11-24 16:06:35,710 client WARNING This message comes from
Server module
2009-11-24 16:06:35,710 client WARNING This message comes from
Client module
2009-11-24 16:06:35,710 client WARNING This message comes from
Client module

$
 
R

Ron Barak

Ron Barak pisze:
















Rename logger in server.py to server:
self.client_logger = logging.getLogger("server")

Rerun, you should get sth. like this:
$ cat client.log
2009-11-24 16:06:54,990 server WARNING This message comes from Server module
2009-11-24 16:06:54,990 client WARNING This message comes from Client module

--
Soltys

"Free software is a matter of liberty not price"- Hide quoted text -

- Show quoted text -

Many thanks Soltys, that did the trick (actually, no need for setting
propagate to 0), namely,

$ cat client.py
import logging
import logging.handlers
from server import Server

class Client():
def __init__(self):
self.client_logger = logging.getLogger("client")
self.client_logger.setLevel(logging.DEBUG)
h = logging.FileHandler("client.log")
h.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(asctime)s %(name)-12s %
(levelname)-8s %(message)s")
h.setFormatter(formatter)
self.client_logger.addHandler(h)

def client_test(self):
self.client_logger.warning("This message comes from Client
module")

if __name__ == "__main__":
ser = Server()
cli = Client()
ser.util()
cli.client_test()

$ cat server.py
import logging
import logging.handlers

class Server():
def __init__(self):
self.client_logger = logging.getLogger("server")
self.client_logger.setLevel(logging.DEBUG)
h = logging.FileHandler("client.log")
h.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(asctime)s %(name)-12s %
(levelname)-8s %(message)s")
h.setFormatter(formatter)
self.client_logger.addHandler(h)

def util(self):
self.client_logger.warning('This message comes from Server
module')

$ rm client.log ; python client.py ; cat client.log
2009-11-24 17:13:15,989 server WARNING This message comes from
Server module
2009-11-24 17:13:15,989 client WARNING This message comes from
Client module
 
V

Vinay Sajip

Many thanks Soltys, that did the trick (actually, no need for setting
propagate to 0), namely,
[snip]

It might work for now, but instantiating a handler in an instance
constructor can be an anti-pattern. If you ever create multiple client
instances, for example, you would create multiple handlers and add
those to the logger (which is essentially persistent for the lifetime
of the process), which could result in multiple messages, corrupted
output or exceptions (in the general case).

It's generally better to declare module-level loggers via

logger = logging.getLogger(__name__)

or, if better granularity is wanted, loggers with names prefixed by
__name__ + '.' - and handler set up should typically be done in one
place in such a way as to not inadvertently create handlers multiple
times. A common pattern is to just add handlers to the root logger
(e.g. the basicConfig() API does this) - other loggers automatically
get to use them, under normal circumstances.

Regards,

Vinay Sajip
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,999
Messages
2,570,246
Members
46,839
Latest member
MartinaBur

Latest Threads

Top