From f3da6de12936a260264e7608b0bdbc28398bce3f Mon Sep 17 00:00:00 2001 From: Lucas Capistrant Date: Fri, 21 Dec 2018 08:38:29 -0600 Subject: [PATCH] Add ability to configure app logs to be written to a file (#903) It gives users the option to send Patroni application logs to a File instead of Standard Out. There are three environment variables that can be set to enable and configure file logging. 1. `PATRONI_FILE_LOG_DIR`: Path to a directory that is writeable by the executing user. Having this variable set is what activates file logging. 2. `PATRONI_FILE_LOG_NUM`: This is a rolling file logger. This variable dictates how many log files are retained. 3. `PATRONI_FILE_LOG_SIZE`: This variable dictates the size at which the logs will roll. If `PATRONI_FILE_LOG_DIR` is not set than Patroni will log to stderr (default behavior does not change) Closes https://github.com/zalando/patroni/issues/902 --- .gitignore | 3 +++ docs/ENVIRONMENT.rst | 4 +++- patroni/__init__.py | 19 ++++++++++++++++--- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 4e614bb2..7255a59f 100644 --- a/.gitignore +++ b/.gitignore @@ -51,3 +51,6 @@ scm-source.json docs/build/ docs/source/_static/ docs/source/_templates/ + +# Pycharm IDE +.idea/ diff --git a/docs/ENVIRONMENT.rst b/docs/ENVIRONMENT.rst index a1a02148..1a00ffcd 100644 --- a/docs/ENVIRONMENT.rst +++ b/docs/ENVIRONMENT.rst @@ -8,11 +8,13 @@ It is possible to override some of the configuration parameters defined in the P Global/Universal ---------------- - **PATRONI\_CONFIGURATION**: it is possible to set the entire configuration for the Patroni via ``PATRONI_CONFIGURATION`` environment variable. In this case any other environment variables will not be considered! +- **PATRONI\_FILE\_LOG\_DIR**: Directory to write application logs to. The directory must exist and be writable by the user executing Patroni. If you set this env variable, the application will retain 4 25MB logs by default. You can tune those retention values with PATRONI_LOG_FILE_NUM and PATRONI_LOG_FILE_SIZE (see below). +- **PATRONI\_FILE\_LOG\_NUM**: The number of application logs to retain. +- **PATRONI\_FILE\_LOG\_SIZE**: Size of log application log file that triggers a log rolling. - **PATRONI\_NAME**: name of the node where the current instance of Patroni is running. Must be unique for the cluster. - **PATRONI\_NAMESPACE**: path within the configuration store where Patroni will keep information about the cluster. Default value: "/service" - **PATRONI\_SCOPE**: cluster name - **PATRONI\_LOGLEVEL**: sets the general logging level (see `the docs for Python logging `_) -- **PATRONI\_REQUESTS_LOGLEVEL**: sets the logging level for all HTTP requests e.g. Kubernetes API calls (see `the docs for Python logging `_) Bootstrap configuration ----------------------- diff --git a/patroni/__init__.py b/patroni/__init__.py index 18df8186..be843c8e 100644 --- a/patroni/__init__.py +++ b/patroni/__init__.py @@ -1,3 +1,4 @@ +from logging.handlers import RotatingFileHandler import logging import os import signal @@ -138,11 +139,22 @@ class Patroni(object): def patroni_main(): + logdir = os.environ.get('PATRONI_FILE_LOG_DIR', None) logformat = os.environ.get('PATRONI_LOGFORMAT', '%(asctime)s %(levelname)s: %(message)s') loglevel = os.environ.get('PATRONI_LOGLEVEL', 'INFO') - requests_loglevel = os.environ.get('PATRONI_REQUESTS_LOGLEVEL', 'WARNING') - logging.basicConfig(format=logformat, level=loglevel) - logging.getLogger('requests').setLevel(requests_loglevel) + + if not logdir: + logging.basicConfig(format=logformat, level=loglevel) + else: + logsize = os.environ.get('PATRONI_FILE_LOG_SIZE', 25000000) + lognum = os.environ.get('PATRONI_FILE_LOG_NUM', 4) + + root_logger = logging.getLogger() + root_logger.setLevel(loglevel) + handler = RotatingFileHandler(os.path.join(logdir, 'patroni.log'), mode='a', maxBytes=logsize, + backupCount=lognum) + handler.setFormatter(logging.Formatter(logformat)) + root_logger.addHandler(handler) patroni = Patroni() try: @@ -151,6 +163,7 @@ def patroni_main(): pass finally: patroni.shutdown() + logging.shutdown() def pg_ctl_start(args):