Skip to content

Commit

Permalink
Add "--generate-explain-analyze-helper-sql" command
Browse files Browse the repository at this point in the history
Like "--generate-stats-helper-sql" this allows generating a SQL script
that installs the pganalyze.explain_analyze helper into all databases on
a server, as specified by the server section name passed as an argument.

Additionally, the "--generate-helper-explain-analyze-role" option allows
setting the role that the helper function should be owned by as a value,
defaulting to "pganalyze_explain".

Note that the role creation, as well as any GRANT statements for the role
must be taken care of separately.
  • Loading branch information
lfittl committed Dec 27, 2024
1 parent c3faec6 commit c4de2a7
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 31 deletions.
52 changes: 29 additions & 23 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ func main() {
var testExplain bool
var testSection string
var generateStatsHelperSql string
var generateHelperExplainAnalyzeSql string
var generateHelperExplainAnalyzeRole string
var forceStateUpdate bool
var configFilename string
var stateFilename string
Expand All @@ -74,6 +76,8 @@ func main() {
flag.BoolVar(&testExplain, "test-explain", false, "Tests whether EXPLAIN collection works by issuing a dummy query (ensure log collection works first)")
flag.StringVar(&testSection, "test-section", "", "Tests a particular section of the config file, i.e. a specific server, and ignores all other config sections")
flag.StringVar(&generateStatsHelperSql, "generate-stats-helper-sql", "", "Generates a SQL script for the given server (name of section in the config file, or \"default\" for env variables), that can be run with \"psql -f\" for installing the collector stats helpers on all configured databases")
flag.StringVar(&generateHelperExplainAnalyzeSql, "generate-explain-analyze-helper-sql", "", "Generates a SQL script for the given server (name of section in the config file, or \"default\" for env variables), that can be run with \"psql -f\" for installing the collector pganalyze.explain_analyze helper on all configured databases")
flag.StringVar(&generateHelperExplainAnalyzeRole, "generate-explain-analyze-helper-role", "pganalyze_explain", "Sets owner role of the pganalyze.explain_analyze helper function, defaults to \"pganalyze_explain\"")
flag.BoolVar(&reloadRun, "reload", false, "Reloads the collector daemon that's running on the host")
flag.BoolVar(&noReload, "no-reload", false, "Disables automatic config reloading during a test run")
flag.BoolVarP(&logger.Verbose, "verbose", "v", false, "Outputs additional debugging information, use this if you're encountering errors or other problems")
Expand Down Expand Up @@ -145,33 +149,35 @@ func main() {
}
}

if testRunLogs || testRunAndTrace || testExplain || generateStatsHelperSql != "" {
if testRunLogs || testRunAndTrace || testExplain || generateStatsHelperSql != "" || generateHelperExplainAnalyzeSql != "" {
testRun = true
}

globalCollectionOpts := state.CollectionOpts{
StartedAt: time.Now(),
SubmitCollectedData: !benchmark && true,
TestRun: testRun,
TestRunLogs: testRunLogs || dryRunLogs,
TestExplain: testExplain,
TestSection: testSection,
GenerateStatsHelperSql: generateStatsHelperSql,
DebugLogs: debugLogs,
DiscoverLogLocation: discoverLogLocation,
CollectPostgresRelations: !noPostgresRelations,
CollectPostgresSettings: !noPostgresSettings,
CollectPostgresLocks: !noPostgresLocks,
CollectPostgresFunctions: !noPostgresFunctions,
CollectPostgresBloat: !noPostgresBloat,
CollectPostgresViews: !noPostgresViews,
CollectLogs: !noLogs,
CollectExplain: !noExplain,
CollectSystemInformation: !noSystemInformation,
StateFilename: stateFilename,
WriteStateUpdate: (!dryRun && !dryRunLogs && !testRun) || forceStateUpdate,
ForceEmptyGrant: dryRun || dryRunLogs || testRunLogs || benchmark,
OutputAsJson: !benchmark,
StartedAt: time.Now(),
SubmitCollectedData: !benchmark && true,
TestRun: testRun,
TestRunLogs: testRunLogs || dryRunLogs,
TestExplain: testExplain,
TestSection: testSection,
GenerateStatsHelperSql: generateStatsHelperSql,
GenerateHelperExplainAnalyzeSql: generateHelperExplainAnalyzeSql,

Check failure on line 164 in main.go

View workflow job for this annotation

GitHub Actions / build

unknown field GenerateHelperExplainAnalyzeSql in struct literal of type "github.com/pganalyze/collector/state".CollectionOpts
GenerateHelperExplainAnalyzeRole: generateHelperExplainAnalyzeRole,

Check failure on line 165 in main.go

View workflow job for this annotation

GitHub Actions / build

unknown field GenerateHelperExplainAnalyzeRole in struct literal of type "github.com/pganalyze/collector/state".CollectionOpts
DebugLogs: debugLogs,
DiscoverLogLocation: discoverLogLocation,
CollectPostgresRelations: !noPostgresRelations,
CollectPostgresSettings: !noPostgresSettings,
CollectPostgresLocks: !noPostgresLocks,
CollectPostgresFunctions: !noPostgresFunctions,
CollectPostgresBloat: !noPostgresBloat,
CollectPostgresViews: !noPostgresViews,
CollectLogs: !noLogs,
CollectExplain: !noExplain,
CollectSystemInformation: !noSystemInformation,
StateFilename: stateFilename,
WriteStateUpdate: (!dryRun && !dryRunLogs && !testRun) || forceStateUpdate,
ForceEmptyGrant: dryRun || dryRunLogs || testRunLogs || benchmark,
OutputAsJson: !benchmark,
}

if reloadRun && !testRun {
Expand Down
33 changes: 33 additions & 0 deletions runner/generate_helper_sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,36 @@ func GenerateStatsHelperSql(ctx context.Context, server *state.Server, globalCol

return output.String(), nil
}

func GenerateExplainAnalyzeHelperSql(ctx context.Context, server *state.Server, globalCollectionOpts state.CollectionOpts, logger *util.Logger) (string, error) {
db, err := postgres.EstablishConnection(ctx, server, logger, globalCollectionOpts, "")
if err != nil {
return "", err
}
defer db.Close()

version, err := postgres.GetPostgresVersion(ctx, logger, db)
if err != nil {
return "", fmt.Errorf("error collecting Postgres version: %s", err)
}

databases, _, err := postgres.GetDatabases(ctx, logger, db, version)
if err != nil {
return "", fmt.Errorf("error collecting pg_databases: %s", err)
}

output := strings.Builder{}
for _, dbName := range postgres.GetDatabasesToCollect(server, databases) {
output.WriteString(fmt.Sprintf("\\c %s\n", pq.QuoteIdentifier(dbName)))
output.WriteString("CREATE SCHEMA IF NOT EXISTS pganalyze;\n")
output.WriteString(fmt.Sprintf("GRANT USAGE ON SCHEMA pganalyze TO %s;\n", server.Config.GetDbUsername()))
output.WriteString(fmt.Sprintf("GRANT CREATE ON SCHEMA pganalyze TO %s;\n", globalCollectionOpts.GenerateExplainAnalyzeHelperRole))
output.WriteString(fmt.Sprintf("SET ROLE %s;\n", globalCollectionOpts.GenerateExplainAnalyzeHelperRole))
output.WriteString(util.ExplainAnalyzeHelper + "\n")
output.WriteString("RESET ROLE;\n")
output.WriteString(fmt.Sprintf("REVOKE CREATE ON SCHEMA pganalyze FROM %s;\n", globalCollectionOpts.GenerateExplainAnalyzeHelperRole))
output.WriteString("\n")
}

return output.String(), nil
}
28 changes: 28 additions & 0 deletions runner/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,34 @@ func Run(ctx context.Context, wg *sync.WaitGroup, globalCollectionOpts state.Col
return
}

if globalCollectionOpts.GenerateExplainAnalyzeHelperSql != "" {
wg.Add(1)
testRunSuccess = make(chan bool)
go func() {
var matchingServer *state.Server
for _, server := range servers {
if globalCollectionOpts.GenerateExplainAnalyzeHelperSql == server.Config.SectionName {
matchingServer = server
}
}
if matchingServer == nil {
fmt.Fprintf(os.Stderr, "ERROR - Specified configuration section name '%s' not known\n", globalCollectionOpts.GenerateExplainAnalyzeHelperSql)
testRunSuccess <- false
} else {
output, err := GenerateExplainAnalyzeHelperSql(ctx, matchingServer, globalCollectionOpts, logger.WithPrefix(matchingServer.Config.SectionName))
if err != nil {
fmt.Fprintf(os.Stderr, "ERROR - %s\n", err)
testRunSuccess <- false
} else {
fmt.Print(output)
testRunSuccess <- true
}
}
wg.Done()
}()
return
}

state.ReadStateFile(servers, globalCollectionOpts, logger)

writeStateFile = func() {
Expand Down
18 changes: 10 additions & 8 deletions state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,14 +213,16 @@ type CollectionOpts struct {

DiffStatements bool

SubmitCollectedData bool
TestRun bool
TestRunLogs bool
TestExplain bool
TestSection string
GenerateStatsHelperSql string
DebugLogs bool
DiscoverLogLocation bool
SubmitCollectedData bool
TestRun bool
TestRunLogs bool
TestExplain bool
TestSection string
GenerateStatsHelperSql string
GenerateExplainAnalyzeHelperSql string
GenerateExplainAnalyzeHelperRole string
DebugLogs bool
DiscoverLogLocation bool

StateFilename string
WriteStateUpdate bool
Expand Down

0 comments on commit c4de2a7

Please sign in to comment.