Python和Go真是一对难兄难弟
大家好,这篇文章主要是在我做需求的时候的所思所感,很多代码没优化甚至写的相当矬,期望大家勇于提出问题大家一块进步。
剖析需求
我们公司主要做的是某款电商APP,主要数据分为两种一是支撑OLTP的业务数据,二是支撑OLAP的历史数据和日志数据,对于业务数据一般是存在Mysql中,这个无需详细展开,对于历史数据,记录的是某些数据的历史状态变化,从而根据需求发掘出数据本身的价值,对于日志数据,主要记录的是用户的行为数据,这次的需求主要是针对前端埋点日志数据进行采集落地。
一般来说,采集的最普遍的方法就是,APP端产生的埋点日志数据在服务器上沉淀成文件,用ftp或者利用开源工具flume直接采集到kafka或者其他消息队列中等待消费或者直接落地,但现在的需求是APP端不沉淀文件,直接利用服务接口实时发送数据,然后落地到阿里云的odps上。
Python实现数据采集
主要步骤:
1.利用python写一个Http服务,并暴露接口
2.接收JSON数据完成数据格式化
3.利用python中logging模块将格式化的数据转发给阿里云的loghub,odps消费。
代码还是很简单的,直接附上:
# coding=utf-8
import os
import sys
import datetime
import requests
import flask_cors
from flask import request, Flask, jsonify
import logging
import logging.config
import json
sys.path.append(os.path.join( os.path.dirname(__file__), '../'))
#加载配置文件
logging.config.fileConfig('/root/logservice/Logservice/logging.conf', disable_existing_loggers=False)
#拿到sls的自定义日志输出,其中handler转发
logger = logging.getLogger('sls')
#flask框架初始化
app = Flask(__name__)
#实现跨域通信
CORS(app, supports_credentials=True)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
//指定路由,指定methods
@app.route('/api/logservice/info', methods=['post'])
def Log_sevice_info():
#通过request.form.get获取对应的数据即json_arr字段后面对应的json串
json_arr = request.form.get('json_arr')
try:
#转换成字典类型,以utf-8编码
jsonArray = json.loads(json_arr, encoding='utf-8')
except:
print('**************')
print(type(json_arr))
#遍历字典json串,我接收的json的每个k-v结构的k是需要替换的,下面的title_dic就是需要替换的,如果原先的k是1就换成event_name,以此类推。
for jb in jsonArray:
title_dic={"event_name":"1","event_time":"2","user_id":"3","adid":"4","trace_id":"5","source":"6","platform":"7",
"creat_version":"8","action_version":"9","pagename":"10","seatindex":"11","from_page":"12","to_page":"13",
"expand_value":"14"}
try:
jb["event_name"] = jb.pop(title_dic['event_name'])
jb["event_time"] = jb.pop(title_dic['event_time'])
jb["user_id"] = jb.pop(title_dic['user_id'])
jb["adid"] = jb.pop(title_dic['adid'])
jb["trace_id"] = jb.pop(title_dic['trace_id'])
jb["source"] = jb.pop(title_dic['source'])
jb["platform"] = jb.pop(title_dic['platform'])
jb["creat_version"] = jb.pop(title_dic['creat_version'])
jb["action_version"] = jb.pop(title_dic['action_version'])
jb["pagename"] = jb.pop(title_dic['pagename'])
jb["seatindex"] = jb.pop(title_dic['seatindex'])
jb["from_page"] = jb.pop(title_dic['from_page'])
jb["to_page"] = jb.pop(title_dic['to_page'])
jb["expand_value"] = jb.pop(title_dic['expand_value'])
//转发格式化后的json
logger.info(jb)
except:
pass
return jsonify({'code':"000000",'data':"",'message':'成功'})
//ip 和 port
if __name__ == '__main__':
app.run(host='172.20.10.61', port=4000, debug=False,threaded=True)
后面是贴的日志转发模块的conf,很简单,大家看看就明白了。
[loggers]
keys=root,sls
[handlers]
keys=consoleHandler, slsHandler
[formatters]
keys=simpleFormatter, rawFormatter
[logger_root]
level=DEBUG
handlers=consoleHandler
[logger_sls]
level=INFO
handlers=consoleHandler, slsHandler
qualname=sls
propagate=0
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)
[handler_slsHandler]
class=aliyun.log.QueuedLogHandler
level=INFO
formatter=rawFormatter
args=(os.environ.get('', ''), os.environ.get('', ''), os.environ.get('', ''), os.environ.get('', ''), "", None, None, None, None, None, None, None, None, True)
[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
[formatter_rawFormatter]
format=%(message)s
Go语言重构
使用Go语言主要是看中了他的运行效率和他的写服务的速度,但是两天前我Go语言都不知道是啥,真的就是硬写,用完Go语言我才发现python是真好使,Go语言的数据类型转换是真的费劲,不知道是不是我技术不行。。。
还有一个重要的一点就是领导想要完全舍弃阿里云,使用原生的组件自己搭建集群。
主要步骤:
1.利用Go写一个Http服务,并暴露接口
2.接收JSON数据完成数据格式化
3.利用三方包推入kafka
代码还是很简单的,直接附上(go语言这个仅供参考一切还是根据业务出发根据上面的python还是能看出逻辑的,写的我自己都不想看,真的矬。。。):
package main
import (
"encoding/json"
//"encoding/json"
"fmt"
"github.com/astaxie/beego"
"os"
"os/exec"
"path/filepath"
"strings"
)
type User struct {
Id string
Name string
Pwd string
}
type Animal struct {
Name string
Order string
}
type HanController struct {
beego.Controller
}
type MainController struct {
beego.Controller
}
func (this *MainController) Post() {
mapss := map[string]string{"event_name": "1", "event_time": "2", "user_id": "3", "adid": "4", "trace_id": "5", "source": "6",
"platform": "7",
"creat_version": "8", "action_version": "9", "pagename": "10", "seatindex": "11", "from_page": "12",
"to_page": "13",
"expand_value": "14"}
jsonmap := make(map[string]string,14)
newjsonmap :=make(map[string]string,14)
var zhz string
var pinjie string
sumpinjie :=""
//var messages string
jsar :=this.GetString("jsar")
afteranashuzu:=strings.Split(strings.Split(strings.Split(jsar, "[")[1],"]")[0],"},")
fmt.Println(len(afteranashuzu))
for _,v:=range afteranashuzu{fmt.Println(v)}
for i:=0;i< len(afteranashuzu);i++{
if i !=(len(afteranashuzu)-1) {
zhz=afteranashuzu[i]+"}"
//fmt.Println(zhz)
//json格式的数据变成map
err :=json.Unmarshal([]byte(zhz),&jsonmap)
if err !=nil{println(err)}
//替换jsonmap中的key
for k,v :=range jsonmap{
for k2,_ :=range mapss{
if k==mapss[k2]{
newjsonmap[k2]=v
}
}
}
for j:=0;j< len(afteranashuzu);j++{
for k,v:=range newjsonmap{
if j!= len(afteranashuzu)-2 {
pinjie=k+":"+v
sumpinjie=sumpinjie+pinjie+","
}else {
pinjie=k+":"+v
sumpinjie=sumpinjie+pinjie+","
}
}
afteranashuzu[j]=strings.TrimRight(sumpinjie,",")
sumpinjie=""
}
}
if i== (len(afteranashuzu)-1){
//fmt.Println(zhz)
//json格式的数据变成map
err :=json.Unmarshal([]byte(zhz),&jsonmap)
if err !=nil{println(err)}
//替换jsonmap中的key
for k,v :=range jsonmap{
for k2,_ :=range mapss{
if k==mapss[k2]{
newjsonmap[k2]=v
}
}
}
for k,v:=range newjsonmap{
pinjie=k+":"+v
sumpinjie=sumpinjie+pinjie+","
}
afteranashuzu[len(afteranashuzu)-1]=strings.TrimRight(sumpinjie,",")
}
}
//最终替换的json串存储在数组中,后面要写传入kafka然后flink进行消费
//这块就不粘了。。
}
func main() {
beego.BConfig.Listen.HTTPAddr="192.167.99.113"
beego.BConfig.Listen.HTTPPort=8080
beego.BConfig.CopyRequestBody=true
beego.BConfig.WebConfig.ViewsPath="views"
//路由注册,第一个参数就是用户请求的地址,后面的控制器用于把请求分发到不同的控制器
beego.Router("/api/logservice/exposure", &MainController{})
beego.Run()
}
上面的主要用的是beego框架,数据格式化的时候我是真没找到三方的包费死个劲了,我的go充其量算个入门吧,大家多多指正!!有大神给我讲讲beego也行啊哈哈哈哈。