소스 검색

initial development

liqian 1 년 전
부모
커밋
68a0d853db
8개의 변경된 파일762개의 추가작업 그리고 0개의 파일을 삭제
  1. 2 0
      .gitignore
  2. 54 0
      ad_predict.py
  3. 53 0
      app.py
  4. 75 0
      config.py
  5. 437 0
      db_helper.py
  6. 16 0
      gunicorn.config.py
  7. 40 0
      log.py
  8. 85 0
      log_conf.py

+ 2 - 0
.gitignore

@@ -58,3 +58,5 @@ docs/_build/
 # PyBuilder
 target/
 
+.idea/
+

+ 54 - 0
ad_predict.py

@@ -0,0 +1,54 @@
+import json
+import random
+import gevent
+from db_helper import RedisHelper
+from config import set_config
+from gevent import monkey, pool
+monkey.patch_all()
+
+config_ = set_config()
+redis_helper = RedisHelper()
+
+
+def thompson_process(ad_idea_id):
+    # 获取ad_idea_id对应的Thompson参数
+    thompson_param = redis_helper.get_data_from_redis(key_name=f"{config_.THOMPSON_PARAM_KEY_PREFIX}{ad_idea_id}")
+    if thompson_param is None or thompson_param == '':
+        # 参数不存在,随机生成[0, 1)之间的浮点数
+        score = random.random()
+        random_flag = 'random'
+    else:
+        # 参数存在
+        param_alpha, param_beta = json.loads(thompson_param.strip())
+        param_alpha, param_beta = int(param_alpha), int(param_beta)
+        if param_alpha + param_beta >= 100:
+            # ad_idea_id 曝光数 >= 100,生成参数为(param_alpha+1, param_beta+1)的beta分布随机数
+            score = random.betavariate(alpha=param_alpha+1, beta=param_beta+1)
+            random_flag = 'beta'
+        else:
+            # ad_idea_id 曝光数 < 100,随机生成[0, 1)之间的浮点数
+            score = random.random()
+            random_flag = 'random'
+    thompson_res = [ad_idea_id, score, thompson_param, random_flag]
+    return thompson_res
+
+
+def get_ad_idea_id_with_thompson(mid, ad_idea_id_list):
+    """利用Thompson采样获取此次要展示的广告创意ID"""
+    # 限制协程最大并发数:20
+    gevent_pool = pool.Pool(20)
+    tasks = [gevent_pool.spawn(thompson_process, ad_idea_id) for ad_idea_id in ad_idea_id_list]
+    gevent.joinall(tasks)
+    thompson_res_list = [t.get() for t in tasks]
+    # 按照score排序
+    thompson_res_rank = sorted(thompson_res_list, key=lambda x: x[1], reverse=True)
+    rank_res = {
+        'mid': mid,
+        'ad_idea_id': thompson_res_rank[0][0],
+        'score': thompson_res_rank[0][1],
+        'thompson_param': thompson_res_rank[0][2],
+        'random_flag': thompson_res_rank[0][3],
+        'thompson_res_rank': thompson_res_rank
+    }
+    return rank_res
+

+ 53 - 0
app.py

@@ -0,0 +1,53 @@
+import random
+import os
+import logging
+import json
+import time
+import traceback
+import ast
+from gevent import monkey
+monkey.patch_all()
+
+from flask import Flask, request
+from log import Log
+from config import set_config
+from ad_predict import get_ad_idea_id_with_thompson
+
+app = Flask(__name__)
+log_ = Log()
+config_ = set_config()
+
+
+@app.route('/healthcheck')
+def health_check():
+    return 'ok!'
+
+
+@app.route('/ad/predict/getAdIdeaId', methods=['GET', 'POST'])
+def get_ad_idea_id():
+    start_time = time.time()
+    try:
+        request_data = json.loads(request.get_data())
+        mid = request_data.get('mid')
+        ad_idea_id_list = request_data.get('adIdeaIdList')
+        thompson_result = get_ad_idea_id_with_thompson(mid=mid, ad_idea_id_list=ad_idea_id_list)
+        result = {'code': 200, 'message': 'success', 'data': {'mid': mid, 'adIdeaId': thompson_result['ad_idea_id']}}
+        log_message = {
+            'requestUri': '/ad/predict/getAdIdeaId',
+            'logTimestamp': int(time.time() * 1000),
+            'requestData': request_data,
+            'thompsonResult': thompson_result,
+            'result': result,
+            'executeTime': (time.time() - start_time) * 1000
+        }
+        log_.info(log_message)
+        return json.dumps(result)
+
+    except Exception as e:
+        log_.error(traceback.format_exc())
+        result = {'code': -1, 'message': 'fail'}
+        return json.dumps(result)
+
+
+if __name__ == '__main__':
+    app.run()

