mirror of
https://github.com/foomo/keel.git
synced 2025-10-16 12:35:34 +00:00
feat: fix lint errors
This commit is contained in:
parent
03be454c91
commit
596f43e841
159
.golangci.yml
159
.golangci.yml
@ -26,32 +26,139 @@ linters-settings:
|
||||
settings:
|
||||
hugeParam:
|
||||
sizeThreshold: 512
|
||||
# https://golangci-lint.run/usage/linters/#gosec
|
||||
gosec:
|
||||
config:
|
||||
G306: "0700"
|
||||
excludes:
|
||||
- G101 # Potential hardcoded credentials
|
||||
- G102 # Bind to all interfaces
|
||||
- G112 # Potential slowloris attack
|
||||
- G401 # Detect the usage of DES, RC4, MD5 or SHA1
|
||||
- G402 # Look for bad TLS connection settings
|
||||
- G404 # Insecure random number source (rand)
|
||||
- G501 # Import blocklist: crypto/md5
|
||||
- G505 # Import blocklist: crypto/sha1
|
||||
|
||||
linters:
|
||||
enable:
|
||||
- bodyclose
|
||||
- dogsled
|
||||
- exportloopref
|
||||
# - gci TODO re-enable
|
||||
- goconst
|
||||
- gocritic
|
||||
# - gocyclo
|
||||
- gofmt
|
||||
- goprintffuncname
|
||||
#- gosec
|
||||
- ifshort
|
||||
- misspell
|
||||
- nakedret
|
||||
- noctx
|
||||
- nolintlint
|
||||
- prealloc
|
||||
- revive
|
||||
- promlinter
|
||||
- rowserrcheck
|
||||
- sqlclosecheck
|
||||
- stylecheck
|
||||
- thelper
|
||||
- tparallel
|
||||
- unconvert
|
||||
- unparam
|
||||
- whitespace
|
||||
# - bodyclose
|
||||
# - dogsled
|
||||
# - exportloopref
|
||||
# # - gci TODO re-enable
|
||||
# - goconst
|
||||
# - gocritic
|
||||
# # - gocyclo
|
||||
# - gofmt
|
||||
# - goprintffuncname
|
||||
# #- gosec
|
||||
# - ifshort
|
||||
# - misspell
|
||||
# - nakedret
|
||||
# - noctx
|
||||
# - nolintlint
|
||||
# - prealloc
|
||||
# - revive
|
||||
# - promlinter
|
||||
# - rowserrcheck
|
||||
# - sqlclosecheck
|
||||
# - stylecheck
|
||||
# - thelper
|
||||
# - tparallel
|
||||
# - unconvert
|
||||
# - unparam
|
||||
# - whitespace
|
||||
|
||||
# Enabled by default linters:
|
||||
- deadcode # Finds unused code [fast: false, auto-fix: false]
|
||||
- errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases [fast: false, auto-fix: false]
|
||||
- gosimple # (megacheck): Linter for Go source code that specializes in simplifying code [fast: false, auto-fix: false]
|
||||
- govet # (vet, vetshadow): Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string [fast: false, auto-fix: false]
|
||||
- ineffassign # Detects when assignments to existing variables are not used [fast: true, auto-fix: false]
|
||||
- staticcheck # (megacheck): It's a set of rules from staticcheck. It's not the same thing as the staticcheck binary. The author of staticcheck doesn't support or approve the use of staticcheck as a library inside golangci-lint. [fast: false, auto-fix: false]
|
||||
- typecheck # Like the front-end of a Go compiler, parses and type-checks Go code [fast: false, auto-fix: false]
|
||||
- unused # (megacheck): Checks Go code for unused constants, variables, functions and types [fast: false, auto-fix: false]
|
||||
- varcheck # Finds unused global variables and constants [fast: false, auto-fix: false]
|
||||
|
||||
# Disabled by default linters:
|
||||
- asasalint # check for pass []any as any in variadic func(...any) [fast: false, auto-fix: false]
|
||||
- asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers [fast: true, auto-fix: false]
|
||||
- bidichk # Checks for dangerous unicode character sequences [fast: true, auto-fix: false]
|
||||
- bodyclose # checks whether HTTP response body is closed successfully [fast: false, auto-fix: false]
|
||||
#- containedctx # containedctx is a linter that detects struct contained context.Context field [fast: true, auto-fix: false]
|
||||
#- contextcheck # check the function whether to use a non-inherited context [fast: false, auto-fix: false]
|
||||
#- cyclop # checks function and package cyclomatic complexity [fast: false, auto-fix: false]
|
||||
- decorder # check declaration order and count of types, constants, variables and functions [fast: true, auto-fix: false]
|
||||
- depguard # Go linter that checks if package imports are in a list of acceptable packages [fast: true, auto-fix: false]
|
||||
- dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) [fast: true, auto-fix: false]
|
||||
#- dupl # Tool for code clone detection [fast: true, auto-fix: false]
|
||||
- durationcheck # check for two durations multiplied together [fast: false, auto-fix: false]
|
||||
- errchkjson # Checks types passed to the json encoding functions. Reports unsupported types and optionally reports occasions, where the check for the returned error can be omitted. [fast: false, auto-fix: false]
|
||||
- errname # Checks that sentinel errors are prefixed with the `Err` and error types are suffixed with the `Error`. [fast: false, auto-fix: false]
|
||||
- errorlint # errorlint is a linter for that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13. [fast: false, auto-fix: false]
|
||||
- execinquery # execinquery is a linter about query string checker in Query function which reads your Go src files and warning it finds [fast: false, auto-fix: false]
|
||||
- exhaustive # check exhaustiveness of enum switch statements [fast: false, auto-fix: false]
|
||||
#- exhaustruct # Checks if all structure fields are initialized [fast: false, auto-fix: false]
|
||||
- exportloopref # checks for pointers to enclosing loop variables [fast: false, auto-fix: false]
|
||||
- forbidigo # Forbids identifiers [fast: true, auto-fix: false]
|
||||
- forcetypeassert # finds forced type assertions [fast: true, auto-fix: false]
|
||||
#- funlen # Tool for detection of long functions [fast: true, auto-fix: false]
|
||||
#- gci # Gci controls golang package import order and makes it always deterministic. [fast: true, auto-fix: false]
|
||||
#- gochecknoglobals # check that no global variables exist [fast: true, auto-fix: false]
|
||||
#- gochecknoinits # Checks that no init functions are present in Go code [fast: true, auto-fix: false]
|
||||
#- gocognit # Computes and checks the cognitive complexity of functions [fast: true, auto-fix: false]
|
||||
- goconst # Finds repeated strings that could be replaced by a constant [fast: true, auto-fix: false]
|
||||
- gocritic # Provides diagnostics that check for bugs, performance and style issues. [fast: false, auto-fix: false]
|
||||
#- gocyclo # Computes and checks the cyclomatic complexity of functions [fast: true, auto-fix: false]
|
||||
#- godot # Check if comments end in a period [fast: true, auto-fix: true]
|
||||
#- godox # Tool for detection of FIXME, TODO and other comment keywords [fast: true, auto-fix: false]
|
||||
- goerr113 # Golang linter to check the errors handling expressions [fast: false, auto-fix: false]
|
||||
- gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification [fast: true, auto-fix: true]
|
||||
#- gofumpt # Gofumpt checks whether code was gofumpt-ed. [fast: true, auto-fix: true]
|
||||
- goheader # Checks is file header matches to pattern [fast: true, auto-fix: false]
|
||||
- goimports # In addition to fixing imports, goimports also formats your code in the same style as gofmt. [fast: true, auto-fix: true]
|
||||
#- gomnd # An analyzer to detect magic numbers. [fast: true, auto-fix: false]
|
||||
#- gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod. [fast: true, auto-fix: false]
|
||||
- gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations. [fast: true, auto-fix: false]
|
||||
- goprintffuncname # Checks that printf-like functions are named with `f` at the end [fast: true, auto-fix: false]
|
||||
- gosec # (gas): Inspects source code for security problems [fast: false, auto-fix: false]
|
||||
- grouper # An analyzer to analyze expression groups. [fast: true, auto-fix: false]
|
||||
- importas # Enforces consistent import aliases [fast: false, auto-fix: false]
|
||||
#- ireturn # Accept Interfaces, Return Concrete Types [fast: false, auto-fix: false]
|
||||
#- lll # Reports long lines [fast: true, auto-fix: false]
|
||||
- maintidx # maintidx measures the maintainability index of each function. [fast: true, auto-fix: false]
|
||||
- makezero # Finds slice declarations with non-zero initial length [fast: false, auto-fix: false]
|
||||
- misspell # Finds commonly misspelled English words in comments [fast: true, auto-fix: true]
|
||||
- nakedret # Finds naked returns in functions greater than a specified function length [fast: true, auto-fix: false]
|
||||
#- nestif # Reports deeply nested if statements [fast: true, auto-fix: false]
|
||||
- nilerr # Finds the code that returns nil even if it checks that the error is not nil. [fast: false, auto-fix: false]
|
||||
- nilnil # Checks that there is no simultaneous return of `nil` error and an invalid value. [fast: false, auto-fix: false]
|
||||
#- nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity [fast: true, auto-fix: false]
|
||||
- noctx # noctx finds sending http request without context.Context [fast: false, auto-fix: false]
|
||||
- nolintlint # Reports ill-formed or insufficient nolint directives [fast: true, auto-fix: false]
|
||||
- nonamedreturns # Reports all named returns [fast: false, auto-fix: false]
|
||||
- nosnakecase # nosnakecase is a linter that detects snake case of variable naming and function name. [fast: true, auto-fix: false]
|
||||
- nosprintfhostport # Checks for misuse of Sprintf to construct a host with port in a URL. [fast: true, auto-fix: false]
|
||||
#- paralleltest # paralleltest detects missing usage of t.Parallel() method in your Go test [fast: false, auto-fix: false]
|
||||
- prealloc # Finds slice declarations that could potentially be pre-allocated [fast: true, auto-fix: false]
|
||||
- predeclared # find code that shadows one of Go's predeclared identifiers [fast: true, auto-fix: false]
|
||||
- promlinter # Check Prometheus metrics naming via promlint [fast: true, auto-fix: false]
|
||||
- revive # Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint. [fast: false, auto-fix: false]
|
||||
- rowserrcheck # checks whether Err of rows is checked successfully [fast: false, auto-fix: false]
|
||||
- sqlclosecheck # Checks that sql.Rows and sql.Stmt are closed. [fast: false, auto-fix: false]
|
||||
- structcheck # Finds unused struct fields [fast: false, auto-fix: false]
|
||||
- stylecheck # Stylecheck is a replacement for golint [fast: false, auto-fix: false]
|
||||
- tagliatelle # Checks the struct tags. [fast: true, auto-fix: false]
|
||||
- tenv # tenv is analyzer that detects using os.Setenv instead of t.Setenv since Go1.17 [fast: false, auto-fix: false]
|
||||
- testpackage # linter that makes you use a separate _test package [fast: true, auto-fix: false]
|
||||
- thelper # thelper detects golang test helpers without t.Helper() call and checks the consistency of test helpers [fast: false, auto-fix: false]
|
||||
- tparallel # tparallel detects inappropriate usage of t.Parallel() method in your Go test codes [fast: false, auto-fix: false]
|
||||
- unconvert # Remove unnecessary type conversions [fast: false, auto-fix: false]
|
||||
- unparam # Reports unused function parameters [fast: false, auto-fix: false]
|
||||
- usestdlibvars # A linter that detect the possibility to use variables/constants from the Go standard library. [fast: true, auto-fix: false]
|
||||
#- varnamelen # checks that the length of a variable's name matches its scope [fast: false, auto-fix: false]
|
||||
- wastedassign # wastedassign finds wasted assignment statements. [fast: false, auto-fix: false]
|
||||
- whitespace # Tool for detection of leading and trailing whitespace [fast: true, auto-fix: true]
|
||||
#- wrapcheck # Checks that errors returned from external packages are wrapped [fast: false, auto-fix: false]
|
||||
#- wsl # Whitespace Linter - Forces you to use empty lines! [fast: true, auto-fix: false]
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@ type (
|
||||
Bool bool `yaml:"bool"`
|
||||
String string `yaml:"string"`
|
||||
CamelCaseString string `yaml:"camelCaseString"`
|
||||
SnakeCaseString string `yaml:"snake_case_string"`
|
||||
SnakeCaseString string `yaml:"snake_case_string"` //nolint:tagliatelle
|
||||
}
|
||||
Config struct {
|
||||
Int int `yaml:"int"`
|
||||
|
||||
@ -18,12 +18,12 @@ func main() {
|
||||
err2 := keelerrors.NewWrappedError(err1, ErrTwo)
|
||||
|
||||
if errors.Is(err1, ErrOne) {
|
||||
fmt.Println("err1 = ErrOne")
|
||||
fmt.Println("err1 = ErrOne") //nolint:forbidigo
|
||||
}
|
||||
if errors.Is(err2, ErrTwo) {
|
||||
fmt.Println("err2 = ErrTwo")
|
||||
fmt.Println("err2 = ErrTwo") //nolint:forbidigo
|
||||
}
|
||||
if errors.Is(err2, ErrOne) {
|
||||
fmt.Println("err2 = ErrOne")
|
||||
fmt.Println("err2 = ErrOne") //nolint:forbidigo
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,9 +50,10 @@ func main() {
|
||||
svs := http.NewServeMux()
|
||||
svs.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
// retrieve from context
|
||||
claims := r.Context().Value(contextKey).(*CustomClaims)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte(claims.Name))
|
||||
if claims, ok := r.Context().Value(contextKey).(*CustomClaims); ok {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte(claims.Name))
|
||||
}
|
||||
})
|
||||
|
||||
svr.AddService(
|
||||
|
||||
@ -48,9 +48,10 @@ func main() {
|
||||
svs := http.NewServeMux()
|
||||
svs.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
// retrieve from context
|
||||
claims := r.Context().Value(contextKey).(*CustomClaims)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte(claims.Name))
|
||||
if claims, ok := r.Context().Value(contextKey).(*CustomClaims); ok {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte(claims.Name))
|
||||
}
|
||||
})
|
||||
svs.HandleFunc("/token", func(w http.ResponseWriter, r *http.Request) {
|
||||
if token, err := jwtInst.GetSignedToken(CustomClaims{
|
||||
|
||||
@ -30,7 +30,7 @@ func (r *DummyRepository) Get(ctx context.Context, id string, opts ...*options.F
|
||||
}
|
||||
|
||||
// Upsert entity
|
||||
func (r *DummyRepository) Upsert(ctx context.Context, entity *store.Dummy) (err error) {
|
||||
func (r *DummyRepository) Upsert(ctx context.Context, entity *store.Dummy) error {
|
||||
if err := r.collection.Upsert(ctx, entity.GetID(), entity); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import (
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"go.mongodb.org/mongo-driver/bson/bsoncodec"
|
||||
"go.mongodb.org/mongo-driver/bson/bsonrw"
|
||||
"go.mongodb.org/mongo-driver/bson/bsontype"
|
||||
@ -20,7 +21,10 @@ func (d *DateTimeCodec) EncodeValue(_ bsoncodec.EncodeContext, vw bsonrw.ValueWr
|
||||
if !val.IsValid() || val.Type() != TDateTime {
|
||||
return bsoncodec.ValueEncoderError{Name: "DateTimeEncodeValue", Types: []reflect.Type{TDateTime}, Received: val}
|
||||
}
|
||||
td := val.Interface().(DateTime)
|
||||
td, ok := val.Interface().(DateTime)
|
||||
if !ok {
|
||||
return errors.New("failed to encode date time")
|
||||
}
|
||||
tt, err := td.Time()
|
||||
if err != nil {
|
||||
return bsoncodec.ValueEncoderError{Name: "DateTimeEncodeValue", Types: []reflect.Type{TDateTime}, Received: val}
|
||||
@ -34,7 +38,7 @@ func (d *DateTimeCodec) DecodeValue(_ bsoncodec.DecodeContext, vr bsonrw.ValueRe
|
||||
}
|
||||
|
||||
var dateTimeVal DateTime
|
||||
switch t := vr.Type(); t {
|
||||
switch t := vr.Type(); t { //nolint:exhaustive
|
||||
case bsontype.DateTime:
|
||||
dt, err := vr.ReadDateTime()
|
||||
if err != nil {
|
||||
@ -48,7 +52,7 @@ func (d *DateTimeCodec) DecodeValue(_ bsoncodec.DecodeContext, vr bsonrw.ValueRe
|
||||
}
|
||||
dateTimeVal = DateTime(decimalStr)
|
||||
default:
|
||||
return fmt.Errorf("cannot decode %v into a DateTime", t)
|
||||
return fmt.Errorf("cannot decode %v into a DateTime", t) //nolint:goerr113
|
||||
}
|
||||
|
||||
val.Set(reflect.ValueOf(dateTimeVal))
|
||||
|
||||
@ -19,7 +19,7 @@ var (
|
||||
// Entity type
|
||||
type Entity struct {
|
||||
ID string `json:"id" bson:"id" yaml:"id"`
|
||||
BsonID primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty" yaml:"_id,omitempty"`
|
||||
BsonID primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty" yaml:"_id,omitempty"` //nolint:tagliatelle
|
||||
}
|
||||
|
||||
func NewEntity(id string) Entity {
|
||||
|
||||
@ -23,11 +23,11 @@ func main() {
|
||||
|
||||
// create config reader
|
||||
fooFn := config.GetString(c, "foo", "default_foo")
|
||||
fmt.Println("initial foo:", fooFn())
|
||||
fmt.Println("initial foo:", fooFn()) //nolint:forbidigo
|
||||
|
||||
// watch changes
|
||||
config.WatchString(svr.CancelContext(), fooFn, func(s string) {
|
||||
fmt.Println("change foo:", fooFn())
|
||||
fmt.Println("change foo:", fooFn()) //nolint:forbidigo
|
||||
})
|
||||
|
||||
ch := make(chan string)
|
||||
@ -36,7 +36,7 @@ func main() {
|
||||
go func(ch chan string) {
|
||||
for {
|
||||
value := <-ch
|
||||
fmt.Println("channel foo:", value)
|
||||
fmt.Println("channel foo:", value) //nolint:forbidigo
|
||||
}
|
||||
}(ch)
|
||||
|
||||
@ -44,7 +44,7 @@ func main() {
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", http.HandlerFunc(
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Println("current foo:", fooFn())
|
||||
fmt.Println("current foo:", fooFn()) //nolint:forbidigo
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
@ -17,9 +17,9 @@ func client() {
|
||||
|
||||
var err error
|
||||
|
||||
_, err = client.Get("http://localhost:8080") // nolint
|
||||
_, err = client.Get("http://localhost:8080") //nolint:all
|
||||
log.Must(l, err, "failed to retrieve response")
|
||||
|
||||
_, err = client.Get("http://localhost:8080/404") // nolint
|
||||
_, err = client.Get("http://localhost:8080/404") //nolint:all
|
||||
log.Must(l, err, "failed to retrieve response")
|
||||
}
|
||||
|
||||
@ -20,14 +20,17 @@ func main() {
|
||||
httpClient := keelhttp.NewHTTPClient(
|
||||
keelhttp.HTTPClientWithRoundTripware(l,
|
||||
roundtripware.RequestID(),
|
||||
roundtripware.SessionID(),
|
||||
roundtripware.TrackingID(),
|
||||
),
|
||||
)
|
||||
|
||||
// create demo service
|
||||
svs := http.NewServeMux()
|
||||
|
||||
// send internal http request
|
||||
svs.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
l := log.WithHTTPRequest(l, r)
|
||||
// send internal http request
|
||||
// send request
|
||||
if req, err := http.NewRequestWithContext(r.Context(), http.MethodGet, "http://localhost:8080/internal", nil); err != nil {
|
||||
httputils.InternalServerError(l, w, r, err)
|
||||
return
|
||||
@ -37,19 +40,22 @@ func main() {
|
||||
} else {
|
||||
defer resp.Body.Close()
|
||||
w.WriteHeader(http.StatusOK)
|
||||
log.WithHTTPRequest(l, r).Info("handled request")
|
||||
_, _ = w.Write([]byte(r.Header.Get(keelhttp.HeaderXRequestID) + " - " + resp.Header.Get(keelhttp.HeaderXRequestID)))
|
||||
log.WithHTTPRequestOut(l, req).Info("sent internal request")
|
||||
}
|
||||
})
|
||||
// handle internal http request
|
||||
svs.HandleFunc("/internal", func(w http.ResponseWriter, r *http.Request) {
|
||||
l := log.WithHTTPRequest(l, r)
|
||||
l.Info("handled internal request")
|
||||
log.WithHTTPRequest(l, r).Info("handled internal request")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
||||
middleware.RequestID(),
|
||||
middleware.SessionID(),
|
||||
middleware.TrackingID(),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@ -85,7 +85,7 @@ func main() {
|
||||
log.Must(l, err, "failed to create up down meter")
|
||||
|
||||
svs.HandleFunc("/histogram", func(w http.ResponseWriter, r *http.Request) {
|
||||
histogram.Record(r.Context(), int64(rand.Int()), attribute.String("key", "value")) // nolint:gosec
|
||||
histogram.Record(r.Context(), int64(rand.Int()), attribute.String("key", "value"))
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte("OK!"))
|
||||
})
|
||||
|
||||
@ -84,7 +84,7 @@ func NewClient(ctx context.Context, endpoint string, opts ...ClientOption) (clie
|
||||
}
|
||||
} else if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to retrieve temporal namespace info")
|
||||
} else if nsInfo := ns.GetNamespaceInfo(); nsInfo.State != enums.NAMESPACE_STATE_REGISTERED {
|
||||
} else if nsInfo := ns.GetNamespaceInfo(); nsInfo.State != enums.NAMESPACE_STATE_REGISTERED { //nolint:nosnakecase
|
||||
return nil, errors.New("Could not register namespace due to existing state: " + nsInfo.State.String())
|
||||
} else if err := nsc.Update(ctx, &workflowservice.UpdateNamespaceRequest{
|
||||
Namespace: o.RegisterNamespace.Namespace,
|
||||
|
||||
@ -17,7 +17,6 @@ type metricsHandler struct {
|
||||
attr []attribute.KeyValue
|
||||
}
|
||||
|
||||
// scope, _ := tally.NewRootScope(opts, time.Second)
|
||||
func NewMetricsHandler(meter metric.Meter) client.MetricsHandler {
|
||||
return metricsHandler{meter: meter}
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ import (
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/golang-jwt/jwt"
|
||||
@ -38,7 +38,7 @@ func NewKeyFromFilenames(publicKeyPemFilename, privateKeyPemFilename string) (Ke
|
||||
|
||||
// load private key
|
||||
if privateKeyPemFilename != "" {
|
||||
if bytes, err := ioutil.ReadFile(privateKeyPemFilename); err != nil {
|
||||
if bytes, err := os.ReadFile(privateKeyPemFilename); err != nil {
|
||||
return Key{}, errors.Wrap(err, "failed to read private key: "+privateKeyPemFilename)
|
||||
} else if key, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(strings.ReplaceAll(string(bytes), `\n`, "\n"))); err != nil {
|
||||
return Key{}, errors.Wrap(err, "failed to parse private key: "+privateKeyPemFilename)
|
||||
@ -48,7 +48,7 @@ func NewKeyFromFilenames(publicKeyPemFilename, privateKeyPemFilename string) (Ke
|
||||
}
|
||||
|
||||
// load public key
|
||||
if v, err := ioutil.ReadFile(publicKeyPemFilename); err != nil {
|
||||
if v, err := os.ReadFile(publicKeyPemFilename); err != nil {
|
||||
return Key{}, errors.Wrap(err, "failed to read public key: "+publicKeyPemFilename)
|
||||
} else if key, err := jwt.ParseRSAPublicKeyFromPEM([]byte(strings.ReplaceAll(string(v), `\n`, "\n"))); err != nil {
|
||||
return Key{}, errors.Wrap(err, "failed to parse public key: "+publicKeyPemFilename)
|
||||
|
||||
@ -40,11 +40,14 @@ const (
|
||||
// HTTPFlavorKey represents the Kind of HTTP protocol used.
|
||||
HTTPFlavorKey = "http_flavor"
|
||||
|
||||
// HTTPRequestIDKey represents the HTTP request id if known (e.g from X-Request-ID).
|
||||
// HTTPRequestIDKey represents the HTTP request id if known (e.g. from X-Request-ID).
|
||||
HTTPRequestIDKey = "http_request_id"
|
||||
|
||||
// HTTPSessionIDKey represents the HTTP session id if known (e.g from X-Session-ID).
|
||||
// HTTPSessionIDKey represents the HTTP session id if known (e.g. from X-Session-ID).
|
||||
HTTPSessionIDKey = "http_session_id"
|
||||
|
||||
// HTTPTrackingIDKey represents the HTTP tracking id if known (e.g. from X-Tracking-ID).
|
||||
HTTPTrackingIDKey = "http_tracking_id"
|
||||
)
|
||||
|
||||
func FHTTPServerName(id string) zap.Field {
|
||||
@ -59,6 +62,10 @@ func FHTTPSessionID(id string) zap.Field {
|
||||
return zap.String(HTTPSessionIDKey, id)
|
||||
}
|
||||
|
||||
func FHTTPTrackingID(id string) zap.Field {
|
||||
return zap.String(HTTPTrackingIDKey, id)
|
||||
}
|
||||
|
||||
func FHTTPRequestContentLength(bytes int64) zap.Field {
|
||||
return zap.Int64(HTTPRequestContentLengthKey, bytes)
|
||||
}
|
||||
|
||||
24
log/with.go
24
log/with.go
@ -46,7 +46,7 @@ func WithHTTPRequest(l *zap.Logger, r *http.Request) *zap.Logger {
|
||||
FHTTPUserAgent(r.UserAgent()),
|
||||
FHTTPTarget(r.RequestURI),
|
||||
}
|
||||
|
||||
// host
|
||||
if value := r.Header.Get("X-Forwarded-Host"); value != "" {
|
||||
fields = append(fields, FHTTPHost(value))
|
||||
} else if !r.URL.IsAbs() {
|
||||
@ -54,21 +54,31 @@ func WithHTTPRequest(l *zap.Logger, r *http.Request) *zap.Logger {
|
||||
} else {
|
||||
fields = append(fields, FHTTPHost(r.URL.Host))
|
||||
}
|
||||
// request id
|
||||
if id := r.Header.Get("X-Request-ID"); id != "" {
|
||||
fields = append(fields, FHTTPRequestID(id))
|
||||
} else if id, ok := keelhttpcontext.GetRequestID(r.Context()); ok && id != "" {
|
||||
fields = append(fields, FHTTPRequestID(id))
|
||||
}
|
||||
// session id
|
||||
if id := r.Header.Get("X-Session-ID"); id != "" {
|
||||
fields = append(fields, FHTTPSessionID(id))
|
||||
} else if id, ok := keelhttpcontext.GetSessionID(r.Context()); ok && id != "" {
|
||||
fields = append(fields, FHTTPSessionID(id))
|
||||
}
|
||||
// tracking id
|
||||
if id := r.Header.Get("X-Tracking-ID"); id != "" {
|
||||
fields = append(fields, FHTTPTrackingID(id))
|
||||
} else if id, ok := keelhttpcontext.GetTrackingID(r.Context()); ok && id != "" {
|
||||
fields = append(fields, FHTTPTrackingID(id))
|
||||
}
|
||||
// schema
|
||||
if r.TLS != nil {
|
||||
fields = append(fields, FHTTPScheme("https"))
|
||||
} else {
|
||||
fields = append(fields, FHTTPScheme("http"))
|
||||
}
|
||||
// flavor
|
||||
if r.ProtoMajor == 1 {
|
||||
fields = append(fields, FHTTPFlavor(fmt.Sprintf("1.%d", r.ProtoMinor)))
|
||||
} else if r.ProtoMajor == 2 {
|
||||
@ -106,25 +116,35 @@ func WithHTTPRequestOut(l *zap.Logger, r *http.Request) *zap.Logger {
|
||||
FHTTPMethod(r.Method),
|
||||
FHTTPTarget(r.URL.Path),
|
||||
}
|
||||
|
||||
// host
|
||||
if r.URL.Host != "" {
|
||||
fields = append(fields, FHTTPHost(r.URL.Host))
|
||||
}
|
||||
// request id
|
||||
if id := r.Header.Get("X-Request-ID"); id != "" {
|
||||
fields = append(fields, FHTTPRequestID(id))
|
||||
} else if id, ok := keelhttpcontext.GetRequestID(r.Context()); ok && id != "" {
|
||||
fields = append(fields, FHTTPRequestID(id))
|
||||
}
|
||||
// session id
|
||||
if id := r.Header.Get("X-Session-ID"); id != "" {
|
||||
fields = append(fields, FHTTPSessionID(id))
|
||||
} else if id, ok := keelhttpcontext.GetSessionID(r.Context()); ok && id != "" {
|
||||
fields = append(fields, FHTTPSessionID(id))
|
||||
}
|
||||
// tracking id
|
||||
if id := r.Header.Get("X-Tracking-ID"); id != "" {
|
||||
fields = append(fields, FHTTPTrackingID(id))
|
||||
} else if id, ok := keelhttpcontext.GetTrackingID(r.Context()); ok && id != "" {
|
||||
fields = append(fields, FHTTPTrackingID(id))
|
||||
}
|
||||
// schema
|
||||
if r.TLS != nil {
|
||||
fields = append(fields, FHTTPScheme("https"))
|
||||
} else {
|
||||
fields = append(fields, FHTTPScheme("http"))
|
||||
}
|
||||
// flavor
|
||||
if r.ProtoMajor == 1 {
|
||||
fields = append(fields, FHTTPFlavor(fmt.Sprintf("1.%d", r.ProtoMinor)))
|
||||
} else if r.ProtoMajor == 2 {
|
||||
|
||||
@ -5,9 +5,9 @@ type Error string
|
||||
|
||||
// Common errors
|
||||
const (
|
||||
ErrorNotFound Error = "notFound"
|
||||
ErrorForbidden Error = "forbidden"
|
||||
ErrorPermissionDenied Error = "permissionDenied"
|
||||
ErrorNotFound Error = "notFound" //nolint:errname
|
||||
ErrorForbidden Error = "forbidden" //nolint:errname
|
||||
ErrorPermissionDenied Error = "permissionDenied" //nolint:errname
|
||||
)
|
||||
|
||||
// NewError returns a pointer error
|
||||
@ -19,7 +19,7 @@ func NewError(e Error) *Error {
|
||||
func (e *Error) Is(err error) bool {
|
||||
if e == nil || err == nil {
|
||||
return false
|
||||
} else if v, ok := err.(*Error); ok && v != nil {
|
||||
} else if v, ok := err.(*Error); ok && v != nil { //nolint:errorlint
|
||||
return e.Error() == v.Error()
|
||||
}
|
||||
return false
|
||||
|
||||
@ -14,6 +14,6 @@ func GetSessionID(ctx context.Context) (string, bool) {
|
||||
}
|
||||
}
|
||||
|
||||
func SetSessionID(ctx context.Context, requestID string) context.Context {
|
||||
return context.WithValue(ctx, ContextKeySessionID, requestID)
|
||||
func SetSessionID(ctx context.Context, sessionID string) context.Context {
|
||||
return context.WithValue(ctx, ContextKeySessionID, sessionID)
|
||||
}
|
||||
|
||||
@ -61,7 +61,7 @@ const (
|
||||
HeaderXFrameOptions = "X-Frame-Options"
|
||||
HeaderContentSecurityPolicy = "Content-Security-Policy"
|
||||
HeaderContentSecurityPolicyReportOnly = "Content-Security-Policy-Report-Only"
|
||||
HeaderXCSRFToken = "X-CSRF-Token" //nolint:gosec
|
||||
HeaderXCSRFToken = "X-CSRF-Token"
|
||||
HeaderReferrerPolicy = "Referrer-Policy"
|
||||
|
||||
// Telementry
|
||||
|
||||
@ -51,7 +51,7 @@ func RecoverWithOptions(opts RecoverOptions) Middleware {
|
||||
if e := recover(); e != nil {
|
||||
err, ok := e.(error)
|
||||
if !ok {
|
||||
err = fmt.Errorf("%v", e)
|
||||
err = fmt.Errorf("%v", e) //nolint:goerr113
|
||||
}
|
||||
ll := log.WithError(l, err)
|
||||
if !opts.DisablePrintStack {
|
||||
|
||||
@ -44,20 +44,20 @@ func dumpRequest(req *http.Request) {
|
||||
if req.Header != nil && req.Header.Get("Content-Type") != "" {
|
||||
var body string
|
||||
if req.Body, body = readBodyPretty(req.Header.Get("Content-Type"), req.Body); body != "" {
|
||||
fmt.Printf("Request %s:\n%s\n", req.URL, body)
|
||||
fmt.Printf("Request %s:\n%s\n", req.URL, body) //nolint:forbidigo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func dumpResponse(req *http.Request, resp *http.Response) {
|
||||
if resp == nil {
|
||||
fmt.Println("Response is nil")
|
||||
fmt.Println("Response is nil") //nolint:forbidigo
|
||||
return
|
||||
}
|
||||
if resp.Header != nil && resp.Header.Get("Content-Type") != "" {
|
||||
var body string
|
||||
if resp.Body, body = readBodyPretty(resp.Header.Get("Content-Type"), resp.Body); body != "" {
|
||||
fmt.Printf("Response %s:\n%s\n", req.URL, body)
|
||||
fmt.Printf("Response %s:\n%s\n", req.URL, body) //nolint:forbidigo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"github.com/tinylib/msgp/msgp"
|
||||
@ -41,5 +40,5 @@ func readBodyPretty(contentType string, original io.ReadCloser) (io.ReadCloser,
|
||||
}
|
||||
|
||||
// return copy of the original
|
||||
return ioutil.NopCloser(strings.NewReader(bs.String())), body
|
||||
return io.NopCloser(strings.NewReader(bs.String())), body
|
||||
}
|
||||
|
||||
@ -21,17 +21,17 @@ func Metric(meter metric.Meter, name, description string) RoundTripware {
|
||||
}
|
||||
|
||||
return func(l *zap.Logger, next Handler) Handler {
|
||||
return func(req *http.Request) (*http.Response, error) {
|
||||
ctx, labeler := LabelerFromContext(req.Context())
|
||||
return func(r *http.Request) (*http.Response, error) {
|
||||
ctx, labeler := LabelerFromContext(r.Context())
|
||||
|
||||
start := time.Now()
|
||||
resp, err := next(req.WithContext(ctx))
|
||||
resp, err := next(r.WithContext(ctx))
|
||||
duration := time.Since(start)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
attributes := append(labeler.Get(), attribute.String("method", req.Method))
|
||||
attributes := append(labeler.Get(), attribute.String("method", r.Method))
|
||||
|
||||
if resp != nil {
|
||||
attributes = append(labeler.Get(), attribute.Int("status_code", resp.StatusCode))
|
||||
|
||||
@ -44,12 +44,12 @@ func Recover(opts ...RecoverOption) RoundTripware {
|
||||
// RecoverWithOptions returns a RoundTripper which catches any panics
|
||||
func RecoverWithOptions(opts RecoverOptions) RoundTripware {
|
||||
return func(l *zap.Logger, next Handler) Handler {
|
||||
return func(req *http.Request) (*http.Response, error) {
|
||||
return func(r *http.Request) (*http.Response, error) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
err, ok := e.(error)
|
||||
if !ok {
|
||||
err = fmt.Errorf("%v", e)
|
||||
err = fmt.Errorf("%v", e) //nolint:goerr113
|
||||
}
|
||||
ll := log.WithError(l, err)
|
||||
if !opts.DisablePrintStack {
|
||||
@ -58,7 +58,7 @@ func RecoverWithOptions(opts RecoverOptions) RoundTripware {
|
||||
ll.Error("recovering from panic")
|
||||
}
|
||||
}()
|
||||
return next(req)
|
||||
return next(r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,6 +28,6 @@ func NewRoundTripper(l *zap.Logger, parent http.RoundTripper, roundTripwares ...
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *RoundTripper) RoundTrip(req *http.Request) (resp *http.Response, err error) {
|
||||
func (rt *RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
return rt.handler(req)
|
||||
}
|
||||
|
||||
51
net/http/roundtripware/sessionid.go
Normal file
51
net/http/roundtripware/sessionid.go
Normal file
@ -0,0 +1,51 @@
|
||||
package roundtripware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
keelhttpcontext "github.com/foomo/keel/net/http/context"
|
||||
)
|
||||
|
||||
type (
|
||||
SessionIDOptions struct {
|
||||
Header string
|
||||
}
|
||||
SessionIDOption func(*SessionIDOptions)
|
||||
SessionIDGenerator func() string
|
||||
)
|
||||
|
||||
// GetDefaultSessionIDOptions returns the default options
|
||||
func GetDefaultSessionIDOptions() SessionIDOptions {
|
||||
return SessionIDOptions{
|
||||
Header: "X-Session-ID",
|
||||
}
|
||||
}
|
||||
|
||||
// SessionIDWithHeader middleware option
|
||||
func SessionIDWithHeader(v string) SessionIDOption {
|
||||
return func(o *SessionIDOptions) {
|
||||
o.Header = v
|
||||
}
|
||||
}
|
||||
|
||||
// SessionID returns a RoundTripper which prints out the request & response object
|
||||
func SessionID(opts ...SessionIDOption) RoundTripware {
|
||||
o := GetDefaultSessionIDOptions()
|
||||
for _, opt := range opts {
|
||||
if opt != nil {
|
||||
opt(&o)
|
||||
}
|
||||
}
|
||||
return func(l *zap.Logger, next Handler) Handler {
|
||||
return func(r *http.Request) (*http.Response, error) {
|
||||
if value := r.Header.Get(o.Header); value == "" {
|
||||
if value, ok := keelhttpcontext.GetSessionID(r.Context()); ok && value != "" {
|
||||
r.Header.Set(o.Header, value)
|
||||
}
|
||||
}
|
||||
return next(r)
|
||||
}
|
||||
}
|
||||
}
|
||||
51
net/http/roundtripware/trackingid.go
Normal file
51
net/http/roundtripware/trackingid.go
Normal file
@ -0,0 +1,51 @@
|
||||
package roundtripware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
keelhttpcontext "github.com/foomo/keel/net/http/context"
|
||||
)
|
||||
|
||||
type (
|
||||
TrackingIDOptions struct {
|
||||
Header string
|
||||
}
|
||||
TrackingIDOption func(*TrackingIDOptions)
|
||||
TrackingIDGenerator func() string
|
||||
)
|
||||
|
||||
// GetDefaultTrackingIDOptions returns the default options
|
||||
func GetDefaultTrackingIDOptions() TrackingIDOptions {
|
||||
return TrackingIDOptions{
|
||||
Header: "X-Tracking-ID",
|
||||
}
|
||||
}
|
||||
|
||||
// TrackingIDWithHeader middleware option
|
||||
func TrackingIDWithHeader(v string) TrackingIDOption {
|
||||
return func(o *TrackingIDOptions) {
|
||||
o.Header = v
|
||||
}
|
||||
}
|
||||
|
||||
// TrackingID returns a RoundTripper which prints out the request & response object
|
||||
func TrackingID(opts ...TrackingIDOption) RoundTripware {
|
||||
o := GetDefaultTrackingIDOptions()
|
||||
for _, opt := range opts {
|
||||
if opt != nil {
|
||||
opt(&o)
|
||||
}
|
||||
}
|
||||
return func(l *zap.Logger, next Handler) Handler {
|
||||
return func(r *http.Request) (*http.Response, error) {
|
||||
if value := r.Header.Get(o.Header); value == "" {
|
||||
if value, ok := keelhttpcontext.GetTrackingID(r.Context()); ok && value != "" {
|
||||
r.Header.Set(o.Header, value)
|
||||
}
|
||||
}
|
||||
return next(r)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3,7 +3,7 @@ package keel_test
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"syscall"
|
||||
@ -209,7 +209,7 @@ func (s *KeelTestSuite) httpGet(url string) (int, string, error) {
|
||||
return 0, "", err
|
||||
} else if resp, err := http.DefaultClient.Do(req); err != nil {
|
||||
return 0, "", err
|
||||
} else if body, err := ioutil.ReadAll(resp.Body); err != nil {
|
||||
} else if body, err := io.ReadAll(resp.Body); err != nil {
|
||||
return 0, "", err
|
||||
} else if err := resp.Body.Close(); err != nil {
|
||||
return 0, "", err
|
||||
@ -224,7 +224,7 @@ func (s *KeelTestSuite) httpPut(url, data string) (int, string, error) {
|
||||
return 0, "", err
|
||||
} else if resp, err := http.DefaultClient.Do(req); err != nil {
|
||||
return 0, "", err
|
||||
} else if body, err := ioutil.ReadAll(resp.Body); err != nil {
|
||||
} else if body, err := io.ReadAll(resp.Body); err != nil {
|
||||
return 0, "", err
|
||||
} else if err := resp.Body.Close(); err != nil {
|
||||
return 0, "", err
|
||||
|
||||
@ -6,6 +6,7 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/foomo/keel/log"
|
||||
@ -64,7 +65,7 @@ func (s *ServiceHTTP) Start(ctx context.Context) error {
|
||||
s.running = false
|
||||
})
|
||||
s.running = true
|
||||
if err := s.server.ListenAndServe(); err != http.ErrServerClosed {
|
||||
if err := s.server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
|
||||
log.WithError(s.l, err).Error("service error")
|
||||
return err
|
||||
}
|
||||
|
||||
@ -16,6 +16,14 @@ const (
|
||||
DefaultServiceHTTPHealthzPath = "/healthz"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrUnhandledHealthzProbe = errors.New("unhandled healthz probe")
|
||||
ErrProbeFailed = errors.New("probe failed")
|
||||
ErrLivenessProbeFailed = errors.New("liveness probe failed")
|
||||
ErrReadinessProbeFailed = errors.New("readiness probe failed")
|
||||
ErrStartupProbeFailed = errors.New("startup probe failed")
|
||||
)
|
||||
|
||||
func NewServiceHTTPHealthz(l *zap.Logger, name, addr, path string, probes map[HealthzType][]interface{}) *ServiceHTTP {
|
||||
handler := http.NewServeMux()
|
||||
|
||||
@ -41,7 +49,7 @@ func NewServiceHTTPHealthz(l *zap.Logger, name, addr, path string, probes map[He
|
||||
case ErrorPingerWithContext:
|
||||
return true, h.Ping(ctx)
|
||||
default:
|
||||
return false, errors.New("unhandled healthz probe")
|
||||
return false, ErrUnhandledHealthzProbe
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,7 +63,7 @@ func NewServiceHTTPHealthz(l *zap.Logger, name, addr, path string, probes map[He
|
||||
unavailable(l, w, r, err)
|
||||
return
|
||||
} else if !ok {
|
||||
unavailable(l, w, r, errors.New("probe failed"))
|
||||
unavailable(l, w, r, ErrProbeFailed)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -77,7 +85,7 @@ func NewServiceHTTPHealthz(l *zap.Logger, name, addr, path string, probes map[He
|
||||
unavailable(l, w, r, err)
|
||||
return
|
||||
} else if !ok {
|
||||
unavailable(l, w, r, errors.New("liveness probe failed"))
|
||||
unavailable(l, w, r, ErrLivenessProbeFailed)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -98,7 +106,7 @@ func NewServiceHTTPHealthz(l *zap.Logger, name, addr, path string, probes map[He
|
||||
unavailable(l, w, r, err)
|
||||
return
|
||||
} else if !ok {
|
||||
unavailable(l, w, r, errors.New("readiness probe failed"))
|
||||
unavailable(l, w, r, ErrReadinessProbeFailed)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -119,7 +127,7 @@ func NewServiceHTTPHealthz(l *zap.Logger, name, addr, path string, probes map[He
|
||||
unavailable(l, w, r, err)
|
||||
return
|
||||
} else if !ok {
|
||||
unavailable(l, w, r, errors.New("startup probe failed"))
|
||||
unavailable(l, w, r, ErrStartupProbeFailed)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
)
|
||||
@ -75,7 +75,7 @@ func (c *HTTPClient) Post(ctx context.Context, path string, data interface{}) ([
|
||||
|
||||
func (c *HTTPClient) readBody(resp *http.Response) ([]byte, error) {
|
||||
defer resp.Body.Close()
|
||||
if body, err := ioutil.ReadAll(resp.Body); err != nil {
|
||||
if body, err := io.ReadAll(resp.Body); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return body, nil
|
||||
|
||||
@ -89,9 +89,9 @@ func newTestingWriter(t zaptest.TestingT) *testingWriter {
|
||||
return &testingWriter{t: t}
|
||||
}
|
||||
|
||||
func (w *testingWriter) Write(p []byte) (n int, err error) {
|
||||
func (w *testingWriter) Write(p []byte) (int, error) {
|
||||
if w.t == nil {
|
||||
return fmt.Printf("%s", p)
|
||||
return fmt.Printf("%s", p) //nolint:forbidigo
|
||||
} else {
|
||||
// Note: t.Log is safe for concurrent use.
|
||||
// Strip trailing newline because t.Log always adds one.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user