github.com/instana/go-sensor@v1.62.2-0.20240520081010-4919868049e1/instrumentation_sql_go1.10_test.go (about) 1 // (c) Copyright IBM Corp. 2021 2 // (c) Copyright Instana Inc. 2020 3 4 package instana_test 5 6 import ( 7 "context" 8 "database/sql" 9 "database/sql/driver" 10 "errors" 11 "testing" 12 13 instana "github.com/instana/go-sensor" 14 ot "github.com/opentracing/opentracing-go" 15 "github.com/opentracing/opentracing-go/ext" 16 "github.com/stretchr/testify/assert" 17 "github.com/stretchr/testify/require" 18 ) 19 20 func TestWrapSQLConnector_Exec(t *testing.T) { 21 22 recorder := instana.NewTestRecorder() 23 s := instana.NewSensorWithTracer(instana.NewTracerWithEverything(&instana.Options{ 24 Service: "go-sensor-test", 25 AgentClient: alwaysReadyClient{}, 26 }, recorder)) 27 defer instana.ShutdownSensor() 28 29 db := sql.OpenDB(instana.WrapSQLConnector(s, "connection string", sqlConnector{})) 30 31 pSpan := s.Tracer().StartSpan("parent-span") 32 ctx := context.Background() 33 if pSpan != nil { 34 ctx = instana.ContextWithSpan(ctx, pSpan) 35 } 36 37 res, err := db.ExecContext(ctx, "TEST QUERY") 38 require.NoError(t, err) 39 40 lastID, err := res.LastInsertId() 41 require.NoError(t, err) 42 assert.Equal(t, int64(42), lastID) 43 44 spans := recorder.GetQueuedSpans() 45 require.Len(t, spans, 1) 46 47 span := spans[0] 48 assert.Equal(t, 0, span.Ec) 49 assert.EqualValues(t, instana.ExitSpanKind, span.Kind) 50 51 require.IsType(t, instana.SDKSpanData{}, span.Data) 52 data := span.Data.(instana.SDKSpanData) 53 54 assert.Equal(t, instana.SDKSpanTags{ 55 Name: "sdk.database", 56 Type: "exit", 57 Custom: map[string]interface{}{ 58 "tags": ot.Tags{ 59 "span.kind": ext.SpanKindRPCClientEnum, 60 "db.instance": "connection string", 61 "db.statement": "TEST QUERY", 62 "db.type": "sql", 63 "peer.address": "connection string", 64 }, 65 }, 66 }, data.Tags) 67 } 68 69 func TestWrapSQLConnector_Exec_Error(t *testing.T) { 70 71 recorder := instana.NewTestRecorder() 72 s := instana.NewSensorWithTracer(instana.NewTracerWithEverything(&instana.Options{ 73 Service: "go-sensor-test", 74 AgentClient: alwaysReadyClient{}, 75 }, recorder)) 76 defer instana.ShutdownSensor() 77 78 pSpan := s.Tracer().StartSpan("parent-span") 79 ctx := context.Background() 80 if pSpan != nil { 81 ctx = instana.ContextWithSpan(ctx, pSpan) 82 } 83 84 db := sql.OpenDB(instana.WrapSQLConnector(s, "connection string", sqlConnector{ 85 Error: errors.New("something went wrong"), 86 })) 87 88 _, err := db.ExecContext(ctx, "TEST QUERY") 89 assert.Error(t, err) 90 91 spans := recorder.GetQueuedSpans() 92 require.Len(t, spans, 2) 93 94 span, logSpan := spans[0], spans[1] 95 assert.Equal(t, 1, span.Ec) 96 assert.EqualValues(t, instana.ExitSpanKind, span.Kind) 97 98 require.IsType(t, instana.SDKSpanData{}, span.Data) 99 100 assert.Equal(t, span.TraceID, logSpan.TraceID) 101 assert.Equal(t, span.SpanID, logSpan.ParentID) 102 assert.Equal(t, "log.go", logSpan.Name) 103 104 // assert that log message has been recorded within the span interval 105 assert.GreaterOrEqual(t, logSpan.Timestamp, span.Timestamp) 106 assert.LessOrEqual(t, logSpan.Duration, span.Duration) 107 108 require.IsType(t, instana.LogSpanData{}, logSpan.Data) 109 logData := logSpan.Data.(instana.LogSpanData) 110 111 assert.Equal(t, instana.LogSpanTags{ 112 Level: "ERROR", 113 Message: `error.object: "something went wrong"`, 114 }, logData.Tags) 115 } 116 117 func TestWrapSQLConnector_Query(t *testing.T) { 118 119 recorder := instana.NewTestRecorder() 120 s := instana.NewSensorWithTracer(instana.NewTracerWithEverything(&instana.Options{ 121 Service: "go-sensor-test", 122 AgentClient: alwaysReadyClient{}, 123 }, recorder)) 124 defer instana.ShutdownSensor() 125 126 pSpan := s.Tracer().StartSpan("parent-span") 127 ctx := context.Background() 128 if pSpan != nil { 129 ctx = instana.ContextWithSpan(ctx, pSpan) 130 } 131 132 db := sql.OpenDB(instana.WrapSQLConnector(s, "connection string", sqlConnector{})) 133 134 res, err := db.QueryContext(ctx, "TEST QUERY") 135 require.NoError(t, err) 136 137 cols, err := res.Columns() 138 require.NoError(t, err) 139 assert.Equal(t, []string{"col1", "col2"}, cols) 140 141 spans := recorder.GetQueuedSpans() 142 require.Len(t, spans, 1) 143 144 span := spans[0] 145 assert.Equal(t, 0, span.Ec) 146 assert.EqualValues(t, instana.ExitSpanKind, span.Kind) 147 148 require.IsType(t, instana.SDKSpanData{}, span.Data) 149 data := span.Data.(instana.SDKSpanData) 150 151 assert.Equal(t, instana.SDKSpanTags{ 152 Name: "sdk.database", 153 Type: "exit", 154 Custom: map[string]interface{}{ 155 "tags": ot.Tags{ 156 "span.kind": ext.SpanKindRPCClientEnum, 157 "db.instance": "connection string", 158 "db.statement": "TEST QUERY", 159 "db.type": "sql", 160 "peer.address": "connection string", 161 }, 162 }, 163 }, data.Tags) 164 } 165 166 func TestWrapSQLConnector_Query_Error(t *testing.T) { 167 168 recorder := instana.NewTestRecorder() 169 s := instana.NewSensorWithTracer(instana.NewTracerWithEverything(&instana.Options{ 170 Service: "go-sensor-test", 171 AgentClient: alwaysReadyClient{}, 172 }, recorder)) 173 defer instana.ShutdownSensor() 174 175 dbErr := errors.New("something went wrong") 176 db := sql.OpenDB(instana.WrapSQLConnector(s, "connection string", sqlConnector{ 177 Error: dbErr, 178 })) 179 180 pSpan := s.Tracer().StartSpan("parent-span") 181 ctx := context.Background() 182 if pSpan != nil { 183 ctx = instana.ContextWithSpan(ctx, pSpan) 184 } 185 186 _, err := db.QueryContext(ctx, "TEST QUERY") 187 assert.Error(t, err) 188 189 spans := recorder.GetQueuedSpans() 190 require.Len(t, spans, 2) 191 192 span, logSpan := spans[0], spans[1] 193 assert.Equal(t, 1, span.Ec) 194 assert.EqualValues(t, instana.ExitSpanKind, span.Kind) 195 196 require.IsType(t, instana.SDKSpanData{}, span.Data) 197 198 assert.Equal(t, span.TraceID, logSpan.TraceID) 199 assert.Equal(t, span.SpanID, logSpan.ParentID) 200 assert.Equal(t, "log.go", logSpan.Name) 201 202 // assert that log message has been recorded within the span interval 203 assert.GreaterOrEqual(t, logSpan.Timestamp, span.Timestamp) 204 assert.LessOrEqual(t, logSpan.Duration, span.Duration) 205 206 require.IsType(t, instana.LogSpanData{}, logSpan.Data) 207 logData := logSpan.Data.(instana.LogSpanData) 208 209 assert.Equal(t, instana.LogSpanTags{ 210 Level: "ERROR", 211 Message: `error.object: "something went wrong"`, 212 }, logData.Tags) 213 } 214 215 type sqlConnector struct{ Error error } 216 217 func (c sqlConnector) Connect(context.Context) (driver.Conn, error) { 218 return sqlConn{Error: c.Error}, nil 219 } //nolint:gosimple 220 func (sqlConnector) Driver() driver.Driver { return sqlDriver{} }