+ 75 - 0
config.py

@@ -0,0 +1,75 @@
+import os
+
+
+class BaseConfig(object):
+    # adIdeaId对应Thompson参数结果存放 redis key 前缀,完整格式:thompson:param:{ad_idea_id}
+    THOMPSON_PARAM_KEY_PREFIX = 'thompson:param:'
+
+
+class TestConfig(BaseConfig):
+    """测试环境配置"""
+    # 日志服务配置
+    ALIYUN_LOG = {
+        'ENDPOINT': 'cn-hangzhou-intranet.log.aliyuncs.com',
+        'ACCESSID': 'LTAIWYUujJAm7CbH',
+        'ACCESSKEY': 'RfSjdiWwED1sGFlsjXv0DlfTnZTG1P',
+        'PROJECT': 'ad-server-test',
+    }
+    # 测试环境redis地址
+    REDIS_INFO = {
+        'host': 'r-bp1ps6my7lzg8rdhwx682.redis.rds.aliyuncs.com',
+        'port': 6379,
+        'password': 'Wqsd@2019',
+    }
+
+
+class PreProductionConfig(BaseConfig):
+    """测试环境配置"""
+    # 日志服务配置
+    ALIYUN_LOG = {
+        'ENDPOINT': 'cn-hangzhou-intranet.log.aliyuncs.com',
+        'ACCESSID': 'LTAIWYUujJAm7CbH',
+        'ACCESSKEY': 'RfSjdiWwED1sGFlsjXv0DlfTnZTG1P',
+        'PROJECT': 'ad-server',
+    }
+    # 测试环境redis地址
+    REDIS_INFO = {
+        'host': 'r-bp1ps6my7lzg8rdhwx682.redis.rds.aliyuncs.com',
+        'port': 6379,
+        'password': 'Wqsd@2019',
+    }
+
+
+class ProductionConfig(BaseConfig):
+    """测试环境配置"""
+    # 日志服务配置
+    ALIYUN_LOG = {
+        'ENDPOINT': 'cn-hangzhou-intranet.log.aliyuncs.com',
+        'ACCESSID': 'LTAIWYUujJAm7CbH',
+        'ACCESSKEY': 'RfSjdiWwED1sGFlsjXv0DlfTnZTG1P',
+        'PROJECT': 'ad-server',
+    }
+    # 测试环境redis地址
+    REDIS_INFO = {
+        'host': 'r-bp1yup71yo02ki3yb5.redis.rds.aliyuncs.com',
+        'port': 6379,
+        'password': 'Wqsd@2019',
+    }
+
+
+def set_config():
+    # 获取环境变量 ROV_SERVER_ENV
+    env = os.environ.get('ROV_SERVER_ENV')
+    # env = 'test'
+    if env is None:
+        # log_.error('ENV ERROR: is None!')
+        return
+    if env == 'test':
+        return TestConfig()
+    elif env == 'pre':
+        return PreProductionConfig()
+    elif env == 'pro':
+        return ProductionConfig()
+    else:
+        # log_.error('ENV ERROR: is {}'.format(env))
+        return

+ 437 - 0
db_helper.py

