Skip to content

Commit

Permalink
[pocketbase#3918] added --dev flag, dev log printer and some minor lo…
Browse files Browse the repository at this point in the history
…g UI enhacements
  • Loading branch information
ganigeorgiev committed Dec 16, 2023
1 parent bf5eba0 commit 5c961f8
Show file tree
Hide file tree
Showing 43 changed files with 7,796 additions and 7,436 deletions.
19 changes: 13 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
## v0.20.1-WIP

- Removed the blank current time entry from the logs chart as it was causing confusion when used with custom time ranges.

- Removed the default Go API tests timeout and added a new`ApiScenario.Timeout` option ([#3930](https://github.com/pocketbase/pocketbase/issues/3930)).
- Added `--dev` flag and its accompanying `app.IsDev()` method (_in place of the previosly removed `--debug`_) to assist during development ([#3918](https://github.com/pocketbase/pocketbase/discussions/3918)).
The `--dev` flag prints in the console "everything" and more specifically:
- the data DB SQL statements
- all `app.Logger().*` logs (debug, info, warning, error, etc.), no matter of the logs persistence settings in the Admin UI

- Minor Admin UI fixes:
- Fixed the log `error` label text wrapping.
- Added the log `referer` (_when it is from a different source_) and `details` labels in the logs listing.
- Removed the blank current time entry from the logs chart because it was causing confusion when used with custom time ranges.
- Updated the SQL syntax highligher and keywords autocompletion in the Admin UI to recognize `CAST(x as bool)` expressions.

- Replaced the default API tests timeout with a new `ApiScenario.Timeout` option ([#3930](https://github.com/pocketbase/pocketbase/issues/3930)).
A negative or zero value means no tests timeout.
If a single API test takes more than 3s to complete it will have a log message visible when the test fails or when [`go test -v`] flag is used.

- Updated the SQL syntax highligher and keywords autocompletion in the Admin UI to recognize `CAST(x as bool)` expressions.
If a single API test takes more than 3s to complete it will have a log message visible when the test fails or when `go test -v` flag is used.


## v0.20.0
Expand Down
14 changes: 11 additions & 3 deletions apis/middlewares.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"log/slog"
"net"
"net/http"
"net/url"
"strings"
"time"

Expand Down Expand Up @@ -315,7 +316,7 @@ func logRequest(app core.App, c echo.Context, err *ApiError) {
httpResponse := c.Response()
method := strings.ToUpper(httpRequest.Method)
status := httpResponse.Status
url := httpRequest.URL.RequestURI()
requestUri := httpRequest.URL.RequestURI()

// parse the request error
if err != nil {
Expand All @@ -336,7 +337,7 @@ func logRequest(app core.App, c echo.Context, err *ApiError) {

attrs = append(
attrs,
slog.String("url", url),
slog.String("url", requestUri),
slog.String("method", method),
slog.Int("status", status),
slog.String("auth", requestAuth),
Expand All @@ -355,7 +356,14 @@ func logRequest(app core.App, c echo.Context, err *ApiError) {

// don't block on logs write
routine.FireAndForget(func() {
message := method + " " + url
message := method + " "

if escaped, err := url.PathUnescape(requestUri); err == nil {
message += escaped
} else {
message += requestUri
}

if err != nil {
app.Logger().Error(message, attrs...)
} else {
Expand Down
3 changes: 3 additions & 0 deletions core/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ type App interface {
// (used for settings encryption).
EncryptionEnv() string

// IsDev returns whether the app is in dev mode.
IsDev() bool

// Settings returns the loaded app settings.
Settings() *settings.Settings

Expand Down
61 changes: 45 additions & 16 deletions core/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type BaseApp struct {
// @todo consider introducing a mutex to allow safe concurrent config changes during runtime

// configurable parameters
isDev bool
dataDir string
encryptionEnv string
dataMaxOpenConns int
Expand Down Expand Up @@ -174,6 +175,7 @@ type BaseApp struct {

// BaseAppConfig defines a BaseApp configuration option
type BaseAppConfig struct {
IsDev bool
DataDir string
EncryptionEnv string
DataMaxOpenConns int // default to 500
Expand All @@ -188,6 +190,7 @@ type BaseAppConfig struct {
// To initialize the app, you need to call `app.Bootstrap()`.
func NewBaseApp(config BaseAppConfig) *BaseApp {
app := &BaseApp{
isDev: config.IsDev,
dataDir: config.DataDir,
encryptionEnv: config.EncryptionEnv,
dataMaxOpenConns: config.DataMaxOpenConns,
Expand Down Expand Up @@ -458,6 +461,13 @@ func (app *BaseApp) EncryptionEnv() string {
return app.encryptionEnv
}

// IsDev returns whether the app is in dev mode.
//
// When enabled logs, executed sql statements, etc. are printed to the stderr.
func (app *BaseApp) IsDev() bool {
return app.isDev
}

// Settings returns the loaded app settings.
func (app *BaseApp) Settings() *settings.Settings {
return app.settings
Expand Down Expand Up @@ -589,9 +599,11 @@ func (app *BaseApp) RefreshSettings() error {
return err
}

// reload handler level (if initialized)
if h, ok := app.Logger().Handler().(*logger.BatchHandler); ok {
h.SetLevel(slog.Level(app.settings.Logs.MinLevel))
// reload handler level (if initialized and not in dev mode)
if !app.IsDev() && app.Logger() != nil {
if h, ok := app.Logger().Handler().(*logger.BatchHandler); ok {
h.SetLevel(slog.Level(app.settings.Logs.MinLevel))
}
}

return nil
Expand Down Expand Up @@ -1054,15 +1066,16 @@ func (app *BaseApp) initDataDB() error {
nonconcurrentDB.DB().SetMaxIdleConns(1)
nonconcurrentDB.DB().SetConnMaxIdleTime(3 * time.Minute)

// @todo benchmark whether it will have an impact if always enabled as TRACE log
// nonconcurrentDB.QueryLogFunc = func(ctx context.Context, t time.Duration, sql string, rows *sql.Rows, err error) {
// color.HiBlack("[%.2fms] %v\n", float64(t.Milliseconds()), sql)
// }
// concurrentDB.QueryLogFunc = nonconcurrentDB.QueryLogFunc
// nonconcurrentDB.ExecLogFunc = func(ctx context.Context, t time.Duration, sql string, result sql.Result, err error) {
// color.HiBlack("[%.2fms] %v\n", float64(t.Milliseconds()), sql)
// }
// concurrentDB.ExecLogFunc = nonconcurrentDB.ExecLogFunc
if app.IsDev() {
nonconcurrentDB.QueryLogFunc = func(ctx context.Context, t time.Duration, sql string, rows *sql.Rows, err error) {
color.HiBlack("[%.2fms] %v\n", float64(t.Milliseconds()), sql)
}
nonconcurrentDB.ExecLogFunc = func(ctx context.Context, t time.Duration, sql string, result sql.Result, err error) {
color.HiBlack("[%.2fms] %v\n", float64(t.Milliseconds()), sql)
}
concurrentDB.QueryLogFunc = nonconcurrentDB.QueryLogFunc
concurrentDB.ExecLogFunc = nonconcurrentDB.ExecLogFunc
}

app.dao = app.createDaoWithHooks(concurrentDB, nonconcurrentDB)

Expand Down Expand Up @@ -1176,15 +1189,31 @@ func (app *BaseApp) initLogger() error {
ticker := time.NewTicker(duration)
done := make(chan bool)

level := slog.LevelInfo
if app.Settings() != nil {
level = slog.Level(app.Settings().Logs.MinLevel)
// Apply the min level only if it is not in develop
// to allow printing the logs to the console.
//
// DB logs are still filtered but the checks for the min level are done
// in the BatchOptions.BeforeAddFunc instead of the slog.Handler.Enabled() method.
var minLevel slog.Level
if app.IsDev() {
minLevel = -9999
} else if app.Settings() != nil {
minLevel = slog.Level(app.Settings().Logs.MinLevel)
}

handler := logger.NewBatchHandler(logger.BatchOptions{
Level: level,
Level: minLevel,
BatchSize: 200,
BeforeAddFunc: func(ctx context.Context, log *logger.Log) bool {
if app.IsDev() {
printLog(log)

// manually check the log level and skip if necessary
if log.Level < slog.Level(app.Settings().Logs.MinLevel) {
return false
}
}

ticker.Reset(duration)

return app.Settings().Logs.MaxDays > 0
Expand Down
Loading

0 comments on commit 5c961f8

Please sign in to comment.