add query string in the request log
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
Simon Vieille 2023-05-27 18:11:40 +02:00
parent 5346e68c5c
commit d84612a425
Signed by: deblan
GPG key ID: 579388D585F70417
4 changed files with 47 additions and 14 deletions

View file

@ -1,5 +1,9 @@
## [Unreleased] ## [Unreleased]
## v1.1.0
### Added
- add query string in the request log
## v1.0.0 ## v1.0.0
### Added ### Added
- remove "retry" button and add a button for each request in the list - remove "retry" button and add a button for each request in the list

View file

@ -27,12 +27,13 @@ type Capture struct {
} }
type Req struct { type Req struct {
Proto string Proto string `json:"proto"`
Method string Method string `json:"method"`
Url string Url string `json:"url"`
Path string Path string `json:"path"`
Header http.Header Query string `json:"query"`
Body []byte Header http.Header `json:"header"`
Body []byte `json:"body"`
} }
type Res struct { type Res struct {
@ -54,6 +55,7 @@ type CaptureInfo struct {
type DashboardItem struct { type DashboardItem struct {
ID int `json:"id"` ID int `json:"id"`
Path string `json:"path"` Path string `json:"path"`
Query string `json:"query"`
Method string `json:"method"` Method string `json:"method"`
Status int `json:"status"` Status int `json:"status"`
@ -115,6 +117,7 @@ func (s *CaptureService) DashboardItems() []DashboardItem {
metadatas[i] = DashboardItem{ metadatas[i] = DashboardItem{
ID: capture.ID, ID: capture.ID,
Path: capture.Req.Path, Path: capture.Req.Path,
Query: capture.Req.Query,
Method: capture.Req.Method, Method: capture.Req.Method,
Status: capture.Res.Code, Status: capture.Res.Code,
Elapsed: capture.Elapsed, Elapsed: capture.Elapsed,

View file

@ -185,6 +185,14 @@
color: var(--disabled); color: var(--disabled);
} }
.query {
padding: 1rem;
font-family: inherit;
font-weight: 400;
line-height: 1.2em;
color: #fff;
}
pre { pre {
word-break: break-all; word-break: break-all;
white-space: pre-wrap; white-space: pre-wrap;
@ -330,11 +338,11 @@
<div class="list-inner"> <div class="list-inner">
<div class="list-item" v-for="item in items" :key="item.id" @click="show(item)" <div class="list-item" v-for="item in items" :key="item.id" @click="show(item)"
:class="{selected: selectedItem.id == item.id}"> :class="{selected: selectedItem.id == item.id}">
<span class="method" :class="item.method">{{item.method}}</span> <span class="method" :class="item.method">{{ item.method }}</span>
<span class="path">&lrm;{{item.path}}&lrm;</span> <span class="path">&lrm;{{ item.path }}&lrm;</span>
<span class="time">{{item.elapsed}}ms</span> <span class="time">{{ item.elapsed }}ms</span>
<span class="status" :class="statusColor(item)"> <span class="status" :class="statusColor(item)">
{{item.status == 999 ? 'failed' : item.status}} {{ item.status == 999 ? 'failed' : item.status }}
</span> </span>
<button class="retry" @click="retry(item.id)"> <button class="retry" @click="retry(item.id)">
<svg stroke-width="3" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M21.888 13.5C21.164 18.311 17.013 22 12 22 6.477 22 2 17.523 2 12S6.477 2 12 2c4.1 0 7.625 2.468 9.168 6" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"></path><path d="M17 8h4.4a.6.6 0 00.6-.6V3" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"></path></svg> <svg stroke-width="3" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M21.888 13.5C21.164 18.311 17.013 22 12 22 6.477 22 2 17.523 2 12S6.477 2 12 2c4.1 0 7.625 2.468 9.168 6" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"></path><path d="M17 8h4.4a.6.6 0 00.6-.6V3" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"></path></svg>
@ -350,7 +358,7 @@
</div> </div>
<div class="req-inner"> <div class="req-inner">
<div class="corner">req</div> <div class="corner">req</div>
<pre>{{selectedItem.request}}</pre> <pre>{{ selectedItem.request }}</pre>
</div> </div>
</div> </div>
@ -360,14 +368,14 @@
</div> </div>
<div class="res-inner"> <div class="res-inner">
<div class="corner">res</div> <div class="corner">res</div>
<pre :class="{error: selectedItem.status == 999}">{{selectedItem.response}}</pre> <pre :class="{error: selectedItem.status == 999}">{{ selectedItem.response }}</pre>
</div> </div>
</div> </div>
<div class="welcome" v-show="items.length == 0"> <div class="welcome" v-show="items.length == 0">
<p> <p>
Waiting for requests on http://localhost:{{proxyPort}}/<br> Waiting for requests on http://localhost:{{proxyPort}}/<br>
<span>Proxying {{targetURL}}</span> <span>Proxying {{ targetURL }}</span>
</p> </p>
</div> </div>

20
main.go
View file

@ -212,9 +212,11 @@ func NewRecorderHandler(srv *CaptureService, next http.HandlerFunc) http.Handler
Method: r.Method, Method: r.Method,
Url: r.URL.String(), Url: r.URL.String(),
Path: r.URL.Path, Path: r.URL.Path,
Query: extractQueryString(r.RequestURI),
Header: r.Header, Header: r.Header,
Body: reqBody.Bytes(), Body: reqBody.Bytes(),
} }
res := Res{ res := Res{
Proto: rec.Result().Proto, Proto: rec.Result().Proto,
Status: rec.Result().Status, Status: rec.Result().Status,
@ -246,8 +248,14 @@ func NewProxyHandler(URL string) http.HandlerFunc {
func dump(c *Capture) CaptureInfo { func dump(c *Capture) CaptureInfo {
req := c.Req req := c.Req
res := c.Res res := c.Res
query := ""
if len(req.Query) > 1 {
query = "?" + req.Query
}
return CaptureInfo{ return CaptureInfo{
Request: dumpContent(req.Header, req.Body, "%s %s %s\n\n", req.Method, req.Path, req.Proto), Request: dumpContent(req.Header, req.Body, "%s %s%s %s\n\n", req.Method, req.Path, query, req.Proto),
Response: dumpContent(res.Header, res.Body, "%s %s\n\n", res.Proto, res.Status), Response: dumpContent(res.Header, res.Body, "%s %s\n\n", res.Proto, res.Status),
Curl: dumpCurl(req), Curl: dumpCurl(req),
} }
@ -296,3 +304,13 @@ func dumpCurl(req Req) string {
} }
return b.String() return b.String()
} }
func extractQueryString(uri string) string {
parts := strings.SplitN(uri, "?", 2)
if len(parts) != 2 {
return ""
}
return parts[1]
}