diff --git a/Makefile b/Makefile index 8ec71fe5..fb27c2d2 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,6 @@ endif define LDFLAGS -ldflags "\ -s -w \ - -extldflags \"-static\" \ -X ${VERSION_PACKAGE}.version=${VERSION} \ -X ${VERSION_PACKAGE}.gitSHA=${GIT_SHA} \ -X ${VERSION_PACKAGE}.buildTime=${DATE} \ diff --git a/README.md b/README.md index 863e975f..e6123d05 100644 --- a/README.md +++ b/README.md @@ -39,20 +39,3 @@ For details on creating the custom resource files that drive support-bundle coll # Community For questions about using Troubleshoot, there's a [Replicated Community](https://help.replicated.com/community) forum, and a [#app-troubleshoot channel in Kubernetes Slack](https://kubernetes.slack.com/channels/app-troubleshoot). - -# Building - -The following packages are required for building the project from source code: - -pkg-config -librrd-dev -libglib2.0-dev -libcairo2-dev -libpango1.0-dev -libpixman-1-dev -libpng-dev -libsdl-pango-dev -libthai-dev -libpcre3-dev - -There are known issues with libc6 2.27-3ubuntu1.2 on Ubuntu 18. Upgrading to 2.27-3ubuntu1.3 (apt-get install libc6) resolves these. \ No newline at end of file diff --git a/deploy/.goreleaser.yaml b/deploy/.goreleaser.yaml index a135fd8b..cd2f1fba 100644 --- a/deploy/.goreleaser.yaml +++ b/deploy/.goreleaser.yaml @@ -10,7 +10,7 @@ builds: goarch: - amd64 env: - - CGO_ENABLED=1 + - CGO_ENABLED=0 - GO111MODULE=on main: ffi/main.go flags: -buildmode=c-shared @@ -23,13 +23,12 @@ builds: goarch: - amd64 env: - - CGO_ENABLED=1 + - CGO_ENABLED=0 main: cmd/preflight/main.go ldflags: -s -w -X github.com/replicatedhq/troubleshoot/pkg/version.version={{.Version}} -X github.com/replicatedhq/troubleshoot/pkg/version.gitSHA={{.Commit}} -X github.com/replicatedhq/troubleshoot/pkg/version.buildTime={{.Date}} - -extldflags "-static" flags: -tags netgo -installsuffix netgo binary: preflight hooks: {} @@ -45,7 +44,6 @@ builds: -X github.com/replicatedhq/troubleshoot/pkg/version.version={{.Version}} -X github.com/replicatedhq/troubleshoot/pkg/version.gitSHA={{.Commit}} -X github.com/replicatedhq/troubleshoot/pkg/version.buildTime={{.Date}} - -extldflags "-static" flags: -tags netgo -installsuffix netgo binary: preflight hooks: {} @@ -56,13 +54,12 @@ builds: goarch: - amd64 env: - - CGO_ENABLED=1 + - CGO_ENABLED=0 main: cmd/troubleshoot/main.go ldflags: -s -w -X github.com/replicatedhq/troubleshoot/pkg/version.version={{.Version}} -X github.com/replicatedhq/troubleshoot/pkg/version.gitSHA={{.Commit}} -X github.com/replicatedhq/troubleshoot/pkg/version.buildTime={{.Date}} - -extldflags "-static" flags: -tags netgo -installsuffix netgo binary: support-bundle hooks: {} @@ -78,7 +75,6 @@ builds: -X github.com/replicatedhq/troubleshoot/pkg/version.version={{.Version}} -X github.com/replicatedhq/troubleshoot/pkg/version.gitSHA={{.Commit}} -X github.com/replicatedhq/troubleshoot/pkg/version.buildTime={{.Date}} - -extldflags "-static" flags: -tags netgo -installsuffix netgo binary: support-bundle hooks: {} diff --git a/pkg/analyze/analyzer.go b/pkg/analyze/analyzer.go index 529b5ae4..8c4a6b10 100644 --- a/pkg/analyze/analyzer.go +++ b/pkg/analyze/analyzer.go @@ -251,20 +251,6 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont } return []*AnalyzeResult{result}, nil } - if analyzer.Collectd != nil { - isExcluded, err := isExcluded(analyzer.Collectd.Exclude) - if err != nil { - return nil, err - } - if isExcluded { - return nil, nil - } - result, err := analyzeCollectd(analyzer.Collectd, findFiles) - if err != nil { - return nil, err - } - return []*AnalyzeResult{result}, nil - } return nil, errors.New("invalid analyzer") } diff --git a/pkg/analyze/collectd.go b/pkg/analyze/collectd.go deleted file mode 100644 index 6b49e6dc..00000000 --- a/pkg/analyze/collectd.go +++ /dev/null @@ -1,316 +0,0 @@ -package analyzer - -import ( - "archive/tar" - "bytes" - "io" - "io/ioutil" - "math" - "os" - "path/filepath" - "strconv" - "strings" - "time" - - "github.com/pkg/errors" - troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2" - "github.com/replicatedhq/troubleshoot/pkg/rrd" -) - -type CollectdSummary struct { - Load float64 -} - -func analyzeCollectd(analyzer *troubleshootv1beta2.CollectdAnalyze, getCollectedFileContents func(string) (map[string][]byte, error)) (*AnalyzeResult, error) { - rrdArchives, err := getCollectedFileContents("/collectd/rrd/*.tar") - if err != nil { - return nil, errors.Wrap(err, "failed to find rrd archives") - } - - tmpDir, err := ioutil.TempDir("", "rrd") - if err != nil { - return nil, errors.Wrap(err, "failed to create temp rrd dir") - } - defer os.RemoveAll(tmpDir) - - for name, data := range rrdArchives { - destDir := filepath.Join(tmpDir, filepath.Base(name)) - if err := extractRRDFiles(data, destDir); err != nil { - return nil, errors.Wrap(err, "failed to extract rrd file") - } - } - - loadFiles, err := findRRDLoadFiles(tmpDir) - if err != nil { - return nil, errors.Wrap(err, "failed to find load files") - } - - collectdSummary := CollectdSummary{ - Load: 0, - } - - // load files are always present, so this loop can be used for all host metrics - for _, loadFile := range loadFiles { - pathParts := strings.Split(loadFile, string(filepath.Separator)) - if len(pathParts) < 3 { - continue - } - - // ...//load/load.rrd - hostname := pathParts[len(pathParts)-3] - hostDir := strings.TrimSuffix(loadFile, "/load/load.rrd") - - hostLoad, err := getHostLoad(analyzer, loadFile, hostDir) - if err != nil { - return nil, errors.Wrapf(err, "failed to find analyze %s files", hostname) - } - - collectdSummary.Load = math.Max(collectdSummary.Load, hostLoad) - } - - result, err := getCollectdAnalyzerOutcome(analyzer, collectdSummary) - if err != nil { - return nil, errors.Wrap(err, "failed to generate outcome") - } - - return result, nil -} - -func extractRRDFiles(archiveData []byte, dst string) error { - tarReader := tar.NewReader(bytes.NewReader(archiveData)) - for { - header, err := tarReader.Next() - if err == io.EOF { - return nil - } else if err != nil { - return errors.Wrap(err, "failed to read rrd archive") - } - - if header.Typeflag != tar.TypeReg { - continue - } - - dstFileName := filepath.Join(dst, header.Name) - - if err := os.MkdirAll(filepath.Dir(dstFileName), 0755); err != nil { - return errors.Wrap(err, "failed to create dest path") - } - - err = func() error { - f, err := os.Create(dstFileName) - if err != nil { - return errors.Wrap(err, "failed to create dest file") - } - defer f.Close() - - _, err = io.Copy(f, tarReader) - if err != nil { - return errors.Wrap(err, "failed to copy") - } - return nil - }() - - if err != nil { - return errors.Wrap(err, "failed to write dest file") - } - } -} - -func findRRDLoadFiles(rootDir string) ([]string, error) { - files := make([]string, 0) - err := filepath.Walk(rootDir, func(filename string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - if filepath.Base(filename) == "load.rrd" { - files = append(files, filename) - } - - return nil - }) - if err != nil { - return nil, errors.Wrap(err, "failed to find rrd load files") - } - - return files, nil -} - -func getHostLoad(analyzer *troubleshootv1beta2.CollectdAnalyze, loadFile string, hostRoot string) (float64, error) { - numberOfCPUs := 0 - err := filepath.Walk(hostRoot, func(filename string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if !info.IsDir() { - return nil - } - - if strings.HasPrefix(filepath.Base(filename), "cpu-") { - numberOfCPUs++ - } - return nil - }) - if err != nil { - return 0, errors.Wrap(err, "failed to find rrd files") - } - - if numberOfCPUs == 0 { - numberOfCPUs = 1 // what else can we do here? return an error? - } - - fileInfo, err := rrd.Info(loadFile) - if err != nil { - return 0, errors.Wrap(err, "failed to get rrd info") - } - - // Query RRD data. Start and end have to be multiples of step. - - window := 7 * 24 * time.Hour - step := 1 * time.Hour - lastUpdate := int64(fileInfo["last_update"].(uint)) - endSeconds := int64(lastUpdate/int64(step.Seconds())) * int64(step.Seconds()) - end := time.Unix(int64(endSeconds), 0) - start := end.Add(-window) - fetchResult, err := rrd.Fetch(loadFile, "MAX", start, end, step) - if err != nil { - return 0, errors.Wrap(err, "failed to fetch load data") - } - defer fetchResult.FreeValues() - - values := fetchResult.Values() - maxLoad := float64(0) - for i := 0; i < len(values); i += 3 { // +3 because "shortterm", "midterm", "longterm" - v := values[i+1] // midterm - if math.IsNaN(v) { - continue - } - maxLoad = math.Max(maxLoad, values[i+1]) - } - - return maxLoad / float64(numberOfCPUs), nil -} - -func getCollectdAnalyzerOutcome(analyzer *troubleshootv1beta2.CollectdAnalyze, collectdSummary CollectdSummary) (*AnalyzeResult, error) { - collectorName := analyzer.CollectorName - if collectorName == "" { - collectorName = "rrd" - } - - title := analyzer.CheckName - if title == "" { - title = collectorName - } - result := &AnalyzeResult{ - Title: title, - IconKey: "host_load_analyze", - IconURI: "https://troubleshoot.sh/images/analyzer-icons/rrd-analyze.svg", - } - - for _, outcome := range analyzer.Outcomes { - if outcome.Fail != nil { - if outcome.Fail.When == "" { - result.IsFail = true - result.Message = outcome.Fail.Message - result.URI = outcome.Fail.URI - - return result, nil - } - - isMatch, err := compareCollectdConditionalToActual(outcome.Fail.When, collectdSummary) - if err != nil { - return result, errors.Wrap(err, "failed to compare rrd fail conditional") - } - - if isMatch { - result.IsFail = true - result.Message = outcome.Fail.Message - result.URI = outcome.Fail.URI - - return result, nil - } - } else if outcome.Warn != nil { - if outcome.Pass.When == "" { - result.IsWarn = true - result.Message = outcome.Warn.Message - result.URI = outcome.Warn.URI - - return result, nil - } - - isMatch, err := compareCollectdConditionalToActual(outcome.Warn.When, collectdSummary) - if err != nil { - return result, errors.Wrap(err, "failed to compare rrd warn conditional") - } - - if isMatch { - result.IsWarn = true - result.Message = outcome.Warn.Message - result.URI = outcome.Warn.URI - - return result, nil - } - } else if outcome.Pass != nil { - if outcome.Pass.When == "" { - result.IsPass = true - result.Message = outcome.Pass.Message - result.URI = outcome.Pass.URI - - return result, nil - } - - isMatch, err := compareCollectdConditionalToActual(outcome.Pass.When, collectdSummary) - if err != nil { - return result, errors.Wrap(err, "failed to compare rrd pass conditional") - } - - if isMatch { - result.IsPass = true - result.Message = outcome.Pass.Message - result.URI = outcome.Pass.URI - - return result, nil - } - } - } - - return result, nil -} - -func compareCollectdConditionalToActual(conditional string, collectdSummary CollectdSummary) (bool, error) { - parts := strings.Split(strings.TrimSpace(conditional), " ") - - if len(parts) != 3 { - return false, errors.New("unable to parse conditional") - } - - switch parts[0] { - case "load": - expected, err := strconv.ParseFloat(parts[2], 64) - if err != nil { - return false, errors.Wrap(err, "failed to parse float") - } - - switch parts[1] { - case "=", "==", "===": - return collectdSummary.Load == expected, nil - case "!=", "!==": - return collectdSummary.Load != expected, nil - case "<": - return collectdSummary.Load < expected, nil - - case ">": - return collectdSummary.Load > expected, nil - - case "<=": - return collectdSummary.Load <= expected, nil - - case ">=": - return collectdSummary.Load >= expected, nil - } - - return false, errors.Errorf("unknown rrd comparator: %q", parts[0]) - } - - return false, nil -} diff --git a/pkg/apis/troubleshoot/v1beta2/analyzer_shared.go b/pkg/apis/troubleshoot/v1beta2/analyzer_shared.go index 4b40ccf3..cb608639 100644 --- a/pkg/apis/troubleshoot/v1beta2/analyzer_shared.go +++ b/pkg/apis/troubleshoot/v1beta2/analyzer_shared.go @@ -142,5 +142,4 @@ type Analyze struct { Postgres *DatabaseAnalyze `json:"postgres,omitempty" yaml:"postgres,omitempty"` Mysql *DatabaseAnalyze `json:"mysql,omitempty" yaml:"mysql,omitempty"` Redis *DatabaseAnalyze `json:"redis,omitempty" yaml:"redis,omitempty"` - Collectd *CollectdAnalyze `json:"collectd,omitempty" yaml:"collectd,omitempty"` } diff --git a/pkg/apis/troubleshoot/v1beta2/collector_shared.go b/pkg/apis/troubleshoot/v1beta2/collector_shared.go index 65d0db8b..e1a239b2 100644 --- a/pkg/apis/troubleshoot/v1beta2/collector_shared.go +++ b/pkg/apis/troubleshoot/v1beta2/collector_shared.go @@ -347,7 +347,7 @@ func (c *Collect) GetName() string { name = c.HTTP.CollectorName } if c.Collectd != nil { - collector = "rrd" + collector = "collectd" name = c.Collectd.CollectorName } diff --git a/pkg/apis/troubleshoot/v1beta2/zz_generated.deepcopy.go b/pkg/apis/troubleshoot/v1beta2/zz_generated.deepcopy.go index c89f296b..f947667f 100644 --- a/pkg/apis/troubleshoot/v1beta2/zz_generated.deepcopy.go +++ b/pkg/apis/troubleshoot/v1beta2/zz_generated.deepcopy.go @@ -127,11 +127,6 @@ func (in *Analyze) DeepCopyInto(out *Analyze) { *out = new(DatabaseAnalyze) (*in).DeepCopyInto(*out) } - if in.Collectd != nil { - in, out := &in.Collectd, &out.Collectd - *out = new(CollectdAnalyze) - (*in).DeepCopyInto(*out) - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Analyze. diff --git a/pkg/rrd/LICENSE b/pkg/rrd/LICENSE deleted file mode 100644 index 251010b0..00000000 --- a/pkg/rrd/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -Copyright (c) 2012, Michal Derkacz -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -3. The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/pkg/rrd/README.md b/pkg/rrd/README.md deleted file mode 100644 index 6f5df372..00000000 --- a/pkg/rrd/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Go bindings to rrdtool C library (rrdtool) - -This package implements [Go](http://golang.org) (golang) bindings for the [rrdtool](http://oss.oetiker.ch/rrdtool/) C API. - -## Installing - -rrd currently supports rrdtool-1.4.x - -Install rrd with: - - go get github.com/ziutek/rrd - -## Usage - -See [GoDoc](http://godoc.org/github.com/ziutek/rrd) for documentation. - -## Example -See [rrd_test.go](https://github.com/ziutek/rrd/blob/master/rrd_test.go) for an example of using this package. diff --git a/pkg/rrd/rrd.go b/pkg/rrd/rrd.go deleted file mode 100644 index aa300ea9..00000000 --- a/pkg/rrd/rrd.go +++ /dev/null @@ -1,505 +0,0 @@ -// Copied from "github.com/ziutek/rrd" - -// Simple wrapper for rrdtool C library -package rrd - -import ( - "fmt" - "math" - "os" - "runtime" - "strings" - "time" -) - -type Error string - -func (e Error) Error() string { - return string(e) -} - -/* -type cstring []byte - -func newCstring(s string) cstring { - cs := make(cstring, len(s)+1) - copy(cs, s) - return cs -} - -func (cs cstring) p() unsafe.Pointer { - if len(cs) == 0 { - return nil - } - return unsafe.Pointer(&cs[0]) -} - -func (cs cstring) String() string { - return string(cs[:len(cs)-1]) -} -*/ - -func join(args []interface{}) string { - sa := make([]string, len(args)) - for i, a := range args { - var s string - switch v := a.(type) { - case time.Time: - s = i64toa(v.Unix()) - default: - s = fmt.Sprint(v) - } - sa[i] = s - } - return strings.Join(sa, ":") -} - -type Creator struct { - filename string - start time.Time - step uint - args []string -} - -// NewCreator returns new Creator object. You need to call Create to really -// create database file. -// filename - name of database file -// start - don't accept any data timed before or at time specified -// step - base interval in seconds with which data will be fed into RRD -func NewCreator(filename string, start time.Time, step uint) *Creator { - return &Creator{ - filename: filename, - start: start, - step: step, - } -} - -// DS formats a DS argument and appends it to the list of arguments to be -// passed to rrdcreate(). Each element of args is formatted with fmt.Sprint(). -// Please see the rrdcreate(1) manual page for in-depth documentation. -func (c *Creator) DS(name, compute string, args ...interface{}) { - c.args = append(c.args, "DS:"+name+":"+compute+":"+join(args)) -} - -// RRA formats an RRA argument and appends it to the list of arguments to be -// passed to rrdcreate(). Each element of args is formatted with fmt.Sprint(). -// Please see the rrdcreate(1) manual page for in-depth documentation. -func (c *Creator) RRA(cf string, args ...interface{}) { - c.args = append(c.args, "RRA:"+cf+":"+join(args)) -} - -// Create creates new database file. If overwrite is true it overwrites -// database file if exists. If overwrite is false it returns error if file -// exists (you can use os.IsExist function to check this case). -func (c *Creator) Create(overwrite bool) error { - if !overwrite { - f, err := os.OpenFile( - c.filename, - os.O_WRONLY|os.O_CREATE|os.O_EXCL, - 0666, - ) - if err != nil { - return err - } - f.Close() - } - return c.create() -} - -// Use cstring and unsafe.Pointer to avoid allocations for C calls - -type Updater struct { - filename *cstring - template *cstring - - args []*cstring -} - -func NewUpdater(filename string) *Updater { - u := &Updater{filename: newCstring(filename)} - runtime.SetFinalizer(u, cfree) - return u -} - -func cfree(u *Updater) { - u.filename.Free() - u.template.Free() - for _, a := range u.args { - a.Free() - } -} - -func (u *Updater) SetTemplate(dsName ...string) { - u.template.Free() - u.template = newCstring(strings.Join(dsName, ":")) -} - -// Cache chaches data for later save using Update(). Use it to avoid -// open/read/write/close for every update. -func (u *Updater) Cache(args ...interface{}) { - u.args = append(u.args, newCstring(join(args))) -} - -// Update saves data in RRDB. -// Without args Update saves all subsequent updates buffered by Cache method. -// If you specify args it saves them immediately. -func (u *Updater) Update(args ...interface{}) error { - if len(args) != 0 { - cs := newCstring(join(args)) - err := u.update([]*cstring{cs}) - cs.Free() - return err - } else if len(u.args) != 0 { - err := u.update(u.args) - for _, a := range u.args { - a.Free() - } - u.args = nil - return err - } - return nil -} - -type GraphInfo struct { - Print []string - Width, Height uint - Ymin, Ymax float64 -} - -type Grapher struct { - title string - vlabel string - width, height uint - borderWidth uint - upperLimit float64 - lowerLimit float64 - rigid bool - altAutoscale bool - altAutoscaleMin bool - altAutoscaleMax bool - noGridFit bool - - logarithmic bool - unitsExponent int - unitsLength uint - - rightAxisScale float64 - rightAxisShift float64 - rightAxisLabel string - - noLegend bool - - lazy bool - - colors map[string]string - - slopeMode bool - - watermark string - base uint - imageFormat string - interlaced bool - - daemon string - - args []string -} - -const ( - maxUint = ^uint(0) - maxInt = int(maxUint >> 1) - minInt = -maxInt - 1 - defWidth = 2 -) - -func NewGrapher() *Grapher { - return &Grapher{ - upperLimit: -math.MaxFloat64, - lowerLimit: math.MaxFloat64, - unitsExponent: minInt, - borderWidth: defWidth, - colors: make(map[string]string), - } -} - -func (g *Grapher) SetTitle(title string) { - g.title = title -} - -func (g *Grapher) SetVLabel(vlabel string) { - g.vlabel = vlabel -} - -func (g *Grapher) SetSize(width, height uint) { - g.width = width - g.height = height -} - -func (g *Grapher) SetBorder(width uint) { - g.borderWidth = width -} - -func (g *Grapher) SetLowerLimit(limit float64) { - g.lowerLimit = limit -} - -func (g *Grapher) SetUpperLimit(limit float64) { - g.upperLimit = limit -} - -func (g *Grapher) SetRigid() { - g.rigid = true -} - -func (g *Grapher) SetAltAutoscale() { - g.altAutoscale = true -} - -func (g *Grapher) SetAltAutoscaleMin() { - g.altAutoscaleMin = true -} - -func (g *Grapher) SetAltAutoscaleMax() { - - g.altAutoscaleMax = true -} - -func (g *Grapher) SetNoGridFit() { - g.noGridFit = true -} - -func (g *Grapher) SetLogarithmic() { - g.logarithmic = true -} - -func (g *Grapher) SetUnitsExponent(e int) { - g.unitsExponent = e -} - -func (g *Grapher) SetUnitsLength(l uint) { - g.unitsLength = l -} - -func (g *Grapher) SetRightAxis(scale, shift float64) { - g.rightAxisScale = scale - g.rightAxisShift = shift -} - -func (g *Grapher) SetRightAxisLabel(label string) { - g.rightAxisLabel = label -} - -func (g *Grapher) SetNoLegend() { - g.noLegend = true -} - -func (g *Grapher) SetLazy() { - g.lazy = true -} - -func (g *Grapher) SetColor(colortag, color string) { - g.colors[colortag] = color -} - -func (g *Grapher) SetSlopeMode() { - g.slopeMode = true -} - -func (g *Grapher) SetImageFormat(format string) { - g.imageFormat = format -} - -func (g *Grapher) SetInterlaced() { - g.interlaced = true -} - -func (g *Grapher) SetBase(base uint) { - g.base = base -} - -func (g *Grapher) SetWatermark(watermark string) { - g.watermark = watermark -} - -func (g *Grapher) SetDaemon(daemon string) { - g.daemon = daemon -} - -func (g *Grapher) AddOptions(options ...string) { - g.args = append(g.args, options...) -} - -func (g *Grapher) push(cmd string, options []string) { - if len(options) > 0 { - cmd += ":" + strings.Join(options, ":") - } - g.args = append(g.args, cmd) -} - -func (g *Grapher) Def(vname, rrdfile, dsname, cf string, options ...string) { - g.push( - fmt.Sprintf("DEF:%s=%s:%s:%s", vname, rrdfile, dsname, cf), - options, - ) -} - -func (g *Grapher) VDef(vname, rpn string) { - g.push("VDEF:"+vname+"="+rpn, nil) -} - -func (g *Grapher) CDef(vname, rpn string) { - g.push("CDEF:"+vname+"="+rpn, nil) -} - -func (g *Grapher) Print(vname, format string) { - g.push("PRINT:"+vname+":"+format, nil) -} - -func (g *Grapher) PrintT(vname, format string) { - g.push("PRINT:"+vname+":"+format+":strftime", nil) -} -func (g *Grapher) GPrint(vname, format string) { - g.push("GPRINT:"+vname+":"+format, nil) -} - -func (g *Grapher) GPrintT(vname, format string) { - g.push("GPRINT:"+vname+":"+format+":strftime", nil) -} - -func (g *Grapher) Comment(s string) { - g.push("COMMENT:"+s, nil) -} - -func (g *Grapher) VRule(t interface{}, color string, options ...string) { - if v, ok := t.(time.Time); ok { - t = v.Unix() - } - vr := fmt.Sprintf("VRULE:%v#%s", t, color) - g.push(vr, options) -} - -func (g *Grapher) HRule(value, color string, options ...string) { - hr := "HRULE:" + value + "#" + color - g.push(hr, options) -} - -func (g *Grapher) Line(width float32, value, color string, options ...string) { - line := fmt.Sprintf("LINE%f:%s", width, value) - if color != "" { - line += "#" + color - } - g.push(line, options) -} - -func (g *Grapher) Area(value, color string, options ...string) { - area := "AREA:" + value - if color != "" { - area += "#" + color - } - g.push(area, options) -} - -func (g *Grapher) Tick(vname, color string, options ...string) { - tick := "TICK:" + vname - if color != "" { - tick += "#" + color - } - g.push(tick, options) -} - -func (g *Grapher) Shift(vname string, offset interface{}) { - if v, ok := offset.(time.Duration); ok { - offset = int64((v + time.Second/2) / time.Second) - } - shift := fmt.Sprintf("SHIFT:%s:%v", vname, offset) - g.push(shift, nil) -} - -func (g *Grapher) TextAlign(align string) { - g.push("TEXTALIGN:"+align, nil) -} - -// Graph returns GraphInfo and image as []byte or error -func (g *Grapher) Graph(start, end time.Time) (GraphInfo, []byte, error) { - return g.graph("-", start, end) -} - -// SaveGraph saves image to file and returns GraphInfo or error -func (g *Grapher) SaveGraph(filename string, start, end time.Time) (GraphInfo, error) { - gi, _, err := g.graph(filename, start, end) - return gi, err -} - -type FetchResult struct { - Filename string - Cf string - Start time.Time - End time.Time - Step time.Duration - DsNames []string - RowCnt int - values []float64 -} - -func (r *FetchResult) ValueAt(dsIndex, rowIndex int) float64 { - return r.values[len(r.DsNames)*rowIndex+dsIndex] -} - -type Exporter struct { - maxRows uint - - daemon string - - args []string -} - -func NewExporter() *Exporter { - return &Exporter{} -} - -func (e *Exporter) SetMaxRows(maxRows uint) { - e.maxRows = maxRows -} - -func (e *Exporter) push(cmd string, options []string) { - if len(options) > 0 { - cmd += ":" + strings.Join(options, ":") - } - e.args = append(e.args, cmd) -} - -func (e *Exporter) Def(vname, rrdfile, dsname, cf string, options ...string) { - e.push( - fmt.Sprintf("DEF:%s=%s:%s:%s", vname, rrdfile, dsname, cf), - options, - ) -} - -func (e *Exporter) CDef(vname, rpn string) { - e.push("CDEF:"+vname+"="+rpn, nil) -} - -func (e *Exporter) XportDef(vname, label string) { - e.push("XPORT:"+vname+":"+label, nil) -} - -func (e *Exporter) Xport(start, end time.Time, step time.Duration) (XportResult, error) { - return e.xport(start, end, step) -} - -func (e *Exporter) SetDaemon(daemon string) { - e.daemon = daemon -} - -type XportResult struct { - Start time.Time - End time.Time - Step time.Duration - Legends []string - RowCnt int - values []float64 -} - -func (r *XportResult) ValueAt(legendIndex, rowIndex int) float64 { - return r.values[len(r.Legends)*rowIndex+legendIndex] -} diff --git a/pkg/rrd/rrd_darwin.go b/pkg/rrd/rrd_darwin.go deleted file mode 100644 index df59726a..00000000 --- a/pkg/rrd/rrd_darwin.go +++ /dev/null @@ -1,85 +0,0 @@ -package rrd - -import ( - "errors" - "strconv" - "time" -) - -type cstring byte - -func newCstring(s string) *cstring { - return nil -} - -func (cs *cstring) Free() { - return -} - -func (cs *cstring) String() string { - return "" -} - -func (c *Creator) create() error { - return errors.New("not implemented") -} - -func (u *Updater) update(args []*cstring) error { - return errors.New("not implemented") -} - -func ftoa(f float64) string { - return strconv.FormatFloat(f, 'e', 10, 64) -} - -func i64toa(i int64) string { - return strconv.FormatInt(i, 10) -} - -func u64toa(u uint64) string { - return "" -} - -func itoa(i int) string { - return "" -} - -func utoa(u uint) string { - return "" -} - -func parseInfoKey(ik string) (kname, kkey string, kid int) { - return -} - -func (g *Grapher) graph(filename string, start, end time.Time) (GraphInfo, []byte, error) { - return GraphInfo{}, nil, errors.New("not implemented") -} - -// Info returns information about RRD file. -func Info(filename string) (map[string]interface{}, error) { - return nil, errors.New("not implemented") -} - -// Fetch retrieves data from RRD file. -func Fetch(filename, cf string, start, end time.Time, step time.Duration) (FetchResult, error) { - return FetchResult{}, errors.New("not implemented") -} - -// FreeValues free values memory allocated by C. -func (r *FetchResult) FreeValues() { -} - -// Values returns copy of internal array of values. -func (r *FetchResult) Values() []float64 { - return nil -} - -// Export data from RRD file(s) -func (e *Exporter) xport(start, end time.Time, step time.Duration) (XportResult, error) { - return XportResult{}, errors.New("not implemented") -} - -// FreeValues free values memory allocated by C. -func (r *XportResult) FreeValues() { -} diff --git a/pkg/rrd/rrd_linux.go b/pkg/rrd/rrd_linux.go deleted file mode 100644 index 32a6f006..00000000 --- a/pkg/rrd/rrd_linux.go +++ /dev/null @@ -1,553 +0,0 @@ -package rrd - -/* -#include -#include -#include "rrdfunc.h" -#cgo LDFLAGS: -lpthread -lrrd -lpng -lcairo -lpixman-1 -lpango-1.0 -lfontconfig -lssl -lexpat -lfreetype -lgobject-2.0 -lglib-2.0 -lpcre -lthai -ldatrie -lz -lffi -ldbi -ldl -lc -lm -Wl,--unresolved-symbols=ignore-all -#cgo CFLAGS: -std=c99 -Wno-implicit-function-declaration -Wno-int-conversion -*/ -import "C" -import ( - "math" - "reflect" - "strconv" - "strings" - "sync" - "time" - "unsafe" -) - -type cstring C.char - -func newCstring(s string) *cstring { - cs := C.malloc(C.size_t(len(s) + 1)) - buf := (*[1<<31 - 1]byte)(cs)[:len(s)+1] - copy(buf, s) - buf[len(s)] = 0 - return (*cstring)(cs) -} - -func (cs *cstring) Free() { - if cs != nil { - C.free(unsafe.Pointer(cs)) - } -} - -func (cs *cstring) String() string { - buf := (*[1<<31 - 1]byte)(unsafe.Pointer(cs)) - for n, b := range buf { - if b == 0 { - return string(buf[:n]) - } - } - panic("rrd: bad C string") -} - -var mutex sync.Mutex - -func makeArgs(args []string) []*C.char { - ret := make([]*C.char, len(args)) - for i, s := range args { - ret[i] = C.CString(s) - } - return ret -} - -func freeCString(s *C.char) { - C.free(unsafe.Pointer(s)) -} - -func freeArgs(cArgs []*C.char) { - for _, s := range cArgs { - freeCString(s) - } -} - -func makeError(e *C.char) error { - var null *C.char - if e == null { - return nil - } - defer freeCString(e) - return Error(C.GoString(e)) -} - -func (c *Creator) create() error { - filename := C.CString(c.filename) - defer freeCString(filename) - args := makeArgs(c.args) - defer freeArgs(args) - - e := C.rrdCreate( - filename, - C.ulong(c.step), - C.time_t(c.start.Unix()), - C.int(len(args)), - &args[0], - ) - return makeError(e) -} - -func (u *Updater) update(args []*cstring) error { - e := C.rrdUpdate( - (*C.char)(u.filename), - (*C.char)(u.template), - C.int(len(args)), - (**C.char)(unsafe.Pointer(&args[0])), - ) - return makeError(e) -} - -var ( - graphv = C.CString("graphv") - xport = C.CString("xport") - - oStart = C.CString("-s") - oEnd = C.CString("-e") - oTitle = C.CString("-t") - oVlabel = C.CString("-v") - oWidth = C.CString("-w") - oHeight = C.CString("-h") - oUpperLimit = C.CString("-u") - oLowerLimit = C.CString("-l") - oRigid = C.CString("-r") - oAltAutoscale = C.CString("-A") - oAltAutoscaleMin = C.CString("-J") - oAltAutoscaleMax = C.CString("-M") - oNoGridFit = C.CString("-N") - - oLogarithmic = C.CString("-o") - oUnitsExponent = C.CString("-X") - oUnitsLength = C.CString("-L") - - oRightAxis = C.CString("--right-axis") - oRightAxisLabel = C.CString("--right-axis-label") - - oDaemon = C.CString("--daemon") - - oBorder = C.CString("--border") - - oNoLegend = C.CString("-g") - - oLazy = C.CString("-z") - - oColor = C.CString("-c") - - oSlopeMode = C.CString("-E") - oImageFormat = C.CString("-a") - oInterlaced = C.CString("-i") - - oBase = C.CString("-b") - oWatermark = C.CString("-W") - - oStep = C.CString("--step") - oMaxRows = C.CString("-m") -) - -func ftoa(f float64) string { - return strconv.FormatFloat(f, 'e', 10, 64) -} - -func ftoc(f float64) *C.char { - return C.CString(ftoa(f)) -} - -func i64toa(i int64) string { - return strconv.FormatInt(i, 10) -} - -func i64toc(i int64) *C.char { - return C.CString(i64toa(i)) -} - -func u64toa(u uint64) string { - return strconv.FormatUint(u, 10) -} - -func u64toc(u uint64) *C.char { - return C.CString(u64toa(u)) -} -func itoa(i int) string { - return i64toa(int64(i)) -} - -func itoc(i int) *C.char { - return i64toc(int64(i)) -} - -func utoa(u uint) string { - return u64toa(uint64(u)) -} - -func utoc(u uint) *C.char { - return u64toc(uint64(u)) -} - -func (g *Grapher) makeArgs(filename string, start, end time.Time) []*C.char { - args := []*C.char{ - graphv, C.CString(filename), - oStart, i64toc(start.Unix()), - oEnd, i64toc(end.Unix()), - oTitle, C.CString(g.title), - oVlabel, C.CString(g.vlabel), - } - if g.width != 0 { - args = append(args, oWidth, utoc(g.width)) - } - if g.height != 0 { - args = append(args, oHeight, utoc(g.height)) - } - if g.upperLimit != -math.MaxFloat64 { - args = append(args, oUpperLimit, ftoc(g.upperLimit)) - } - if g.lowerLimit != math.MaxFloat64 { - args = append(args, oLowerLimit, ftoc(g.lowerLimit)) - } - if g.rigid { - args = append(args, oRigid) - } - if g.altAutoscale { - args = append(args, oAltAutoscale) - } - if g.altAutoscaleMax { - args = append(args, oAltAutoscaleMax) - } - if g.altAutoscaleMin { - args = append(args, oAltAutoscaleMin) - } - if g.noGridFit { - args = append(args, oNoGridFit) - } - if g.logarithmic { - args = append(args, oLogarithmic) - } - if g.unitsExponent != minInt { - args = append( - args, - oUnitsExponent, itoc(g.unitsExponent), - ) - } - if g.unitsLength != 0 { - args = append( - args, - oUnitsLength, utoc(g.unitsLength), - ) - } - if g.rightAxisScale != 0 { - args = append( - args, - oRightAxis, - C.CString(ftoa(g.rightAxisScale)+":"+ftoa(g.rightAxisShift)), - ) - } - if g.rightAxisLabel != "" { - args = append( - args, - oRightAxisLabel, C.CString(g.rightAxisLabel), - ) - } - if g.noLegend { - args = append(args, oNoLegend) - } - if g.lazy { - args = append(args, oLazy) - } - for tag, color := range g.colors { - args = append(args, oColor, C.CString(tag+"#"+color)) - } - if g.slopeMode { - args = append(args, oSlopeMode) - } - if g.imageFormat != "" { - args = append(args, oImageFormat, C.CString(g.imageFormat)) - } - if g.interlaced { - args = append(args, oInterlaced) - } - if g.base != 0 { - args = append(args, oBase, utoc(g.base)) - } - if g.watermark != "" { - args = append(args, oWatermark, C.CString(g.watermark)) - } - if g.daemon != "" { - args = append(args, oDaemon, C.CString(g.daemon)) - } - if g.borderWidth != defWidth { - args = append(args, oBorder, utoc(g.borderWidth)) - } - return append(args, makeArgs(g.args)...) -} - -func (e *Exporter) makeArgs(start, end time.Time, step time.Duration) []*C.char { - args := []*C.char{ - xport, - oStart, i64toc(start.Unix()), - oEnd, i64toc(end.Unix()), - oStep, i64toc(int64(step.Seconds())), - } - if e.maxRows != 0 { - args = append(args, oMaxRows, utoc(e.maxRows)) - } - if e.daemon != "" { - args = append(args, oDaemon, C.CString(e.daemon)) - } - return append(args, makeArgs(e.args)...) -} - -func parseInfoKey(ik string) (kname, kkey string, kid int) { - kid = -1 - o := strings.IndexRune(ik, '[') - if o == -1 { - kname = ik - return - } - c := strings.IndexRune(ik[o+1:], ']') - if c == -1 { - kname = ik - return - } - c += o + 1 - kname = ik[:o] + ik[c+1:] - kkey = ik[o+1 : c] - if strings.HasPrefix(kname, "ds.") { - return - } else if id, err := strconv.Atoi(kkey); err == nil && id >= 0 { - kid = id - } - return -} - -func updateInfoValue(i *C.struct_rrd_info_t, v interface{}) interface{} { - switch i._type { - case C.RD_I_VAL: - return float64(*(*C.rrd_value_t)(unsafe.Pointer(&i.value[0]))) - case C.RD_I_CNT: - return uint(*(*C.ulong)(unsafe.Pointer(&i.value[0]))) - case C.RD_I_STR: - return C.GoString(*(**C.char)(unsafe.Pointer(&i.value[0]))) - case C.RD_I_INT: - return int(*(*C.int)(unsafe.Pointer(&i.value[0]))) - case C.RD_I_BLO: - blob := *(*C.rrd_blob_t)(unsafe.Pointer(&i.value[0])) - b := C.GoBytes(unsafe.Pointer(blob.ptr), C.int(blob.size)) - if v == nil { - return b - } - return append(v.([]byte), b...) - } - - return nil -} - -func parseRRDInfo(i *C.rrd_info_t) map[string]interface{} { - defer C.rrd_info_free(i) - - r := make(map[string]interface{}) - for w := (*C.struct_rrd_info_t)(i); w != nil; w = w.next { - kname, kkey, kid := parseInfoKey(C.GoString(w.key)) - v, ok := r[kname] - switch { - case kid != -1: - var a []interface{} - if ok { - a = v.([]interface{}) - } - if len(a) < kid+1 { - oldA := a - a = make([]interface{}, kid+1) - copy(a, oldA) - } - a[kid] = updateInfoValue(w, a[kid]) - v = a - case kkey != "": - var m map[string]interface{} - if ok { - m = v.(map[string]interface{}) - } else { - m = make(map[string]interface{}) - } - old, _ := m[kkey] - m[kkey] = updateInfoValue(w, old) - v = m - default: - v = updateInfoValue(w, v) - } - r[kname] = v - } - return r -} - -func parseGraphInfo(i *C.rrd_info_t) (gi GraphInfo, img []byte) { - inf := parseRRDInfo(i) - if v, ok := inf["image_info"]; ok { - gi.Print = append(gi.Print, v.(string)) - } - for k, v := range inf { - if k == "print" { - for _, line := range v.([]interface{}) { - gi.Print = append(gi.Print, line.(string)) - } - } - } - if v, ok := inf["image_width"]; ok { - gi.Width = v.(uint) - } - if v, ok := inf["image_height"]; ok { - gi.Height = v.(uint) - } - if v, ok := inf["value_min"]; ok { - gi.Ymin = v.(float64) - } - if v, ok := inf["value_max"]; ok { - gi.Ymax = v.(float64) - } - if v, ok := inf["image"]; ok { - img = v.([]byte) - } - return -} - -func (g *Grapher) graph(filename string, start, end time.Time) (GraphInfo, []byte, error) { - var i *C.rrd_info_t - args := g.makeArgs(filename, start, end) - - mutex.Lock() // rrd_graph_v isn't thread safe - defer mutex.Unlock() - - err := makeError(C.rrdGraph( - &i, - C.int(len(args)), - &args[0], - )) - - if err != nil { - return GraphInfo{}, nil, err - } - gi, img := parseGraphInfo(i) - - return gi, img, nil -} - -// Info returns information about RRD file. -func Info(filename string) (map[string]interface{}, error) { - fn := C.CString(filename) - defer freeCString(fn) - var i *C.rrd_info_t - err := makeError(C.rrdInfo(&i, fn)) - if err != nil { - return nil, err - } - return parseRRDInfo(i), nil -} - -// Fetch retrieves data from RRD file. -func Fetch(filename, cf string, start, end time.Time, step time.Duration) (FetchResult, error) { - fn := C.CString(filename) - defer freeCString(fn) - cCf := C.CString(cf) - defer freeCString(cCf) - cStart := C.time_t(start.Unix()) - cEnd := C.time_t(end.Unix()) - cStep := C.ulong(step.Seconds()) - var ( - ret C.int - cDsCnt C.ulong - cDsNames **C.char - cData *C.double - ) - err := makeError(C.rrdFetch(&ret, fn, cCf, &cStart, &cEnd, &cStep, &cDsCnt, &cDsNames, &cData)) - if err != nil { - return FetchResult{filename, cf, start, end, step, nil, 0, nil}, err - } - - start = time.Unix(int64(cStart), 0) - end = time.Unix(int64(cEnd), 0) - step = time.Duration(cStep) * time.Second - dsCnt := int(cDsCnt) - - dsNames := make([]string, dsCnt) - for i := 0; i < dsCnt; i++ { - dsName := C.arrayGetCString(cDsNames, C.int(i)) - dsNames[i] = C.GoString(dsName) - C.free(unsafe.Pointer(dsName)) - } - C.free(unsafe.Pointer(cDsNames)) - - rowCnt := (int(cEnd)-int(cStart))/int(cStep) + 1 - valuesLen := dsCnt * rowCnt - var values []float64 - sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&values))) - sliceHeader.Cap = valuesLen - sliceHeader.Len = valuesLen - sliceHeader.Data = uintptr(unsafe.Pointer(cData)) - return FetchResult{filename, cf, start, end, step, dsNames, rowCnt, values}, nil -} - -// FreeValues free values memory allocated by C. -func (r *FetchResult) FreeValues() { - sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&r.values))) - C.free(unsafe.Pointer(sliceHeader.Data)) -} - -// Values returns copy of internal array of values. -func (r *FetchResult) Values() []float64 { - return append([]float64{}, r.values...) -} - -// Export data from RRD file(s) -func (e *Exporter) xport(start, end time.Time, step time.Duration) (XportResult, error) { - cStart := C.time_t(start.Unix()) - cEnd := C.time_t(end.Unix()) - cStep := C.ulong(step.Seconds()) - args := e.makeArgs(start, end, step) - - mutex.Lock() - defer mutex.Unlock() - - var ( - ret C.int - cXSize C.int - cColCnt C.ulong - cLegends **C.char - cData *C.double - ) - err := makeError(C.rrdXport( - &ret, - C.int(len(args)), - &args[0], - &cXSize, &cStart, &cEnd, &cStep, &cColCnt, &cLegends, &cData, - )) - if err != nil { - return XportResult{start, end, step, nil, 0, nil}, err - } - - start = time.Unix(int64(cStart), 0) - end = time.Unix(int64(cEnd), 0) - step = time.Duration(cStep) * time.Second - colCnt := int(cColCnt) - - legends := make([]string, colCnt) - for i := 0; i < colCnt; i++ { - legend := C.arrayGetCString(cLegends, C.int(i)) - legends[i] = C.GoString(legend) - C.free(unsafe.Pointer(legend)) - } - C.free(unsafe.Pointer(cLegends)) - - rowCnt := (int(cEnd) - int(cStart)) / int(cStep) //+ 1 // FIXED: + 1 added extra uninitialized value - valuesLen := colCnt * rowCnt - values := make([]float64, valuesLen) - sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&values))) - sliceHeader.Cap = valuesLen - sliceHeader.Len = valuesLen - sliceHeader.Data = uintptr(unsafe.Pointer(cData)) - return XportResult{start, end, step, legends, rowCnt, values}, nil -} - -// FreeValues free values memory allocated by C. -func (r *XportResult) FreeValues() { - sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&r.values))) - C.free(unsafe.Pointer(sliceHeader.Data)) -} diff --git a/pkg/rrd/rrd_windows.go b/pkg/rrd/rrd_windows.go deleted file mode 100644 index df59726a..00000000 --- a/pkg/rrd/rrd_windows.go +++ /dev/null @@ -1,85 +0,0 @@ -package rrd - -import ( - "errors" - "strconv" - "time" -) - -type cstring byte - -func newCstring(s string) *cstring { - return nil -} - -func (cs *cstring) Free() { - return -} - -func (cs *cstring) String() string { - return "" -} - -func (c *Creator) create() error { - return errors.New("not implemented") -} - -func (u *Updater) update(args []*cstring) error { - return errors.New("not implemented") -} - -func ftoa(f float64) string { - return strconv.FormatFloat(f, 'e', 10, 64) -} - -func i64toa(i int64) string { - return strconv.FormatInt(i, 10) -} - -func u64toa(u uint64) string { - return "" -} - -func itoa(i int) string { - return "" -} - -func utoa(u uint) string { - return "" -} - -func parseInfoKey(ik string) (kname, kkey string, kid int) { - return -} - -func (g *Grapher) graph(filename string, start, end time.Time) (GraphInfo, []byte, error) { - return GraphInfo{}, nil, errors.New("not implemented") -} - -// Info returns information about RRD file. -func Info(filename string) (map[string]interface{}, error) { - return nil, errors.New("not implemented") -} - -// Fetch retrieves data from RRD file. -func Fetch(filename, cf string, start, end time.Time, step time.Duration) (FetchResult, error) { - return FetchResult{}, errors.New("not implemented") -} - -// FreeValues free values memory allocated by C. -func (r *FetchResult) FreeValues() { -} - -// Values returns copy of internal array of values. -func (r *FetchResult) Values() []float64 { - return nil -} - -// Export data from RRD file(s) -func (e *Exporter) xport(start, end time.Time, step time.Duration) (XportResult, error) { - return XportResult{}, errors.New("not implemented") -} - -// FreeValues free values memory allocated by C. -func (r *XportResult) FreeValues() { -} diff --git a/pkg/rrd/rrdfunc.h b/pkg/rrd/rrdfunc.h deleted file mode 100644 index a42391b9..00000000 --- a/pkg/rrd/rrdfunc.h +++ /dev/null @@ -1,7 +0,0 @@ -extern char *rrdCreate(const char *filename, unsigned long step, time_t start, int argc, const char **argv); -extern char *rrdUpdate(const char *filename, const char *template, int argc, const char **argv); -extern char *rrdGraph(rrd_info_t **ret, int argc, char **argv); -extern char *rrdInfo(rrd_info_t **ret, char *filename); -extern char *rrdFetch(int *ret, char *filename, const char *cf, time_t *start, time_t *end, unsigned long *step, unsigned long *ds_cnt, char ***ds_namv, double **data); -extern char *rrdXport(int *ret, int argc, char **argv, int *xsize, time_t *start, time_t *end, unsigned long *step, unsigned long *col_cnt, char ***legend_v, double **data); -extern char *arrayGetCString(char **values, int i); diff --git a/pkg/rrd/rrdfunc_linux.c b/pkg/rrd/rrdfunc_linux.c deleted file mode 100644 index 96995610..00000000 --- a/pkg/rrd/rrdfunc_linux.c +++ /dev/null @@ -1,57 +0,0 @@ -#include -#include - -char *rrdError() { - char *err = NULL; - if (rrd_test_error()) { - // RRD error is local for thread so other gorutine can call some RRD - // function in the same thread before we use C.GoString. So we need to - // copy current error before return from C to Go. It need to be freed - // after C.GoString in Go code. - err = strdup(rrd_get_error()); - if (err == NULL) { - abort(); - } - } - return err; -} - -char *rrdCreate(const char *filename, unsigned long step, time_t start, int argc, const char **argv) { - rrd_clear_error(); - rrd_create_r(filename, step, start, argc, argv); - return rrdError(); -} - -char *rrdUpdate(const char *filename, const char *template, int argc, const char **argv) { - rrd_clear_error(); - rrd_update_r(filename, template, argc, argv); - return rrdError(); -} - -char *rrdGraph(rrd_info_t **ret, int argc, char **argv) { - rrd_clear_error(); - *ret = rrd_graph_v(argc, argv); - return rrdError(); -} - -char *rrdInfo(rrd_info_t **ret, char *filename) { - rrd_clear_error(); - *ret = rrd_info_r(filename); - return rrdError(); -} - -char *rrdFetch(int *ret, char *filename, const char *cf, time_t *start, time_t *end, unsigned long *step, unsigned long *ds_cnt, char ***ds_namv, double **data) { - rrd_clear_error(); - *ret = rrd_fetch_r(filename, cf, start, end, step, ds_cnt, ds_namv, data); - return rrdError(); -} - -char *rrdXport(int *ret, int argc, char **argv, int *xsize, time_t *start, time_t *end, unsigned long *step, unsigned long *col_cnt, char ***legend_v, double **data) { - rrd_clear_error(); - *ret = rrd_xport(argc, argv, xsize, start, end, step, col_cnt, legend_v, data); - return rrdError(); -} - -char *arrayGetCString(char **values, int i) { - return values[i]; -}