jackc / pgx

PostgreSQL driver and toolkit for Go

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Request for guidance on tracing and logging

templatedop opened this issue · comments

Hey!
With limited resources/knowledge I was trying to add tracer and logger to an application.
The intention is to trace queries and connections to find what's happening with application and database.
However, I was not able to trace/log anything.

I am sure I am missing something please guide.

Kindly guide or point towards resources which can be utilised to enable logger and tracer.

 
config, err := pgxpool.ParseConfig(dsn)
//added logger
m := pgxtrace.CompositeQueryTracer{
		Tracers: []pgx.QueryTracer{
			
			&tracelog.TraceLog{
				Logger:   pgxtrace.NewLogger(&CustomLogger{}),
				LogLevel: tracelog.LogLevelDebug,
			},
		},
	}

	config.ConnConfig.Tracer = &m


//customer logger which is attached above.
type CustomLogger struct{}

func (cl *CustomLogger) Log(args ...interface{}) {
	fmt.Println("Log method called")
	fmt.Println(args...)
}


// This is pgx trace package

package pgxtrace

import (
	"context"

	"github.com/jackc/pgx/v5"
)

var (
	_ pgx.QueryTracer    = (*CompositeQueryTracer)(nil)
	_ pgx.BatchTracer    = (*CompositeQueryTracer)(nil)
	_ pgx.ConnectTracer  = (*CompositeQueryTracer)(nil)
	_ pgx.PrepareTracer  = (*CompositeQueryTracer)(nil)
	_ pgx.CopyFromTracer = (*CompositeQueryTracer)(nil)
)
type CompositeQueryTracer struct {
	Tracers []pgx.QueryTracer
}
// CompositeQueryTracer represent a composite query tracer
//type CompositeQueryTracer []pgx.QueryTracer

// TraceConnectStart implements pgx.ConnectTracer.
func (t CompositeQueryTracer) TraceConnectStart(ctx context.Context, data pgx.TraceConnectStartData) context.Context {
	for _, item := range t.Tracers {
		if tracer, ok := item.(pgx.ConnectTracer); ok {
			ctx = tracer.TraceConnectStart(ctx, data)
		}
	}

	return ctx
}

// TraceConnectEnd implements pgx.ConnectTracer.
func (t CompositeQueryTracer) TraceConnectEnd(ctx context.Context, data pgx.TraceConnectEndData) {
	for _, item := range t.Tracers {
		if tracer, ok := item.(pgx.ConnectTracer); ok {
			tracer.TraceConnectEnd(ctx, data)
		}
	}
}

// TracePrepareStart implements pgx.PrepareTracer.
func (t CompositeQueryTracer) TracePrepareStart(ctx context.Context, conn *pgx.Conn, data pgx.TracePrepareStartData) context.Context {
	for _, item := range t.Tracers {
		if tracer, ok := item.(pgx.PrepareTracer); ok {
			ctx = tracer.TracePrepareStart(ctx, conn, data)
		}
	}

	return ctx
}

// TracePrepareEnd implements pgx.PrepareTracer.
func (t CompositeQueryTracer) TracePrepareEnd(ctx context.Context, conn *pgx.Conn, data pgx.TracePrepareEndData) {
	for _, item := range t.Tracers {
		if tracer, ok := item.(pgx.PrepareTracer); ok {
			tracer.TracePrepareEnd(ctx, conn, data)
		}
	}
}

// TraceQueryStart implements pgx.QueryTracer.
func (t CompositeQueryTracer) TraceQueryStart(ctx context.Context, conn *pgx.Conn, data pgx.TraceQueryStartData) context.Context {
	for _, tracer := range t.Tracers {
		ctx = tracer.TraceQueryStart(ctx, conn, data)
	}

	return ctx
}



// TraceQueryEnd implements pgx.QueryTracer.
func (t CompositeQueryTracer) TraceQueryEnd(ctx context.Context, conn *pgx.Conn, data pgx.TraceQueryEndData) {
	for _, tracer := range t.Tracers {
		tracer.TraceQueryEnd(ctx, conn, data)
	}
}

// TraceBatchStart implements pgx.BatchTracer.
func (t CompositeQueryTracer) TraceBatchStart(ctx context.Context, conn *pgx.Conn, data pgx.TraceBatchStartData) context.Context {
	for _, item := range t.Tracers {
		if tracer, ok := item.(pgx.BatchTracer); ok {
			ctx = tracer.TraceBatchStart(ctx, conn, data)
		}
	}

	return ctx
}

