def _request(api_url, api_name, method, endpoint, **kwargs):
    ckanapi_key = current_app.config['CKAN_API_KEY']
    access_token = ckanapi_key or get_access_token()
    verify_tls = get_env() != 'development'
    timeout = None if get_env() == 'development' else 10
    headers = {
        'Accept': 'application/json',
        'Authorization': 'Bearer ' + access_token,
    }
    if method in ('POST', 'PUT'):
        headers['Content-Type'] = 'application/json'
    headers.update(kwargs.pop('headers', {}))
    try:
        r = requests.request(
            method,
            api_url + endpoint,
            **kwargs,
            headers=headers,
            verify=verify_tls,
            timeout=timeout,
        )
        r.raise_for_status()
        return r.json()

    except requests.HTTPError as e:
        try:
            detail = e.response.json()
        except ValueError:
            detail = e.response.reason
        flash(f"{e.response.status_code} error from {api_name}: {detail}",
              category='error')

    except requests.RequestException as e:
        flash(f"Error sending request to {api_name}: {e}", category='error')
Beispiel #2
0
def create_app(env: Union[str, None] = None) -> Flask:
    env = env or get_env()
    app = Flask(__name__, static_folder=STATIC_PATH)  # type: Flask
    app.config.from_object(config.config_dict[env])
    Moment(app)
    babel = Babel(app)
    models.init_app(app)
    cli.init_app(app)
    views.init_app(app)
    if get_env() == "development":
        admin.init_app(app)
    templating.init_app(app)
    api.init_app(app)
    Environment(app)

    @babel.localeselector
    def get_locale():
        if 'site' in g:
            return g.site['locale']
        return request.accept_languages.best_match(['zh', 'en'])

    login_manager = LoginManager(app)
    login_manager.login_view = 'admin.login'
    login_manager.login_message = lazy_gettext('Please login')
    login_manager.login_message_category = 'warning'

    @login_manager.user_loader
    def get_user(uid):
        return models.User.query.get(uid)

    @app.shell_context_processor
    def shell_context():
        return {'db': models.db, 'Post': models.Post, 'markdown': markdown}

    return app
Beispiel #3
0
def create_app(config=None):
    conf_map = {
        'dev': 'development',
        'prod': 'production',
        'test': 'testing'
    }
    config_obj = conf_map.get(config) or get_env()

    app = Flask(__name__, instance_relative_config=True)
    app.config.from_object(f'<%= app_name %>.config.{config_obj}')
    app.url_map.strict_slashes = False

    register_extensions(app)
    register_shellcontext(app)
    register_blueprints(app)
    register_errorhandlers(app)
    register_commands(app)

    if config_obj != 'testing':
        register_logging(app)

    if config_obj == 'production':
        app.config.from_pyfile('prod.secret.cfg', silent=True)
    else:
        from <%= app_name %>.swagger import register_apispec
        register_apispec(app)

    return app
Beispiel #4
0
def create_app(config=None):
    """
    Flask application factory.

    :param config: config dict or filename
    :return: Flask app instance
    """
    from . import models, views
    from .config import Config

    app = Flask(__name__)
    app.config.from_object(Config)

    if config is not None:
        if isinstance(config, dict):
            app.config.from_mapping(config)
        else:
            app.config.from_pyfile(config, silent=True)

    models.init_app(app)
    views.init_app(app)

    login_manager.init_app(app)
    mail.init_app(app)

    hydra_admin.server_url = app.config['HYDRA_ADMIN_URL']
    hydra_admin.remember_login_for = app.config['HYDRA_LOGIN_EXPIRY']
    hydra_admin.verify_tls = get_env() != 'development'

    # trust the X-Forwarded-* headers set by the proxy server
    app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_prefix=1)

    return app
