Пример #1
0
def mongo_pool():
    """
    通过配置参数建立链接并生成连接池
    :return:
    """
    config = get_config()
    pool = pymongo.MongoClient(**config.MONGODB_CONN)[config.MONGODB_DB]
    return pool
def identifier_decrypt(data):
    data = aes_decrypt(getattr(get_config(), 'RESOURCE_AES_KEY'), data)
    # 通过正则校验确定数据的正确性
    group = re.match(r'^(student|teacher|klass|room);([\s\S]+)$', data)
    if group is None:
        raise ValueError('解密后的数据无法被合理解读,解密后数据:%s' % data)
    else:
        return group.group(1), group.group(2)
Пример #3
0
def mysql_connect():
    """
    建立单个MySQL数据库的连接
    :return: MySQL连接句柄
    """
    config = get_config()
    conn = pymysql.connect(**config.MYSQL_CONFIG)
    conn.autocommit(1)  # 定义数据库不自动提交
    return conn
Пример #4
0
def mysql_pool():
    """
    通过配置参数建立链接并生成连接池
    :return: MySQl连接池
    """
    config = get_config()
    pool = PooledDB(creator=pymysql,
                    **config.MYSQL_CONFIG,
                    **config.MYSQL_POOL_CONFIG)  # 建立MySQL连接池
    return pool
def identifier_encrypt(cate, code):
    return aes_encrypt(getattr(get_config(), 'RESOURCE_AES_KEY'), "%s;%s" % (cate, code))
Пример #6
0
def create_app(offline=False) -> Flask:
    """创建 flask app
    @param offline: 如果设置为 `True`,则为离线模式。此模式下不会连接到 Sentry 和 ElasticAPM
    """
    from everyclass.api_server.db.dao import new_user_id_sequence
    from everyclass.api_server.db.mysql import get_connection, init_pool
    from everyclass.api_server.utils.log import LogstashHandler, LogstashFormatter, LOG_FORMAT_STRING

    app = Flask(__name__)

    # load app config
    from everyclass.api_server.config import get_config
    _config = get_config()
    app.config.from_object(_config)
    """
    每课统一日志机制


    规则如下:
    - WARNING 以下 log 输出到 stdout
    - WARNING 以上输出到 stderr
    - DEBUG 以上日志以 json 形式通过 TCP 输出到 Logstash,然后发送到日志中心
    - WARNING 以上级别的输出到 Sentry


    日志等级:
    critical – for errors that lead to termination
    error – for errors that occur, but are handled
    warning – for exceptional circumstances that might not be errors
    notice – for non-error messages you usually want to see
    info – for messages you usually don’t want to see
    debug – for debug messages
    
    
    Sentry:
    https://docs.sentry.io/clients/python/api/#raven.Client.captureMessage
    - stack 默认是 False
    
    """
    stdout_handler = logbook.StreamHandler(stream=sys.stdout,
                                           bubble=True,
                                           filter=lambda r, h: r.level < 13)
    stdout_handler.format_string = LOG_FORMAT_STRING
    logger.handlers.append(stdout_handler)

    stderr_handler = logbook.StreamHandler(stream=sys.stderr,
                                           bubble=True,
                                           level='WARNING')
    stderr_handler.format_string = LOG_FORMAT_STRING
    logger.handlers.append(stderr_handler)

    if not offline and (app.config['CONFIG_NAME']
                        in ["production", "staging", "testing"]):
        # Sentry
        sentry.init_app(app=app)
        sentry_handler = SentryHandler(
            sentry.client, level='WARNING')  # Sentry 只处理 WARNING 以上的
        logger.handlers.append(sentry_handler)

        # Elastic APM
        ElasticAPM(app)

        # Log to Logstash
        logstash_handler = LogstashHandler(
            host=app.config['LOGSTASH']['HOST'],
            port=app.config['LOGSTASH']['PORT'],
            release=app.config['GIT_DESCRIBE'],
            bubble=True,
            logger=logger,
            filter=lambda r, h: r.level >= 11)  # do not send DEBUG
        logger.handlers.append(logstash_handler)

    # 初始化数据库
    if not offline and (app.config['CONFIG_NAME']
                        in ("production", "staging", "testing",
                            "development")):
        init_pool(app)

    # 导入并注册 blueprints
    from everyclass.api_server.views import main_blueprint as main_blueprint
    from everyclass.api_server.api import api_v1 as api_blueprint
    app.register_blueprint(main_blueprint)
    app.register_blueprint(api_blueprint, url_prefix='/api/v1')

    @app.errorhandler(500)
    def internal_server_error():
        return jsonify({
            'success': False,
            'message': 'Server could not response to the request.'
        })

    logger.info('App created with `{0}` config'.format(
        app.config['CONFIG_NAME']),
                stack=False)

    # 输出配置内容
    logger.info('Below are configurations we are using:')
    logger.info(
        '================================================================')
    for key, value in app.config.items():
        if key not in ('SECRET_KEY', ):
            value = copy.copy(value)

            # 敏感内容抹去
            if key == 'SENTRY_CONFIG':
                value['dsn'] = '[secret]'
            if key == 'MYSQL_CONFIG':
                value['password'] = '******'
            if key == 'ELASTIC_APM':
                value['SECRET_TOKEN'] = '[secret]'

            logger.info('{}: {}'.format(key, value))
    logger.info(
        '================================================================')

    return app
