fix: replace fmt.Errorf with signoz/pkg/errors and update golangci-li… (#9373)

This PR fulfills the requirements of #9069 by:

- Adding a golangci-lint directive (forbidigo) to disallow all fmt.Errorf usages.
- Replacing existing fmt.Errorf instances with structured errors from github.com/SigNoz/signoz/pkg/errors for consistent error classification and lint compliance.
- Verified lint and build integrity.
This commit is contained in:
Pranjul Kalsi
2025-10-27 16:30:18 +05:30
committed by GitHub
parent 5f8cfbe474
commit bdce97a727
56 changed files with 315 additions and 293 deletions

View File

@@ -32,6 +32,10 @@ linters-settings:
iface:
enable:
- identical
forbidigo:
forbid:
- fmt.Errorf
- ^(fmt\.Print.*|print|println)$
issues:
exclude-dirs:
- "pkg/query-service"

View File

@@ -1,10 +1,10 @@
package licensing
import (
"fmt"
"sync"
"time"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/licensing"
)
@@ -18,7 +18,7 @@ func Config(pollInterval time.Duration, failureThreshold int) licensing.Config {
once.Do(func() {
config = licensing.Config{PollInterval: pollInterval, FailureThreshold: failureThreshold}
if err := config.Validate(); err != nil {
panic(fmt.Errorf("invalid licensing config: %w", err))
panic(errors.WrapInternalf(err, errors.CodeInternal, "invalid licensing config"))
}
})

View File

@@ -1,10 +1,10 @@
package zeus
import (
"fmt"
neturl "net/url"
"sync"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/zeus"
)
@@ -24,17 +24,17 @@ func Config() zeus.Config {
once.Do(func() {
parsedURL, err := neturl.Parse(url)
if err != nil {
panic(fmt.Errorf("invalid zeus URL: %w", err))
panic(errors.WrapInternalf(err, errors.CodeInternal, "invalid zeus URL"))
}
deprecatedParsedURL, err := neturl.Parse(deprecatedURL)
if err != nil {
panic(fmt.Errorf("invalid zeus deprecated URL: %w", err))
panic(errors.WrapInternalf(err, errors.CodeInternal, "invalid zeus deprecated URL"))
}
config = zeus.Config{URL: parsedURL, DeprecatedURL: deprecatedParsedURL}
if err := config.Validate(); err != nil {
panic(fmt.Errorf("invalid zeus config: %w", err))
panic(errors.WrapInternalf(err, errors.CodeInternal, "invalid zeus config"))
}
})

View File

@@ -4,7 +4,6 @@ import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"log/slog"
"net/http"
@@ -12,6 +11,7 @@ import (
"slices"
"strings"
"github.com/SigNoz/signoz/pkg/errors"
commoncfg "github.com/prometheus/common/config"
"github.com/prometheus/common/model"
@@ -145,7 +145,7 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error)
} else {
content, err := os.ReadFile(n.conf.WebhookURLFile)
if err != nil {
return false, fmt.Errorf("read webhook_url_file: %w", err)
return false, errors.WrapInternalf(err, errors.CodeInternal, "read webhook_url_file")
}
url = strings.TrimSpace(string(content))
}

View File

@@ -2,14 +2,14 @@ package alertmanagerserver
import (
"context"
"fmt"
"github.com/prometheus/alertmanager/types"
"golang.org/x/sync/errgroup"
"log/slog"
"strings"
"sync"
"time"
"github.com/prometheus/alertmanager/types"
"golang.org/x/sync/errgroup"
"github.com/SigNoz/signoz/pkg/alertmanager/alertmanagernotify"
"github.com/SigNoz/signoz/pkg/alertmanager/nfmanager"
"github.com/SigNoz/signoz/pkg/errors"
@@ -395,7 +395,7 @@ func (server *Server) TestAlert(ctx context.Context, receiversMap map[*alertmana
receiver, err := server.alertmanagerConfig.GetReceiver(receiverName)
if err != nil {
mu.Lock()
errs = append(errs, fmt.Errorf("failed to get receiver %q: %w", receiverName, err))
errs = append(errs, errors.WrapInternalf(err, errors.CodeInternal, "failed to get receiver %q", receiverName))
mu.Unlock()
return nil // Return nil to continue processing other goroutines
}
@@ -412,7 +412,7 @@ func (server *Server) TestAlert(ctx context.Context, receiversMap map[*alertmana
)
if err != nil {
mu.Lock()
errs = append(errs, fmt.Errorf("receiver %q test failed: %w", receiverName, err))
errs = append(errs, errors.WrapInternalf(err, errors.CodeInternal, "receiver %q test failed", receiverName))
mu.Unlock()
}
return nil // Return nil to continue processing other goroutines

View File

@@ -2,9 +2,9 @@ package nfmanagertest
import (
"context"
"fmt"
"strings"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/types/alertmanagertypes"
"github.com/prometheus/common/model"
)
@@ -94,7 +94,7 @@ func (m *MockNotificationManager) CreateRoutePolicy(ctx context.Context, orgID s
}
if route == nil {
return fmt.Errorf("route cannot be nil")
return errors.NewInvalidInputf(errors.CodeInvalidInput, "route cannot be nil")
}
if err := route.Validate(); err != nil {
@@ -116,14 +116,14 @@ func (m *MockNotificationManager) CreateRoutePolicies(ctx context.Context, orgID
}
if len(routes) == 0 {
return fmt.Errorf("routes cannot be empty")
return errors.NewInvalidInputf(errors.CodeInvalidInput, "routes cannot be empty")
}
for i, route := range routes {
if route == nil {
return fmt.Errorf("route at index %d cannot be nil", i)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "route at index %d cannot be nil", i)
}
if err := route.Validate(); err != nil {
return fmt.Errorf("route at index %d: %s", i, err.Error())
return errors.WrapInvalidInputf(err, errors.CodeInvalidInput, "route at index %d", i)
}
}
for _, route := range routes {
@@ -142,13 +142,13 @@ func (m *MockNotificationManager) GetRoutePolicyByID(ctx context.Context, orgID
}
if routeID == "" {
return nil, fmt.Errorf("routeID cannot be empty")
return nil, errors.NewInvalidInputf(errors.CodeInvalidInput, "routeID cannot be empty")
}
routeKey := getKey(orgID, routeID)
route, exists := m.routes[routeKey]
if !exists {
return nil, fmt.Errorf("route with ID %s not found", routeID)
return nil, errors.NewNotFoundf(errors.CodeNotFound, "route with ID %s not found", routeID)
}
return route, nil
@@ -161,7 +161,7 @@ func (m *MockNotificationManager) GetAllRoutePolicies(ctx context.Context, orgID
}
if orgID == "" {
return nil, fmt.Errorf("orgID cannot be empty")
return nil, errors.NewInvalidInputf(errors.CodeInvalidInput, "orgID cannot be empty")
}
var routes []*alertmanagertypes.RoutePolicy
@@ -182,13 +182,13 @@ func (m *MockNotificationManager) DeleteRoutePolicy(ctx context.Context, orgID s
}
if routeID == "" {
return fmt.Errorf("routeID cannot be empty")
return errors.NewInvalidInputf(errors.CodeInvalidInput, "routeID cannot be empty")
}
routeKey := getKey(orgID, routeID)
route, exists := m.routes[routeKey]
if !exists {
return fmt.Errorf("route with ID %s not found", routeID)
return errors.NewNotFoundf(errors.CodeNotFound, "route with ID %s not found", routeID)
}
delete(m.routes, routeKey)
@@ -217,11 +217,11 @@ func (m *MockNotificationManager) DeleteAllRoutePoliciesByName(ctx context.Conte
}
if orgID == "" {
return fmt.Errorf("orgID cannot be empty")
return errors.NewInvalidInputf(errors.CodeInvalidInput, "orgID cannot be empty")
}
if name == "" {
return fmt.Errorf("name cannot be empty")
return errors.NewInvalidInputf(errors.CodeInvalidInput, "name cannot be empty")
}
nameKey := getKey(orgID, name)

View File

@@ -1,8 +1,9 @@
package config
import (
"fmt"
"regexp"
"github.com/SigNoz/signoz/pkg/errors"
)
var (
@@ -20,8 +21,9 @@ func NewUri(input string) (Uri, error) {
submatches := uriRegex.FindStringSubmatch(input)
if len(submatches) != 3 {
return Uri{}, fmt.Errorf("invalid uri: %q", input)
return Uri{}, errors.NewInvalidInputf(errors.CodeInvalidInput, "invalid uri: %q", input)
}
return Uri{
scheme: submatches[1],
value: submatches[2],

View File

@@ -1,7 +1,6 @@
package errors
import (
"fmt"
"regexp"
)
@@ -28,7 +27,7 @@ type Code struct{ s string }
func NewCode(s string) (Code, error) {
if !codeRegex.MatchString(s) {
return Code{}, fmt.Errorf("invalid code: %v", s)
return Code{}, NewInvalidInputf(CodeInvalidInput, "invalid code: %v", s)
}
return Code{s: s}, nil

View File

@@ -39,7 +39,7 @@ func (b *base) Error() string {
return b.e.Error()
}
return fmt.Sprintf("%s(%s): %s", b.t.s, b.c, b.m)
return b.m
}
// New returns a base error. It requires type, code and message as input.

View File

@@ -17,7 +17,7 @@ func TestNewf(t *testing.T) {
typ := typ{"test-error"}
err := Newf(typ, MustNewCode("test_code"), "test error info with %s", "string")
assert.NotNil(t, err)
assert.Equal(t, "test-error(test_code): test error info with string", err.Error())
assert.Equal(t, "test error info with string", err.Error())
}
func TestWrapf(t *testing.T) {
@@ -29,10 +29,10 @@ func TestWrapf(t *testing.T) {
func TestError(t *testing.T) {
typ := typ{"test-error"}
err1 := New(typ, MustNewCode("test_code"), "info for err1")
assert.Equal(t, "test-error(test_code): info for err1", err1.Error())
assert.Equal(t, "info for err1", err1.Error())
err2 := Wrapf(err1, typ, MustNewCode("test_code"), "info for err2")
assert.Equal(t, "test-error(test_code): info for err1", err2.Error())
assert.Equal(t, "info for err1", err2.Error())
}
func TestUnwrapb(t *testing.T) {

View File

@@ -1,9 +1,10 @@
package factory
import (
"fmt"
"log/slog"
"regexp"
"github.com/SigNoz/signoz/pkg/errors"
)
var _ slog.LogValuer = (Name{})
@@ -29,7 +30,7 @@ func (n Name) String() string {
// NewName creates a new name.
func NewName(name string) (Name, error) {
if !nameRegex.MatchString(name) {
return Name{}, fmt.Errorf("invalid factory name %q", name)
return Name{}, errors.NewInvalidInputf(errors.CodeInvalidInput, "invalid factory name %q", name)
}
return Name{name: name}, nil
}

View File

@@ -1,6 +1,8 @@
package factory
import "fmt"
import (
"github.com/SigNoz/signoz/pkg/errors"
)
// Named is implemented by all types of factories.
type Named interface {
@@ -18,7 +20,11 @@ func NewNamedMap[T Named](factories ...T) (NamedMap[T], error) {
fmap := make(map[Name]T)
for _, factory := range factories {
if _, ok := fmap[factory.Name()]; ok {
return NamedMap[T]{}, fmt.Errorf("cannot build factory map, duplicate name %q found", factory.Name())
return NamedMap[T]{}, errors.NewInvalidInputf(
errors.CodeInvalidInput,
"cannot build factory map, duplicate name %q found",
factory.Name(),
)
}
fmap[factory.Name()] = factory
@@ -47,7 +53,11 @@ func (n *NamedMap[T]) Get(namestr string) (t T, err error) {
factory, ok := n.factories[name]
if !ok {
err = fmt.Errorf("factory %q not found or not registered", name)
err = errors.NewNotFoundf(
errors.CodeNotFound,
"factory %q not found or not registered",
name,
)
return
}
@@ -60,7 +70,12 @@ func (n *NamedMap[T]) Get(namestr string) (t T, err error) {
func (n *NamedMap[T]) Add(factory T) (err error) {
name := factory.Name()
if _, ok := n.factories[name]; ok {
return fmt.Errorf("factory %q already exists", name)
return errors.Newf(
errors.TypeAlreadyExists,
errors.CodeAlreadyExists,
"factory %q already exists",
name,
)
}
n.factories[name] = factory

View File

@@ -2,10 +2,11 @@ package middleware
import (
"bufio"
"fmt"
"io"
"net"
"net/http"
"github.com/SigNoz/signoz/pkg/errors"
)
const (
@@ -100,7 +101,7 @@ func (writer *nonFlushingBadResponseLoggingWriter) Hijack() (net.Conn, *bufio.Re
if ok {
return hj.Hijack()
}
return nil, nil, fmt.Errorf("cannot cast underlying response writer to Hijacker")
return nil, nil, errors.NewInternalf(errors.CodeInternal, "cannot cast underlying response writer to Hijacker")
}
func (writer *nonFlushingBadResponseLoggingWriter) StatusCode() int {

View File

@@ -2,11 +2,11 @@ package server
import (
"context"
"fmt"
"log/slog"
"net/http"
"time"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/factory"
)
@@ -21,11 +21,11 @@ type Server struct {
func New(logger *slog.Logger, cfg Config, handler http.Handler) (*Server, error) {
if handler == nil {
return nil, fmt.Errorf("cannot build http server, handler is required")
return nil, errors.NewInvalidInputf(errors.CodeInvalidInput, "cannot build http server, handler is required")
}
if logger == nil {
return nil, fmt.Errorf("cannot build http server, logger is required")
return nil, errors.NewInvalidInputf(errors.CodeInvalidInput, "cannot build http server, logger is required")
}
srv := &http.Server{

View File

@@ -40,10 +40,10 @@ func (rws readerWithServer) Shutdown(ctx context.Context) error {
func prometheusReaderWithCustomRegistry(ctx context.Context, prometheusConfig *contribsdkconfig.Prometheus, customRegistry *prometheus.Registry) (sdkmetric.Reader, error) {
var opts []otelprom.Option
if prometheusConfig.Host == nil {
return nil, fmt.Errorf("host must be specified")
return nil, errors.NewInvalidInputf(errors.CodeInvalidInput, "host must be specified")
}
if prometheusConfig.Port == nil {
return nil, fmt.Errorf("port must be specified")
return nil, errors.NewInvalidInputf(errors.CodeInvalidInput, "port must be specified")
}
if prometheusConfig.WithoutScopeInfo != nil && *prometheusConfig.WithoutScopeInfo {
opts = append(opts, otelprom.WithoutScopeInfo())

View File

@@ -3,10 +3,10 @@ package implsavedview
import (
"context"
"encoding/json"
"fmt"
"strings"
"time"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/modules/savedview"
v3 "github.com/SigNoz/signoz/pkg/query-service/model/v3"
"github.com/SigNoz/signoz/pkg/sqlstore"
@@ -32,7 +32,7 @@ func (module *module) GetViewsForFilters(ctx context.Context, orgID string, sour
err = module.sqlstore.BunDB().NewSelect().Model(&views).Where("org_id = ? AND source_page = ? AND category LIKE ? AND name LIKE ?", orgID, sourcePage, "%"+category+"%", "%"+name+"%").Scan(ctx)
}
if err != nil {
return nil, fmt.Errorf("error in getting saved views: %s", err.Error())
return nil, errors.WrapInternalf(err, errors.CodeInternal, "error in getting saved views")
}
var savedViews []*v3.SavedView
@@ -40,7 +40,7 @@ func (module *module) GetViewsForFilters(ctx context.Context, orgID string, sour
var compositeQuery v3.CompositeQuery
err = json.Unmarshal([]byte(view.Data), &compositeQuery)
if err != nil {
return nil, fmt.Errorf("error in unmarshalling explorer query data: %s", err.Error())
return nil, errors.WrapInternalf(err, errors.CodeInternal, "error in unmarshalling explorer query data: %s", err.Error())
}
savedViews = append(savedViews, &v3.SavedView{
ID: view.ID,
@@ -61,7 +61,7 @@ func (module *module) GetViewsForFilters(ctx context.Context, orgID string, sour
func (module *module) CreateView(ctx context.Context, orgID string, view v3.SavedView) (valuer.UUID, error) {
data, err := json.Marshal(view.CompositeQuery)
if err != nil {
return valuer.UUID{}, fmt.Errorf("error in marshalling explorer query data: %s", err.Error())
return valuer.UUID{}, errors.WrapInternalf(err, errors.CodeInternal, "error in marshalling explorer query data")
}
uuid := valuer.GenerateUUID()
@@ -70,7 +70,7 @@ func (module *module) CreateView(ctx context.Context, orgID string, view v3.Save
claims, errv2 := authtypes.ClaimsFromContext(ctx)
if errv2 != nil {
return valuer.UUID{}, fmt.Errorf("error in getting email from context")
return valuer.UUID{}, errors.NewInternalf(errors.CodeInternal, "error in getting email from context")
}
createBy := claims.Email
@@ -99,7 +99,7 @@ func (module *module) CreateView(ctx context.Context, orgID string, view v3.Save
_, err = module.sqlstore.BunDB().NewInsert().Model(&dbView).Exec(ctx)
if err != nil {
return valuer.UUID{}, fmt.Errorf("error in creating saved view: %s", err.Error())
return valuer.UUID{}, errors.WrapInternalf(err, errors.CodeInternal, "error in creating saved view")
}
return uuid, nil
}
@@ -108,13 +108,13 @@ func (module *module) GetView(ctx context.Context, orgID string, uuid valuer.UUI
var view types.SavedView
err := module.sqlstore.BunDB().NewSelect().Model(&view).Where("org_id = ? AND id = ?", orgID, uuid.StringValue()).Scan(ctx)
if err != nil {
return nil, fmt.Errorf("error in getting saved view: %s", err.Error())
return nil, errors.WrapInternalf(err, errors.CodeInternal, "error in getting saved view")
}
var compositeQuery v3.CompositeQuery
err = json.Unmarshal([]byte(view.Data), &compositeQuery)
if err != nil {
return nil, fmt.Errorf("error in unmarshalling explorer query data: %s", err.Error())
return nil, errors.WrapInternalf(err, errors.CodeInternal, "error in unmarshalling explorer query data")
}
return &v3.SavedView{
ID: view.ID,
@@ -134,12 +134,12 @@ func (module *module) GetView(ctx context.Context, orgID string, uuid valuer.UUI
func (module *module) UpdateView(ctx context.Context, orgID string, uuid valuer.UUID, view v3.SavedView) error {
data, err := json.Marshal(view.CompositeQuery)
if err != nil {
return fmt.Errorf("error in marshalling explorer query data: %s", err.Error())
return errors.WrapInternalf(err, errors.CodeInternal, "error in marshalling explorer query data")
}
claims, errv2 := authtypes.ClaimsFromContext(ctx)
if errv2 != nil {
return fmt.Errorf("error in getting email from context")
return errors.NewInternalf(errors.CodeInternal, "error in getting email from context")
}
updatedAt := time.Now()
@@ -153,7 +153,7 @@ func (module *module) UpdateView(ctx context.Context, orgID string, uuid valuer.
Where("org_id = ?", orgID).
Exec(ctx)
if err != nil {
return fmt.Errorf("error in updating saved view: %s", err.Error())
return errors.WrapInternalf(err, errors.CodeInternal, "error in updating saved view")
}
return nil
}
@@ -165,7 +165,7 @@ func (module *module) DeleteView(ctx context.Context, orgID string, uuid valuer.
Where("org_id = ?", orgID).
Exec(ctx)
if err != nil {
return fmt.Errorf("error in deleting explorer query: %s", err.Error())
return errors.WrapInternalf(err, errors.CodeInternal, "error in deleting explorer query")
}
return nil
}

View File

@@ -15,9 +15,9 @@ func TestBuildFunnelOverviewQuery_WithLatencyPointer(t *testing.T) {
LatencyPointer string
Clause string
}
startTs int64
endTs int64
wantContains []string
startTs int64
endTs int64
wantContains []string
wantNotContains []string
}{
{
@@ -86,13 +86,13 @@ func TestBuildFunnelOverviewQuery_WithLatencyPointer(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
query := BuildFunnelOverviewQuery(tt.steps, tt.startTs, tt.endTs)
for _, want := range tt.wantContains {
if !strings.Contains(query, want) {
t.Errorf("Query missing expected content: %s", want)
}
}
for _, notWant := range tt.wantNotContains {
if strings.Contains(query, notWant) {
t.Errorf("Query contains unexpected content: %s", notWant)
@@ -142,7 +142,7 @@ func TestBuildFunnelStepOverviewQuery_WithLatencyPointer(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
query := BuildFunnelStepOverviewQuery(tt.steps, 1000000000, 2000000000, tt.stepStart, tt.stepEnd)
for _, want := range tt.wantContains {
if !strings.Contains(query, want) {
t.Errorf("Query missing expected content: %s", want)
@@ -154,10 +154,10 @@ func TestBuildFunnelStepOverviewQuery_WithLatencyPointer(t *testing.T) {
func TestBuildFunnelTopSlowTracesQuery_WithLatencyPointer(t *testing.T) {
tests := []struct {
name string
latencyPointerT1 string
latencyPointerT2 string
wantContains []string
name string
latencyPointerT1 string
latencyPointerT2 string
wantContains []string
}{
{
name: "both steps with end latency",
@@ -199,7 +199,7 @@ func TestBuildFunnelTopSlowTracesQuery_WithLatencyPointer(t *testing.T) {
tt.latencyPointerT1,
tt.latencyPointerT2,
)
for _, want := range tt.wantContains {
if !strings.Contains(query, want) {
t.Errorf("Query missing expected content: %s", want)
@@ -211,10 +211,10 @@ func TestBuildFunnelTopSlowTracesQuery_WithLatencyPointer(t *testing.T) {
func TestBuildFunnelTopSlowErrorTracesQuery_WithLatencyPointer(t *testing.T) {
tests := []struct {
name string
latencyPointerT1 string
latencyPointerT2 string
wantContains []string
name string
latencyPointerT1 string
latencyPointerT2 string
wantContains []string
}{
{
name: "both steps with end latency",
@@ -247,7 +247,7 @@ func TestBuildFunnelTopSlowErrorTracesQuery_WithLatencyPointer(t *testing.T) {
tt.latencyPointerT1,
tt.latencyPointerT2,
)
for _, want := range tt.wantContains {
if !strings.Contains(query, want) {
t.Errorf("Query missing expected content: %s", want)
@@ -255,4 +255,4 @@ func TestBuildFunnelTopSlowErrorTracesQuery_WithLatencyPointer(t *testing.T) {
}
})
}
}
}

View File

@@ -7,8 +7,8 @@ import (
func TestBuildFunnelValidationQuery(t *testing.T) {
tests := []struct {
name string
steps []struct {
name string
steps []struct {
ServiceName string
SpanName string
ContainsError int
@@ -90,7 +90,7 @@ func TestBuildFunnelValidationQuery(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := BuildFunnelValidationQuery(tt.steps, tt.startTs, tt.endTs)
for _, want := range tt.wantContains {
if !strings.Contains(got, want) {
t.Errorf("BuildFunnelValidationQuery() missing expected string: %q", want)
@@ -103,8 +103,8 @@ func TestBuildFunnelValidationQuery(t *testing.T) {
func TestBuildFunnelOverviewQuery(t *testing.T) {
tests := []struct {
name string
steps []struct {
name string
steps []struct {
ServiceName string
SpanName string
ContainsError int
@@ -168,7 +168,7 @@ func TestBuildFunnelOverviewQuery(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := BuildFunnelOverviewQuery(tt.steps, tt.startTs, tt.endTs)
for _, want := range tt.wantContains {
if !strings.Contains(got, want) {
t.Errorf("BuildFunnelOverviewQuery() missing expected string: %q", want)
@@ -181,8 +181,8 @@ func TestBuildFunnelOverviewQuery(t *testing.T) {
func TestBuildFunnelCountQuery(t *testing.T) {
tests := []struct {
name string
steps []struct {
name string
steps []struct {
ServiceName string
SpanName string
ContainsError int
@@ -241,7 +241,7 @@ func TestBuildFunnelCountQuery(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := BuildFunnelCountQuery(tt.steps, tt.startTs, tt.endTs)
for _, want := range tt.wantContains {
if !strings.Contains(got, want) {
t.Errorf("BuildFunnelCountQuery() missing expected string: %q", want)
@@ -254,8 +254,8 @@ func TestBuildFunnelCountQuery(t *testing.T) {
func TestBuildFunnelStepOverviewQuery(t *testing.T) {
tests := []struct {
name string
steps []struct {
name string
steps []struct {
ServiceName string
SpanName string
ContainsError int
@@ -347,14 +347,14 @@ func TestBuildFunnelStepOverviewQuery(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := BuildFunnelStepOverviewQuery(tt.steps, tt.startTs, tt.endTs, tt.stepStart, tt.stepEnd)
for _, want := range tt.wantContains {
if !strings.Contains(got, want) {
t.Errorf("BuildFunnelStepOverviewQuery() missing expected string: %q", want)
t.Logf("Got query:\n%s", got)
}
}
if tt.wantFallback && !strings.Contains(got, "SELECT 0 AS conversion_rate") {
t.Errorf("BuildFunnelStepOverviewQuery() expected fallback query for invalid step range")
}
@@ -376,17 +376,17 @@ func TestTemporalOrderingLogic(t *testing.T) {
{ServiceName: "s3", SpanName: "sp3", ContainsError: 0, LatencyPointer: "start", Clause: ""},
{ServiceName: "s4", SpanName: "sp4", ContainsError: 0, LatencyPointer: "start", Clause: ""},
}, 1000000000, 2000000000)
// Check that each step has proper temporal ordering (cumulative format)
temporalChecks := []string{
"t2_time > t1_time",
"t2_time > t1_time AND t3_time > t2_time",
"t2_time > t1_time AND t3_time > t2_time AND t4_time > t3_time",
}
for _, check := range temporalChecks {
if !strings.Contains(query, check) {
t.Errorf("Missing temporal ordering check: %s", check)
}
}
}
}

View File

@@ -2,9 +2,9 @@ package impltracefunnel
import (
"context"
"fmt"
"time"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/modules/tracefunnel"
"github.com/SigNoz/signoz/pkg/types"
traceFunnels "github.com/SigNoz/signoz/pkg/types/tracefunneltypes"
@@ -76,7 +76,7 @@ func (module *module) Update(ctx context.Context, funnel *traceFunnels.StorableF
func (module *module) List(ctx context.Context, orgID valuer.UUID) ([]*traceFunnels.StorableFunnel, error) {
funnels, err := module.store.List(ctx, orgID)
if err != nil {
return nil, fmt.Errorf("failed to list funnels: %v", err)
return nil, errors.WrapInternalf(err, errors.CodeInternal, "failed to list funnels")
}
return funnels, nil

View File

@@ -110,12 +110,12 @@ func (store *store) Update(ctx context.Context, funnel *traceFunnels.StorableFun
if err != nil {
return errors.Wrapf(err, errors.TypeInternal, errors.CodeInternal, "failed to update funnel")
}
err = tx.Commit()
if err != nil {
return errors.Wrapf(err, errors.TypeInternal, errors.CodeInternal, "failed to commit transaction")
}
return nil
}

View File

@@ -46,7 +46,7 @@ func TestModule_Update_DuplicateNameValidation(t *testing.T) {
userID := valuer.GenerateUUID()
orgID := valuer.GenerateUUID()
funnelName := "Duplicate Name"
funnel := &traceFunnels.StorableFunnel{
Name: funnelName,
OrgID: orgID,
@@ -93,4 +93,4 @@ func (m *MockStore) Update(ctx context.Context, funnel *traceFunnels.StorableFun
func (m *MockStore) Delete(ctx context.Context, uuid valuer.UUID, orgID valuer.UUID) error {
args := m.Called(ctx, uuid, orgID)
return args.Error(0)
}
}

View File

@@ -1,9 +1,9 @@
package tracefunnel
import (
"fmt"
"strings"
"github.com/SigNoz/signoz/pkg/errors"
tracev4 "github.com/SigNoz/signoz/pkg/query-service/app/traces/v4"
v3 "github.com/SigNoz/signoz/pkg/query-service/model/v3"
"github.com/SigNoz/signoz/pkg/types/tracefunneltypes"
@@ -113,7 +113,7 @@ func GetFunnelAnalytics(funnel *tracefunneltypes.StorableFunnel, timeRange trace
func GetFunnelStepAnalytics(funnel *tracefunneltypes.StorableFunnel, timeRange tracefunneltypes.TimeRange, stepStart, stepEnd int64) (*v3.ClickHouseQuery, error) {
if stepStart == stepEnd {
return nil, fmt.Errorf("step start and end cannot be the same for /step/overview")
return nil, errors.NewInvalidInputf(errors.CodeInvalidInput, "step start and end cannot be the same for /step/overview")
}
funnelSteps := funnel.Steps

View File

@@ -74,7 +74,7 @@ func TestValidateTracesMultipleSteps(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := ValidateTraces(tt.funnel, tt.timeRange)
if tt.expectError && err == nil {
t.Errorf("ValidateTraces() expected error but got none")
}
@@ -150,7 +150,7 @@ func TestGetFunnelAnalyticsMultipleSteps(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := GetFunnelAnalytics(tt.funnel, tt.timeRange)
if tt.expectError && err == nil {
t.Errorf("GetFunnelAnalytics() expected error but got none")
}
@@ -177,14 +177,14 @@ func TestGetStepAnalyticsMultipleSteps(t *testing.T) {
{ServiceName: "s5", SpanName: "sp5", HasErrors: true, Filters: &v3.FilterSet{}},
},
}
timeRange := tracefunneltypes.TimeRange{
StartTime: 1000000000,
EndTime: 2000000000,
}
result, err := GetStepAnalytics(funnel, timeRange)
if err != nil {
t.Errorf("GetStepAnalytics() unexpected error: %v", err)
}
@@ -246,7 +246,7 @@ func TestGetFunnelStepAnalyticsMultipleSteps(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := GetFunnelStepAnalytics(tt.funnel, tt.timeRange, tt.stepStart, tt.stepEnd)
if tt.expectError && err == nil {
t.Errorf("GetFunnelStepAnalytics() expected error but got none")
}
@@ -268,4 +268,4 @@ func init() {
// This would normally be handled by the actual implementation
// For testing purposes, we'll assume it returns an empty string
_ = tracev4.BuildTracesFilterQuery
}
}

View File

@@ -3,12 +3,13 @@ package clickhouseprometheus
import (
"context"
"fmt"
"github.com/SigNoz/signoz/pkg/query-service/constants"
"math"
"strconv"
"strings"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/query-service/constants"
"github.com/SigNoz/signoz/pkg/telemetrystore"
promValue "github.com/prometheus/prometheus/model/value"
"github.com/prometheus/prometheus/prompb"
@@ -122,7 +123,7 @@ func (client *client) queryToClickhouseQuery(_ context.Context, query *prompb.Qu
case prompb.LabelMatcher_NRE:
conditions = append(conditions, fmt.Sprintf("not match(JSONExtractString(labels, $%d), $%d)", argCount+2, argCount+3))
default:
return "", nil, fmt.Errorf("unexpected matcher found in query: %s", m.Type.String())
return "", nil, errors.NewInvalidInputf(errors.CodeInvalidInput, "unsupported or invalid matcher type: %s", m.Type.String())
}
args = append(args, m.Name, m.Value)
argCount += 2

View File

@@ -1,7 +1,7 @@
package prometheus
import (
"fmt"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/prometheus/prometheus/promql"
)
@@ -43,7 +43,7 @@ func RemoveExtraLabels(res *promql.Result, labelsToRemove ...string) error {
case promql.Scalar:
return nil
default:
return fmt.Errorf("rule result is not a vector or scalar or matrix")
return errors.NewInternalf(errors.CodeInternal, "rule result is not a vector or scalar or matrix")
}
return nil
}

View File

@@ -237,7 +237,6 @@ func postProcessTraceOperator(
return result
}
// applyMetricReduceTo applies reduce to operation using the metric's ReduceTo field
func (q *querier) applyMetricReduceTo(result *qbtypes.Result, reduceOp qbtypes.ReduceTo) *qbtypes.Result {
tsData, ok := result.Value.(*qbtypes.TimeSeriesData)

View File

@@ -140,7 +140,7 @@ func (q *querier) QueryRange(ctx context.Context, orgID valuer.UUID, req *qbtype
if spec, ok := query.Spec.(qbtypes.QueryBuilderTraceOperator); ok {
// Parse expression to find dependencies
if err := spec.ParseExpression(); err != nil {
return nil, fmt.Errorf("failed to parse trace operator expression: %w", err)
return nil, err
}
deps := spec.CollectReferencedQueries(spec.ParsedExpression)
@@ -652,7 +652,7 @@ func (q *querier) executeWithCache(ctx context.Context, orgID valuer.UUID, query
// Execute queries for missing ranges with bounded parallelism
freshResults := make([]*qbtypes.Result, len(missingRanges))
errors := make([]error, len(missingRanges))
errs := make([]error, len(missingRanges))
totalStats := qbtypes.ExecStats{}
q.logger.DebugContext(ctx, "executing queries for missing ranges",
@@ -673,14 +673,14 @@ func (q *querier) executeWithCache(ctx context.Context, orgID valuer.UUID, query
// Create a new query with the missing time range
rangedQuery := q.createRangedQuery(query, *tr)
if rangedQuery == nil {
errors[idx] = fmt.Errorf("failed to create ranged query for range %d-%d", tr.From, tr.To)
errs[idx] = errors.NewInternalf(errors.CodeInternal, "failed to create ranged query for range %d-%d", tr.From, tr.To)
return
}
// Execute the ranged query
result, err := rangedQuery.Execute(ctx)
if err != nil {
errors[idx] = err
errs[idx] = err
return
}
@@ -692,7 +692,7 @@ func (q *querier) executeWithCache(ctx context.Context, orgID valuer.UUID, query
wg.Wait()
// Check for errors
for _, err := range errors {
for _, err := range errs {
if err != nil {
// If any query failed, fall back to full execution
q.logger.ErrorContext(ctx, "parallel query execution failed", "error", err)

View File

@@ -87,4 +87,3 @@ func (q *traceOperatorQuery) executeWithContext(ctx context.Context, query strin
},
}, nil
}

View File

@@ -5,6 +5,7 @@ import (
"strconv"
"strings"
"github.com/SigNoz/signoz/pkg/errors"
grammar "github.com/SigNoz/signoz/pkg/parser/grammar"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/antlr4-go/antlr/v4"
@@ -54,7 +55,7 @@ func DetectContradictions(query string) ([]string, error) {
// Check for syntax errors
if len(parserErrorListener.SyntaxErrors) > 0 {
return nil, fmt.Errorf("syntax errors: %v", parserErrorListener.SyntaxErrors)
return nil, errors.NewInvalidInputf(errors.CodeInvalidInput, "syntax errors: %v", parserErrorListener.SyntaxErrors)
}
// Create detector and visit tree
@@ -856,7 +857,7 @@ func parseNumericValue(value interface{}) (float64, error) {
case string:
return strconv.ParseFloat(v, 64)
default:
return 0, fmt.Errorf("not a numeric value")
return 0, errors.NewInvalidInputf(errors.CodeInvalidInput, "not a numeric value")
}
}

View File

@@ -119,7 +119,7 @@ func (b *resourceFilterStatementBuilder[T]) Build(
) (*qbtypes.Statement, error) {
config, exists := signalConfigs[b.signal]
if !exists {
return nil, fmt.Errorf("%w: %s", ErrUnsupportedSignal, b.signal)
return nil, errors.WrapInvalidInputf(ErrUnsupportedSignal, errors.CodeInvalidInput, "unsupported signal: %s", b.signal)
}
q := sqlbuilder.NewSelectBuilder()

View File

@@ -2,7 +2,6 @@ package signoz
import (
"context"
"fmt"
"log/slog"
"net/url"
"os"
@@ -16,6 +15,7 @@ import (
"github.com/SigNoz/signoz/pkg/cache"
"github.com/SigNoz/signoz/pkg/config"
"github.com/SigNoz/signoz/pkg/emailing"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/gateway"
"github.com/SigNoz/signoz/pkg/instrumentation"
@@ -182,11 +182,11 @@ func validateConfig(config Config) error {
for i := 0; i < rvConfig.NumField(); i++ {
factoryConfig, ok := rvConfig.Field(i).Interface().(factory.Config)
if !ok {
return fmt.Errorf("%q is not of type \"factory.Config\"", rvConfig.Type().Field(i).Name)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "%q is not of type \"factory.Config\"", rvConfig.Type().Field(i).Name)
}
if err := factoryConfig.Validate(); err != nil {
return fmt.Errorf("failed to validate config %q: %w", rvConfig.Type().Field(i).Tag.Get("mapstructure"), err)
return errors.WrapInvalidInputf(err, errors.CodeInvalidInput, "failed to validate config %q", rvConfig.Type().Field(i).Tag.Get("mapstructure"))
}
}

View File

@@ -117,7 +117,7 @@ func (c *Client) Do(ctx context.Context, tos []*mail.Address, subject string, co
if c.hello != "" {
err = smtpClient.Hello(c.hello)
if err != nil {
return fmt.Errorf("failed to send EHLO command: %w", err)
return errors.WrapInternalf(err, errors.CodeInternal, "failed to send EHLO command")
}
}
@@ -125,7 +125,7 @@ func (c *Client) Do(ctx context.Context, tos []*mail.Address, subject string, co
if !c.tls.Enabled {
if ok, _ := smtpClient.Extension("STARTTLS"); ok {
if err := smtpClient.StartTLS(c.tlsConfig); err != nil {
return fmt.Errorf("failed to send STARTTLS command: %w", err)
return errors.WrapInternalf(err, errors.CodeInternal, "failed to send STARTTLS command")
}
}
}
@@ -136,32 +136,32 @@ func (c *Client) Do(ctx context.Context, tos []*mail.Address, subject string, co
if c.auth.Username != "" {
auth, err := c.smtpAuth(ctx, mech)
if err != nil {
return fmt.Errorf("failed to find auth mechanism: %w", err)
return errors.WrapInternalf(err, errors.CodeInternal, "failed to find auth mechanism")
}
// Send the AUTH command.
if err := smtpClient.Auth(auth); err != nil {
return fmt.Errorf("failed to auth: %T: %w", auth, err)
return errors.WrapInternalf(err, errors.CodeInternal, "failed to auth: %T", auth)
}
}
}
// Send the MAIL command.
if err = smtpClient.Mail(c.from.Address); err != nil {
return fmt.Errorf("failed to send MAIL command: %w", err)
return errors.WrapInternalf(err, errors.CodeInternal, "failed to send MAIL command")
}
// Send the RCPT command for each recipient.
for _, addr := range tos {
if err = smtpClient.Rcpt(addr.Address); err != nil {
return fmt.Errorf("failed to send RCPT command: %w", err)
return errors.WrapInternalf(err, errors.CodeInternal, "failed to send RCPT command")
}
}
// Send the email headers and body.
message, err := smtpClient.Data()
if err != nil {
return fmt.Errorf("failed to send DATA command: %w", err)
return errors.WrapInternalf(err, errors.CodeInternal, "failed to send DATA command")
}
closeOnce := sync.OnceValue(func() error {
@@ -200,7 +200,7 @@ func (c *Client) Do(ctx context.Context, tos []*mail.Address, subject string, co
_, err = message.Write(buffer.Bytes())
if err != nil {
return fmt.Errorf("failed to write headers: %w", err)
return errors.WrapInternalf(err, errors.CodeInternal, "failed to write headers")
}
// Text template
@@ -210,17 +210,17 @@ func (c *Client) Do(ctx context.Context, tos []*mail.Address, subject string, co
"Content-Type": {"text/plain; charset=UTF-8"},
})
if err != nil {
return fmt.Errorf("failed to create part for text template: %w", err)
return errors.WrapInternalf(err, errors.CodeInternal, "failed to create part for text template")
}
qw := quotedprintable.NewWriter(w)
_, err = qw.Write([]byte(body))
if err != nil {
return fmt.Errorf("failed to write text part: %w", err)
return errors.WrapInternalf(err, errors.CodeInternal, "failed to write text part")
}
err = qw.Close()
if err != nil {
return fmt.Errorf("failed to close text part: %w", err)
return errors.WrapInternalf(err, errors.CodeInternal, "failed to close text part")
}
}
@@ -233,33 +233,33 @@ func (c *Client) Do(ctx context.Context, tos []*mail.Address, subject string, co
"Content-Type": {"text/html; charset=UTF-8"},
})
if err != nil {
return fmt.Errorf("failed to create part for html template: %w", err)
return errors.WrapInternalf(err, errors.CodeInternal, "failed to create part for html template")
}
qw := quotedprintable.NewWriter(w)
_, err = qw.Write([]byte(body))
if err != nil {
return fmt.Errorf("failed to write HTML part: %w", err)
return errors.WrapInternalf(err, errors.CodeInternal, "failed to write HTML part")
}
err = qw.Close()
if err != nil {
return fmt.Errorf("failed to close HTML part: %w", err)
return errors.WrapInternalf(err, errors.CodeInternal, "failed to close HTML part")
}
}
err = multipartWriter.Close()
if err != nil {
return fmt.Errorf("failed to close multipartWriter: %w", err)
return errors.WrapInternalf(err, errors.CodeInternal, "failed to close multipartWriter")
}
_, err = message.Write(multipartBuffer.Bytes())
if err != nil {
return fmt.Errorf("failed to write body buffer: %w", err)
return errors.WrapInternalf(err, errors.CodeInternal, "failed to write body buffer")
}
// Complete the message and await response.
if err = closeOnce(); err != nil {
return fmt.Errorf("failed to deliver: %w", err)
return errors.WrapInternalf(err, errors.CodeInternal, "failed to deliver")
}
success = true
@@ -317,7 +317,7 @@ func (c *Client) dial(ctx context.Context) (net.Conn, error) {
if c.tls.Enabled || c.port == "465" {
conn, err = tls.Dial("tcp", c.address, c.tlsConfig)
if err != nil {
return nil, fmt.Errorf("failed to establish TLS connection to server: %w", err)
return nil, errors.WrapInternalf(err, errors.CodeInternal, "failed to establish TLS connection to server")
}
return conn, nil
@@ -326,7 +326,7 @@ func (c *Client) dial(ctx context.Context) (net.Conn, error) {
var d net.Dialer
conn, err = d.DialContext(ctx, "tcp", c.address)
if err != nil {
return nil, fmt.Errorf("failed to establish connection to server: %w", err)
return nil, errors.WrapInternalf(err, errors.CodeInternal, "failed to establish connection to server")
}
return conn, nil
@@ -341,7 +341,7 @@ func newTLSConfig(config TLS, serverName string) (*tls.Config, error) {
if config.CertFilePath != "" {
cert, err := tls.LoadX509KeyPair(config.CertFilePath, config.KeyFilePath)
if err != nil {
return nil, fmt.Errorf("failed to load cert or key file: %w", err)
return nil, errors.WrapInternalf(err, errors.CodeInternal, "failed to load cert or key file")
}
tlsConfig.Certificates = []tls.Certificate{cert}
}
@@ -349,11 +349,11 @@ func newTLSConfig(config TLS, serverName string) (*tls.Config, error) {
if config.CAFilePath != "" {
ca, err := os.ReadFile(config.CAFilePath)
if err != nil {
return nil, fmt.Errorf("failed to load CA file: %w", err)
return nil, errors.WrapInternalf(err, errors.CodeInternal, "failed to load CA file")
}
tlsConfig.RootCAs = x509.NewCertPool()
if !tlsConfig.RootCAs.AppendCertsFromPEM(ca) {
return nil, fmt.Errorf("failed to append CA file: %s", config.CAFilePath)
return nil, errors.WrapInternalf(err, errors.CodeInternal, "failed to append CA file: %s", config.CAFilePath)
}
}

View File

@@ -251,7 +251,7 @@ func parseAllColumns(in string) ([]sqlschema.ColumnName, error) {
quote = ']'
continue
} else if s[i] == ')' {
return columns, fmt.Errorf("unexpected token: %s", string(s[i]))
return columns, errors.NewInternalf(ErrCodeInvalidDDL, "unexpected token: %s", string(s[i]))
}
state = parseAllColumnsState_ReadingRawName
name = append(name, s[i])
@@ -267,7 +267,7 @@ func parseAllColumns(in string) ([]sqlschema.ColumnName, error) {
columns = append(columns, sqlschema.ColumnName(name))
}
if isQuote(s[i]) {
return nil, fmt.Errorf("unexpected token: %s", string(s[i]))
return nil, errors.NewInternalf(ErrCodeInvalidDDL, "unexpected token: %s", string(s[i]))
}
if isSpace(s[i]) {
state = parseAllColumnsState_EndOfName

View File

@@ -3,7 +3,6 @@ package sqlstoretest
import (
"context"
"database/sql"
"fmt"
"github.com/DATA-DOG/go-sqlmock"
"github.com/SigNoz/signoz/pkg/errors"
@@ -35,7 +34,7 @@ func New(config sqlstore.Config, matcher sqlmock.QueryMatcher) *Provider {
} else if config.Provider == "postgres" {
bunDB = bun.NewDB(db, pgdialect.New())
} else {
panic(fmt.Errorf("provider %q is not supported", config.Provider))
panic(errors.NewInvalidInputf(errors.CodeInvalidInput, "provider %q is not supported", config.Provider))
}
return &Provider{
@@ -71,9 +70,9 @@ func (provider *Provider) RunInTxCtx(ctx context.Context, opts *sql.TxOptions, c
}
func (provider *Provider) WrapNotFoundErrf(err error, code errors.Code, format string, args ...any) error {
return fmt.Errorf(format, args...)
return errors.WrapNotFoundf(err, code, format, args...)
}
func (provider *Provider) WrapAlreadyExistsErrf(err error, code errors.Code, format string, args ...any) error {
return fmt.Errorf(format, args...)
return errors.Wrapf(err, errors.TypeAlreadyExists, code, format, args...)
}

View File

@@ -7,6 +7,7 @@ import (
"strings"
schema "github.com/SigNoz/signoz-otel-collector/cmd/signozschemamigrator/schema_migrator"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/querybuilder"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
@@ -205,10 +206,10 @@ func (c *conditionBuilder) conditionFor(
return sb.NE(leftOperand, true), nil
}
default:
return "", fmt.Errorf("exists operator is not supported for column type %s", column.Type)
return "", errors.NewInvalidInputf(errors.CodeInvalidInput, "exists operator is not supported for column type %s", column.Type)
}
}
return "", fmt.Errorf("unsupported operator: %v", operator)
return "", errors.NewInvalidInputf(errors.CodeInvalidInput, "unsupported operator: %v", operator)
}
func (c *conditionBuilder) ConditionFor(

View File

@@ -6,6 +6,7 @@ import (
"log/slog"
"strings"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/querybuilder"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
@@ -87,7 +88,7 @@ func (b *logQueryStatementBuilder) Build(
return b.buildScalarQuery(ctx, q, query, start, end, keys, false, variables)
}
return nil, fmt.Errorf("unsupported request type: %s", requestType)
return nil, errors.NewInvalidInputf(errors.CodeInvalidInput, "unsupported request type: %s", requestType)
}
func getKeySelectors(query qbtypes.QueryBuilderQuery[qbtypes.LogAggregation]) []*telemetrytypes.FieldKeySelector {

View File

@@ -2,10 +2,10 @@ package telemetrymetadata
import (
"context"
"fmt"
"regexp"
"testing"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/instrumentation/instrumentationtest"
"github.com/SigNoz/signoz/pkg/telemetrylogs"
"github.com/SigNoz/signoz/pkg/telemetrymeter"
@@ -28,7 +28,7 @@ func (m *regexMatcher) Match(expectedSQL, actualSQL string) error {
return err
}
if !re.MatchString(actualSQL) {
return fmt.Errorf("expected query to contain %s, got %s", expectedSQL, actualSQL)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "expected query to contain %s, got %s", expectedSQL, actualSQL)
}
return nil
}

View File

@@ -211,7 +211,7 @@ func (c *conditionBuilder) conditionFor(
return sb.NE(leftOperand, true), nil
}
default:
return "", fmt.Errorf("exists operator is not supported for column type %s", column.Type)
return "", errors.NewInvalidInputf(errors.CodeInvalidInput, "exists operator is not supported for column type %s", column.Type)
}
}
return "", nil

View File

@@ -82,9 +82,9 @@ func (b *traceQueryStatementBuilder) Build(
if found && len(traceIDs) > 0 {
finder := NewTraceTimeRangeFinder(b.telemetryStore)
traceStart, traceEnd, err := finder.GetTraceTimeRangeMulti(ctx, traceIDs)
if err != nil {
b.logger.DebugContext(ctx, "failed to get trace time range", "trace_ids", traceIDs, "error", err)
traceStart, traceEnd, ok := finder.GetTraceTimeRangeMulti(ctx, traceIDs)
if !ok {
b.logger.DebugContext(ctx, "failed to get trace time range", "trace_ids", traceIDs)
} else if traceStart > 0 && traceEnd > 0 {
start = uint64(traceStart)
end = uint64(traceEnd)
@@ -107,7 +107,7 @@ func (b *traceQueryStatementBuilder) Build(
return b.buildTraceQuery(ctx, q, query, start, end, keys, variables)
}
return nil, fmt.Errorf("unsupported request type: %s", requestType)
return nil, errors.NewInvalidInputf(errors.CodeInvalidInput, "unsupported request type: %s", requestType)
}
func getKeySelectors(query qbtypes.QueryBuilderQuery[qbtypes.TraceAggregation]) []*telemetrytypes.FieldKeySelector {

View File

@@ -3,12 +3,13 @@ package telemetrytraces
import (
"context"
"fmt"
"strings"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/querybuilder"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
"github.com/huandu/go-sqlbuilder"
"strings"
)
type cteNode struct {
@@ -402,7 +403,7 @@ func (b *traceOperatorCTEBuilder) buildFinalQuery(ctx context.Context, selectFro
case qbtypes.RequestTypeScalar:
return b.buildScalarQuery(ctx, selectFromCTE)
default:
return nil, fmt.Errorf("unsupported request type: %s", requestType)
return nil, errors.NewInvalidInputf(errors.CodeInvalidInput, "unsupported request type: %s", requestType)
}
}

View File

@@ -2,7 +2,6 @@ package telemetrytraces
import (
"context"
"database/sql"
"fmt"
"strings"
@@ -19,14 +18,14 @@ func NewTraceTimeRangeFinder(telemetryStore telemetrystore.TelemetryStore) *Trac
}
}
func (f *TraceTimeRangeFinder) GetTraceTimeRange(ctx context.Context, traceID string) (startNano, endNano int64, err error) {
func (f *TraceTimeRangeFinder) GetTraceTimeRange(ctx context.Context, traceID string) (startNano, endNano int64, ok bool) {
traceIDs := []string{traceID}
return f.GetTraceTimeRangeMulti(ctx, traceIDs)
}
func (f *TraceTimeRangeFinder) GetTraceTimeRangeMulti(ctx context.Context, traceIDs []string) (startNano, endNano int64, err error) {
func (f *TraceTimeRangeFinder) GetTraceTimeRangeMulti(ctx context.Context, traceIDs []string) (startNano, endNano int64, ok bool) {
if len(traceIDs) == 0 {
return 0, 0, fmt.Errorf("no trace IDs provided")
return 0, 0, false
}
cleanedIDs := make([]string, len(traceIDs))
@@ -51,12 +50,9 @@ func (f *TraceTimeRangeFinder) GetTraceTimeRangeMulti(ctx context.Context, trace
row := f.telemetryStore.ClickhouseDB().QueryRow(ctx, query, args...)
err = row.Scan(&startNano, &endNano)
err := row.Scan(&startNano, &endNano)
if err != nil {
if err == sql.ErrNoRows {
return 0, 0, fmt.Errorf("traces not found: %v", cleanedIDs)
}
return 0, 0, fmt.Errorf("failed to query trace time range: %w", err)
return 0, 0, false
}
if startNano > 1_000_000_000 {
@@ -64,5 +60,5 @@ func (f *TraceTimeRangeFinder) GetTraceTimeRangeMulti(ctx context.Context, trace
}
endNano += 1_000_000_000
return startNano, endNano, nil
return startNano, endNano, true
}

View File

@@ -12,29 +12,29 @@ func TestGetTraceTimeRangeMulti(t *testing.T) {
ctx := context.Background()
tests := []struct {
name string
traceIDs []string
expectErr bool
name string
traceIDs []string
expectOK bool
}{
{
name: "single trace ID",
traceIDs: []string{"trace1"},
expectErr: false,
name: "single trace ID",
traceIDs: []string{"trace1"},
expectOK: true,
},
{
name: "multiple trace IDs",
traceIDs: []string{"trace1", "trace2", "trace3"},
expectErr: false,
name: "multiple trace IDs",
traceIDs: []string{"trace1", "trace2", "trace3"},
expectOK: true,
},
{
name: "empty trace IDs",
traceIDs: []string{},
expectErr: true,
name: "empty trace IDs",
traceIDs: []string{},
expectOK: false,
},
{
name: "trace IDs with quotes",
traceIDs: []string{"'trace1'", `"trace2"`, "trace3"},
expectErr: false,
name: "trace IDs with quotes",
traceIDs: []string{"'trace1'", `"trace2"`, "trace3"},
expectOK: true,
},
}
@@ -42,9 +42,9 @@ func TestGetTraceTimeRangeMulti(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
finder := &TraceTimeRangeFinder{telemetryStore: nil}
if tt.expectErr {
_, _, err := finder.GetTraceTimeRangeMulti(ctx, tt.traceIDs)
assert.Error(t, err)
if !tt.expectOK {
_, _, ok := finder.GetTraceTimeRangeMulti(ctx, tt.traceIDs)
assert.False(t, ok)
}
})
}

View File

@@ -2,8 +2,8 @@ package alertmanagertypes
import (
"bytes"
"fmt"
"github.com/SigNoz/signoz/pkg/errors"
alertmanagertemplate "github.com/prometheus/alertmanager/template"
)
@@ -23,7 +23,7 @@ func FromGlobs(paths []string) (*alertmanagertemplate.Template, error) {
{{ define "__alertmanagerURL" }}{{ .ExternalURL }}/alerts{{ template "__ruleIdPath" . }}{{ end }}
{{ define "msteamsv2.default.titleLink" }}{{ template "__alertmanagerURL" . }}{{ end }}
`))); err != nil {
return nil, fmt.Errorf("error parsing alertmanager templates: %w", err)
return nil, errors.WrapInternalf(err, errors.CodeInternal, "error parsing alertmanager templates")
}
return t, nil

View File

@@ -3,10 +3,9 @@ package types
import (
"database/sql/driver"
"encoding/json"
"fmt"
"time"
"github.com/pkg/errors"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/uptrace/bun"
)
@@ -45,7 +44,7 @@ func (c *InstalledIntegrationConfig) Scan(src interface{}) error {
case string:
data = []byte(v)
default:
return fmt.Errorf("tried to scan from %T instead of string or bytes", src)
return errors.NewInternalf(errors.CodeInternal, "tried to scan from %T instead of string or bytes", src)
}
return json.Unmarshal(data, c)
@@ -55,7 +54,7 @@ func (c *InstalledIntegrationConfig) Scan(src interface{}) error {
func (c *InstalledIntegrationConfig) Value() (driver.Value, error) {
filterSetJson, err := json.Marshal(c)
if err != nil {
return nil, errors.Wrap(err, "could not serialize integration config to JSON")
return nil, errors.WrapInternalf(err, errors.CodeInternal, "could not serialize integration config to JSON")
}
return filterSetJson, nil
}
@@ -136,7 +135,7 @@ func (c *AccountConfig) Scan(src any) error {
case string:
data = []byte(v)
default:
return fmt.Errorf("tried to scan from %T instead of string or bytes", src)
return errors.NewInternalf(errors.CodeInternal, "tried to scan from %T instead of string or bytes", src)
}
return json.Unmarshal(data, c)
@@ -145,12 +144,12 @@ func (c *AccountConfig) Scan(src any) error {
// For serializing to db
func (c *AccountConfig) Value() (driver.Value, error) {
if c == nil {
return nil, fmt.Errorf("cloud account config is nil")
return nil, errors.NewInternalf(errors.CodeInternal, "cloud account config is nil")
}
serialized, err := json.Marshal(c)
if err != nil {
return nil, fmt.Errorf("couldn't serialize cloud account config to JSON: %w", err)
return nil, errors.WrapInternalf(err, errors.CodeInternal, "couldn't serialize cloud account config to JSON")
}
return serialized, nil
}
@@ -169,7 +168,7 @@ func (r *AgentReport) Scan(src any) error {
case string:
data = []byte(v)
default:
return fmt.Errorf("tried to scan from %T instead of string or bytes", src)
return errors.NewInternalf(errors.CodeInternal, "tried to scan from %T instead of string or bytes", src)
}
return json.Unmarshal(data, r)
@@ -178,13 +177,13 @@ func (r *AgentReport) Scan(src any) error {
// For serializing to db
func (r *AgentReport) Value() (driver.Value, error) {
if r == nil {
return nil, fmt.Errorf("agent report is nil")
return nil, errors.NewInternalf(errors.CodeInternal, "agent report is nil")
}
serialized, err := json.Marshal(r)
if err != nil {
return nil, fmt.Errorf(
"couldn't serialize agent report to JSON: %w", err,
return nil, errors.WrapInternalf(
err, errors.CodeInternal, "couldn't serialize agent report to JSON",
)
}
return serialized, nil
@@ -223,7 +222,7 @@ func (c *CloudServiceConfig) Scan(src any) error {
case string:
data = []byte(src)
default:
return fmt.Errorf("tried to scan from %T instead of string or bytes", src)
return errors.NewInternalf(errors.CodeInternal, "tried to scan from %T instead of string or bytes", src)
}
return json.Unmarshal(data, c)
@@ -232,13 +231,13 @@ func (c *CloudServiceConfig) Scan(src any) error {
// For serializing to db
func (c *CloudServiceConfig) Value() (driver.Value, error) {
if c == nil {
return nil, fmt.Errorf("cloud service config is nil")
return nil, errors.NewInternalf(errors.CodeInternal, "cloud service config is nil")
}
serialized, err := json.Marshal(c)
if err != nil {
return nil, fmt.Errorf(
"couldn't serialize cloud service config to JSON: %w", err,
return nil, errors.WrapInternalf(
err, errors.CodeInternal, "couldn't serialize cloud service config to JSON",
)
}
return serialized, nil

View File

@@ -3,7 +3,6 @@ package licensetypes
import (
"context"
"encoding/json"
"fmt"
"reflect"
"time"
@@ -113,9 +112,9 @@ func extractKeyFromMapStringInterface[T any](data map[string]interface{}, key st
if value, ok := val.(T); ok {
return value, nil
}
return zeroValue, fmt.Errorf("%s key is not a valid %s", key, reflect.TypeOf(zeroValue))
return zeroValue, errors.NewInvalidInputf(errors.CodeInvalidInput, "%s key is not a valid %s", key, reflect.TypeOf(zeroValue))
}
return zeroValue, fmt.Errorf("%s key is missing", key)
return zeroValue, errors.NewInvalidInputf(errors.CodeInvalidInput, "%s key is missing", key)
}
func NewLicense(data []byte, organizationID valuer.UUID) (*License, error) {

View File

@@ -2,15 +2,14 @@ package pipelinetypes
import (
"encoding/json"
"fmt"
"regexp"
"slices"
"strings"
"github.com/SigNoz/signoz/pkg/errors"
v3 "github.com/SigNoz/signoz/pkg/query-service/model/v3"
"github.com/SigNoz/signoz/pkg/query-service/queryBuilderToExpr"
"github.com/SigNoz/signoz/pkg/types"
"github.com/pkg/errors"
"github.com/uptrace/bun"
)
@@ -66,7 +65,7 @@ func (i *GettablePipeline) ParseRawConfig() error {
c := []PipelineOperator{}
err := json.Unmarshal([]byte(i.ConfigJSON), &c)
if err != nil {
return errors.Wrap(err, "failed to parse ingestion rule config")
return errors.WrapInvalidInputf(err, errors.CodeInvalidInput, "failed to parse ingestion rule config")
}
i.Config = c
return nil
@@ -76,7 +75,7 @@ func (i *GettablePipeline) ParseFilter() error {
f := v3.FilterSet{}
err := json.Unmarshal([]byte(i.FilterString), &f)
if err != nil {
return errors.Wrap(err, "failed to parse filter")
return errors.WrapInvalidInputf(err, errors.CodeInvalidInput, "failed to parse filter")
}
i.Filter = &f
return nil
@@ -208,20 +207,20 @@ type PostablePipeline struct {
// IsValid checks if postable pipeline has all the required params
func (p *PostablePipeline) IsValid() error {
if p.OrderID == 0 {
return fmt.Errorf("orderId with value > 1 is required")
return errors.NewInvalidInputf(errors.CodeInvalidInput, "orderId with value > 1 is required")
}
if p.Name == "" {
return fmt.Errorf("pipeline name is required")
return errors.NewInvalidInputf(errors.CodeInvalidInput, "pipeline name is required")
}
if p.Alias == "" {
return fmt.Errorf("pipeline alias is required")
return errors.NewInvalidInputf(errors.CodeInvalidInput, "pipeline alias is required")
}
// check the filter
_, err := queryBuilderToExpr.Parse(p.Filter)
if err != nil {
return fmt.Errorf("filter for pipeline %v is not correct: %v", p.Name, err.Error())
return errors.WrapInvalidInputf(err, errors.CodeInvalidInput, "filter for pipeline %v is not correct", p.Name)
}
idUnique := map[string]struct{}{}
@@ -230,30 +229,30 @@ func (p *PostablePipeline) IsValid() error {
l := len(p.Config)
for i, op := range p.Config {
if op.OrderId == 0 {
return fmt.Errorf("orderId with value > 1 is required in operator")
return errors.NewInvalidInputf(errors.CodeInvalidInput, "orderId with value > 1 is required in operator")
}
if op.ID == "" {
return fmt.Errorf("id of an operator cannot be empty")
return errors.NewInvalidInputf(errors.CodeInvalidInput, "id of an operator cannot be empty")
}
if op.Type == "" {
return fmt.Errorf("type of an operator cannot be empty")
return errors.NewInvalidInputf(errors.CodeInvalidInput, "type of an operator cannot be empty")
}
if i != (l-1) && op.Output == "" {
return fmt.Errorf("output of operator %s cannot be nil", op.ID)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "output of operator %s cannot be nil", op.ID)
}
if i == (l-1) && op.Output != "" {
return fmt.Errorf("output of operator %s should be empty", op.ID)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "output of operator %s should be empty", op.ID)
}
if _, ok := idUnique[op.ID]; ok {
return fmt.Errorf("duplicate id cannot be present")
return errors.NewInvalidInputf(errors.CodeInvalidInput, "duplicate id cannot be present")
}
if _, ok := outputUnique[op.Output]; ok {
return fmt.Errorf("duplicate output cannot be present")
return errors.NewInvalidInputf(errors.CodeInvalidInput, "duplicate output cannot be present")
}
if op.ID == op.Output {
return fmt.Errorf("id and output cannot be same")
return errors.NewInvalidInputf(errors.CodeInvalidInput, "id and output cannot be same")
}
err := isValidOperator(op)
@@ -269,31 +268,31 @@ func (p *PostablePipeline) IsValid() error {
func isValidOperator(op PipelineOperator) error {
if op.ID == "" {
return errors.New("PipelineOperator.ID is required")
return errors.New(errors.TypeInvalidInput, errors.CodeInvalidInput, "PipelineOperator.ID is required")
}
switch op.Type {
case "json_parser":
if op.ParseFrom == "" && op.ParseTo == "" {
return fmt.Errorf("parse from and parse to of %s json operator cannot be empty", op.ID)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "parse from and parse to of %s json operator cannot be empty", op.ID)
}
for k := range op.Mapping {
if !slices.Contains(validMappingVariableTypes, strings.ToLower(k)) {
return fmt.Errorf("%s is not a valid mapping type in processor %s", k, op.ID)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "%s is not a valid mapping type in processor %s", k, op.ID)
}
}
case "grok_parser":
if op.Pattern == "" {
return fmt.Errorf("pattern of %s grok operator cannot be empty", op.ID)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "pattern of %s grok operator cannot be empty", op.ID)
}
case "regex_parser":
if op.Regex == "" {
return fmt.Errorf("regex of %s regex operator cannot be empty", op.ID)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "regex of %s regex operator cannot be empty", op.ID)
}
r, err := regexp.Compile(op.Regex)
if err != nil {
return fmt.Errorf("error compiling regex expression of %s regex operator", op.ID)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "error compiling regex expression of %s regex operator", op.ID)
}
namedCaptureGroups := 0
for _, groupName := range r.SubexpNames() {
@@ -302,27 +301,27 @@ func isValidOperator(op PipelineOperator) error {
}
}
if namedCaptureGroups == 0 {
return fmt.Errorf("no capture groups in regex expression of %s regex operator", op.ID)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "no capture groups in regex expression of %s regex operator", op.ID)
}
case "copy":
if op.From == "" || op.To == "" {
return fmt.Errorf("from or to of %s copy operator cannot be empty", op.ID)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "from or to of %s copy operator cannot be empty", op.ID)
}
case "move":
if op.From == "" || op.To == "" {
return fmt.Errorf("from or to of %s move operator cannot be empty", op.ID)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "from or to of %s move operator cannot be empty", op.ID)
}
case "add":
if op.Field == "" || op.Value == "" {
return fmt.Errorf("field or value of %s add operator cannot be empty", op.ID)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "field or value of %s add operator cannot be empty", op.ID)
}
case "remove":
if op.Field == "" {
return fmt.Errorf("field of %s remove operator cannot be empty", op.ID)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "field of %s remove operator cannot be empty", op.ID)
}
case "trace_parser":
if op.TraceParser == nil {
return fmt.Errorf("field of %s remove operator cannot be empty", op.ID)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "field of %s remove operator cannot be empty", op.ID)
}
hasTraceIdParseFrom := (op.TraceParser.TraceId != nil && op.TraceParser.TraceId.ParseFrom != "")
@@ -330,42 +329,40 @@ func isValidOperator(op PipelineOperator) error {
hasTraceFlagsParseFrom := (op.TraceParser.TraceFlags != nil && op.TraceParser.TraceFlags.ParseFrom != "")
if !(hasTraceIdParseFrom || hasSpanIdParseFrom || hasTraceFlagsParseFrom) {
return fmt.Errorf("one of trace_id, span_id, trace_flags of %s trace_parser operator must be present", op.ID)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "one of trace_id, span_id, trace_flags of %s trace_parser operator must be present", op.ID)
}
if hasTraceIdParseFrom && !isValidOtelValue(op.TraceParser.TraceId.ParseFrom) {
return fmt.Errorf("trace id can't be parsed from %s", op.TraceParser.TraceId.ParseFrom)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "trace id can't be parsed from %s", op.TraceParser.TraceId.ParseFrom)
}
if hasSpanIdParseFrom && !isValidOtelValue(op.TraceParser.SpanId.ParseFrom) {
return fmt.Errorf("span id can't be parsed from %s", op.TraceParser.SpanId.ParseFrom)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "span id can't be parsed from %s", op.TraceParser.SpanId.ParseFrom)
}
if hasTraceFlagsParseFrom && !isValidOtelValue(op.TraceParser.TraceFlags.ParseFrom) {
return fmt.Errorf("trace flags can't be parsed from %s", op.TraceParser.TraceFlags.ParseFrom)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "trace flags can't be parsed from %s", op.TraceParser.TraceFlags.ParseFrom)
}
case "retain":
if len(op.Fields) == 0 {
return fmt.Errorf("fields of %s retain operator cannot be empty", op.ID)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "fields of %s retain operator cannot be empty", op.ID)
}
case "time_parser":
if op.ParseFrom == "" {
return fmt.Errorf("parse from of time parsing processor %s cannot be empty", op.ID)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "parse from of time parsing processor %s cannot be empty", op.ID)
}
if op.LayoutType != "epoch" && op.LayoutType != "strptime" {
// TODO(Raj): Maybe add support for gotime format
return fmt.Errorf(
"invalid format type '%s' of time parsing processor %s", op.LayoutType, op.ID,
)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "invalid format type '%s' of time parsing processor %s", op.LayoutType, op.ID)
}
if op.Layout == "" {
return fmt.Errorf("format can not be empty for time parsing processor %s", op.ID)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "format can not be empty for time parsing processor %s", op.ID)
}
validEpochLayouts := []string{"s", "ms", "us", "ns", "s.ms", "s.us", "s.ns"}
if op.LayoutType == "epoch" && !slices.Contains(validEpochLayouts, op.Layout) {
return fmt.Errorf(
"invalid epoch format '%s' of time parsing processor %s", op.LayoutType, op.ID,
return errors.NewInvalidInputf(
errors.CodeInvalidInput, "invalid epoch format '%s' of time parsing processor %s", op.LayoutType, op.ID,
)
}
@@ -374,23 +371,30 @@ func isValidOperator(op PipelineOperator) error {
if op.LayoutType == "strptime" {
_, err := RegexForStrptimeLayout(op.Layout)
if err != nil {
return fmt.Errorf("invalid strptime format '%s' of time parsing processor %s: %w", op.LayoutType, op.ID, err)
return errors.WrapInvalidInputf(
err, errors.CodeInvalidInput, "invalid strptime format '%s' of time parsing processor %s",
op.LayoutType, op.ID,
)
}
}
case "severity_parser":
if op.ParseFrom == "" {
return fmt.Errorf("parse from of severity parsing processor %s cannot be empty", op.ID)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "parse from of severity parsing processor %s cannot be empty", op.ID)
}
for k := range op.Mapping {
if !slices.Contains(validMappingLevels, strings.ToLower(k)) {
return fmt.Errorf("%s is not a valid severity in processor %s", k, op.ID)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "%s is not a valid severity in processor %s", k, op.ID)
}
}
default:
return fmt.Errorf("operator type %s not supported for %s, use one of (grok_parser, regex_parser, copy, move, add, remove, trace_parser, retain)", op.Type, op.ID)
return errors.NewInvalidInputf(
errors.CodeInvalidInput,
"operator type %s not supported for %s, use one of (grok_parser, regex_parser, copy, move, add, remove, trace_parser, retain)",
op.Type, op.ID,
)
}
if !isValidOtelValue(op.ParseFrom) ||
@@ -399,7 +403,7 @@ func isValidOperator(op PipelineOperator) error {
!isValidOtelValue(op.To) ||
!isValidOtelValue(op.Field) {
valueErrStr := "value should have prefix of body, attributes, resource"
return fmt.Errorf("%s for operator Id %s", valueErrStr, op.ID)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "%s for operator Id %s", valueErrStr, op.ID)
}
return nil
}

View File

@@ -1,7 +1,6 @@
package pipelinetypes
import (
"fmt"
"regexp"
"strings"
@@ -114,7 +113,7 @@ func RegexForStrptimeLayout(layout string) (string, error) {
strptimeDirectiveRegexp := regexp.MustCompile(`%.`)
layoutRegex = strptimeDirectiveRegexp.ReplaceAllStringFunc(layoutRegex, replaceStrptimeDirectiveWithRegex)
if len(errs) != 0 {
return "", fmt.Errorf("couldn't generate regex for ctime format: %v", errs)
return "", errors.NewInvalidInputf(errors.CodeInvalidInput, "couldn't generate regex for ctime format: %v", errs)
}
return layoutRegex, nil

View File

@@ -173,7 +173,8 @@ func (ns *NotificationSettings) UnmarshalJSON(data []byte) error {
// Validate states after unmarshaling
for _, state := range ns.Renotify.AlertStates {
if state != model.StateFiring && state != model.StateNoData {
return fmt.Errorf("invalid alert state: %s", state)
return signozError.NewInvalidInputf(signozError.CodeInvalidInput, "invalid alert state: %s", state)
}
}
return nil

View File

@@ -290,7 +290,7 @@ func (te TemplateExpander) Expand() (result string, resultErr error) {
var ok bool
resultErr, ok = r.(error)
if !ok {
resultErr = fmt.Errorf("panic expanding template %v: %v", te.name, r)
resultErr = errors.NewInternalf(errors.CodeInternal, "panic expanding template %v: %v", te.name, r)
}
}
}()
@@ -299,12 +299,12 @@ func (te TemplateExpander) Expand() (result string, resultErr error) {
tmpl, err := text_template.New(te.name).Funcs(te.funcMap).Option("missingkey=zero").Parse(te.text)
if err != nil {
return "", fmt.Errorf("error parsing template %v: %v", te.name, err)
return "", errors.WrapInvalidInputf(err, errors.CodeInvalidInput, "error parsing template %v", te.name)
}
var buffer bytes.Buffer
err = tmpl.Execute(&buffer, te.data)
if err != nil {
return "", fmt.Errorf("error executing template %v: %v", te.name, err)
return "", errors.WrapInvalidInputf(err, errors.CodeInvalidInput, "error executing template %v", te.name)
}
return buffer.String(), nil
}
@@ -316,7 +316,7 @@ func (te TemplateExpander) ExpandHTML(templateFiles []string) (result string, re
var ok bool
resultErr, ok = r.(error)
if !ok {
resultErr = fmt.Errorf("panic expanding template %v: %v", te.name, r)
resultErr = errors.NewInternalf(errors.CodeInternal, "panic expanding template %v: %v", te.name, r)
}
}
}()
@@ -332,18 +332,18 @@ func (te TemplateExpander) ExpandHTML(templateFiles []string) (result string, re
})
tmpl, err := tmpl.Parse(te.text)
if err != nil {
return "", fmt.Errorf("error parsing template %v: %v", te.name, err)
return "", errors.WrapInvalidInputf(err, errors.CodeInvalidInput, "error parsing template %v", te.name)
}
if len(templateFiles) > 0 {
_, err = tmpl.ParseFiles(templateFiles...)
if err != nil {
return "", fmt.Errorf("error parsing template files for %v: %v", te.name, err)
return "", errors.WrapInvalidInputf(err, errors.CodeInvalidInput, "error parsing template files for %v", te.name)
}
}
var buffer bytes.Buffer
err = tmpl.Execute(&buffer, te.data)
if err != nil {
return "", fmt.Errorf("error executing template %v: %v", te.name, err)
return "", errors.WrapInvalidInputf(err, errors.CodeInvalidInput, "error executing template %v", te.name)
}
return buffer.String(), nil
}

View File

@@ -2,9 +2,9 @@ package telemetrytypes
import (
"encoding/json"
"fmt"
"strings"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/valuer"
)
@@ -98,7 +98,7 @@ func (f *FieldContext) UnmarshalJSON(data []byte) error {
// Scan implements the sql.Scanner interface
func (f *FieldContext) Scan(value interface{}) error {
if f == nil {
return fmt.Errorf("fieldcontext: nil receiver")
return errors.NewInternalf(errors.CodeInternal, "fieldcontext: nil receiver")
}
if value == nil {
@@ -108,7 +108,7 @@ func (f *FieldContext) Scan(value interface{}) error {
str, ok := value.(string)
if !ok {
return fmt.Errorf("fieldcontext: expected string, got %T", value)
return errors.NewInternalf(errors.CodeInternal, "fieldcontext: expected string, got %T", value)
}
// Normalize the string

View File

@@ -2,9 +2,9 @@ package telemetrytypes
import (
"encoding/json"
"fmt"
"strings"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/valuer"
)
@@ -123,7 +123,7 @@ func (f *FieldDataType) UnmarshalJSON(data []byte) error {
// Scan implements the sql.Scanner interface
func (f *FieldDataType) Scan(value interface{}) error {
if f == nil {
return fmt.Errorf("fielddatatype: nil receiver")
return errors.NewInternalf(errors.CodeInternal, "fielddatatype: nil receiver")
}
if value == nil {
@@ -133,7 +133,7 @@ func (f *FieldDataType) Scan(value interface{}) error {
str, ok := value.(string)
if !ok {
return fmt.Errorf("fielddatatype: expected string, got %T", value)
return errors.NewInternalf(errors.CodeInternal, "fielddatatype: expected string, got %T", value)
}
// Normalize the string

View File

@@ -2,9 +2,9 @@ package telemetrytypestest
import (
"encoding/json"
"fmt"
"os"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
)
@@ -12,12 +12,12 @@ import (
func LoadFieldKeysFromJSON(filePath string) (map[string][]*telemetrytypes.TelemetryFieldKey, error) {
jsonData, err := os.ReadFile(filePath)
if err != nil {
return nil, fmt.Errorf("failed to read JSON file: %w", err)
return nil, errors.WrapInvalidInputf(err, errors.CodeInvalidInput, "failed to read JSON file")
}
var result map[string][]*telemetrytypes.TelemetryFieldKey
if err := json.Unmarshal(jsonData, &result); err != nil {
return nil, fmt.Errorf("failed to unmarshal JSON: %w", err)
return nil, errors.WrapInvalidInputf(err, errors.CodeInvalidInput, "failed to unmarshal JSON")
}
return result, nil
@@ -27,7 +27,7 @@ func LoadFieldKeysFromJSON(filePath string) (map[string][]*telemetrytypes.Teleme
func LoadFieldKeysFromJSONString(jsonStr string) (map[string][]*telemetrytypes.TelemetryFieldKey, error) {
var result map[string][]*telemetrytypes.TelemetryFieldKey
if err := json.Unmarshal([]byte(jsonStr), &result); err != nil {
return nil, fmt.Errorf("failed to unmarshal JSON: %w", err)
return nil, errors.WrapInvalidInputf(err, errors.CodeInvalidInput, "failed to unmarshal JSON")
}
return result, nil

View File

@@ -1,7 +1,6 @@
package tracefunneltypes
import (
"fmt"
"sort"
"time"
@@ -13,10 +12,10 @@ import (
// ValidateTimestamp validates a timestamp
func ValidateTimestamp(timestamp int64, fieldName string) error {
if timestamp == 0 {
return fmt.Errorf("%s is required", fieldName)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "%s is required", fieldName)
}
if timestamp < 0 {
return fmt.Errorf("%s must be positive", fieldName)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "%s must be positive", fieldName)
}
return nil
}
@@ -28,18 +27,18 @@ func ValidateTimestampIsMilliseconds(timestamp int64) bool {
func ValidateFunnelSteps(steps []*FunnelStep) error {
if len(steps) < 2 {
return fmt.Errorf("funnel must have at least 2 steps")
return errors.NewInvalidInputf(errors.CodeInvalidInput, "funnel must have at least 2 steps")
}
for i, step := range steps {
if step.ServiceName == "" {
return fmt.Errorf("step %d: service name is required", i+1)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "step %d: service name is required", i+1)
}
if step.SpanName == "" {
return fmt.Errorf("step %d: span name is required", i+1)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "step %d: span name is required", i+1)
}
if step.Order < 0 {
return fmt.Errorf("step %d: order must be non-negative", i+1)
return errors.NewInvalidInputf(errors.CodeInvalidInput, "step %d: order must be non-negative", i+1)
}
}

View File

@@ -1,10 +1,10 @@
package clickhouse
import (
"fmt"
"strings"
"github.com/AfterShip/clickhouse-sql-parser/parser"
"github.com/SigNoz/signoz/pkg/errors"
)
// FilterAction represents what to do with a filter containing a variable
@@ -37,7 +37,7 @@ func (qp *QueryProcessor) ProcessQuery(query string, transformer FilterTransform
p := parser.NewParser(query)
stmts, err := p.ParseStmts()
if err != nil {
return "", fmt.Errorf("failed to parse query: %w", err)
return "", errors.WrapInvalidInputf(err, errors.CodeInvalidInput, "failed to parse query")
}
if len(stmts) == 0 {

View File

@@ -5,6 +5,7 @@ import (
"strconv"
"strings"
"github.com/SigNoz/signoz/pkg/errors"
grammar "github.com/SigNoz/signoz/pkg/parser/grammar"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/antlr4-go/antlr/v4"
@@ -26,7 +27,7 @@ func NewErrorListener() *ErrorListener {
// SyntaxError is called when a syntax error is encountered
func (e *ErrorListener) SyntaxError(recognizer antlr.Recognizer, offendingSymbol any, line, column int, msg string, ex antlr.RecognitionException) {
e.SyntaxErrors = append(e.SyntaxErrors, fmt.Errorf("line %d:%d %s", line, column, msg))
e.SyntaxErrors = append(e.SyntaxErrors, errors.NewInvalidInputf(errors.CodeInvalidInput, "line %d:%d %s", line, column, msg))
}
// variableReplacementVisitor implements the visitor interface
@@ -62,13 +63,13 @@ func ReplaceVariablesInExpression(expression string, variables map[string]qbtype
tree := parser.Query()
if len(parserErrorListener.SyntaxErrors) > 0 {
return "", fmt.Errorf("syntax errors in expression: %v", parserErrorListener.SyntaxErrors)
return "", errors.NewInvalidInputf(errors.CodeInvalidInput, "syntax errors in expression: %v", parserErrorListener.SyntaxErrors)
}
result := visitor.Visit(tree).(string)
if len(visitor.errors) > 0 {
return "", fmt.Errorf("errors processing expression: %v", visitor.errors)
return "", errors.NewInvalidInputf(errors.CodeInvalidInput, "errors processing expression: %v", visitor.errors)
}
// If the entire expression should be skipped, return empty string

View File

@@ -2,11 +2,11 @@ package routerweb
import (
"context"
"fmt"
"net/http"
"os"
"path/filepath"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/http/middleware"
"github.com/SigNoz/signoz/pkg/web"
@@ -28,21 +28,21 @@ func NewFactory() factory.ProviderFactory[web.Web, web.Config] {
func New(ctx context.Context, settings factory.ProviderSettings, config web.Config) (web.Web, error) {
fi, err := os.Stat(config.Directory)
if err != nil {
return nil, fmt.Errorf("cannot access web directory: %w", err)
return nil, errors.WrapInvalidInputf(err, errors.CodeInvalidInput, "cannot access web directory")
}
ok := fi.IsDir()
if !ok {
return nil, fmt.Errorf("web directory is not a directory")
return nil, errors.NewInvalidInputf(errors.CodeInvalidInput, "web directory is not a directory")
}
fi, err = os.Stat(filepath.Join(config.Directory, indexFileName))
if err != nil {
return nil, fmt.Errorf("cannot access %q in web directory: %w", indexFileName, err)
return nil, errors.WrapInvalidInputf(err, errors.CodeInvalidInput, "cannot access %q in web directory", indexFileName)
}
if os.IsNotExist(err) || fi.IsDir() {
return nil, fmt.Errorf("%q does not exist", indexFileName)
return nil, errors.NewInvalidInputf(errors.CodeInvalidInput, "%q does not exist", indexFileName)
}
return &provider{
@@ -60,7 +60,7 @@ func (provider *provider) AddToRouter(router *mux.Router) error {
),
).GetError()
if err != nil {
return fmt.Errorf("unable to add web to router: %w", err)
return errors.WrapInternalf(err, errors.CodeInternal, "unable to add web to router")
}
return nil