feat: fix lint errors

This commit is contained in:
Kevin Franklin Kim 2022-08-12 15:58:56 +02:00
parent 03be454c91
commit 596f43e841
33 changed files with 350 additions and 95 deletions

View File

@ -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]

View File

@ -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"`

View File

@ -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
}
}

View File

@ -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(

View File

@ -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{

View File

@ -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
}

View File

@ -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))

View File

@ -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 {

View File

@ -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
}),
),
)

View File

@ -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")
}

View File

@ -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(),
),
)

View File

@ -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!"))
})

View File

@ -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,

View File

@ -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}
}

View File

@ -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)

View File

@ -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)
}

View File

@ -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 {

View File

@ -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

View File

@ -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)
}

View File

@ -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

View File

@ -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 {

View File

@ -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
}
}
}

View File

@ -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
}

View File

@ -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))

View File

@ -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)
}
}
}

View File

@ -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)
}

View 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)
}
}
}

View 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)
}
}
}

View File

@ -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

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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

View File

@ -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.