Monitoring

동적 Prometheus 쿼리 만들기 with golang(레이블 삽입하기)

토마스.dev 2023. 12. 27. 07:27

그라파나를 통해서 사용자에게 메트릭을 제공하려고 할때 가끔가다가 사용자별 테넌트 분리를 해야하는 경우가 있다.

또는 동적으로 변하는 특정 타겟별로 각 메트릭을 얻어오는 사이드카를 만들려고 할때 고정된 쿼리를 사용할수 없는 경우도 있다.

 

이럴 때는 base prometheus 쿼리를 기반으로 동적으로 레이블을 넣어줄 수 있다. 여기서는 golang client를 이용하는 방법을 설명한다.

 

package main

import (
	"fmt"
	"github.com/prometheus/prometheus/promql/parser"
)

// addLabelToQuery는 주어진 PromQL 쿼리에 새로운 레이블을 추가합니다.
func addLabelToQuery(query, labelName, labelValue string) (string, error) {
	expr, err := parser.ParseExpr(query)
	if err != nil {
		return "", err
	}

	parser.Inspect(expr, func(node parser.Node, path []parser.Node) error {
		switch n := node.(type) {
		case *parser.VectorSelector:
			n.LabelMatchers = append(n.LabelMatchers, &parser.LabelMatcher{
				Type:  parser.MatchEqual,
				Name:  labelName,
				Value: labelValue,
			})
		}
		return nil
	})

	return expr.String(), nil
}

func main() {
	originalQuery := `sum(rate(http_requests_total[5m])) by (service)`
	labelToAdd := "region"
	labelValue := "us-west"

	newQuery, err := addLabelToQuery(originalQuery, labelToAdd, labelValue)
	if err != nil {
		fmt.Println("Error modifying query:", err)
		return
	}

	fmt.Println("Modified Query:", newQuery)
}

 

client 에 포함된 parser pkg를 사용한다.

parser 는 문자열로 인입된 쿼리를 파싱하여. 셀렉터(레이블) 노드 지점에 새로운 셀렉터를 추가한다.

셀렉터 외에도 다른 노드도 처리할 수 있다.

 

https://pkg.go.dev/github.com/prometheus/prometheus/promql/parser

 

parser package - github.com/prometheus/prometheus/promql/parser - Go Packages

  The highest tagged major version is v2. Discover Packages github.com/prometheus/prometheus promql parser Version: v0.48.1 Opens a new window with list of versions in this module. Published: Dec 8, 2023 License: Apache-2.0 Opens a new window with license

pkg.go.dev

 

위 예시코드의 결과는 다음과 같다.

sum(rate(http_requests_total{region="us-west"}[5m])) by (service)

 

리전이 동적으로 변해서 미래에 추가되거나 삭제될수 있는데, 리전별로 메트릭을 추출해 운영 자동화를 하고자할때 유용하게 사용할 수 있다.