作者 yangfu

compare , request history

FROM golang:1.13 as builder
ENV GOPROXY https://goproxy.cn
ENV GO111MODULE on
RUN git clone http://gitlab.fjmaimaimai.com/mmm-go/gocomm.git /app/gocomm
WORKDIR /app/ab
COPY go.mod .
COPY go.sum .
RUN go mod download
COPY . .
RUN GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -installsuffix cgo -o ab main.go
#FROM scratch
FROM alpine:latest
RUN apk add --no-cache tzdata \
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo "Asia/Shanghai" > /etc/timezone \
&& rm -rf /var/cache/apk/* /tmp/* /var/tmp/* $HOME/.cache ## 清除缓存
WORKDIR /root/
COPY --from=builder /app/ab .
#RUN ls -l
EXPOSE 8080
CMD ["./ab"]
\ No newline at end of file
... ...
... ... @@ -2,10 +2,13 @@ appname = ab
httpport = 8080
runmode = dev
#没设置的话 this.Ctx.Input.RequestBody 没有值
copyrequestbody = true
#redis相关配置
redis_add_port = "127.0.0.1:6379"
redis_auth = "123456"
#远程
AHost = "127.0.0.1:8081"
BHost = "127.0.0.1:8082"
AHost = "http://127.0.0.1:8081"
BHost = "http://127.0.0.1:8082"
... ...
package controllers
import (
"encoding/hex"
"encoding/json"
"fmt"
"github.com/astaxie/beego"
"gitlab.fjmaimaimai.com/mmm-go/ab/protocol"
"gitlab.fjmaimaimai.com/mmm-go/ab/services/ab"
"gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/mybeego"
"gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log"
"github.com/astaxie/beego/httplib"
"io/ioutil"
"net/http"
"path"
"reflect"
"strings"
)
type ABController struct {
... ... @@ -24,7 +16,8 @@ var bHost string
const (
QueryResponseError = 1 //请求应答错误
CompareResultError=2 //应答对比错误
CompareResultSuccess=2 //应答对比成功
CompareResultError=3 //应答对比错误
)
func init(){
... ... @@ -34,124 +27,20 @@ func init(){
//Compare
func(this *ABController)Compare(){
var (
msg *mybeego.Message
status string = "OK"
)
var msg *mybeego.Message
defer func(){
this.Resp(msg)
}()
method := this.Ctx.Request.Method
head :=this.Ctx.Request.Header
body :=this.ByteBody
newRequest:= NewRequest(bHost,method,head,body)
aResp,err :=makeHttpRequest(aHost,method,head,body)
if err!=nil{
status ="FAIL"
request :=&protocol.CompareRequest{
Method:this.Ctx.Request.Method,
RequestUri:this.Ctx.Request.RequestURI,
Head:this.Ctx.Request.Header,
Body:this.ByteBody,
IsRetry:false,
}
log.Debug(fmt.Sprintf("[%v]- Method:%v \n Head:\n%v \nBody:\n%v \n Response:\n%v",status,method,head,body,aResp))
this.Data["json"] = aResp
Compare :=func(){
defer func(){
if p:=recover();p!=nil{
log.Error(p)
}
}()
//判断已经在错误列表里面就不再判断请求
bResp,err :=makeHttpRequest(bHost,method,head,body)
if err!=nil{
log.Error(err)
errorHandler(QueryResponseError,newRequest)
return
}
cResult,err :=compareResponse(aResp,bResp)
if err!=nil{
log.Error(err)
errorHandler(QueryResponseError,newRequest)
return
}
if !cResult{
errorHandler(CompareResultError,newRequest)
log.Warn(fmt.Sprintf("" +
"[Companre Error] - ErrorType:%v " +
"\nMethod:\n %v " +
"\nHead:\n %v " +
"\nAResponse:\n %v " +
"\nBResponse:\n %v",CompareResultError,method,head,string(aResp),string(bResp)))
}else{
//记录到记录行里面
log.Info("[Success] \nMethod:\n %v " +
"\nHead:\n %v " +
"\nBody:\n%v",method,head,string(body))
}
}
go Compare()
this.ServeJSON()
msg = this.GenMessage(ab.Compare(request))
}
func compareResponse(aResp,bResp []byte)(result bool,err error){
defer func(){
if p:=recover();p!=nil{
log.Error(p)
}
}()
var mapA = make(map[string]interface{})
var mapB = make(map[string]interface{})
if err =json.Unmarshal(aResp,&mapA);err!=nil{
result = false
return
}
if err =json.Unmarshal(bResp,&mapB);err!=nil{
result = false
return
}
result = reflect.DeepEqual(mapA,mapB)
return
}
func errorHandler(errType int,req Request){
//写redis error
}
func makeHttpRequest(host,method string,head map[string][]string,body []byte)(data []byte,err error){
var (
resp *http.Response
)
rawUrl := path.Join(host,method)
req := httplib.NewBeegoRequest(rawUrl,"Post")
for k,v:=range head{
req.Header(k,strings.Join(v,","))
}
req.Body(body)
resp,err =req.DoRequest()
if err!=nil{
return
}
data,err = ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
return
}
type Request struct {
Host string
Method string
Head map[string][]string
Body string //hex
}
func NewRequest(host,method string,head map[string][]string,body []byte)Request{
return Request{
Host:host,
Method:method,
Head:head,
Body:hex.EncodeToString(body),
}
}
func(req Request)GetBody()([]byte){
data,err:= hex.DecodeString(req.Body)
if err!=nil{
log.Error(err)
return []byte{}
}
return data
}
\ No newline at end of file
... ...
... ... @@ -46,4 +46,4 @@ func (this *BaseController)GenMessage(rsp interface{},err error)*mybeego.Message
}
msg = mybeego.NewMessage(1)
return msg
}
\ No newline at end of file
}
... ...
package controllers
import (
"encoding/json"
"gitlab.fjmaimaimai.com/mmm-go/ab/protocol"
"gitlab.fjmaimaimai.com/mmm-go/ab/services/history"
"gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/mybeego"
"gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log"
)
type HistoryController struct {
BaseController
}
//SuccessList
func(this *HistoryController)SuccessList(){
var msg *mybeego.Message
defer func(){
this.Resp(msg)
}()
var request *protocol.SuccessListRequest
if err:=json.Unmarshal(this.ByteBody,&request);err!=nil{
log.Error(err)
msg = mybeego.NewMessage(1)
return
}
if b,m :=this.Valid(request);!b{
msg = m
return
}
msg = this.GenMessage(history.SuccessList(request))
}
//GetRequest
func(this *HistoryController)GetRequest(){
var msg *mybeego.Message
defer func(){
this.Resp(msg)
}()
var request *protocol.GetRequestRequest
if err:=json.Unmarshal(this.ByteBody,&request);err!=nil{
log.Error(err)
msg = mybeego.NewMessage(1)
return
}
if b,m :=this.Valid(request);!b{
msg = m
return
}
msg = this.GenMessage(history.GetRequest(request))
}
//Retry
func(this *HistoryController)Retry(){
var msg *mybeego.Message
defer func(){
this.Resp(msg)
}()
var request *protocol.RetryRequest
if err:=json.Unmarshal(this.ByteBody,&request);err!=nil{
log.Error(err)
msg = mybeego.NewMessage(1)
return
}
if b,m :=this.Valid(request);!b{
msg = m
return
}
msg = this.GenMessage(history.Retry(request))
}
//DeleteHistory
func(this *HistoryController)DeleteHistory(){
var msg *mybeego.Message
defer func(){
this.Resp(msg)
}()
var request *protocol.DeleteHistoryRequest
if err:=json.Unmarshal(this.ByteBody,&request);err!=nil{
log.Error(err)
msg = mybeego.NewMessage(1)
return
}
if b,m :=this.Valid(request);!b{
msg = m
return
}
msg = this.GenMessage(history.DeleteHistory(request))
}
\ No newline at end of file
... ...
... ... @@ -4,6 +4,7 @@ go 1.13
require (
github.com/astaxie/beego v1.10.0
github.com/prometheus/common v0.4.0
gitlab.fjmaimaimai.com/mmm-go/gocomm v0.0.1
)
... ...
package protocol
import (
"encoding/json"
"gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log"
)
/*Compare */
type CompareRequest struct {
Method string
RequestUri string
Head map[string][]string
Body []byte
IsRetry bool
}
type CompareResponse struct {
}
type Request struct {
Host string `json:"-"`
Method string `json:"method"`
RequestUri string `json:"request_uri"`
Head map[string][]string `json:"head"`
Body interface{} `json:"body"`
AResp interface{} `json:"a_resp"`
BResp interface{} `json:"b_resp"`
}
func NewRequest(host,method,requestUri string,head map[string][]string,body []byte)Request{
var mapBody = make(map[string]interface{})
json.Unmarshal(body,&mapBody)
return Request{
//Host:host,
Method:method,
RequestUri:requestUri,
Head:head,
Body:mapBody,
}
}
func(req Request)GetBody()([]byte){
data,err:= json.Marshal(req.Body)
if err!=nil{
log.Error(err)
return []byte{}
}
return data
}
... ...
package protocol
import (
"sort"
"sync"
)
var(
SuccessRequestMap *sync.Map
ErrorRequestMap *sync.Map
)
const(
StatusOK ="OK"
StatusFial ="Fail"
)
func init(){
SuccessRequestMap =new(sync.Map) //&sync.Map{}
ErrorRequestMap = new(sync.Map)
//SuccessRequestMap.Store("/auth/login",&Request{Host:"1237.0.0.1"})
}
func Exists(status string,key string)bool{
m :=GetMap(status)
if _,ok:=m.Load(key);ok{
return true
}
return false
}
func SetRequest(status string,key string,req *Request){
m :=GetMap(status)
if _,ok:=m.Load(key);ok{
return
}
m.Store(key,req)
}
func GetRequest(status string,key string)(*Request){
m :=GetMap(status)
if v,ok:=m.Load(key);ok{
return v.(*Request)
}
return nil
}
func GetRequests(status string)([]*Request){
m :=GetMap(status)
var listKey []string
var list []*Request
m.Range(func(key,value interface{})bool{
listKey = append(listKey,key.(string))
return true
})
sort.Strings(listKey)
for i:=range listKey{
r :=GetRequest(status,listKey[i])
if r!=nil{
list = append(list,r)
}
}
return list
}
func DeleteRequest(status string,key string){
m :=GetMap(status)
m.Delete(key)
}
func DeleteAll(status string){
m :=GetMap(status)
m.Range(func(key,value interface{})bool{
m.Delete(key)
return true
})
}
func GetMap(status string) *sync.Map{
if status==StatusOK{
return SuccessRequestMap
}
return ErrorRequestMap
}
... ...
package protocol
/*SuccessList */
type SuccessListRequest struct {
Status int `json:"status"` // 1 succ 0 fail
}
type SuccessListResponse struct {
List []*Request `json:"list"`
}
/*GetRequest */
type GetRequestRequest struct {
Status int `json:"status" valid:"Required"`
Uri string `json:"uri" valid:"Required"`
}
type GetRequestResponse struct {
*Request
}
/*Retry */
type RetryRequest struct {
Status int `json:"status" valid:"Required"`
Uri string `json:"uri" valid:"Required"`
}
type RetryResponse struct {
ResultEqual bool `json:"result_equal"`
}
/*DeleteHistory */
type DeleteHistoryRequest struct {
Status int `json:"status" valid:"Required"`
Uri string `json:"uri" valid:"Required"`
}
type DeleteHistoryResponse struct {
}
... ...
... ... @@ -8,4 +8,12 @@ import (
func init() {
//beego.Router("/", &controllers.MainController{})
beego.Router("/*", &controllers.ABController{},"Post:Compare")
{
history :=&controllers.HistoryController{}
beego.Router("/history/successList",history,"post:SuccessList")
beego.Router("/history/getRequest",history,"post:GetRequest")
beego.Router("/history/retry",history,"post:Retry")
beego.Router("/history/deleteHistory",history,"post:DeleteHistory")
}
}
... ...
package ab
import (
"fmt"
"github.com/astaxie/beego/httplib"
"gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log"
"gitlab.fjmaimaimai.com/mmm-go/ab/protocol"
"github.com/astaxie/beego"
"io/ioutil"
"net/http"
"reflect"
"strings"
"encoding/json"
)
var aHost string
var bHost string
const (
QueryResponseError = 1 //请求应答错误
CompareResultSuccess=2 //应答对比成功
CompareResultError=3 //应答对比错误
)
func init(){
aHost =beego.AppConfig.String("AHost")
bHost =beego.AppConfig.String("BHost")
}
func Compare(request *protocol.CompareRequest)(rsp interface{},err error){
var (
status string = protocol.StatusOK
key string
)
method := request.Method
requestURI :=request.RequestUri
head :=request.Head
body :=request.Body
newRequest:= protocol.NewRequest(bHost,method,requestURI,head,body)
aResp,err :=makeHttpRequest(aHost,method,requestURI,head,body)
key =requestURI
if err!=nil{
log.Error(err)
status =protocol.StatusFial
}
var mapA = make(map[string]interface{})
if err =json.Unmarshal(aResp,&mapA);err!=nil{
return
}
//log.Debug(fmt.Sprintf("[%v]- URI:%v \n Head:\n%v \nBody:\n%v \n Response:\n%v",status,requestURI,head,string(body),string(aResp)))
Compare :=func(){
defer func(){
if p:=recover();p!=nil{
log.Error(p)
}
}()
//判断已经在错误列表里面就不再判断请求
bResp,err :=makeHttpRequest(bHost,method,requestURI,head,body)
if err!=nil{
log.Error(err)
errorHandler(QueryResponseError,&newRequest)
return
}
cResult,err :=compareResponse(aResp,bResp,&newRequest)
if err!=nil{
log.Error(err)
errorHandler(QueryResponseError,&newRequest)
return
}
if !cResult{
errorHandler(CompareResultError,&newRequest)
log.Warn(fmt.Sprintf("" +
"[Compare Error] - ErrorType:%v " +
"Method: %v " +
"\nHead: %v " +
"\nAResponse: %v " +
"\nBResponse: %v",CompareResultError,requestURI,head,string(aResp),string(bResp)))
}else{
//记录到记录行里面
errorHandler(CompareResultSuccess,&newRequest)
log.Info(fmt.Sprintf("[Compare Success] Method:%v " +
"\nHead:%v " +
"\nBody:%v",requestURI,head,string(body)))
}
}
if status==protocol.StatusOK && (!protocol.Exists(protocol.StatusOK,key) || request.IsRetry){
if !protocol.Exists(protocol.StatusFial,key){
go Compare() //已经在错误列表
}
}
rsp =mapA
return
}
func compareResponse(aResp,bResp []byte,req *protocol.Request)(result bool,err error){
defer func(){
if p:=recover();p!=nil{
log.Error(p)
}
}()
var mapA = make(map[string]interface{})
var mapB = make(map[string]interface{})
if err =json.Unmarshal(aResp,&mapA);err!=nil{
result = false
return
}
if err =json.Unmarshal(bResp,&mapB);err!=nil{
result = false
return
}
req.AResp = mapA
req.BResp = mapB
result = reflect.DeepEqual(mapA,mapB)
return
}
func errorHandler(errType int,req *protocol.Request){
if errType==QueryResponseError{
protocol.SetRequest(protocol.StatusFial,req.RequestUri,req)
return
}
if errType==CompareResultSuccess{
protocol.SetRequest(protocol.StatusOK,req.RequestUri,req)
protocol.DeleteRequest(protocol.StatusFial,req.RequestUri)
return
}
if errType==CompareResultError{
protocol.SetRequest(protocol.StatusFial,req.RequestUri,req)
return
}
}
func makeHttpRequest(host,method,requestUri string,head map[string][]string,body []byte)(data []byte,err error){
var (
resp *http.Response
)
rawUrl := host+requestUri
req := httplib.Post(rawUrl)
for k,v:=range head{
req.Header(k,strings.Join(v,","))
}
req.Body(body)
resp,err =req.Response()
if err!=nil{
return
}
data,err = ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
return
}
... ...
package history
import (
"github.com/prometheus/common/log"
"gitlab.fjmaimaimai.com/mmm-go/ab/protocol"
"gitlab.fjmaimaimai.com/mmm-go/ab/services/ab"
)
func SuccessList(request *protocol.SuccessListRequest)(rsp *protocol.SuccessListResponse,err error){
var (
)
rsp =&protocol.SuccessListResponse{
List:protocol.GetRequests(getStatus(request.Status)),
}
return
}
func getStatus(statu int)string{
status :=protocol.StatusOK
if statu==0{
status = protocol.StatusFial
}
return status
}
func GetRequest(request *protocol.GetRequestRequest)(rsp *protocol.GetRequestResponse,err error){
var (
)
rsp =&protocol.GetRequestResponse{
protocol.GetRequest(getStatus(request.Status),request.Uri),
}
return
}
func Retry(request *protocol.RetryRequest)(rsp *protocol.RetryResponse,err error){
var (
)
historyRequest := protocol.GetRequest(getStatus(request.Status),request.Uri)
if historyRequest==nil{
log.Warn("request not found , Uri:",request.Uri)
return
}
compareRequest :=&protocol.CompareRequest{
Method:historyRequest.Method,
RequestUri:historyRequest.RequestUri,
Head:historyRequest.Head,
Body: historyRequest.GetBody(),
IsRetry:true,
}
_,err = ab.Compare(compareRequest)
if err!=nil{
log.Error(err)
return
}
newRequest := protocol.GetRequest(getStatus(1),request.Uri)
rsp =&protocol.RetryResponse{ResultEqual:false}
if newRequest!=nil{//获取到成功的请求用力
rsp =&protocol.RetryResponse{ResultEqual:true}
}
return
}
func DeleteHistory(request *protocol.DeleteHistoryRequest)(rsp *protocol.DeleteHistoryResponse,err error){
var (
)
protocol.DeleteRequest(getStatus(request.Status),request.Uri)
rsp =&protocol.DeleteHistoryResponse{}
return
}
\ No newline at end of file
... ...