forked from j2gg0s/otsql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdriver.go
More file actions
139 lines (118 loc) · 3.5 KB
/
driver.go
File metadata and controls
139 lines (118 loc) · 3.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package otsql
import (
"context"
"database/sql"
"database/sql/driver"
"errors"
"strconv"
"sync"
)
var regMu sync.Mutex
var (
// Compile time assertions
_ driver.Driver = &otDriver{}
_ driver.Result = &otResult{}
_ driver.Stmt = &otStmt{}
_ driver.StmtExecContext = &otStmt{}
_ driver.StmtQueryContext = &otStmt{}
_ driver.Rows = &otRows{}
)
// Register initializes and registers our otsql wrapped database driver
// identified by its driverName and using provided TraceOptions. On success it
// returns the generated driverName to use when calling sql.Open.
// It is possible to register multiple wrappers for the same database driver if
// needing different TraceOptions for different connections.
func Register(driverName string, options ...TraceOption) (string, error) {
db, err := sql.Open(driverName, "")
if err != nil {
return "", err
}
dri := db.Driver()
if err = db.Close(); err != nil {
return "", err
}
regMu.Lock()
defer regMu.Unlock()
driverName = driverName + "-j2gg0s-otsql-"
NewDriverName:
for i := 0; i < 100; i++ {
regName := driverName + strconv.Itoa(i)
for _, name := range sql.Drivers() {
if name == regName {
continue NewDriverName
}
}
sql.Register(regName, Wrap(dri, options...))
return regName, nil
}
return "", errors.New("unable to register driver, all slots have been taken")
}
// Wrap takes a SQL driver and wraps it with OpenCensus instrumentation.
func Wrap(dri driver.Driver, options ...TraceOption) driver.Driver {
return wrapDriver(dri, newTraceOptions(options...))
}
type otConnector struct {
dc driver.Connector
dri driver.Driver
options TraceOptions
}
func (oc otConnector) Connect(ctx context.Context) (conn driver.Conn, err error) {
ctx, _, endTrace := startTrace(ctx, oc.options, methodCreateConn, "", nil)
defer func() {
endTrace(ctx, err)
}()
conn, err = oc.dc.Connect(ctx)
if err != nil {
return nil, err
}
return wrapConn(conn, oc.options), nil
}
func (oc otConnector) Driver() driver.Driver {
return oc.dri
}
// WrapConnector allows wrapping a database driver.Connector which eliminates
// the need to register otsql as an available driver.Driver.
func WrapConnector(dc driver.Connector, options ...TraceOption) driver.Connector {
return &otConnector{
dc: dc,
dri: wrapDriver(dc.Driver(), newTraceOptions(options...)),
options: newTraceOptions(options...),
}
}
// WrapConn allows an existing driver.Conn to be wrapped by otsql.
func WrapConn(c driver.Conn, options ...TraceOption) driver.Conn {
return wrapConn(c, newTraceOptions(options...))
}
func wrapDriver(dri driver.Driver, options TraceOptions) driver.Driver {
if _, ok := dri.(driver.DriverContext); ok {
return otDriver{Driver: dri, options: options}
}
return struct{ driver.Driver }{otDriver{Driver: dri, options: options}}
}
type otDriver struct {
driver.Driver
options TraceOptions
}
func (d otDriver) Open(name string) (conn driver.Conn, err error) {
ctx, span, endTrace := startTrace(context.Background(), d.options, methodCreateConn, "", nil)
span.SetAttributes(labelMissingContext)
defer func() {
endTrace(ctx, err)
}()
conn, err = d.Driver.Open(name)
if err != nil {
return nil, err
}
return wrapConn(conn, d.options), nil
}
func (d otDriver) OpenConnector(name string) (driver.Connector, error) {
connector, err := d.Driver.(driver.DriverContext).OpenConnector(name)
if err != nil {
return nil, err
}
return &otConnector{
dc: connector,
dri: d,
options: d.options,
}, nil
}