Skip to content

Commit 992c14a

Browse files
author
兰师鹏
committed
support parse gzip response & record traffic to es
1 parent d7bba4d commit 992c14a

File tree

9 files changed

+211
-6
lines changed

9 files changed

+211
-6
lines changed

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ require (
66
github.com/agiledragon/gomonkey v2.0.1+incompatible
77
github.com/stretchr/testify v1.6.1
88
github.com/v2pro/plz v0.0.0-20221028024117-e5f9aec5b631
9+
golang.org/x/text v0.1.0
910
)

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd
1818
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
1919
github.com/v2pro/plz v0.0.0-20221028024117-e5f9aec5b631 h1:WYq/4UeJfAorBY7ncC31bVxI031x4MUCQvF+z12fIYA=
2020
github.com/v2pro/plz v0.0.0-20221028024117-e5f9aec5b631/go.mod h1:3gacX+hQo+xvl0vtLqCMufzxuNCwt4geAVOMt2LQYfE=
21+
golang.org/x/text v0.1.0 h1:LEnmSFmpuy9xPmlp2JeGQQOYbPv3TkQbuGJU3A0HegU=
22+
golang.org/x/text v0.1.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
2123
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
2224
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
2325
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package httpclient
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"io/ioutil"
7+
"net/http"
8+
"time"
9+
10+
"github.com/didi/sharingan/recorder-agent/common/zap"
11+
)
12+
13+
type HttpClient struct {
14+
}
15+
16+
var Handler HttpClient
17+
18+
func Init() {
19+
Handler = HttpClient{}
20+
}
21+
22+
//Post http post
23+
func (hc *HttpClient) Post(ctx context.Context, url string, jsonBytes []byte, timeout time.Duration) (*http.Response, []byte, error) {
24+
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBytes))
25+
if err != nil {
26+
zap.Logger.Error(zap.Format(ctx, "ERROR", err.Error()))
27+
return nil, nil, err
28+
}
29+
req.SetBasicAuth("elastic", "ES_test_7")
30+
//默认 application/json
31+
req.Header.Set("Content-Type", "application/json;charset=utf-8")
32+
33+
client := &http.Client{}
34+
if timeout > 0 {
35+
client.Timeout = timeout
36+
}
37+
resp, err := client.Do(req)
38+
zap.Logger.Info(zap.Format(ctx, "INFO", "resp=%v", resp))
39+
if err != nil {
40+
zap.Logger.Error(zap.Format(ctx, "ERROR", err.Error()))
41+
return nil, nil, err
42+
}
43+
defer resp.Body.Close()
44+
45+
body, _ := ioutil.ReadAll(resp.Body)
46+
return resp, body, nil
47+
}

recorder-agent/common/zap/init.go

+26
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package zap
22

