diff --git a/README.md b/README.md index 188d605..b8f4b43 100644 --- a/README.md +++ b/README.md @@ -246,6 +246,29 @@ connection_settings: # env: GOOGLE_APPLICATION_CREDENTIALS ``` +### Runtime Settings + +```yaml +runtime: + flat: false + unix_time_unit: s # enum: s, ms + format: + timestamp: rfc3339 # enum: rfc3339, unix + value: float64 # enum: string, float64 +``` + +#### Flatten values + +By default, values are grouped by the label set. If you want to flatten the values array set `flat=true`. + +#### Unix timestamp's unit + +If you use integer values for duration and timestamp fields the connector will transform them with this unix timestamp unit. Accept second (`s`) and millisecond (`ms`). The default unit is second. + +#### Response Format + +These settings specify the format of response timestamp and value. + ## Development ### Get started diff --git a/connector/client/client.go b/connector/client/client.go index 98ca4ab..2c7729d 100644 --- a/connector/client/client.go +++ b/connector/client/client.go @@ -7,6 +7,8 @@ import ( "fmt" "log/slog" "net/http" + "net/url" + "strconv" "strings" "time" @@ -27,6 +29,10 @@ type Client struct { v1.API clientOptions + + // common OpenTelemetry attributes + serverAddress string + serverPort int } // NewClient creates a new Prometheus client instance @@ -40,6 +46,11 @@ func NewClient(ctx context.Context, cfg ClientSettings, tracer trace.Tracer, opt return nil, errors.New("the endpoint setting is empty") } + u, err := url.Parse(endpoint) + if err != nil { + return nil, fmt.Errorf("invalid Prometheus URL: %s", err) + } + httpClient, err := cfg.createHttpClient(ctx) if err != nil { return nil, err @@ -58,12 +69,25 @@ func NewClient(ctx context.Context, cfg ClientSettings, tracer trace.Tracer, opt opt(&opts) } clientWrapper := createHTTPClient(apiClient) - return &Client{ + + c := &Client{ client: clientWrapper, tracer: tracer, API: v1.NewAPI(clientWrapper), clientOptions: opts, - }, nil + + serverAddress: u.Host, + } + + port := u.Port() + if port != "" { + p, err := strconv.ParseInt(port, 10, 32) + if err != nil { + return nil, fmt.Errorf("invalid port of Prometheus URL: %s", err) + } + c.serverPort = int(p) + } + return c, nil } // ApplyOptions apply options to the Prometheus request diff --git a/connector/client/query.go b/connector/client/query.go index 33eed02..c97aecc 100644 --- a/connector/client/query.go +++ b/connector/client/query.go @@ -12,6 +12,7 @@ import ( "github.com/prometheus/common/model" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/trace" ) // Query evaluates an [instant query] at a single point in time @@ -22,9 +23,11 @@ func (c *Client) Query(ctx context.Context, queryString string, timestamp any, t ctx, span := c.tracer.Start(ctx, "Query") defer span.End() - span.SetAttributes(attribute.String("query", queryString)) - span.SetAttributes(attribute.String("timestamp", fmt.Sprint(timestamp))) - span.SetAttributes(attribute.String("timeout", fmt.Sprint(timeout))) + c.setQuerySpanAttributes(span, queryString) + span.SetAttributes( + attribute.String("timestamp", fmt.Sprint(timestamp)), + attribute.String("timeout", fmt.Sprint(timeout)), + ) opts, err := c.ApplyOptions(span, timeout) if err != nil { @@ -71,7 +74,7 @@ func (c *Client) QueryRange(ctx context.Context, queryString string, start any, ctx, span := c.tracer.Start(ctx, "QueryRange") defer span.End() - span.SetAttributes(attribute.String("query", queryString)) + c.setQuerySpanAttributes(span, queryString) span.SetAttributes(attribute.String("start", fmt.Sprint(start))) span.SetAttributes(attribute.String("end", fmt.Sprint(end))) span.SetAttributes(attribute.String("step", fmt.Sprint(step))) @@ -189,3 +192,14 @@ func (c *Client) FormatQuery(ctx context.Context, queryString string) (string, e } return result.Data, nil } + +func (c *Client) setQuerySpanAttributes(span trace.Span, queryString string) { + span.SetAttributes( + attribute.String("db.system", "prometheus"), + attribute.String("db.query.text", queryString), + attribute.String("server.address", c.serverAddress), + ) + if c.serverPort > 0 { + span.SetAttributes(attribute.Int("server.port", c.serverPort)) + } +} diff --git a/go.mod b/go.mod index 541fda8..0274c28 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.23.0 require ( github.com/alecthomas/kong v1.2.1 github.com/go-viper/mapstructure/v2 v2.2.1 - github.com/hasura/ndc-sdk-go v1.3.1-0.20240924031613-bf965d014b44 + github.com/hasura/ndc-sdk-go v1.4.0 github.com/iancoleman/strcase v0.3.0 github.com/invopop/jsonschema v0.12.0 github.com/lmittmann/tint v1.0.5 @@ -13,13 +13,13 @@ require ( github.com/prometheus/common v0.59.1 go.opentelemetry.io/otel v1.30.0 go.opentelemetry.io/otel/trace v1.30.0 - google.golang.org/api v0.198.0 + google.golang.org/api v0.199.0 gopkg.in/yaml.v3 v3.0.1 gotest.tools/v3 v3.5.1 ) require ( - cloud.google.com/go/auth v0.9.4 // indirect + cloud.google.com/go/auth v0.9.5 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect cloud.google.com/go/compute/metadata v0.5.2 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect diff --git a/go.sum b/go.sum index 2dae50e..161a4ef 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.115.1 h1:Jo0SM9cQnSkYfp44+v+NQXHpcHqlnRJk2qxh6yvxxxQ= -cloud.google.com/go/auth v0.9.4 h1:DxF7imbEbiFu9+zdKC6cKBko1e8XeJnipNqIbWZ+kDI= -cloud.google.com/go/auth v0.9.4/go.mod h1:SHia8n6//Ya940F1rLimhJCjjx7KE17t0ctFEci3HkA= +cloud.google.com/go/auth v0.9.5 h1:4CTn43Eynw40aFVr3GpPqsQponx2jv0BQpjvajsbbzw= +cloud.google.com/go/auth v0.9.5/go.mod h1:Xo0n7n66eHyOWWCnitop6870Ilwo3PiZyodVkkH1xWM= cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY= cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= -cloud.google.com/go/compute/metadata v0.5.1 h1:NM6oZeZNlYjiwYje+sYFjEpP0Q0zCan1bmQW/KmIrGs= -cloud.google.com/go/compute/metadata v0.5.1/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo= cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -42,8 +39,6 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-viper/mapstructure/v2 v2.2.0 h1:zGE1Kaz78LVwzU0kOfZuqwKKiG1gLkHTZ/cZioHp9po= -github.com/go-viper/mapstructure/v2 v2.2.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -78,8 +73,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gT github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= -github.com/hasura/ndc-sdk-go v1.3.1-0.20240924031613-bf965d014b44 h1:2sjWUqUlhiGsn4OaoAGKWyleq0ArWDBB33M6rEyWNpg= -github.com/hasura/ndc-sdk-go v1.3.1-0.20240924031613-bf965d014b44/go.mod h1:HYlvIl0qvoUupwb0MfDY9JZnltab+qSDQapEeSC70jY= +github.com/hasura/ndc-sdk-go v1.4.0 h1:RdkQm0efQfhDOxp/Gb1sLyOPh/q3XM7n1oOVKoG/rms= +github.com/hasura/ndc-sdk-go v1.4.0/go.mod h1:1DV7DoWoCrBdsyg/eSkdRxuvQJRySmyzdpcvFUmDoGo= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= @@ -91,8 +86,6 @@ github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2E github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/compress v1.17.10 h1:oXAz+Vh0PMUvJczoi+flxpnBEPxoER1IaAnU/NMPtT0= github.com/klauspost/compress v1.17.10/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -140,8 +133,6 @@ github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/ github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 h1:ZIg3ZT/aQ7AfKqdwp7ECpOK6vHqquXXuyTjIO8ZdmPs= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0/go.mod h1:DQAwmETtZV00skUwgD6+0U89g80NKsJE3DCKeLLPQMI= go.opentelemetry.io/contrib/propagators/b3 v1.30.0 h1:vumy4r1KMyaoQRltX7cJ37p3nluzALX9nugCjNNefuY= @@ -212,19 +203,15 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.198.0 h1:OOH5fZatk57iN0A7tjJQzt6aPfYQ1JiWkt1yGseazks= -google.golang.org/api v0.198.0/go.mod h1:/Lblzl3/Xqqk9hw/yS97TImKTUwnf1bv89v7+OagJzc= +google.golang.org/api v0.199.0 h1:aWUXClp+VFJmqE0JPvpZOK3LDQMyFKYIow4etYd9qxs= +google.golang.org/api v0.199.0/go.mod h1:ohG4qSztDJmZdjK/Ar6MhbAmb/Rpi4JHOqagsh90K28= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc= -google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= google.golang.org/genproto/googleapis/api v0.0.0-20240924160255-9d4c2d233b61 h1:pAjq8XSSzXoP9ya73v/w+9QEAAJNluLrpmMq5qFJQNY= google.golang.org/genproto/googleapis/api v0.0.0-20240924160255-9d4c2d233b61/go.mod h1:O6rP0uBq4k0mdi/b4ZEMAZjkhYWhS815kCvaMha4VN8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61 h1:N9BgCIAUvn/M+p4NJccWPWb3BWh88+zyL0ll9HgbEeM= google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=