github.com/newrelic/go-agent@v3.26.0+incompatible/internal_slow_queries_test.go (about) 1 // Copyright 2020 New Relic Corporation. All rights reserved. 2 // SPDX-License-Identifier: Apache-2.0 3 4 package newrelic 5 6 import ( 7 "strings" 8 "testing" 9 "time" 10 11 "github.com/newrelic/go-agent/internal" 12 "github.com/newrelic/go-agent/internal/crossagent" 13 ) 14 15 func TestSlowQueryBasic(t *testing.T) { 16 cfgfn := func(cfg *Config) { 17 cfg.DatastoreTracer.SlowQuery.Threshold = 0 18 } 19 app := testApp(nil, cfgfn, t) 20 txn := app.StartTransaction("hello", nil, helloRequest) 21 s1 := DatastoreSegment{ 22 StartTime: StartSegmentNow(txn), 23 Product: DatastoreMySQL, 24 Collection: "users", 25 Operation: "INSERT", 26 ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)", 27 } 28 s1.End() 29 txn.End() 30 31 app.ExpectSlowQueries(t, []internal.WantSlowQuery{{ 32 Count: 1, 33 MetricName: "Datastore/statement/MySQL/users/INSERT", 34 Query: "INSERT INTO users (name, age) VALUES ($1, $2)", 35 TxnName: "WebTransaction/Go/hello", 36 TxnURL: "/hello", 37 DatabaseName: "", 38 Host: "", 39 PortPathOrID: "", 40 }}) 41 } 42 43 func TestSlowQueryLocallyDisabled(t *testing.T) { 44 cfgfn := func(cfg *Config) { 45 cfg.DatastoreTracer.SlowQuery.Threshold = 0 46 cfg.DatastoreTracer.SlowQuery.Enabled = false 47 } 48 app := testApp(nil, cfgfn, t) 49 txn := app.StartTransaction("hello", nil, helloRequest) 50 s1 := DatastoreSegment{ 51 StartTime: StartSegmentNow(txn), 52 Product: DatastoreMySQL, 53 Collection: "users", 54 Operation: "INSERT", 55 ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)", 56 } 57 s1.End() 58 txn.End() 59 60 app.ExpectSlowQueries(t, []internal.WantSlowQuery{}) 61 } 62 63 func TestSlowQueryRemotelyDisabled(t *testing.T) { 64 cfgfn := func(cfg *Config) { 65 cfg.DatastoreTracer.SlowQuery.Threshold = 0 66 } 67 replyfn := func(reply *internal.ConnectReply) { 68 reply.CollectTraces = false 69 } 70 app := testApp(replyfn, cfgfn, t) 71 txn := app.StartTransaction("hello", nil, helloRequest) 72 s1 := DatastoreSegment{ 73 StartTime: StartSegmentNow(txn), 74 Product: DatastoreMySQL, 75 Collection: "users", 76 Operation: "INSERT", 77 ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)", 78 } 79 s1.End() 80 txn.End() 81 82 app.ExpectSlowQueries(t, []internal.WantSlowQuery{}) 83 } 84 85 func TestSlowQueryBelowThreshold(t *testing.T) { 86 cfgfn := func(cfg *Config) { 87 cfg.DatastoreTracer.SlowQuery.Threshold = 1 * time.Hour 88 } 89 app := testApp(nil, cfgfn, t) 90 txn := app.StartTransaction("hello", nil, helloRequest) 91 s1 := DatastoreSegment{ 92 StartTime: StartSegmentNow(txn), 93 Product: DatastoreMySQL, 94 Collection: "users", 95 Operation: "INSERT", 96 ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)", 97 } 98 s1.End() 99 txn.End() 100 101 app.ExpectSlowQueries(t, []internal.WantSlowQuery{}) 102 } 103 104 func TestSlowQueryDatabaseProvided(t *testing.T) { 105 cfgfn := func(cfg *Config) { 106 cfg.DatastoreTracer.SlowQuery.Threshold = 0 107 } 108 app := testApp(nil, cfgfn, t) 109 txn := app.StartTransaction("hello", nil, helloRequest) 110 s1 := DatastoreSegment{ 111 StartTime: StartSegmentNow(txn), 112 Product: DatastoreMySQL, 113 Collection: "users", 114 Operation: "INSERT", 115 ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)", 116 DatabaseName: "my_database", 117 } 118 s1.End() 119 txn.End() 120 121 app.ExpectSlowQueries(t, []internal.WantSlowQuery{{ 122 Count: 1, 123 MetricName: "Datastore/statement/MySQL/users/INSERT", 124 Query: "INSERT INTO users (name, age) VALUES ($1, $2)", 125 TxnName: "WebTransaction/Go/hello", 126 TxnURL: "/hello", 127 DatabaseName: "my_database", 128 Host: "", 129 PortPathOrID: "", 130 }}) 131 } 132 133 func TestSlowQueryHostProvided(t *testing.T) { 134 cfgfn := func(cfg *Config) { 135 cfg.DatastoreTracer.SlowQuery.Threshold = 0 136 } 137 app := testApp(nil, cfgfn, t) 138 txn := app.StartTransaction("hello", nil, helloRequest) 139 s1 := DatastoreSegment{ 140 StartTime: StartSegmentNow(txn), 141 Product: DatastoreMySQL, 142 Collection: "users", 143 Operation: "INSERT", 144 ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)", 145 Host: "db-server-1", 146 } 147 s1.End() 148 txn.End() 149 150 app.ExpectSlowQueries(t, []internal.WantSlowQuery{{ 151 Count: 1, 152 MetricName: "Datastore/statement/MySQL/users/INSERT", 153 Query: "INSERT INTO users (name, age) VALUES ($1, $2)", 154 TxnName: "WebTransaction/Go/hello", 155 TxnURL: "/hello", 156 DatabaseName: "", 157 Host: "db-server-1", 158 PortPathOrID: "unknown", 159 }}) 160 scope := "WebTransaction/Go/hello" 161 app.ExpectMetrics(t, append([]internal.WantMetric{ 162 {Name: "Datastore/all", Scope: "", Forced: true, Data: nil}, 163 {Name: "Datastore/allWeb", Scope: "", Forced: true, Data: nil}, 164 {Name: "Datastore/MySQL/all", Scope: "", Forced: true, Data: nil}, 165 {Name: "Datastore/MySQL/allWeb", Scope: "", Forced: true, Data: nil}, 166 {Name: "Datastore/operation/MySQL/INSERT", Scope: "", Forced: false, Data: nil}, 167 {Name: "Datastore/statement/MySQL/users/INSERT", Scope: "", Forced: false, Data: nil}, 168 {Name: "Datastore/statement/MySQL/users/INSERT", Scope: scope, Forced: false, Data: nil}, 169 {Name: "Datastore/instance/MySQL/db-server-1/unknown", Scope: "", Forced: false, Data: nil}, 170 }, webMetrics...)) 171 } 172 173 func TestSlowQueryPortProvided(t *testing.T) { 174 cfgfn := func(cfg *Config) { 175 cfg.DatastoreTracer.SlowQuery.Threshold = 0 176 } 177 app := testApp(nil, cfgfn, t) 178 txn := app.StartTransaction("hello", nil, helloRequest) 179 s1 := DatastoreSegment{ 180 StartTime: StartSegmentNow(txn), 181 Product: DatastoreMySQL, 182 Collection: "users", 183 Operation: "INSERT", 184 ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)", 185 PortPathOrID: "98021", 186 } 187 s1.End() 188 txn.End() 189 190 app.ExpectSlowQueries(t, []internal.WantSlowQuery{{ 191 Count: 1, 192 MetricName: "Datastore/statement/MySQL/users/INSERT", 193 Query: "INSERT INTO users (name, age) VALUES ($1, $2)", 194 TxnName: "WebTransaction/Go/hello", 195 TxnURL: "/hello", 196 DatabaseName: "", 197 Host: "unknown", 198 PortPathOrID: "98021", 199 }}) 200 scope := "WebTransaction/Go/hello" 201 app.ExpectMetrics(t, append([]internal.WantMetric{ 202 {Name: "Datastore/all", Scope: "", Forced: true, Data: nil}, 203 {Name: "Datastore/allWeb", Scope: "", Forced: true, Data: nil}, 204 {Name: "Datastore/MySQL/all", Scope: "", Forced: true, Data: nil}, 205 {Name: "Datastore/MySQL/allWeb", Scope: "", Forced: true, Data: nil}, 206 {Name: "Datastore/operation/MySQL/INSERT", Scope: "", Forced: false, Data: nil}, 207 {Name: "Datastore/statement/MySQL/users/INSERT", Scope: "", Forced: false, Data: nil}, 208 {Name: "Datastore/statement/MySQL/users/INSERT", Scope: scope, Forced: false, Data: nil}, 209 {Name: "Datastore/instance/MySQL/unknown/98021", Scope: "", Forced: false, Data: nil}, 210 }, webMetrics...)) 211 } 212 213 func TestSlowQueryHostPortProvided(t *testing.T) { 214 cfgfn := func(cfg *Config) { 215 cfg.DatastoreTracer.SlowQuery.Threshold = 0 216 } 217 app := testApp(nil, cfgfn, t) 218 txn := app.StartTransaction("hello", nil, helloRequest) 219 s1 := DatastoreSegment{ 220 StartTime: StartSegmentNow(txn), 221 Product: DatastoreMySQL, 222 Collection: "users", 223 Operation: "INSERT", 224 ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)", 225 Host: "db-server-1", 226 PortPathOrID: "98021", 227 } 228 s1.End() 229 txn.End() 230 231 app.ExpectSlowQueries(t, []internal.WantSlowQuery{{ 232 Count: 1, 233 MetricName: "Datastore/statement/MySQL/users/INSERT", 234 Query: "INSERT INTO users (name, age) VALUES ($1, $2)", 235 TxnName: "WebTransaction/Go/hello", 236 TxnURL: "/hello", 237 DatabaseName: "", 238 Host: "db-server-1", 239 PortPathOrID: "98021", 240 }}) 241 scope := "WebTransaction/Go/hello" 242 app.ExpectMetrics(t, append([]internal.WantMetric{ 243 {Name: "Datastore/all", Scope: "", Forced: true, Data: nil}, 244 {Name: "Datastore/allWeb", Scope: "", Forced: true, Data: nil}, 245 {Name: "Datastore/MySQL/all", Scope: "", Forced: true, Data: nil}, 246 {Name: "Datastore/MySQL/allWeb", Scope: "", Forced: true, Data: nil}, 247 {Name: "Datastore/operation/MySQL/INSERT", Scope: "", Forced: false, Data: nil}, 248 {Name: "Datastore/statement/MySQL/users/INSERT", Scope: "", Forced: false, Data: nil}, 249 {Name: "Datastore/statement/MySQL/users/INSERT", Scope: scope, Forced: false, Data: nil}, 250 {Name: "Datastore/instance/MySQL/db-server-1/98021", Scope: "", Forced: false, Data: nil}, 251 }, webMetrics...)) 252 } 253 254 func TestSlowQueryAggregation(t *testing.T) { 255 cfgfn := func(cfg *Config) { 256 cfg.DatastoreTracer.SlowQuery.Threshold = 0 257 } 258 app := testApp(nil, cfgfn, t) 259 txn := app.StartTransaction("hello", nil, helloRequest) 260 ds := DatastoreSegment{ 261 StartTime: StartSegmentNow(txn), 262 Product: DatastoreMySQL, 263 Collection: "users", 264 Operation: "INSERT", 265 ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)", 266 } 267 ds.End() 268 ds = DatastoreSegment{ 269 StartTime: StartSegmentNow(txn), 270 Product: DatastoreMySQL, 271 Collection: "users", 272 Operation: "INSERT", 273 ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)", 274 } 275 ds.End() 276 ds = DatastoreSegment{ 277 StartTime: StartSegmentNow(txn), 278 Product: DatastorePostgres, 279 Collection: "products", 280 Operation: "INSERT", 281 ParameterizedQuery: "INSERT INTO products (name, price) VALUES ($1, $2)", 282 } 283 ds.End() 284 txn.End() 285 286 app.ExpectSlowQueries(t, []internal.WantSlowQuery{{ 287 Count: 2, 288 MetricName: "Datastore/statement/MySQL/users/INSERT", 289 Query: "INSERT INTO users (name, age) VALUES ($1, $2)", 290 TxnName: "WebTransaction/Go/hello", 291 TxnURL: "/hello", 292 DatabaseName: "", 293 Host: "", 294 PortPathOrID: "", 295 }, { 296 Count: 1, 297 MetricName: "Datastore/statement/Postgres/products/INSERT", 298 Query: "INSERT INTO products (name, price) VALUES ($1, $2)", 299 TxnName: "WebTransaction/Go/hello", 300 TxnURL: "/hello", 301 DatabaseName: "", 302 Host: "", 303 PortPathOrID: "", 304 }, 305 }) 306 } 307 308 func TestSlowQueryMissingQuery(t *testing.T) { 309 cfgfn := func(cfg *Config) { 310 cfg.DatastoreTracer.SlowQuery.Threshold = 0 311 } 312 app := testApp(nil, cfgfn, t) 313 txn := app.StartTransaction("hello", nil, helloRequest) 314 s1 := DatastoreSegment{ 315 StartTime: StartSegmentNow(txn), 316 Product: DatastoreMySQL, 317 Collection: "users", 318 Operation: "INSERT", 319 } 320 s1.End() 321 txn.End() 322 323 app.ExpectSlowQueries(t, []internal.WantSlowQuery{{ 324 Count: 1, 325 MetricName: "Datastore/statement/MySQL/users/INSERT", 326 Query: "'INSERT' on 'users' using 'MySQL'", 327 TxnName: "WebTransaction/Go/hello", 328 TxnURL: "/hello", 329 DatabaseName: "", 330 Host: "", 331 PortPathOrID: "", 332 }}) 333 } 334 335 func TestSlowQueryMissingEverything(t *testing.T) { 336 cfgfn := func(cfg *Config) { 337 cfg.DatastoreTracer.SlowQuery.Threshold = 0 338 } 339 app := testApp(nil, cfgfn, t) 340 txn := app.StartTransaction("hello", nil, helloRequest) 341 s1 := DatastoreSegment{ 342 StartTime: StartSegmentNow(txn), 343 } 344 s1.End() 345 txn.End() 346 347 app.ExpectSlowQueries(t, []internal.WantSlowQuery{{ 348 Count: 1, 349 MetricName: "Datastore/operation/Unknown/other", 350 Query: "'other' on 'unknown' using 'Unknown'", 351 TxnName: "WebTransaction/Go/hello", 352 TxnURL: "/hello", 353 DatabaseName: "", 354 Host: "", 355 PortPathOrID: "", 356 }}) 357 scope := "WebTransaction/Go/hello" 358 app.ExpectMetrics(t, append([]internal.WantMetric{ 359 {Name: "Datastore/all", Scope: "", Forced: true, Data: nil}, 360 {Name: "Datastore/allWeb", Scope: "", Forced: true, Data: nil}, 361 {Name: "Datastore/Unknown/all", Scope: "", Forced: true, Data: nil}, 362 {Name: "Datastore/Unknown/allWeb", Scope: "", Forced: true, Data: nil}, 363 {Name: "Datastore/operation/Unknown/other", Scope: "", Forced: false, Data: nil}, 364 {Name: "Datastore/operation/Unknown/other", Scope: scope, Forced: false, Data: nil}, 365 }, webMetrics...)) 366 } 367 368 func TestSlowQueryWithQueryParameters(t *testing.T) { 369 cfgfn := func(cfg *Config) { 370 cfg.DatastoreTracer.SlowQuery.Threshold = 0 371 } 372 app := testApp(nil, cfgfn, t) 373 txn := app.StartTransaction("hello", nil, helloRequest) 374 params := map[string]interface{}{ 375 "str": "zap", 376 "int": 123, 377 } 378 s1 := DatastoreSegment{ 379 StartTime: StartSegmentNow(txn), 380 Product: DatastoreMySQL, 381 Collection: "users", 382 Operation: "INSERT", 383 ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)", 384 QueryParameters: params, 385 } 386 s1.End() 387 txn.End() 388 389 app.ExpectSlowQueries(t, []internal.WantSlowQuery{{ 390 Count: 1, 391 MetricName: "Datastore/statement/MySQL/users/INSERT", 392 Query: "INSERT INTO users (name, age) VALUES ($1, $2)", 393 TxnName: "WebTransaction/Go/hello", 394 TxnURL: "/hello", 395 DatabaseName: "", 396 Host: "", 397 PortPathOrID: "", 398 Params: params, 399 }}) 400 } 401 402 func TestSlowQueryHighSecurity(t *testing.T) { 403 cfgfn := func(cfg *Config) { 404 cfg.DatastoreTracer.SlowQuery.Threshold = 0 405 cfg.HighSecurity = true 406 } 407 app := testApp(nil, cfgfn, t) 408 txn := app.StartTransaction("hello", nil, helloRequest) 409 params := map[string]interface{}{ 410 "str": "zap", 411 "int": 123, 412 } 413 s1 := DatastoreSegment{ 414 StartTime: StartSegmentNow(txn), 415 Product: DatastoreMySQL, 416 Collection: "users", 417 Operation: "INSERT", 418 ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)", 419 QueryParameters: params, 420 } 421 s1.End() 422 txn.End() 423 424 app.ExpectSlowQueries(t, []internal.WantSlowQuery{{ 425 Count: 1, 426 MetricName: "Datastore/statement/MySQL/users/INSERT", 427 Query: "INSERT INTO users (name, age) VALUES ($1, $2)", 428 TxnName: "WebTransaction/Go/hello", 429 TxnURL: "/hello", 430 DatabaseName: "", 431 Host: "", 432 PortPathOrID: "", 433 Params: nil, 434 }}) 435 } 436 437 func TestSlowQuerySecurityPolicyFalse(t *testing.T) { 438 // When the record_sql security policy is set to false, sql parameters 439 // and the sql format string should be replaced. 440 cfgfn := func(cfg *Config) { 441 cfg.DatastoreTracer.SlowQuery.Threshold = 0 442 } 443 replyfn := func(reply *internal.ConnectReply) { 444 reply.SecurityPolicies.RecordSQL.SetEnabled(false) 445 } 446 app := testApp(replyfn, cfgfn, t) 447 txn := app.StartTransaction("hello", nil, helloRequest) 448 params := map[string]interface{}{ 449 "str": "zap", 450 "int": 123, 451 } 452 s1 := DatastoreSegment{ 453 StartTime: StartSegmentNow(txn), 454 Product: DatastoreMySQL, 455 Collection: "users", 456 Operation: "INSERT", 457 ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)", 458 QueryParameters: params, 459 } 460 s1.End() 461 txn.End() 462 463 app.ExpectSlowQueries(t, []internal.WantSlowQuery{{ 464 Count: 1, 465 MetricName: "Datastore/statement/MySQL/users/INSERT", 466 Query: "'INSERT' on 'users' using 'MySQL'", 467 TxnName: "WebTransaction/Go/hello", 468 TxnURL: "/hello", 469 DatabaseName: "", 470 Host: "", 471 PortPathOrID: "", 472 Params: nil, 473 }}) 474 } 475 476 func TestSlowQuerySecurityPolicyTrue(t *testing.T) { 477 // When the record_sql security policy is set to true, sql parameters 478 // should be omitted. 479 cfgfn := func(cfg *Config) { 480 cfg.DatastoreTracer.SlowQuery.Threshold = 0 481 } 482 replyfn := func(reply *internal.ConnectReply) { 483 reply.SecurityPolicies.RecordSQL.SetEnabled(true) 484 } 485 app := testApp(replyfn, cfgfn, t) 486 txn := app.StartTransaction("hello", nil, helloRequest) 487 params := map[string]interface{}{ 488 "str": "zap", 489 "int": 123, 490 } 491 s1 := DatastoreSegment{ 492 StartTime: StartSegmentNow(txn), 493 Product: DatastoreMySQL, 494 Collection: "users", 495 Operation: "INSERT", 496 ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)", 497 QueryParameters: params, 498 } 499 s1.End() 500 txn.End() 501 502 app.ExpectSlowQueries(t, []internal.WantSlowQuery{{ 503 Count: 1, 504 MetricName: "Datastore/statement/MySQL/users/INSERT", 505 Query: "INSERT INTO users (name, age) VALUES ($1, $2)", 506 TxnName: "WebTransaction/Go/hello", 507 TxnURL: "/hello", 508 DatabaseName: "", 509 Host: "", 510 PortPathOrID: "", 511 Params: nil, 512 }}) 513 } 514 515 func TestSlowQueryInvalidParameters(t *testing.T) { 516 cfgfn := func(cfg *Config) { 517 cfg.DatastoreTracer.SlowQuery.Threshold = 0 518 } 519 app := testApp(nil, cfgfn, t) 520 txn := app.StartTransaction("hello", nil, helloRequest) 521 params := map[string]interface{}{ 522 "str": "zap", 523 "int": 123, 524 "invalid_value": struct{}{}, 525 strings.Repeat("key-too-long", 100): 1, 526 "long-key": strings.Repeat("A", 300), 527 } 528 s1 := DatastoreSegment{ 529 StartTime: StartSegmentNow(txn), 530 Product: DatastoreMySQL, 531 Collection: "users", 532 Operation: "INSERT", 533 ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)", 534 QueryParameters: params, 535 } 536 s1.End() 537 txn.End() 538 539 app.ExpectSlowQueries(t, []internal.WantSlowQuery{{ 540 Count: 1, 541 MetricName: "Datastore/statement/MySQL/users/INSERT", 542 Query: "INSERT INTO users (name, age) VALUES ($1, $2)", 543 TxnName: "WebTransaction/Go/hello", 544 TxnURL: "/hello", 545 DatabaseName: "", 546 Host: "", 547 PortPathOrID: "", 548 Params: map[string]interface{}{ 549 "str": "zap", 550 "int": 123, 551 "long-key": strings.Repeat("A", 255), 552 }, 553 }}) 554 } 555 556 func TestSlowQueryParametersDisabled(t *testing.T) { 557 cfgfn := func(cfg *Config) { 558 cfg.DatastoreTracer.SlowQuery.Threshold = 0 559 cfg.DatastoreTracer.QueryParameters.Enabled = false 560 } 561 app := testApp(nil, cfgfn, t) 562 txn := app.StartTransaction("hello", nil, helloRequest) 563 params := map[string]interface{}{ 564 "str": "zap", 565 "int": 123, 566 } 567 s1 := DatastoreSegment{ 568 StartTime: StartSegmentNow(txn), 569 Product: DatastoreMySQL, 570 Collection: "users", 571 Operation: "INSERT", 572 ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)", 573 QueryParameters: params, 574 } 575 s1.End() 576 txn.End() 577 578 app.ExpectSlowQueries(t, []internal.WantSlowQuery{{ 579 Count: 1, 580 MetricName: "Datastore/statement/MySQL/users/INSERT", 581 Query: "INSERT INTO users (name, age) VALUES ($1, $2)", 582 TxnName: "WebTransaction/Go/hello", 583 TxnURL: "/hello", 584 DatabaseName: "", 585 Host: "", 586 PortPathOrID: "", 587 Params: nil, 588 }}) 589 } 590 591 func TestSlowQueryInstanceDisabled(t *testing.T) { 592 cfgfn := func(cfg *Config) { 593 cfg.DatastoreTracer.SlowQuery.Threshold = 0 594 cfg.DatastoreTracer.InstanceReporting.Enabled = false 595 } 596 app := testApp(nil, cfgfn, t) 597 txn := app.StartTransaction("hello", nil, helloRequest) 598 s1 := DatastoreSegment{ 599 StartTime: StartSegmentNow(txn), 600 Product: DatastoreMySQL, 601 Collection: "users", 602 Operation: "INSERT", 603 ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)", 604 Host: "db-server-1", 605 } 606 s1.End() 607 txn.End() 608 609 app.ExpectSlowQueries(t, []internal.WantSlowQuery{{ 610 Count: 1, 611 MetricName: "Datastore/statement/MySQL/users/INSERT", 612 Query: "INSERT INTO users (name, age) VALUES ($1, $2)", 613 TxnName: "WebTransaction/Go/hello", 614 TxnURL: "/hello", 615 DatabaseName: "", 616 Host: "", 617 PortPathOrID: "", 618 }}) 619 scope := "WebTransaction/Go/hello" 620 app.ExpectMetrics(t, append([]internal.WantMetric{ 621 {Name: "Datastore/all", Scope: "", Forced: true, Data: nil}, 622 {Name: "Datastore/allWeb", Scope: "", Forced: true, Data: nil}, 623 {Name: "Datastore/MySQL/all", Scope: "", Forced: true, Data: nil}, 624 {Name: "Datastore/MySQL/allWeb", Scope: "", Forced: true, Data: nil}, 625 {Name: "Datastore/operation/MySQL/INSERT", Scope: "", Forced: false, Data: nil}, 626 {Name: "Datastore/statement/MySQL/users/INSERT", Scope: "", Forced: false, Data: nil}, 627 {Name: "Datastore/statement/MySQL/users/INSERT", Scope: scope, Forced: false, Data: nil}, 628 }, webMetrics...)) 629 } 630 631 func TestSlowQueryInstanceDisabledLocalhost(t *testing.T) { 632 cfgfn := func(cfg *Config) { 633 cfg.DatastoreTracer.SlowQuery.Threshold = 0 634 cfg.DatastoreTracer.InstanceReporting.Enabled = false 635 } 636 app := testApp(nil, cfgfn, t) 637 txn := app.StartTransaction("hello", nil, helloRequest) 638 s1 := DatastoreSegment{ 639 StartTime: StartSegmentNow(txn), 640 Product: DatastoreMySQL, 641 Collection: "users", 642 Operation: "INSERT", 643 ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)", 644 Host: "localhost", 645 PortPathOrID: "3306", 646 } 647 s1.End() 648 txn.End() 649 650 app.ExpectSlowQueries(t, []internal.WantSlowQuery{{ 651 Count: 1, 652 MetricName: "Datastore/statement/MySQL/users/INSERT", 653 Query: "INSERT INTO users (name, age) VALUES ($1, $2)", 654 TxnName: "WebTransaction/Go/hello", 655 TxnURL: "/hello", 656 DatabaseName: "", 657 Host: "", 658 PortPathOrID: "", 659 }}) 660 scope := "WebTransaction/Go/hello" 661 app.ExpectMetrics(t, append([]internal.WantMetric{ 662 {Name: "Datastore/all", Scope: "", Forced: true, Data: nil}, 663 {Name: "Datastore/allWeb", Scope: "", Forced: true, Data: nil}, 664 {Name: "Datastore/MySQL/all", Scope: "", Forced: true, Data: nil}, 665 {Name: "Datastore/MySQL/allWeb", Scope: "", Forced: true, Data: nil}, 666 {Name: "Datastore/operation/MySQL/INSERT", Scope: "", Forced: false, Data: nil}, 667 {Name: "Datastore/statement/MySQL/users/INSERT", Scope: "", Forced: false, Data: nil}, 668 {Name: "Datastore/statement/MySQL/users/INSERT", Scope: scope, Forced: false, Data: nil}, 669 }, webMetrics...)) 670 } 671 672 func TestSlowQueryDatabaseNameDisabled(t *testing.T) { 673 cfgfn := func(cfg *Config) { 674 cfg.DatastoreTracer.SlowQuery.Threshold = 0 675 cfg.DatastoreTracer.DatabaseNameReporting.Enabled = false 676 } 677 app := testApp(nil, cfgfn, t) 678 txn := app.StartTransaction("hello", nil, helloRequest) 679 s1 := DatastoreSegment{ 680 StartTime: StartSegmentNow(txn), 681 Product: DatastoreMySQL, 682 Collection: "users", 683 Operation: "INSERT", 684 ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)", 685 DatabaseName: "db-server-1", 686 } 687 s1.End() 688 txn.End() 689 690 app.ExpectSlowQueries(t, []internal.WantSlowQuery{{ 691 Count: 1, 692 MetricName: "Datastore/statement/MySQL/users/INSERT", 693 Query: "INSERT INTO users (name, age) VALUES ($1, $2)", 694 TxnName: "WebTransaction/Go/hello", 695 TxnURL: "/hello", 696 DatabaseName: "", 697 Host: "", 698 PortPathOrID: "", 699 }}) 700 } 701 702 func TestDatastoreAPICrossAgent(t *testing.T) { 703 var testcases []struct { 704 TestName string `json:"test_name"` 705 Input struct { 706 Parameters struct { 707 Product string `json:"product"` 708 Collection string `json:"collection"` 709 Operation string `json:"operation"` 710 Host string `json:"host"` 711 PortPathOrID string `json:"port_path_or_id"` 712 DatabaseName string `json:"database_name"` 713 } `json:"parameters"` 714 IsWeb bool `json:"is_web"` 715 SystemHostname string `json:"system_hostname"` 716 Configuration struct { 717 InstanceEnabled bool `json:"datastore_tracer.instance_reporting.enabled"` 718 DatabaseEnabled bool `json:"datastore_tracer.database_name_reporting.enabled"` 719 } 720 } 721 Expectation struct { 722 MetricsScoped []string `json:"metrics_scoped"` 723 MetricsUnscoped []string `json:"metrics_unscoped"` 724 Trace struct { 725 MetricName string `json:"metric_name"` 726 Host string `json:"host"` 727 PortPathOrID string `json:"port_path_or_id"` 728 DatabaseName string `json:"database_name"` 729 } `json:"transaction_segment_and_slow_query_trace"` 730 } 731 } 732 733 err := crossagent.ReadJSON("datastores/datastore_api.json", &testcases) 734 if err != nil { 735 t.Fatal(err) 736 } 737 738 for _, tc := range testcases { 739 query := "my query" 740 cfgfn := func(cfg *Config) { 741 cfg.DatastoreTracer.SlowQuery.Threshold = 0 742 cfg.DatastoreTracer.InstanceReporting.Enabled = 743 tc.Input.Configuration.InstanceEnabled 744 cfg.DatastoreTracer.DatabaseNameReporting.Enabled = 745 tc.Input.Configuration.DatabaseEnabled 746 } 747 app := testApp(nil, cfgfn, t) 748 var txn Transaction 749 var txnURL string 750 if tc.Input.IsWeb { 751 txnURL = helloPath 752 txn = app.StartTransaction("hello", nil, helloRequest) 753 } else { 754 txn = app.StartTransaction("hello", nil, nil) 755 } 756 ds := DatastoreSegment{ 757 StartTime: StartSegmentNow(txn), 758 Product: DatastoreProduct(tc.Input.Parameters.Product), 759 Operation: tc.Input.Parameters.Operation, 760 Collection: tc.Input.Parameters.Collection, 761 PortPathOrID: tc.Input.Parameters.PortPathOrID, 762 Host: tc.Input.Parameters.Host, 763 DatabaseName: tc.Input.Parameters.DatabaseName, 764 ParameterizedQuery: query, 765 } 766 ds.End() 767 txn.End() 768 769 var metrics []internal.WantMetric 770 var scope string 771 if tc.Input.IsWeb { 772 scope = "WebTransaction/Go/hello" 773 metrics = append([]internal.WantMetric{}, webMetrics...) 774 } else { 775 scope = "OtherTransaction/Go/hello" 776 metrics = append([]internal.WantMetric{}, backgroundMetrics...) 777 } 778 779 for _, m := range tc.Expectation.MetricsScoped { 780 metrics = append(metrics, internal.WantMetric{ 781 Name: m, Scope: scope, Forced: nil, Data: nil, 782 }) 783 } 784 for _, m := range tc.Expectation.MetricsUnscoped { 785 metrics = append(metrics, internal.WantMetric{ 786 Name: m, Scope: "", Forced: nil, Data: nil, 787 }) 788 } 789 790 expectTraceHost := tc.Expectation.Trace.Host 791 if tc.Input.SystemHostname != "" { 792 for i := range metrics { 793 metrics[i].Name = strings.Replace(metrics[i].Name, 794 tc.Input.SystemHostname, 795 internal.ThisHost, -1) 796 } 797 expectTraceHost = strings.Replace(expectTraceHost, 798 tc.Input.SystemHostname, 799 internal.ThisHost, -1) 800 } 801 802 tt := internal.ExtendValidator(t, tc.TestName) 803 app.ExpectMetrics(tt, metrics) 804 app.ExpectSlowQueries(tt, []internal.WantSlowQuery{{ 805 Count: 1, 806 MetricName: tc.Expectation.Trace.MetricName, 807 TxnName: scope, 808 DatabaseName: tc.Expectation.Trace.DatabaseName, 809 Host: expectTraceHost, 810 PortPathOrID: tc.Expectation.Trace.PortPathOrID, 811 TxnURL: txnURL, 812 Query: query, 813 }}) 814 } 815 } 816 817 func TestSlowQueryParamsInvalid(t *testing.T) { 818 cfgfn := func(cfg *Config) { 819 cfg.DatastoreTracer.SlowQuery.Threshold = 0 820 } 821 app := testApp(nil, cfgfn, t) 822 txn := app.StartTransaction("hello", nil, helloRequest) 823 s1 := DatastoreSegment{ 824 StartTime: StartSegmentNow(txn), 825 Product: DatastoreMySQL, 826 Collection: "users", 827 Operation: "INSERT", 828 ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)", 829 QueryParameters: map[string]interface{}{ 830 "cookies": []string{"chocolate", "sugar", "oatmeal"}, 831 "number": 5, 832 }, 833 } 834 err := s1.End() 835 if nil == err { 836 t.Error("error should have been returned") 837 } 838 txn.End() 839 840 app.ExpectSlowQueries(t, []internal.WantSlowQuery{{ 841 Count: 1, 842 MetricName: "Datastore/statement/MySQL/users/INSERT", 843 Query: "INSERT INTO users (name, age) VALUES ($1, $2)", 844 TxnName: "WebTransaction/Go/hello", 845 TxnURL: "/hello", 846 DatabaseName: "", 847 Host: "", 848 PortPathOrID: "", 849 Params: map[string]interface{}{"number": 5}, 850 }}) 851 }