-
Notifications
You must be signed in to change notification settings - Fork 0
/
tracing.go
134 lines (114 loc) · 3.33 KB
/
tracing.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package main
import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"net/http/httputil"
"strings"
"github.com/Sirupsen/logrus"
"github.com/gorilla/mux"
"github.com/TykTechnologies/tyk/apidef"
)
type traceHttpRequest struct {
Method string `json:"method"`
Path string `json:"path"`
Body string `json:"body"`
Headers http.Header `json:"headers"`
}
func (tr *traceHttpRequest) toRequest() *http.Request {
r := httptest.NewRequest(tr.Method, tr.Path, strings.NewReader(tr.Body))
r.Header = tr.Headers
ctxSetTrace(r)
return r
}
// Tracing HTTP request
//
// swagger:model
type traceRequest struct {
Request *traceHttpRequest `json:"request"`
Spec *apidef.APIDefinition `json:"spec"`
}
// Tracing HTTP response
//
// swagger:model
type traceResponse struct {
Message string `json:"message"`
Response string `json:"response"`
Logs string `json:"logs"`
}
// swagger:operation POST /trace trace trace
//
// Tracing request
// Used to test API definition by sending sample request,
// and analysisng output of both response and logs
//
//---
// requestBody:
// content:
// application/json:
// schema:
// "$ref": "#/definitions/traceRequest"
// examples:
// request:
// method: GET
// path: /get
// headers:
// Authorization: key
// spec:
// api_name: "Test"
// responses:
// 200:
// description: Success tracing request
// schema:
// "$ref": "#/definitions/traceResponse"
// examples:
// message: "ok"
// response:
// code: 200
// headers:
// Header: value
// body: body-value
// logs: {...}\n{...}
func traceHandler(w http.ResponseWriter, r *http.Request) {
var traceReq traceRequest
if err := json.NewDecoder(r.Body).Decode(&traceReq); err != nil {
log.Error("Couldn't decode trace request: ", err)
doJSONWrite(w, http.StatusBadRequest, apiError("Request malformed"))
return
}
if traceReq.Spec == nil {
log.Error("Spec field is missing")
doJSONWrite(w, http.StatusBadRequest, apiError("Spec field is missing"))
return
}
if traceReq.Request == nil {
log.Error("Request field is missing")
doJSONWrite(w, http.StatusBadRequest, apiError("Request field is missing"))
return
}
var logStorage bytes.Buffer
logger := logrus.New()
logger.Formatter = &logrus.JSONFormatter{}
logger.Level = logrus.DebugLevel
logger.Out = &logStorage
redisStore, redisOrgStore, healthStore, rpcAuthStore, rpcOrgStore := prepareStorage()
subrouter := mux.NewRouter()
loader := &APIDefinitionLoader{}
spec := loader.MakeSpec(traceReq.Spec, logrus.NewEntry(logger))
chainObj := processSpec(spec, nil, redisStore, redisOrgStore, healthStore, rpcAuthStore, rpcOrgStore, subrouter, logrus.NewEntry(logger))
spec.middlewareChain = chainObj.ThisHandler
if chainObj.ThisHandler == nil {
doJSONWrite(w, http.StatusBadRequest, traceResponse{Message: "error", Logs: logStorage.String()})
return
}
wr := httptest.NewRecorder()
chainObj.ThisHandler.ServeHTTP(wr, traceReq.Request.toRequest())
var response string
if dump, err := httputil.DumpResponse(wr.Result(), true); err == nil {
response = string(dump)
} else {
response = err.Error()
}
doJSONWrite(w, http.StatusOK, traceResponse{Message: "ok", Response: response, Logs: logStorage.String()})
}