From 1bff9ed8b9b5909ea0316e89831f16b7d6baa439 Mon Sep 17 00:00:00 2001 From: Yugandhar Vardhineni Date: Thu, 13 Jun 2024 20:35:18 +0530 Subject: [PATCH 1/6] feat: Add Prometheus metric to track exec querys per transaction * Added a new summary metric `transaction_exec_query_total` to track the number of exec querys per transaction * Introduced a new struct `managedTx` to to hold the context and connection of a transaction * Introduced a new field `execQueryCounter` in the `managedConn` to track the number of exec querys in a transaction. * When SQL lib opens a transaction we are storing the connection for that transacation and context of the transaction in the `managedTx`. * Context is used to store the required grpc labels for the metric. i.e. grpc method, grpc service * Added a UnaryInterceptor to the grpc server to store the grpc method and grpc service in the context * On commit or rollback of the transaction we are removing the connection from the `managedTx` and resetting the execQueryCounter to 0 * On commit of the transaction we are observing the `transaction_exec_query_total` metric by the number of exec querys in the transaction --- conn.go | 22 +++++++++++++++++++- go.mod | 20 +++++++++++++------ go.sum | 47 ++++++++++++++++++++++++++++++------------- prometheus.go | 50 ++++++++++++++++++++++++++++++++++++++++++++++ transaction.go | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 172 insertions(+), 21 deletions(-) create mode 100644 prometheus.go create mode 100644 transaction.go diff --git a/conn.go b/conn.go index be4bfc5..31da6fc 100644 --- a/conn.go +++ b/conn.go @@ -16,6 +16,8 @@ type managedConn struct { reset bool killed bool mu sync.RWMutex + + execQueryCounter int } // BeginTx calls the underlying BeginTx method unless the supervising context @@ -34,7 +36,12 @@ func (c *managedConn) BeginTx(ctx context.Context, opts driver.TxOptions) (drive } if conn, ok := c.conn.(driver.ConnBeginTx); ok { - return conn.BeginTx(ctx, opts) + tx, err := conn.BeginTx(ctx, opts) + if err != nil { + return nil, err + } + + return &managedTx{tx: tx, conn: c, ctx: ctx}, nil } // same as is defined in go sql package to call Begin method if the TxOptions are default @@ -79,6 +86,7 @@ func (c *managedConn) ExecContext(ctx context.Context, query string, args []driv if !ok { return nil, driver.ErrSkip } + c.incExecQueryCounter() //increment the exec counter to keep track of the number of exec calls return conn.ExecContext(ctx, query, args) } @@ -184,3 +192,15 @@ func (c *managedConn) GetKill() bool { defer c.mu.RUnlock() return c.killed } + +func (c *managedConn) incExecQueryCounter() { + c.mu.Lock() + defer c.mu.Unlock() + c.execQueryCounter++ +} + +func (c *managedConn) resetExecQueryCounter() { + c.mu.Lock() + defer c.mu.Unlock() + c.execQueryCounter = 0 +} diff --git a/go.mod b/go.mod index bf48ad7..ccb707e 100644 --- a/go.mod +++ b/go.mod @@ -9,17 +9,25 @@ require ( github.com/onsi/ginkgo v1.16.5 github.com/onsi/gomega v1.27.6 github.com/pkg/errors v0.9.1 + github.com/prometheus/client_golang v1.19.1 github.com/sirupsen/logrus v1.9.0 + google.golang.org/grpc v1.64.0 ) require ( - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/kr/text v0.2.0 // indirect github.com/nxadm/tail v1.4.8 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/sys v0.6.0 // indirect - golang.org/x/text v0.8.0 // indirect - golang.org/x/tools v0.7.0 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.48.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect + golang.org/x/net v0.22.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/text v0.14.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 53e73c1..46261ea 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,10 @@ github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -10,7 +15,6 @@ github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbS github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -18,14 +22,17 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.10.8 h1:3fdt97i/cwSU83+E0hZTC/Xpc9mTZxc6UWSCRcSbxiE= github.com/lib/pq v1.10.8/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -44,11 +51,19 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= +github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -61,8 +76,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -77,30 +92,34 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= +google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= diff --git a/prometheus.go b/prometheus.go new file mode 100644 index 0000000..30f38bd --- /dev/null +++ b/prometheus.go @@ -0,0 +1,50 @@ +package hotload + +import ( + "context" + "strings" + + "github.com/prometheus/client_golang/prometheus" + "google.golang.org/grpc" +) + +const ( + GRPCMethodKey = "grpc_method" + GRPCServiceKey = "grpc_service" +) + +// execQuerySummary is a prometheus metric to keep track of the number of times +// exec query is called in a transaction +var execQuerySummary = prometheus.NewSummaryVec(prometheus.SummaryOpts{ + Name: "transaction_exec_query_total", + Help: "The number of times exec query is called in a transaction", +}, []string{GRPCServiceKey, GRPCMethodKey}) + +func init() { + prometheus.MustRegister(execQuerySummary) +} + +// PromUnaryServerInterceptor returns a unary server interceptor that sets the +// prometheus labels for the grpc service and method. This is useful for +// population the prometheus metrics. +func PromUnaryServerInterceptor() func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + service, method := splitMethod(info.FullMethod) + labels := map[string]string{ + GRPCMethodKey: method, + GRPCServiceKey: service, + } + ctx = ContextWithExecLabels(ctx, labels) + return handler(ctx, req) + } +} + +func splitMethod(fullMethod string) (service, method string) { + // fullMethod is in the form "/service/method" + // We need to split it into service and method + split := strings.Split(fullMethod, "/") + if len(split) != 3 { + return "unknown", "unknown" + } + return split[1], split[2] +} diff --git a/transaction.go b/transaction.go new file mode 100644 index 0000000..0ff062c --- /dev/null +++ b/transaction.go @@ -0,0 +1,54 @@ +package hotload + +import ( + "context" + "database/sql/driver" +) + +// managedTx wraps a sql/driver.Tx so that it can store the context of the +// transaction and clean up the execQueryCounter on Commit or Rollback. +type managedTx struct { + tx driver.Tx + conn *managedConn + ctx context.Context +} + +func (t *managedTx) Commit() error { + err := t.tx.Commit() + t.cleanup() + return err +} + +func (t *managedTx) Rollback() error { + err := t.tx.Rollback() + t.cleanup() + return err +} + +func observeExecQuerySummary(ctx context.Context, counter int) { + labels := GetExecLabelsFromContext(ctx) + execQuerySummary.WithLabelValues(labels[GRPCServiceKey], labels[GRPCMethodKey]).Observe(float64(counter)) +} + +func (t *managedTx) cleanup() { + observeExecQuerySummary(t.ctx, t.conn.execQueryCounter) + t.conn.resetExecQueryCounter() +} + +var promLabelKey = struct{}{} + +func ContextWithExecLabels(ctx context.Context, labels map[string]string) context.Context { + return context.WithValue(ctx, promLabelKey, labels) +} + +func GetExecLabelsFromContext(ctx context.Context) map[string]string { + if ctx == nil { + return nil + } + + if ctx.Value(promLabelKey) == nil { + return nil + } + + return ctx.Value(promLabelKey).(map[string]string) +} From 612f26276bff60d1d1f37574f77079629813a5bb Mon Sep 17 00:00:00 2001 From: Yugandhar Vardhineni Date: Tue, 18 Jun 2024 21:37:44 +0530 Subject: [PATCH 2/6] feat: Add Prometheus metric to track exec querys per transaction * Added two counter to track exec and query statements seperately. * UTs added for the same. --- conn.go | 28 ++++- conn_test.go | 202 ++++++++++++++++++++++++++++++- go.mod | 1 + integrationtests/hotload_test.go | 7 +- prometheus.go | 17 +-- prometheus_test.go | 39 ++++++ transaction.go | 15 ++- 7 files changed, 287 insertions(+), 22 deletions(-) create mode 100644 prometheus_test.go diff --git a/conn.go b/conn.go index 31da6fc..cea8935 100644 --- a/conn.go +++ b/conn.go @@ -17,7 +17,8 @@ type managedConn struct { killed bool mu sync.RWMutex - execQueryCounter int + execStmtsCounter int // count the number of exec calls in a transaction + queryStmtsCounter int // count the number of query calls in a transaction } // BeginTx calls the underlying BeginTx method unless the supervising context @@ -78,6 +79,7 @@ func (c *managedConn) Exec(query string, args []driver.Value) (driver.Result, er if !ok { return nil, driver.ErrSkip } + c.incExecStmtsCounter() //increment the exec counter to keep track of the number of exec calls return conn.Exec(query, args) } @@ -86,7 +88,7 @@ func (c *managedConn) ExecContext(ctx context.Context, query string, args []driv if !ok { return nil, driver.ErrSkip } - c.incExecQueryCounter() //increment the exec counter to keep track of the number of exec calls + c.incExecStmtsCounter() //increment the exec counter to keep track of the number of exec calls return conn.ExecContext(ctx, query, args) } @@ -103,6 +105,7 @@ func (c *managedConn) Query(query string, args []driver.Value) (driver.Rows, err if !ok { return nil, driver.ErrSkip } + c.incQueryStmtsCounter() //increment the query counter to keep track of the number of query calls return conn.Query(query, args) } @@ -111,6 +114,7 @@ func (c *managedConn) QueryContext(ctx context.Context, query string, args []dri if !ok { return nil, driver.ErrSkip } + c.incQueryStmtsCounter() //increment the query counter to keep track of the number of query calls return conn.QueryContext(ctx, query, args) } @@ -193,14 +197,26 @@ func (c *managedConn) GetKill() bool { return c.killed } -func (c *managedConn) incExecQueryCounter() { +func (c *managedConn) incExecStmtsCounter() { c.mu.Lock() defer c.mu.Unlock() - c.execQueryCounter++ + c.execStmtsCounter++ } -func (c *managedConn) resetExecQueryCounter() { +func (c *managedConn) resetExecStmtsCounter() { c.mu.Lock() defer c.mu.Unlock() - c.execQueryCounter = 0 + c.execStmtsCounter = 0 +} + +func (c *managedConn) incQueryStmtsCounter() { + c.mu.Lock() + defer c.mu.Unlock() + c.queryStmtsCounter++ +} + +func (c *managedConn) resetQueryStmtsCounter() { + c.mu.Lock() + defer c.mu.Unlock() + c.queryStmtsCounter = 0 } diff --git a/conn_test.go b/conn_test.go index d17a278..aeaa0cc 100644 --- a/conn_test.go +++ b/conn_test.go @@ -1,9 +1,15 @@ package hotload import ( + "context" + "database/sql/driver" + "io" + "strings" + "sync" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "sync" + "github.com/prometheus/client_golang/prometheus/testutil" ) var _ = Describe("managedConn", func() { @@ -34,3 +40,197 @@ var _ = Describe("managedConn", func() { Consistently(readLockAcquired).Should(BeFalse()) }) }) + +/**** Mocks for Prometheus Metrics ****/ + +type mockDriverConn struct{} + +type mockTx struct{} + +func (mockTx) Commit() error { + return nil +} + +func (mockTx) Rollback() error { + return nil +} + +func (mockDriverConn) Prepare(query string) (driver.Stmt, error) { + return nil, nil +} + +func (mockDriverConn) Begin() (driver.Tx, error) { + return mockTx{}, nil +} + +func (mockDriverConn) Close() error { + return nil +} + +func (mockDriverConn) IsValid() bool { + return true +} + +func (mockDriverConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { + return mockTx{}, nil +} + +func (mockDriverConn) Exec(query string, args []driver.Value) (driver.Result, error) { + return nil, nil +} + +func (mockDriverConn) Query(query string, args []driver.Value) (driver.Rows, error) { + return nil, nil +} + +func (mockDriverConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) { + return nil, nil +} + +func (mockDriverConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { + return nil, nil +} + +/**** End Mocks for Prometheus Metrics ****/ + +var _ = Describe("PrometheusMetrics", func() { + const help = ` + # HELP transaction_sql_stmts_total The number of sql stmts called in a transaction by statement type per grpc service and method + # TYPE transaction_sql_stmts_total summary + ` + + var service1Metrics = ` + transaction_sql_stmts_total_sum{grpc_method="service_1",grpc_service="method_1",stmt="exec"} 3 + transaction_sql_stmts_total_count{grpc_method="service_1",grpc_service="method_1",stmt="exec"} 1 + transaction_sql_stmts_total_sum{grpc_method="service_1",grpc_service="method_1",stmt="query"} 3 + transaction_sql_stmts_total_count{grpc_method="service_1",grpc_service="method_1",stmt="query"} 1 + ` + + var service2Metrics = ` + transaction_sql_stmts_total_sum{grpc_method="service_2",grpc_service="method_2",stmt="exec"} 4 + transaction_sql_stmts_total_count{grpc_method="service_2",grpc_service="method_2",stmt="exec"} 1 + transaction_sql_stmts_total_sum{grpc_method="service_2",grpc_service="method_2",stmt="query"} 4 + transaction_sql_stmts_total_count{grpc_method="service_2",grpc_service="method_2",stmt="query"} 1 + ` + + var service1RerunMetrics = ` + transaction_sql_stmts_total_sum{grpc_method="service_1",grpc_service="method_1",stmt="exec"} 4 + transaction_sql_stmts_total_count{grpc_method="service_1",grpc_service="method_1",stmt="exec"} 2 + transaction_sql_stmts_total_sum{grpc_method="service_1",grpc_service="method_1",stmt="query"} 4 + transaction_sql_stmts_total_count{grpc_method="service_1",grpc_service="method_1",stmt="query"} 2 + ` + + var noMethodMetrics = ` + transaction_sql_stmts_total_sum{grpc_method="",grpc_service="",stmt="exec"} 1 + transaction_sql_stmts_total_count{grpc_method="",grpc_service="",stmt="exec"} 1 + transaction_sql_stmts_total_sum{grpc_method="",grpc_service="",stmt="query"} 1 + transaction_sql_stmts_total_count{grpc_method="",grpc_service="",stmt="query"} 1 + ` + + It("Should emit the correct metrics", func() { + mc := newManagedConn(context.Background(), mockDriverConn{}) + + ctx := ContextWithExecLabels(context.Background(), map[string]string{"grpc_method": "service_1", "grpc_service": "method_1"}) + + // begin a transaction + tx, err := mc.BeginTx(ctx, driver.TxOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + + // exec a statement + mc.Exec("INSERT INTO table (column) VALUES (?)", []driver.Value{"value"}) + + // query a statement + mc.Query("SELECT * FROM table WHERE column = ?", []driver.Value{"value"}) + mc.Query("SELECT * FROM table WHERE column = ?", []driver.Value{"value"}) + + // exec a statement with context + mc.ExecContext(ctx, "INSERT INTO table (column) VALUES (?)", []driver.NamedValue{{Value: "value"}}) + mc.ExecContext(ctx, "INSERT INTO table (column) VALUES (?)", []driver.NamedValue{{Value: "value"}}) + + // query a statement with context + mc.QueryContext(ctx, "SELECT * FROM table WHERE column = ?", []driver.NamedValue{{Value: "value"}}) + + // commit the transaction + err = tx.Commit() + Expect(err).ShouldNot(HaveOccurred()) + + // collect and compare metrics + err = testutil.CollectAndCompare(sqlStmtsSummary, strings.NewReader(help+service1Metrics)) + Expect(err).ShouldNot(HaveOccurred()) + + // reset the metrics + // new context + ctx = ContextWithExecLabels(context.Background(), map[string]string{"grpc_method": "service_2", "grpc_service": "method_2"}) + // begin a transaction + tx, err = mc.BeginTx(ctx, driver.TxOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + + // exec a statement + mc.Exec("INSERT INTO table (column) VALUES (?)", []driver.Value{"value"}) + mc.Exec("INSERT INTO table (column) VALUES (?)", []driver.Value{"value"}) + + // query a statement + mc.Query("SELECT * FROM table WHERE column = ?", []driver.Value{"value"}) + mc.Query("SELECT * FROM table WHERE column = ?", []driver.Value{"value"}) + + // exec a statement with context + mc.ExecContext(ctx, "INSERT INTO table (column) VALUES (?)", []driver.NamedValue{{Value: "value"}}) + mc.ExecContext(ctx, "INSERT INTO table (column) VALUES (?)", []driver.NamedValue{{Value: "value"}}) + + // query a statement with context + mc.QueryContext(ctx, "SELECT * FROM table WHERE column = ?", []driver.NamedValue{{Value: "value"}}) + mc.QueryContext(ctx, "SELECT * FROM table WHERE column = ?", []driver.NamedValue{{Value: "value"}}) + + // commit the transaction + err = tx.Commit() + Expect(err).ShouldNot(HaveOccurred()) + + // collect and compare metrics + err = testutil.CollectAndCompare(sqlStmtsSummary, strings.NewReader(help+service1Metrics+service2Metrics)) + Expect(err).ShouldNot(HaveOccurred()) + + // rerun with initial metrics + ctx = ContextWithExecLabels(context.Background(), map[string]string{"grpc_method": "service_1", "grpc_service": "method_1"}) + // begin a transaction + tx, err = mc.BeginTx(ctx, driver.TxOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + + // exec a statement with context + mc.ExecContext(ctx, "INSERT INTO table (column) VALUES (?)", []driver.NamedValue{{Value: "value"}}) + + // query a statement with context + mc.QueryContext(ctx, "SELECT * FROM table WHERE column = ?", []driver.NamedValue{{Value: "value"}}) + + // rollback the transaction + err = tx.Rollback() + Expect(err).ShouldNot(HaveOccurred()) + + // collect and compare metrics + err = testutil.CollectAndCompare(sqlStmtsSummary, strings.NewReader(help+service1RerunMetrics+service2Metrics)) + Expect(err).ShouldNot(HaveOccurred()) + + // non labeled context + ctx = context.Background() + // begin a transaction + tx, err = mc.BeginTx(ctx, driver.TxOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + + // exec query context + mc.ExecContext(ctx, "INSERT INTO table (column) VALUES (?)", []driver.NamedValue{{Value: "value"}}) + + // query a statement with context + mc.QueryContext(ctx, "SELECT * FROM table WHERE column = ?", []driver.NamedValue{{Value: "value"}}) + + // commit the transaction + err = tx.Commit() + Expect(err).ShouldNot(HaveOccurred()) + + // collect and compare metrics + err = testutil.CollectAndCompare(sqlStmtsSummary, strings.NewReader(help+noMethodMetrics+service1RerunMetrics+service2Metrics)) + Expect(err).ShouldNot(HaveOccurred()) + }) +}) + +func CollectAndCompareMetrics(r io.Reader) error { + return testutil.CollectAndCompare(sqlStmtsSummary, r) +} diff --git a/go.mod b/go.mod index ccb707e..917c54c 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,7 @@ require ( require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/kr/text v0.2.0 // indirect github.com/nxadm/tail v1.4.8 // indirect diff --git a/integrationtests/hotload_test.go b/integrationtests/hotload_test.go index cd91db1..398a9be 100644 --- a/integrationtests/hotload_test.go +++ b/integrationtests/hotload_test.go @@ -3,15 +3,16 @@ package integrationtests import ( "database/sql" "fmt" + "io/ioutil" + "log" + "time" + "github.com/infobloxopen/hotload" _ "github.com/infobloxopen/hotload/fsnotify" "github.com/lib/pq" _ "github.com/lib/pq" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "io/ioutil" - "log" - "time" ) const ( diff --git a/prometheus.go b/prometheus.go index 30f38bd..bd0be0b 100644 --- a/prometheus.go +++ b/prometheus.go @@ -11,17 +11,20 @@ import ( const ( GRPCMethodKey = "grpc_method" GRPCServiceKey = "grpc_service" + StatementKey = "stmt" // either exec or query + ExecStatement = "exec" + QueryStatement = "query" ) -// execQuerySummary is a prometheus metric to keep track of the number of times -// exec query is called in a transaction -var execQuerySummary = prometheus.NewSummaryVec(prometheus.SummaryOpts{ - Name: "transaction_exec_query_total", - Help: "The number of times exec query is called in a transaction", -}, []string{GRPCServiceKey, GRPCMethodKey}) +// sqlStmtsSummary is a prometheus metric to keep track of the number of times +// a sql statement is called in a transaction by statement type per grpc service +var sqlStmtsSummary = prometheus.NewSummaryVec(prometheus.SummaryOpts{ + Name: "transaction_sql_stmts_total", + Help: "The number of sql stmts called in a transaction by statement type per grpc service and method", +}, []string{GRPCServiceKey, GRPCMethodKey, StatementKey}) func init() { - prometheus.MustRegister(execQuerySummary) + prometheus.MustRegister(sqlStmtsSummary) } // PromUnaryServerInterceptor returns a unary server interceptor that sets the diff --git a/prometheus_test.go b/prometheus_test.go new file mode 100644 index 0000000..9fff8ef --- /dev/null +++ b/prometheus_test.go @@ -0,0 +1,39 @@ +package hotload + +import ( + "context" + "errors" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/prometheus/client_golang/prometheus" + "google.golang.org/grpc" +) + +var _ = Describe("PrometheusMetric", func() { + It("Should register a prometheus metric", func() { + // This test is a placeholder for a real test + err := prometheus.Register(sqlStmtsSummary) + Expect(err).Should(HaveOccurred()) + Expect(errors.As(err, &prometheus.AlreadyRegisteredError{})).Should(BeTrue()) + }) +}) + +var _ = Describe("PromUnaryServerInterceptor", func() { + It("Should return a unary server interceptor", func() { + validationHandler := func(ctx context.Context, req interface{}) (interface{}, error) { + labels := GetExecLabelsFromContext(ctx) + + Expect(labels).ShouldNot(BeNil()) + Expect(labels[GRPCMethodKey]).Should(Equal("List")) + Expect(labels[GRPCServiceKey]).Should(Equal("infoblox.service.SampleService")) + + return nil, nil + } + + promUnaryServerInterceptor := PromUnaryServerInterceptor() + promUnaryServerInterceptor(context.Background(), struct{}{}, &grpc.UnaryServerInfo{ + FullMethod: "/infoblox.service.SampleService/List", + }, validationHandler) + }) +}) diff --git a/transaction.go b/transaction.go index 0ff062c..7d695bd 100644 --- a/transaction.go +++ b/transaction.go @@ -6,7 +6,7 @@ import ( ) // managedTx wraps a sql/driver.Tx so that it can store the context of the -// transaction and clean up the execQueryCounter on Commit or Rollback. +// transaction and clean up the execqueryCallsCounter on Commit or Rollback. type managedTx struct { tx driver.Tx conn *managedConn @@ -25,14 +25,19 @@ func (t *managedTx) Rollback() error { return err } -func observeExecQuerySummary(ctx context.Context, counter int) { +func observeSQLStmtsSummary(ctx context.Context, execStmtsCounter, queryStmtsCounter int) { labels := GetExecLabelsFromContext(ctx) - execQuerySummary.WithLabelValues(labels[GRPCServiceKey], labels[GRPCMethodKey]).Observe(float64(counter)) + service := labels[GRPCServiceKey] + method := labels[GRPCMethodKey] + + sqlStmtsSummary.WithLabelValues(service, method, ExecStatement).Observe(float64(execStmtsCounter)) + sqlStmtsSummary.WithLabelValues(service, method, QueryStatement).Observe(float64(queryStmtsCounter)) } func (t *managedTx) cleanup() { - observeExecQuerySummary(t.ctx, t.conn.execQueryCounter) - t.conn.resetExecQueryCounter() + observeSQLStmtsSummary(t.ctx, t.conn.execStmtsCounter, t.conn.queryStmtsCounter) + t.conn.resetExecStmtsCounter() + t.conn.resetQueryStmtsCounter() } var promLabelKey = struct{}{} From 7f60ff2a2f09a1ba36225e452f402fdef5c4cbe8 Mon Sep 17 00:00:00 2001 From: Yugandhar Vardhineni Date: Tue, 18 Jun 2024 21:58:26 +0530 Subject: [PATCH 3/6] downgraded prom versions to support go 1.19 --- Makefile | 5 ++++- go.mod | 5 +++-- go.sum | 10 ++++++---- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index d58b5ac..f500507 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,9 @@ get: fmt: get go fmt ./... +tidy: + go mod tidy + # assert that there is no difference after running format no-diff: git diff --exit-code @@ -25,7 +28,7 @@ test: vet get-ginkgo # test target which includes the no-diff fail condition -ci-test: fmt no-diff test +ci-test: fmt tidy no-diff test test-docker: docker build -f Dockerfile.test . diff --git a/go.mod b/go.mod index 917c54c..1d1213b 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/onsi/ginkgo v1.16.5 github.com/onsi/gomega v1.27.6 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.19.1 + github.com/prometheus/client_golang v1.18.0 github.com/sirupsen/logrus v1.9.0 google.golang.org/grpc v1.64.0 ) @@ -20,9 +20,10 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/kr/text v0.2.0 // indirect + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/nxadm/tail v1.4.8 // indirect github.com/prometheus/client_model v0.5.0 // indirect - github.com/prometheus/common v0.48.0 // indirect + github.com/prometheus/common v0.45.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect golang.org/x/net v0.22.0 // indirect golang.org/x/sys v0.18.0 // indirect diff --git a/go.sum b/go.sum index 46261ea..facfc55 100644 --- a/go.sum +++ b/go.sum @@ -35,6 +35,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.10.8 h1:3fdt97i/cwSU83+E0hZTC/Xpc9mTZxc6UWSCRcSbxiE= github.com/lib/pq v1.10.8/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= @@ -51,12 +53,12 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= -github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= -github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= +github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= From e5cc080009bf7cd1a1ce8b874e67be54e00bade0 Mon Sep 17 00:00:00 2001 From: Yugandhar Vardhineni Date: Tue, 18 Jun 2024 23:50:35 +0530 Subject: [PATCH 4/6] fix ut --- conn_test.go | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/conn_test.go b/conn_test.go index aeaa0cc..c6d8cea 100644 --- a/conn_test.go +++ b/conn_test.go @@ -100,24 +100,24 @@ var _ = Describe("PrometheusMetrics", func() { ` var service1Metrics = ` - transaction_sql_stmts_total_sum{grpc_method="service_1",grpc_service="method_1",stmt="exec"} 3 - transaction_sql_stmts_total_count{grpc_method="service_1",grpc_service="method_1",stmt="exec"} 1 - transaction_sql_stmts_total_sum{grpc_method="service_1",grpc_service="method_1",stmt="query"} 3 - transaction_sql_stmts_total_count{grpc_method="service_1",grpc_service="method_1",stmt="query"} 1 + transaction_sql_stmts_total_sum{grpc_method="method_1",grpc_service="service_1",stmt="exec"} 3 + transaction_sql_stmts_total_count{grpc_method="method_1",grpc_service="service_1",stmt="exec"} 1 + transaction_sql_stmts_total_sum{grpc_method="method_1",grpc_service="service_1",stmt="query"} 3 + transaction_sql_stmts_total_count{grpc_method="method_1",grpc_service="service_1",stmt="query"} 1 ` var service2Metrics = ` - transaction_sql_stmts_total_sum{grpc_method="service_2",grpc_service="method_2",stmt="exec"} 4 - transaction_sql_stmts_total_count{grpc_method="service_2",grpc_service="method_2",stmt="exec"} 1 - transaction_sql_stmts_total_sum{grpc_method="service_2",grpc_service="method_2",stmt="query"} 4 - transaction_sql_stmts_total_count{grpc_method="service_2",grpc_service="method_2",stmt="query"} 1 + transaction_sql_stmts_total_sum{grpc_method="method_2",grpc_service="service_2",stmt="exec"} 4 + transaction_sql_stmts_total_count{grpc_method="method_2",grpc_service="service_2",stmt="exec"} 1 + transaction_sql_stmts_total_sum{grpc_method="method_2",grpc_service="service_2",stmt="query"} 4 + transaction_sql_stmts_total_count{grpc_method="method_2",grpc_service="service_2",stmt="query"} 1 ` var service1RerunMetrics = ` - transaction_sql_stmts_total_sum{grpc_method="service_1",grpc_service="method_1",stmt="exec"} 4 - transaction_sql_stmts_total_count{grpc_method="service_1",grpc_service="method_1",stmt="exec"} 2 - transaction_sql_stmts_total_sum{grpc_method="service_1",grpc_service="method_1",stmt="query"} 4 - transaction_sql_stmts_total_count{grpc_method="service_1",grpc_service="method_1",stmt="query"} 2 + transaction_sql_stmts_total_sum{grpc_method="method_1",grpc_service="service_1",stmt="exec"} 4 + transaction_sql_stmts_total_count{grpc_method="method_1",grpc_service="service_1",stmt="exec"} 2 + transaction_sql_stmts_total_sum{grpc_method="method_1",grpc_service="service_1",stmt="query"} 4 + transaction_sql_stmts_total_count{grpc_method="method_1",grpc_service="service_1",stmt="query"} 2 ` var noMethodMetrics = ` @@ -130,7 +130,7 @@ var _ = Describe("PrometheusMetrics", func() { It("Should emit the correct metrics", func() { mc := newManagedConn(context.Background(), mockDriverConn{}) - ctx := ContextWithExecLabels(context.Background(), map[string]string{"grpc_method": "service_1", "grpc_service": "method_1"}) + ctx := ContextWithExecLabels(context.Background(), map[string]string{"grpc_method": "method_1", "grpc_service": "service_1"}) // begin a transaction tx, err := mc.BeginTx(ctx, driver.TxOptions{}) @@ -160,7 +160,7 @@ var _ = Describe("PrometheusMetrics", func() { // reset the metrics // new context - ctx = ContextWithExecLabels(context.Background(), map[string]string{"grpc_method": "service_2", "grpc_service": "method_2"}) + ctx = ContextWithExecLabels(context.Background(), map[string]string{"grpc_method": "method_2", "grpc_service": "service_2"}) // begin a transaction tx, err = mc.BeginTx(ctx, driver.TxOptions{}) Expect(err).ShouldNot(HaveOccurred()) @@ -190,7 +190,7 @@ var _ = Describe("PrometheusMetrics", func() { Expect(err).ShouldNot(HaveOccurred()) // rerun with initial metrics - ctx = ContextWithExecLabels(context.Background(), map[string]string{"grpc_method": "service_1", "grpc_service": "method_1"}) + ctx = ContextWithExecLabels(context.Background(), map[string]string{"grpc_method": "method_1", "grpc_service": "service_1"}) // begin a transaction tx, err = mc.BeginTx(ctx, driver.TxOptions{}) Expect(err).ShouldNot(HaveOccurred()) From 5fd99141dff8767383b566c6d6e4a3af797f5ba1 Mon Sep 17 00:00:00 2001 From: Yugandhar Vardhineni Date: Wed, 19 Jun 2024 00:54:03 +0530 Subject: [PATCH 5/6] naming conventions --- conn_test.go | 36 ++++++++++++++++++------------------ prometheus.go | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/conn_test.go b/conn_test.go index c6d8cea..39463ab 100644 --- a/conn_test.go +++ b/conn_test.go @@ -95,36 +95,36 @@ func (mockDriverConn) QueryContext(ctx context.Context, query string, args []dri var _ = Describe("PrometheusMetrics", func() { const help = ` - # HELP transaction_sql_stmts_total The number of sql stmts called in a transaction by statement type per grpc service and method - # TYPE transaction_sql_stmts_total summary + # HELP transaction_sql_stmts The number of sql stmts called in a transaction by statement type per grpc service and method + # TYPE transaction_sql_stmts summary ` var service1Metrics = ` - transaction_sql_stmts_total_sum{grpc_method="method_1",grpc_service="service_1",stmt="exec"} 3 - transaction_sql_stmts_total_count{grpc_method="method_1",grpc_service="service_1",stmt="exec"} 1 - transaction_sql_stmts_total_sum{grpc_method="method_1",grpc_service="service_1",stmt="query"} 3 - transaction_sql_stmts_total_count{grpc_method="method_1",grpc_service="service_1",stmt="query"} 1 + transaction_sql_stmts_sum{grpc_method="method_1",grpc_service="service_1",stmt="exec"} 3 + transaction_sql_stmts_count{grpc_method="method_1",grpc_service="service_1",stmt="exec"} 1 + transaction_sql_stmts_sum{grpc_method="method_1",grpc_service="service_1",stmt="query"} 3 + transaction_sql_stmts_count{grpc_method="method_1",grpc_service="service_1",stmt="query"} 1 ` var service2Metrics = ` - transaction_sql_stmts_total_sum{grpc_method="method_2",grpc_service="service_2",stmt="exec"} 4 - transaction_sql_stmts_total_count{grpc_method="method_2",grpc_service="service_2",stmt="exec"} 1 - transaction_sql_stmts_total_sum{grpc_method="method_2",grpc_service="service_2",stmt="query"} 4 - transaction_sql_stmts_total_count{grpc_method="method_2",grpc_service="service_2",stmt="query"} 1 + transaction_sql_stmts_sum{grpc_method="method_2",grpc_service="service_2",stmt="exec"} 4 + transaction_sql_stmts_count{grpc_method="method_2",grpc_service="service_2",stmt="exec"} 1 + transaction_sql_stmts_sum{grpc_method="method_2",grpc_service="service_2",stmt="query"} 4 + transaction_sql_stmts_count{grpc_method="method_2",grpc_service="service_2",stmt="query"} 1 ` var service1RerunMetrics = ` - transaction_sql_stmts_total_sum{grpc_method="method_1",grpc_service="service_1",stmt="exec"} 4 - transaction_sql_stmts_total_count{grpc_method="method_1",grpc_service="service_1",stmt="exec"} 2 - transaction_sql_stmts_total_sum{grpc_method="method_1",grpc_service="service_1",stmt="query"} 4 - transaction_sql_stmts_total_count{grpc_method="method_1",grpc_service="service_1",stmt="query"} 2 + transaction_sql_stmts_sum{grpc_method="method_1",grpc_service="service_1",stmt="exec"} 4 + transaction_sql_stmts_count{grpc_method="method_1",grpc_service="service_1",stmt="exec"} 2 + transaction_sql_stmts_sum{grpc_method="method_1",grpc_service="service_1",stmt="query"} 4 + transaction_sql_stmts_count{grpc_method="method_1",grpc_service="service_1",stmt="query"} 2 ` var noMethodMetrics = ` - transaction_sql_stmts_total_sum{grpc_method="",grpc_service="",stmt="exec"} 1 - transaction_sql_stmts_total_count{grpc_method="",grpc_service="",stmt="exec"} 1 - transaction_sql_stmts_total_sum{grpc_method="",grpc_service="",stmt="query"} 1 - transaction_sql_stmts_total_count{grpc_method="",grpc_service="",stmt="query"} 1 + transaction_sql_stmts_sum{grpc_method="",grpc_service="",stmt="exec"} 1 + transaction_sql_stmts_count{grpc_method="",grpc_service="",stmt="exec"} 1 + transaction_sql_stmts_sum{grpc_method="",grpc_service="",stmt="query"} 1 + transaction_sql_stmts_count{grpc_method="",grpc_service="",stmt="query"} 1 ` It("Should emit the correct metrics", func() { diff --git a/prometheus.go b/prometheus.go index bd0be0b..0e0fca8 100644 --- a/prometheus.go +++ b/prometheus.go @@ -19,7 +19,7 @@ const ( // sqlStmtsSummary is a prometheus metric to keep track of the number of times // a sql statement is called in a transaction by statement type per grpc service var sqlStmtsSummary = prometheus.NewSummaryVec(prometheus.SummaryOpts{ - Name: "transaction_sql_stmts_total", + Name: "transaction_sql_stmts", Help: "The number of sql stmts called in a transaction by statement type per grpc service and method", }, []string{GRPCServiceKey, GRPCMethodKey, StatementKey}) From 700112e99d632606c6f06af74c987ead32cc2567 Mon Sep 17 00:00:00 2001 From: Yugandhar Vardhineni Date: Wed, 19 Jun 2024 23:53:46 +0530 Subject: [PATCH 6/6] removed interceptor --- go.mod | 3 +-- go.sum | 5 +---- prometheus.go | 29 ----------------------------- prometheus_test.go | 21 --------------------- 4 files changed, 2 insertions(+), 56 deletions(-) diff --git a/go.mod b/go.mod index 1d1213b..6251049 100644 --- a/go.mod +++ b/go.mod @@ -11,13 +11,13 @@ require ( github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.18.0 github.com/sirupsen/logrus v1.9.0 - google.golang.org/grpc v1.64.0 ) require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/kr/text v0.2.0 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect @@ -28,7 +28,6 @@ require ( golang.org/x/net v0.22.0 // indirect golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index facfc55..ef3409f 100644 --- a/go.sum +++ b/go.sum @@ -23,6 +23,7 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -108,10 +109,6 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/prometheus.go b/prometheus.go index 0e0fca8..4c97af2 100644 --- a/prometheus.go +++ b/prometheus.go @@ -1,11 +1,7 @@ package hotload import ( - "context" - "strings" - "github.com/prometheus/client_golang/prometheus" - "google.golang.org/grpc" ) const ( @@ -26,28 +22,3 @@ var sqlStmtsSummary = prometheus.NewSummaryVec(prometheus.SummaryOpts{ func init() { prometheus.MustRegister(sqlStmtsSummary) } - -// PromUnaryServerInterceptor returns a unary server interceptor that sets the -// prometheus labels for the grpc service and method. This is useful for -// population the prometheus metrics. -func PromUnaryServerInterceptor() func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { - return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { - service, method := splitMethod(info.FullMethod) - labels := map[string]string{ - GRPCMethodKey: method, - GRPCServiceKey: service, - } - ctx = ContextWithExecLabels(ctx, labels) - return handler(ctx, req) - } -} - -func splitMethod(fullMethod string) (service, method string) { - // fullMethod is in the form "/service/method" - // We need to split it into service and method - split := strings.Split(fullMethod, "/") - if len(split) != 3 { - return "unknown", "unknown" - } - return split[1], split[2] -} diff --git a/prometheus_test.go b/prometheus_test.go index 9fff8ef..64ec7c9 100644 --- a/prometheus_test.go +++ b/prometheus_test.go @@ -1,13 +1,11 @@ package hotload import ( - "context" "errors" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/prometheus/client_golang/prometheus" - "google.golang.org/grpc" ) var _ = Describe("PrometheusMetric", func() { @@ -18,22 +16,3 @@ var _ = Describe("PrometheusMetric", func() { Expect(errors.As(err, &prometheus.AlreadyRegisteredError{})).Should(BeTrue()) }) }) - -var _ = Describe("PromUnaryServerInterceptor", func() { - It("Should return a unary server interceptor", func() { - validationHandler := func(ctx context.Context, req interface{}) (interface{}, error) { - labels := GetExecLabelsFromContext(ctx) - - Expect(labels).ShouldNot(BeNil()) - Expect(labels[GRPCMethodKey]).Should(Equal("List")) - Expect(labels[GRPCServiceKey]).Should(Equal("infoblox.service.SampleService")) - - return nil, nil - } - - promUnaryServerInterceptor := PromUnaryServerInterceptor() - promUnaryServerInterceptor(context.Background(), struct{}{}, &grpc.UnaryServerInfo{ - FullMethod: "/infoblox.service.SampleService/List", - }, validationHandler) - }) -})