Beispiel #5
0
class Settings(object):
    """Base configuration."""

    # Load dotenv in the base root
    dotenv_path = os.path.join(os.path.dirname(__file__), '..', '.env')
    load_dotenv(dotenv_path)

    # Set config
    ENV = get_env()
    IS_PRODUCTION = ENV == 'production'
    DEBUG = get_debug_flag()
    APP_DIR = os.path.abspath(os.path.dirname(__file__))
    DB_SERVER = os.getenv('DB_HOST')
    DB_NAME = os.getenv('DB_NAME')
    DB_USER = os.getenv('DB_USER')
    DB_PASSWORD = os.getenv('DB_PASSWORD')
    DB_DRIVER = os.getenv('DB_DRIVER')
    DB_TRUSTED_CONNECTION = os.getenv('DB_TRUSTED_CONNECTION')
    SECRET_KEY = 'QUAD-ADMIN-CONSOLE-SECRET'
    JWT_SECRET_KEY = 'QUAD-ADMIN-CONSOLE-JWT'
    JWT_TOKEN_LOCATION = ['headers']
    JWT_HEADER_NAME = 'Authorization'
    JWT_HEADER_TYPE = 'Bearer'
    JWT_ACCESS_TOKEN_EXPIRES = False
    JWT_REFRESH_TOKEN_EXPIRES = False
    CORS_ORIGIN_WHITELIST = [
        'http://localhost:3000', 'http://localhost:3001',
        'http://localhost:5000', 'http://127.0.0.1:3000',
        'http://127.0.0.1:3001', 'http://127.0.0.1:5000'
    ]
Beispiel #6
0
def init_app(app: Flask) -> None:
    from . import views

    app.register_blueprint(api, url_prefix='/api')
    if get_env() == 'development':
        CORS(app,
             resources={r"/api/*": {
                 "origins": "http://localhost:9527"
             }},
             supports_credentials=True)
Beispiel #7
0
def add_data_to_db():
    app = create_app(get_env())
    app_context = app.app_context()
    app_context.push()
    db.drop_all()
    db.create_all()

    data = get_data()
    keys = list(data.keys())
    services_objects_map = upload_services(prepare_keys(keys))
    upload_events(data, services_objects_map)
    db.session.commit()
Beispiel #8
0
def create_app(env=None):
    app = Flask(__name__, instance_relative_config=True)

    # 配置
    config_obj = conf_map.get(env) or get_env()
    app.config.from_object(config_obj)

    # 配置exts
    init_exts(app)

    # bp
    register_bps(app, blueprints)

    return app
    def __init__(self, name, import_name, db_session, user_model, token_model,
                 final_redirect_view):
        """
        :param db_session: SQLAlchemy session object
        :param user_model: User model class;
            this should be a flask_login.UserMixin or similar
        :param token_model: Token model class;
            this should be a hydra_oauth2.HydraTokenMixin or similar
        :param final_redirect_view: the endpoint to which to redirect the user
            after login/logout has been completed
        """
        super().__init__(
            name,
            import_name,
            login_url='/login',
            authorized_url='/authorized',
            redirect_to=final_redirect_view,
            storage=SQLAlchemyStorage(token_model,
                                      db_session,
                                      user=current_user),

            # hack to disable SSL certificate verification in a dev environment:
            # this is a sneaky way to make flask-dance set the 'verify' kwarg for
            # requests calls made when fetching tokens; it's not the intended use
            # of token_url_params, but hey-ho
            token_url_params={'verify': get_env() != 'development'},
        )

        self.db_session = db_session
        self.user_model = user_model
        self.token_model = token_model

        self.hydra_public_url = None
        self.userinfo_url = None
        self.logout_url = None

        self.from_config['hydra_public_url'] = 'HYDRA_PUBLIC_URL'
        self.from_config['client_id'] = 'OAUTH2_CLIENT_ID'
        self.from_config['client_secret'] = 'OAUTH2_CLIENT_SECRET'
        self.from_config['scope'] = 'OAUTH2_SCOPES'
        self.from_config['audience'] = 'OAUTH2_AUDIENCE'

        self.add_url_rule('/signup', view_func=self.signup)
        self.add_url_rule('/logout', view_func=self.logout)
        self.add_url_rule('/logged_out', view_func=self.logged_out)

        oauth_authorized.connect(self.hydra_logged_in, sender=self)
        oauth_error.connect(self.hydra_error, sender=self)

        self.create_or_update_local_user = None
