From d4446e3203c959b790b4ff766de2dce4770ff4cf Mon Sep 17 00:00:00 2001 From: chyroc Date: Wed, 29 May 2024 18:16:20 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=87=8D=E6=9E=84=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- impl.go | 1 + impl_request.go | 79 +++++++++++++++++++++++++++++++------------------ lark.go | 6 ++++ logger.go | 26 +++++++++++++++- 4 files changed, 82 insertions(+), 30 deletions(-) diff --git a/impl.go b/impl.go index 8281b5be..5659329d 100644 --- a/impl.go +++ b/impl.go @@ -39,6 +39,7 @@ type Lark struct { wwwBaseURL string isEnableLogID bool noBlocking bool + disableErrorLog bool apiMiddlewares []ApiMiddleware httpClient HttpClient diff --git a/impl_request.go b/impl_request.go index 6119bef8..b488e213 100644 --- a/impl_request.go +++ b/impl_request.go @@ -70,33 +70,60 @@ func (r *Mock) UnMockRawRequest() { } func (r *Lark) rawRequest(ctx context.Context, req *RawRequestReq, resp interface{}) (response *Response, err error) { - r.Log(ctx, LogLevelInfo, "[lark] %s#%s call api", req.Scope, req.API) - // 1. parse request rawHttpReq, err := r.parseRawHttpRequest(ctx, req) if err != nil { + // 这里日志不需要区分 level, 输出 [error] 日志 + r.Log(ctx, LogLevelError, "[lark] %s#%s %s %s parse_req failed, err=%s", req.Scope, req.API, req.Method, req.URL, err) return response, err } - // 2. do request - response, err = r.doRequest(ctx, rawHttpReq, resp) + // 请求日志 + logLevel := r.getLogLevel() + switch logLevel { + case LogLevelDebug: + r.Log(ctx, LogLevelDebug, "[lark] %s#%s %s %s req, header=%s, body=%s", rawHttpReq.Scope, rawHttpReq.API, rawHttpReq.Method, rawHttpReq.URL, jsonHeader(rawHttpReq.Headers), string(rawHttpReq.RawBody)) + case LogLevelInfo: + r.Log(ctx, LogLevelInfo, "[lark] %s#%s %s %s req", rawHttpReq.Scope, rawHttpReq.API, rawHttpReq.Method, rawHttpReq.URL) + default: + // error 不需要 req 日志, 合并到 resp 一起 + } - logID, statusCode := getResponseLogID(response) + // 2. do request + var respContent string + response, respContent, err = r.doRequest(ctx, rawHttpReq, resp) if err != nil { - r.Log(ctx, LogLevelError, "[lark] %s#%s %s %s failed, log_id: %s, status_code: %d, error: %s", req.Scope, req.API, req.Method, req.URL, logID, statusCode, err) + switch logLevel { + case LogLevelDebug: + // [debug]: 详细 error 日志 + r.Log(ctx, LogLevelError, "[lark] %s#%s %s %s resp, log_id=%s, status=%s, resp=%s", rawHttpReq.Scope, rawHttpReq.API, rawHttpReq.Method, rawHttpReq.URL, response.LogID, response.StatusCode, respContent) + default: + // 其他: 简单 error 日志 + r.Log(ctx, LogLevelError, "[lark] %s#%s %s %s resp, log_id=%s, status=%s", rawHttpReq.Scope, rawHttpReq.API, rawHttpReq.Method, rawHttpReq.URL, response.LogID, response.StatusCode) + } return response, err } - code, msg, detailErr := getCodeMsg(resp) + + // 业务错误(API 成功) + if response.StatusCode >= http.StatusBadRequest || code != 0 { + r.Log(ctx, LogLevelError, "[lark] %s#%s %s %s resp, log_id=%s, status=%s, code=%d, msg=%s, detail=%s", rawHttpReq.Scope, rawHttpReq.API, rawHttpReq.Method, rawHttpReq.URL, response.LogID, response.StatusCode, code, msg, detailErr) + } else { + switch logLevel { + case LogLevelDebug: + r.Log(ctx, LogLevelDebug, "[lark] %s#%s %s %s resp, log_id=%s, body=%s", rawHttpReq.Scope, rawHttpReq.API, rawHttpReq.Method, rawHttpReq.URL, response.LogID, respContent) + case LogLevelInfo: + r.Log(ctx, LogLevelInfo, "[lark] %s#%s %s %s resp, log_id=%s", rawHttpReq.Scope, rawHttpReq.API, rawHttpReq.Method, rawHttpReq.URL, response.LogID) + default: + // error 不需要 resp 日志 + } + } if code != 0 { e := NewError(req.Scope, req.API, code, msg) e.(*Error).ErrorDetail = detailErr - r.Log(ctx, LogLevelError, "[lark] %s#%s %s %s failed, log_id: %s, status_code: %d, code: %d, msg: %s", req.Scope, req.API, req.Method, req.URL, logID, statusCode, code, msg) return response, e } - r.Log(ctx, LogLevelDebug, "[lark] %s#%s success, log_id: %s, status_code: %d, response: %s", req.Scope, req.API, logID, statusCode, "TODO") - return response, nil } @@ -149,17 +176,12 @@ func (r *Lark) parseRawHttpRequest(ctx context.Context, req *RawRequestReq) (*ra return rawHttpReq, nil } -func (r *Lark) doRequest(ctx context.Context, rawHttpReq *rawHttpRequest, realResponse interface{}) (*Response, error) { +func (r *Lark) doRequest(ctx context.Context, rawHttpReq *rawHttpRequest, realResponse interface{}) (*Response, string, error) { response := new(Response) response.Method = rawHttpReq.Method response.URL = rawHttpReq.URL response.Header = map[string][]string{} - if r.logLevel <= LogLevelTrace { - r.Log(ctx, LogLevelTrace, "[lark] request %s#%s, %s %s, header=%s, body=%s", rawHttpReq.Scope, rawHttpReq.API, - rawHttpReq.Method, rawHttpReq.URL, jsonHeader(rawHttpReq.Headers), string(rawHttpReq.RawBody)) - } - if rawHttpReq.Timeout > 0 { var cancel context.CancelFunc ctx, cancel = context.WithTimeout(ctx, rawHttpReq.Timeout) @@ -168,7 +190,7 @@ func (r *Lark) doRequest(ctx context.Context, rawHttpReq *rawHttpRequest, realRe req, err := http.NewRequestWithContext(ctx, rawHttpReq.Method, rawHttpReq.URL, rawHttpReq.Body) if err != nil { - return response, err + return response, "", err } for k, v := range rawHttpReq.Headers { req.Header.Set(k, v) @@ -176,7 +198,7 @@ func (r *Lark) doRequest(ctx context.Context, rawHttpReq *rawHttpRequest, realRe resp, err := r.httpClient.Do(ctx, req) if err != nil { - return response, err + return response, "", err } _, media, _ := mime.ParseMediaType(resp.Header.Get("Content-Disposition")) @@ -197,15 +219,14 @@ func (r *Lark) doRequest(ctx context.Context, rawHttpReq *rawHttpRequest, realRe bs, err := ioutil.ReadAll(resp.Body) if err != nil { - return response, err + return response, "", err } - if r.logLevel <= LogLevelTrace { - if respFilename == "" { - r.Log(ctx, LogLevelTrace, "[lark] response %s#%s, %s %s, body=%s", rawHttpReq.Scope, rawHttpReq.API, rawHttpReq.Method, rawHttpReq.URL, string(bs)) - } else { - r.Log(ctx, LogLevelTrace, "[lark] response %s#%s, %s %s, body=", rawHttpReq.Scope, rawHttpReq.API, rawHttpReq.Method, rawHttpReq.URL, len(bs)) - } + var respContent string + if respFilename == "" { + respContent = string(bs) + } else { + respContent = fmt.Sprintf("", len(bs)) } if realResponse != nil { @@ -220,20 +241,20 @@ func (r *Lark) doRequest(ctx context.Context, rawHttpReq *rawHttpRequest, realRe setter.SetFilename(respFilename) } if isSpecResp { - return response, nil + return response, respContent, nil } } if len(bs) == 0 && resp.StatusCode >= http.StatusBadRequest { - return response, fmt.Errorf("request fail: %s", resp.Status) + return response, respContent, fmt.Errorf("request fail: %s", resp.Status) } if err = json.Unmarshal(bs, realResponse); err != nil { - return response, fmt.Errorf("invalid json: %s, err: %s", bs, err) + return response, respContent, fmt.Errorf("invalid json: %s, err: %s", bs, err) } } - return response, nil + return response, respContent, nil } func (r *rawHttpRequest) parseHeader(ctx context.Context, ins *Lark, req *RawRequestReq) error { diff --git a/lark.go b/lark.go index b854b7e9..11de4ef3 100644 --- a/lark.go +++ b/lark.go @@ -157,6 +157,12 @@ func WithNonBlockingCallback(noBlocking bool) ClientOptionFunc { } } +func WithDisableErrorLog(disableErrorLog bool) ClientOptionFunc { + return func(lark *Lark) { + lark.disableErrorLog = disableErrorLog + } +} + // MethodOptionFunc new method option type MethodOptionFunc func(*MethodOption) diff --git a/logger.go b/logger.go index 607c96bc..f76692ae 100644 --- a/logger.go +++ b/logger.go @@ -35,8 +35,20 @@ type Logger interface { type LogLevel int // LogLevelTrace ... +// +// 1. 开启了 mock 的情况下, mock 链路打印一条 debug 日志 +// +// 2. req: +// 2.1 trace/debug: [debug] 日志 + 请求体 +// 2.2 info: [info] 日志 + 无请求体 +// 2.3 warn/error: 没有日志 +// +// 3. resp: +// 3.1 trace/debug: 无论有无错误: [debug] 日志 + 返回体 +// 3.2 info: 无论有无错误: [info] 日志 + 无返回体 +// 3.3 warn/error: 有错误: [error] 日志 + 无返回体; 无错误: 无日志 const ( - LogLevelTrace LogLevel = iota + 1 // 只有两个 log req 和 resp 的 文本内容 + LogLevelTrace LogLevel = iota + 1 LogLevelDebug LogLevelInfo LogLevelWarn @@ -61,7 +73,19 @@ func (r LogLevel) String() string { } } +func (r *Lark) getLogLevel() LogLevel { + if r.logLevel <= LogLevelDebug { + return LogLevelDebug + } else if r.logLevel <= LogLevelInfo { + return LogLevelInfo + } + return LogLevelError +} + func (r *Lark) Log(ctx context.Context, level LogLevel, msg string, args ...interface{}) { + if level == LogLevelError && r.disableErrorLog { + level = LogLevelWarn + } if r.logger != nil && r.logLevel <= level { r.logger.Log(ctx, level, msg, args...) }