@@ -350,6 +350,206 @@ func TestOpenSQLDB_RedisConnString(t *testing.T) {
350
350
}, data .Tags )
351
351
}
352
352
353
+ func TestConnPrepareContext (t * testing.T ) {
354
+ recorder := instana .NewTestRecorder ()
355
+ s := instana .NewSensorWithTracer (instana .NewTracerWithEverything (& instana.Options {
356
+ Service : "go-sensor-test" ,
357
+ AgentClient : alwaysReadyClient {},
358
+ }, recorder ))
359
+ defer instana .ShutdownSensor ()
360
+
361
+ instana .InstrumentSQLDriver (s , "fake_pc" , sqlDriver {})
362
+ require .Contains (t , sql .Drivers (), "fake_pc_with_instana" )
363
+
364
+ db , err := instana .SQLOpen ("fake_pc" , "conn string" )
365
+ require .NoError (t , err )
366
+
367
+ ctx := context .Background ()
368
+
369
+ stmt , err := db .PrepareContext (ctx , "select 1 from table" )
370
+ require .NoError (t , err )
371
+
372
+ _ , err = stmt .QueryContext (ctx )
373
+ require .NoError (t , err )
374
+
375
+ spans := recorder .GetQueuedSpans ()
376
+
377
+ require .Len (t , spans , 1 )
378
+
379
+ require .IsType (t , instana.SDKSpanData {}, spans [0 ].Data )
380
+ data := spans [0 ].Data .(instana.SDKSpanData )
381
+
382
+ assert .Equal (t , instana.SDKSpanTags {
383
+ Name : "sdk.database" ,
384
+ Type : "exit" ,
385
+ Custom : map [string ]interface {}{
386
+ "tags" : ot.Tags {
387
+ "span.kind" : ext .SpanKindRPCClientEnum ,
388
+ "db.instance" : "conn string" ,
389
+ "db.statement" : "select 1 from table" ,
390
+ "db.type" : "sql" ,
391
+ "peer.address" : "conn string" ,
392
+ },
393
+ },
394
+ }, data .Tags )
395
+ }
396
+
397
+ func TestConnPrepareContextWithError (t * testing.T ) {
398
+ recorder := instana .NewTestRecorder ()
399
+ s := instana .NewSensorWithTracer (instana .NewTracerWithEverything (& instana.Options {
400
+ Service : "go-sensor-test" ,
401
+ AgentClient : alwaysReadyClient {},
402
+ }, recorder ))
403
+ defer instana .ShutdownSensor ()
404
+
405
+ instana .InstrumentSQLDriver (s , "fake_conn_pc_error" , sqlDriver {Error : errors .New ("some error" )})
406
+ require .Contains (t , sql .Drivers (), "fake_conn_pc_error_with_instana" )
407
+
408
+ db , err := instana .SQLOpen ("fake_conn_pc_error" , "conn string" )
409
+ require .NoError (t , err )
410
+
411
+ ctx := context .Background ()
412
+
413
+ stmt , err := db .PrepareContext (ctx , "select 1 from table" )
414
+ require .NoError (t , err )
415
+
416
+ _ , err = stmt .QueryContext (ctx )
417
+ require .Error (t , err )
418
+
419
+ spans := recorder .GetQueuedSpans ()
420
+
421
+ require .Len (t , spans , 2 )
422
+
423
+ assert .Equal (t , spans [0 ].Ec , 1 )
424
+
425
+ require .IsType (t , instana.SDKSpanData {}, spans [0 ].Data )
426
+ data := spans [0 ].Data .(instana.SDKSpanData )
427
+
428
+ assert .Equal (t , instana.SDKSpanTags {
429
+ Name : "sdk.database" ,
430
+ Type : "exit" ,
431
+ Custom : map [string ]interface {}{
432
+ "tags" : ot.Tags {
433
+ "span.kind" : ext .SpanKindRPCClientEnum ,
434
+ "db.error" : "some error" ,
435
+ "db.instance" : "conn string" ,
436
+ "db.statement" : "select 1 from table" ,
437
+ "db.type" : "sql" ,
438
+ "peer.address" : "conn string" ,
439
+ },
440
+ },
441
+ }, data .Tags )
442
+ }
443
+
444
+ func TestStmtExecContext (t * testing.T ) {
445
+ recorder := instana .NewTestRecorder ()
446
+ s := instana .NewSensorWithTracer (instana .NewTracerWithEverything (& instana.Options {
447
+ Service : "go-sensor-test" ,
448
+ AgentClient : alwaysReadyClient {},
449
+ }, recorder ))
450
+ defer instana .ShutdownSensor ()
451
+
452
+ instana .InstrumentSQLDriver (s , "fake_stmt_ec" , sqlDriver {})
453
+ require .Contains (t , sql .Drivers (), "fake_stmt_ec_with_instana" )
454
+
455
+ db , err := instana .SQLOpen ("fake_stmt_ec" , "conn string" )
456
+ require .NoError (t , err )
457
+
458
+ ctx := context .Background ()
459
+
460
+ stmt , err := db .PrepareContext (ctx , "select 1 from table" )
461
+ require .NoError (t , err )
462
+
463
+ _ , err = stmt .ExecContext (ctx )
464
+ require .NoError (t , err )
465
+
466
+ spans := recorder .GetQueuedSpans ()
467
+
468
+ require .Len (t , spans , 1 )
469
+
470
+ require .IsType (t , instana.SDKSpanData {}, spans [0 ].Data )
471
+ data := spans [0 ].Data .(instana.SDKSpanData )
472
+
473
+ assert .Equal (t , instana.SDKSpanTags {
474
+ Name : "sdk.database" ,
475
+ Type : "exit" ,
476
+ Custom : map [string ]interface {}{
477
+ "tags" : ot.Tags {
478
+ "span.kind" : ext .SpanKindRPCClientEnum ,
479
+ "db.instance" : "conn string" ,
480
+ "db.statement" : "select 1 from table" ,
481
+ "db.type" : "sql" ,
482
+ "peer.address" : "conn string" ,
483
+ },
484
+ },
485
+ }, data .Tags )
486
+ }
487
+
488
+ func TestStmtExecContextWithError (t * testing.T ) {
489
+ recorder := instana .NewTestRecorder ()
490
+ s := instana .NewSensorWithTracer (instana .NewTracerWithEverything (& instana.Options {
491
+ Service : "go-sensor-test" ,
492
+ AgentClient : alwaysReadyClient {},
493
+ }, recorder ))
494
+ defer instana .ShutdownSensor ()
495
+
496
+ instana .InstrumentSQLDriver (s , "fake_stmt_ec_with_error" , sqlDriver {Error : errors .New ("oh no" )})
497
+ require .Contains (t , sql .Drivers (), "fake_stmt_ec_with_error_with_instana" )
498
+
499
+ db , err := instana .SQLOpen ("fake_stmt_ec_with_error" , "conn string" )
500
+ require .NoError (t , err )
501
+
502
+ ctx := context .Background ()
503
+
504
+ stmt , err := db .PrepareContext (ctx , "select 1 from table" )
505
+ require .NoError (t , err )
506
+
507
+ _ , err = stmt .ExecContext (ctx )
508
+ require .Error (t , err )
509
+
510
+ spans := recorder .GetQueuedSpans ()
511
+
512
+ require .Len (t , spans , 2 )
513
+
514
+ require .IsType (t , instana.SDKSpanData {}, spans [0 ].Data )
515
+ data := spans [0 ].Data .(instana.SDKSpanData )
516
+
517
+ assert .Equal (t , instana.SDKSpanTags {
518
+ Name : "sdk.database" ,
519
+ Type : "exit" ,
520
+ Custom : map [string ]interface {}{
521
+ "tags" : ot.Tags {
522
+ "span.kind" : ext .SpanKindRPCClientEnum ,
523
+ "db.error" : "oh no" ,
524
+ "db.instance" : "conn string" ,
525
+ "db.statement" : "select 1 from table" ,
526
+ "db.type" : "sql" ,
527
+ "peer.address" : "conn string" ,
528
+ },
529
+ },
530
+ }, data .Tags )
531
+ }
532
+
533
+ func TestConnPrepareContextWithErrorOnReturn (t * testing.T ) {
534
+ recorder := instana .NewTestRecorder ()
535
+ s := instana .NewSensorWithTracer (instana .NewTracerWithEverything (& instana.Options {
536
+ Service : "go-sensor-test" ,
537
+ AgentClient : alwaysReadyClient {},
538
+ }, recorder ))
539
+ defer instana .ShutdownSensor ()
540
+
541
+ instana .InstrumentSQLDriver (s , "fake_conn_pc_error_on_ret" , sqlDriver {PrepareError : errors .New ("oh no" )})
542
+ require .Contains (t , sql .Drivers (), "fake_conn_pc_error_on_ret_with_instana" )
543
+
544
+ db , err := instana .SQLOpen ("fake_conn_pc_error_on_ret" , "conn string" )
545
+ require .NoError (t , err )
546
+
547
+ ctx := context .Background ()
548
+
549
+ _ , err = db .PrepareContext (ctx , "select 1 from table" )
550
+ require .Error (t , err )
551
+ }
552
+
353
553
func TestOpenSQLDB_RedisConnString_WithError (t * testing.T ) {
354
554
recorder := instana .NewTestRecorder ()
355
555
s := instana .NewSensorWithTracer (instana .NewTracerWithEverything (& instana.Options {
@@ -358,7 +558,7 @@ func TestOpenSQLDB_RedisConnString_WithError(t *testing.T) {
358
558
}, recorder ))
359
559
defer instana .ShutdownSensor ()
360
560
361
- instana .InstrumentSQLDriver (s , "fake_redis_driver_with_error" , sqlDriver {errors .New ("oops" )})
561
+ instana .InstrumentSQLDriver (s , "fake_redis_driver_with_error" , sqlDriver {Error : errors .New ("oops" )})
362
562
require .Contains (t , sql .Drivers (), "fake_redis_driver_with_error_with_instana" )
363
563
364
564
db ,
err := instana .
SQLOpen (
"fake_redis_driver_with_error" ,
":[email protected] :6790" )
@@ -482,15 +682,41 @@ func TestProcedureWithNoDefaultChecker(t *testing.T) {
482
682
assert .NoError (t , err )
483
683
}
484
684
485
- type sqlDriver struct { Error error }
685
+ type sqlDriver struct {
686
+ // Error is a generic error in the SQL execution. It generates spans with errors
687
+ Error error
688
+ // StmtError will give an error when a method from Stmt returns. It does not generate spans at all
689
+ StmtError error
690
+ // PrepareError will give an error when a method from Prepare* returns. It does not generate spans at all
691
+ PrepareError error
692
+ }
486
693
487
- func (drv sqlDriver ) Open (name string ) (driver.Conn , error ) { return sqlConn {drv .Error }, nil } //nolint:gosimple
694
+ func (drv sqlDriver ) Open (name string ) (driver.Conn , error ) {
695
+ return sqlConn {
696
+ Error : drv .Error ,
697
+ StmtError : drv .StmtError ,
698
+ PrepareError : drv .PrepareError ,
699
+ }, nil
700
+ } //nolint:gosimple
488
701
489
- type sqlConn struct { Error error }
702
+ type sqlConn struct {
703
+ Error error
704
+ StmtError error
705
+ PrepareError error
706
+ }
490
707
491
- func (conn sqlConn ) Prepare (query string ) (driver.Stmt , error ) { return sqlStmt {conn .Error }, nil } //nolint:gosimple
492
- func (s sqlConn ) Close () error { return driver .ErrSkip }
493
- func (s sqlConn ) Begin () (driver.Tx , error ) { return nil , driver .ErrSkip }
708
+ var _ driver.Conn = (* sqlConn )(nil )
709
+ var _ driver.ConnPrepareContext = (* sqlConn )(nil )
710
+
711
+ func (conn sqlConn ) Prepare (query string ) (driver.Stmt , error ) {
712
+ return sqlStmt {Error : conn .Error }, nil
713
+ } //nolint:gosimple
714
+ func (conn sqlConn ) Close () error { return driver .ErrSkip }
715
+ func (conn sqlConn ) Begin () (driver.Tx , error ) { return nil , driver .ErrSkip }
716
+
717
+ func (conn sqlConn ) PrepareContext (ctx context.Context , query string ) (driver.Stmt , error ) {
718
+ return sqlStmt {StmtError : conn .StmtError , Error : conn .Error }, conn .PrepareError //nolint:gosimple
719
+ }
494
720
495
721
func (conn sqlConn ) ExecContext (ctx context.Context , query string , args []driver.NamedValue ) (driver.Result , error ) {
496
722
return sqlResult {}, conn .Error
@@ -500,12 +726,21 @@ func (conn sqlConn) QueryContext(ctx context.Context, query string, args []drive
500
726
return sqlRows {}, conn .Error
501
727
}
502
728
503
- type sqlStmt struct { Error error }
729
+ type sqlStmt struct {
730
+ Error error
731
+ StmtError error
732
+ }
504
733
505
734
func (sqlStmt ) Close () error { return nil }
506
735
func (sqlStmt ) NumInput () int { return - 1 }
507
736
func (stmt sqlStmt ) Exec (args []driver.Value ) (driver.Result , error ) { return sqlResult {}, stmt .Error }
508
737
func (stmt sqlStmt ) Query (args []driver.Value ) (driver.Rows , error ) { return sqlRows {}, stmt .Error }
738
+ func (stmt sqlStmt ) QueryContext (ctx context.Context , args []driver.NamedValue ) (driver.Rows , error ) {
739
+ return sqlRows {}, stmt .Error
740
+ }
741
+ func (stmt sqlStmt ) ExecContext (ctx context.Context , args []driver.NamedValue ) (driver.Result , error ) {
742
+ return sqlResult {}, stmt .Error
743
+ }
509
744
510
745
type sqlResult struct {}
511
746
0 commit comments