Beispiel #10
0
def run(info):
    debug = True

    # Check that the user has added a proper Flask App
    info.load_app()

    show_server_banner(get_env(), debug, info.app_import_path, None)
    app = DispatchingApp(info.load_app, use_eager_loading=None)
    run_simple('127.0.0.1',
               5000,
               app,
               use_reloader=debug,
               use_debugger=debug,
               threaded=True)
Beispiel #11
0
def run(info, host, port, reload, debugger, eager_loading, with_threads, cert,
        extra_files):
    """Run a local development server.
    This server is for development purposes only. It does not provide
    the stability, security, or performance of production WSGI servers.
    The reloader and debugger are enabled by default if
    FLASK_ENV=development or FLASK_DEBUG=1.
    """
    debug = get_debug_flag()

    if reload is None:
        reload = debug

    if debugger is None:
        debugger = debug
    if debugger:
        os.environ['AIOFLASK_USE_DEBUGGER'] = 'true'

    certfile = None
    keyfile = None
    if cert is not None and len(cert) == 2:
        certfile = cert[0]
        keyfile = cert[1]

    show_server_banner(get_env(), debug, info.app_import_path, eager_loading)

    app_import_path = info.app_import_path
    if app_import_path is None:
        for path in ('wsgi', 'app'):
            if os.path.exists(path) or os.path.exists(path + '.py'):
                app_import_path = path + ':app'
                if sys.path[0] != '.':
                    sys.path.insert(0, '.')
                break
    if app_import_path.endswith('.py'):
        app_import_path = app_import_path[:-3] + ':app'

    uvicorn.run(
        app_import_path,
        host=host,
        port=port,
        reload=reload,
        workers=1,
        log_level='debug' if debug else 'info',
        ssl_certfile=certfile,
        ssl_keyfile=keyfile,
    )
Beispiel #12
0
    def make_config(self, instance_relative=False):
        """
        Overriding the default `make_config` function in order to support
        Flask OIDC package and all of their settings.
        """
        root_path = self.root_path
        if instance_relative:
            root_path = self.instance_path
        defaults = dict(self.default_config)
        defaults['ENV'] = get_env()
        defaults['DEBUG'] = get_debug_flag()

        # Append all the configurations from the base config class.
        for key, value in BaseConfig.__dict__.items():
            if not key.startswith('__'):
                defaults[key] = value
        return self.config_class(root_path, defaults)
Beispiel #13
0
def create_app():
    app = Flask(__name__, instance_relative_config=True)
    app.config.from_object('app.configs.{}'.format(get_env()))
    # cors = CORS(app, resources=r"/*", origins=r"*", )

    with app.app_context():
        register_extensions(app)
        register_blueprints(app)
        # register_cmds(app)
    register_error_handler(app)

    @app.before_request
    def log_request_info():
        logger = logging.getLogger('werkzeug')
        if request.method in ['POST', 'PUT']:
            logger.info('Body: %s', request.get_data())

    return app
Beispiel #14
0
def create_app(env: Optional[str] = None) -> Flask:
    # load_dotenv('.env')
    env = env or get_env()
    app = Flask(__name__, static_folder=STATIC_PATH)
    app.config.from_object(config.config_dict[env])
    app.jinja_env.auto_reload = True
    app.config['TEMPLATES_AUTO_RELOAD'] = True
    Moment(app)
    babel = Babel(app)
    models.init_app(app)
    cli.init_app(app)
    views.init_app(app)
    if env == "development":
        admin.init_app(app)
    templating.init_app(app)
    api.init_app(app)
    Environment(app)

    @babel.localeselector
    def get_locale():
        lang = request.accept_languages.best_match(['zh', 'en'])
        if not lang and 'site' in g:
            lang = g.site['locale']
        if lang == 'zh':
            lang = 'zh_Hans_CN'
        return lang

    login_manager = LoginManager(app)
    login_manager.login_view = "admin.login"
    login_manager.login_message = lazy_gettext('Please login')
    login_manager.login_message_category = 'warning'

    @login_manager.user_loader
    def get_user(uid):
        return models.User.query.get(uid)

    @app.shell_context_processor
    def shell_context():
        return {'db': models.db, 'Blog': models.Blog, 'markdown': markdown}

    return app
