From b81bad871165705bb51136a98aebc186097e5c4a Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Fri, 24 Nov 2023 22:17:35 +0100 Subject: [PATCH] use Go standard errors Signed-off-by: Matthieu MOREL --- .golangci.yml | 7 +++- api/api.go | 2 +- api/v2/api.go | 5 +-- cli/silence_import.go | 9 ++--- cli/silence_query.go | 2 +- cli/silence_update.go | 2 +- cluster/advertise.go | 13 +++---- cluster/cluster.go | 20 +++++------ cluster/connection_pool.go | 4 +-- cluster/tls_connection.go | 15 ++++---- cluster/tls_transport.go | 20 +++++------ cmd/alertmanager/main.go | 10 +++--- config/config.go | 6 ++-- config/notifiers.go | 9 +++-- dispatch/dispatch.go | 3 +- go.mod | 1 - go.sum | 1 - matchers/parse/parse.go | 18 +++++----- nflog/nflog.go | 2 +- notify/email/email.go | 62 +++++++++++++++++----------------- notify/msteams/msteams_test.go | 5 +-- notify/notify.go | 22 +++++++----- notify/opsgenie/opsgenie.go | 5 ++- notify/pagerduty/pagerduty.go | 20 +++++------ notify/slack/slack.go | 9 +++-- notify/slack/slack_test.go | 5 +-- notify/sns/sns.go | 7 ++-- notify/util.go | 8 ++--- notify/victorops/victorops.go | 9 +++-- notify/wechat/wechat.go | 6 ++-- pkg/labels/parse.go | 11 +++--- silence/silence.go | 18 +++++----- test/cli/acceptance.go | 8 ++--- test/with_api_v2/acceptance.go | 6 ++-- types/types.go | 4 +-- 35 files changed, 184 insertions(+), 170 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 5df6c359..4a06a84e 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,8 +1,8 @@ run: - deadline: 5m skip-files: # Skip autogenerated files. - ^.*\.(pb|y)\.go$ + timeout: 5m output: sort-results: true @@ -10,12 +10,15 @@ output: linters: enable: - depguard + - errorlint - gofumpt - goimports - revive - misspell issues: + max-issues-per-linter: 0 + max-same-issues: 0 exclude-rules: - path: _test.go linters: @@ -32,6 +35,8 @@ linters-settings: desc: "Use github.com/stretchr/testify/require instead of github.com/stretchr/testify/assert" - pkg: github.com/go-kit/kit/log desc: "Use github.com/go-kit/log instead of github.com/go-kit/kit/log" + - pkg: github.com/pkg/errors + desc: "Use errors or fmt instead of github.com/pkg/errors" errcheck: exclude-functions: # Don't flag lines such as "io.Copy(io.Discard, resp.Body)". diff --git a/api/api.go b/api/api.go index 56916a6c..7d8ece9d 100644 --- a/api/api.go +++ b/api/api.go @@ -100,7 +100,7 @@ func (o Options) validate() error { // call is also needed to get the APIs into an operational state. func New(opts Options) (*API, error) { if err := opts.validate(); err != nil { - return nil, fmt.Errorf("invalid API options: %s", err) + return nil, fmt.Errorf("invalid API options: %w", err) } l := opts.Logger if l == nil { diff --git a/api/v2/api.go b/api/v2/api.go index 25f6c4b4..3e0bc0fd 100644 --- a/api/v2/api.go +++ b/api/v2/api.go @@ -14,6 +14,7 @@ package v2 import ( + "errors" "fmt" "net/http" "regexp" @@ -635,7 +636,7 @@ func (api *API) deleteSilenceHandler(params silence_ops.DeleteSilenceParams) mid sid := params.SilenceID.String() if err := api.silences.Expire(sid); err != nil { level.Error(logger).Log("msg", "Failed to expire silence", "err", err) - if err == silence.ErrNotFound { + if errors.Is(err, silence.ErrNotFound) { return silence_ops.NewDeleteSilenceNotFound() } return silence_ops.NewDeleteSilenceInternalServerError().WithPayload(err.Error()) @@ -669,7 +670,7 @@ func (api *API) postSilencesHandler(params silence_ops.PostSilencesParams) middl sid, err := api.silences.Set(sil) if err != nil { level.Error(logger).Log("msg", "Failed to create silence", "err", err) - if err == silence.ErrNotFound { + if errors.Is(err, silence.ErrNotFound) { return silence_ops.NewPostSilencesNotFound().WithPayload(err.Error()) } return silence_ops.NewPostSilencesBadRequest().WithPayload(err.Error()) diff --git a/cli/silence_import.go b/cli/silence_import.go index e6e0d1e9..52c8e70d 100644 --- a/cli/silence_import.go +++ b/cli/silence_import.go @@ -16,12 +16,12 @@ package cli import ( "context" "encoding/json" + "errors" "fmt" "os" "sync" kingpin "github.com/alecthomas/kingpin/v2" - "github.com/pkg/errors" "github.com/prometheus/alertmanager/api/v2/client/silence" "github.com/prometheus/alertmanager/api/v2/models" @@ -62,7 +62,8 @@ func addSilenceWorker(ctx context.Context, sclient silence.ClientService, silenc sid := s.ID params := silence.NewPostSilencesParams().WithContext(ctx).WithSilence(s) postOk, err := sclient.PostSilences(params) - if _, ok := err.(*silence.PostSilencesNotFound); ok { + var e *silence.PostSilencesNotFound + if errors.As(err, &e) { // silence doesn't exists yet, retry to create as a new one params.Silence.ID = "" postOk, err = sclient.PostSilences(params) @@ -92,7 +93,7 @@ func (c *silenceImportCmd) bulkImport(ctx context.Context, _ *kingpin.ParseConte // read open square bracket _, err = dec.Token() if err != nil { - return errors.Wrap(err, "couldn't unmarshal input data, is it JSON?") + return fmt.Errorf("couldn't unmarshal input data, is it JSON?: %w", err) } amclient := NewAlertmanagerClient(alertmanagerURL) @@ -121,7 +122,7 @@ func (c *silenceImportCmd) bulkImport(ctx context.Context, _ *kingpin.ParseConte var s models.PostableSilence err := dec.Decode(&s) if err != nil { - return errors.Wrap(err, "couldn't unmarshal input data, is it JSON?") + return fmt.Errorf("couldn't unmarshal input data, is it JSON?: %w", err) } if c.force { diff --git a/cli/silence_query.go b/cli/silence_query.go index ddffca3b..b25569f8 100644 --- a/cli/silence_query.go +++ b/cli/silence_query.go @@ -154,7 +154,7 @@ func (c *silenceQueryCmd) query(ctx context.Context, _ *kingpin.ParseContext) er return errors.New("unknown output formatter") } if err := formatter.FormatSilences(displaySilences); err != nil { - return fmt.Errorf("error formatting silences: %v", err) + return fmt.Errorf("error formatting silences: %w", err) } } return nil diff --git a/cli/silence_update.go b/cli/silence_update.go index 7d84dcb8..48d8d154 100644 --- a/cli/silence_update.go +++ b/cli/silence_update.go @@ -131,7 +131,7 @@ func (c *silenceUpdateCmd) update(ctx context.Context, _ *kingpin.ParseContext) return fmt.Errorf("unknown output formatter") } if err := formatter.FormatSilences(updatedSilences); err != nil { - return fmt.Errorf("error formatting silences: %v", err) + return fmt.Errorf("error formatting silences: %w", err) } } return nil diff --git a/cluster/advertise.go b/cluster/advertise.go index b1b8fe94..ac734649 100644 --- a/cluster/advertise.go +++ b/cluster/advertise.go @@ -14,10 +14,11 @@ package cluster import ( + "errors" + "fmt" "net" "github.com/hashicorp/go-sockaddr" - "github.com/pkg/errors" ) type getIPFunc func() (string, error) @@ -38,7 +39,7 @@ func calculateAdvertiseAddress(bindAddr, advertiseAddr string, allowInsecureAdve if advertiseAddr != "" { ip := net.ParseIP(advertiseAddr) if ip == nil { - return nil, errors.Errorf("failed to parse advertise addr '%s'", advertiseAddr) + return nil, fmt.Errorf("failed to parse advertise addr '%s'", advertiseAddr) } if ip4 := ip.To4(); ip4 != nil { ip = ip4 @@ -52,7 +53,7 @@ func calculateAdvertiseAddress(bindAddr, advertiseAddr string, allowInsecureAdve ip := net.ParseIP(bindAddr) if ip == nil { - return nil, errors.Errorf("failed to parse bind addr '%s'", bindAddr) + return nil, fmt.Errorf("failed to parse bind addr '%s'", bindAddr) } return ip, nil } @@ -64,7 +65,7 @@ func calculateAdvertiseAddress(bindAddr, advertiseAddr string, allowInsecureAdve func discoverAdvertiseAddress(allowInsecureAdvertise bool) (net.IP, error) { addr, err := getPrivateAddress() if err != nil { - return nil, errors.Wrap(err, "failed to get private IP") + return nil, fmt.Errorf("failed to get private IP: %w", err) } if addr == "" && !allowInsecureAdvertise { return nil, errors.New("no private IP found, explicit advertise addr not provided") @@ -73,7 +74,7 @@ func discoverAdvertiseAddress(allowInsecureAdvertise bool) (net.IP, error) { if addr == "" { addr, err = getPublicAddress() if err != nil { - return nil, errors.Wrap(err, "failed to get public IP") + return nil, fmt.Errorf("failed to get public IP: %w", err) } if addr == "" { return nil, errors.New("no private/public IP found, explicit advertise addr not provided") @@ -82,7 +83,7 @@ func discoverAdvertiseAddress(allowInsecureAdvertise bool) (net.IP, error) { ip := net.ParseIP(addr) if ip == nil { - return nil, errors.Errorf("failed to parse discovered IP '%s'", addr) + return nil, fmt.Errorf("failed to parse discovered IP '%s'", addr) } return ip, nil } diff --git a/cluster/cluster.go b/cluster/cluster.go index 2c7ee945..d85ee7f5 100644 --- a/cluster/cluster.go +++ b/cluster/cluster.go @@ -15,6 +15,7 @@ package cluster import ( "context" + "errors" "fmt" "math/rand" "net" @@ -28,7 +29,6 @@ import ( "github.com/go-kit/log/level" "github.com/hashicorp/memberlist" "github.com/oklog/ulid" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" ) @@ -146,11 +146,11 @@ func Create( ) (*Peer, error) { bindHost, bindPortStr, err := net.SplitHostPort(bindAddr) if err != nil { - return nil, errors.Wrap(err, "invalid listen address") + return nil, fmt.Errorf("invalid listen address: %w", err) } bindPort, err := strconv.Atoi(bindPortStr) if err != nil { - return nil, errors.Wrapf(err, "address %s: invalid port", bindAddr) + return nil, fmt.Errorf("address %s: invalid port: %w", bindAddr, err) } var advertiseHost string @@ -159,17 +159,17 @@ func Create( var advertisePortStr string advertiseHost, advertisePortStr, err = net.SplitHostPort(advertiseAddr) if err != nil { - return nil, errors.Wrap(err, "invalid advertise address") + return nil, fmt.Errorf("invalid advertise address: %w", err) } advertisePort, err = strconv.Atoi(advertisePortStr) if err != nil { - return nil, errors.Wrapf(err, "address %s: invalid port", advertiseAddr) + return nil, fmt.Errorf("address %s: invalid port: %w", advertiseAddr, err) } } resolvedPeers, err := resolvePeers(context.Background(), knownPeers, advertiseAddr, &net.Resolver{}, waitIfEmpty) if err != nil { - return nil, errors.Wrap(err, "resolve peers") + return nil, fmt.Errorf("resolve peers: %w", err) } level.Debug(l).Log("msg", "resolved peers to following addresses", "peers", strings.Join(resolvedPeers, ",")) @@ -242,13 +242,13 @@ func Create( level.Info(l).Log("msg", "using TLS for gossip") cfg.Transport, err = NewTLSTransport(context.Background(), l, reg, cfg.BindAddr, cfg.BindPort, tlsTransportConfig) if err != nil { - return nil, errors.Wrap(err, "tls transport") + return nil, fmt.Errorf("tls transport: %w", err) } } ml, err := memberlist.Create(cfg) if err != nil { - return nil, errors.Wrap(err, "create memberlist") + return nil, fmt.Errorf("create memberlist: %w", err) } p.mlist = ml return p, nil @@ -736,7 +736,7 @@ func resolvePeers(ctx context.Context, peers []string, myAddress string, res *ne for _, peer := range peers { host, port, err := net.SplitHostPort(peer) if err != nil { - return nil, errors.Wrapf(err, "split host/port for peer %s", peer) + return nil, fmt.Errorf("split host/port for peer %s: %w", peer, err) } retryCtx, cancel := context.WithCancel(ctx) @@ -761,7 +761,7 @@ func resolvePeers(ctx context.Context, peers []string, myAddress string, res *ne ips, err = res.LookupIPAddr(retryCtx, host) if err != nil { lookupErrSpotted = true - return errors.Wrapf(err, "IP Addr lookup for peer %s", peer) + return fmt.Errorf("IP Addr lookup for peer %s: %w", peer, err) } ips = removeMyAddr(ips, port, myAddress) diff --git a/cluster/connection_pool.go b/cluster/connection_pool.go index 4d8085dd..b9bda3a8 100644 --- a/cluster/connection_pool.go +++ b/cluster/connection_pool.go @@ -15,12 +15,12 @@ package cluster import ( "crypto/tls" + "errors" "fmt" "sync" "time" lru "github.com/hashicorp/golang-lru/v2" - "github.com/pkg/errors" ) const capacity = 1024 @@ -38,7 +38,7 @@ func newConnectionPool(tlsClientCfg *tls.Config) (*connectionPool, error) { }, ) if err != nil { - return nil, errors.Wrap(err, "failed to create new LRU") + return nil, fmt.Errorf("failed to create new LRU: %w", err) } return &connectionPool{ cache: cache, diff --git a/cluster/tls_connection.go b/cluster/tls_connection.go index 21ffc959..5d6416fd 100644 --- a/cluster/tls_connection.go +++ b/cluster/tls_connection.go @@ -17,6 +17,8 @@ import ( "bufio" "crypto/tls" "encoding/binary" + "errors" + "fmt" "io" "net" "sync" @@ -24,7 +26,6 @@ import ( "github.com/gogo/protobuf/proto" "github.com/hashicorp/memberlist" - "github.com/pkg/errors" "github.com/prometheus/alertmanager/cluster/clusterpb" ) @@ -99,7 +100,7 @@ func (conn *tlsConn) writePacket(fromAddr string, b []byte) error { }, ) if err != nil { - return errors.Wrap(err, "unable to marshal memeberlist packet message") + return fmt.Errorf("unable to marshal memeberlist packet message: %w", err) } buf := make([]byte, uint32length, uint32length+len(msg)) binary.LittleEndian.PutUint32(buf, uint32(len(msg))) @@ -116,7 +117,7 @@ func (conn *tlsConn) writeStream() error { }, ) if err != nil { - return errors.Wrap(err, "unable to marshal memeberlist stream message") + return fmt.Errorf("unable to marshal memeberlist stream message: %w", err) } buf := make([]byte, uint32length, uint32length+len(msg)) binary.LittleEndian.PutUint32(buf, uint32(len(msg))) @@ -136,7 +137,7 @@ func (conn *tlsConn) read() (*memberlist.Packet, error) { lenBuf := make([]byte, uint32length) _, err := io.ReadFull(reader, lenBuf) if err != nil { - return nil, errors.Wrap(err, "error reading message length") + return nil, fmt.Errorf("error reading message length: %w", err) } msgLen := binary.LittleEndian.Uint32(lenBuf) msgBuf := make([]byte, msgLen) @@ -144,12 +145,12 @@ func (conn *tlsConn) read() (*memberlist.Packet, error) { conn.mtx.Unlock() if err != nil { - return nil, errors.Wrap(err, "error reading message") + return nil, fmt.Errorf("error reading message: %w", err) } pb := clusterpb.MemberlistMessage{} err = proto.Unmarshal(msgBuf, &pb) if err != nil { - return nil, errors.Wrap(err, "error parsing message") + return nil, fmt.Errorf("error parsing message: %w", err) } if pb.Version != version { return nil, errors.New("tls memberlist message version incompatible") @@ -167,7 +168,7 @@ func (conn *tlsConn) read() (*memberlist.Packet, error) { func toPacket(pb clusterpb.MemberlistMessage) (*memberlist.Packet, error) { addr, err := net.ResolveTCPAddr(network, pb.FromAddr) if err != nil { - return nil, errors.Wrap(err, "error parsing packet sender address") + return nil, fmt.Errorf("error parsing packet sender address: %w", err) } return &memberlist.Packet{ Buf: pb.Msg, diff --git a/cluster/tls_transport.go b/cluster/tls_transport.go index eb521e04..7e39d6fe 100644 --- a/cluster/tls_transport.go +++ b/cluster/tls_transport.go @@ -20,6 +20,7 @@ package cluster import ( "context" "crypto/tls" + "errors" "fmt" "net" "strings" @@ -29,7 +30,6 @@ import ( "github.com/go-kit/log/level" "github.com/hashicorp/go-sockaddr" "github.com/hashicorp/memberlist" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" common "github.com/prometheus/common/config" "github.com/prometheus/exporter-toolkit/web" @@ -83,12 +83,12 @@ func NewTLSTransport( tlsServerCfg, err := web.ConfigToTLSConfig(cfg.TLSServerConfig) if err != nil { - return nil, errors.Wrap(err, "invalid TLS server config") + return nil, fmt.Errorf("invalid TLS server config: %w", err) } tlsClientCfg, err := common.NewTLSConfig(cfg.TLSClientConfig) if err != nil { - return nil, errors.Wrap(err, "invalid TLS client config") + return nil, fmt.Errorf("invalid TLS client config: %w", err) } ip := net.ParseIP(bindAddr) @@ -99,12 +99,12 @@ func NewTLSTransport( addr := &net.TCPAddr{IP: ip, Port: bindPort} listener, err := tls.Listen(network, addr.String(), tlsServerCfg) if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("failed to start TLS listener on %q port %d", bindAddr, bindPort)) + return nil, fmt.Errorf("failed to start TLS listener on %q port %d: %w", bindAddr, bindPort, err) } connPool, err := newConnectionPool(tlsClientCfg) if err != nil { - return nil, errors.Wrap(err, "failed to initialize tls transport connection pool") + return nil, fmt.Errorf("failed to initialize tls transport connection pool: %w", err) } ctx, cancel := context.WithCancel(ctx) @@ -155,7 +155,7 @@ func (t *TLSTransport) FinalAdvertiseAddr(ip string, port int) (net.IP, int, err var err error ip, err = sockaddr.GetPrivateIP() if err != nil { - return nil, 0, fmt.Errorf("failed to get interface addresses: %v", err) + return nil, 0, fmt.Errorf("failed to get interface addresses: %w", err) } if ip == "" { return nil, 0, fmt.Errorf("no private IP address found, and explicit IP not provided") @@ -203,13 +203,13 @@ func (t *TLSTransport) WriteTo(b []byte, addr string) (time.Time, error) { conn, err := t.connPool.borrowConnection(addr, DefaultTCPTimeout) if err != nil { t.writeErrs.WithLabelValues("packet").Inc() - return time.Now(), errors.Wrap(err, "failed to dial") + return time.Now(), fmt.Errorf("failed to dial: %w", err) } fromAddr := t.listener.Addr().String() err = conn.writePacket(fromAddr, b) if err != nil { t.writeErrs.WithLabelValues("packet").Inc() - return time.Now(), errors.Wrap(err, "failed to write packet") + return time.Now(), fmt.Errorf("failed to write packet: %w", err) } t.packetsSent.Add(float64(len(b))) return time.Now(), nil @@ -221,13 +221,13 @@ func (t *TLSTransport) DialTimeout(addr string, timeout time.Duration) (net.Conn conn, err := dialTLSConn(addr, timeout, t.tlsClientCfg) if err != nil { t.writeErrs.WithLabelValues("stream").Inc() - return nil, errors.Wrap(err, "failed to dial") + return nil, fmt.Errorf("failed to dial: %w", err) } err = conn.writeStream() netConn := conn.getRawConn() if err != nil { t.writeErrs.WithLabelValues("stream").Inc() - return netConn, errors.Wrap(err, "failed to create stream connection") + return netConn, fmt.Errorf("failed to create stream connection: %w", err) } t.streamsSent.Inc() return netConn, nil diff --git a/cmd/alertmanager/main.go b/cmd/alertmanager/main.go index 231e11dd..15716c98 100644 --- a/cmd/alertmanager/main.go +++ b/cmd/alertmanager/main.go @@ -15,6 +15,7 @@ package main import ( "context" + "errors" "fmt" "net" "net/http" @@ -31,7 +32,6 @@ import ( "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/common/model" @@ -332,7 +332,7 @@ func run() int { GroupFunc: groupFn, }) if err != nil { - level.Error(logger).Log("err", errors.Wrap(err, "failed to create API")) + level.Error(logger).Log("err", fmt.Errorf("failed to create API: %w", err)) return 1 } @@ -370,7 +370,7 @@ func run() int { configCoordinator.Subscribe(func(conf *config.Config) error { tmpl, err = template.FromGlobs(conf.Templates) if err != nil { - return errors.Wrap(err, "failed to parse templates") + return fmt.Errorf("failed to parse templates: %w", err) } tmpl.ExternalURL = amURL @@ -508,7 +508,7 @@ func run() int { srvc := make(chan struct{}) go func() { - if err := web.ListenAndServe(srv, webConfig, logger); err != http.ErrServerClosed { + if err := web.ListenAndServe(srv, webConfig, logger); !errors.Is(err, http.ErrServerClosed) { level.Error(logger).Log("msg", "Listen error", "err", err) close(srvc) } @@ -572,7 +572,7 @@ func extURL(logger log.Logger, hostnamef func() (string, error), listen, externa return nil, err } if u.Scheme != "http" && u.Scheme != "https" { - return nil, errors.Errorf("%q: invalid %q scheme, only 'http' and 'https' are supported", u.String(), u.Scheme) + return nil, fmt.Errorf("%q: invalid %q scheme, only 'http' and 'https' are supported", u.String(), u.Scheme) } ppref := strings.TrimRight(u.Path, "/") diff --git a/config/config.go b/config/config.go index 5714f2d5..355209b4 100644 --- a/config/config.go +++ b/config/config.go @@ -15,6 +15,7 @@ package config import ( "encoding/json" + "errors" "fmt" "net" "net/url" @@ -25,7 +26,6 @@ import ( "strings" "time" - "github.com/pkg/errors" commoncfg "github.com/prometheus/common/config" "github.com/prometheus/common/model" "gopkg.in/yaml.v2" @@ -689,7 +689,7 @@ func (hp *HostPort) UnmarshalYAML(unmarshal func(interface{}) error) error { return err } if hp.Port == "" { - return errors.Errorf("address %q: port cannot be empty", s) + return fmt.Errorf("address %q: port cannot be empty", s) } return nil } @@ -711,7 +711,7 @@ func (hp *HostPort) UnmarshalJSON(data []byte) error { return err } if hp.Port == "" { - return errors.Errorf("address %q: port cannot be empty", s) + return fmt.Errorf("address %q: port cannot be empty", s) } return nil } diff --git a/config/notifiers.go b/config/notifiers.go index 82eacee3..0759a573 100644 --- a/config/notifiers.go +++ b/config/notifiers.go @@ -21,7 +21,6 @@ import ( "text/template" "time" - "github.com/pkg/errors" commoncfg "github.com/prometheus/common/config" "github.com/prometheus/common/sigv4" ) @@ -541,7 +540,7 @@ func (c *WechatConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { } if !wechatTypeMatcher.MatchString(c.MessageType) { - return errors.Errorf("weChat message type %q does not match valid options %s", c.MessageType, wechatValidTypesRe) + return fmt.Errorf("weChat message type %q does not match valid options %s", c.MessageType, wechatValidTypesRe) } return nil @@ -587,18 +586,18 @@ func (c *OpsGenieConfig) UnmarshalYAML(unmarshal func(interface{}) error) error for _, r := range c.Responders { if r.ID == "" && r.Username == "" && r.Name == "" { - return errors.Errorf("opsGenieConfig responder %v has to have at least one of id, username or name specified", r) + return fmt.Errorf("opsGenieConfig responder %v has to have at least one of id, username or name specified", r) } if strings.Contains(r.Type, "{{") { _, err := template.New("").Parse(r.Type) if err != nil { - return errors.Errorf("opsGenieConfig responder %v type is not a valid template: %v", r, err) + return fmt.Errorf("opsGenieConfig responder %v type is not a valid template: %w", r, err) } } else { r.Type = strings.ToLower(r.Type) if !opsgenieTypeMatcher.MatchString(r.Type) { - return errors.Errorf("opsGenieConfig responder %v type does not match valid options %s", r, opsgenieValidTypesRe) + return fmt.Errorf("opsGenieConfig responder %v type does not match valid options %s", r, opsgenieValidTypesRe) } } } diff --git a/dispatch/dispatch.go b/dispatch/dispatch.go index 853d8496..640b22ab 100644 --- a/dispatch/dispatch.go +++ b/dispatch/dispatch.go @@ -15,6 +15,7 @@ package dispatch import ( "context" + "errors" "fmt" "sort" "sync" @@ -343,7 +344,7 @@ func (d *Dispatcher) processAlert(alert *types.Alert, route *Route) { _, _, err := d.stage.Exec(ctx, d.logger, alerts...) if err != nil { lvl := level.Error(d.logger) - if ctx.Err() == context.Canceled { + if errors.Is(ctx.Err(), context.Canceled) { // It is expected for the context to be canceled on // configuration reload or shutdown. In this case, the // message should only be logged at the debug level. diff --git a/go.mod b/go.mod index 461651d1..d0759e29 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,6 @@ require ( github.com/matttproud/golang_protobuf_extensions v1.0.4 github.com/oklog/run v1.1.0 github.com/oklog/ulid v1.3.1 - github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.17.0 github.com/prometheus/common v0.45.0 github.com/prometheus/common/assets v0.2.0 diff --git a/go.sum b/go.sum index c8bffd19..e085a998 100644 --- a/go.sum +++ b/go.sum @@ -466,7 +466,6 @@ github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/matchers/parse/parse.go b/matchers/parse/parse.go index 96af0d34..30a95b25 100644 --- a/matchers/parse/parse.go +++ b/matchers/parse/parse.go @@ -132,7 +132,7 @@ func (p *parser) parseCloseBrace(l *lexer) (parseFunc, error) { if p.hasOpenBrace { // If there was an open brace there must be a matching close brace. if _, err := p.expect(l, tokenCloseBrace); err != nil { - return nil, fmt.Errorf("0:%d: %s: %w", l.position().columnEnd, err, errNoCloseBrace) + return nil, fmt.Errorf("0:%d: %w: %w", l.position().columnEnd, err, errNoCloseBrace) } } else { // If there was no open brace there must not be a close brace either. @@ -152,7 +152,7 @@ func (p *parser) parseMatcher(l *lexer) (parseFunc, error) { ) // The first token should be the label name. if t, err = p.expect(l, tokenQuoted, tokenUnquoted); err != nil { - return nil, fmt.Errorf("%s: %w", err, errNoLabelName) + return nil, fmt.Errorf("%w: %w", err, errNoLabelName) } matchName, err = t.unquote() if err != nil { @@ -160,7 +160,7 @@ func (p *parser) parseMatcher(l *lexer) (parseFunc, error) { } // The next token should be the operator. if t, err = p.expect(l, tokenEquals, tokenNotEquals, tokenMatches, tokenNotMatches); err != nil { - return nil, fmt.Errorf("%s: %w", err, errNoOperator) + return nil, fmt.Errorf("%w: %w", err, errNoOperator) } switch t.kind { case tokenEquals: @@ -177,7 +177,7 @@ func (p *parser) parseMatcher(l *lexer) (parseFunc, error) { // The next token should be the match value. Like the match name, this too // can be either double-quoted UTF-8 or unquoted UTF-8 without reserved characters. if t, err = p.expect(l, tokenUnquoted, tokenQuoted); err != nil { - return nil, fmt.Errorf("%s: %w", err, errNoLabelValue) + return nil, fmt.Errorf("%w: %w", err, errNoLabelValue) } matchValue, err = t.unquote() if err != nil { @@ -185,7 +185,7 @@ func (p *parser) parseMatcher(l *lexer) (parseFunc, error) { } m, err := labels.NewMatcher(matchTy, matchName, matchValue) if err != nil { - return nil, fmt.Errorf("failed to create matcher: %s", err) + return nil, fmt.Errorf("failed to create matcher: %w", err) } p.matchers = append(p.matchers, m) return p.parseEndOfMatcher, nil @@ -199,7 +199,7 @@ func (p *parser) parseEndOfMatcher(l *lexer) (parseFunc, error) { // open brace has a matching close brace return p.parseCloseBrace, nil } - return nil, fmt.Errorf("%s: %w", err, errExpectedCommaOrCloseBrace) + return nil, fmt.Errorf("%w: %w", err, errExpectedCommaOrCloseBrace) } switch t.kind { case tokenComma: @@ -213,7 +213,7 @@ func (p *parser) parseEndOfMatcher(l *lexer) (parseFunc, error) { func (p *parser) parseComma(l *lexer) (parseFunc, error) { if _, err := p.expect(l, tokenComma); err != nil { - return nil, fmt.Errorf("%s: %w", err, errExpectedComma) + return nil, fmt.Errorf("%w: %w", err, errExpectedComma) } // The token after the comma can be another matcher, a close brace or end of input. t, err := p.expectPeek(l, tokenCloseBrace, tokenUnquoted, tokenQuoted) @@ -223,7 +223,7 @@ func (p *parser) parseComma(l *lexer) (parseFunc, error) { // open brace has a matching close brace return p.parseCloseBrace, nil } - return nil, fmt.Errorf("%s: %w", err, errExpectedMatcherOrCloseBrace) + return nil, fmt.Errorf("%w: %w", err, errExpectedMatcherOrCloseBrace) } if t.kind == tokenCloseBrace { return p.parseCloseBrace, nil @@ -234,7 +234,7 @@ func (p *parser) parseComma(l *lexer) (parseFunc, error) { func (p *parser) parseEOF(l *lexer) (parseFunc, error) { t, err := l.scan() if err != nil { - return nil, fmt.Errorf("%s: %w", err, errExpectedEOF) + return nil, fmt.Errorf("%w: %w", err, errExpectedEOF) } if !t.isEOF() { return nil, fmt.Errorf("%d:%d: %s: %w", t.columnStart, t.columnEnd, t.value, errExpectedEOF) diff --git a/nflog/nflog.go b/nflog/nflog.go index c318cede..c533dd0e 100644 --- a/nflog/nflog.go +++ b/nflog/nflog.go @@ -212,7 +212,7 @@ func decodeState(r io.Reader) (state, error) { st[stateKey(string(e.Entry.GroupKey), e.Entry.Receiver)] = &e continue } - if err == io.EOF { + if errors.Is(err, io.EOF) { break } return nil, err diff --git a/notify/email/email.go b/notify/email/email.go index 944aabdf..25b09875 100644 --- a/notify/email/email.go +++ b/notify/email/email.go @@ -17,6 +17,7 @@ import ( "bytes" "context" "crypto/tls" + "errors" "fmt" "math/rand" "mime" @@ -32,7 +33,6 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/pkg/errors" commoncfg "github.com/prometheus/common/config" "github.com/prometheus/alertmanager/config" @@ -133,7 +133,7 @@ func (n *Email) Notify(ctx context.Context, as ...*types.Alert) (bool, error) { if n.conf.Smarthost.Port == "465" { tlsConfig, err := commoncfg.NewTLSConfig(&n.conf.TLSConfig) if err != nil { - return false, errors.Wrap(err, "parse TLS configuration") + return false, fmt.Errorf("parse TLS configuration: %w", err) } if tlsConfig.ServerName == "" { tlsConfig.ServerName = n.conf.Smarthost.Host @@ -141,7 +141,7 @@ func (n *Email) Notify(ctx context.Context, as ...*types.Alert) (bool, error) { conn, err = tls.Dial("tcp", n.conf.Smarthost.String(), tlsConfig) if err != nil { - return true, errors.Wrap(err, "establish TLS connection to server") + return true, fmt.Errorf("establish TLS connection to server: %w", err) } } else { var ( @@ -150,13 +150,13 @@ func (n *Email) Notify(ctx context.Context, as ...*types.Alert) (bool, error) { ) conn, err = d.DialContext(ctx, "tcp", n.conf.Smarthost.String()) if err != nil { - return true, errors.Wrap(err, "establish connection to server") + return true, fmt.Errorf("establish connection to server: %w", err) } } c, err = smtp.NewClient(conn, n.conf.Smarthost.Host) if err != nil { conn.Close() - return true, errors.Wrap(err, "create SMTP client") + return true, fmt.Errorf("create SMTP client: %w", err) } defer func() { // Try to clean up after ourselves but don't log anything if something has failed. @@ -168,37 +168,37 @@ func (n *Email) Notify(ctx context.Context, as ...*types.Alert) (bool, error) { if n.conf.Hello != "" { err = c.Hello(n.conf.Hello) if err != nil { - return true, errors.Wrap(err, "send EHLO command") + return true, fmt.Errorf("send EHLO command: %w", err) } } // Global Config guarantees RequireTLS is not nil. if *n.conf.RequireTLS { if ok, _ := c.Extension("STARTTLS"); !ok { - return true, errors.Errorf("'require_tls' is true (default) but %q does not advertise the STARTTLS extension", n.conf.Smarthost) + return true, fmt.Errorf("'require_tls' is true (default) but %q does not advertise the STARTTLS extension", n.conf.Smarthost) } tlsConf, err := commoncfg.NewTLSConfig(&n.conf.TLSConfig) if err != nil { - return false, errors.Wrap(err, "parse TLS configuration") + return false, fmt.Errorf("parse TLS configuration: %w", err) } if tlsConf.ServerName == "" { tlsConf.ServerName = n.conf.Smarthost.Host } if err := c.StartTLS(tlsConf); err != nil { - return true, errors.Wrap(err, "send STARTTLS command") + return true, fmt.Errorf("send STARTTLS command: %w", err) } } if ok, mech := c.Extension("AUTH"); ok { auth, err := n.auth(mech) if err != nil { - return true, errors.Wrap(err, "find auth mechanism") + return true, fmt.Errorf("find auth mechanism: %w", err) } if auth != nil { if err := c.Auth(auth); err != nil { - return true, errors.Wrapf(err, "%T auth", auth) + return true, fmt.Errorf("%T auth: %w", auth, err) } } } @@ -210,37 +210,37 @@ func (n *Email) Notify(ctx context.Context, as ...*types.Alert) (bool, error) { ) from := tmpl(n.conf.From) if tmplErr != nil { - return false, errors.Wrap(tmplErr, "execute 'from' template") + return false, fmt.Errorf("execute 'from' template: %w", tmplErr) } to := tmpl(n.conf.To) if tmplErr != nil { - return false, errors.Wrap(tmplErr, "execute 'to' template") + return false, fmt.Errorf("execute 'to' template: %w", tmplErr) } addrs, err := mail.ParseAddressList(from) if err != nil { - return false, errors.Wrap(err, "parse 'from' addresses") + return false, fmt.Errorf("parse 'from' addresses: %w", err) } if len(addrs) != 1 { - return false, errors.Errorf("must be exactly one 'from' address (got: %d)", len(addrs)) + return false, fmt.Errorf("must be exactly one 'from' address (got: %d)", len(addrs)) } if err = c.Mail(addrs[0].Address); err != nil { - return true, errors.Wrap(err, "send MAIL command") + return true, fmt.Errorf("send MAIL command: %w", err) } addrs, err = mail.ParseAddressList(to) if err != nil { - return false, errors.Wrapf(err, "parse 'to' addresses") + return false, fmt.Errorf("parse 'to' addresses: %w", err) } for _, addr := range addrs { if err = c.Rcpt(addr.Address); err != nil { - return true, errors.Wrapf(err, "send RCPT command") + return true, fmt.Errorf("send RCPT command: %w", err) } } // Send the email headers and body. message, err := c.Data() if err != nil { - return true, errors.Wrapf(err, "send DATA command") + return true, fmt.Errorf("send DATA command: %w", err) } defer message.Close() @@ -248,7 +248,7 @@ func (n *Email) Notify(ctx context.Context, as ...*types.Alert) (bool, error) { for header, t := range n.conf.Headers { value, err := n.tmpl.ExecuteTextString(t, data) if err != nil { - return false, errors.Wrapf(err, "execute %q header template", header) + return false, fmt.Errorf("execute %q header template: %w", header, err) } fmt.Fprintf(buffer, "%s: %s\r\n", header, mime.QEncoding.Encode("utf-8", value)) } @@ -268,7 +268,7 @@ func (n *Email) Notify(ctx context.Context, as ...*types.Alert) (bool, error) { // and active/resolved. _, err = message.Write(buffer.Bytes()) if err != nil { - return false, errors.Wrap(err, "write headers") + return false, fmt.Errorf("write headers: %w", err) } if len(n.conf.Text) > 0 { @@ -278,20 +278,20 @@ func (n *Email) Notify(ctx context.Context, as ...*types.Alert) (bool, error) { "Content-Type": {"text/plain; charset=UTF-8"}, }) if err != nil { - return false, errors.Wrap(err, "create part for text template") + return false, fmt.Errorf("create part for text template: %w", err) } body, err := n.tmpl.ExecuteTextString(n.conf.Text, data) if err != nil { - return false, errors.Wrap(err, "execute text template") + return false, fmt.Errorf("execute text template: %w", err) } qw := quotedprintable.NewWriter(w) _, err = qw.Write([]byte(body)) if err != nil { - return true, errors.Wrap(err, "write text part") + return true, fmt.Errorf("write text part: %w", err) } err = qw.Close() if err != nil { - return true, errors.Wrap(err, "close text part") + return true, fmt.Errorf("close text part: %w", err) } } @@ -304,31 +304,31 @@ func (n *Email) Notify(ctx context.Context, as ...*types.Alert) (bool, error) { "Content-Type": {"text/html; charset=UTF-8"}, }) if err != nil { - return false, errors.Wrap(err, "create part for html template") + return false, fmt.Errorf("create part for html template: %w", err) } body, err := n.tmpl.ExecuteHTMLString(n.conf.HTML, data) if err != nil { - return false, errors.Wrap(err, "execute html template") + return false, fmt.Errorf("execute html template: %w", err) } qw := quotedprintable.NewWriter(w) _, err = qw.Write([]byte(body)) if err != nil { - return true, errors.Wrap(err, "write HTML part") + return true, fmt.Errorf("write HTML part: %w", err) } err = qw.Close() if err != nil { - return true, errors.Wrap(err, "close HTML part") + return true, fmt.Errorf("close HTML part: %w", err) } } err = multipartWriter.Close() if err != nil { - return false, errors.Wrap(err, "close multipartWriter") + return false, fmt.Errorf("close multipartWriter: %w", err) } _, err = message.Write(multipartBuffer.Bytes()) if err != nil { - return false, errors.Wrap(err, "write body buffer") + return false, fmt.Errorf("write body buffer: %w", err) } success = true diff --git a/notify/msteams/msteams_test.go b/notify/msteams/msteams_test.go index efe1886a..2171018a 100644 --- a/notify/msteams/msteams_test.go +++ b/notify/msteams/msteams_test.go @@ -16,6 +16,7 @@ package msteams import ( "context" "encoding/json" + "errors" "fmt" "io" "net/http" @@ -185,8 +186,8 @@ func TestNotifier_Notify_WithReason(t *testing.T) { if tt.noError { require.NoError(t, err) } else { - reasonError, ok := err.(*notify.ErrorWithReason) - require.True(t, ok) + var reasonError *notify.ErrorWithReason + require.True(t, errors.As(err, &reasonError)) require.Equal(t, tt.expectedReason, reasonError.Reason) } }) diff --git a/notify/notify.go b/notify/notify.go index 7b4603c0..0a2b0d03 100644 --- a/notify/notify.go +++ b/notify/notify.go @@ -15,6 +15,7 @@ package notify import ( "context" + "errors" "fmt" "sort" "sync" @@ -24,7 +25,6 @@ import ( "github.com/cespare/xxhash/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/model" @@ -686,7 +686,7 @@ func (n *DedupStage) Exec(ctx context.Context, _ log.Logger, alerts ...*types.Al ctx = WithResolvedAlerts(ctx, resolved) entries, err := n.nflog.Query(nflog.QGroupKey(gkey), nflog.QReceiver(n.recv)) - if err != nil && err != nflog.ErrNotFound { + if err != nil && !errors.Is(err, nflog.ErrNotFound) { return ctx, nil, err } @@ -696,7 +696,7 @@ func (n *DedupStage) Exec(ctx context.Context, _ log.Logger, alerts ...*types.Al case 1: entry = entries[0] default: - return ctx, nil, errors.Errorf("unexpected entry result size %d", len(entries)) + return ctx, nil, fmt.Errorf("unexpected entry result size %d", len(entries)) } if n.needsUpdate(entry, firingSet, resolvedSet, repeatInterval) { @@ -736,7 +736,8 @@ func (r RetryStage) Exec(ctx context.Context, l log.Logger, alerts ...*types.Ale failureReason := DefaultReason.String() if err != nil { - if e, ok := errors.Cause(err).(*ErrorWithReason); ok { + var e *ErrorWithReason + if errors.As(err, &e) { failureReason = e.Reason.String() } r.metrics.numTotalFailedNotifications.WithLabelValues(append(r.labelValues, failureReason)...).Inc() @@ -797,7 +798,10 @@ func (r RetryStage) exec(ctx context.Context, l log.Logger, alerts ...*types.Ale } } - return ctx, nil, errors.Wrapf(iErr, "%s/%s: notify retry canceled after %d attempts", r.groupName, r.integration.String(), i) + if iErr != nil { + return ctx, nil, fmt.Errorf("%s/%s: notify retry canceled after %d attempts: %w", r.groupName, r.integration.String(), i, iErr) + } + return ctx, nil, nil default: } @@ -811,7 +815,7 @@ func (r RetryStage) exec(ctx context.Context, l log.Logger, alerts ...*types.Ale if err != nil { r.metrics.numNotificationRequestsFailedTotal.WithLabelValues(r.labelValues...).Inc() if !retry { - return ctx, alerts, errors.Wrapf(err, "%s/%s: notify retry canceled due to unrecoverable error after %d attempts", r.groupName, r.integration.String(), i) + return ctx, alerts, fmt.Errorf("%s/%s: notify retry canceled due to unrecoverable error after %d attempts: %w", r.groupName, r.integration.String(), i, err) } if ctx.Err() == nil { if iErr == nil || err.Error() != iErr.Error() { @@ -840,8 +844,10 @@ func (r RetryStage) exec(ctx context.Context, l log.Logger, alerts ...*types.Ale iErr = NewErrorWithReason(ContextDeadlineExceededReason, iErr) } } - - return ctx, nil, errors.Wrapf(iErr, "%s/%s: notify retry canceled after %d attempts", r.groupName, r.integration.String(), i) + if iErr != nil { + return ctx, nil, fmt.Errorf("%s/%s: notify retry canceled after %d attempts: %w", r.groupName, r.integration.String(), i, iErr) + } + return ctx, nil, nil } } } diff --git a/notify/opsgenie/opsgenie.go b/notify/opsgenie/opsgenie.go index 0a5e218f..4421cd65 100644 --- a/notify/opsgenie/opsgenie.go +++ b/notify/opsgenie/opsgenie.go @@ -24,7 +24,6 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/pkg/errors" commoncfg "github.com/prometheus/common/config" "github.com/prometheus/common/model" @@ -281,13 +280,13 @@ func (n *Notifier) createRequests(ctx context.Context, as ...*types.Alert) ([]*h } else { content, err := os.ReadFile(n.conf.APIKeyFile) if err != nil { - return nil, false, errors.Wrap(err, "read key_file error") + return nil, false, fmt.Errorf("read key_file error: %w", err) } apiKey = tmpl(string(content)) } if err != nil { - return nil, false, errors.Wrap(err, "templating error") + return nil, false, fmt.Errorf("templating error: %w", err) } for _, req := range requests { diff --git a/notify/pagerduty/pagerduty.go b/notify/pagerduty/pagerduty.go index 39ec84d9..6f6e1a20 100644 --- a/notify/pagerduty/pagerduty.go +++ b/notify/pagerduty/pagerduty.go @@ -17,6 +17,7 @@ import ( "bytes" "context" "encoding/json" + "errors" "fmt" "io" "net/http" @@ -26,7 +27,6 @@ import ( "github.com/alecthomas/units" "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/pkg/errors" commoncfg "github.com/prometheus/common/config" "github.com/prometheus/common/model" @@ -120,7 +120,7 @@ type pagerDutyPayload struct { func (n *Notifier) encodeMessage(msg *pagerDutyMessage) (bytes.Buffer, error) { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(msg); err != nil { - return buf, errors.Wrap(err, "failed to encode PagerDuty message") + return buf, fmt.Errorf("failed to encode PagerDuty message: %w", err) } if buf.Len() > maxEventSize { @@ -137,7 +137,7 @@ func (n *Notifier) encodeMessage(msg *pagerDutyMessage) (bytes.Buffer, error) { buf.Reset() if err := json.NewEncoder(&buf).Encode(msg); err != nil { - return buf, errors.Wrap(err, "failed to encode PagerDuty message") + return buf, fmt.Errorf("failed to encode PagerDuty message: %w", err) } } @@ -164,7 +164,7 @@ func (n *Notifier) notifyV1( if serviceKey == "" { content, fileErr := os.ReadFile(n.conf.ServiceKeyFile) if fileErr != nil { - return false, errors.Wrap(fileErr, "failed to read service key from file") + return false, fmt.Errorf("failed to read service key from file: %w", fileErr) } serviceKey = strings.TrimSpace(string(content)) } @@ -183,7 +183,7 @@ func (n *Notifier) notifyV1( } if tmplErr != nil { - return false, errors.Wrap(tmplErr, "failed to template PagerDuty v1 message") + return false, fmt.Errorf("failed to template PagerDuty v1 message: %w", tmplErr) } // Ensure that the service key isn't empty after templating. @@ -198,7 +198,7 @@ func (n *Notifier) notifyV1( resp, err := notify.PostJSON(ctx, n.client, n.apiV1, &encodedMsg) if err != nil { - return true, errors.Wrap(err, "failed to post message to PagerDuty v1") + return true, fmt.Errorf("failed to post message to PagerDuty v1: %w", err) } defer notify.Drain(resp) @@ -229,7 +229,7 @@ func (n *Notifier) notifyV2( if routingKey == "" { content, fileErr := os.ReadFile(n.conf.RoutingKeyFile) if fileErr != nil { - return false, errors.Wrap(fileErr, "failed to read routing key from file") + return false, fmt.Errorf("failed to read routing key from file: %w", fileErr) } routingKey = strings.TrimSpace(string(content)) } @@ -277,7 +277,7 @@ func (n *Notifier) notifyV2( } if tmplErr != nil { - return false, errors.Wrap(tmplErr, "failed to template PagerDuty v2 message") + return false, fmt.Errorf("failed to template PagerDuty v2 message: %w", tmplErr) } // Ensure that the routing key isn't empty after templating. @@ -292,7 +292,7 @@ func (n *Notifier) notifyV2( resp, err := notify.PostJSON(ctx, n.client, n.conf.URL.String(), &encodedMsg) if err != nil { - return true, errors.Wrap(err, "failed to post message to PagerDuty") + return true, fmt.Errorf("failed to post message to PagerDuty: %w", err) } defer notify.Drain(resp) @@ -325,7 +325,7 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) for k, v := range n.conf.Details { detail, err := n.tmpl.ExecuteTextString(v, data) if err != nil { - return false, errors.Wrapf(err, "%q: failed to template %q", k, v) + return false, fmt.Errorf("%q: failed to template %q: %w", k, v, err) } details[k] = detail } diff --git a/notify/slack/slack.go b/notify/slack/slack.go index 79097b7a..b4b5a195 100644 --- a/notify/slack/slack.go +++ b/notify/slack/slack.go @@ -25,7 +25,6 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/pkg/errors" commoncfg "github.com/prometheus/common/config" "github.com/prometheus/alertmanager/config" @@ -216,7 +215,7 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) // classify them as retriable or not. retry, err := n.retrier.Check(resp.StatusCode, resp.Body) if err != nil { - err = errors.Wrap(err, fmt.Sprintf("channel %q", req.Channel)) + err = fmt.Errorf("channel %q: %w", req.Channel, err) return retry, notify.NewErrorWithReason(notify.GetFailureReasonFromStatusCode(resp.StatusCode), err) } @@ -224,7 +223,7 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) // https://slack.dev/node-slack-sdk/web-api#handle-errors retry, err = checkResponseError(resp) if err != nil { - err = errors.Wrap(err, fmt.Sprintf("channel %q", req.Channel)) + err = fmt.Errorf("channel %q: %w", req.Channel, err) return retry, notify.NewErrorWithReason(notify.ClientErrorReason, err) } @@ -235,7 +234,7 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) func checkResponseError(resp *http.Response) (bool, error) { body, err := io.ReadAll(resp.Body) if err != nil { - return true, errors.Wrap(err, "could not read response body") + return true, fmt.Errorf("could not read response body: %w", err) } if strings.HasPrefix(resp.Header.Get("Content-Type"), "application/json") { @@ -265,7 +264,7 @@ func checkJSONResponseError(body []byte) (bool, error) { var data response if err := json.Unmarshal(body, &data); err != nil { - return true, errors.Wrapf(err, "could not unmarshal JSON response %q", string(body)) + return true, fmt.Errorf("could not unmarshal JSON response %q: %w", string(body), err) } if !data.OK { return false, fmt.Errorf("error response from Slack: %s", data.Error) diff --git a/notify/slack/slack_test.go b/notify/slack/slack_test.go index 9f2eb985..02a0e589 100644 --- a/notify/slack/slack_test.go +++ b/notify/slack/slack_test.go @@ -15,6 +15,7 @@ package slack import ( "context" + "errors" "fmt" "io" "net/http" @@ -226,8 +227,8 @@ func TestNotifier_Notify_WithReason(t *testing.T) { if tt.noError { require.NoError(t, err) } else { - reasonError, ok := err.(*notify.ErrorWithReason) - require.True(t, ok) + var reasonError *notify.ErrorWithReason + require.True(t, errors.As(err, &reasonError)) require.Equal(t, tt.expectedReason, reasonError.Reason) require.Contains(t, err.Error(), tt.expectedErr) require.Contains(t, err.Error(), "channelname") diff --git a/notify/sns/sns.go b/notify/sns/sns.go index b9881b01..996566c7 100644 --- a/notify/sns/sns.go +++ b/notify/sns/sns.go @@ -15,6 +15,7 @@ package sns import ( "context" + "errors" "fmt" "net/http" "strings" @@ -69,7 +70,8 @@ func (n *Notifier) Notify(ctx context.Context, alert ...*types.Alert) (bool, err client, err := n.createSNSClient(tmpl) if err != nil { - if e, ok := err.(awserr.RequestFailure); ok { + var e awserr.RequestFailure + if errors.As(err, &e) { return n.retrier.Check(e.StatusCode(), strings.NewReader(e.Message())) } return true, err @@ -82,7 +84,8 @@ func (n *Notifier) Notify(ctx context.Context, alert ...*types.Alert) (bool, err publishOutput, err := client.Publish(publishInput) if err != nil { - if e, ok := err.(awserr.RequestFailure); ok { + var e awserr.RequestFailure + if errors.As(err, &e) { retryable, error := n.retrier.Check(e.StatusCode(), strings.NewReader(e.Message())) reasonErr := notify.NewErrorWithReason(notify.GetFailureReasonFromStatusCode(e.StatusCode()), error) diff --git a/notify/util.go b/notify/util.go index b5110f63..bd54e2b4 100644 --- a/notify/util.go +++ b/notify/util.go @@ -16,6 +16,7 @@ package notify import ( "context" "crypto/sha256" + "errors" "fmt" "io" "net/http" @@ -24,7 +25,6 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/pkg/errors" "github.com/prometheus/common/version" "github.com/prometheus/alertmanager/template" @@ -39,8 +39,8 @@ var UserAgentHeader = fmt.Sprintf("Alertmanager/%s", version.Version) // RedactURL removes the URL part from an error of *url.Error type. func RedactURL(err error) error { - e, ok := err.(*url.Error) - if !ok { + var e *url.Error + if !errors.As(err, &e) { return err } e.URL = "" @@ -160,7 +160,7 @@ type Key string func ExtractGroupKey(ctx context.Context) (Key, error) { key, ok := GroupKey(ctx) if !ok { - return "", errors.Errorf("group key missing") + return "", fmt.Errorf("group key missing") } return Key(key), nil } diff --git a/notify/victorops/victorops.go b/notify/victorops/victorops.go index 780f7a8d..44088b4e 100644 --- a/notify/victorops/victorops.go +++ b/notify/victorops/victorops.go @@ -24,7 +24,6 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/pkg/errors" commoncfg "github.com/prometheus/common/config" "github.com/prometheus/common/model" @@ -83,14 +82,14 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) } else { content, fileErr := os.ReadFile(n.conf.APIKeyFile) if fileErr != nil { - return false, errors.Wrap(fileErr, "failed to read API key from file") + return false, fmt.Errorf("failed to read API key from file: %w", fileErr) } apiKey = strings.TrimSpace(string(content)) } apiURL.Path += fmt.Sprintf("%s/%s", apiKey, tmpl(n.conf.RoutingKey)) if err != nil { - return false, fmt.Errorf("templating error: %s", err) + return false, fmt.Errorf("templating error: %w", err) } buf, err := n.createVictorOpsPayload(ctx, as...) @@ -155,14 +154,14 @@ func (n *Notifier) createVictorOpsPayload(ctx context.Context, as ...*types.Aler } if err != nil { - return nil, fmt.Errorf("templating error: %s", err) + return nil, fmt.Errorf("templating error: %w", err) } // Add custom fields to the payload. for k, v := range n.conf.CustomFields { msg[k] = tmpl(v) if err != nil { - return nil, fmt.Errorf("templating error: %s", err) + return nil, fmt.Errorf("templating error: %w", err) } } diff --git a/notify/wechat/wechat.go b/notify/wechat/wechat.go index 2e3b2c29..9eb77b66 100644 --- a/notify/wechat/wechat.go +++ b/notify/wechat/wechat.go @@ -17,6 +17,7 @@ import ( "bytes" "context" "encoding/json" + "errors" "fmt" "io" "net/http" @@ -25,7 +26,6 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/pkg/errors" commoncfg "github.com/prometheus/common/config" "github.com/prometheus/alertmanager/config" @@ -101,7 +101,7 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) parameters.Add("corpsecret", tmpl(string(n.conf.APISecret))) parameters.Add("corpid", tmpl(string(n.conf.CorpID))) if err != nil { - return false, fmt.Errorf("templating error: %s", err) + return false, fmt.Errorf("templating error: %w", err) } u := n.conf.APIURL.Copy() @@ -147,7 +147,7 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) } } if err != nil { - return false, fmt.Errorf("templating error: %s", err) + return false, fmt.Errorf("templating error: %w", err) } var buf bytes.Buffer diff --git a/pkg/labels/parse.go b/pkg/labels/parse.go index a125d59d..5138716e 100644 --- a/pkg/labels/parse.go +++ b/pkg/labels/parse.go @@ -14,11 +14,10 @@ package labels import ( + "fmt" "regexp" "strings" "unicode/utf8" - - "github.com/pkg/errors" ) var ( @@ -118,7 +117,7 @@ func ParseMatchers(s string) ([]*Matcher, error) { func ParseMatcher(s string) (_ *Matcher, err error) { ms := re.FindStringSubmatch(s) if len(ms) == 0 { - return nil, errors.Errorf("bad matcher format: %s", s) + return nil, fmt.Errorf("bad matcher format: %s", s) } var ( @@ -134,7 +133,7 @@ func ParseMatcher(s string) (_ *Matcher, err error) { } if !utf8.ValidString(rawValue) { - return nil, errors.Errorf("matcher value not valid UTF-8: %s", ms[3]) + return nil, fmt.Errorf("matcher value not valid UTF-8: %s", ms[3]) } // Unescape the rawValue: @@ -163,7 +162,7 @@ func ParseMatcher(s string) (_ *Matcher, err error) { value.WriteByte('\\') case '"': if !expectTrailingQuote || i < len(rawValue)-1 { - return nil, errors.Errorf("matcher value contains unescaped double quote: %s", ms[3]) + return nil, fmt.Errorf("matcher value contains unescaped double quote: %s", ms[3]) } expectTrailingQuote = false default: @@ -172,7 +171,7 @@ func ParseMatcher(s string) (_ *Matcher, err error) { } if expectTrailingQuote { - return nil, errors.Errorf("matcher value contains unescaped double quote: %s", ms[3]) + return nil, fmt.Errorf("matcher value contains unescaped double quote: %s", ms[3]) } return NewMatcher(typeMap[ms[2]], ms[1], value.String()) diff --git a/silence/silence.go b/silence/silence.go index 40ad304b..3a31139c 100644 --- a/silence/silence.go +++ b/silence/silence.go @@ -17,6 +17,7 @@ package silence import ( "bytes" + "errors" "fmt" "io" "math/rand" @@ -33,7 +34,6 @@ import ( "github.com/go-kit/log/level" uuid "github.com/gofrs/uuid" "github.com/matttproud/golang_protobuf_extensions/pbutil" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/model" @@ -79,7 +79,7 @@ func (c matcherCache) add(s *pb.Silence) (labels.Matchers, error) { case pb.Matcher_NOT_REGEXP: mt = labels.MatchNotRegexp default: - return nil, errors.Errorf("unknown matcher type %q", m.Type) + return nil, fmt.Errorf("unknown matcher type %q", m.Type) } matcher, err := labels.NewMatcher(mt, m.Name, m.Pattern) if err != nil { @@ -489,7 +489,7 @@ func validateClassicMatcher(m *pb.Matcher) error { } case pb.Matcher_REGEXP, pb.Matcher_NOT_REGEXP: if _, err := regexp.Compile(m.Pattern); err != nil { - return fmt.Errorf("invalid regular expression %q: %s", m.Pattern, err) + return fmt.Errorf("invalid regular expression %q: %w", m.Pattern, err) } default: return fmt.Errorf("unknown matcher type %q", m.Type) @@ -512,7 +512,7 @@ func validateUTF8Matcher(m *pb.Matcher) error { return fmt.Errorf("invalid regular expression %q", m.Pattern) } if _, err := regexp.Compile(m.Pattern); err != nil { - return fmt.Errorf("invalid regular expression %q: %s", m.Pattern, err) + return fmt.Errorf("invalid regular expression %q: %w", m.Pattern, err) } default: return fmt.Errorf("unknown matcher type %q", m.Type) @@ -548,7 +548,7 @@ func validateSilence(s *pb.Silence, ff featurecontrol.Flagger) error { for i, m := range s.Matchers { if err := validateFunc(m); err != nil { - return fmt.Errorf("invalid label matcher %d: %s", i, err) + return fmt.Errorf("invalid label matcher %d: %w", i, err) } allMatchEmpty = allMatchEmpty && matchesEmpty(m) } @@ -589,7 +589,7 @@ func (s *Silences) setSilence(sil *pb.Silence, now time.Time, skipValidate bool) if !skipValidate { if err := validateSilence(sil, s.ff); err != nil { - return errors.Wrap(err, "silence invalid") + return fmt.Errorf("silence invalid: %w", err) } } @@ -629,14 +629,14 @@ func (s *Silences) Set(sil *pb.Silence) (string, error) { if getState(prev, s.nowUTC()) != types.SilenceStateExpired { // We cannot update the silence, expire the old one. if err := s.expire(prev.Id); err != nil { - return "", errors.Wrap(err, "expire previous silence") + return "", fmt.Errorf("expire previous silence: %w", err) } } } // If we got here it's either a new silence or a replacing one. uid, err := uuid.NewV4() if err != nil { - return "", errors.Wrap(err, "generate uuid") + return "", fmt.Errorf("generate uuid: %w", err) } sil.Id = uid.String() @@ -994,7 +994,7 @@ func decodeState(r io.Reader) (state, error) { st[s.Silence.Id] = &s continue } - if err == io.EOF { + if errors.Is(err, io.EOF) { break } return nil, err diff --git a/test/cli/acceptance.go b/test/cli/acceptance.go index 74fd1447..d799c2e2 100644 --- a/test/cli/acceptance.go +++ b/test/cli/acceptance.go @@ -294,14 +294,14 @@ func (amc *AlertmanagerCluster) Start() error { for _, am := range amc.ams { err := am.Start(peerFlags) if err != nil { - return fmt.Errorf("starting alertmanager cluster: %v", err.Error()) + return fmt.Errorf("starting alertmanager cluster: %w", err) } } for _, am := range amc.ams { err := am.WaitForCluster(len(amc.ams)) if err != nil { - return fmt.Errorf("waiting alertmanager cluster: %v", err.Error()) + return fmt.Errorf("waiting alertmanager cluster: %w", err) } } @@ -342,7 +342,7 @@ func (am *Alertmanager) Start(additionalArg []string) error { am.cmd = cmd if err := am.cmd.Start(); err != nil { - return fmt.Errorf("starting alertmanager failed: %s", err) + return fmt.Errorf("starting alertmanager failed: %w", err) } go func() { @@ -364,7 +364,7 @@ func (am *Alertmanager) Start(additionalArg []string) error { } _, err = io.ReadAll(resp.Body) if err != nil { - return fmt.Errorf("starting alertmanager failed: %s", err) + return fmt.Errorf("starting alertmanager failed: %w", err) } return nil } diff --git a/test/with_api_v2/acceptance.go b/test/with_api_v2/acceptance.go index 22b0b248..a6c4abd8 100644 --- a/test/with_api_v2/acceptance.go +++ b/test/with_api_v2/acceptance.go @@ -274,14 +274,14 @@ func (amc *AlertmanagerCluster) Start() error { for _, am := range amc.ams { err := am.Start(peerFlags) if err != nil { - return fmt.Errorf("failed to start alertmanager cluster: %v", err.Error()) + return fmt.Errorf("failed to start alertmanager cluster: %w", err) } } for _, am := range amc.ams { err := am.WaitForCluster(len(amc.ams)) if err != nil { - return fmt.Errorf("failed to wait for Alertmanager instance %q to join cluster: %v", am.clusterAddr, err.Error()) + return fmt.Errorf("failed to wait for Alertmanager instance %q to join cluster: %w", am.clusterAddr, err) } } @@ -343,7 +343,7 @@ func (am *Alertmanager) Start(additionalArg []string) error { } time.Sleep(500 * time.Millisecond) } - return fmt.Errorf("unable to get a successful response from the Alertmanager: %v", lastErr) + return fmt.Errorf("unable to get a successful response from the Alertmanager: %w", lastErr) } // WaitForCluster waits for the Alertmanager instance to join a cluster with the diff --git a/types/types.go b/types/types.go index afcbc980..e10cc688 100644 --- a/types/types.go +++ b/types/types.go @@ -345,10 +345,10 @@ func (a *Alert) Validate(ff featurecontrol.Flagger) error { return fmt.Errorf("at least one label pair required") } if err := validateLs(a.Labels, ff); err != nil { - return fmt.Errorf("invalid label set: %s", err) + return fmt.Errorf("invalid label set: %w", err) } if err := validateLs(a.Annotations, ff); err != nil { - return fmt.Errorf("invalid annotations: %s", err) + return fmt.Errorf("invalid annotations: %w", err) } return nil }