Skip to content

Commit

Permalink
feat: complete dev of kube metrics parse
Browse files Browse the repository at this point in the history
  • Loading branch information
Esonhugh committed Dec 6, 2024
1 parent 2886634 commit 48017dd
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 7 deletions.
93 changes: 93 additions & 0 deletions cmd/metrics/parser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package metrics

import (
"bufio"
"io"
"net/http"
"os"
"strings"

cmdx "github.com/esonhugh/k8spider/cmd"
"github.com/esonhugh/k8spider/pkg/metrics"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

var MetricOpt struct {
From string
}

func init() {
cmdx.RootCmd.AddCommand(MetricCmd)
MetricCmd.PersistentFlags().StringVarP(&MetricOpt.From, "metric", "m", "", "metrics from (file / remote url)")

}

var MetricCmd = &cobra.Command{
Use: "metric",
Short: "parse kube stat metrics to readable resource",
Run: func(cmd *cobra.Command, args []string) {
if MetricOpt.From == "" {
return
}
log.Debugf("parse metrics from %v", MetricOpt.From)
rule := metrics.DefaultMatchRules()
if err := rule.Compile(); err != nil {
log.Fatalf("compile rule failed: %v", err)
}
log.Debugf("compiled rules completed, start to get resource \n")

ot := output()

var r io.Reader
if strings.HasPrefix("http://", MetricOpt.From) || strings.HasPrefix("https://", MetricOpt.From) {
resp, err := http.Get(MetricOpt.From)
if err != nil {
log.Fatalf("get metrics from %v failed: %v", MetricOpt.From, err)
}
defer resp.Body.Close()
r = resp.Body
} else {
f, err := os.OpenFile(MetricOpt.From, os.O_RDONLY, 0666)
if err != nil {
log.Fatalf("open file %v failed: %v", MetricOpt.From, err)
}
defer f.Close()
r = f
}
log.Debugf("start to parse metrics line by line\n")

var rx []*metrics.MetricMatcher
scanner := bufio.NewScanner(r)
for scanner.Scan() {
line := scanner.Text()
res, err := rule.Match(line)
if err != nil {
continue
} else {
log.Debugf("matched: %s", res.DumpString())
rx = append(rx, res.CopyData())
}
}
if err := scanner.Err(); err != nil {
log.Warnf("scan metrics failed and break out, reason: %v", err)
}
var res metrics.ResourceList = metrics.ConvertToResource(rx)
log.Debugf("parse metrics completed, start to print result\n")

res.Print(ot)
},
}

func output() io.WriteCloser {
if cmdx.Opts.OutputFile != "" {
f, err := os.OpenFile(cmdx.Opts.OutputFile, os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Warnf("create output file failed: %v", err)
return nil
}
return f
} else {
return os.Stdout
}
}
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
_ "github.com/esonhugh/k8spider/cmd/all"
_ "github.com/esonhugh/k8spider/cmd/axfr"
_ "github.com/esonhugh/k8spider/cmd/dnsutils"
_ "github.com/esonhugh/k8spider/cmd/metrics"
_ "github.com/esonhugh/k8spider/cmd/neighbor"
_ "github.com/esonhugh/k8spider/cmd/service"
_ "github.com/esonhugh/k8spider/cmd/subnet"
Expand Down
3 changes: 1 addition & 2 deletions pkg/metrics/metrics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,5 @@ func TestConvertToResource(t *testing.T) {
rules = append(rules, r)
}
var res ResourceList = ConvertToResource(rules)
_, _ = output.WriteString(res.JSON() + "\n")
t.Logf(res.JSON())
res.Print(os.Stderr)
}
27 changes: 22 additions & 5 deletions pkg/metrics/resource.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
package metrics

import "encoding/json"
import (
"encoding/json"
"fmt"
"io"
"os"

log "github.com/sirupsen/logrus"
)

type Resource struct {
Namespace string `json:"namespace"`
Expand Down Expand Up @@ -37,12 +44,22 @@ func (r *Resource) JSON() string {
return string(b)
}

func (rl *ResourceList) JSON() string {
var res = ""
func (rl *ResourceList) Print(writer ...io.Writer) {
var W io.Writer
if len(writer) == 0 {
W = os.Stdout
} else {
w := io.MultiWriter(writer...)
W = io.MultiWriter(os.Stdout, w)
}
for _, r := range *rl {
res += r.JSON() + "\n"
data, err := json.Marshal(r.JSON())
if err != nil {
log.Error(err)
return
}
_, _ = fmt.Fprintf(W, "%v\n", string(data))
}
return res
}

type ResourceMergeHook func(m *MetricMatcher, resource ResourceList) (res *Resource, addFlag bool)
Expand Down

0 comments on commit 48017dd

Please sign in to comment.