Skip to content

Commit

Permalink
Feat : resolved review comments (#42)
Browse files Browse the repository at this point in the history
resolved review comments
  • Loading branch information
tharun0064 authored Jan 15, 2025
1 parent 28483e3 commit 948764b
Show file tree
Hide file tree
Showing 21 changed files with 766 additions and 70 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ require (
github.com/blang/semver/v4 v4.0.0
github.com/jmoiron/sqlx v1.4.0
github.com/lib/pq v1.10.9
github.com/mitchellh/mapstructure v1.5.0
github.com/newrelic/infra-integrations-sdk/v3 v3.9.1
github.com/stretchr/testify v1.10.0
github.com/xeipuuv/gojsonschema v1.2.0
gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0
gopkg.in/yaml.v3 v3.0.1
github.com/go-viper/mapstructure/v2 v2.2.1
)

require (
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ 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=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
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/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
Expand All @@ -18,8 +20,6 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/newrelic/infra-integrations-sdk/v3 v3.9.1 h1:dCtVLsYNHWTQ5aAlAaHroomOUlqxlGTrdi6XTlvBDfI=
github.com/newrelic/infra-integrations-sdk/v3 v3.9.1/go.mod h1:yPeidhcq9Cla0QDquGXH0KqvS2k9xtetFOD7aLA0Z8M=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package commonutils_test

import (
"sort"
"testing"
"time"

"github.com/newrelic/nri-postgresql/src/collection"
commonutils "github.com/newrelic/nri-postgresql/src/query-performance-monitoring/common-utils"
"github.com/stretchr/testify/assert"
)

func TestGetQuotedStringFromArray(t *testing.T) {
input := []string{"db1", "db2", "db3"}
expected := "'db1','db2','db3'"
result := commonutils.GetQuotedStringFromArray(input)
assert.Equal(t, expected, result)
}

func TestGetDatabaseListInString(t *testing.T) {
dbListKeys := []string{"db1", "db2"}
sort.Strings(dbListKeys) // Sort the keys to ensure consistent order
dbList := collection.DatabaseList{}
for _, key := range dbListKeys {
dbList[key] = collection.SchemaList{}
}
expected := "'db1','db2'"
result := commonutils.GetDatabaseListInString(dbList)
assert.Equal(t, expected, result)

// Test with empty database list
dbList = collection.DatabaseList{}
expected = ""
result = commonutils.GetDatabaseListInString(dbList)
assert.Equal(t, expected, result)
}

func TestAnonymizeQueryText(t *testing.T) {
query := "SELECT * FROM users WHERE id = 1 AND name = 'John'"
expected := "SELECT * FROM users WHERE id = ? AND name = ?"
result := commonutils.AnonymizeQueryText(query)
assert.Equal(t, expected, result)
}

func TestGeneratePlanID(t *testing.T) {
queryID := "query123"
result := commonutils.GeneratePlanID(queryID)
assert.NotNil(t, result)
assert.Contains(t, *result, queryID)
assert.Contains(t, *result, "-")
assert.Contains(t, *result, time.Now().Format(commonutils.TimeFormat)[:8]) // Check date part
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import (
"github.com/newrelic/nri-postgresql/src/collection"
)

func getQuotedStringFromArray(array []string) string {
var re = regexp.MustCompile(`'[^']*'|\d+|".*?"`)

func GetQuotedStringFromArray(array []string) string {
var quotedNames = make([]string, 0)
for _, name := range array {
quotedNames = append(quotedNames, fmt.Sprintf("'%s'", name))
Expand All @@ -27,11 +29,10 @@ func GetDatabaseListInString(dbList collection.DatabaseList) string {
if len(databaseNames) == 0 {
return ""
}
return getQuotedStringFromArray(databaseNames)
return GetQuotedStringFromArray(databaseNames)
}

func AnonymizeQueryText(query string) string {
re := regexp.MustCompile(`'[^']*'|\d+|".*?"`)
anonymizedQuery := re.ReplaceAllString(query, "?")
return anonymizedQuery
}
Expand Down
4 changes: 4 additions & 0 deletions src/query-performance-monitoring/common-utils/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@ const VersionRegex = "PostgreSQL (\\d+)\\."

var ErrParseVersion = errors.New("unable to parse PostgreSQL version from string")
var ErrUnsupportedVersion = errors.New("unsupported PostgreSQL version")
var ErrUnExpectedError = errors.New("unexpected error")

var ErrVersionFetchError = errors.New("no rows returned from version query")
var ErrInvalidModelType = errors.New("invalid model type")
var ErrNotEligible = errors.New("not Eligible to fetch metrics")

const PostgresVersion12 = 12
const PostgresVersion11 = 11
const PostgresVersion13 = 13
const PostgresVersion14 = 14
const VersionIndex = 2
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package commonutils_test

import (
"testing"

"github.com/newrelic/infra-integrations-sdk/v3/integration"
"github.com/newrelic/nri-postgresql/src/args"
commonutils "github.com/newrelic/nri-postgresql/src/query-performance-monitoring/common-utils"
"github.com/stretchr/testify/assert"
)

func TestSetMetric(t *testing.T) {
pgIntegration, _ := integration.New("test", "1.0.0")
entity, _ := pgIntegration.Entity("test-entity", "test-type")

metricSet := entity.NewMetricSet("test-event")

commonutils.SetMetric(metricSet, "testGauge", 123.0, "gauge")
assert.Equal(t, 123.0, metricSet.Metrics["testGauge"])

commonutils.SetMetric(metricSet, "testAttribute", "value", "attribute")
assert.Equal(t, "value", metricSet.Metrics["testAttribute"])

commonutils.SetMetric(metricSet, "testDefault", 456.0, "unknown")
assert.Equal(t, 456.0, metricSet.Metrics["testDefault"])
}

func TestIngestMetric(t *testing.T) {
pgIntegration, _ := integration.New("test", "1.0.0")
args := args.ArgumentList{
Hostname: "localhost",
Port: "5432",
}
metricList := []interface{}{
struct {
TestField int `metric_name:"testField" source_type:"gauge"`
}{TestField: 123},
}

commonutils.IngestMetric(metricList, "testEvent", pgIntegration, args)
assert.NotEmpty(t, pgIntegration.Entities)
}

func TestCreateEntity(t *testing.T) {
pgIntegration, _ := integration.New("test", "1.0.0")
args := args.ArgumentList{
Hostname: "localhost",
Port: "5432",
}

entity, err := commonutils.CreateEntity(pgIntegration, args)
assert.NoError(t, err)
assert.NotNil(t, entity)
assert.Equal(t, "localhost:5432", entity.Metadata.Name)
}

func TestProcessModel(t *testing.T) {
pgIntegration, _ := integration.New("test", "1.0.0")
entity, _ := pgIntegration.Entity("test-entity", "test-type")

metricSet := entity.NewMetricSet("test-event")

model := struct {
TestField int `metric_name:"testField" source_type:"gauge"`
}{TestField: 123}

err := commonutils.ProcessModel(model, metricSet)
assert.NoError(t, err)
assert.Equal(t, 123.0, metricSet.Metrics["testField"])
}

func TestPublishMetrics(t *testing.T) {
pgIntegration, _ := integration.New("test", "1.0.0")
args := args.ArgumentList{
Hostname: "localhost",
Port: "5432",
}
entity, _ := commonutils.CreateEntity(pgIntegration, args)

err := commonutils.PublishMetrics(pgIntegration, &entity, args)
assert.NoError(t, err)
assert.NotNil(t, entity)
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func SetMetric(metricSet *metric.Set, name string, value interface{}, sourceType
}

func IngestMetric(metricList []interface{}, eventName string, pgIntegration *integration.Integration, args args.ArgumentList) {
instanceEntity, err := createEntity(pgIntegration, args)
instanceEntity, err := CreateEntity(pgIntegration, args)
if err != nil {
log.Error("Error creating entity: %v", err)
return
Expand All @@ -50,33 +50,33 @@ func IngestMetric(metricList []interface{}, eventName string, pgIntegration *int
metricCount += 1
metricSet := instanceEntity.NewMetricSet(eventName)

processErr := processModel(model, metricSet)
processErr := ProcessModel(model, metricSet)
if processErr != nil {
log.Error("Error processing model: %v", processErr)
continue
}

if metricCount == PublishThreshold || metricCount == lenOfMetricList {
metricCount = 0
if err := publishMetrics(pgIntegration, &instanceEntity, args); err != nil {
if err := PublishMetrics(pgIntegration, &instanceEntity, args); err != nil {
log.Error("Error publishing metrics: %v", err)
return
}
}
}
if metricCount > 0 {
if err := publishMetrics(pgIntegration, &instanceEntity, args); err != nil {
if err := PublishMetrics(pgIntegration, &instanceEntity, args); err != nil {
log.Error("Error publishing metrics: %v", err)
return
}
}
}

func createEntity(pgIntegration *integration.Integration, args args.ArgumentList) (*integration.Entity, error) {
func CreateEntity(pgIntegration *integration.Integration, args args.ArgumentList) (*integration.Entity, error) {
return pgIntegration.Entity(fmt.Sprintf("%s:%s", args.Hostname, args.Port), "pg-instance")
}

func processModel(model interface{}, metricSet *metric.Set) error {
func ProcessModel(model interface{}, metricSet *metric.Set) error {
modelValue := reflect.ValueOf(model)
if modelValue.Kind() == reflect.Ptr {
modelValue = modelValue.Elem()
Expand Down Expand Up @@ -108,7 +108,7 @@ func processModel(model interface{}, metricSet *metric.Set) error {
return nil
}

func publishMetrics(pgIntegration *integration.Integration, instanceEntity **integration.Entity, args args.ArgumentList) error {
func PublishMetrics(pgIntegration *integration.Integration, instanceEntity **integration.Entity, args args.ArgumentList) error {
if err := pgIntegration.Publish(); err != nil {
return err
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package commonutils_test

import (
"testing"

commonutils "github.com/newrelic/nri-postgresql/src/query-performance-monitoring/common-utils"

"github.com/newrelic/nri-postgresql/src/query-performance-monitoring/queries"
"github.com/stretchr/testify/assert"
)

func runTestCases(t *testing.T, tests []struct {
version uint64
expected string
expectErr bool
}, fetchFunc func(uint64) (string, error)) {
for _, test := range tests {
result, err := fetchFunc(test.version)
if test.expectErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, test.expected, result)
}
}
}

func TestFetchVersionSpecificSlowQueries(t *testing.T) {
tests := []struct {
version uint64
expected string
expectErr bool
}{
{commonutils.PostgresVersion12, queries.SlowQueriesForV12, false},
{commonutils.PostgresVersion13, queries.SlowQueriesForV13AndAbove, false},
{commonutils.PostgresVersion11, "", true},
}

runTestCases(t, tests, commonutils.FetchVersionSpecificSlowQueries)
}

func TestFetchVersionSpecificBlockingQueries(t *testing.T) {
tests := []struct {
version uint64
expected string
expectErr bool
}{
{commonutils.PostgresVersion12, queries.BlockingQueriesForV12AndV13, false},
{commonutils.PostgresVersion13, queries.BlockingQueriesForV12AndV13, false},
{commonutils.PostgresVersion14, queries.BlockingQueriesForV14AndAbove, false},
{commonutils.PostgresVersion11, "", true},
}

runTestCases(t, tests, commonutils.FetchVersionSpecificBlockingQueries)
}

func TestFetchVersionSpecificIndividualQueries(t *testing.T) {
tests := []struct {
version uint64
expected string
expectErr bool
}{
{commonutils.PostgresVersion12, queries.IndividualQuerySearchV12, false},
{commonutils.PostgresVersion13, queries.IndividualQuerySearchV13AndAbove, false},
{commonutils.PostgresVersion14, queries.IndividualQuerySearchV13AndAbove, false},
{commonutils.PostgresVersion11, "", true},
}

runTestCases(t, tests, commonutils.FetchVersionSpecificIndividualQueries)
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,27 @@ import (
"github.com/newrelic/nri-postgresql/src/query-performance-monitoring/datamodels"
)

func PopulateBlockingMetrics(conn *performancedbconnection.PGSQLConnection, pgIntegration *integration.Integration, args args.ArgumentList, databaseName string, version uint64) {
isPgStatStatementEnabled, enableCheckError := validations.CheckBlockingSessionMetricsFetchEligibility(conn, version)
func PopulateBlockingMetrics(conn *performancedbconnection.PGSQLConnection, pgIntegration *integration.Integration, args args.ArgumentList, databaseName string, version uint64) error {
isEligible, enableCheckError := validations.CheckBlockingSessionMetricsFetchEligibility(conn, version)
if enableCheckError != nil {
log.Debug("Error executing query: %v in PopulateBlockingMetrics", enableCheckError)
return
return commonutils.ErrUnExpectedError
}
if !isPgStatStatementEnabled {
log.Debug("Extension 'pg_stat_statements' is not enabled for the database.")
return
if !isEligible {
log.Debug("Extension 'pg_stat_statements' is not enabled or unsupported version.")
return commonutils.ErrNotEligible
}
blockingQueriesMetricsList, blockQueryFetchErr := GetBlockingMetrics(conn, args, databaseName, version)
if blockQueryFetchErr != nil {
log.Error("Error fetching Blocking queries: %v", blockQueryFetchErr)
return
return commonutils.ErrUnExpectedError
}
if len(blockingQueriesMetricsList) == 0 {
log.Debug("No Blocking queries found.")
return
return nil
}
commonutils.IngestMetric(blockingQueriesMetricsList, "PostgresBlockingSessions", pgIntegration, args)
return nil
}

func GetBlockingMetrics(conn *performancedbconnection.PGSQLConnection, args args.ArgumentList, databaseName string, version uint64) ([]interface{}, error) {
Expand Down
Loading

0 comments on commit 948764b

Please sign in to comment.