summaryrefslogtreecommitdiff
path: root/part.go
diff options
context:
space:
mode:
authordyknon <dyknon@r5f.jp>2025-07-13 22:42:28 +0900
committerdyknon <dyknon@r5f.jp>2025-07-13 22:42:28 +0900
commit86fad60ef2b217cb975983d0d08edf1dcf4ec7cf (patch)
tree6c0c8a51b047c9a1f5fb89e159d00be2a0b1aef8 /part.go
Initial commit
Diffstat (limited to 'part.go')
-rw-r--r--part.go150
1 files changed, 150 insertions, 0 deletions
diff --git a/part.go b/part.go
new file mode 100644
index 0000000..5ad5867
--- /dev/null
+++ b/part.go
@@ -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
+}