@@ -0,0 +1,437 @@
+import traceback
+import time
+import redis
+from config import set_config
+from log import Log
+
+config_ = set_config()
+log_ = Log()
+
+conn_redis = None
+
+
+class RedisHelper(object):
+    def __init__(self, params=None, redis_info=config_.REDIS_INFO):
+        """
+        初始化redis连接信息
+        redis_info: redis连接信息, 格式:dict, {'host': '', 'port': '', 'password': ''}
+        """
+        self.redis_info = redis_info
+        self.host = redis_info['host']
+        self.port = redis_info['port']
+        self.password = redis_info['password']
+        self.params = params
+
+    def connect(self):
+        """
+        连接redis
+        :return: conn
+        """
+        global conn_redis
+        if conn_redis is None:
+            pool = redis.ConnectionPool(host=self.host,
+                                        port=self.port,
+                                        password=self.password,
+                                        decode_responses=True)
+            conn = redis.Redis(connection_pool=pool)
+            conn_redis = conn
+        return conn_redis
+
+    def key_exists(self, key_name):
+        """
+        判断key是否存在
+        :param key_name: key
+        :return: 存在-True, 不存在-False
+        """
+        # start_time = time.time()
+        conn = self.connect()
+        res = conn.exists(key_name)
+        # if self.params is not None:
+        #     log_.info({
+        #         'logTimestamp': int(time.time() * 1000),
+        #         'request_id': self.params.request_id,
+        #         'operation': 'get_data_from_redis',
+        #         'executeTime': (time.time() - start_time) * 1000
+        #     })
+        return res
+
+    def del_keys(self, key_name):
+        """
+        删除key
+        :param key_name: key
+        :return: None
+        """
+        conn = self.connect()
+        conn.delete(key_name)
+
+    def get_data_from_redis(self, key_name):
+        """
+        读取redis中的数据
+        :param key_name: key
+        :return: data
+        """
+        # start_time = time.time()
+        conn = self.connect()
+        if not conn.exists(key_name):
+            # key不存在
+            return None
+        data = conn.get(key_name)
+        # if self.params is not None:
+        #     log_.info({
+        #         'logTimestamp': int(time.time() * 1000),
+        #         'request_id': self.params.request_id,
+        #         'operation': 'get_data_from_redis',
+        #         'executeTime': (time.time() - start_time) * 1000
+        #     })
+        return data
+
+    def set_data_to_redis(self, key_name, value, expire_time=24*3600):
+        """
+        新增数据
+        :param key_name: key
+        :param value: 元素的值 videoId
+        :param expire_time: 过期时间,单位:s,默认1天
+        :return: None
+        """
+        # start_time = time.time()
+        conn = self.connect()
+        conn.set(key_name, value, ex=int(expire_time))
+        # if self.params is not None:
+        #     log_.info({
+        #         'logTimestamp': int(time.time() * 1000),
+        #         'request_id': self.params.request_id,
+        #         'operation': 'set_data_to_redis',
+        #         'executeTime': (time.time() - start_time) * 1000})
+
+    def add_data_with_zset(self, key_name, data, expire_time=7*24*3600):
+        """
+        新增数据,有序set
+        :param key_name: key
+        :param data: 元素的值及对应分数 type-dict  {value: score}
+        :param expire_time: 过期时间,单位:s,默认7天,type-int
+        :return: None
+        """
+        # start_time = time.time()
+        conn = self.connect()
+        conn.zadd(key_name, data)
+        # 设置过期时间
+        conn.expire(key_name, int(expire_time))
+        # if self.params is not None:
+        #     log_.info({
+        #         'logTimestamp': int(time.time() * 1000),
+        #         'request_id': self.params.request_id,
+        #         'operation': 'add_data_with_zset',
+        #         'executeTime': (time.time() - start_time) * 1000
+        #     })
+
+    def get_data_zset_with_index(self, key_name, start, end, desc=True, with_scores=False):
+        """
+        根据索引位置获取元素的值
+        :param key_name: key
+        :param start: 索引起始点 闭区间,包含start
+        :param end: 索引结束点 闭区间,包含end
+        :param desc: 分数排序方式,默认从大到小
+        :param with_scores: 是否获取元素的分数,默认 False,只获取元素的值
+        :return: data 元素值列表(不包含分数),value(videoId)类型转换为int, 包含分数时不进行类型转换
+        """
+        # start_time = time.time()
+        conn = self.connect()
+        if not conn.exists(key_name):
+            return None
+        data = conn.zrange(key_name, start, end, desc, with_scores)
+        if with_scores:
+            data = data
+        else:
+            data = [eval(value) for value in data]
+
+        # if self.params is not None:
+        #     log_.info({
+        #         'logTimestamp': int(time.time() * 1000),
+        #         'request_id': self.params.request_id,
+        #         'operation': 'get_data_zset_with_index',
+        #         'executeTime': (time.time() - start_time) * 1000
+        #     })
+        return data
+
+    def get_all_data_from_zset(self, key_name, desc=True, with_scores=False):
+        """
+        获取zset中所有元素的值
+        :param key_name: key
+        :param desc: 分数排序方式,默认从大到小
+        :param with_scores: 是否获取元素的分数,默认 False,只获取元素的值
+        :return: data 元素值列表(不包含分数),value(videoId)类型转换为int, 包含分数时不进行类型转换
+        """
+        conn = self.connect()
+        if not conn.exists(key_name):
+            return None
+        data = []
+        start = 0
+        step = 100
+        while True:
+            end = start + step - 1
+            temp = conn.zrange(key_name, start, end, desc, with_scores)
+            if not temp:
+                break
+            data.extend(temp)
+            start += step
+        return data
+
+    def get_score_with_value(self, key_name, value):
+        """
+        在zset中,根据元素的value获取对应的score
+        :param key_name: key
+        :param value: 元素的值
+        :return: score value对应的score
+        """
+        conn = self.connect()
+        if not conn.exists(key_name):
+            return None
+        return conn.zscore(key_name, value)
+
+    def get_rank_with_value(self, key_name, value, desc=False):
+        """
+        在zset中,根据元素的value获取对应排名
+        :param key_name: key
+        :param value: 元素的值
+        :param desc: 是否倒序 type-bool 默认:False-按照score从小到大
+        :return: rank value对应的rank,从0开始,不存在返回None
+        """
+        conn = self.connect()
+        if not conn.exists(key_name):
+            return None
+        if desc is True:
+            return conn.zrevrank(key_name, value)
+        else:
+            return conn.zrank(key_name, value)
+
+    def update_score_with_value(self, key_name, value, score, expire_time=24*3600):
+        """
+        在zset中,修改元素value对应的score
+        :param key_name: key
+        :param value: 元素的值
+        :param score: value对应的score更新值
+        :param expire_time: 过期时间,单位:s,默认1天,type-int
+        """
+        conn = self.connect()
+        if conn.exists(key_name):
+            conn.zadd(key_name, {value: score})
+        else:
+            # key不存在时,需设置过期时间
+            conn.zadd(key_name, {value: score})
+            conn.expire(key_name, int(expire_time))
+
+    def remove_value_from_zset(self, key_name, value):
+        """
+        删除zset中的指定元素
+        :param key_name: key
+        :param value: 元素的值
+        :return: None
+        """
+        # start_time = time.time()
+        conn = self.connect()
+        res = conn.zrem(key_name, value)
+        # if self.params is not None:
+        #     log_.info({
+        #         'logTimestamp': int(time.time() * 1000),
+        #         'request_id': self.params.request_id,
+        #         'operation': 'remove_value_from_zset',
+        #         'executeTime': (time.time() - start_time) * 1000
+        #     })
+        return res
+
+    def get_index_with_data(self, key_name, value):
+        """
+        根据元素的值获取在有序set中的位置,按照分数倒序(从大到小)
+        :param key_name: key
+        :param value: 元素的值
+        :return: idx 位置索引
+        """
+        # start_time = time.time()
+        conn = self.connect()
+        res = conn.zrevrank(key_name, value)
+        # if self.params is not None:
+        #     log_.info({
+        #         'logTimestamp': int(time.time() * 1000),
+        #         'request_id': self.params.request_id,
+        #         'operation': 'get_index_with_data',
+        #         'executeTime': (time.time() - start_time) * 1000
+        #     })
+        return res
+
+    def get_data_from_set(self, key_name):
+        """
+        获取set中的所有数据
+        :param key_name: key
+        :return: data
+        """
+        # start_time = time.time()
+        conn = self.connect()
+        if not conn.exists(key_name):
+            # key不存在
+            return None
+        data = []
+        cursor = 0
+        while True:
+            cur, temp = conn.sscan(key_name, cursor=cursor, count=2000)
+            data.extend(temp)
+            if cur == 0:
+                break
+            cursor = cur
+
+        # if self.params is not None:
+        #     log_.info({
+        #         'logTimestamp': int(time.time() * 1000),
+        #         'request_id': self.params.request_id,
+        #         'operation': 'get_data_from_set',
+        #         'executeTime': (time.time() - start_time) * 1000
+        #     })
+        return list(set(data))
+
+    def add_data_with_set(self, key_name, values, expire_time=30*60):
+        """
+        新增数据,set
+        :param key_name: key
+        :param values: 要添加的元素  类型-tuple
+        :param expire_time: 过期时间,单位:s,默认0.5小时 type-int
+        :return: None
+        """
+        # start_time = time.time()
+        conn = self.connect()
+        conn.sadd(key_name, *values)
+        # 设置过期时间
+        conn.expire(key_name, int(expire_time))
+        # if self.params is not None:
+        #     log_.info({
+        #         'logTimestamp': int(time.time() * 1000),
+        #         'request_id': self.params.request_id,
+        #         'operation': 'add_data_with_set',
+        #         'executeTime': (time.time() - start_time) * 1000
+        #     })
+
+    def data_exists_with_set(self, key_name, value):
+        """
+        判断元素value是否在集合key_name中
+        :param key_name: key
+        :param value: 需判断的元素
+        :return: 存在-True, 不存在-False
+        """
+        # start_time = time.time()
+        conn = self.connect()
+        res = conn.sismember(key_name, value)
+        # if self.params is not None:
+        #     log_.info({
+        #         'logTimestamp': int(time.time() * 1000),
+        #         'request_id': self.params.request_id,
+        #         'operation': 'data_exists_with_set',
+        #         'executeTime': (time.time() - start_time) * 1000
+        #     })
+        return res
+
+    def get_data_with_count_from_set(self, key_name, count=1):
+        """
+        从set中随机获取元素,并放回
+        :param key_name: key
+        :param count: 获取个数, 默认为1
+        :return:
+        """
+        conn = self.connect()
+        data = conn.srandmember(name=key_name, number=count)
+        return data
+
+    def remove_value_from_set(self, key_name, values):
+        """
+        删除set中的指定元素
+        :param key_name: key
+        :param values: 元素的值, 类型-tuple
+        :return: None
+        """
+        # start_time = time.time()
+        conn = self.connect()
+        res = conn.srem(key_name, *values)
+        # if self.params is not None:
+        #     log_.info({
+        #         'logTimestamp': int(time.time() * 1000),
+        #         'request_id': self.params.request_id,
+        #         'operation': 'remove_value_from_set',
+        #         'executeTime': (time.time() - start_time) * 1000
+        #     })
+        return res
+
+    def decr_key(self, key_name, amount=1, expire_time=30*60):
+        """
+        redis自减
+        :param key_name: key
+        :param amount: 自减数,默认为1,type-int
+        :param expire_time: 过期时间,单位:s,默认0.5小时 type-int
+        :return: None
+        """
+        # start_time = time.time()
+        conn = self.connect()
+        conn.decr(name=key_name, amount=amount)
+        conn.expire(key_name, int(expire_time))
+        # if self.params is not None:
+        #     log_.info({
+        #         'logTimestamp': int(time.time() * 1000),
+        #         'request_id': self.params.request_id,
+        #         'operation': 'decr_key',
+        #         'executeTime': (time.time() - start_time) * 1000
+        #     })
+
+    def incr_key(self, key_name, amount=1, expire_time=30*60):
+        """
+        redis自增
+        :param key_name: key
+        :param amount: 自增数,默认为1,type-int
+        :param expire_time: 过期时间,单位:s,默认0.5小时 type-int
+        :return: None
+        """
+        # start_time = time.time()
+        conn = self.connect()
+        conn.incr(name=key_name, amount=amount)
+        conn.expire(key_name, int(expire_time))
+        # if self.params is not None:
+        #     log_.info({
+        #         'logTimestamp': int(time.time() * 1000),
+        #         'request_id': self.params.request_id,
+        #         'operation': 'incr_key',
+        #         'executeTime': (time.time() - start_time) * 1000
+        #     })
+
+    def setnx_key(self, key_name, value, expire_time=5*60):
+        """
+        当key不存在时,将value塞入key中,key存在时不做操作
+        :param key_name: key
+        :param value: value
+        :return: 过期时间,单位:s,默认5分钟 type-int
+        """
+        # start_time = time.time()
+        conn = self.connect()
+        conn.setnx(name=key_name, value=value)
+        conn.expire(name=key_name, time=int(expire_time))
+
+    def get_batch_key(self, name_list):
+        conn = self.connect()
+        res = conn.mget(name_list)
+        return res
+
+    def mget(self, keys):
+        conn = self.connect()
+        data = conn.mget(keys=keys)
+        return data
+
+
+
+if __name__ == '__main__':
+    redis_helper = RedisHelper()
+    key_name = f"previewed:videos:5:aan7"
+    res = redis_helper.get_data_with_count_from_set(
+        key_name=key_name,
+        count=20)
+    print(res)
+    res1 = redis_helper.remove_value_from_set(key_name=key_name, values=tuple({'2881413'}))
+    print(res1)
+    res = redis_helper.get_data_with_count_from_set(
+        key_name=key_name,
+        count=20)
+    print(res)
+

