github.com/PDOK/gokoala@v0.50.6/internal/ogc/features/datasources/sqllog.go (about)

     1  package datasources
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"log"
     7  	"os"
     8  	"strconv"
     9  	"strings"
    10  	"time"
    11  )
    12  
    13  type contextKey int
    14  
    15  const (
    16  	envLogSQL                       = "LOG_SQL"
    17  	envSlowQueryTime                = "SLOW_QUERY_TIME"
    18  	defaultSlowQueryTime            = 5 * time.Second
    19  	sqlContextKey        contextKey = iota
    20  )
    21  
    22  // SQLLog query logging for debugging purposes
    23  type SQLLog struct {
    24  	LogSQL        bool
    25  	SlowQueryTime time.Duration
    26  }
    27  
    28  // NewSQLLogFromEnv build a SQLLog from environment variables listed in this file
    29  func NewSQLLogFromEnv() *SQLLog {
    30  	var err error
    31  	logSQL := false
    32  	if os.Getenv(envLogSQL) != "" {
    33  		logSQL, err = strconv.ParseBool(os.Getenv(envLogSQL))
    34  		if err != nil {
    35  			log.Fatalf("invalid %s value provided, must be a boolean", envLogSQL)
    36  		}
    37  	}
    38  	slowQueryTime := defaultSlowQueryTime
    39  	if os.Getenv(envSlowQueryTime) != "" {
    40  		slowQueryTime, err = time.ParseDuration(os.Getenv(envSlowQueryTime))
    41  		if err != nil {
    42  			log.Fatalf("invalid %s value provided, value such as '5s' expected", envSlowQueryTime)
    43  		}
    44  	}
    45  	return &SQLLog{LogSQL: logSQL, SlowQueryTime: slowQueryTime}
    46  }
    47  
    48  // Before callback prior to execution of the given SQL query
    49  func (s *SQLLog) Before(ctx context.Context, _ string, _ ...any) (context.Context, error) {
    50  	return context.WithValue(ctx, sqlContextKey, time.Now()), nil
    51  }
    52  
    53  // After callback once execution of the given SQL query is done
    54  func (s *SQLLog) After(ctx context.Context, query string, args ...any) (context.Context, error) {
    55  	start := ctx.Value(sqlContextKey).(time.Time)
    56  	timeSpent := time.Since(start)
    57  	if timeSpent > s.SlowQueryTime || s.LogSQL {
    58  		query = replaceBindVars(query, args)
    59  		log.Printf("\n--- SQL:\n%s\n--- SQL query took: %s\n", query, timeSpent)
    60  	}
    61  	return ctx, nil
    62  }
    63  
    64  // replaceBindVars replaces '?' bind vars in order to log a complete query
    65  func replaceBindVars(query string, args []any) string {
    66  	for _, arg := range args {
    67  		query = strings.Replace(query, "?", fmt.Sprintf("%v", arg), 1)
    68  	}
    69  	return query
    70  }