package main import ( "fmt" "strings" "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/model/relabel" ) type Part struct{ Name string Transforms []Transform Source Source } func (self Part) Get() (MetricFamilies, error){ mf, err := self.Source.Get() if err != nil{ return MetricFamilies{}, fmt.Errorf("while reading source: %w", err) } for _, t := range self.Transforms{ mf, err = t.Process(mf) if err != nil{ return MetricFamilies{}, fmt.Errorf("while transforming input: %w", err) } } return mf, nil } func PartFromArg(arg string, re map[string]*[]*relabel.Config) (Part, error){ tf := []Transform{} namef := func(n string)string{ return n } at := strings.Index(arg, "@") if at >= 0 && strings.IndexAny(arg[0:at], "=,:") < 0{ name := arg[0:at] namef = func(string)string{ return name } arg = arg[at+1:] } for true{ sp := strings.IndexAny(arg, "=,:") if sp < 0{ return Part{}, fmt.Errorf("Unexpected end of part spec") }else if arg[sp] == ':'{ if arg[0:sp] == "http" || arg[0:sp] == "https"{ s, err := NewHttpSource(arg) if err != nil{ return Part{}, err } return Part{ Name: namef(arg), Transforms: tf, Source: s, }, nil }else if arg[0:sp] == "unix+http"{ s, err := NewUnixHttpSource(arg) if err != nil{ return Part{}, err } return Part{ Name: namef(arg), Transforms: tf, Source: s, }, nil }else if arg[0:sp] == "file"{ fn := arg[sp+1:] if strings.HasPrefix(fn, "//"){ fn = fn[2:] } return Part{ Name: namef(fn), Transforms: tf, Source: FileSource(fn), }, nil }else{ return Part{}, fmt.Errorf("Unknown protocol %q", arg[0:sp]) } }else if arg[sp] == '='{ vstop := strings.Index(arg, ",") if vstop < 0{ return Part{}, fmt.Errorf("Unexpected end of part spec") } tf = append(tf, SetLabel{ Name: arg[0:sp], Val: arg[sp+1:vstop], }) arg = arg[vstop+1:] }else{ // arg[sp] == ',' r := re[arg[0:sp]] if r == nil{ return Part{}, fmt.Errorf("Undefined relabel %q", arg[0:sp]) } tf = append(tf, Relabel(*r)) arg = arg[sp+1:] } } return Part{}, fmt.Errorf("impossible branch") } type Parts []Part func (self Parts) Get() (MetricFamilies, error){ ret := EmptyMetricFamilies() for _, part := range self{ p, err := part.Get() if err != nil{ logger.Error(fmt.Sprintf("In %q: %s", part.Name, err.Error())) }else{ ret.Merge(p) } } return ret, nil } func PartsFromArgs( args []string, re map[string]*[]*relabel.Config, ) (Parts, error){ ret := Parts([]Part{}) for _, arg := range args{ p, err := PartFromArg(arg, re) if err != nil{ return []Part{}, err } ret = append(ret, p) } return ret, nil } type Transform interface{ Process(target MetricFamilies) (MetricFamilies, error) } type Relabel []*relabel.Config func (self Relabel) Process(target MetricFamilies) (MetricFamilies, error){ f := func(l labels.Labels) (labels.Labels, bool){ return relabel.Process(l, self...) } return target.Relabel(f), nil } type SetLabel struct{ Name string Val string } func (self SetLabel) Process(target MetricFamilies) (MetricFamilies, error){ f := func(l labels.Labels) (labels.Labels, bool){ l = l.Copy() for _, ll := range l{ if ll.Name == self.Name{ ll.Value = self.Val goto FIN } } l = append(l, labels.Label{ Name: self.Name, Value: self.Val, }) FIN: return l, true } return target.Relabel(f), nil }