-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(query-performance-monitoring): Implement query performance monit…
…oring (#189) feat(query-performance-monitoring): Implement query performance monitoring
- Loading branch information
1 parent
d7cc25a
commit daf69cc
Showing
52 changed files
with
3,337 additions
and
140 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
55 changes: 55 additions & 0 deletions
55
src/query-performance-monitoring/common-parameters/common_parameters.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package commonparameters | ||
|
||
import ( | ||
"github.com/newrelic/infra-integrations-sdk/v3/log" | ||
"github.com/newrelic/nri-postgresql/src/args" | ||
) | ||
|
||
// The maximum number records that can be fetched in a single metrics | ||
const MaxQueryCountThreshold = 30 | ||
|
||
// DefaultQueryMonitoringCountThreshold is the default threshold for the number of queries to monitor. | ||
const DefaultQueryMonitoringCountThreshold = 20 | ||
|
||
// DefaultQueryResponseTimeThreshold is the default threshold for the response time of a query. | ||
const DefaultQueryResponseTimeThreshold = 500 | ||
|
||
type CommonParameters struct { | ||
Version uint64 | ||
Databases string | ||
QueryMonitoringCountThreshold int | ||
QueryMonitoringResponseTimeThreshold int | ||
Host string | ||
Port string | ||
} | ||
|
||
func SetCommonParameters(args args.ArgumentList, version uint64, databases string) *CommonParameters { | ||
return &CommonParameters{ | ||
Version: version, | ||
Databases: databases, // comma separated database names | ||
QueryMonitoringCountThreshold: validateAndGetQueryMonitoringCountThreshold(args), | ||
QueryMonitoringResponseTimeThreshold: validateAndGetQueryMonitoringResponseTimeThreshold(args), | ||
Host: args.Hostname, | ||
Port: args.Port, | ||
} | ||
} | ||
|
||
func validateAndGetQueryMonitoringResponseTimeThreshold(args args.ArgumentList) int { | ||
if args.QueryMonitoringResponseTimeThreshold < 0 { | ||
log.Warn("QueryResponseTimeThreshold should be greater than or equal to 0 but the input is %d, setting value to default which is %d", args.QueryMonitoringResponseTimeThreshold, DefaultQueryResponseTimeThreshold) | ||
return DefaultQueryResponseTimeThreshold | ||
} | ||
return args.QueryMonitoringResponseTimeThreshold | ||
} | ||
|
||
func validateAndGetQueryMonitoringCountThreshold(args args.ArgumentList) int { | ||
if args.QueryMonitoringCountThreshold < 0 { | ||
log.Warn("QueryCountThreshold should be greater than 0 but the input is %d, setting value to default which is %d", args.QueryMonitoringCountThreshold, DefaultQueryMonitoringCountThreshold) | ||
return DefaultQueryMonitoringCountThreshold | ||
} | ||
if args.QueryMonitoringCountThreshold > MaxQueryCountThreshold { | ||
log.Warn("QueryCountThreshold should be less than or equal to max limit but the input is %d, setting value to max limit which is %d", args.QueryMonitoringCountThreshold, MaxQueryCountThreshold) | ||
return MaxQueryCountThreshold | ||
} | ||
return args.QueryMonitoringCountThreshold | ||
} |
42 changes: 42 additions & 0 deletions
42
src/query-performance-monitoring/common-utils/common_helpers.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package commonutils | ||
|
||
import ( | ||
"crypto/rand" | ||
"fmt" | ||
"math/big" | ||
"regexp" | ||
"strings" | ||
"time" | ||
|
||
"github.com/newrelic/nri-postgresql/src/collection" | ||
) | ||
|
||
// re is a regular expression that matches single-quoted strings, numbers, or double-quoted strings | ||
var re = regexp.MustCompile(`'[^']*'|\d+|".*?"`) | ||
|
||
func GetDatabaseListInString(dbMap collection.DatabaseList) string { | ||
if len(dbMap) == 0 { | ||
return "" | ||
} | ||
var quotedNames = make([]string, 0) | ||
for dbName := range dbMap { | ||
quotedNames = append(quotedNames, fmt.Sprintf("'%s'", dbName)) | ||
} | ||
return strings.Join(quotedNames, ",") | ||
} | ||
|
||
func AnonymizeQueryText(query string) string { | ||
anonymizedQuery := re.ReplaceAllString(query, "?") | ||
return anonymizedQuery | ||
} | ||
|
||
// This function is used to generate a unique plan ID for a query | ||
func GeneratePlanID() (string, error) { | ||
randomInt, err := rand.Int(rand.Reader, big.NewInt(RandomIntRange)) | ||
if err != nil { | ||
return "", ErrUnExpectedError | ||
} | ||
currentTime := time.Now().Format(TimeFormat) | ||
result := fmt.Sprintf("%d-%s", randomInt.Int64(), currentTime) | ||
return result, nil | ||
} |
38 changes: 38 additions & 0 deletions
38
src/query-performance-monitoring/common-utils/common_helpers_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package commonutils | ||
|
||
import ( | ||
"sort" | ||
"testing" | ||
|
||
"github.com/newrelic/nri-postgresql/src/collection" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestGetDatabaseListInString(t *testing.T) { | ||
dbListKeys := []string{"db1"} | ||
sort.Strings(dbListKeys) // Sort the keys to ensure consistent order | ||
dbList := collection.DatabaseList{} | ||
for _, key := range dbListKeys { | ||
dbList[key] = collection.SchemaList{} | ||
} | ||
expected := "'db1'" | ||
result := GetDatabaseListInString(dbList) | ||
assert.Equal(t, expected, result) | ||
|
||
// Test with empty database list | ||
dbList = collection.DatabaseList{} | ||
expected = "" | ||
result = 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 := AnonymizeQueryText(query) | ||
assert.Equal(t, expected, result) | ||
query = "SELECT * FROM employees WHERE id = 10 OR name <> 'John Doe' OR name != 'John Doe' OR age < 30 OR age <= 30 OR salary > 50000OR salary >= 50000 OR department LIKE 'Sales%' OR department ILIKE 'sales%'OR join_date BETWEEN '2023-01-01' AND '2023-12-31' OR department IN ('HR', 'Engineering', 'Marketing') OR department IS NOT NULL OR department IS NULL;" | ||
expected = "SELECT * FROM employees WHERE id = ? OR name <> ? OR name != ? OR age < ? OR age <= ? OR salary > ?OR salary >= ? OR department LIKE ? OR department ILIKE ?OR join_date BETWEEN ? AND ? OR department IN (?, ?, ?) OR department IS NOT NULL OR department IS NULL;" | ||
result = AnonymizeQueryText(query) | ||
assert.Equal(t, expected, result) | ||
} |
Oops, something went wrong.