mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-13 05:29:04 +08:00
Add support in query service for querybuilder filterset based log pipelines (#3560)
* chore: use v3.Filterset as pipeline filters in logparsing pipelines integration tests * chore: get logparsing integration tests passing with filterset based pipeline * chore: get all other breaking tests passing * chore: move models.logparsingpipeline to logparsingpipeline.model * chore: implement Valuer and Scanner interfaces for v3.FilterSet
This commit is contained in:
parent
8324d010ae
commit
3db8a25eb9
@ -28,7 +28,7 @@ func NewLogParsingPipelinesController(db *sqlx.DB, engine string) (*LogParsingPi
|
|||||||
type PipelinesResponse struct {
|
type PipelinesResponse struct {
|
||||||
*agentConf.ConfigVersion
|
*agentConf.ConfigVersion
|
||||||
|
|
||||||
Pipelines []model.Pipeline `json:"pipelines"`
|
Pipelines []Pipeline `json:"pipelines"`
|
||||||
History []agentConf.ConfigVersion `json:"history"`
|
History []agentConf.ConfigVersion `json:"history"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ func (ic *LogParsingPipelineController) ApplyPipelines(
|
|||||||
return nil, model.UnauthorizedError(errors.Wrap(authErr, "failed to get userId from context"))
|
return nil, model.UnauthorizedError(errors.Wrap(authErr, "failed to get userId from context"))
|
||||||
}
|
}
|
||||||
|
|
||||||
var pipelines []model.Pipeline
|
var pipelines []Pipeline
|
||||||
|
|
||||||
// scan through postable pipelines, to select the existing pipelines or insert missing ones
|
// scan through postable pipelines, to select the existing pipelines or insert missing ones
|
||||||
for _, r := range postable {
|
for _, r := range postable {
|
||||||
|
@ -41,7 +41,7 @@ func (r *Repo) InitDB(engine string) error {
|
|||||||
// insertPipeline stores a given postable pipeline to database
|
// insertPipeline stores a given postable pipeline to database
|
||||||
func (r *Repo) insertPipeline(
|
func (r *Repo) insertPipeline(
|
||||||
ctx context.Context, postable *PostablePipeline,
|
ctx context.Context, postable *PostablePipeline,
|
||||||
) (*model.Pipeline, *model.ApiError) {
|
) (*Pipeline, *model.ApiError) {
|
||||||
if err := postable.IsValid(); err != nil {
|
if err := postable.IsValid(); err != nil {
|
||||||
return nil, model.BadRequest(errors.Wrap(err,
|
return nil, model.BadRequest(errors.Wrap(err,
|
||||||
"pipeline is not valid",
|
"pipeline is not valid",
|
||||||
@ -65,7 +65,7 @@ func (r *Repo) insertPipeline(
|
|||||||
return nil, model.UnauthorizedError(err)
|
return nil, model.UnauthorizedError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
insertRow := &model.Pipeline{
|
insertRow := &Pipeline{
|
||||||
Id: uuid.New().String(),
|
Id: uuid.New().String(),
|
||||||
OrderId: postable.OrderId,
|
OrderId: postable.OrderId,
|
||||||
Enabled: postable.Enabled,
|
Enabled: postable.Enabled,
|
||||||
@ -75,7 +75,7 @@ func (r *Repo) insertPipeline(
|
|||||||
Filter: postable.Filter,
|
Filter: postable.Filter,
|
||||||
Config: postable.Config,
|
Config: postable.Config,
|
||||||
RawConfig: string(rawConfig),
|
RawConfig: string(rawConfig),
|
||||||
Creator: model.Creator{
|
Creator: Creator{
|
||||||
CreatedBy: claims["email"].(string),
|
CreatedBy: claims["email"].(string),
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
},
|
},
|
||||||
@ -107,9 +107,11 @@ func (r *Repo) insertPipeline(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getPipelinesByVersion returns pipelines associated with a given version
|
// getPipelinesByVersion returns pipelines associated with a given version
|
||||||
func (r *Repo) getPipelinesByVersion(ctx context.Context, version int) ([]model.Pipeline, []error) {
|
func (r *Repo) getPipelinesByVersion(
|
||||||
|
ctx context.Context, version int,
|
||||||
|
) ([]Pipeline, []error) {
|
||||||
var errors []error
|
var errors []error
|
||||||
pipelines := []model.Pipeline{}
|
pipelines := []Pipeline{}
|
||||||
|
|
||||||
versionQuery := `SELECT r.id,
|
versionQuery := `SELECT r.id,
|
||||||
r.name,
|
r.name,
|
||||||
@ -151,8 +153,8 @@ func (r *Repo) getPipelinesByVersion(ctx context.Context, version int) ([]model.
|
|||||||
// GetPipelines returns pipeline and errors (if any)
|
// GetPipelines returns pipeline and errors (if any)
|
||||||
func (r *Repo) GetPipeline(
|
func (r *Repo) GetPipeline(
|
||||||
ctx context.Context, id string,
|
ctx context.Context, id string,
|
||||||
) (*model.Pipeline, *model.ApiError) {
|
) (*Pipeline, *model.ApiError) {
|
||||||
pipelines := []model.Pipeline{}
|
pipelines := []Pipeline{}
|
||||||
|
|
||||||
pipelineQuery := `SELECT id,
|
pipelineQuery := `SELECT id,
|
||||||
name,
|
name,
|
||||||
|
@ -1,21 +1,22 @@
|
|||||||
package model
|
package logparsingpipeline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Pipeline is stored and also deployed finally to collector config
|
// Pipeline is stored and also deployed finally to collector config
|
||||||
type Pipeline struct {
|
type Pipeline struct {
|
||||||
Id string `json:"id,omitempty" db:"id"`
|
Id string `json:"id,omitempty" db:"id"`
|
||||||
OrderId int `json:"orderId" db:"order_id"`
|
OrderId int `json:"orderId" db:"order_id"`
|
||||||
Name string `json:"name,omitempty" db:"name"`
|
Name string `json:"name,omitempty" db:"name"`
|
||||||
Alias string `json:"alias" db:"alias"`
|
Alias string `json:"alias" db:"alias"`
|
||||||
Description *string `json:"description" db:"description"`
|
Description *string `json:"description" db:"description"`
|
||||||
Enabled bool `json:"enabled" db:"enabled"`
|
Enabled bool `json:"enabled" db:"enabled"`
|
||||||
Filter string `json:"filter" db:"filter"`
|
Filter *v3.FilterSet `json:"filter" db:"filter"`
|
||||||
|
|
||||||
// configuration for pipeline
|
// configuration for pipeline
|
||||||
RawConfig string `db:"config_json" json:"-"`
|
RawConfig string `db:"config_json" json:"-"`
|
@ -1,15 +1,20 @@
|
|||||||
package logparsingpipeline
|
package logparsingpipeline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/pkg/errors"
|
||||||
"go.signoz.io/signoz/pkg/query-service/constants"
|
"go.signoz.io/signoz/pkg/query-service/constants"
|
||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
"go.signoz.io/signoz/pkg/query-service/queryBuilderToExpr"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
NOOP = "noop"
|
NOOP = "noop"
|
||||||
)
|
)
|
||||||
|
|
||||||
func PreparePipelineProcessor(pipelines []model.Pipeline) (map[string]interface{}, []string, error) {
|
func CollectorConfProcessorName(p Pipeline) string {
|
||||||
|
return constants.LogsPPLPfx + p.Alias
|
||||||
|
}
|
||||||
|
|
||||||
|
func PreparePipelineProcessor(pipelines []Pipeline) (map[string]interface{}, []string, error) {
|
||||||
processors := map[string]interface{}{}
|
processors := map[string]interface{}{}
|
||||||
names := []string{}
|
names := []string{}
|
||||||
for _, v := range pipelines {
|
for _, v := range pipelines {
|
||||||
@ -21,14 +26,20 @@ func PreparePipelineProcessor(pipelines []model.Pipeline) (map[string]interface{
|
|||||||
if len(operators) == 0 {
|
if len(operators) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
router := []model.PipelineOperator{
|
|
||||||
|
filterExpr, err := queryBuilderToExpr.Parse(v.Filter)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, errors.Wrap(err, "failed to parse pipeline filter")
|
||||||
|
}
|
||||||
|
|
||||||
|
router := []PipelineOperator{
|
||||||
{
|
{
|
||||||
ID: "router_signoz",
|
ID: "router_signoz",
|
||||||
Type: "router",
|
Type: "router",
|
||||||
Routes: &[]model.Route{
|
Routes: &[]Route{
|
||||||
{
|
{
|
||||||
Output: v.Config[0].ID,
|
Output: v.Config[0].ID,
|
||||||
Expr: v.Filter,
|
Expr: filterExpr,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Default: NOOP,
|
Default: NOOP,
|
||||||
@ -38,24 +49,24 @@ func PreparePipelineProcessor(pipelines []model.Pipeline) (map[string]interface{
|
|||||||
v.Config = append(router, operators...)
|
v.Config = append(router, operators...)
|
||||||
|
|
||||||
// noop operator is needed as the default operator so that logs are not dropped
|
// noop operator is needed as the default operator so that logs are not dropped
|
||||||
noop := model.PipelineOperator{
|
noop := PipelineOperator{
|
||||||
ID: NOOP,
|
ID: NOOP,
|
||||||
Type: NOOP,
|
Type: NOOP,
|
||||||
}
|
}
|
||||||
v.Config = append(v.Config, noop)
|
v.Config = append(v.Config, noop)
|
||||||
|
|
||||||
processor := model.Processor{
|
processor := Processor{
|
||||||
Operators: v.Config,
|
Operators: v.Config,
|
||||||
}
|
}
|
||||||
name := constants.LogsPPLPfx + v.Alias
|
name := CollectorConfProcessorName(v)
|
||||||
processors[name] = processor
|
processors[name] = processor
|
||||||
names = append(names, name)
|
names = append(names, name)
|
||||||
}
|
}
|
||||||
return processors, names, nil
|
return processors, names, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getOperators(ops []model.PipelineOperator) []model.PipelineOperator {
|
func getOperators(ops []PipelineOperator) []PipelineOperator {
|
||||||
filteredOp := []model.PipelineOperator{}
|
filteredOp := []PipelineOperator{}
|
||||||
for i, operator := range ops {
|
for i, operator := range ops {
|
||||||
if operator.Enabled {
|
if operator.Enabled {
|
||||||
if len(filteredOp) > 0 {
|
if len(filteredOp) > 0 {
|
||||||
|
@ -4,17 +4,16 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var prepareProcessorTestData = []struct {
|
var prepareProcessorTestData = []struct {
|
||||||
Name string
|
Name string
|
||||||
Operators []model.PipelineOperator
|
Operators []PipelineOperator
|
||||||
Output []model.PipelineOperator
|
Output []PipelineOperator
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
Name: "Last operator disabled",
|
Name: "Last operator disabled",
|
||||||
Operators: []model.PipelineOperator{
|
Operators: []PipelineOperator{
|
||||||
{
|
{
|
||||||
ID: "t1",
|
ID: "t1",
|
||||||
Name: "t1",
|
Name: "t1",
|
||||||
@ -27,7 +26,7 @@ var prepareProcessorTestData = []struct {
|
|||||||
Enabled: false,
|
Enabled: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Output: []model.PipelineOperator{
|
Output: []PipelineOperator{
|
||||||
{
|
{
|
||||||
ID: "t1",
|
ID: "t1",
|
||||||
Name: "t1",
|
Name: "t1",
|
||||||
@ -37,7 +36,7 @@ var prepareProcessorTestData = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Operator in middle disabled",
|
Name: "Operator in middle disabled",
|
||||||
Operators: []model.PipelineOperator{
|
Operators: []PipelineOperator{
|
||||||
{
|
{
|
||||||
ID: "t1",
|
ID: "t1",
|
||||||
Name: "t1",
|
Name: "t1",
|
||||||
@ -56,7 +55,7 @@ var prepareProcessorTestData = []struct {
|
|||||||
Enabled: true,
|
Enabled: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Output: []model.PipelineOperator{
|
Output: []PipelineOperator{
|
||||||
{
|
{
|
||||||
ID: "t1",
|
ID: "t1",
|
||||||
Name: "t1",
|
Name: "t1",
|
||||||
@ -72,7 +71,7 @@ var prepareProcessorTestData = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Single operator disabled",
|
Name: "Single operator disabled",
|
||||||
Operators: []model.PipelineOperator{
|
Operators: []PipelineOperator{
|
||||||
{
|
{
|
||||||
ID: "t1",
|
ID: "t1",
|
||||||
Name: "t1",
|
Name: "t1",
|
||||||
@ -80,18 +79,18 @@ var prepareProcessorTestData = []struct {
|
|||||||
Enabled: false,
|
Enabled: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Output: []model.PipelineOperator{},
|
Output: []PipelineOperator{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Single operator enabled",
|
Name: "Single operator enabled",
|
||||||
Operators: []model.PipelineOperator{
|
Operators: []PipelineOperator{
|
||||||
{
|
{
|
||||||
ID: "t1",
|
ID: "t1",
|
||||||
Name: "t1",
|
Name: "t1",
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Output: []model.PipelineOperator{
|
Output: []PipelineOperator{
|
||||||
{
|
{
|
||||||
ID: "t1",
|
ID: "t1",
|
||||||
Name: "t1",
|
Name: "t1",
|
||||||
@ -101,12 +100,12 @@ var prepareProcessorTestData = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Empty operator",
|
Name: "Empty operator",
|
||||||
Operators: []model.PipelineOperator{},
|
Operators: []PipelineOperator{},
|
||||||
Output: []model.PipelineOperator{},
|
Output: []PipelineOperator{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "new test",
|
Name: "new test",
|
||||||
Operators: []model.PipelineOperator{
|
Operators: []PipelineOperator{
|
||||||
{
|
{
|
||||||
ID: "move_filename",
|
ID: "move_filename",
|
||||||
Output: "move_function",
|
Output: "move_function",
|
||||||
@ -137,7 +136,7 @@ var prepareProcessorTestData = []struct {
|
|||||||
Name: "move_lwp",
|
Name: "move_lwp",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Output: []model.PipelineOperator{
|
Output: []PipelineOperator{
|
||||||
{
|
{
|
||||||
ID: "move_filename",
|
ID: "move_filename",
|
||||||
Output: "move_line",
|
Output: "move_line",
|
||||||
@ -165,7 +164,7 @@ var prepareProcessorTestData = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "first op disabled",
|
Name: "first op disabled",
|
||||||
Operators: []model.PipelineOperator{
|
Operators: []PipelineOperator{
|
||||||
{
|
{
|
||||||
ID: "move_filename",
|
ID: "move_filename",
|
||||||
Output: "move_function",
|
Output: "move_function",
|
||||||
@ -178,7 +177,7 @@ var prepareProcessorTestData = []struct {
|
|||||||
Name: "move_function",
|
Name: "move_function",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Output: []model.PipelineOperator{
|
Output: []PipelineOperator{
|
||||||
{
|
{
|
||||||
ID: "move_function",
|
ID: "move_function",
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
|
@ -6,9 +6,8 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/antonmedv/expr"
|
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||||
|
"go.signoz.io/signoz/pkg/query-service/queryBuilderToExpr"
|
||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// PostablePipelines are a list of user defined pielines
|
// PostablePipelines are a list of user defined pielines
|
||||||
@ -19,14 +18,14 @@ type PostablePipelines struct {
|
|||||||
// PostablePipeline captures user inputs in setting the pipeline
|
// PostablePipeline captures user inputs in setting the pipeline
|
||||||
|
|
||||||
type PostablePipeline struct {
|
type PostablePipeline struct {
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
OrderId int `json:"orderId"`
|
OrderId int `json:"orderId"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Alias string `json:"alias"`
|
Alias string `json:"alias"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
Filter string `json:"filter"`
|
Filter *v3.FilterSet `json:"filter"`
|
||||||
Config []model.PipelineOperator `json:"config"`
|
Config []PipelineOperator `json:"config"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsValid checks if postable pipeline has all the required params
|
// IsValid checks if postable pipeline has all the required params
|
||||||
@ -42,12 +41,8 @@ func (p *PostablePipeline) IsValid() error {
|
|||||||
return fmt.Errorf("pipeline alias is required")
|
return fmt.Errorf("pipeline alias is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.Filter == "" {
|
// check the filter
|
||||||
return fmt.Errorf("pipeline filter is required")
|
_, err := queryBuilderToExpr.Parse(p.Filter)
|
||||||
}
|
|
||||||
|
|
||||||
// check the expression
|
|
||||||
_, err := expr.Compile(p.Filter, expr.AsBool(), expr.AllowUndefinedVariables())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf(fmt.Sprintf("filter for pipeline %v is not correct: %v", p.Name, err.Error()))
|
return fmt.Errorf(fmt.Sprintf("filter for pipeline %v is not correct: %v", p.Name, err.Error()))
|
||||||
}
|
}
|
||||||
@ -95,7 +90,7 @@ func (p *PostablePipeline) IsValid() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func isValidOperator(op model.PipelineOperator) error {
|
func isValidOperator(op PipelineOperator) error {
|
||||||
if op.ID == "" {
|
if op.ID == "" {
|
||||||
return errors.New("PipelineOperator.ID is required.")
|
return errors.New("PipelineOperator.ID is required.")
|
||||||
}
|
}
|
||||||
|
@ -4,74 +4,102 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var correctQueriesTest = []struct {
|
|
||||||
Name string
|
|
||||||
Pipeline PostablePipeline
|
|
||||||
IsValid bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
Name: "No orderId",
|
|
||||||
Pipeline: PostablePipeline{
|
|
||||||
Name: "pipeline 1",
|
|
||||||
Alias: "pipeline1",
|
|
||||||
Enabled: true,
|
|
||||||
Filter: "attributes.method == \"GET\"",
|
|
||||||
Config: []model.PipelineOperator{},
|
|
||||||
},
|
|
||||||
IsValid: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "Invalid orderId",
|
|
||||||
Pipeline: PostablePipeline{
|
|
||||||
OrderId: 0,
|
|
||||||
Name: "pipeline 1",
|
|
||||||
Alias: "pipeline1",
|
|
||||||
Enabled: true,
|
|
||||||
Filter: "attributes.method == \"GET\"",
|
|
||||||
Config: []model.PipelineOperator{},
|
|
||||||
},
|
|
||||||
IsValid: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "Valid orderId",
|
|
||||||
Pipeline: PostablePipeline{
|
|
||||||
OrderId: 1,
|
|
||||||
Name: "pipeline 1",
|
|
||||||
Alias: "pipeline1",
|
|
||||||
Enabled: true,
|
|
||||||
Filter: "attributes.method == \"GET\"",
|
|
||||||
Config: []model.PipelineOperator{},
|
|
||||||
},
|
|
||||||
IsValid: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "Invalid filter",
|
|
||||||
Pipeline: PostablePipeline{
|
|
||||||
OrderId: 1,
|
|
||||||
Name: "pipeline 1",
|
|
||||||
Alias: "pipeline1",
|
|
||||||
Enabled: true,
|
|
||||||
Filter: "test filter",
|
|
||||||
},
|
|
||||||
IsValid: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "Valid filter",
|
|
||||||
Pipeline: PostablePipeline{
|
|
||||||
OrderId: 1,
|
|
||||||
Name: "pipeline 1",
|
|
||||||
Alias: "pipeline1",
|
|
||||||
Enabled: true,
|
|
||||||
Filter: "attributes.method == \"GET\"",
|
|
||||||
},
|
|
||||||
IsValid: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIsValidPostablePipeline(t *testing.T) {
|
func TestIsValidPostablePipeline(t *testing.T) {
|
||||||
|
validPipelineFilterSet := &v3.FilterSet{
|
||||||
|
Operator: "AND",
|
||||||
|
Items: []v3.FilterItem{
|
||||||
|
{
|
||||||
|
Key: v3.AttributeKey{
|
||||||
|
Key: "method",
|
||||||
|
DataType: v3.AttributeKeyDataTypeString,
|
||||||
|
Type: v3.AttributeKeyTypeTag,
|
||||||
|
},
|
||||||
|
Operator: "=",
|
||||||
|
Value: "GET",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var correctQueriesTest = []struct {
|
||||||
|
Name string
|
||||||
|
Pipeline PostablePipeline
|
||||||
|
IsValid bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Name: "No orderId",
|
||||||
|
Pipeline: PostablePipeline{
|
||||||
|
Name: "pipeline 1",
|
||||||
|
Alias: "pipeline1",
|
||||||
|
Enabled: true,
|
||||||
|
Filter: validPipelineFilterSet,
|
||||||
|
Config: []PipelineOperator{},
|
||||||
|
},
|
||||||
|
IsValid: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Invalid orderId",
|
||||||
|
Pipeline: PostablePipeline{
|
||||||
|
OrderId: 0,
|
||||||
|
Name: "pipeline 1",
|
||||||
|
Alias: "pipeline1",
|
||||||
|
Enabled: true,
|
||||||
|
Filter: validPipelineFilterSet,
|
||||||
|
Config: []PipelineOperator{},
|
||||||
|
},
|
||||||
|
IsValid: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Valid orderId",
|
||||||
|
Pipeline: PostablePipeline{
|
||||||
|
OrderId: 1,
|
||||||
|
Name: "pipeline 1",
|
||||||
|
Alias: "pipeline1",
|
||||||
|
Enabled: true,
|
||||||
|
Filter: validPipelineFilterSet,
|
||||||
|
Config: []PipelineOperator{},
|
||||||
|
},
|
||||||
|
IsValid: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Invalid filter",
|
||||||
|
Pipeline: PostablePipeline{
|
||||||
|
OrderId: 1,
|
||||||
|
Name: "pipeline 1",
|
||||||
|
Alias: "pipeline1",
|
||||||
|
Enabled: true,
|
||||||
|
Filter: &v3.FilterSet{
|
||||||
|
Operator: "AND",
|
||||||
|
Items: []v3.FilterItem{
|
||||||
|
{
|
||||||
|
Key: v3.AttributeKey{
|
||||||
|
Key: "method",
|
||||||
|
DataType: v3.AttributeKeyDataTypeString,
|
||||||
|
Type: v3.AttributeKeyTypeUnspecified,
|
||||||
|
},
|
||||||
|
Operator: "regex",
|
||||||
|
Value: "[0-9A-Z*",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
IsValid: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Valid filter",
|
||||||
|
Pipeline: PostablePipeline{
|
||||||
|
OrderId: 1,
|
||||||
|
Name: "pipeline 1",
|
||||||
|
Alias: "pipeline1",
|
||||||
|
Enabled: true,
|
||||||
|
Filter: validPipelineFilterSet,
|
||||||
|
},
|
||||||
|
IsValid: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
for _, test := range correctQueriesTest {
|
for _, test := range correctQueriesTest {
|
||||||
Convey(test.Name, t, func() {
|
Convey(test.Name, t, func() {
|
||||||
err := test.Pipeline.IsValid()
|
err := test.Pipeline.IsValid()
|
||||||
@ -86,12 +114,12 @@ func TestIsValidPostablePipeline(t *testing.T) {
|
|||||||
|
|
||||||
var operatorTest = []struct {
|
var operatorTest = []struct {
|
||||||
Name string
|
Name string
|
||||||
Operator model.PipelineOperator
|
Operator PipelineOperator
|
||||||
IsValid bool
|
IsValid bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
Name: "Operator - without id",
|
Name: "Operator - without id",
|
||||||
Operator: model.PipelineOperator{
|
Operator: PipelineOperator{
|
||||||
Type: "remove",
|
Type: "remove",
|
||||||
Field: "attributes.abc",
|
Field: "attributes.abc",
|
||||||
},
|
},
|
||||||
@ -99,7 +127,7 @@ var operatorTest = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Operator - without type",
|
Name: "Operator - without type",
|
||||||
Operator: model.PipelineOperator{
|
Operator: PipelineOperator{
|
||||||
ID: "test",
|
ID: "test",
|
||||||
Field: "attributes.abc",
|
Field: "attributes.abc",
|
||||||
},
|
},
|
||||||
@ -107,7 +135,7 @@ var operatorTest = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Copy - invalid to and from",
|
Name: "Copy - invalid to and from",
|
||||||
Operator: model.PipelineOperator{
|
Operator: PipelineOperator{
|
||||||
ID: "copy",
|
ID: "copy",
|
||||||
Type: "copy",
|
Type: "copy",
|
||||||
From: "date",
|
From: "date",
|
||||||
@ -117,7 +145,7 @@ var operatorTest = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Move - invalid to and from",
|
Name: "Move - invalid to and from",
|
||||||
Operator: model.PipelineOperator{
|
Operator: PipelineOperator{
|
||||||
ID: "move",
|
ID: "move",
|
||||||
Type: "move",
|
Type: "move",
|
||||||
From: "attributes",
|
From: "attributes",
|
||||||
@ -127,7 +155,7 @@ var operatorTest = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Add - invalid to and from",
|
Name: "Add - invalid to and from",
|
||||||
Operator: model.PipelineOperator{
|
Operator: PipelineOperator{
|
||||||
ID: "add",
|
ID: "add",
|
||||||
Type: "add",
|
Type: "add",
|
||||||
Field: "data",
|
Field: "data",
|
||||||
@ -136,7 +164,7 @@ var operatorTest = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Remove - invalid to and from",
|
Name: "Remove - invalid to and from",
|
||||||
Operator: model.PipelineOperator{
|
Operator: PipelineOperator{
|
||||||
ID: "remove",
|
ID: "remove",
|
||||||
Type: "remove",
|
Type: "remove",
|
||||||
Field: "data",
|
Field: "data",
|
||||||
@ -145,7 +173,7 @@ var operatorTest = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Add - valid",
|
Name: "Add - valid",
|
||||||
Operator: model.PipelineOperator{
|
Operator: PipelineOperator{
|
||||||
ID: "add",
|
ID: "add",
|
||||||
Type: "add",
|
Type: "add",
|
||||||
Field: "body",
|
Field: "body",
|
||||||
@ -155,7 +183,7 @@ var operatorTest = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Move - valid",
|
Name: "Move - valid",
|
||||||
Operator: model.PipelineOperator{
|
Operator: PipelineOperator{
|
||||||
ID: "move",
|
ID: "move",
|
||||||
Type: "move",
|
Type: "move",
|
||||||
From: "attributes.x1",
|
From: "attributes.x1",
|
||||||
@ -165,7 +193,7 @@ var operatorTest = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Copy - valid",
|
Name: "Copy - valid",
|
||||||
Operator: model.PipelineOperator{
|
Operator: PipelineOperator{
|
||||||
ID: "copy",
|
ID: "copy",
|
||||||
Type: "copy",
|
Type: "copy",
|
||||||
From: "resource.x1",
|
From: "resource.x1",
|
||||||
@ -175,7 +203,7 @@ var operatorTest = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Unknown operator",
|
Name: "Unknown operator",
|
||||||
Operator: model.PipelineOperator{
|
Operator: PipelineOperator{
|
||||||
ID: "copy",
|
ID: "copy",
|
||||||
Type: "operator",
|
Type: "operator",
|
||||||
From: "resource.x1",
|
From: "resource.x1",
|
||||||
@ -185,7 +213,7 @@ var operatorTest = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Grok - valid",
|
Name: "Grok - valid",
|
||||||
Operator: model.PipelineOperator{
|
Operator: PipelineOperator{
|
||||||
ID: "grok",
|
ID: "grok",
|
||||||
Type: "grok_parser",
|
Type: "grok_parser",
|
||||||
Pattern: "%{COMMONAPACHELOG}",
|
Pattern: "%{COMMONAPACHELOG}",
|
||||||
@ -195,7 +223,7 @@ var operatorTest = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Grok - invalid",
|
Name: "Grok - invalid",
|
||||||
Operator: model.PipelineOperator{
|
Operator: PipelineOperator{
|
||||||
ID: "grok",
|
ID: "grok",
|
||||||
Type: "grok_parser",
|
Type: "grok_parser",
|
||||||
Pattern: "%{COMMONAPACHELOG}",
|
Pattern: "%{COMMONAPACHELOG}",
|
||||||
@ -205,7 +233,7 @@ var operatorTest = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Regex - valid",
|
Name: "Regex - valid",
|
||||||
Operator: model.PipelineOperator{
|
Operator: PipelineOperator{
|
||||||
ID: "regex",
|
ID: "regex",
|
||||||
Type: "regex_parser",
|
Type: "regex_parser",
|
||||||
Regex: "(?P<time>[^ Z]+) (?P<stream>stdout|stderr) (?P<logtag>[^ ]*) ?(?P<log>.*)$",
|
Regex: "(?P<time>[^ Z]+) (?P<stream>stdout|stderr) (?P<logtag>[^ ]*) ?(?P<log>.*)$",
|
||||||
@ -215,7 +243,7 @@ var operatorTest = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Regex - invalid",
|
Name: "Regex - invalid",
|
||||||
Operator: model.PipelineOperator{
|
Operator: PipelineOperator{
|
||||||
ID: "regex",
|
ID: "regex",
|
||||||
Type: "regex_parser",
|
Type: "regex_parser",
|
||||||
Regex: "abcd",
|
Regex: "abcd",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package v3
|
package v3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
@ -8,6 +9,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
"go.signoz.io/signoz/pkg/query-service/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -529,6 +531,22 @@ func (f *FilterSet) Validate() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For serializing to and from db
|
||||||
|
func (f *FilterSet) Scan(src interface{}) error {
|
||||||
|
if data, ok := src.([]byte); ok {
|
||||||
|
return json.Unmarshal(data, &f)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FilterSet) Value() (driver.Value, error) {
|
||||||
|
filterSetJson, err := json.Marshal(f)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not serialize FilterSet to JSON")
|
||||||
|
}
|
||||||
|
return filterSetJson, nil
|
||||||
|
}
|
||||||
|
|
||||||
type FilterOperator string
|
type FilterOperator string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
"github.com/open-telemetry/opamp-go/protobufs"
|
"github.com/open-telemetry/opamp-go/protobufs"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
"go.signoz.io/signoz/pkg/query-service/agentConf"
|
"go.signoz.io/signoz/pkg/query-service/agentConf"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app"
|
"go.signoz.io/signoz/pkg/query-service/app"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app/logparsingpipeline"
|
"go.signoz.io/signoz/pkg/query-service/app/logparsingpipeline"
|
||||||
@ -28,7 +29,10 @@ import (
|
|||||||
"go.signoz.io/signoz/pkg/query-service/constants"
|
"go.signoz.io/signoz/pkg/query-service/constants"
|
||||||
"go.signoz.io/signoz/pkg/query-service/dao"
|
"go.signoz.io/signoz/pkg/query-service/dao"
|
||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
"go.signoz.io/signoz/pkg/query-service/model"
|
||||||
|
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||||
|
"go.signoz.io/signoz/pkg/query-service/queryBuilderToExpr"
|
||||||
"golang.org/x/exp/maps"
|
"golang.org/x/exp/maps"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLogPipelinesLifecycle(t *testing.T) {
|
func TestLogPipelinesLifecycle(t *testing.T) {
|
||||||
@ -46,6 +50,21 @@ func TestLogPipelinesLifecycle(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Should be able to create pipelines config
|
// Should be able to create pipelines config
|
||||||
|
pipelineFilterSet := &v3.FilterSet{
|
||||||
|
Operator: "AND",
|
||||||
|
Items: []v3.FilterItem{
|
||||||
|
{
|
||||||
|
Key: v3.AttributeKey{
|
||||||
|
Key: "method",
|
||||||
|
DataType: v3.AttributeKeyDataTypeString,
|
||||||
|
Type: v3.AttributeKeyTypeTag,
|
||||||
|
},
|
||||||
|
Operator: "=",
|
||||||
|
Value: "GET",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
postablePipelines := logparsingpipeline.PostablePipelines{
|
postablePipelines := logparsingpipeline.PostablePipelines{
|
||||||
Pipelines: []logparsingpipeline.PostablePipeline{
|
Pipelines: []logparsingpipeline.PostablePipeline{
|
||||||
{
|
{
|
||||||
@ -53,8 +72,8 @@ func TestLogPipelinesLifecycle(t *testing.T) {
|
|||||||
Name: "pipeline1",
|
Name: "pipeline1",
|
||||||
Alias: "pipeline1",
|
Alias: "pipeline1",
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Filter: "attributes.method == \"GET\"",
|
Filter: pipelineFilterSet,
|
||||||
Config: []model.PipelineOperator{
|
Config: []logparsingpipeline.PipelineOperator{
|
||||||
{
|
{
|
||||||
OrderId: 1,
|
OrderId: 1,
|
||||||
ID: "add",
|
ID: "add",
|
||||||
@ -70,8 +89,8 @@ func TestLogPipelinesLifecycle(t *testing.T) {
|
|||||||
Name: "pipeline2",
|
Name: "pipeline2",
|
||||||
Alias: "pipeline2",
|
Alias: "pipeline2",
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Filter: "attributes.method == \"GET\"",
|
Filter: pipelineFilterSet,
|
||||||
Config: []model.PipelineOperator{
|
Config: []logparsingpipeline.PipelineOperator{
|
||||||
{
|
{
|
||||||
OrderId: 1,
|
OrderId: 1,
|
||||||
ID: "remove",
|
ID: "remove",
|
||||||
@ -150,6 +169,21 @@ func TestLogPipelinesLifecycle(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLogPipelinesValidation(t *testing.T) {
|
func TestLogPipelinesValidation(t *testing.T) {
|
||||||
|
validPipelineFilterSet := &v3.FilterSet{
|
||||||
|
Operator: "AND",
|
||||||
|
Items: []v3.FilterItem{
|
||||||
|
{
|
||||||
|
Key: v3.AttributeKey{
|
||||||
|
Key: "method",
|
||||||
|
DataType: v3.AttributeKeyDataTypeString,
|
||||||
|
Type: v3.AttributeKeyTypeTag,
|
||||||
|
},
|
||||||
|
Operator: "=",
|
||||||
|
Value: "GET",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
Name string
|
Name string
|
||||||
Pipeline logparsingpipeline.PostablePipeline
|
Pipeline logparsingpipeline.PostablePipeline
|
||||||
@ -162,8 +196,8 @@ func TestLogPipelinesValidation(t *testing.T) {
|
|||||||
Name: "pipeline 1",
|
Name: "pipeline 1",
|
||||||
Alias: "pipeline1",
|
Alias: "pipeline1",
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Filter: "attributes.method == \"GET\"",
|
Filter: validPipelineFilterSet,
|
||||||
Config: []model.PipelineOperator{
|
Config: []logparsingpipeline.PipelineOperator{
|
||||||
{
|
{
|
||||||
OrderId: 1,
|
OrderId: 1,
|
||||||
ID: "add",
|
ID: "add",
|
||||||
@ -184,8 +218,8 @@ func TestLogPipelinesValidation(t *testing.T) {
|
|||||||
Name: "pipeline 1",
|
Name: "pipeline 1",
|
||||||
Alias: "pipeline1",
|
Alias: "pipeline1",
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Filter: "attributes.method == \"GET\"",
|
Filter: validPipelineFilterSet,
|
||||||
Config: []model.PipelineOperator{
|
Config: []logparsingpipeline.PipelineOperator{
|
||||||
{
|
{
|
||||||
OrderId: 1,
|
OrderId: 1,
|
||||||
ID: "add",
|
ID: "add",
|
||||||
@ -206,8 +240,8 @@ func TestLogPipelinesValidation(t *testing.T) {
|
|||||||
Name: "pipeline 1",
|
Name: "pipeline 1",
|
||||||
Alias: "pipeline1",
|
Alias: "pipeline1",
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Filter: "bad filter",
|
Filter: &v3.FilterSet{},
|
||||||
Config: []model.PipelineOperator{
|
Config: []logparsingpipeline.PipelineOperator{
|
||||||
{
|
{
|
||||||
OrderId: 1,
|
OrderId: 1,
|
||||||
ID: "add",
|
ID: "add",
|
||||||
@ -228,8 +262,8 @@ func TestLogPipelinesValidation(t *testing.T) {
|
|||||||
Name: "pipeline 1",
|
Name: "pipeline 1",
|
||||||
Alias: "pipeline1",
|
Alias: "pipeline1",
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Filter: "attributes.method == \"GET\"",
|
Filter: validPipelineFilterSet,
|
||||||
Config: []model.PipelineOperator{
|
Config: []logparsingpipeline.PipelineOperator{
|
||||||
{
|
{
|
||||||
OrderId: 1,
|
OrderId: 1,
|
||||||
ID: "add",
|
ID: "add",
|
||||||
@ -411,32 +445,32 @@ func (tb *LogPipelinesTestBed) GetPipelinesFromQS() *logparsingpipeline.Pipeline
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tb *LogPipelinesTestBed) assertPipelinesSentToOpampClient(
|
func (tb *LogPipelinesTestBed) assertPipelinesSentToOpampClient(
|
||||||
pipelines []model.Pipeline,
|
pipelines []logparsingpipeline.Pipeline,
|
||||||
) {
|
) {
|
||||||
lastMsg := tb.opampClientConn.latestMsgFromServer()
|
lastMsg := tb.opampClientConn.latestMsgFromServer()
|
||||||
otelConfigFiles := lastMsg.RemoteConfig.Config.ConfigMap
|
collectorConfigFiles := lastMsg.RemoteConfig.Config.ConfigMap
|
||||||
assert.Equal(
|
assert.Equal(
|
||||||
tb.t, len(otelConfigFiles), 1,
|
tb.t, len(collectorConfigFiles), 1,
|
||||||
"otel config sent to client is expected to contain atleast 1 file",
|
"otel config sent to client is expected to contain atleast 1 file",
|
||||||
)
|
)
|
||||||
|
|
||||||
otelConfigYaml := maps.Values(otelConfigFiles)[0].Body
|
collectorConfigYaml := maps.Values(collectorConfigFiles)[0].Body
|
||||||
otelConfSentToClient, err := yaml.Parser().Unmarshal(otelConfigYaml)
|
collectorConfSentToClient, err := yaml.Parser().Unmarshal(collectorConfigYaml)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tb.t.Fatalf("could not unmarshal config file sent to opamp client: %v", err)
|
tb.t.Fatalf("could not unmarshal config file sent to opamp client: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Each pipeline is expected to become its own processor
|
// Each pipeline is expected to become its own processor
|
||||||
// in the logs service in otel collector config.
|
// in the logs service in otel collector config.
|
||||||
otelConfSvcs := otelConfSentToClient["service"].(map[string]interface{})
|
collectorConfSvcs := collectorConfSentToClient["service"].(map[string]interface{})
|
||||||
otelConfLogsSvc := otelConfSvcs["pipelines"].(map[string]interface{})["logs"].(map[string]interface{})
|
collectorConfLogsSvc := collectorConfSvcs["pipelines"].(map[string]interface{})["logs"].(map[string]interface{})
|
||||||
otelConfLogsSvcProcessorNames := otelConfLogsSvc["processors"].([]interface{})
|
collectorConfLogsSvcProcessorNames := collectorConfLogsSvc["processors"].([]interface{})
|
||||||
otelConfLogsPipelineProcNames := []string{}
|
collectorConfLogsPipelineProcNames := []string{}
|
||||||
for _, procNameVal := range otelConfLogsSvcProcessorNames {
|
for _, procNameVal := range collectorConfLogsSvcProcessorNames {
|
||||||
procName := procNameVal.(string)
|
procName := procNameVal.(string)
|
||||||
if strings.HasPrefix(procName, constants.LogsPPLPfx) {
|
if strings.HasPrefix(procName, constants.LogsPPLPfx) {
|
||||||
otelConfLogsPipelineProcNames = append(
|
collectorConfLogsPipelineProcNames = append(
|
||||||
otelConfLogsPipelineProcNames,
|
collectorConfLogsPipelineProcNames,
|
||||||
procName,
|
procName,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -444,16 +478,40 @@ func (tb *LogPipelinesTestBed) assertPipelinesSentToOpampClient(
|
|||||||
|
|
||||||
_, expectedLogProcessorNames, err := logparsingpipeline.PreparePipelineProcessor(pipelines)
|
_, expectedLogProcessorNames, err := logparsingpipeline.PreparePipelineProcessor(pipelines)
|
||||||
assert.Equal(
|
assert.Equal(
|
||||||
tb.t, expectedLogProcessorNames, otelConfLogsPipelineProcNames,
|
tb.t, expectedLogProcessorNames, collectorConfLogsPipelineProcNames,
|
||||||
"config sent to opamp client doesn't contain expected log pipelines",
|
"config sent to opamp client doesn't contain expected log pipelines",
|
||||||
)
|
)
|
||||||
|
|
||||||
otelConfProcessors := otelConfSentToClient["processors"].(map[string]interface{})
|
collectorConfProcessors := collectorConfSentToClient["processors"].(map[string]interface{})
|
||||||
for _, procName := range expectedLogProcessorNames {
|
for _, procName := range expectedLogProcessorNames {
|
||||||
_, procExists := otelConfProcessors[procName]
|
pipelineProcessorInConf, procExists := collectorConfProcessors[procName]
|
||||||
assert.True(tb.t, procExists, fmt.Sprintf(
|
assert.True(tb.t, procExists, fmt.Sprintf(
|
||||||
"%s processor not found in config sent to opamp client", procName,
|
"%s processor not found in config sent to opamp client", procName,
|
||||||
))
|
))
|
||||||
|
|
||||||
|
// Validate that filter expr in collector conf is as expected.
|
||||||
|
|
||||||
|
// extract expr present in collector conf processor
|
||||||
|
pipelineProcOps := pipelineProcessorInConf.(map[string]interface{})["operators"].([]interface{})
|
||||||
|
|
||||||
|
routerOpIdx := slices.IndexFunc(
|
||||||
|
pipelineProcOps,
|
||||||
|
func(op interface{}) bool { return op.(map[string]interface{})["id"] == "router_signoz" },
|
||||||
|
)
|
||||||
|
require.GreaterOrEqual(tb.t, routerOpIdx, 0)
|
||||||
|
routerOproutes := pipelineProcOps[routerOpIdx].(map[string]interface{})["routes"].([]interface{})
|
||||||
|
pipelineFilterExpr := routerOproutes[0].(map[string]interface{})["expr"].(string)
|
||||||
|
|
||||||
|
// find logparsingpipeline.Pipeline whose processor is being validated here
|
||||||
|
pipelineIdx := slices.IndexFunc(
|
||||||
|
pipelines, func(p logparsingpipeline.Pipeline) bool {
|
||||||
|
return logparsingpipeline.CollectorConfProcessorName(p) == procName
|
||||||
|
},
|
||||||
|
)
|
||||||
|
require.GreaterOrEqual(tb.t, pipelineIdx, 0)
|
||||||
|
expectedExpr, err := queryBuilderToExpr.Parse(pipelines[pipelineIdx].Filter)
|
||||||
|
require.Nil(tb.t, err)
|
||||||
|
require.Equal(tb.t, expectedExpr, pipelineFilterExpr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -633,8 +691,8 @@ func (conn *mockOpAmpConnection) latestMsgFromServer() *protobufs.ServerToAgent
|
|||||||
return conn.serverToAgentMsgs[len(conn.serverToAgentMsgs)-1]
|
return conn.serverToAgentMsgs[len(conn.serverToAgentMsgs)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conn *mockOpAmpConnection) LatestPipelinesReceivedFromServer() ([]model.Pipeline, error) {
|
func (conn *mockOpAmpConnection) LatestPipelinesReceivedFromServer() ([]logparsingpipeline.Pipeline, error) {
|
||||||
pipelines := []model.Pipeline{}
|
pipelines := []logparsingpipeline.Pipeline{}
|
||||||
lastMsg := conn.latestMsgFromServer()
|
lastMsg := conn.latestMsgFromServer()
|
||||||
if lastMsg == nil {
|
if lastMsg == nil {
|
||||||
return pipelines, nil
|
return pipelines, nil
|
||||||
|
Loading…
x
Reference in New Issue
Block a user