Beispiel #15
0
def create_app(config_class=None):
    """Entry point to the Flask RESTful Server application."""
    kwargs = {
        'static_folder': None,  # Don't register static view
    }

    # Init Flask app
    app = Flask('BEMServer API', **kwargs)

    # A config class can be passed "manually" (typically for tests)
    # The general use case is "config_class is None". In this case, we get
    #  the fully qualified path to the class object.
    # 'from_object' can take either a class object or a path
    if config_class is None:
        config_class = '.'.join((DEFAULT_CONFIG_FILE, CONFIGS[get_env()]))
    app.config.from_object(config_class)

    # Override config with optional settings file
    app.config.from_envvar('FLASK_SETTINGS_FILE', silent=True)

    extensions.init_app(app)
    app.logger.debug('Extensions initialized.')

    with app.app_context():  # this allows to get access to config parameters
        views.init_app(app)
        app.logger.debug('Views initialized.')

    if app.config.get('MAINTENANCE_MODE'):
        app.logger.info('BEMServer in maintenance mode.')
    else:
        app.logger.info('BEMServer started. Ready to rock.')

    # Initialize Flask-Migrate
    Migrate(app, db)

    return app
Beispiel #16
0
def create_app(config_name=None, config_extra=None):
    """
    Generate a new instance of the Flask app

    This generates and configures the main application instance. Testing
    environments can use `config_extra` to provide extra configuration values
    such as a temporary database URL.

    @param config_name The name of the configuration to load from settings.py
    @param config_extra An optional dict of configuration override values
    """
    app = LinOTPApp()

    # We need to do this here because the Flask CLI machinery doesn't seem
    # to pass the correct value.

    if config_name is None:
        config_name = get_env()

    _configure_app(app, config_name, config_extra)

    babel = Babel(app, configure_jinja=False, default_domain="linotp")

    # Determine which languages are available in the i18n directory.
    # Note that we always have English even without a translation file.

    app.available_languages = list(
        {'en'} | {t.language for t in babel.list_translations()}
    )

    setup_mako(app)
    init_logging(app)

    with app.app_context():
        setup_cache(app)
        setup_db(app)

        init_linotp_config(app)
        set_config()       # ensure `request_context` exists

        init_security_provider()

        app.setup_audit()

        reload_token_classes()
        app.check_license()

    @app.before_request
    def setup_env():
        # The following functions are called here because they're
        # stuffing bits into `flask.g`, which is a per-request global
        # object. Much of what is stuffed into `flask.g` is actually
        # application-wide stuff that has no business being stored in
        # `flask.g` in the first place, but lots of code expects to be
        # able to look at the "request context" and find stuff
        # there. Disentangling the application-wide stuff in the
        # request context from the request-scoped stuff is a major
        # project that will not be undertaken just now, and we're
        # probably doing more work here than we need to. Global
        # variables suck.

        set_config()

        if request.path.startswith(app.static_url_path):
            return

        allocate_security_module()

    app.add_url_rule('/healthcheck/status', 'healthcheck', healthcheck)

    # Add pre request handlers
    app.before_first_request(init_logging_config)
    app.before_request(app._run_setup)
    app.before_request(app.start_session)

    # Per controller setup and handlers
    app.setup_controllers()

    @app.route('/')
    def index():
        site_root_redirect = config["SITE_ROOT_REDIRECT"]
        if site_root_redirect:
            return redirect(site_root_redirect)

        if 'selfservice' in app.enabled_controllers:
            return redirect(url_for('selfservice.index'))

        return abort(404)

    # Post handlers
    app.teardown_request(app.finalise_request)

    @app.errorhandler(LinotpError)
    def linotp_error_handler(e):
        """
        Pass LinotpError exceptions to sendError

        If Flask receives an exception which is derived from LinotpError,
        this handler will be called so that an error response can be
        returned to the user.
        """
        return sendError(None, e)

    @babel.localeselector
    def get_locale():
        """Figure out the locale for this request. We look at the
        request's `Accept-Language` header and pick the first language
        in the list that matches one of the languages that we actually
        support.
        """
        return request.accept_languages.best_match(app.available_languages,
                                                   "en")

    # Enable profiling if desired. The options are debatable and could be
    # made more configurable. OTOH, we could all have a pony.
    profiling = False
    if app.config['PROFILE']:
        try:                    # Werkzeug >= 1.0.0
            from werkzeug.middleware.profiler import ProfilerMiddleware
            profiling = True
        except ImportError:
            try:                # Werkzeug < 1.0.0
                from werkzeug.contrib.profiler import ProfilerMiddleware
                profiling = True
            except ImportError:
                log.error("PROFILE is enabled but ProfilerMiddleware could "
                          "not be imported. No profiling for you!")
        if profiling:
            app.wsgi_app = ProfilerMiddleware(
                app.wsgi_app, profile_dir='profile',
                restrictions=[30], sort_by=['cumulative'])
            log.info("PROFILE is enabled (do not use this in production!)")

    return app
