You can add logging handlers to the default logger in jupyterhub_config.py:
# create your handler
h = logging.handlers.RotatingFileHandler("jupyterhub.log", backupCount=2, maxBytes=1024 * 1024)
formatter = logging.Formatter(
"[%(levelname)1.1s %(asctime)s %(name)s %(module)s:%(lineno)d] %(message)s"
# get the logger
root_log = traitlets.log.get_logger()
# connect your handler to the logger
However, there aren’t a lot of docs for doing this because I don’t really recommend doing it this way. Using a Python logging handler means you won’t get all the logs. You will only get actual log statements from the application you are configuring, .i.e. only hub logs, no proxy logs, no single-user server logs.
I think it’s generally preferable to use whatever service-runner (e.g. supervisor, systemd, docker) you use to launch jupyterhub to capture stdout/stderr and handle log rotation at that level. Then you get much more robust capture.