Skip to content

Include the contents of logs when postgres fails to start or initdb fails #84

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Feb 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion embedded_postgres.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,10 @@ func startPostgres(ep *EmbeddedPostgres) error {
postgresProcess.Stderr = ep.syncedLogger.file

if err := postgresProcess.Run(); err != nil {
return fmt.Errorf("could not start postgres using %s", postgresProcess.String())
_ = ep.syncedLogger.flush()
logContent, _ := readLogsOrTimeout(ep.syncedLogger.file)

return fmt.Errorf("could not start postgres using %s:\n%s", postgresProcess.String(), string(logContent))
}

return nil
Expand Down
3 changes: 2 additions & 1 deletion embedded_postgres_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,12 +226,13 @@ func Test_ErrorWhenCannotStartPostgresProcess(t *testing.T) {
}

database.initDatabase = func(binaryExtractLocation, runtimePath, dataLocation, username, password, locale string, logger *os.File) error {
_, _ = logger.Write([]byte("ah it did not work"))
return nil
}

err = database.Start()

assert.EqualError(t, err, fmt.Sprintf(`could not start postgres using %s/bin/pg_ctl start -w -D %s/data -o "-p 5432"`, extractPath, extractPath))
assert.EqualError(t, err, fmt.Sprintf("could not start postgres using %s/bin/pg_ctl start -w -D %s/data -o \"-p 5432\":\nah it did not work", extractPath, extractPath))
}

func Test_CustomConfig(t *testing.T) {
Expand Down
26 changes: 26 additions & 0 deletions logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package embeddedpostgres
import (
"fmt"
"io"
"io/ioutil"
"os"
"time"
)

type syncedLogger struct {
Expand Down Expand Up @@ -53,3 +55,27 @@ func (s *syncedLogger) flush() error {

return nil
}

func readLogsOrTimeout(logger *os.File) (logContent []byte, err error) {
logContent = []byte("logs could not be read")

logContentChan := make(chan []byte, 1)
errChan := make(chan error, 1)

go func() {
if actualLogContent, err := ioutil.ReadFile(logger.Name()); err == nil {
logContentChan <- actualLogContent
} else {
errChan <- err
}
}()

select {
case logContent = <-logContentChan:
case err = <-errChan:
case <-time.After(10 * time.Second):
err = fmt.Errorf("timed out waiting for logs")
}

return logContent, err
}
25 changes: 25 additions & 0 deletions logging_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package embeddedpostgres

import (
"fmt"
"io/ioutil"
"os"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

type customLogger struct {
Expand Down Expand Up @@ -56,3 +59,25 @@ func Test_SyncedLogger_NoErrorDuringFlush(t *testing.T) {

assert.Equal(t, "some logs\non a new line", string(logger.logLines))
}

func Test_readLogsOrTimeout(t *testing.T) {
logFile, err := ioutil.TempFile("", "prepare_database_test_log")
if err != nil {
panic(err)
}

logContent, err := readLogsOrTimeout(logFile)
assert.NoError(t, err)
assert.Equal(t, []byte(""), logContent)

_, _ = logFile.Write([]byte("and here are the logs!"))

logContent, err = readLogsOrTimeout(logFile)
assert.NoError(t, err)
assert.Equal(t, []byte("and here are the logs!"), logContent)

require.NoError(t, os.Remove(logFile.Name()))
logContent, err = readLogsOrTimeout(logFile)
assert.Equal(t, []byte("logs could not be read"), logContent)
assert.EqualError(t, err, fmt.Sprintf("open %s: no such file or directory", logFile.Name()))
}
6 changes: 5 additions & 1 deletion prepare_database.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,11 @@ func defaultInitDatabase(binaryExtractLocation, runtimePath, pgDataDir, username
postgresInitDBProcess.Stdout = logger

if err = postgresInitDBProcess.Run(); err != nil {
return fmt.Errorf("unable to init database using '%s': %w", postgresInitDBProcess.String(), err)
logContent, readLogsErr := readLogsOrTimeout(logger) // we want to preserve the original error
if readLogsErr != nil {
logContent = []byte(string(logContent) + " - " + readLogsErr.Error())
}
return fmt.Errorf("unable to init database using '%s': %w\n%s", postgresInitDBProcess.String(), err, string(logContent))
}

if err = os.Remove(passwordFile); err != nil {
Expand Down
15 changes: 14 additions & 1 deletion prepare_database_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package embeddedpostgres
import (
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
Expand All @@ -27,6 +28,11 @@ func Test_defaultInitDatabase_ErrorWhenCannotStartInitDBProcess(t *testing.T) {
panic(err)
}

logFile, err := ioutil.TempFile("", "prepare_database_test_log")
if err != nil {
panic(err)
}

defer func() {
if err := os.RemoveAll(binTempDir); err != nil {
panic(err)
Expand All @@ -35,15 +41,22 @@ func Test_defaultInitDatabase_ErrorWhenCannotStartInitDBProcess(t *testing.T) {
if err := os.RemoveAll(runtimeTempDir); err != nil {
panic(err)
}

if err := os.Remove(logFile.Name()); err != nil {
panic(err)
}
}()

err = defaultInitDatabase(binTempDir, runtimeTempDir, filepath.Join(runtimeTempDir, "data"), "Tom", "Beer", "", os.Stderr)
_, _ = logFile.Write([]byte("and here are the logs!"))

err = defaultInitDatabase(binTempDir, runtimeTempDir, filepath.Join(runtimeTempDir, "data"), "Tom", "Beer", "", logFile)

assert.NotNil(t, err)
assert.Contains(t, err.Error(), fmt.Sprintf("unable to init database using '%s/bin/initdb -A password -U Tom -D %s/data --pwfile=%s/pwfile'",
binTempDir,
runtimeTempDir,
runtimeTempDir))
assert.Contains(t, err.Error(), "and here are the logs!")
assert.FileExists(t, filepath.Join(runtimeTempDir, "pwfile"))
}

Expand Down