2020-07-02 16:42:12 +00:00
package relabel
import (
"flag"
"fmt"
2022-09-26 10:11:37 +00:00
"regexp"
2020-07-02 16:42:12 +00:00
"sync/atomic"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/procutil"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompb"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promrelabel"
2020-07-23 11:57:42 +00:00
"github.com/VictoriaMetrics/metrics"
2020-07-02 16:42:12 +00:00
)
2021-06-04 17:27:55 +00:00
var (
relabelConfig = flag . String ( "relabelConfig" , "" , "Optional path to a file with relabeling rules, which are applied to all the ingested metrics. " +
2021-12-02 22:08:42 +00:00
"The path can point either to local file or to http url. " +
2021-09-29 18:17:25 +00:00
"See https://docs.victoriametrics.com/#relabeling for details. The config is reloaded on SIGHUP signal" )
2021-06-04 17:27:55 +00:00
relabelDebug = flag . Bool ( "relabelDebug" , false , "Whether to log metrics before and after relabeling with -relabelConfig. If the -relabelDebug is enabled, " +
"then the metrics aren't sent to storage. This is useful for debugging the relabeling configs" )
2022-09-26 10:11:37 +00:00
usePromCompatibleNaming = flag . Bool ( "usePromCompatibleNaming" , false , "Whether to replace characters unsupported by Prometheus with underscores " +
"in the ingested metric names and label names. For example, foo.bar{a.b='c'} is transformed into foo_bar{a_b='c'} during data ingestion if this flag is set. " +
"See https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels" )
2021-06-04 17:27:55 +00:00
)
2020-07-02 16:42:12 +00:00
// Init must be called after flag.Parse and before using the relabel package.
func Init ( ) {
2021-05-21 13:34:03 +00:00
// Register SIGHUP handler for config re-read just before loadRelabelConfig call.
// This guarantees that the config will be re-read if the signal arrives during loadRelabelConfig call.
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1240
sighupCh := procutil . NewSighupChan ( )
2021-02-22 14:33:55 +00:00
pcs , err := loadRelabelConfig ( )
2020-07-02 16:42:12 +00:00
if err != nil {
logger . Fatalf ( "cannot load relabelConfig: %s" , err )
}
2021-02-22 14:33:55 +00:00
pcsGlobal . Store ( pcs )
2020-07-02 16:42:12 +00:00
if len ( * relabelConfig ) == 0 {
return
}
go func ( ) {
for range sighupCh {
logger . Infof ( "received SIGHUP; reloading -relabelConfig=%q..." , * relabelConfig )
2021-02-22 14:33:55 +00:00
pcs , err := loadRelabelConfig ( )
2020-07-02 16:42:12 +00:00
if err != nil {
logger . Errorf ( "cannot load the updated relabelConfig: %s; preserving the previous config" , err )
continue
}
2021-02-22 14:33:55 +00:00
pcsGlobal . Store ( pcs )
2020-07-02 16:42:12 +00:00
logger . Infof ( "successfully reloaded -relabelConfig=%q" , * relabelConfig )
}
} ( )
}
2021-02-22 14:33:55 +00:00
var pcsGlobal atomic . Value
2020-07-02 16:42:12 +00:00
2021-02-22 14:33:55 +00:00
func loadRelabelConfig ( ) ( * promrelabel . ParsedConfigs , error ) {
2020-07-02 16:42:12 +00:00
if len ( * relabelConfig ) == 0 {
return nil , nil
}
2021-06-04 17:27:55 +00:00
pcs , err := promrelabel . LoadRelabelConfigs ( * relabelConfig , * relabelDebug )
2020-07-02 16:42:12 +00:00
if err != nil {
return nil , fmt . Errorf ( "error when reading -relabelConfig=%q: %w" , * relabelConfig , err )
}
2021-02-22 14:33:55 +00:00
return pcs , nil
2020-07-02 16:42:12 +00:00
}
// HasRelabeling returns true if there is global relabeling.
func HasRelabeling ( ) bool {
2021-02-22 14:33:55 +00:00
pcs := pcsGlobal . Load ( ) . ( * promrelabel . ParsedConfigs )
2022-09-26 10:11:37 +00:00
return pcs . Len ( ) > 0 || * usePromCompatibleNaming
2020-07-02 16:42:12 +00:00
}
// Ctx holds relabeling context.
type Ctx struct {
// tmpLabels is used during ApplyRelabeling call.
tmpLabels [ ] prompbmarshal . Label
}
// Reset resets ctx.
func ( ctx * Ctx ) Reset ( ) {
2020-11-07 14:16:56 +00:00
promrelabel . CleanLabels ( ctx . tmpLabels )
2020-07-02 16:42:12 +00:00
ctx . tmpLabels = ctx . tmpLabels [ : 0 ]
}
// ApplyRelabeling applies relabeling to the given labels and returns the result.
//
// The returned labels are valid until the next call to ApplyRelabeling.
func ( ctx * Ctx ) ApplyRelabeling ( labels [ ] prompb . Label ) [ ] prompb . Label {
2021-02-22 14:33:55 +00:00
pcs := pcsGlobal . Load ( ) . ( * promrelabel . ParsedConfigs )
2022-09-26 10:11:37 +00:00
if pcs . Len ( ) == 0 && ! * usePromCompatibleNaming {
2020-07-02 20:13:13 +00:00
// There are no relabeling rules.
2020-07-02 16:42:12 +00:00
return labels
}
2022-09-26 10:11:37 +00:00
// Convert labels to prompbmarshal.Label format suitable for relabeling.
2020-07-02 16:42:12 +00:00
tmpLabels := ctx . tmpLabels [ : 0 ]
for _ , label := range labels {
name := bytesutil . ToUnsafeString ( label . Name )
if len ( name ) == 0 {
name = "__name__"
}
value := bytesutil . ToUnsafeString ( label . Value )
tmpLabels = append ( tmpLabels , prompbmarshal . Label {
Name : name ,
Value : value ,
} )
}
2022-09-26 10:11:37 +00:00
if * usePromCompatibleNaming {
// Replace unsupported Prometheus chars in label names and metric names with underscores.
for i := range tmpLabels {
label := & tmpLabels [ i ]
if label . Name == "__name__" {
label . Value = unsupportedPromChars . ReplaceAllString ( label . Value , "_" )
} else {
label . Name = unsupportedPromChars . ReplaceAllString ( label . Name , "_" )
}
}
}
if pcs . Len ( ) > 0 {
// Apply relabeling
tmpLabels = pcs . Apply ( tmpLabels , 0 , true )
if len ( tmpLabels ) == 0 {
metricsDropped . Inc ( )
}
2020-07-23 11:57:42 +00:00
}
2020-07-02 16:42:12 +00:00
2022-09-26 10:11:37 +00:00
ctx . tmpLabels = tmpLabels
2020-07-02 16:42:12 +00:00
// Return back labels to the desired format.
dst := labels [ : 0 ]
for _ , label := range tmpLabels {
name := bytesutil . ToUnsafeBytes ( label . Name )
if label . Name == "__name__" {
name = nil
}
value := bytesutil . ToUnsafeBytes ( label . Value )
dst = append ( dst , prompb . Label {
Name : name ,
Value : value ,
} )
}
return dst
}
2020-07-23 11:57:42 +00:00
var metricsDropped = metrics . NewCounter ( ` vm_relabel_metrics_dropped_total ` )
2022-09-26 10:11:37 +00:00
// See https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels
var unsupportedPromChars = regexp . MustCompile ( ` [^a-zA-Z0-9_:] ` )