package main import ( "strings" "io" "fmt" "os" "context" "net" "net/http" ) type Source interface{ Get() (MetricFamilies, error) } type textSource interface{ textGet() (io.ReadCloser, string, error) } func sourceGetHelper(self textSource) (MetricFamilies, error){ rc, ty, err := self.textGet() if err != nil{ return MetricFamilies{}, fmt.Errorf("while opening: %w", err) } text, err := io.ReadAll(rc) rc.Close() if err != nil{ return MetricFamilies{}, fmt.Errorf("while reading: %w", err) } ret, err := ParseMetrics(text, ty) if err != nil{ return MetricFamilies{}, fmt.Errorf("while parsing: %w", err) } return ret, nil } type FileSource string func (self FileSource) Get() (MetricFamilies, error){ return sourceGetHelper(self) } func (self FileSource) textGet() (io.ReadCloser, string, error){ f, err := os.Open(string(self)) if err != nil{ return nil, "", err } return f, "application/openmetrics-text", nil } type HttpSource struct{ vurl string client *http.Client } func NewHttpSource(loc string) (HttpSource, error){ return HttpSource{ vurl: loc, client: &http.Client{}, }, nil } func NewUnixHttpSource(loc string) (HttpSource, error){ colon := strings.Index(loc, ":") if colon < 0 { return HttpSource{}, fmt.Errorf("No protocol part") } if loc[0:colon] != "unix+http"{ return HttpSource{}, fmt.Errorf("Invalid protocol") } loc = loc[colon+1:] path := loc domstart := strings.Index(loc, "//") if 0 < domstart{ path = loc[0:domstart] if strings.Index(loc[domstart+2:], "/") < 0{ loc = "http:" + loc[domstart:] + "/metrics" }else{ loc = "http:" + loc[domstart:] } }else{ loc = "http://0.0.0.0/metrics" } tp := http.Transport{ DialContext: func(c context.Context, _, _ string)(net.Conn, error){ return (&net.Dialer{}).DialContext(c, "unix", path) }, } return HttpSource{ vurl: loc, client: &http.Client{Transport: &tp}, }, nil } func (self HttpSource) Get() (MetricFamilies, error){ return sourceGetHelper(self) } func (self HttpSource) textGet() (io.ReadCloser, string, error){ r, err := self.client.Get(self.vurl) if err != nil{ return nil, "", err } if r.StatusCode != 200{ r.Body.Close() return nil, "", fmt.Errorf("unexpected response: %s", r.Status) } return r.Body, r.Header.Get("Content-Type"), nil }