mirror of
https://github.com/SigNoz/signoz.git
synced 2026-09-22 19:30:43 +01:00
Some checks failed
build-staging / prepare (push) Has been cancelled
cacheci / tests (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
<!--A few plain bullets saying what changed and why, for a reviewer skimming it - not a wall of text, not a restatement of the diff, not generated boilerplate.--> #### Description Enable the processors by default so that metadata is populated <!--Reference issues using `Closes #issue-number` to enable automatic closure on merge. --> #### Issues closed by this PR No issue
224 lines
7.8 KiB
Go
224 lines
7.8 KiB
Go
package implspanmapper
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
|
|
"github.com/SigNoz/signoz/pkg/errors"
|
|
"github.com/SigNoz/signoz/pkg/factory"
|
|
"github.com/SigNoz/signoz/pkg/modules/spanmapper"
|
|
"github.com/SigNoz/signoz/pkg/query-service/agentConf"
|
|
"github.com/SigNoz/signoz/pkg/types/opamptypes"
|
|
"github.com/SigNoz/signoz/pkg/types/spantypes"
|
|
"github.com/SigNoz/signoz/pkg/valuer"
|
|
)
|
|
|
|
// maxTestSpans bounds the input size: every test request boots a full
|
|
// in-memory collector pipeline and is reachable with viewer access.
|
|
const maxTestSpans = 100
|
|
|
|
type module struct {
|
|
store spantypes.SpanMapperStore
|
|
registry spantypes.SpanMapperGroupRegistry
|
|
settings factory.ScopedProviderSettings
|
|
}
|
|
|
|
func NewModule(store spantypes.SpanMapperStore, registry spantypes.SpanMapperGroupRegistry, providerSettings factory.ProviderSettings) spanmapper.Module {
|
|
return &module{
|
|
store: store,
|
|
registry: registry,
|
|
settings: factory.NewScopedProviderSettings(providerSettings, "github.com/SigNoz/signoz/pkg/modules/spanmapper/implspanmapper"),
|
|
}
|
|
}
|
|
|
|
func (module *module) ListGroups(ctx context.Context, orgID valuer.UUID, q *spantypes.ListSpanMapperGroupsQuery) ([]*spantypes.SpanMapperGroup, error) {
|
|
return module.store.ListGroups(ctx, orgID, q)
|
|
}
|
|
|
|
func (module *module) GetGroup(ctx context.Context, orgID, id valuer.UUID) (*spantypes.SpanMapperGroup, error) {
|
|
return module.store.GetGroup(ctx, orgID, id)
|
|
}
|
|
|
|
func (module *module) CreateGroup(ctx context.Context, orgID valuer.UUID, group *spantypes.SpanMapperGroup) error {
|
|
if module.registry.IsReserved(group.Name) {
|
|
return errors.Newf(errors.TypeInvalidInput, spantypes.ErrCodeMappingGroupNameReserved, "group name %q is reserved for a default group", group.Name)
|
|
}
|
|
return module.store.CreateGroup(ctx, group)
|
|
}
|
|
|
|
func (module *module) UpdateGroup(ctx context.Context, orgID, id valuer.UUID, name *string, condition *spantypes.SpanMapperGroupCondition, enabled *bool, updatedBy string) error {
|
|
group, err := module.store.GetGroup(ctx, orgID, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if name != nil && *name != group.Name && module.registry.IsReserved(*name) {
|
|
return errors.Newf(errors.TypeInvalidInput, spantypes.ErrCodeMappingGroupNameReserved, "group name %q is reserved for a default group", *name)
|
|
}
|
|
if err := group.Update(name, condition, enabled, updatedBy); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := module.store.UpdateGroup(ctx, group); err != nil {
|
|
return err
|
|
}
|
|
agentConf.NotifyConfigUpdate(ctx)
|
|
return nil
|
|
}
|
|
|
|
func (module *module) DeleteGroup(ctx context.Context, orgID, id valuer.UUID) error {
|
|
if err := module.store.DeleteGroup(ctx, orgID, id); err != nil {
|
|
return err
|
|
}
|
|
agentConf.NotifyConfigUpdate(ctx)
|
|
return nil
|
|
}
|
|
|
|
func (module *module) ListMappers(ctx context.Context, orgID, groupID valuer.UUID) ([]*spantypes.SpanMapper, error) {
|
|
return module.store.ListMappers(ctx, orgID, groupID)
|
|
}
|
|
|
|
func (module *module) GetMapper(ctx context.Context, orgID, groupID, id valuer.UUID) (*spantypes.SpanMapper, error) {
|
|
return module.store.GetMapper(ctx, orgID, groupID, id)
|
|
}
|
|
|
|
func (module *module) CreateMapper(ctx context.Context, orgID, groupID valuer.UUID, mapper *spantypes.SpanMapper) error {
|
|
// Ensure the group belongs to the org before inserting the child row.
|
|
if _, err := module.store.GetGroup(ctx, orgID, groupID); err != nil {
|
|
return err
|
|
}
|
|
err := module.store.CreateMapper(ctx, mapper)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
agentConf.NotifyConfigUpdate(ctx)
|
|
return nil
|
|
}
|
|
|
|
func (module *module) UpdateMapper(ctx context.Context, orgID, groupID, id valuer.UUID, fieldContext spantypes.FieldContext, config *spantypes.SpanMapperConfig, enabled *bool, updatedBy string) error {
|
|
mapper, err := module.store.GetMapper(ctx, orgID, groupID, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := mapper.Update(fieldContext, config, enabled, updatedBy); err != nil {
|
|
return err
|
|
}
|
|
err = module.store.UpdateMapper(ctx, mapper)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
agentConf.NotifyConfigUpdate(ctx)
|
|
return nil
|
|
}
|
|
|
|
func (module *module) DeleteMapper(ctx context.Context, orgID, groupID, id valuer.UUID) error {
|
|
if err := module.store.DeleteMapper(ctx, orgID, groupID, id, spantypes.SpanMapperOriginUser); err != nil {
|
|
return err
|
|
}
|
|
agentConf.NotifyConfigUpdate(ctx)
|
|
return nil
|
|
}
|
|
|
|
func (module *module) TestMappers(ctx context.Context, orgID valuer.UUID, spans []spantypes.SpanMapperTestSpan, groups []*spantypes.SpanMapperGroupWithMappers) ([]spantypes.SpanMapperTestSpan, []string, error) {
|
|
if len(spans) == 0 {
|
|
return nil, nil, errors.New(errors.TypeInvalidInput, spantypes.ErrCodeMappingInvalidInput, "'spans' must contain at least one span")
|
|
}
|
|
if len(spans) > maxTestSpans {
|
|
return nil, nil, errors.Newf(errors.TypeInvalidInput, spantypes.ErrCodeMappingInvalidInput, "'spans' must contain at most %d spans", maxTestSpans)
|
|
}
|
|
|
|
resolved, err := module.backfillMappers(ctx, orgID, groups)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
out, collectorLogs, err := spantypes.SimulateSpanMappersProcessing(ctx, resolved, spans)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
return out, collectorLogs, nil
|
|
}
|
|
|
|
func (module *module) AgentFeatureType() agentConf.AgentFeatureType {
|
|
return spantypes.SpanAttrMappingFeatureType
|
|
}
|
|
|
|
func (module *module) RecommendAgentConfig(orgID valuer.UUID, currentConfYaml []byte, configVersion *opamptypes.AgentConfigVersion) ([]byte, string, error) {
|
|
ctx := context.Background()
|
|
|
|
enabledMappers, err := module.listEnabledGroupsWithMappers(ctx, orgID)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
|
|
updatedConf, err := spantypes.GenerateCollectorConfigWithSpanMapperProcessor(currentConfYaml, enabledMappers)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
|
|
serialized, err := json.Marshal(enabledMappers)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
|
|
return updatedConf, string(serialized), nil
|
|
}
|
|
|
|
// backfillMappers loads saved mappers for any enabled group whose Mappers is
|
|
// nil. Disabled groups are skipped: the simulation filters them out anyway,
|
|
// so there is no point loading their mappers or failing on their names.
|
|
func (module *module) backfillMappers(ctx context.Context, orgID valuer.UUID, groups []*spantypes.SpanMapperGroupWithMappers) ([]*spantypes.SpanMapperGroupWithMappers, error) {
|
|
savedGroups, err := module.store.ListGroups(ctx, orgID, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
savedByName := make(map[string]*spantypes.SpanMapperGroup, len(savedGroups))
|
|
for _, g := range savedGroups {
|
|
savedByName[g.Name] = g
|
|
}
|
|
|
|
// For each group in the request, if Mappers is nil, load the saved mappers for that group name.
|
|
for _, g := range groups {
|
|
if g.Mappers != nil || !g.Group.Enabled {
|
|
continue
|
|
}
|
|
saved, ok := savedByName[g.Group.Name]
|
|
if !ok {
|
|
return nil, errors.Newf(errors.TypeNotFound, spantypes.ErrCodeMappingGroupNotFound, "no saved group named %q to load mappers from; send 'mappers' for new or edited groups", g.Group.Name)
|
|
}
|
|
loaded, err := module.store.ListMappers(ctx, orgID, saved.ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
g.Mappers = loaded
|
|
}
|
|
return groups, nil
|
|
}
|
|
|
|
// listEnabledGroupsWithMappers returns groups with their mappers.
|
|
func (module *module) listEnabledGroupsWithMappers(ctx context.Context, orgID valuer.UUID) ([]*spantypes.SpanMapperGroupWithMappers, error) {
|
|
enabled := true
|
|
groups, err := module.store.ListGroups(ctx, orgID, &spantypes.ListSpanMapperGroupsQuery{Enabled: &enabled})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
out := make([]*spantypes.SpanMapperGroupWithMappers, 0, len(groups))
|
|
for _, g := range groups {
|
|
mappers, err := module.store.ListMappers(ctx, orgID, g.ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
enabledMappers := make([]*spantypes.SpanMapper, 0, len(mappers))
|
|
for _, m := range mappers {
|
|
if m.Enabled {
|
|
enabledMappers = append(enabledMappers, m)
|
|
}
|
|
}
|
|
if len(enabledMappers) == 0 {
|
|
continue
|
|
}
|
|
out = append(out, &spantypes.SpanMapperGroupWithMappers{Group: g, Mappers: enabledMappers})
|
|
}
|
|
return out, nil
|
|
}
|