instapgx

package module
v0.15.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 2, 2024 License: MIT Imports: 10 Imported by: 0

README

Instana instrumentation for pgx

This module contains the middleware to instrument services written with github.com/jackc/pgx/v4.

PkgGoDev

The API of this instrumentation might change in the future.

The current version contains the instrumentation for most of the methods defined for pgx.Tx and *pg.Conn.

Known limitation:
  • LargeObjects are not supported by this version.
  • For methods BeginTxFunc and BeginFunc time for Begin statement is not measured precisely.
  • Span for CopyFrom statement does not contain detailed information about the parameters.
  • Function QueryRow requires the result row to be Scan. This operation will close the corresponding span and prevent resource leaks. Span's duration will be a sum of query and scan duration.
  • For a SendBatch result, when methods either Exec, Query, QueryRow or QueryFunc are called, the correspondent span will have the wrong duration because these methods are only reading the result of the execution that happened before.

Installation

To add the module to your go.mod file, run the following command in your project directory:

$ go get github.com/instana/go-sensor/instrumentation/instapgx

Usage

// Create a sensor
sensor := instana.NewSensor("pgx-sensort")

// Parse config
conf, err := pgx.ParseConfig("postgres://postgres:mysecretpassword@localhost/postgres")
...

// Instrument connection 
conn, err := instapgx.ConnectConfig(context.Background(), sensor, conf)

For a SendBatch method, to have more information about statements in the span, please enable detailed mode.

// Enable detailed batch mode globally
instapgx.EnableDetailedBatchMode()
...
// Create batch
b := &pgx.Batch{}
...
// Send batch
br := conn.SendBatch(ctx, b)

Examples

Connection examples

Transaction examples

Testing

To run integration tests, a PostgreSQL database is required in the environment. It can be started with:

docker run -e POSTGRES_PASSWORD=mysecretpassword -p 5432:5432 -d postgres

Documentation

Index

Examples

Constants

View Source
const Version = "0.15.0"

Version is the instrumentation module semantic version

Variables

This section is empty.

Functions

func EnableDetailedBatchMode

func EnableDetailedBatchMode()

EnableDetailedBatchMode allows reporting detailed information about sql statements when executing sql in batches.

Types

type Conn

type Conn struct {
	*pgx.Conn
	// contains filtered or unexported fields
}

Conn wraps *pgx.Conn and adds tracing to it.

func Connect

func Connect(ctx context.Context, sensor instana.TracerLogger, connString string) (*Conn, error)

Connect establishes a connection with a PostgreSQL server using connection string and returns instrumented connection.

func ConnectConfig

func ConnectConfig(ctx context.Context, sensor instana.TracerLogger, connConfig *pgx.ConnConfig) (*Conn, error)

ConnectConfig establishes a connection with a PostgreSQL server using configuration struct and returns instrumented connection.

func (*Conn) Begin

func (c *Conn) Begin(ctx context.Context) (pgx.Tx, error)

Begin wraps (*pgx.Conn).Begin method and adds tracing to it.

Example
databaseUrl := "postgres://postgres:mysecretpassword@localhost/postgres"

sensor := instana.NewSensor("pgx-example-begin")
conf, err := pgx.ParseConfig(databaseUrl)
if err != nil {
	log.Fatalln(err.Error())
}

ctx := context.Background()
conn, err := instapgx.ConnectConfig(ctx, sensor, conf)
if err != nil {
	log.Fatalln(err.Error())
}

tx, err := conn.Begin(ctx)
if err != nil {
	log.Fatalln(err.Error())
}

err = tx.Commit(ctx)
if err != nil {
	_ = tx.Rollback(ctx)
	log.Fatalln(err.Error())
}
Output:

func (*Conn) BeginFunc

func (c *Conn) BeginFunc(ctx context.Context, f func(pgx.Tx) error) error

BeginFunc wraps (*pgx.Conn).BeginFunc method and adds tracing to it.

Example
databaseUrl := "postgres://postgres:mysecretpassword@localhost/postgres"

sensor := instana.NewSensor("pgx-example-begin-func")
conf, err := pgx.ParseConfig(databaseUrl)
if err != nil {
	log.Fatalln(err.Error())
}

ctx := context.Background()
conn, err := instapgx.ConnectConfig(ctx, sensor, conf)
if err != nil {
	log.Fatalln(err.Error())
}

err = conn.BeginFunc(ctx, func(tx pgx.Tx) error {
	var a, b int
	_, err = tx.QueryFunc(
		ctx,
		"select n, n * 2 from generate_series(1, $1) n",
		[]interface{}{3},
		[]interface{}{&a, &b},
		func(pgx.QueryFuncRow) error {
			return nil
		},
	)

	return err
})

if err != nil {
	log.Fatalln(err.Error())
}
Output:

func (*Conn) BeginTx

func (c *Conn) BeginTx(ctx context.Context, txOptions pgx.TxOptions) (pgx.Tx, error)

BeginTx wraps (*pgx.Conn).BeginTx method and adds tracing to it.

func (*Conn) BeginTxFunc

func (c *Conn) BeginTxFunc(ctx context.Context, txOptions pgx.TxOptions, f func(pgx.Tx) error) error

BeginTxFunc wraps (*pgx.Conn).BeginTxFunc method and adds tracing to it.

func (*Conn) CopyFrom

func (c *Conn) CopyFrom(ctx context.Context, tableName pgx.Identifier, columnNames []string, rowSrc pgx.CopyFromSource) (int64, error)

CopyFrom wraps (*pgx.Conn).CopyFrom method and adds tracing to it. It doesn't provide details of the call.

func (*Conn) Exec

func (c *Conn) Exec(ctx context.Context, sql string, arguments ...interface{}) (pgconn.CommandTag, error)

