git.colasdn.top/newrelic/go-agent@v3.26.0+incompatible/_integrations/nrmysql/nrmysql.go (about)

     1  // Copyright 2020 New Relic Corporation. All rights reserved.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  // +build go1.10
     5  
     6  // Package nrmysql instruments https://github.com/go-sql-driver/mysql.
     7  //
     8  // Use this package to instrument your MySQL calls without having to manually
     9  // create DatastoreSegments.  This is done in a two step process:
    10  //
    11  // 1. Use this package's driver in place of the mysql driver.
    12  //
    13  // If your code is using sql.Open like this:
    14  //
    15  //	import (
    16  //		_ "github.com/go-sql-driver/mysql"
    17  //	)
    18  //
    19  //	func main() {
    20  //		db, err := sql.Open("mysql", "user@unix(/path/to/socket)/dbname")
    21  //	}
    22  //
    23  // Then change the side-effect import to this package, and open "nrmysql" instead:
    24  //
    25  //	import (
    26  //		_ "github.com/newrelic/go-agent/_integrations/nrmysql"
    27  //	)
    28  //
    29  //	func main() {
    30  //		db, err := sql.Open("nrmysql", "user@unix(/path/to/socket)/dbname")
    31  //	}
    32  //
    33  // 2. Provide a context containing a newrelic.Transaction to all exec and query
    34  // methods on sql.DB, sql.Conn, sql.Tx, and sql.Stmt.  This requires using the
    35  // context methods ExecContext, QueryContext, and QueryRowContext in place of
    36  // Exec, Query, and QueryRow respectively.  For example, instead of the
    37  // following:
    38  //
    39  //	row := db.QueryRow("SELECT count(*) from tables")
    40  //
    41  // Do this:
    42  //
    43  //	ctx := newrelic.NewContext(context.Background(), txn)
    44  //	row := db.QueryRowContext(ctx, "SELECT count(*) from tables")
    45  //
    46  // A working example is shown here:
    47  // https://github.com/newrelic/go-agent/tree/master/_integrations/nrmysql/example/main.go
    48  package nrmysql
    49  
    50  import (
    51  	"database/sql"
    52  	"net"
    53  
    54  	"github.com/go-sql-driver/mysql"
    55  	newrelic "github.com/newrelic/go-agent"
    56  	"github.com/newrelic/go-agent/internal"
    57  	"github.com/newrelic/go-agent/internal/sqlparse"
    58  )
    59  
    60  var (
    61  	baseBuilder = newrelic.SQLDriverSegmentBuilder{
    62  		BaseSegment: newrelic.DatastoreSegment{
    63  			Product: newrelic.DatastoreMySQL,
    64  		},
    65  		ParseQuery: sqlparse.ParseQuery,
    66  		ParseDSN:   parseDSN,
    67  	}
    68  )
    69  
    70  func init() {
    71  	sql.Register("nrmysql", newrelic.InstrumentSQLDriver(mysql.MySQLDriver{}, baseBuilder))
    72  	internal.TrackUsage("integration", "driver", "mysql")
    73  }
    74  
    75  func parseDSN(s *newrelic.DatastoreSegment, dsn string) {
    76  	cfg, err := mysql.ParseDSN(dsn)
    77  	if nil != err {
    78  		return
    79  	}
    80  	parseConfig(s, cfg)
    81  }
    82  
    83  func parseConfig(s *newrelic.DatastoreSegment, cfg *mysql.Config) {
    84  	s.DatabaseName = cfg.DBName
    85  
    86  	var host, ppoid string
    87  	switch cfg.Net {
    88  	case "unix", "unixgram", "unixpacket":
    89  		host = "localhost"
    90  		ppoid = cfg.Addr
    91  	case "cloudsql":
    92  		host = cfg.Addr
    93  	default:
    94  		var err error
    95  		host, ppoid, err = net.SplitHostPort(cfg.Addr)
    96  		if nil != err {
    97  			host = cfg.Addr
    98  		} else if host == "" {
    99  			host = "localhost"
   100  		}
   101  	}
   102  
   103  	s.Host = host
   104  	s.PortPathOrID = ppoid
   105  }