def create_app(outside_container=False) -> Flask:
    """创建 flask app
    @param outside_container: 是否不在容器内运行
    """
    import os
    from flask import jsonify

    from everyclass.api_server.util.logbook_logstash.formatter import LOG_FORMAT_STRING
    from everyclass.api_server.util import mysql_pool, mongo_pool
    from everyclass.api_server.api import blueprint as api_v1_blueprint

    app = Flask(__name__)

    # load app config
    from everyclass.api_server.config import get_config
    _config = get_config()
    app.config.from_object(_config)

    app.register_blueprint(api_v1_blueprint, url_prefix='/v1')
    """
    每课统一日志机制


    规则如下:
    - WARNING 以下 log 输出到 stdout
    - WARNING 以上输出到 stderr
    - DEBUG 以上日志以 json 形式通过 TCP 输出到 Logstash,然后发送到日志中心
    - WARNING 以上级别的输出到 Sentry


    日志等级:
    critical – for errors that lead to termination
    error – for errors that occur, but are handled
    warning – for exceptional circumstances that might not be errors
    notice – for non-error messages you usually want to see
    info – for messages you usually don’t want to see
    debug – for debug messages


    Sentry:
    https://docs.sentry.io/clients/python/api/#raven.Client.captureMessage
    - stack 默认是 False
    """
    stdout_handler = logbook.StreamHandler(stream=sys.stdout,
                                           bubble=True,
                                           filter=lambda r, h: r.level < 13)
    stdout_handler.format_string = LOG_FORMAT_STRING
    logger.handlers.append(stdout_handler)

    stderr_handler = logbook.StreamHandler(stream=sys.stderr,
                                           bubble=True,
                                           level='WARNING')
    stderr_handler.format_string = LOG_FORMAT_STRING
    logger.handlers.append(stderr_handler)

    # 容器外运行(无 uWSGI)时初始化数据库
    if outside_container and (os.environ.get("MODE") == 'DEVELOPMENT'):
        app.mysql_pool = mysql_pool()
        app.mongo_pool = mongo_pool()

    @app.route('/')
    def hello_world():
        return 'Hello World!'

    # 查询的资源不存在
    @app.errorhandler(404)
    def not_found_error(error):
        return jsonify({'message': str(error)}), 404

    # 访问参数异常处理
    @app.errorhandler(400)
    def bad_request_error(error):
        return jsonify({'message': str(error)}), 400

    # 访问参数异常处理
    @app.errorhandler(500)
    def server_internal_error(error):
        return jsonify({'message': str(error)}), 500

    global __app
    __app = app

    return app