diff options
author | dyknon <dyknon@r5f.jp> | 2025-07-13 22:42:28 +0900 |
---|---|---|
committer | dyknon <dyknon@r5f.jp> | 2025-07-13 22:42:28 +0900 |
commit | 86fad60ef2b217cb975983d0d08edf1dcf4ec7cf (patch) | |
tree | 6c0c8a51b047c9a1f5fb89e159d00be2a0b1aef8 /part.go |
Initial commit
Diffstat (limited to 'part.go')
-rw-r--r-- | part.go | 150 |
1 files changed, 150 insertions, 0 deletions
@@ -0,0 +1,150 @@ +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] == "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 +} |