Skip to content

Commit

Permalink
Added intergation for ms sql server with newrelic
Browse files Browse the repository at this point in the history
Added intergation for ms sql server
  • Loading branch information
Imran Shahid committed Dec 20, 2021
1 parent 4b46fc5 commit 1aba054
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 0 deletions.
1 change: 1 addition & 0 deletions v3/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/newrelic/go-agent/v3
go 1.7

require (
github.com/denisenkom/go-mssqldb v0.11.0
github.com/golang/protobuf v1.3.3
google.golang.org/grpc v1.27.0
)
8 changes: 8 additions & 0 deletions v3/integrations/nrmssql/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# v3/integrations/nrmssql [![GoDoc](https://godoc.org/github.com/newrelic/go-agent/v3/integrations/nrmysql?status.svg)](https://godoc.org/github.com/newrelic/go-agent/v3/integrations/nrmysql)

Package `nrmssql` instruments github.com/denisenkom/go-mssqldb.

```go
import "github.com/newrelic/go-agent/v3/integrations/nrmssql"
```

42 changes: 42 additions & 0 deletions v3/integrations/nrmssql/example/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package main

import (
"context"
"database/sql"
"fmt"
"os"
"time"

_ "github.com/newrelic/go-agent/v3/integrations/nrmssql"
"github.com/newrelic/go-agent/v3/newrelic"
)

func main() {
// Set up a local ms sql docker

db, err := sql.Open("nrmssql", "server=localhost;user id=sa;database=master;app name=MyAppName")
if nil != err {
panic(err)
}

app, err := newrelic.NewApplication(
newrelic.ConfigAppName("MSSQL App"),
newrelic.ConfigLicense(os.Getenv("NEW_RELIC_LICENSE_KEY")),
newrelic.ConfigDebugLogger(os.Stdout),
)
if nil != err {
panic(err)
}
app.WaitForConnection(5 * time.Second)
txn := app.StartTransaction("mssqlQuery")

ctx := newrelic.NewContext(context.Background(), txn)
row := db.QueryRowContext(ctx, "SELECT count(*) from tables")
var count int
row.Scan(&count)

txn.End()
app.Shutdown(5 * time.Second)

fmt.Println("number of tables in information_schema", count)
}
83 changes: 83 additions & 0 deletions v3/integrations/nrmssql/nrmssql.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright 2020 New Relic Corporation. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

// +build go1.10

// Package nrmssql instruments github.com/denisenkom/go-mssqldb.
//
// Use this package to instrument your MSSQL calls without having to manually
// create DatastoreSegments. This is done in a two step process:
//
// 1. Use this package's driver in place of the mssql driver.
//
// If your code is using sql.Open like this:
//
// import (
// _ "github.com/denisenkom/go-mssqldb"
// )
//
// func main() {
// db, err := sql.Open("mssql", "server=localhost;user id=sa;database=master;app name=MyAppName")
// }
//
// Then change the side-effect import to this package, and open "nrmssql" instead:
//
// import (
// _ "github.com/newrelic/go-agent/v3/integrations/nrmssql"
// )
//
// func main() {
// db, err := sql.Open("nrmssql", "server=localhost;user id=sa;database=master;app name=MyAppName")
// }
//
// 2. Provide a context containing a newrelic.Transaction to all exec and query
// methods on sql.DB, sql.Conn, sql.Tx, and sql.Stmt. This requires using the
// context methods ExecContext, QueryContext, and QueryRowContext in place of
// Exec, Query, and QueryRow respectively. For example, instead of the
// following:
//
// row := db.QueryRow("SELECT count(*) from tables")
//
// Do this:
//
// ctx := newrelic.NewContext(context.Background(), txn)
// row := db.QueryRowContext(ctx, "SELECT count(*) from tables")

package nrmssql

import (
"database/sql"
"fmt"
"github.com/denisenkom/go-mssqldb/msdsn"

"github.com/denisenkom/go-mssqldb"
"github.com/newrelic/go-agent/v3/internal"
"github.com/newrelic/go-agent/v3/newrelic"
"github.com/newrelic/go-agent/v3/newrelic/sqlparse"
)

var (
baseBuilder = newrelic.SQLDriverSegmentBuilder{
BaseSegment: newrelic.DatastoreSegment{
Product: newrelic.DatastoreMSSQL,
},
ParseQuery: sqlparse.ParseQuery,
ParseDSN: parseDSN,
}
)

func init() {
sql.Register("nrmssql", newrelic.InstrumentSQLDriver(&mssql.Driver{}, baseBuilder))
internal.TrackUsage("integration", "driver", "mssql")
}

func parseDSN(s *newrelic.DatastoreSegment, dsn string) {
cfg, _, err := msdsn.Parse(dsn)
if nil != err {
return
}

s.DatabaseName = cfg.Database
s.Host = cfg.Host
s.PortPathOrID = fmt.Sprint(cfg.Port)
}
67 changes: 67 additions & 0 deletions v3/integrations/nrmssql/nrmssql_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package nrmssql

import (
"github.com/newrelic/go-agent/v3/newrelic"
"testing"
)

func TestParseDSN(t *testing.T) {
testcases := []struct {
dsn string
expHost string
expPortPathOrID string
expDatabaseName string
}{
// examples from https://github.com/denisenkom/go-mssqldb/blob/master/msdsn/conn_str_test.go
{
dsn: "server=server\\instance;database=testdb;user id=tester;password=pwd",
expHost: "server",
expPortPathOrID: "0",
expDatabaseName: "testdb",
},
{
dsn: "server=(local)",
expHost: "localhost",
expPortPathOrID: "0",
expDatabaseName: "",
},
{
dsn: "sqlserver://someuser@somehost?connection+timeout=30",
expHost: "somehost",
expPortPathOrID: "0",
expDatabaseName: "",
},
{
dsn: "sqlserver://someuser:foo%3A%2F%5C%21~%40;bar@somehost:1434?connection+timeout=30",
expHost: "somehost",
expPortPathOrID: "1434",
expDatabaseName: "",
},
{
dsn: "Server=mssql.test.local; Initial Catalog=test; User ID=xxxxxxx; Password=abccxxxxxx;",
expHost: "mssql.test.local",
expPortPathOrID: "0",
expDatabaseName: "test",
},
{
dsn: "sport=invalid",
expHost: "localhost",
expPortPathOrID: "0",
expDatabaseName: "",
},
}

for _, test := range testcases {
s := &newrelic.DatastoreSegment{}
parseDSN(s, test.dsn)
if test.expHost != s.Host {
t.Errorf(`incorrect host, expected="%s", actual="%s"`, test.expHost, s.Host)
}
if test.expPortPathOrID != s.PortPathOrID {
t.Errorf(`incorrect port path or id, expected="%s", actual="%s"`, test.expPortPathOrID, s.PortPathOrID)
}
if test.expDatabaseName != s.DatabaseName {
t.Errorf(`incorrect database name, expected="%s", actual="%s"`, test.expDatabaseName, s.DatabaseName)
}
}
}

0 comments on commit 1aba054

Please sign in to comment.