Beispiel #17
0
from flask.helpers import get_env
from flask_migrate import MigrateCommand
from flask_script import Manager

from app import create_app, register_manage_commands

env = get_env()
app = create_app(env)
manager = Manager(app)
manager.add_command('db', MigrateCommand)
register_manage_commands(manager)

if __name__ == '__main__':
    manager.run()
Beispiel #18
0
 def test_get_env(self, monkeypatch, env, ref_env, debug):
     monkeypatch.setenv("FLASK_ENV", env)
     assert get_debug_flag() == debug
     assert get_env() == ref_env
Beispiel #19
0
# DEFINES THE FLASK APLICATION SETTINGS AND INCLUDES SOME TASKS THAT HELP MANAGE THE APPLICATION
from flask.helpers import get_env
from flask_migrate import Migrate

from app import create_app, db
from app.models import Event, WebSource

app = create_app(get_env())

migrate = Migrate(app, db)


@app.shell_context_processor
def make_shell_context():
    return dict(db=db, Event=Event, WebSource=WebSource)


### IN SHELL ###
# $ pip install -r requirements.txt
# $ export FLASK_ENV=development
# $ export FLASK_APP=events_app.py
# $ export FLASK_DEBUG=1
# $ flask run

### DB ###
# $ flask db init
# $ flask db migrate -m 'initial migration'
# $ flask db upgrade (once a migration script has been accepted, it can be applied to the database using this command)
# $ db.create_all()