+ 16 - 0
gunicorn.config.py

@@ -0,0 +1,16 @@
+import os
+from multiprocessing import cpu_count
+# 日志配置
+# 本地日志存储路径
+log_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "logs")
+if not os.path.exists(log_path):
+    os.makedirs(log_path)
+loglevel = "info"
+accesslog = os.path.join(log_path, 'access.log')
+errorlog = os.path.join(log_path, 'error.log')
+
+# workers = 5
+workers = 2 * cpu_count() + 1
+# 设置工作模式为协程
+worker_class = "gevent"
+bind = "0.0.0.0:5001"

+ 40 - 0
log.py

@@ -0,0 +1,40 @@
+import logging
+import logging.config
+
+from log_conf import conf
+
+
+class Log(object):
+    def __init__(self):
+        # 配置
+        logging.config.dictConfig(conf)
+
+    def __console(self, level, message):
+        if level == 'info':
+            logger = logging.getLogger('sls')
+            logger.info(message)
+        elif level == 'debug':
+            logger = logging.getLogger('root')
+            logger.debug(message)
+        elif level == 'warning':
+            logger = logging.getLogger('root')
+            logger.warning(message)
+        elif level == 'error':
+            logger = logging.getLogger('error')
+            logger.error(message)
+
+    def debug(self, message):
+        self.__console('debug', message)
+        # return
+
+    def info(self, message):
+        self.__console('info', message)
+        # return
+
+    def warning(self, message):
+        self.__console('warning', message)
+        # return
+
+    def error(self, message):
+        self.__console('error', message)
+        # return

