logger_setup.py 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. '''
  2. logger_setup.py customizes the app's logging module. Each time an event is
  3. logged the logger checks the level of the event (eg. debug, warning, info...).
  4. If the event is above the approved threshold then it goes through. The handlers
  5. do the same thing; they output to a file/shell if the event level is above their
  6. threshold.
  7. :Example:
  8. >>> from website import logger
  9. >>> logger.info('event', foo='bar')
  10. **Levels**:
  11. - logger.debug('For debugging purposes')
  12. - logger.info('An event occured, for example a database update')
  13. - logger.warning('Rare situation')
  14. - logger.error('Something went wrong')
  15. - logger.critical('Very very bad')
  16. You can build a log incrementally as so:
  17. >>> log = logger.new(date='now')
  18. >>> log = log.bind(weather='rainy')
  19. >>> log.info('user logged in', user='John')
  20. '''
  21. import datetime as dt
  22. import logging
  23. from logging.handlers import RotatingFileHandler
  24. import pytz
  25. from flask import request, session
  26. from structlog import wrap_logger
  27. from structlog.processors import JSONRenderer
  28. from app import app
  29. # Set the logging level
  30. app.logger.setLevel(app.config['LOG_LEVEL'])
  31. # Remove the stdout handler
  32. app.logger.removeHandler(app.logger.handlers[0])
  33. TZ = pytz.timezone(app.config['TIMEZONE'])
  34. def add_fields(_, level, event_dict):
  35. ''' Add custom fields to each record. '''
  36. now = dt.datetime.now()
  37. event_dict['timestamp'] = TZ.localize(now, True).astimezone(pytz.utc).isoformat()
  38. event_dict['level'] = level
  39. if session:
  40. event_dict['session_id'] = session.get('session_id')
  41. if request:
  42. try:
  43. event_dict['ip_address'] = request.headers['X-Forwarded-For'].split(',')[0].strip()
  44. except:
  45. event_dict['ip_address'] = 'unknown'
  46. return event_dict
  47. # Add a handler to write log messages to a file
  48. if app.config.get('LOG_FILE'):
  49. file_handler = RotatingFileHandler(app.config['LOG_FILENAME'],
  50. app.config['LOG_MAXBYTES'],
  51. app.config['LOG_BACKUPS'],
  52. 'a',
  53. encoding='utf-8')
  54. file_handler.setLevel(logging.DEBUG)
  55. app.logger.addHandler(file_handler)
  56. # Wrap the application logger with structlog to format the output
  57. logger = wrap_logger(
  58. app.logger,
  59. processors=[
  60. add_fields,
  61. JSONRenderer(indent=None)
  62. ]
  63. )