Skip to content

Commit

Permalink
Merge pull request #39 from opsdis/dev
Browse files Browse the repository at this point in the history
String concatenation performance improvments
thenodon authored Oct 6, 2023
2 parents f671a6b + de926fb commit 1711116
Showing 4 changed files with 56 additions and 16 deletions.
8 changes: 5 additions & 3 deletions aci-connection.go
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ import (
"bytes"
"context"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/http/cookiejar"
"strconv"
@@ -192,7 +192,7 @@ func (c AciConnection) doGet(url string) ([]byte, int, error) {
defer resp.Body.Close()

if resp.StatusCode == http.StatusOK {
bodyBytes, err := ioutil.ReadAll(resp.Body)
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
log.WithFields(log.Fields{
"requestid": c.ctx.Value("requestid"),
@@ -224,6 +224,8 @@ func (c AciConnection) doPostXML(label string, url string, requestBody []byte) (

start := time.Now()
resp, err := c.Client.Do(req)
//cook := resp.Cookies()
//print(cook)
if err != nil {
log.WithFields(log.Fields{
"requestid": c.ctx.Value("requestid"),
@@ -252,7 +254,7 @@ func (c AciConnection) doPostXML(label string, url string, requestBody []byte) (
defer resp.Body.Close()

if resp.StatusCode == http.StatusOK {
bodyBytes, err := ioutil.ReadAll(resp.Body)
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
log.WithFields(log.Fields{
"requestid": c.ctx.Value("requestid"),
27 changes: 27 additions & 0 deletions aci-exporter.go
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@ import (
"context"
"flag"
"fmt"
"net/http/pprof"
"os"
"strconv"
"strings"
@@ -71,6 +72,7 @@ func main() {
config := flag.String("config", viper.GetString("config"), "Set configuration file, default config.yaml")
usage := flag.Bool("u", false, "Show usage")
writeConfig := flag.Bool("default", false, "Write default config")
profiling := flag.Bool("pprof", false, "Enable profiling")

cli := flag.Bool("cli", false, "Run single query")
class := flag.String("class", viper.GetString("class"), "The class name - only cli")
@@ -195,6 +197,17 @@ func main() {
EnableOpenMetrics: true,
},
))
// profiling endpoint
if *profiling {
log.Info(fmt.Sprintf("Starting profiling endpoint on %s", viper.GetString("pport")))
mux := http.NewServeMux()
mux.HandleFunc("/debug/pprof/", pprof.Index)
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
go func() { log.Fatal(http.ListenAndServe(viper.GetString("pport"), mux)) }()
}

log.Info(fmt.Sprintf("%s starting on port %d", ExporterName, viper.GetInt("port")))
log.Info(fmt.Sprintf("Read timeout %s, Write timeout %s", viper.GetDuration("httpserver.read_timeout")*time.Second, viper.GetDuration("httpserver.write_timeout")*time.Second))
@@ -283,15 +296,29 @@ func (h HandlerInit) getMonitorMetrics(w http.ResponseWriter, r *http.Request) {
ctx = context.WithValue(ctx, "fabric", fabric)
api := *newAciAPI(ctx, h.AllFabrics[fabric], h.AllQueries, queries)

start := time.Now()
aciName, metrics, err := api.CollectMetrics()
log.WithFields(log.Fields{
"requestid": ctx.Value("requestid"),
"exec_time": time.Since(start).Microseconds(),
"fabric": fmt.Sprintf("%v", ctx.Value("fabric")),
}).Info("total query collection time")

commonLabels := make(map[string]string)
commonLabels["aci"] = aciName
commonLabels["fabric"] = fabric

start = time.Now()
metricsFormat := NewMetricFormat(openmetrics, viper.GetBool("metric_format.label_key_to_lower_case"),
viper.GetBool("metric_format.label_key_to_snake_case"))
var bodyText = Metrics2Prometheus(metrics, api.metricPrefix, commonLabels, metricsFormat)

log.WithFields(log.Fields{
"requestid": ctx.Value("requestid"),
"exec_time": time.Since(start).Microseconds(),
"fabric": fmt.Sprintf("%v", ctx.Value("fabric")),
}).Info("processing metrics to prometheus exposition format")

if openmetrics {
w.Header().Set("Content-Type", "application/openmetrics-text; version=0.0.1; charset=utf-8")
} else {
2 changes: 2 additions & 0 deletions defaults.go
Original file line number Diff line number Diff line change
@@ -53,6 +53,8 @@ func SetDefaultValues() {
viper.BindEnv("config")
viper.SetDefault("prefix", "aci_")
viper.BindEnv("prefix")
viper.SetDefault("pport", "localhost:6060")
viper.BindEnv("pport")

// If set to true response will always be in openmetrics format
viper.SetDefault("openmetrics", false)
35 changes: 22 additions & 13 deletions metric.go
Original file line number Diff line number Diff line change
@@ -18,6 +18,8 @@ import (
"regexp"
"sort"
"strings"

log "github.com/sirupsen/logrus"
)

type MetricDefinition struct {
@@ -85,21 +87,21 @@ func (m Metric) Labels2Prometheus(commonLabels map[string]string, format MetricF

sort.Strings(keys)

labelstr := ""
var builder strings.Builder
sep := ""
for _, k := range keys {
// Filter out empty labels
if m.Labels[k] != "" {
labelstr = labelstr + fmt.Sprintf("%s%s=\"%s\"", sep, toLowerLabels(k, format), m.Labels[k])
addText(&builder, fmt.Sprintf("%s%s=\"%s\"", sep, toLowerLabels(k, format), m.Labels[k]))
sep = ","
}
}
return labelstr
return builder.String()
}

// Metrics2Prometheus convert a slice of Metric to Prometheus text output
func Metrics2Prometheus(metrics []MetricDefinition, prefix string, commonLabels map[string]string, format MetricFormat) string {
promFormat := ""
var builder strings.Builder

for _, metricDefinition := range metrics {

@@ -115,9 +117,9 @@ func Metrics2Prometheus(metrics []MetricDefinition, prefix string, commonLabels

if len(metricDefinition.Metrics) > 0 {
if metricDefinition.Description.Help == "" {
promFormat = promFormat + fmt.Sprintf("# HELP %s%s %s\n", prefix, metricName, "Missing description")
addText(&builder, fmt.Sprintf("# HELP %s%s %s\n", prefix, metricName, "Missing description"))
} else {
promFormat = promFormat + fmt.Sprintf("# HELP %s%s %s\n", prefix, metricName, metricDefinition.Description.Help)
addText(&builder, fmt.Sprintf("# HELP %s%s %s\n", prefix, metricName, metricDefinition.Description.Help))
}

promType := "gauge"
@@ -126,22 +128,29 @@ func Metrics2Prometheus(metrics []MetricDefinition, prefix string, commonLabels
}
if format.openmetrics {
if strings.HasSuffix(metricName, "_info") {
promFormat = promFormat + fmt.Sprintf("# TYPE %s%s %s\n", prefix, metricName, "info")
addText(&builder, fmt.Sprintf("# TYPE %s%s %s\n", prefix, metricName, "info"))
} else {
promFormat = promFormat + fmt.Sprintf("# TYPE %s%s %s\n", prefix, metricName, promType)
addText(&builder, fmt.Sprintf("# TYPE %s%s %s\n", prefix, metricName, promType))
}
promFormat = promFormat + fmt.Sprintf("# UNIT %s%s %s\n", prefix, metricName, metricDefinition.Description.Unit)
addText(&builder, fmt.Sprintf("# UNIT %s%s %s\n", prefix, metricName, metricDefinition.Description.Unit))
} else {
promFormat = promFormat + fmt.Sprintf("# TYPE %s%s %s\n", prefix, metricName, promType)
addText(&builder, fmt.Sprintf("# TYPE %s%s %s\n", prefix, metricName, promType))
}

for _, metric := range metricDefinition.Metrics {
promFormat = promFormat + fmt.Sprintf("%s%s{%s} %g\n", prefix, metricName, metric.Labels2Prometheus(commonLabels, format), metric.Value)
addText(&builder, fmt.Sprintf("%s%s{%s} %g\n", prefix, metricName, metric.Labels2Prometheus(commonLabels, format), metric.Value))
}
}
}
if format.openmetrics {
promFormat = promFormat + "# EOF\n"
addText(&builder, "# EOF\n")
}
return builder.String()
}

func addText(builder *strings.Builder, text string) {
_, err := builder.WriteString(text)
if err != nil {
log.Fatal(err)
}
return promFormat
}

0 comments on commit 1711116

Please sign in to comment.