// TraceBatchQuery implements pgx.BatchTracer.
func (t CompositeQueryTracer) TraceBatchQuery(ctx context.Context, conn *pgx.Conn, data pgx.TraceBatchQueryData) {
	for _, item := range t.Tracers {
		if tracer, ok := item.(pgx.BatchTracer); ok {
			tracer.TraceBatchQuery(ctx, conn, data)
		}
	}
}

// TraceBatchEnd implements pgx.BatchTracer.
func (t CompositeQueryTracer) TraceBatchEnd(ctx context.Context, conn *pgx.Conn, data pgx.TraceBatchEndData) {
	for _, item := range t.Tracers {
		if tracer, ok := item.(pgx.BatchTracer); ok {
			tracer.TraceBatchEnd(ctx, conn, data)
		}
	}
}

// TraceCopyFromStart implements pgx.CopyFromTracer.
func (t CompositeQueryTracer) TraceCopyFromStart(ctx context.Context, conn *pgx.Conn, data pgx.TraceCopyFromStartData) context.Context {
	for _, item := range t.Tracers {
		if tracer, ok := item.(pgx.CopyFromTracer); ok {
			ctx = tracer.TraceCopyFromStart(ctx, conn, data)
		}
	}

	return ctx
}

// TraceCopyFromEnd implements pgx.CopyFromTracer.
func (t CompositeQueryTracer) TraceCopyFromEnd(ctx context.Context, conn *pgx.Conn, data pgx.TraceCopyFromEndData) {
	for _, item := range t.Tracers {
		if tracer, ok := item.(pgx.CopyFromTracer); ok {
			tracer.TraceCopyFromEnd(ctx, conn, data)
		}
	}
}




// Package testingadapter provides a logger that writes to a test or benchmark
// log.
package pgxtrace

import (
	"context"
	"fmt"

	"github.com/jackc/pgx/v5/tracelog"
)

// TestingLogger interface defines the subset of testing.TB methods used by this
// adapter.
type TestingLogger interface {
	Log(args ...any)
}

type Logger struct {
	l TestingLogger
}

func NewLogger(l TestingLogger) *Logger {
	return &Logger{l: l}
}

func (l *Logger) Log(ctx context.Context, level tracelog.LogLevel, msg string, data map[string]any) {
	logArgs := make([]any, 0, 2+len(data))
	logArgs = append(logArgs, level, msg)
	for k, v := range data {
		logArgs = append(logArgs, fmt.Sprintf("%s=%v", k, v))
	}
	l.l.Log(logArgs...)
}

@jackc Can you please help me how to add tracer and log
And what is the pre-requisite in enabling it.

You've got several layers of non-core pgx code there. I don't know what is going on with it.

But if you want working examples of tracing and logging I suggest looking at https://github.com/jackc/pgx/blob/master/tracer_test.go and https://github.com/jackc/pgx/blob/master/tracelog/tracelog_test.go.

Hey! thanks for reply.
I need to implement this. Kindly guide.
I tried both but I might be missing something.

For log

config, err := pgxpool.ParseConfig(dsn)
logger := &testLogger{}
	tracer := &tracelog.TraceLog{
		Logger:   logger,
		LogLevel: tracelog.LogLevelTrace,
	}
		config.ConnConfig.Tracer = tracer

For testLogger above, added code available in (https://github.com/jackc/pgx/blob/master/tracelog/tracelog_test.go)

An then executed queries like Exec and Query thinking that logs at each stage will be printed in console.
But nothing is getting printed.
Is my understanding correct. Shall I need to add anything else.
Am I missing something.

For tracer

config, err := pgxpool.ParseConfig(dsn)
tracer := &testTracer{}
config.ConnConfig.Tracer = tracer

For testTracer above added available at https://github.com/jackc/pgx/blob/master/tracer_test.go
An then executed queries like Exec and Query thinking that trace details will be printed in console.

Am I missing something. Please guide further.

After adding all the config details

I was using pgxpool.New instead of pgxpool.Newwithconfig.

I found the mistake

Logger is working fine after changing from pgxpool.New to pgxpool.NewWithConfig

It's logging all the details.

But while connecting tracer nothing is shown

Do we need to explicitly call something for the sake of tracer...

I don't know. You probably will want to step through the connection process with a debugger and see what happens when you get to the connect trace points.