# -*- coding: utf-8 -*-
# vim:fenc=utf-8

# Copyright (C) 2012-2020 by Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
#
# X2Go Session Broker is free software; you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# X2Go Session Broker is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.

"""\
The :mod:`x2gobroker.loggers` module provides three different logger objects for different purposes:

  * ``logger_broker``: Logging of all sort of things happening in X2Go Session Broker
  * ``logger_access``: Logging of http/https access of the broker's httpd daemon
  * ``logger_error``: Logging of errors encountered at runtime

All ``logger_*`` objects are instantiated via the function :func:`logging.getLogger()` from the :mod:`logging` module..

Depending on the execution context (as a service, in foreground for debugging, as SSH broker), these logging objects are set up slighly different.

"""

import os
import sys
import pwd
import getpass
import logging
import logging.config
import configparser

def init_console_loggers():
    """\
    Initialize loggers that log to stderr.

    :returns: a 3-tuple of (logger_broker, logger_access, logger_error)
    :rtype: ``tuple``
    """
    logger_root = logging.getLogger()
    stderr_handler = logging.StreamHandler(sys.stderr)
    stderr_handler.setFormatter(logging.Formatter(fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt=''))

    # all loggers stream to stderr...
    logger_root.addHandler(stderr_handler)

    logger_broker = logging.getLogger('broker')
    logger_broker.addHandler(stderr_handler)
    logger_broker.propagate = 0

    logger_access = logging.getLogger('access')
    logger_access.addHandler(stderr_handler)
    logger_access.propagate = 0

    logger_error = logging.getLogger('error')
    logger_error.addHandler(stderr_handler)
    logger_error.propagate = 0

    return (logger_broker, logger_access, logger_error)

PROG_NAME = os.path.basename(sys.argv[0])

# load the defaults.conf file, if present
iniconfig_loaded = None
iniconfig_section = '-'.join(PROG_NAME.split('-')[1:])
X2GOBROKER_DEFAULTS = "/etc/x2go/broker/defaults.conf"
if os.path.isfile(X2GOBROKER_DEFAULTS) and os.access(X2GOBROKER_DEFAULTS, os.R_OK):
    iniconfig = configparser.RawConfigParser()
    iniconfig.optionxform = str
    iniconfig_loaded = iniconfig.read(X2GOBROKER_DEFAULTS)

# normally this would go into defaults.py, however, we do not want to create a dependency loop between loggers.py and defaults.py...
if 'X2GOBROKER_DAEMON_USER' in os.environ:
    X2GOBROKER_DAEMON_USER=os.environ['X2GOBROKER_DAEMON_USER']
elif iniconfig_loaded and iniconfig.has_option(iniconfig_section, 'X2GOBROKER_DAEMON_USER'):
    X2GOBROKER_DAEMON_USER=iniconfig.get(iniconfig_section, 'X2GOBROKER_DAEMON_USER')
elif iniconfig_loaded and iniconfig.has_option('common', 'X2GOBROKER_DAEMON_USER'):
    X2GOBROKER_DAEMON_USER=iniconfig.get('common', 'X2GOBROKER_DAEMON_USER')
else:
    X2GOBROKER_DAEMON_USER="x2gobroker"
if 'X2GOBROKER_LOGCONFIG' in os.environ:
    X2GOBROKER_LOGCONFIG=os.environ['X2GOBROKER_LOGCONFIG']
elif iniconfig_loaded and iniconfig.has_option(iniconfig_section, 'X2GOBROKER_LOGCONFIG'):
    X2GOBROKER_LOGCONFIG=iniconfig.get(iniconfig_section, 'X2GOBROKER_LOGCONFIG')
elif iniconfig_loaded and iniconfig.has_option('common', 'X2GOBROKER_LOGCONFIG'):
    X2GOBROKER_LOGCONFIG=iniconfig.get('common', 'X2GOBROKER_LOGCONFIG')
else:
    X2GOBROKER_LOGCONFIG="/etc/x2go/broker/x2gobroker-loggers.conf"

# standalone daemon mode (x2gobroker-daemon)? or x2gobroker-ssh command invocation?
if (
    (getpass.getuser() in (X2GOBROKER_DAEMON_USER, 'root')) or
    (pwd.getpwuid(os.geteuid()).pw_name in (X2GOBROKER_DAEMON_USER, 'root'))
   ) and os.path.exists(X2GOBROKER_LOGCONFIG):

    # we run in standalone daemon mode or broker via SSH (with correct setup),
    # so let's use the system configuration for logging
    logging.config.fileConfig(X2GOBROKER_LOGCONFIG)

    # create loggers
    logger_broker = logging.getLogger('broker')
    logger_access = logging.getLogger('access')
    logger_error = logging.getLogger('error')

else:
    # or interactive mode (called from the cmdline)?
    logger_broker, logger_access, logger_error = init_console_loggers()

def tornado_log_request(handler):
    """\
    Function for overriding the :func:`log_request() <tornado.web.RequestHandler>` method in
    :class:`tornado.web.RequestHandler`.

    :param handler: handler
    :type handler: ``obj``

    """
    if handler.get_status() < 400:
        log_method = logger_access.info
    elif handler.get_status() < 500:
        log_method = logger_access.warning
    else:
        log_method = logger_error.error
    request_time = 1000.0 * handler.request.request_time()
    log_method("%d %s %.2fms", handler.get_status(),
               handler._request_summary(), request_time)
