We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
logging documentation
Check the log configuration.
The yaml config seems to be wrong. 
Is the indentation of `root:` correct?

https://privacyidea.readthedocs.io/en/master/installation/system/logging.html#debug-log

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `privacyidea/app.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 #
3 # 2014-11-15 Cornelius Kölbel, info@privacyidea.org
4 #            Initial creation
5 #
6 # (c) Cornelius Kölbel
7 # Info: http://www.privacyidea.org
8 #
9 # This code is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
11 # License as published by the Free Software Foundation; either
12 # version 3 of the License, or any later version.
13 #
14 # This code is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 # GNU AFFERO GENERAL PUBLIC LICENSE for more details.
18 #
19 # You should have received a copy of the GNU Affero General Public
20 # License along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 #
22 import os
23 import os.path
24 import logging
25 import logging.config
26 import sys
27 import yaml
28 from flask import Flask, request, Response
29 from flask_babel import Babel
30 from flask_migrate import Migrate
31 from flaskext.versioned import Versioned
32 
33 # we need this import to add the before/after request function to the blueprints
34 import privacyidea.api.before_after
35 from privacyidea.api.validate import validate_blueprint
36 from privacyidea.api.token import token_blueprint
37 from privacyidea.api.system import system_blueprint
38 from privacyidea.api.resolver import resolver_blueprint
39 from privacyidea.api.realm import realm_blueprint
40 from privacyidea.api.realm import defaultrealm_blueprint
41 from privacyidea.api.policy import policy_blueprint
42 from privacyidea.api.user import user_blueprint
43 from privacyidea.api.audit import audit_blueprint
44 from privacyidea.api.application import application_blueprint
45 from privacyidea.api.caconnector import caconnector_blueprint
46 from privacyidea.api.register import register_blueprint
47 from privacyidea.api.auth import jwtauth
48 from privacyidea.webui.login import login_blueprint, get_accepted_language
49 from privacyidea.webui.certificate import cert_blueprint
50 from privacyidea.api.machineresolver import machineresolver_blueprint
51 from privacyidea.api.machine import machine_blueprint
52 from privacyidea.api.ttype import ttype_blueprint
53 from privacyidea.api.smtpserver import smtpserver_blueprint
54 from privacyidea.api.radiusserver import radiusserver_blueprint
55 from privacyidea.api.periodictask import periodictask_blueprint
56 from privacyidea.api.privacyideaserver import privacyideaserver_blueprint
57 from privacyidea.api.recover import recover_blueprint
58 from privacyidea.api.event import eventhandling_blueprint
59 from privacyidea.api.smsgateway import smsgateway_blueprint
60 from privacyidea.api.clienttype import client_blueprint
61 from privacyidea.api.subscriptions import subscriptions_blueprint
62 from privacyidea.api.monitoring import monitoring_blueprint
63 from privacyidea.api.tokengroup import tokengroup_blueprint
64 from privacyidea.lib import queue
65 from privacyidea.lib.log import DEFAULT_LOGGING_CONFIG
66 from privacyidea.config import config
67 from privacyidea.models import db
68 from privacyidea.lib.crypto import init_hsm
69 
70 
71 ENV_KEY = "PRIVACYIDEA_CONFIGFILE"
72 
73 
74 class PiResponseClass(Response):
75     """Custom Response class overwriting the flask.Response.
76     To avoid caching problems with the json property in the Response class,
77     the property is overwritten using a non-caching approach.
78     """
79     @property
80     def json(self):
81         """This will contain the parsed JSON data if the mimetype indicates
82         JSON (:mimetype:`application/json`, see :meth:`is_json`), otherwise it
83         will be ``None``.
84         Caching of the json data is disabled.
85         """
86         return self.get_json(cache=False)
87 
88     default_mimetype = 'application/json'
89 
90 
91 def create_app(config_name="development",
92                config_file='/etc/privacyidea/pi.cfg',
93                silent=False, init_hsm=False):
94     """
95     First the configuration from the config.py is loaded depending on the
96     config type like "production" or "development" or "testing".
97 
98     Then the environment variable PRIVACYIDEA_CONFIGFILE is checked for a
99     config file, that contains additional settings, that will overwrite the
100     default settings from config.py
101 
102     :param config_name: The config name like "production" or "testing"
103     :type config_name: basestring
104     :param config_file: The name of a config file to read configuration from
105     :type config_file: basestring
106     :param silent: If set to True the additional information are not printed
107         to stdout
108     :type silent: bool
109     :param init_hsm: Whether the HSM should be initialized on app startup
110     :type init_hsm: bool
111     :return: The flask application
112     :rtype: App object
113     """
114     if not silent:
115         print("The configuration name is: {0!s}".format(config_name))
116     if os.environ.get(ENV_KEY):
117         config_file = os.environ[ENV_KEY]
118     if not silent:
119         print("Additional configuration will be read "
120               "from the file {0!s}".format(config_file))
121     app = Flask(__name__, static_folder="static",
122                 template_folder="static/templates")
123     if config_name:
124         app.config.from_object(config[config_name])
125 
126     # Set up flask-versioned
127     versioned = Versioned(app, format='%(path)s?v=%(version)s')
128 
129     try:
130         # Try to load the given config_file.
131         # If it does not exist, just ignore it.
132         app.config.from_pyfile(config_file, silent=True)
133     except IOError:
134         sys.stderr.write("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n")
135         sys.stderr.write("  WARNING: privacyidea create_app has no access\n")
136         sys.stderr.write("  to {0!s}!\n".format(config_file))
137         sys.stderr.write("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n")
138 
139     # Try to load the file, that was specified in the environment variable
140     # PRIVACYIDEA_CONFIG_FILE
141     # If this file does not exist, we create an error!
142     app.config.from_envvar(ENV_KEY, silent=True)
143 
144     # We allow to set different static folders
145     app.static_folder = app.config.get("PI_STATIC_FOLDER", "static/")
146     app.template_folder = app.config.get("PI_TEMPLATE_FOLDER", "static/templates/")
147 
148     app.register_blueprint(validate_blueprint, url_prefix='/validate')
149     app.register_blueprint(token_blueprint, url_prefix='/token')
150     app.register_blueprint(system_blueprint, url_prefix='/system')
151     app.register_blueprint(resolver_blueprint, url_prefix='/resolver')
152     app.register_blueprint(realm_blueprint, url_prefix='/realm')
153     app.register_blueprint(defaultrealm_blueprint, url_prefix='/defaultrealm')
154     app.register_blueprint(policy_blueprint, url_prefix='/policy')
155     app.register_blueprint(login_blueprint, url_prefix='/')
156     app.register_blueprint(jwtauth, url_prefix='/auth')
157     app.register_blueprint(user_blueprint, url_prefix='/user')
158     app.register_blueprint(audit_blueprint, url_prefix='/audit')
159     app.register_blueprint(machineresolver_blueprint,
160                            url_prefix='/machineresolver')
161     app.register_blueprint(machine_blueprint, url_prefix='/machine')
162     app.register_blueprint(application_blueprint, url_prefix='/application')
163     app.register_blueprint(caconnector_blueprint, url_prefix='/caconnector')
164     app.register_blueprint(cert_blueprint, url_prefix='/certificate')
165     app.register_blueprint(ttype_blueprint, url_prefix='/ttype')
166     app.register_blueprint(register_blueprint, url_prefix='/register')
167     app.register_blueprint(smtpserver_blueprint, url_prefix='/smtpserver')
168     app.register_blueprint(recover_blueprint, url_prefix='/recover')
169     app.register_blueprint(radiusserver_blueprint, url_prefix='/radiusserver')
170     app.register_blueprint(periodictask_blueprint, url_prefix='/periodictask')
171     app.register_blueprint(privacyideaserver_blueprint,
172                            url_prefix='/privacyideaserver')
173     app.register_blueprint(eventhandling_blueprint, url_prefix='/event')
174     app.register_blueprint(smsgateway_blueprint, url_prefix='/smsgateway')
175     app.register_blueprint(client_blueprint, url_prefix='/client')
176     app.register_blueprint(subscriptions_blueprint, url_prefix='/subscriptions')
177     app.register_blueprint(monitoring_blueprint, url_prefix='/monitoring')
178     app.register_blueprint(tokengroup_blueprint, url_prefix='/tokengroup')
179     db.init_app(app)
180     migrate = Migrate(app, db)
181 
182     app.response_class = PiResponseClass
183 
184     # Setup logging
185     log_read_func = {
186         'yaml': lambda x: logging.config.dictConfig(yaml.safe_load(open(x, 'r').read())),
187         'cfg': lambda x: logging.config.fileConfig(x)
188     }
189     have_config = False
190     log_exx = None
191     log_config_file = app.config.get("PI_LOGCONFIG", "/etc/privacyidea/logging.cfg")
192     if os.path.isfile(log_config_file):
193         for cnf_type in ['cfg', 'yaml']:
194             try:
195                 log_read_func[cnf_type](log_config_file)
196                 if not silent:
197                     print('Read Logging settings from {0!s}'.format(log_config_file))
198                 have_config = True
199                 break
200             except Exception as exx:
201                 log_exx = exx
202                 pass
203     if not have_config:
204         if log_exx:
205             sys.stderr.write("Could not use PI_LOGCONFIG: " + str(log_exx) + "\n")
206         if not silent:
207             sys.stderr.write("Using PI_LOGLEVEL and PI_LOGFILE.\n")
208         level = app.config.get("PI_LOGLEVEL", logging.INFO)
209         # If there is another logfile in pi.cfg we use this.
210         logfile = app.config.get("PI_LOGFILE", '/var/log/privacyidea/privacyidea.log')
211         if not silent:
212             sys.stderr.write("Using PI_LOGLEVEL {0!s}.\n".format(level))
213             sys.stderr.write("Using PI_LOGFILE {0!s}.\n".format(logfile))
214         DEFAULT_LOGGING_CONFIG["handlers"]["file"]["filename"] = logfile
215         DEFAULT_LOGGING_CONFIG["handlers"]["file"]["level"] = level
216         DEFAULT_LOGGING_CONFIG["loggers"]["privacyidea"]["level"] = level
217         logging.config.dictConfig(DEFAULT_LOGGING_CONFIG)
218 
219     babel = Babel(app)
220 
221     @babel.localeselector
222     def get_locale():
223         return get_accepted_language(request)
224 
225     queue.register_app(app)
226 
227     if init_hsm:
228         with app.app_context():
229             init_hsm()
230 
231     logging.debug(u"Reading application from the static folder {0!s} and "
232                   u"the template folder {1!s}".format(app.static_folder, app.template_folder))
233 
234     return app
235
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/privacyidea/app.py b/privacyidea/app.py
--- a/privacyidea/app.py
+++ b/privacyidea/app.py
@@ -228,7 +228,8 @@
         with app.app_context():
             init_hsm()
 
-    logging.debug(u"Reading application from the static folder {0!s} and "
-                  u"the template folder {1!s}".format(app.static_folder, app.template_folder))
+    logging.getLogger(__name__).debug(u"Reading application from the static "
+                                      u"folder {0!s} and the template folder "
+                                      u"{1!s}".format(app.static_folder, app.template_folder))
 
     return app

{"golden_diff": "diff --git a/privacyidea/app.py b/privacyidea/app.py\n--- a/privacyidea/app.py\n+++ b/privacyidea/app.py\n@@ -228,7 +228,8 @@\n         with app.app_context():\n             init_hsm()\n \n-    logging.debug(u\"Reading application from the static folder {0!s} and \"\n-                  u\"the template folder {1!s}\".format(app.static_folder, app.template_folder))\n+    logging.getLogger(__name__).debug(u\"Reading application from the static \"\n+                                      u\"folder {0!s} and the template folder \"\n+                                      u\"{1!s}\".format(app.static_folder, app.template_folder))\n \n     return app\n", "issue": "logging documentation\nCheck the log configuration.\r\nThe yaml config seems to be wrong. \r\nIs the indentation of `root:` correct?\r\n\r\nhttps://privacyidea.readthedocs.io/en/master/installation/system/logging.html#debug-log\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n#\n# 2014-11-15 Cornelius K\u00f6lbel, info@privacyidea.org\n#            Initial creation\n#\n# (c) Cornelius K\u00f6lbel\n# Info: http://www.privacyidea.org\n#\n# This code is free software; you can redistribute it and/or\n# modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE\n# License as published by the Free Software Foundation; either\n# version 3 of the License, or any later version.\n#\n# This code is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU AFFERO GENERAL PUBLIC LICENSE for more details.\n#\n# You should have received a copy of the GNU Affero General Public\n# License along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#\nimport os\nimport os.path\nimport logging\nimport logging.config\nimport sys\nimport yaml\nfrom flask import Flask, request, Response\nfrom flask_babel import Babel\nfrom flask_migrate import Migrate\nfrom flaskext.versioned import Versioned\n\n# we need this import to add the before/after request function to the blueprints\nimport privacyidea.api.before_after\nfrom privacyidea.api.validate import validate_blueprint\nfrom privacyidea.api.token import token_blueprint\nfrom privacyidea.api.system import system_blueprint\nfrom privacyidea.api.resolver import resolver_blueprint\nfrom privacyidea.api.realm import realm_blueprint\nfrom privacyidea.api.realm import defaultrealm_blueprint\nfrom privacyidea.api.policy import policy_blueprint\nfrom privacyidea.api.user import user_blueprint\nfrom privacyidea.api.audit import audit_blueprint\nfrom privacyidea.api.application import application_blueprint\nfrom privacyidea.api.caconnector import caconnector_blueprint\nfrom privacyidea.api.register import register_blueprint\nfrom privacyidea.api.auth import jwtauth\nfrom privacyidea.webui.login import login_blueprint, get_accepted_language\nfrom privacyidea.webui.certificate import cert_blueprint\nfrom privacyidea.api.machineresolver import machineresolver_blueprint\nfrom privacyidea.api.machine import machine_blueprint\nfrom privacyidea.api.ttype import ttype_blueprint\nfrom privacyidea.api.smtpserver import smtpserver_blueprint\nfrom privacyidea.api.radiusserver import radiusserver_blueprint\nfrom privacyidea.api.periodictask import periodictask_blueprint\nfrom privacyidea.api.privacyideaserver import privacyideaserver_blueprint\nfrom privacyidea.api.recover import recover_blueprint\nfrom privacyidea.api.event import eventhandling_blueprint\nfrom privacyidea.api.smsgateway import smsgateway_blueprint\nfrom privacyidea.api.clienttype import client_blueprint\nfrom privacyidea.api.subscriptions import subscriptions_blueprint\nfrom privacyidea.api.monitoring import monitoring_blueprint\nfrom privacyidea.api.tokengroup import tokengroup_blueprint\nfrom privacyidea.lib import queue\nfrom privacyidea.lib.log import DEFAULT_LOGGING_CONFIG\nfrom privacyidea.config import config\nfrom privacyidea.models import db\nfrom privacyidea.lib.crypto import init_hsm\n\n\nENV_KEY = \"PRIVACYIDEA_CONFIGFILE\"\n\n\nclass PiResponseClass(Response):\n    \"\"\"Custom Response class overwriting the flask.Response.\n    To avoid caching problems with the json property in the Response class,\n    the property is overwritten using a non-caching approach.\n    \"\"\"\n    @property\n    def json(self):\n        \"\"\"This will contain the parsed JSON data if the mimetype indicates\n        JSON (:mimetype:`application/json`, see :meth:`is_json`), otherwise it\n        will be ``None``.\n        Caching of the json data is disabled.\n        \"\"\"\n        return self.get_json(cache=False)\n\n    default_mimetype = 'application/json'\n\n\ndef create_app(config_name=\"development\",\n               config_file='/etc/privacyidea/pi.cfg',\n               silent=False, init_hsm=False):\n    \"\"\"\n    First the configuration from the config.py is loaded depending on the\n    config type like \"production\" or \"development\" or \"testing\".\n\n    Then the environment variable PRIVACYIDEA_CONFIGFILE is checked for a\n    config file, that contains additional settings, that will overwrite the\n    default settings from config.py\n\n    :param config_name: The config name like \"production\" or \"testing\"\n    :type config_name: basestring\n    :param config_file: The name of a config file to read configuration from\n    :type config_file: basestring\n    :param silent: If set to True the additional information are not printed\n        to stdout\n    :type silent: bool\n    :param init_hsm: Whether the HSM should be initialized on app startup\n    :type init_hsm: bool\n    :return: The flask application\n    :rtype: App object\n    \"\"\"\n    if not silent:\n        print(\"The configuration name is: {0!s}\".format(config_name))\n    if os.environ.get(ENV_KEY):\n        config_file = os.environ[ENV_KEY]\n    if not silent:\n        print(\"Additional configuration will be read \"\n              \"from the file {0!s}\".format(config_file))\n    app = Flask(__name__, static_folder=\"static\",\n                template_folder=\"static/templates\")\n    if config_name:\n        app.config.from_object(config[config_name])\n\n    # Set up flask-versioned\n    versioned = Versioned(app, format='%(path)s?v=%(version)s')\n\n    try:\n        # Try to load the given config_file.\n        # If it does not exist, just ignore it.\n        app.config.from_pyfile(config_file, silent=True)\n    except IOError:\n        sys.stderr.write(\"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\\n\")\n        sys.stderr.write(\"  WARNING: privacyidea create_app has no access\\n\")\n        sys.stderr.write(\"  to {0!s}!\\n\".format(config_file))\n        sys.stderr.write(\"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\\n\")\n\n    # Try to load the file, that was specified in the environment variable\n    # PRIVACYIDEA_CONFIG_FILE\n    # If this file does not exist, we create an error!\n    app.config.from_envvar(ENV_KEY, silent=True)\n\n    # We allow to set different static folders\n    app.static_folder = app.config.get(\"PI_STATIC_FOLDER\", \"static/\")\n    app.template_folder = app.config.get(\"PI_TEMPLATE_FOLDER\", \"static/templates/\")\n\n    app.register_blueprint(validate_blueprint, url_prefix='/validate')\n    app.register_blueprint(token_blueprint, url_prefix='/token')\n    app.register_blueprint(system_blueprint, url_prefix='/system')\n    app.register_blueprint(resolver_blueprint, url_prefix='/resolver')\n    app.register_blueprint(realm_blueprint, url_prefix='/realm')\n    app.register_blueprint(defaultrealm_blueprint, url_prefix='/defaultrealm')\n    app.register_blueprint(policy_blueprint, url_prefix='/policy')\n    app.register_blueprint(login_blueprint, url_prefix='/')\n    app.register_blueprint(jwtauth, url_prefix='/auth')\n    app.register_blueprint(user_blueprint, url_prefix='/user')\n    app.register_blueprint(audit_blueprint, url_prefix='/audit')\n    app.register_blueprint(machineresolver_blueprint,\n                           url_prefix='/machineresolver')\n    app.register_blueprint(machine_blueprint, url_prefix='/machine')\n    app.register_blueprint(application_blueprint, url_prefix='/application')\n    app.register_blueprint(caconnector_blueprint, url_prefix='/caconnector')\n    app.register_blueprint(cert_blueprint, url_prefix='/certificate')\n    app.register_blueprint(ttype_blueprint, url_prefix='/ttype')\n    app.register_blueprint(register_blueprint, url_prefix='/register')\n    app.register_blueprint(smtpserver_blueprint, url_prefix='/smtpserver')\n    app.register_blueprint(recover_blueprint, url_prefix='/recover')\n    app.register_blueprint(radiusserver_blueprint, url_prefix='/radiusserver')\n    app.register_blueprint(periodictask_blueprint, url_prefix='/periodictask')\n    app.register_blueprint(privacyideaserver_blueprint,\n                           url_prefix='/privacyideaserver')\n    app.register_blueprint(eventhandling_blueprint, url_prefix='/event')\n    app.register_blueprint(smsgateway_blueprint, url_prefix='/smsgateway')\n    app.register_blueprint(client_blueprint, url_prefix='/client')\n    app.register_blueprint(subscriptions_blueprint, url_prefix='/subscriptions')\n    app.register_blueprint(monitoring_blueprint, url_prefix='/monitoring')\n    app.register_blueprint(tokengroup_blueprint, url_prefix='/tokengroup')\n    db.init_app(app)\n    migrate = Migrate(app, db)\n\n    app.response_class = PiResponseClass\n\n    # Setup logging\n    log_read_func = {\n        'yaml': lambda x: logging.config.dictConfig(yaml.safe_load(open(x, 'r').read())),\n        'cfg': lambda x: logging.config.fileConfig(x)\n    }\n    have_config = False\n    log_exx = None\n    log_config_file = app.config.get(\"PI_LOGCONFIG\", \"/etc/privacyidea/logging.cfg\")\n    if os.path.isfile(log_config_file):\n        for cnf_type in ['cfg', 'yaml']:\n            try:\n                log_read_func[cnf_type](log_config_file)\n                if not silent:\n                    print('Read Logging settings from {0!s}'.format(log_config_file))\n                have_config = True\n                break\n            except Exception as exx:\n                log_exx = exx\n                pass\n    if not have_config:\n        if log_exx:\n            sys.stderr.write(\"Could not use PI_LOGCONFIG: \" + str(log_exx) + \"\\n\")\n        if not silent:\n            sys.stderr.write(\"Using PI_LOGLEVEL and PI_LOGFILE.\\n\")\n        level = app.config.get(\"PI_LOGLEVEL\", logging.INFO)\n        # If there is another logfile in pi.cfg we use this.\n        logfile = app.config.get(\"PI_LOGFILE\", '/var/log/privacyidea/privacyidea.log')\n        if not silent:\n            sys.stderr.write(\"Using PI_LOGLEVEL {0!s}.\\n\".format(level))\n            sys.stderr.write(\"Using PI_LOGFILE {0!s}.\\n\".format(logfile))\n        DEFAULT_LOGGING_CONFIG[\"handlers\"][\"file\"][\"filename\"] = logfile\n        DEFAULT_LOGGING_CONFIG[\"handlers\"][\"file\"][\"level\"] = level\n        DEFAULT_LOGGING_CONFIG[\"loggers\"][\"privacyidea\"][\"level\"] = level\n        logging.config.dictConfig(DEFAULT_LOGGING_CONFIG)\n\n    babel = Babel(app)\n\n    @babel.localeselector\n    def get_locale():\n        return get_accepted_language(request)\n\n    queue.register_app(app)\n\n    if init_hsm:\n        with app.app_context():\n            init_hsm()\n\n    logging.debug(u\"Reading application from the static folder {0!s} and \"\n                  u\"the template folder {1!s}\".format(app.static_folder, app.template_folder))\n\n    return app\n", "path": "privacyidea/app.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n#\n# 2014-11-15 Cornelius K\u00f6lbel, info@privacyidea.org\n#            Initial creation\n#\n# (c) Cornelius K\u00f6lbel\n# Info: http://www.privacyidea.org\n#\n# This code is free software; you can redistribute it and/or\n# modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE\n# License as published by the Free Software Foundation; either\n# version 3 of the License, or any later version.\n#\n# This code is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU AFFERO GENERAL PUBLIC LICENSE for more details.\n#\n# You should have received a copy of the GNU Affero General Public\n# License along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#\nimport os\nimport os.path\nimport logging\nimport logging.config\nimport sys\nimport yaml\nfrom flask import Flask, request, Response\nfrom flask_babel import Babel\nfrom flask_migrate import Migrate\nfrom flaskext.versioned import Versioned\n\n# we need this import to add the before/after request function to the blueprints\nimport privacyidea.api.before_after\nfrom privacyidea.api.validate import validate_blueprint\nfrom privacyidea.api.token import token_blueprint\nfrom privacyidea.api.system import system_blueprint\nfrom privacyidea.api.resolver import resolver_blueprint\nfrom privacyidea.api.realm import realm_blueprint\nfrom privacyidea.api.realm import defaultrealm_blueprint\nfrom privacyidea.api.policy import policy_blueprint\nfrom privacyidea.api.user import user_blueprint\nfrom privacyidea.api.audit import audit_blueprint\nfrom privacyidea.api.application import application_blueprint\nfrom privacyidea.api.caconnector import caconnector_blueprint\nfrom privacyidea.api.register import register_blueprint\nfrom privacyidea.api.auth import jwtauth\nfrom privacyidea.webui.login import login_blueprint, get_accepted_language\nfrom privacyidea.webui.certificate import cert_blueprint\nfrom privacyidea.api.machineresolver import machineresolver_blueprint\nfrom privacyidea.api.machine import machine_blueprint\nfrom privacyidea.api.ttype import ttype_blueprint\nfrom privacyidea.api.smtpserver import smtpserver_blueprint\nfrom privacyidea.api.radiusserver import radiusserver_blueprint\nfrom privacyidea.api.periodictask import periodictask_blueprint\nfrom privacyidea.api.privacyideaserver import privacyideaserver_blueprint\nfrom privacyidea.api.recover import recover_blueprint\nfrom privacyidea.api.event import eventhandling_blueprint\nfrom privacyidea.api.smsgateway import smsgateway_blueprint\nfrom privacyidea.api.clienttype import client_blueprint\nfrom privacyidea.api.subscriptions import subscriptions_blueprint\nfrom privacyidea.api.monitoring import monitoring_blueprint\nfrom privacyidea.api.tokengroup import tokengroup_blueprint\nfrom privacyidea.lib import queue\nfrom privacyidea.lib.log import DEFAULT_LOGGING_CONFIG\nfrom privacyidea.config import config\nfrom privacyidea.models import db\nfrom privacyidea.lib.crypto import init_hsm\n\n\nENV_KEY = \"PRIVACYIDEA_CONFIGFILE\"\n\n\nclass PiResponseClass(Response):\n    \"\"\"Custom Response class overwriting the flask.Response.\n    To avoid caching problems with the json property in the Response class,\n    the property is overwritten using a non-caching approach.\n    \"\"\"\n    @property\n    def json(self):\n        \"\"\"This will contain the parsed JSON data if the mimetype indicates\n        JSON (:mimetype:`application/json`, see :meth:`is_json`), otherwise it\n        will be ``None``.\n        Caching of the json data is disabled.\n        \"\"\"\n        return self.get_json(cache=False)\n\n    default_mimetype = 'application/json'\n\n\ndef create_app(config_name=\"development\",\n               config_file='/etc/privacyidea/pi.cfg',\n               silent=False, init_hsm=False):\n    \"\"\"\n    First the configuration from the config.py is loaded depending on the\n    config type like \"production\" or \"development\" or \"testing\".\n\n    Then the environment variable PRIVACYIDEA_CONFIGFILE is checked for a\n    config file, that contains additional settings, that will overwrite the\n    default settings from config.py\n\n    :param config_name: The config name like \"production\" or \"testing\"\n    :type config_name: basestring\n    :param config_file: The name of a config file to read configuration from\n    :type config_file: basestring\n    :param silent: If set to True the additional information are not printed\n        to stdout\n    :type silent: bool\n    :param init_hsm: Whether the HSM should be initialized on app startup\n    :type init_hsm: bool\n    :return: The flask application\n    :rtype: App object\n    \"\"\"\n    if not silent:\n        print(\"The configuration name is: {0!s}\".format(config_name))\n    if os.environ.get(ENV_KEY):\n        config_file = os.environ[ENV_KEY]\n    if not silent:\n        print(\"Additional configuration will be read \"\n              \"from the file {0!s}\".format(config_file))\n    app = Flask(__name__, static_folder=\"static\",\n                template_folder=\"static/templates\")\n    if config_name:\n        app.config.from_object(config[config_name])\n\n    # Set up flask-versioned\n    versioned = Versioned(app, format='%(path)s?v=%(version)s')\n\n    try:\n        # Try to load the given config_file.\n        # If it does not exist, just ignore it.\n        app.config.from_pyfile(config_file, silent=True)\n    except IOError:\n        sys.stderr.write(\"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\\n\")\n        sys.stderr.write(\"  WARNING: privacyidea create_app has no access\\n\")\n        sys.stderr.write(\"  to {0!s}!\\n\".format(config_file))\n        sys.stderr.write(\"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\\n\")\n\n    # Try to load the file, that was specified in the environment variable\n    # PRIVACYIDEA_CONFIG_FILE\n    # If this file does not exist, we create an error!\n    app.config.from_envvar(ENV_KEY, silent=True)\n\n    # We allow to set different static folders\n    app.static_folder = app.config.get(\"PI_STATIC_FOLDER\", \"static/\")\n    app.template_folder = app.config.get(\"PI_TEMPLATE_FOLDER\", \"static/templates/\")\n\n    app.register_blueprint(validate_blueprint, url_prefix='/validate')\n    app.register_blueprint(token_blueprint, url_prefix='/token')\n    app.register_blueprint(system_blueprint, url_prefix='/system')\n    app.register_blueprint(resolver_blueprint, url_prefix='/resolver')\n    app.register_blueprint(realm_blueprint, url_prefix='/realm')\n    app.register_blueprint(defaultrealm_blueprint, url_prefix='/defaultrealm')\n    app.register_blueprint(policy_blueprint, url_prefix='/policy')\n    app.register_blueprint(login_blueprint, url_prefix='/')\n    app.register_blueprint(jwtauth, url_prefix='/auth')\n    app.register_blueprint(user_blueprint, url_prefix='/user')\n    app.register_blueprint(audit_blueprint, url_prefix='/audit')\n    app.register_blueprint(machineresolver_blueprint,\n                           url_prefix='/machineresolver')\n    app.register_blueprint(machine_blueprint, url_prefix='/machine')\n    app.register_blueprint(application_blueprint, url_prefix='/application')\n    app.register_blueprint(caconnector_blueprint, url_prefix='/caconnector')\n    app.register_blueprint(cert_blueprint, url_prefix='/certificate')\n    app.register_blueprint(ttype_blueprint, url_prefix='/ttype')\n    app.register_blueprint(register_blueprint, url_prefix='/register')\n    app.register_blueprint(smtpserver_blueprint, url_prefix='/smtpserver')\n    app.register_blueprint(recover_blueprint, url_prefix='/recover')\n    app.register_blueprint(radiusserver_blueprint, url_prefix='/radiusserver')\n    app.register_blueprint(periodictask_blueprint, url_prefix='/periodictask')\n    app.register_blueprint(privacyideaserver_blueprint,\n                           url_prefix='/privacyideaserver')\n    app.register_blueprint(eventhandling_blueprint, url_prefix='/event')\n    app.register_blueprint(smsgateway_blueprint, url_prefix='/smsgateway')\n    app.register_blueprint(client_blueprint, url_prefix='/client')\n    app.register_blueprint(subscriptions_blueprint, url_prefix='/subscriptions')\n    app.register_blueprint(monitoring_blueprint, url_prefix='/monitoring')\n    app.register_blueprint(tokengroup_blueprint, url_prefix='/tokengroup')\n    db.init_app(app)\n    migrate = Migrate(app, db)\n\n    app.response_class = PiResponseClass\n\n    # Setup logging\n    log_read_func = {\n        'yaml': lambda x: logging.config.dictConfig(yaml.safe_load(open(x, 'r').read())),\n        'cfg': lambda x: logging.config.fileConfig(x)\n    }\n    have_config = False\n    log_exx = None\n    log_config_file = app.config.get(\"PI_LOGCONFIG\", \"/etc/privacyidea/logging.cfg\")\n    if os.path.isfile(log_config_file):\n        for cnf_type in ['cfg', 'yaml']:\n            try:\n                log_read_func[cnf_type](log_config_file)\n                if not silent:\n                    print('Read Logging settings from {0!s}'.format(log_config_file))\n                have_config = True\n                break\n            except Exception as exx:\n                log_exx = exx\n                pass\n    if not have_config:\n        if log_exx:\n            sys.stderr.write(\"Could not use PI_LOGCONFIG: \" + str(log_exx) + \"\\n\")\n        if not silent:\n            sys.stderr.write(\"Using PI_LOGLEVEL and PI_LOGFILE.\\n\")\n        level = app.config.get(\"PI_LOGLEVEL\", logging.INFO)\n        # If there is another logfile in pi.cfg we use this.\n        logfile = app.config.get(\"PI_LOGFILE\", '/var/log/privacyidea/privacyidea.log')\n        if not silent:\n            sys.stderr.write(\"Using PI_LOGLEVEL {0!s}.\\n\".format(level))\n            sys.stderr.write(\"Using PI_LOGFILE {0!s}.\\n\".format(logfile))\n        DEFAULT_LOGGING_CONFIG[\"handlers\"][\"file\"][\"filename\"] = logfile\n        DEFAULT_LOGGING_CONFIG[\"handlers\"][\"file\"][\"level\"] = level\n        DEFAULT_LOGGING_CONFIG[\"loggers\"][\"privacyidea\"][\"level\"] = level\n        logging.config.dictConfig(DEFAULT_LOGGING_CONFIG)\n\n    babel = Babel(app)\n\n    @babel.localeselector\n    def get_locale():\n        return get_accepted_language(request)\n\n    queue.register_app(app)\n\n    if init_hsm:\n        with app.app_context():\n            init_hsm()\n\n    logging.getLogger(__name__).debug(u\"Reading application from the static \"\n                                      u\"folder {0!s} and the template folder \"\n                                      u\"{1!s}\".format(app.static_folder, app.template_folder))\n\n    return app\n", "path": "privacyidea/app.py"}]}