github.com/newrelic/go-agent@v3.26.0+incompatible/_integrations/nrpq/example/sqlx/main.go (about)

     1  // Copyright 2020 New Relic Corporation. All rights reserved.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  // An application that illustrates how to instrument jmoiron/sqlx with DatastoreSegments
     5  //
     6  // To run this example, be sure the environment varible NEW_RELIC_LICENSE_KEY
     7  // is set to your license key.  Postgres must be running on the default port
     8  // 5432 and have a user "foo" and a database "bar".
     9  //
    10  // Adding instrumentation for the SQLx package is easy.  It means you can
    11  // make database calls without having to manually create DatastoreSegments.
    12  // Setup can be done in two steps:
    13  //
    14  // Set up your driver
    15  //
    16  // If you are using one of our currently supported database drivers (see
    17  // https://docs.newrelic.com/docs/agents/go-agent/get-started/go-agent-compatibility-requirements#frameworks),
    18  // follow the instructions on installing the driver.
    19  //
    20  // As an example, for the `lib/pq` driver, you will use the newrelic
    21  // integration's driver in place of the postgres driver.  If your code is using
    22  // sqlx.Open with `lib/pq` like this:
    23  //
    24  //	import (
    25  //		"github.com/jmoiron/sqlx"
    26  //		_ "github.com/lib/pq"
    27  //	)
    28  //
    29  //	func main() {
    30  //		db, err := sqlx.Open("postgres", "user=pqgotest dbname=pqgotest sslmode=verify-full")
    31  //	}
    32  //
    33  // Then change the side-effect import to the integration package, and open
    34  // "nrpostgres" instead:
    35  //
    36  //	import (
    37  //		"github.com/jmoiron/sqlx"
    38  //		_ "github.com/newrelic/go-agent/_integrations/nrpq"
    39  //	)
    40  //
    41  //	func main() {
    42  //		db, err := sqlx.Open("nrpostgres", "user=pqgotest dbname=pqgotest sslmode=verify-full")
    43  //	}
    44  //
    45  // If you are not using one of the supported database drivers, use the
    46  // `InstrumentSQLDriver`
    47  // (https://godoc.org/github.com/newrelic/go-agent#InstrumentSQLDriver) API.
    48  // See
    49  // https://github.com/newrelic/go-agent/blob/master/_integrations/nrmysql/nrmysql.go
    50  // for a full example.
    51  //
    52  // Add context to your database calls
    53  //
    54  // Next, you must provide a context containing a newrelic.Transaction to all
    55  // methods on sqlx.DB, sqlx.NamedStmt, sqlx.Stmt, and sqlx.Tx that make a
    56  // database call.  For example, instead of the following:
    57  //
    58  //	err := db.Get(&jason, "SELECT * FROM person WHERE first_name=$1", "Jason")
    59  //
    60  // Do this:
    61  //
    62  //	ctx := newrelic.NewContext(context.Background(), txn)
    63  //	err := db.GetContext(ctx, &jason, "SELECT * FROM person WHERE first_name=$1", "Jason")
    64  //
    65  package main
    66  
    67  import (
    68  	"context"
    69  	"fmt"
    70  	"log"
    71  	"os"
    72  	"time"
    73  
    74  	"github.com/jmoiron/sqlx"
    75  	newrelic "github.com/newrelic/go-agent"
    76  	_ "github.com/newrelic/go-agent/_integrations/nrpq"
    77  )
    78  
    79  var schema = `
    80  CREATE TABLE person (
    81      first_name text,
    82      last_name text,
    83      email text
    84  )`
    85  
    86  // Person is a person in the database
    87  type Person struct {
    88  	FirstName string `db:"first_name"`
    89  	LastName  string `db:"last_name"`
    90  	Email     string
    91  }
    92  
    93  func mustGetEnv(key string) string {
    94  	if val := os.Getenv(key); "" != val {
    95  		return val
    96  	}
    97  	panic(fmt.Sprintf("environment variable %s unset", key))
    98  }
    99  
   100  func createApp() newrelic.Application {
   101  	cfg := newrelic.NewConfig("SQLx", mustGetEnv("NEW_RELIC_LICENSE_KEY"))
   102  	cfg.Logger = newrelic.NewDebugLogger(os.Stdout)
   103  	app, err := newrelic.NewApplication(cfg)
   104  	if nil != err {
   105  		log.Fatalln(err)
   106  	}
   107  	if err := app.WaitForConnection(5 * time.Second); nil != err {
   108  		log.Fatalln(err)
   109  	}
   110  	return app
   111  }
   112  
   113  func main() {
   114  	// Create application
   115  	app := createApp()
   116  	defer app.Shutdown(10 * time.Second)
   117  	// Start a transaction
   118  	txn := app.StartTransaction("main", nil, nil)
   119  	defer txn.End()
   120  	// Add transaction to context
   121  	ctx := newrelic.NewContext(context.Background(), txn)
   122  
   123  	// Connect to database using the "nrpostgres" driver
   124  	db, err := sqlx.Connect("nrpostgres", "user=foo dbname=bar sslmode=disable")
   125  	if err != nil {
   126  		log.Fatalln(err)
   127  	}
   128  
   129  	// Create database table if it does not exist already
   130  	// When the context is passed, DatastoreSegments will be created
   131  	db.ExecContext(ctx, schema)
   132  
   133  	// Add people to the database
   134  	// When the context is passed, DatastoreSegments will be created
   135  	tx := db.MustBegin()
   136  	tx.MustExecContext(ctx, "INSERT INTO person (first_name, last_name, email) VALUES ($1, $2, $3)", "Jason", "Moiron", "jmoiron@jmoiron.net")
   137  	tx.MustExecContext(ctx, "INSERT INTO person (first_name, last_name, email) VALUES ($1, $2, $3)", "John", "Doe", "johndoeDNE@gmail.net")
   138  	tx.Commit()
   139  
   140  	// Read from the database
   141  	// When the context is passed, DatastoreSegments will be created
   142  	people := []Person{}
   143  	db.SelectContext(ctx, &people, "SELECT * FROM person ORDER BY first_name ASC")
   144  	jason := Person{}
   145  	db.GetContext(ctx, &jason, "SELECT * FROM person WHERE first_name=$1", "Jason")
   146  }