Le problème vient du fait que ton code initialisant logging et son logger est appelé plusieurs fois : à chaque import monModuleInitialisantLeLogging.
De fait, à chaque appel, un nouveau logger est configuré et ajouté, d'où une apparition incrémentale de message de log identiques. Cela explique aussi pourquoi Logger.handlers.clear() résoud le problème : à chaque appel le logger précédent est supprimé, et le nouveau est ajouté.
Une solution plus propre est de mettre l'initialisation de logging dans un fichier à part, par exemple initlogger.py, et de ne l'importer que dans un seul module, par exemple logs.
# file: logs/initlogger.py
import logging
from logging.handlers import RotatingFileHandler
# next lines of initialization…
Dans le même module, le fichier qui fait l'interface (ou dans l'init.py) :
# file: logs/logs.py
import logs.initlogger
from logging import * # on veux un accès à tous les membres du module logging
# autres imports, définitions,… relatives à l'usage des logs
logs est importé de multiple fois, mais n'importera lui-même qu'une seule fois le module initlogger, évitant ainsi les initialisations incrémentales.
Et, dans tous les modules qui veulent faire des logs :
# file: entity/monster.py
import logs.logs as logs # peut être simplifié avec l'usage d'un __init__.py dans le module logs
logger = logs.getLogger()
logger.info("here's Johnny !")
Personnellement, j'utilise le snippet suivant pour les logs, définition que j'ajoute dans initlogger.py, lui-même importé une seule fois dans le module poubelle commons.py ou utils.py :
LOGGER_NAME = 'HeliosOne'
def logger(sublogger=None, name=LOGGER_NAME):
if sublogger:
return logging.getLogger(name + '.' + sublogger)
else:
return logging.getLogger(name)
L'intérêt est qu'aucun module n'utilise logging directement, mais demande uniquement un point d'accès au logger.
Les autres modules fonctionnent donc ainsi :
import commons
logger = commons.logger('engine') # ou gui, ou database, ou sans argument, selon le module
logger.info('Folsom Prison Blues')