### FLASK SHELL ###
Beispiel #20
0
    def run(self,
            host=None,
            port=None,
            debug=None,
            load_dotenv=True,
            **options):

        if get_load_dotenv(load_dotenv):
            cli.load_dotenv()

            # if set, let env vars override previous values
            if "FLASK_ENV" in os.environ:
                self.env = get_env()
                self.debug = get_debug_flag()
            elif "FLASK_DEBUG" in os.environ:
                self.debug = get_debug_flag()

        # debug passed to method overrides all other sources
        if debug is not None:
            self.debug = bool(debug)

        server_name = self.config.get("SERVER_NAME")
        sn_host = sn_port = None

        if server_name:
            sn_host, _, sn_port = server_name.partition(":")

        if not host:
            if sn_host:
                host = sn_host
            else:
                host = "127.0.0.1"

        if port or port == 0:
            port = int(port)
        elif sn_port:
            port = int(sn_port)
        else:
            port = 5000

        options.setdefault("use_reloader", self.debug)
        options.setdefault("use_debugger", self.debug)
        options.setdefault("threaded", True)

        certfile = None
        keyfile = None
        cert = options.get('ssl_context')
        if cert is not None and len(cert) == 2:
            certfile = cert[0]
            keyfile = cert[1]
        elif cert == 'adhoc':
            raise RuntimeError(
                'Aad-hoc certificates are not supported by aioflask.')

        if debug:
            os.environ['FLASK_DEBUG'] = 'true'

        if options['use_debugger']:
            os.environ['AIOFLASK_USE_DEBUGGER'] = 'true'

        show_server_banner(self.env, self.debug, self.name, False)

        uvicorn.run(
            self.import_name + ':app',
            host=host,
            port=port,
            reload=options['use_reloader'],
            workers=1,
            log_level='debug' if self.debug else 'info',
            ssl_certfile=certfile,
            ssl_keyfile=keyfile,
        )
Beispiel #21
0
def create_app(config_name=None, config_extra=None):
    """
    Generate a new instance of the Flask app

    This generates and configures the main application instance. Testing
    environments can use `config_extra` to provide extra configuration values
    such as a temporary database URL.

    @param config_name The name of the configuration to load from settings.py
    @param config_extra An optional dict of configuration override values
    """
    app = LinOTPApp()

    # We need to do this here because the Flask CLI machinery doesn't seem
    # to pass the correct value.

    if config_name is None:
        config_name = get_env()

    _configure_app(app, config_name, config_extra)

    babel = Babel(app, configure_jinja=False, default_domain="linotp")

    # Determine which languages are available in the i18n directory.
    # Note that we always have English even without a translation file.

    app.available_languages = list(
        {"en"} | {t.language for t in babel.list_translations()}
    )

    setup_mako(app)
    init_logging(app)

    with app.app_context():
        setup_cache(app)
        setup_db(app)

        init_linotp_config(app)
        set_config()  # ensure `request_context` exists

        init_security_provider()

        app.setup_audit()

        reload_token_classes()
        app.check_license()

    app.add_url_rule("/healthcheck/status", "healthcheck", healthcheck)

    # Add pre request handlers
    app.before_first_request(init_logging_config)
    app.before_first_request(app.init_jwt_config)
    app.before_request(app.setup_env)
    app.before_request(app._run_setup)
    app.before_request(app.start_session)

    # Per controller setup and handlers
    app.setup_controllers()

    @app.route("/")
    def index():
        site_root_redirect = config["SITE_ROOT_REDIRECT"]
        if site_root_redirect:
            return redirect(site_root_redirect)

        if "selfservice" in app.enabled_controllers:
            return redirect(url_for("selfservice.index"))

        return abort(404)

    # Post handlers
    app.teardown_request(app.finalise_request)

    @app.errorhandler(LinotpError)
    def linotp_error_handler(e):
        """
        Pass LinotpError exceptions to sendError

        If Flask receives an exception which is derived from LinotpError,
        this handler will be called so that an error response can be
        returned to the user.
        """
        return sendError(None, e)

    @babel.localeselector
    def get_locale():
        """Figure out the locale for this request. We look at the
        request's `Accept-Language` header and pick the first language
        in the list that matches one of the languages that we actually
        support.
        """
        try:
            return request.accept_languages.best_match(
                app.available_languages, "en"
            )
        except RuntimeError as exx:
            # Working outside of request context.
            return babel.default_locale

    # Enable profiling if desired. The options are debatable and could be
    # made more configurable. OTOH, we could all have a pony.
    profiling = False
    if app.config["PROFILE"]:
        try:  # Werkzeug >= 1.0.0
            from werkzeug.middleware.profiler import ProfilerMiddleware

            profiling = True
        except ImportError:
            try:  # Werkzeug < 1.0.0
                from werkzeug.contrib.profiler import ProfilerMiddleware

                profiling = True
            except ImportError:
                log.error(
                    "PROFILE is enabled but ProfilerMiddleware could "
                    "not be imported. No profiling for you!"
                )
        if profiling:
            app.wsgi_app = ProfilerMiddleware(
                app.wsgi_app,
                profile_dir="profile",
                restrictions=[30],
                sort_by=["cumulative"],
            )
            log.info("PROFILE is enabled (do not use this in production!)")

    return app
