Commit 36b48124 authored by Carsten Orthbandt's avatar Carsten Orthbandt
Browse files

Warnings, logs

parent 437aa6dc
Showing with 62 additions and 42 deletions
+62 -42
......@@ -2,22 +2,18 @@ package pgxcrud
import (
"context"
"io"
"os"
"git.pixeltamer.net/gopub/logfunk"
"github.com/jackc/pgx/v4"
"github.com/jackc/pgx/v4/pgxpool"
)
// environment-only options
// OptLog instructs to use an existing connection pool.
func OptLog(output io.Writer) EnvOptData {
// OptLog sets a logfunk.
func OptLog(f logfunk.F) EnvOptData {
return EnvOptData{fnEnv: func(e *Env) {
if output == nil {
output = os.Stdout
}
e.logOutput = output
e.LogF = f
}}
}
......@@ -111,18 +107,14 @@ func OptRange(offset, limit int) OpOptData {
// OptFilter sets a sql filter and optional parameters
func OptFilter(filtersql string, queryParams ...interface{}) OpOptData {
pl := []interface{}{}
for _, p := range queryParams {
pl = append(pl, p)
}
pl = append(pl, queryParams...)
return OpOptData{fnOp: func(op *Op) { op.FilterSQL = filtersql; op.Params = pl }}
}
// OptQueryParams sets parameters for a query, appending to previously set ones
func OptQueryParams(queryParams ...interface{}) OpOptData {
pl := []interface{}{}
for _, p := range queryParams {
pl = append(pl, p)
}
pl = append(pl, queryParams...)
return OpOptData{fnOp: func(op *Op) { op.Params = append(op.Params, pl...) }}
}
......@@ -130,9 +122,11 @@ func OptQueryParams(queryParams ...interface{}) OpOptData {
// OptContext can be used for any option list and sets the context to use
func OptContext(ctx context.Context) OptAnywhere {
return OptAnywhere{EnvOptData{fnEnv: func(e *Env) { e.DefaultCtx = ctx }},
return OptAnywhere{
EnvOptData{fnEnv: func(e *Env) { e.DefaultCtx = ctx }},
TxOptData{fnTx: func(tx *Tx) { tx.Ctx = ctx }},
OpOptData{fnOp: func(op *Op) { op.Ctx = ctx }}}
OpOptData{fnOp: func(op *Op) { op.Ctx = ctx }},
}
}
// EnvOpt is the common interface for options applying to an Env
......
......@@ -4,13 +4,11 @@ import (
"context"
"crypto/md5"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"reflect"
"sort"
"sync"
"git.pixeltamer.net/gopub/logfunk"
"github.com/jackc/pgx/v4"
"github.com/jackc/pgx/v4/pgxpool"
)
......@@ -24,7 +22,8 @@ type Env struct {
AutoMigrate bool
DefaultCtx context.Context
TypeMap map[reflect.Type]TypeInfo
logOutput io.Writer
PGXLogger pgx.Logger
LogF logfunk.F
sqlLoggers []SQLStmtLog
lastErr error
opened bool
......@@ -34,7 +33,7 @@ type Env struct {
}
type pgxlogger struct {
env *Env
logF logfunk.F
}
const (
......@@ -50,17 +49,39 @@ const (
type SQLStmtLog func(env *Env, kind int, txid int, tx pgx.Tx, stmt string, params ...interface{})
func (pl *pgxlogger) Log(ctx context.Context, level pgx.LogLevel, msg string, data map[string]interface{}) {
if pl.env.logOutput == nil {
if pl.logF == nil {
return
}
logmap := make(map[string]interface{})
var ll logfunk.Level
switch level {
case pgx.LogLevelDebug:
ll = logfunk.Debug
case pgx.LogLevelInfo:
ll = logfunk.Info
case pgx.LogLevelWarn:
ll = logfunk.Warn
case pgx.LogLevelError:
ll = logfunk.Error
default:
ll = logfunk.Spam
}
if pl.logF.LogLevel() > ll {
return
}
kvs := []interface{}{}
kvs = append(kvs, ll)
for k, v := range data {
if k != "commandTag" && k != "pid" && k != "time" {
logmap[k] = v
kvs = append(kvs, logfunk.KV(k, v))
}
}
jd, _ := json.Marshal(logmap)
fmt.Fprintf(pl.env.logOutput, "[SQL] %v: %v %v\n", level.String(), msg, string(jd))
kvs = append(kvs, msg)
pl.logF(kvs...)
}
// MakePgxLogger creates a pgs.Logger compatible implementation translating into logfunk.F calls
func MakePgxLogger(lf logfunk.F) pgx.Logger {
return &pgxlogger{logF: lf}
}
// New creates a new Env instances using the given options
......@@ -72,12 +93,15 @@ func New(opts ...EnvOpt) *Env {
AutoMigrate: true,
nxttxmap: make(map[int]struct{}),
}
for _, o := range opts {
o.ApplyEnv(env)
}
env.PGXLogger = MakePgxLogger(env.LogF)
return env
}
// GlobalTypeHash calculates a non-crypto hash string identifying all registered types and their structure
func (env *Env) GlobalTypeHash() string {
type ti struct {
TypeName string
......@@ -97,7 +121,6 @@ func (env *Env) GlobalTypeHash() string {
// Open (optional) and prepare the database, including (optional) migrations
func (env *Env) Open() error {
logger := &pgxlogger{env: env}
var err error
if env.AutoConnect != "" {
poolCfg, err := pgxpool.ParseConfig(env.AutoConnect)
......@@ -107,7 +130,7 @@ func (env *Env) Open() error {
}
poolCfg.ConnConfig.LogLevel = pgx.LogLevelTrace
poolCfg.ConnConfig.LogLevel = pgx.LogLevelInfo
poolCfg.ConnConfig.Logger = logger
poolCfg.ConnConfig.Logger = env.PGXLogger
/*
poolCfg := pgxpool.Config{
ConnConfig: cfg,
......
......@@ -6,6 +6,7 @@ import (
"fmt"
"strings"
"git.pixeltamer.net/gopub/logfunk"
"github.com/jackc/pgtype"
"github.com/jackc/pgx/v4"
"github.com/pkg/errors"
......@@ -442,15 +443,14 @@ func (su *schemaUpdater) migrateTable(ti TypeInfo) (err error) {
}
}
if didChanges {
if su.env.logOutput != nil {
if su.env.LogF != nil {
stmt := fmt.Sprintf("comment on table "+ti.TableName+" is '%v'", sanitizeSQL(ti.FullName))
su.env.sqlLog(SQLStmtLogStmt, su.txid, su.tx, stmt)
su.tx.Exec(su.ctx, stmt)
if !tableExists {
fmt.Fprintf(su.env.logOutput, "Created table %v for crud type %v", ti.TableName, ti.FullName)
su.env.LogF(logfunk.Info, "Created table %v for crud type %v", ti.TableName, ti.FullName)
} else {
fmt.Fprintf(su.env.logOutput, "Updated table %v schema for crud type %v", ti.TableName, ti.FullName)
su.env.LogF(logfunk.Info, "Updated table %v schema for crud type %v", ti.TableName, ti.FullName)
}
}
}
......
......@@ -255,7 +255,7 @@ func (tx *Tx) Read(itmout interface{}, options ...OpOpt) error {
}
defer rows.Close()
rval := reflect.ValueOf(itmout).Elem()
for rows.Next() {
if rows.Next() {
params := []interface{}{}
for fidx, finfo := range tinfo.Fields {
_ = fidx
......@@ -496,6 +496,9 @@ func (tx *Tx) FilterIDs(sampleitm interface{}, options ...OpOpt) ([]UUID, error)
}
rtype = rtype.Elem()
tinfo, ok := tx.Env.TypeMap[rtype]
if !ok {
return nil, ErrInvalidType
}
stmt := tinfo.StmtFilterID
if ov.FilterSQL == "" {
if ov.SoftDelete {
......
......@@ -61,9 +61,8 @@ type Field struct {
// To simplify the construction custom statements, this is currently a 1:1 conversion
func GoName2SQLName(goname string) string {
ret := []rune{}
gorunes := []rune(goname)
// wasUC := true
for _, c := range gorunes {
for _, c := range goname {
/*
if unicode.IsUpper(c) {
if !wasUC {
......@@ -113,7 +112,7 @@ func (env *Env) RegType(valinst interface{}, options ...TypeOpt) error {
}
ti.ReflectType = rtype
if rtype.Kind() != reflect.Struct {
return fmt.Errorf("Not a struct: %v, %w", ti.FullName, ErrInvalidType)
return fmt.Errorf("not a struct: %v, %w", ti.FullName, ErrInvalidType)
}
var UUIDType reflect.Type
......@@ -121,7 +120,7 @@ func (env *Env) RegType(valinst interface{}, options ...TypeOpt) error {
{
tmp := UUID("")
UUIDType = reflect.TypeOf(tmp)
var fullTypeName = UUIDType.Name()
fullTypeName := UUIDType.Name()
if UUIDType.PkgPath() != "" {
fullTypeName = UUIDType.PkgPath() + "." + fullTypeName
}
......@@ -166,7 +165,7 @@ func (env *Env) RegType(valinst interface{}, options ...TypeOpt) error {
dbtag := fld.Tag.Get("db")
idx := append([]int{}, index...)
idx = append(idx, fld.Index...)
var fullTypeName = fld.Type.Name()
fullTypeName := fld.Type.Name()
if fld.Type.PkgPath() != "" {
fullTypeName = fld.Type.PkgPath() + "." + fullTypeName
}
......@@ -198,7 +197,7 @@ func (env *Env) RegType(valinst interface{}, options ...TypeOpt) error {
// fmt.Printf(" %v %v %v\n\n", fldpath, fld.Type, fld.Tag)
var e FieldEncoding
var w int
var ik IndexKind = IndexKindNone
ik := IndexKindNone
if haveopt("simple") {
ik = IndexKindSimple
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment