github.com/safing/portbase@v0.19.5/metrics/metrics_runtime.go (about)

     1  package metrics
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"fmt"
     7  	"io"
     8  	"strings"
     9  
    10  	vm "github.com/VictoriaMetrics/metrics"
    11  
    12  	"github.com/safing/portbase/api"
    13  	"github.com/safing/portbase/config"
    14  	"github.com/safing/portbase/log"
    15  )
    16  
    17  func registerRuntimeMetric() error {
    18  	runtimeBase, err := newMetricBase("_runtime", nil, Options{
    19  		Name:           "Golang Runtime",
    20  		Permission:     api.PermitAdmin,
    21  		ExpertiseLevel: config.ExpertiseLevelDeveloper,
    22  	})
    23  	if err != nil {
    24  		return err
    25  	}
    26  
    27  	return register(&runtimeMetrics{
    28  		metricBase: runtimeBase,
    29  	})
    30  }
    31  
    32  type runtimeMetrics struct {
    33  	*metricBase
    34  }
    35  
    36  func (r *runtimeMetrics) WritePrometheus(w io.Writer) {
    37  	// If there nothing to change, just write directly to w.
    38  	if metricNamespace == "" && len(globalLabels) == 0 {
    39  		vm.WriteProcessMetrics(w)
    40  		return
    41  	}
    42  
    43  	// Write metrics to buffer.
    44  	buf := new(bytes.Buffer)
    45  	vm.WriteProcessMetrics(buf)
    46  
    47  	// Add namespace and label per line.
    48  	scanner := bufio.NewScanner(buf)
    49  	scanner.Split(bufio.ScanLines)
    50  	for scanner.Scan() {
    51  		line := scanner.Text()
    52  
    53  		// Add namespace, if set.
    54  		if metricNamespace != "" {
    55  			line = metricNamespace + "_" + line
    56  		}
    57  
    58  		// Add global labels, if set.
    59  		if len(globalLabels) > 0 {
    60  			// Find where to insert.
    61  			mergeWithExisting := true
    62  			insertAt := strings.Index(line, "{") + 1
    63  			if insertAt <= 0 {
    64  				mergeWithExisting = false
    65  				insertAt = strings.Index(line, " ")
    66  				if insertAt < 0 {
    67  					continue
    68  				}
    69  			}
    70  
    71  			// Write new line directly to w.
    72  			fmt.Fprint(w, line[:insertAt])
    73  			if !mergeWithExisting {
    74  				fmt.Fprint(w, "{")
    75  			}
    76  			labelsAdded := 0
    77  			for labelKey, labelValue := range globalLabels {
    78  				fmt.Fprintf(w, "%s=%q", labelKey, labelValue)
    79  				// Add separator if not last label.
    80  				labelsAdded++
    81  				if labelsAdded < len(globalLabels) {
    82  					fmt.Fprint(w, ", ")
    83  				}
    84  			}
    85  			if mergeWithExisting {
    86  				fmt.Fprint(w, ", ")
    87  			} else {
    88  				fmt.Fprint(w, "}")
    89  			}
    90  			fmt.Fprintln(w, line[insertAt:])
    91  		}
    92  	}
    93  
    94  	// Check if there was an error in the scanner.
    95  	if scanner.Err() != nil {
    96  		log.Warningf("metrics: failed to scan go process metrics: %s", scanner.Err())
    97  	}
    98  }