Beispiel #22
0
from flask import Flask
from flask.helpers import get_env

from . import api, view

app = Flask(__name__,
            static_folder='../static',
            template_folder='../static/templates')

app.register_blueprint(api.bp)
app.register_blueprint(view.bp)

app.config.from_object('config.{}'.format(get_env().capitalize()))
Beispiel #23
0
 def test_get_env(self, monkeypatch, env, ref_env, debug):
     monkeypatch.setenv("FLASK_ENV", env)
     assert get_debug_flag() == debug
     assert get_env() == ref_env
Beispiel #24
0
class Log:
    if get_env() == 'development':
        log_dir = os.path.expanduser('~/Library/Logs/')
    else:
        log_dir = '/var/log'

    path_log = '%s/%s.log' % (log_dir, Const.app_name)
    path_err = '%s/%s.err.log' % (log_dir, Const.app_name)

    io_log = StringIO()
    io_err = StringIO()
    replaces = {}
    lock_log = Lock()

    stdout: StringIO = None
    stderr: StringIO = None

    debug = False

    @staticmethod
    def init_app(keep_log=False, debug=False):
        Log.debug = debug

        mode = 'a' if keep_log else 'w+'
        Log.io_log = open(Log.path_log, mode)
        Log.io_err = open(Log.path_err, mode)

        # redirect stdout and stderr.
        Log.stdout, Log.stderr = sys.stdout, sys.stderr
        sys.stdout, sys.stderr = Log.io_log, Log.io_err

        if Log.debug:
            Log.debug_redirect()

    @staticmethod
    def debug_redirect():
        log_w = Log.io_log.write
        err_w = Log.io_log.write

        def bind_log_w(*args, **kwargs):
            log_w(*args, **kwargs)
            Log.stdout.write(*args, **kwargs)

        def bind_err_w(*args, **kwargs):
            err_w(*args, **kwargs)
            Log.stderr.write(*args, **kwargs)

        Log.io_log.write = bind_log_w
        Log.io_err.write = bind_err_w

    @staticmethod
    def set_replaces(replaces: dict):
        Log.replaces = replaces

    @staticmethod
    def extract_log():
        with Log.lock_log:
            log = io_helper.read_all(Log.io_log, '')
        return log

    @staticmethod
    def extract_err():
        err = io_helper.read_all(Log.io_err, '')
        return err

    @staticmethod
    def append(src, tag='Info', *args):
        log_items = []
        for i in args:
            if isinstance(i, list) or isinstance(i, dict):
                log_items.append(object_convert.to_json(i))
            elif isinstance(i, tuple) or isinstance(i, set):
                log_items.append(object_convert.to_json(list(i)))
            elif isinstance(i, int) or isinstance(i, float) or isinstance(
                    i, str) or isinstance(i, bool) or i is None:
                log_items.append(i)
            else:
                log_items.append(i)
                log_items.append(
                    object_convert.to_json(object_convert.object_to_dict(i)))

        if isinstance(src, str):
            source = src
        else:
            source = src.__name__

        items_str = []
        for item in log_items:
            item_str = str(item)
            if len(Log.replaces) > 0:
                for k, v in Log.replaces.items():
                    if k is not None and k != '':
                        item_str = item_str.replace(k, v)

            items_str.append(item_str)

        items_str = ' '.join(items_str)
        if items_str.strip() != '':
            items_str = '\t%s\n' % items_str

        with Log.lock_log:
            content = '[%s] %s %s\n%s' % (tag, time.ctime(), source, items_str)
            Log.io_log.write(content)
            Log.io_log.flush()