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