Skip to content

Commit

Permalink
Add instrumentation for gorm (#98)
Browse files Browse the repository at this point in the history
Add instrumentation for gorm
  • Loading branch information
MrAlias authored Sep 28, 2021
1 parent 4143ce0 commit ecebf9c
Show file tree
Hide file tree
Showing 9 changed files with 261 additions and 2 deletions.
4 changes: 4 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ updates:
directory: "/instrumentation/github.com/jackc/pgx/splunkpgx/test"
schedule:
interval: "daily"
- package-ecosystem: "gomod"
directory: "/instrumentation/github.com/jinzhu/gorm/splunkgorm"
schedule:
interval: "daily"
- package-ecosystem: "gomod"
directory: "/instrumentation/github.com/jmoiron/sqlx/splunksqlx"
schedule:
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Add the
`github.com/signalfx/splunk-otel-go/instrumentation/github.com/jmoiron/sqlx/splunksqlx`
instrumentation for the `github.com/jmoiron/sqlx` package. (#93)
- Add the
`github.com/signalfx/splunk-otel-go/instrumentation/github.com/jinzhu/gorm/splunkgorm`
instrumentation for the `github.com/jinzhu/gorm` package. (#98)

### Changed

Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,13 @@ Supported libraries are listed
Additional recommended Splunk specific instrumentations:
- [`splunksql`](./instrumentation/database/sql/splunksql)
- [`splunksqlx`](./instrumentation/github.com/jmoiron/sqlx/splunksqlx)
- [`splunkgorm`](./instrumentation/github.com/jinzhu/gorm/splunkgorm)
- [`splunkhttp`](./instrumentation/net/http/splunkhttp)
- [`splunkmysql`](./instrumentation/github.com/go-sql-driver/mysql/splunkmysql)
- [`splunkpgx`](./instrumentation/github.com/jackc/pgx/splunkpgx)
- [`splunkpq`](./instrumentation/github.com/lib/pq/splunkpq)
- [`splunksql`](./instrumentation/database/sql/splunksql)
- [`splunksqlx`](./instrumentation/github.com/jmoiron/sqlx/splunksqlx)
## Manual Instrumentation
Expand Down
15 changes: 15 additions & 0 deletions instrumentation/github.com/jinzhu/gorm/splunkgorm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Splunk Instrumentation for `github.com/jinzhu/gorm`

[![Go Reference](https://pkg.go.dev/badge/github.com/signalfx/splunk-otel-go/instrumentation/github.com/jinzhu/gorm/splunkgorm.svg)](https://pkg.go.dev/github.com/signalfx/splunk-otel-go/instrumentation/github.com/jinzhu/gorm/splunkgorm)

This package provides instrumentation for the `github.com/jinzhu/gorm`
package. The instrumentation is provided by wrapping the
[`splunksql`](../../../../database/sql/splunksql) instrumentation.

## Getting Started

To start using this instrumentation, replace the use of the `gorm.Open`
function `Open` from this package. The returned `*gorm.DB` can then be use as
normal with the `gorm` package.

An example of this can be found [here](./example_test.go).
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright Splunk Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package splunkgorm_test

import (
"log"

"github.com/jinzhu/gorm"
"github.com/signalfx/splunk-otel-go/instrumentation/github.com/jinzhu/gorm/splunkgorm"
)

func ExampleOpen() {
// This assumes the instrumented driver,
// "github.com/signalfx/splunk-otel-go/instrumentation/github.com/jackc/pgx/splunkpgx",
// is imported. That will ensure the driver and the instrumentation setup
// for the driver are registered with the appropriate packages.
db, err := splunkgorm.Open("pgx", "postgres://localhost/db")
if err != nil {
log.Fatal(err)
}
defer func() {
if err := db.Close(); err != nil {
log.Printf("failed to close db: %v", err)
}
}()

user := struct {
gorm.Model
Name string
}{}

// All calls through gorm.DB are now traced.
db.Where("name = ?", "jinzhu").First(&user)
/* ... */
}
11 changes: 11 additions & 0 deletions instrumentation/github.com/jinzhu/gorm/splunkgorm/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module github.com/signalfx/splunk-otel-go/instrumentation/github.com/jinzhu/gorm/splunkgorm

go 1.15

require (
github.com/jinzhu/gorm v1.9.16
github.com/signalfx/splunk-otel-go/instrumentation/database/sql/splunksql v0.0.0-00010101000000-000000000000
github.com/stretchr/testify v1.7.0
)

replace github.com/signalfx/splunk-otel-go/instrumentation/database/sql/splunksql => ../../../../database/sql/splunksql
59 changes: 59 additions & 0 deletions instrumentation/github.com/jinzhu/gorm/splunkgorm/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/signalfx/splunk-otel-go v0.6.0 h1:3UAUtAiJK1nNpA3CqE4tv8y1SZU1B5qzUhtBGwNOM/Y=
github.com/signalfx/splunk-otel-go v0.6.0/go.mod h1:IAqW/sD3hlerxxw+WyQhh/2ZaKqY01o8Mtg0VwOIby8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
go.opentelemetry.io/contrib/propagators/b3 v0.23.0/go.mod h1:tAJUf0uW1xrgQ1QgOZqLXFbn3DNFO4tTmh0Nqe3kSzw=
go.opentelemetry.io/otel v1.0.0-RC3/go.mod h1:Ka5j3ua8tZs4Rkq4Ex3hwgBgOchyPVq5S6P2lz//nKQ=
go.opentelemetry.io/otel v1.0.0 h1:qTTn6x71GVBvoafHK/yaRUmFzI4LcONZD0/kXxl5PHI=
go.opentelemetry.io/otel v1.0.0/go.mod h1:AjRVh9A5/5DE7S+mZtTR6t8vpKKryam+0lREnfmS4cg=
go.opentelemetry.io/otel/exporters/jaeger v1.0.0-RC3/go.mod h1:UbP19Xlhk9tcRZ+A3PfvyN5ld4X4YrSnzXaYzx1yNLc=
go.opentelemetry.io/otel/sdk v1.0.0-RC3/go.mod h1:78H6hyg2fka0NYT9fqGuFLvly2yCxiBXDJAgLKo/2Us=
go.opentelemetry.io/otel/trace v1.0.0-RC3/go.mod h1:VUt2TUYd8S2/ZRX09ZDFZQwn2RqfMB5MzO17jBojGxo=
go.opentelemetry.io/otel/trace v1.0.0 h1:TSBr8GTEtKevYMG/2d21M989r5WJYVimhTHBKVEZuh4=
go.opentelemetry.io/otel/trace v1.0.0/go.mod h1:PXTWqayeFUlJV1YDNhsJYB184+IvAH814St6o6ajzIs=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd h1:GGJVjV8waZKRHrgwvtH66z9ZGVurTD1MT0n1Bb+q4aM=
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
36 changes: 36 additions & 0 deletions instrumentation/github.com/jinzhu/gorm/splunkgorm/sql.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright Splunk Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package splunkgorm provides instrumentation for the github.com/jinzhu/gorm
// package.
package splunkgorm // import "github.com/signalfx/splunk-otel-go/instrumentation/github.com/jinzhu/gorm/splunkgorm"

import (
"github.com/jinzhu/gorm"
"github.com/signalfx/splunk-otel-go/instrumentation/database/sql/splunksql"
)

// openFunc allows overrides for testing.
var openFunc = splunksql.Open

// Open opens a traced gorm database connection specified by its database
// driver name and a driver-specific data source name. The driver must already
// be registered by the driver package.
func Open(driverName, dataSourceName string, opts ...splunksql.Option) (*gorm.DB, error) {
db, err := openFunc(driverName, dataSourceName, opts...)
if err != nil {
return nil, err
}
return gorm.Open(driverName, db)
}
83 changes: 83 additions & 0 deletions instrumentation/github.com/jinzhu/gorm/splunkgorm/sql_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright Splunk Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package splunkgorm

import (
"context"
"database/sql"
"database/sql/driver"
"errors"
"testing"

"github.com/jinzhu/gorm"
"github.com/signalfx/splunk-otel-go/instrumentation/database/sql/splunksql"
"github.com/stretchr/testify/assert"
)

type mockOpen struct {
driverName, dataSourceName string
options []splunksql.Option
}

func (m *mockOpen) Open(name, dsn string, opts ...splunksql.Option) (*sql.DB, error) {
m.driverName = name
m.dataSourceName = dsn
m.options = opts
// Return something capable of implementing Ping so gorm does not panic.
return sql.OpenDB(mockConnector{}), nil
}

type mockConnector struct {
driver.Connector
}

func (mockConnector) Connect(context.Context) (driver.Conn, error) {
return mockConn{}, nil
}

type mockConn struct {
driver.Conn
}

func (mockConn) Ping(context.Context) error { return nil }

func TestOpen(t *testing.T) {
origOpen := openFunc
m := new(mockOpen)
openFunc = m.Open
defer func() { openFunc = origOpen }()

name, dsn := "testDB", "fake://user:pass@localhost/DB"
options := []splunksql.Option{splunksql.WithAttributes(nil)}
db, err := Open(name, dsn, options...)
assert.NoError(t, err)
assert.IsType(t, &gorm.DB{}, db)
assert.Equal(t, name, m.driverName)
assert.Equal(t, dsn, m.dataSourceName)
assert.Equal(t, options, m.options)
}

func TestOpenError(t *testing.T) {
want := errors.New("test error")
origOpen := openFunc
openFunc = func(string, string, ...splunksql.Option) (*sql.DB, error) {
return nil, want
}
defer func() { openFunc = origOpen }()

// Ensure Open returns any underlying error.
_, got := Open("", "")
assert.ErrorIs(t, got, want)
}

0 comments on commit ecebf9c

Please sign in to comment.