33
import (
4+
"context"
5+
"fmt"
46
"log"
7+
"runtime"
8+
"strings"
59
"time"
610

711
"github.com/didi/sharingan/recorder-agent/common/conf"
@@ -49,3 +53,25 @@ func init() {
4953

5054
Logger = zap.New(core)
5155
}
56+
57+
func Format(ctx context.Context, level string, format string, args ...interface{}) string {
58+
// time
59+
ts := time.Now().Format("2006-01-02 15:04:05.000000")
60+
61+
// file, line
62+
_, file, line, ok := runtime.Caller(2)
63+
if !ok {
64+
file = "file"
65+
line = -1
66+
}
67+
68+
// igonre dir
69+
file = strings.TrimPrefix(file, path.Root+"/")
70+
71+
var ctxString string
72+
if t, ok := ctx.Value(tracerKey).(Tracer); ok {
73+
ctxString = t.Format()
74+
}
75+
76+
return fmt.Sprintf("[%s][%s][%s:%d] %s%s", level, ts, file, line, ctxString, fmt.Sprintf(format, args...))
77+
}

recorder-agent/common/zap/trace.go

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package zap
2+
3+
import (
4+
"bytes"
5+
"context"
6+
)
7+
8+
type Tracer interface {
9+
Format() string
10+
}
11+
12+
var NewTracer = func(data map[string]string) *tracer {
13+
return &tracer{data: data}
14+
}
15+
16+
type tracer struct {
17+
data map[string]string
18+
}
19+
20+
func (t *tracer) Format() string {
21+
var buf bytes.Buffer
22+
for k, v := range t.data {
23+
buf.WriteString(k)
24+
buf.WriteString("=")
25+
buf.WriteString(v)
26+
buf.WriteString("||")
27+
}
28+
return buf.String()
29+
}
30+
31+
const tracerKey = "::tracer::"
32+
33+
func TraceContext(ctx context.Context, t Tracer) context.Context {
34+
return context.WithValue(ctx, tracerKey, t)
35+
}

recorder-agent/conf/app.toml

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,7 @@ idleTimeout = 5000 # Keep-alive timeout(ms)
1010
filename = "log/recorder.log.%Y%m%d%H"
1111
linkname = "log/recorder.log"
1212
maxHourAge = 4 # 默认日志保留4小时
13-
maxHourRotate = 1 # 默认日志按小时切分
13+
maxHourRotate = 1 # 默认日志按小时切分
14+
15+
[es_url]
16+
# 确保录制机器可以访问,check:`curl http://127.0.0.1:9002/xxx/recorder_index/_search`能写入数据

recorder-agent/main.go

+21-3
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,27 @@ import (
55
"log"
66
"net/http"
77
"runtime/debug"
8+
"time"
89

910
"github.com/didi/sharingan/recorder-agent/common/conf"
11+
"github.com/didi/sharingan/recorder-agent/common/httpclient"
1012
"github.com/didi/sharingan/recorder-agent/common/zap"
1113
"github.com/didi/sharingan/recorder-agent/record"
1214
"github.com/didi/sharingan/recorder-agent/server"
1315
)
1416

17+
const (
18+
timeOut = 10 * time.Second
19+
)
20+
1521
var (
1622
svr = server.New()
1723
)
1824

25+
func init() {
26+
httpclient.Init()
27+
}
28+
1929
func main() {
2030
defer func() {
2131
if r := recover(); r != nil {
@@ -57,8 +67,16 @@ func indexHandler(w http.ResponseWriter, r *http.Request) {
5767
return
5868
}
5969

60-
// TO log
61-
w.Write([]byte("OK"))
62-
zap.Logger.Info(string(buf)) // 日志收集,最终入ES
70+
// 日志收集,最终入ES
71+
url := conf.Handler.GetString("es_url.default")
72+
if _, _, err := httpclient.Handler.Post(r.Context(), url, buf, timeOut); err != nil {
73+
zap.Logger.Error(zap.Format(r.Context(), "ERROR", "send data to es err: %v", err))
74+
75+
// TO log
76+
w.Write([]byte("OK"))
77+
zap.Logger.Info(string(buf))
78+
return
79+
}
80+
6381
return
6482
}

recorder/koala/recording/action.go

+73-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,24 @@
11
package recording
22

33
import (
4+
"bufio"
5+
"bytes"
6+
"compress/gzip"
47
"encoding/json"
8+
"fmt"
9+
"io/ioutil"
510
"net"
11+
"net/http"
12+
"strings"
613
"unicode/utf8"
14+
15+
"golang.org/x/text/encoding/simplifiedchinese"
16+
"golang.org/x/text/transform"
17+
)
18+
19+
const (
20+
callOutboundAction = "callOutbound"
21+
returnInboundAction = "returnInbound"
722
)
823

924
// Action Action
@@ -63,7 +78,7 @@ func (returnInbound *ReturnInbound) MarshalJSON() ([]byte, error) {
6378
Response json.RawMessage
6479
}{
6580
ReturnInbound: *returnInbound,
66-
Response: EncodeAnyByteArray(returnInbound.Response),
81+
Response: ParesResponse(returnInbound.Response, returnInboundAction),
6782
})
6883
}
6984

@@ -90,7 +105,7 @@ func (callOutbound *CallOutbound) MarshalJSON() ([]byte, error) {
90105
}{
91106
CallOutbound: *callOutbound,
92107
Request: EncodeAnyByteArray(callOutbound.Request),
93-
Response: EncodeAnyByteArray(callOutbound.Response),
108+
Response: ParesResponse(callOutbound.Response, callOutboundAction),
94109
CSpanID: EncodeAnyByteArray(callOutbound.CSpanID),
95110
})
96111
}
@@ -310,3 +325,59 @@ func EncodeAnyByteArray(s []byte) json.RawMessage {
310325
encoded = append(encoded, '"')
311326
return json.RawMessage(encoded)
312327
}
328+
329+
// ParesResponse ...
330+
func ParesResponse(s []byte, action string) json.RawMessage {
331+
encoded := []byte{'"'}
332+
if !bytes.Contains(s, []byte("Content-Encoding: gzip")) {
333+
return EncodeAnyByteArray(s)
334+
}
335+
336+
// handle gzip response
337+
reader := bufio.NewReader(strings.NewReader(string(s)))
338+
resp, err := http.ReadResponse(reader, nil)
339+
if err != nil {
340+
fmt.Println("反序列化HTTP响应出错:", err)
341+
return encoded
342+
}
343+
defer resp.Body.Close()
344+
345+
// 解析响应体
346+
bodyBytes, err := ioutil.ReadAll(resp.Body)
347+
if err != nil {
348+
fmt.Println("读取响应体出错:", err)
349+
return encoded
350+
}
351+
352+
// 检查Content-Encoding,并解压缩响应体
353+
if resp.Header.Get("Content-Encoding") == "gzip" {
354+
reader, err := gzip.NewReader(bytes.NewReader(bodyBytes))
355+
if err != nil {
356+
fmt.Println("创建gzip解压缩读取器出错:", err)
357+
return encoded
358+
}
359+
defer reader.Close()
360+
361+
bodyBytes, err = ioutil.ReadAll(reader)
362+
if err != nil {
363+
fmt.Println("读取解压缩后的内容出错:", err)
364+
return encoded
365+
}
366+
367+
switch action {
368+
case returnInboundAction:
369+
return bodyBytes
370+
case callOutboundAction:
371+
// 将GBK编码转换为UTF-8编码
372+
utf8Bytes, err := ioutil.ReadAll(transform.NewReader(bytes.NewReader(bodyBytes), simplifiedchinese.GBK.NewDecoder()))
373+
if err != nil {
374+
fmt.Println("err: ", err)
375+
return encoded
376+
}
377+
378+
return utf8Bytes
379+
}
380+
}
381+
382+
return encoded
383+
}

replayer-agent/common/handlers/httpclient/init.go

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ func (hc *HttpClient) Get(ctx context.Context, url string) (*http.Response, []by
2626
tlog.Handler.Errorf(ctx, tlog.DLTagUndefined, err.Error())
2727
return nil, nil, err
2828
}
29+
req.SetBasicAuth("username", "password")
2930
req.Header.Set("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
3031

3132
client := &http.Client{}
@@ -48,6 +49,7 @@ func (hc *HttpClient) Post(ctx context.Context, url string, jsonBytes []byte, ti
4849
tlog.Handler.Errorf(ctx, tlog.DLTagUndefined, err.Error())
4950
return nil, nil, err
5051
}
52+
req.SetBasicAuth("username", "password")
5153
//默认 application/json
5254
req.Header.Set("Content-Type", "application/json;charset=utf-8")
5355
//headers 优先级更高

0 commit comments

Comments
 (0)