+ 85 - 0
log_conf.py

@@ -0,0 +1,85 @@
+# log conf
+import logging
+import aliyun
+import os
+import time
+from config import set_config
+config_ = set_config()
+
+# 本地日志存储路径
+log_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "logs")
+if not os.path.exists(log_path):
+    os.makedirs(log_path)
+# 文件的命名
+log_name = os.path.join(log_path, '{}.log'.format(time.strftime('%Y%m%d')))
+
+conf = {
+    'version': 1,
+    'formatters': {
+        'rawFormatter': {
+            'class': 'logging.Formatter',
+            'format': '%(message)s'
+        },
+        'simpleFormatter': {
+            'class': 'logging.Formatter',
+            'format': '%(asctime)s %(levelname)s: %(message)s'
+        }
+    },
+    'handlers': {
+        'consoleHandler': {
+            '()': 'logging.StreamHandler',
+            'level': 'DEBUG',
+            'formatter': 'simpleFormatter',
+        },
+        'slsHandler': {
+            '()': 'aliyun.log.QueuedLogHandler',
+            'level': 'INFO',
+            'formatter': 'rawFormatter',
+            # custom args:
+            'end_point': config_.ALIYUN_LOG.get('ENDPOINT', ''),
+            'access_key_id': config_.ALIYUN_LOG.get('ACCESSID', ''),
+            'access_key': config_.ALIYUN_LOG.get('ACCESSKEY', ''),
+            'project': config_.ALIYUN_LOG.get('PROJECT', ''),
+            'log_store': "info",
+            'extract_kv': True,
+            'extract_json': True
+        },
+        'errorHandler': {
+            '()': 'aliyun.log.QueuedLogHandler',
+            'level': 'ERROR',
+            'formatter': 'rawFormatter',
+            # custom args:
+            'end_point': config_.ALIYUN_LOG.get('ENDPOINT', ''),
+            'access_key_id': config_.ALIYUN_LOG.get('ACCESSID', ''),
+            'access_key': config_.ALIYUN_LOG.get('ACCESSKEY', ''),
+            'project': config_.ALIYUN_LOG.get('PROJECT', ''),
+            'log_store': "error",
+            'extract_kv': True,
+            'extract_json': True
+        },
+        'fileHandler': {
+            '()': 'logging.FileHandler',
+            'level': 'INFO',
+            'formatter': 'simpleFormatter',
+            'filename': log_name,
+            'mode': 'a',
+            'encoding': 'utf-8'
+        }
+    },
+    'loggers': {
+        'root': {
+            'handlers': ['consoleHandler', ],
+            'level': 'DEBUG'
+        },
+        'sls': {
+            'handlers': ['consoleHandler', 'slsHandler'],
+            'level': 'INFO',
+            'propagate': False
+        },
+        'error': {
+            'handlers': ['consoleHandler', 'errorHandler'],
+            'level': 'ERROR',
+            'propagate': False
+        }
+    }
+}