Python / Django: connectez-vous à la console sous runserver, connectez-vous au fichier sous Apache

114

Comment puis-je envoyer des messages de trace à la console (comme print) lorsque j'exécute mon application Django sous manage.py runserver, mais que ces messages soient envoyés dans un fichier journal lorsque j'exécute l'application sous Apache?

J'ai examiné la journalisation de Django et bien que j'ai été impressionné par sa flexibilité et sa configurabilité pour les utilisations avancées, je suis toujours perplexe sur la façon de gérer mon cas d'utilisation simple.

Justin Grant
la source
1
La solution la plus simple consiste à avoir différents fichiers settings.py pour le serveur principal et l'environnement de développement, voir deploydjango.com/django_project_structure
Alex

Réponses:

84

Le texte imprimé sur stderr apparaîtra dans le journal des erreurs de httpd lors de l'exécution sous mod_wsgi. Vous pouvez soit utiliser printdirectement, soit utiliser à la loggingplace.

print >>sys.stderr, 'Goodbye, cruel world!'
Ignacio Vazquez-Abrams
la source
2
Ce n'est techniquement pas WSGI valide et provoquera des erreurs dans des environnements plus stricts.
Paul McMillan
13
Il n'y a rien de mal à utiliser «print» avec «sys.stderr» pour WSGI et cela ne devrait pas déclencher d'erreurs.
Graham Dumpleton
J'ai importé sys mais cela ne semble pas fonctionner pour moi.
Hack-R
17
Cela ne fonctionne pas dans Python 3, regardez ici . Vous avez besoinprint("Goodbye cruel world!", file=sys.stderr)
cardamome
103

Voici une solution basée sur la journalisation Django. Il utilise le paramètre DEBUG plutôt que de vérifier si vous exécutez ou non le serveur de développement, mais si vous trouvez un meilleur moyen de vérifier cela, il devrait être facile à adapter.

LOGGING = {
    'version': 1,
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
        },
        'simple': {
            'format': '%(levelname)s %(message)s'
        },
    },
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'file': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler',
            'filename': '/path/to/your/file.log',
            'formatter': 'simple'
        },
    },
    'loggers': {
        'django': {
            'handlers': ['file'],
            'level': 'DEBUG',
            'propagate': True,
        },
    }
}

if DEBUG:
    # make all loggers use the console.
    for logger in LOGGING['loggers']:
        LOGGING['loggers'][logger]['handlers'] = ['console']

voir https://docs.djangoproject.com/en/dev/topics/logging/ pour plus de détails.

m01
la source
8
essayez aussiLOGGING['loggers'][logger]['handlers'] += ['console']
Nir Levy
@ m01: Après avoir configuré ceci dans settings.py, comment l'utiliser à des fins d'impression? Merci
Niks Jain
J'ai mis le code de ma réponse dans mon settings.pyvers le bas, et mis DEBUG = True(recherchez ce paramètre près du haut dans le même fichier). Ensuite, je cours python manage.py runserverdepuis un terminal (voir la documentation django pour plus de détails) et les messages du journal apparaîtront dans la fenêtre du terminal. En production, j'utiliserais un autre settings.py, où DEBUG = False- les messages du journal vont /path/to/your/file.log.
m01
Votre indentation m'a donné un mal de tête. Merci pour l'info, ça marche!
ioan
Merci! J'ai apporté quelques modifications à l'indentation, j'espère que c'est mieux maintenant
m01
27

Vous pouvez configurer la journalisation dans votre settings.pyfichier.

Un exemple:

if DEBUG:
    # will output to your console
    logging.basicConfig(
        level = logging.DEBUG,
        format = '%(asctime)s %(levelname)s %(message)s',
    )
else:
    # will output to logging file
    logging.basicConfig(
        level = logging.DEBUG,
        format = '%(asctime)s %(levelname)s %(message)s',
        filename = '/my_log_file.log',
        filemode = 'a'
    )

Cependant, cela dépend de la configuration de DEBUG, et peut-être que vous ne voulez pas avoir à vous soucier de la façon dont il est configuré. Voir cette réponse sur Comment puis-je savoir si mon application Django est exécutée sur un serveur de développement ou non? pour une meilleure façon d'écrire ce conditionnel. Edit: l'exemple ci-dessus est issu d'un projet Django 1.1, la configuration de la journalisation dans Django a quelque peu changé depuis cette version.

bennylope
la source
Je ne veux pas compter sur DEBUG; Je dépendrais plutôt du mécanisme de détection du serveur de développement lié dans cet autre article. Mais le mécanisme de détection de l'autre poste repose sur l'accès à une instance de requête. Comment puis-je obtenir une instance de requête dans settings.py?
Justin Grant
4

J'utilise ceci:

logging.conf:

[loggers]
keys=root,applog
[handlers]
keys=rotateFileHandler,rotateConsoleHandler

[formatters]
keys=applog_format,console_format

[formatter_applog_format]
format=%(asctime)s-[%(levelname)-8s]:%(message)s

[formatter_console_format]
format=%(asctime)s-%(filename)s%(lineno)d[%(levelname)s]:%(message)s

[logger_root]
level=DEBUG
handlers=rotateFileHandler,rotateConsoleHandler

[logger_applog]
level=DEBUG
handlers=rotateFileHandler
qualname=simple_example

[handler_rotateFileHandler]
class=handlers.RotatingFileHandler
level=DEBUG
formatter=applog_format
args=('applog.log', 'a', 10000, 9)

[handler_rotateConsoleHandler]
class=StreamHandler
level=DEBUG
formatter=console_format
args=(sys.stdout,)

testapp.py:

import logging
import logging.config

def main():
    logging.config.fileConfig('logging.conf')
    logger = logging.getLogger('applog')

    logger.debug('debug message')
    logger.info('info message')
    logger.warn('warn message')
    logger.error('error message')
    logger.critical('critical message')
    #logging.shutdown()

if __name__ == '__main__':
    main()
xuejunliang
la source
0

Vous pouvez le faire assez facilement avec tagalog(https://github.com/dorkitude/tagalog)

Par exemple, alors que le module python standard écrit dans un objet fichier ouvert en mode ajout, le module App Engine (https://github.com/dorkitude/tagalog/blob/master/tagalog_appengine.py) remplace ce comportement et l'utilise à la place logging.INFO.

Pour obtenir ce comportement dans un projet App Engine, il suffit de faire:

import tagalog.tagalog_appengine as tagalog
tagalog.log('whatever message', ['whatever','tags'])

Vous pouvez étendre le module vous-même et écraser la fonction de journalisation sans trop de difficulté.

Kyle sauvage
la source
0

Cela fonctionne assez bien dans mon local.py, cela m'évite de gâcher la journalisation régulière:

from .settings import *

LOGGING['handlers']['console'] = {
    'level': 'DEBUG',
    'class': 'logging.StreamHandler',
    'formatter': 'verbose'
}
LOGGING['loggers']['foo.bar'] = {
    'handlers': ['console'],
    'propagate': False,
    'level': 'DEBUG',
}
jmoz
la source