Exec wraps (*pgx.Conn).Exec method and adds tracing to it.

Example
databaseUrl := "postgres://postgres:mysecretpassword@localhost/postgres"

sensor := instana.NewSensor("pgx-example-exec")
conf, err := pgx.ParseConfig(databaseUrl)
if err != nil {
	log.Fatalln(err.Error())
}

ctx := context.Background()
conn, err := instapgx.ConnectConfig(ctx, sensor, conf)
if err != nil {
	log.Fatalln(err.Error())
}

_, err = conn.Exec(ctx, "VACUUM (VERBOSE, ANALYZE)")
if err != nil {
	log.Fatalln(err.Error())
}
Output:

func (*Conn) Ping

func (c *Conn) Ping(ctx context.Context) error

Ping wraps (*pgx.Conn).Ping method and adds tracing to it.

Example
databaseUrl := "postgres://postgres:mysecretpassword@localhost/postgres"

sensor := instana.NewSensor("pgx-example-ping")
conf, err := pgx.ParseConfig(databaseUrl)
if err != nil {
	log.Fatalln(err.Error())
}

ctx := context.Background()
conn, err := instapgx.ConnectConfig(ctx, sensor, conf)
if err != nil {
	log.Fatalln(err.Error())
}

err = conn.Ping(ctx)
if err != nil {
	log.Fatalln(err.Error())
}
Output:

func (*Conn) Prepare

func (c *Conn) Prepare(ctx context.Context, name, sql string) (*pgconn.StatementDescription, error)

Prepare wraps (*pgx.Conn).Prepare method and adds tracing to it.

Example
databaseUrl := "postgres://postgres:mysecretpassword@localhost/postgres"

sensor := instana.NewSensor("pgx-example-prepare")
conf, err := pgx.ParseConfig(databaseUrl)
if err != nil {
	log.Fatalln(err.Error())
}

ctx := context.Background()
conn, err := instapgx.ConnectConfig(ctx, sensor, conf)
if err != nil {
	log.Fatalln(err.Error())
}

_, err = conn.Prepare(ctx, "mystatement", "select name, statement from pg_prepared_statements")
if err != nil {
	log.Fatalln(err.Error())
}
Output:

func (*Conn) Query

func (c *Conn) Query(ctx context.Context, sql string, args ...interface{}) (pgx.Rows, error)

Query wraps (*pgx.Conn).Query method and adds tracing to it.

Example
databaseUrl := "postgres://postgres:mysecretpassword@localhost/postgres"

sensor := instana.NewSensor("pgx-example-query")
conf, err := pgx.ParseConfig(databaseUrl)
if err != nil {
	log.Fatalln(err.Error())
}

ctx := context.Background()
conn, err := instapgx.ConnectConfig(ctx, sensor, conf)
if err != nil {
	log.Fatalln(err.Error())
}

row := conn.QueryRow(ctx, "select name, statement from pg_prepared_statements")

var name, stmt string
err = row.Scan(&name, &stmt)
if err != nil {
	log.Fatalln(err.Error())
}
Output:

func (*Conn) QueryFunc

func (c *Conn) QueryFunc(ctx context.Context, sql string, args []interface{}, scans []interface{}, f func(pgx.QueryFuncRow) error) (pgconn.CommandTag, error)

QueryFunc wraps (*pgx.Conn).QueryFunc method and adds tracing to it.

Example
databaseUrl := "postgres://postgres:mysecretpassword@localhost/postgres"

sensor := instana.NewSensor("pgx-example-query-func")
conf, err := pgx.ParseConfig(databaseUrl)
if err != nil {
	log.Fatalln(err.Error())
}

ctx := context.Background()
conn, err := instapgx.ConnectConfig(ctx, sensor, conf)
if err != nil {
	log.Fatalln(err.Error())
}

var a, b int
_, err = conn.QueryFunc(
	ctx,
	"select n, n * 2 from generate_series(1, $1) n",
	[]interface{}{3},
	[]interface{}{&a, &b},
	func(pgx.QueryFuncRow) error {
		return nil
	},
)

if err != nil {
	log.Fatalln(err.Error())
}
Output:

func (*Conn) QueryRow

func (c *Conn) QueryRow(ctx context.Context, sql string, args ...interface{}) pgx.Row

QueryRow wraps (*pgx.Conn).QueryRow method and adds tracing to it. It requires to calling Scan method on the returned row to finish a span.

func (*Conn) SendBatch

func (c *Conn) SendBatch(ctx context.Context, b *pgx.Batch) pgx.BatchResults

SendBatch wraps (*pgx.Conn).SendBatch method and adds tracing to it. Call the EnableDetailedBatchMode(), to have sql statements in the span. Amount of the sql statements that might be reported are limited.

Example
databaseUrl := "postgres://postgres:mysecretpassword@localhost/postgres"

sensor := instana.NewSensor("pgx-example-send-batch")
conf, err := pgx.ParseConfig(databaseUrl)
if err != nil {
	log.Fatalln(err.Error())
}

ctx := context.Background()
conn, err := instapgx.ConnectConfig(ctx, sensor, conf)
if err != nil {
	log.Fatalln(err.Error())
}

instapgx.EnableDetailedBatchMode()

b := &pgx.Batch{}
b.Queue("select name, statement from pg_prepared_statements")
b.Queue("select n, n * 2 from generate_series(1, $1) n", 1)

br := conn.SendBatch(ctx, b)

_, err = br.Query()
if err != nil {
	log.Fatalln(err.Error())
}

_, err = br.Exec()
if err != nil {
	log.Fatalln(err.Error())
}

err = br.Close()
if err != nil {
	log.Fatalln(err.Error())
}
Output:

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL