diff --git a/.chloggen/add-stored-procedure-columns-to-events.yaml b/.chloggen/add-stored-procedure-columns-to-events.yaml
new file mode 100644
index 0000000000000..60a138e7d2a9d
--- /dev/null
+++ b/.chloggen/add-stored-procedure-columns-to-events.yaml
@@ -0,0 +1,28 @@
+# Use this changelog template to create an entry for release notes.
+
+# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
+change_type: enhancement
+
+# The name of the component, or a single word describing the area of concern, (e.g. receiver/filelog)
+component: receiver/sqlserver
+
+# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
+note: Add the `sqlserver.procedure_id` and `sqlserver.procedure_name` attributes to TopQuery and Sample Events
+
+# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
+issues: [44656]
+
+# (Optional) One or more lines of additional information to render under the primary note.
+# These lines will be padded with 2 spaces and then inserted directly into the document.
+# Use pipe (|) for multiline entries.
+subtext: Refined query and reported events to include stored procedure information when applicable.
+ Additionally, the maximum number of active queries reported by default has been increased from 200 to 250 to account for record deaggregation introduced by this change, ensuring the effective limit remains consistent with the previous 200-query baseline.
+
+# If your change doesn't affect end users or the exported elements of any package,
+# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
+# Optional: The change log or logs in which this entry should be included.
+# e.g. '[user]' or '[user, api]'
+# Include 'user' if the change is relevant to end users.
+# Include 'api' if there is a change to a library API.
+# Default: '[user]'
+change_logs: [user]
diff --git a/receiver/sqlserverreceiver/README.md b/receiver/sqlserverreceiver/README.md
index 2caa7458dfc4c..e97c46d4896d2 100644
--- a/receiver/sqlserverreceiver/README.md
+++ b/receiver/sqlserverreceiver/README.md
@@ -61,7 +61,7 @@ sqlserver:
top_query_collection: # this collection exports the most expensive queries as logs
lookback_time: 60s # which time window should we look for the top queries
max_query_sample_count: 1000 # maximum number query we store in cache for top queries.
- top_query_count: 200 # The maximum number of active queries to report in a single run.
+ top_query_count: 250 # The maximum number of active queries to report in a single run.
collection_interval: 60s # collection interval for top query collection specifically
query_sample_collection: # this collection exports the currently (relate to the query time) executing queries as logs
max_rows_per_query: 100 # the maximum number of samples to return for one single query.
@@ -90,7 +90,7 @@ Top-Query collection specific options (only useful when top-query collection are
- `lookback_time` (optional, example = `60s`, default = `2 * collection_interval`): The time window (in second) in which to query for top queries.
- Queries that were finished execution outside the lookback window are not included in the collection. Increasing the lookback window (in seconds) will be useful for capturing long-running queries.
- `max_query_sample_count` (optional, example = `5000`, default = `1000`): The maximum number of records to fetch in a single run.
-- `top_query_count`: (optional, example = `100`, default = `200`): The maximum number of active queries to report (to the next consumer) in a single run.
+- `top_query_count`: (optional, example = `100`, default = `250`): The maximum number of active queries to report (to the next consumer) in a single run.
- `collection_interval`: (optional, default = `60s`): The interval at which top queries should be emitted by this receiver.
- This value can only guarantee that the top queries are collected at most once in this interval.
- For instance, you have global `collection_interval` as `10s` and `top_query_collection.collection_interval` as `60s`.
diff --git a/receiver/sqlserverreceiver/documentation.md b/receiver/sqlserverreceiver/documentation.md
index a018477cf1617..55fb14a46e8ae 100644
--- a/receiver/sqlserverreceiver/documentation.md
+++ b/receiver/sqlserverreceiver/documentation.md
@@ -606,6 +606,8 @@ query sample
| sqlserver.wait_type | Type of wait encountered by the request. Empty if none. | Any Str |
| sqlserver.writes | Number of writes performed by the query. | Any Int |
| user.name | Login name associated with the SQL Server session. | Any Str |
+| sqlserver.procedure_id | The SQLServer ID of the stored procedure, if any | Any Str |
+| sqlserver.procedure_name | The name of the stored procedure, if any | Any Str |
### db.server.top_query
@@ -630,6 +632,8 @@ top query
| server.address | The network address of the server hosting the database. | Any Str |
| server.port | The port number on which the server is listening. | Any Int |
| db.system.name | The database management system (DBMS) product as identified by the client instrumentation. | Any Str |
+| sqlserver.procedure_id | The SQLServer ID of the stored procedure, if any | Any Str |
+| sqlserver.procedure_name | The name of the stored procedure, if any | Any Str |
## Resource Attributes
diff --git a/receiver/sqlserverreceiver/factory.go b/receiver/sqlserverreceiver/factory.go
index e2079934fc7a9..faa73392b8cff 100644
--- a/receiver/sqlserverreceiver/factory.go
+++ b/receiver/sqlserverreceiver/factory.go
@@ -57,7 +57,7 @@ func createDefaultConfig() component.Config {
},
TopQueryCollection: TopQueryCollection{
MaxQuerySampleCount: 1000,
- TopQueryCount: 200,
+ TopQueryCount: 250,
CollectionInterval: time.Minute,
},
}
diff --git a/receiver/sqlserverreceiver/factory_test.go b/receiver/sqlserverreceiver/factory_test.go
index 27300a46fe0f3..228d9b8236430 100644
--- a/receiver/sqlserverreceiver/factory_test.go
+++ b/receiver/sqlserverreceiver/factory_test.go
@@ -44,7 +44,7 @@ func TestFactory(t *testing.T) {
},
TopQueryCollection: TopQueryCollection{
MaxQuerySampleCount: 1000,
- TopQueryCount: 200,
+ TopQueryCount: 250,
CollectionInterval: time.Minute,
},
QuerySample: QuerySample{
diff --git a/receiver/sqlserverreceiver/internal/metadata/generated_logs.go b/receiver/sqlserverreceiver/internal/metadata/generated_logs.go
index 2224f758a2990..0d7489892146a 100644
--- a/receiver/sqlserverreceiver/internal/metadata/generated_logs.go
+++ b/receiver/sqlserverreceiver/internal/metadata/generated_logs.go
@@ -18,7 +18,7 @@ type eventDbServerQuerySample struct {
config EventConfig // event config provided by user.
}
-func (e *eventDbServerQuerySample) recordEvent(ctx context.Context, timestamp pcommon.Timestamp, clientAddressAttributeValue string, clientPortAttributeValue int64, dbNamespaceAttributeValue string, dbQueryTextAttributeValue string, dbSystemNameAttributeValue string, networkPeerAddressAttributeValue string, networkPeerPortAttributeValue int64, sqlserverBlockingSessionIDAttributeValue int64, sqlserverContextInfoAttributeValue string, sqlserverCommandAttributeValue string, sqlserverCPUTimeAttributeValue float64, sqlserverDeadlockPriorityAttributeValue int64, sqlserverEstimatedCompletionTimeAttributeValue float64, sqlserverLockTimeoutAttributeValue float64, sqlserverLogicalReadsAttributeValue int64, sqlserverOpenTransactionCountAttributeValue int64, sqlserverPercentCompleteAttributeValue float64, sqlserverQueryHashAttributeValue string, sqlserverQueryPlanHashAttributeValue string, sqlserverQueryStartAttributeValue string, sqlserverReadsAttributeValue int64, sqlserverRequestStatusAttributeValue string, sqlserverRowCountAttributeValue int64, sqlserverSessionIDAttributeValue int64, sqlserverSessionStatusAttributeValue string, sqlserverTotalElapsedTimeAttributeValue float64, sqlserverTransactionIDAttributeValue int64, sqlserverTransactionIsolationLevelAttributeValue int64, sqlserverWaitResourceAttributeValue string, sqlserverWaitTimeAttributeValue float64, sqlserverWaitTypeAttributeValue string, sqlserverWritesAttributeValue int64, userNameAttributeValue string) {
+func (e *eventDbServerQuerySample) recordEvent(ctx context.Context, timestamp pcommon.Timestamp, clientAddressAttributeValue string, clientPortAttributeValue int64, dbNamespaceAttributeValue string, dbQueryTextAttributeValue string, dbSystemNameAttributeValue string, networkPeerAddressAttributeValue string, networkPeerPortAttributeValue int64, sqlserverBlockingSessionIDAttributeValue int64, sqlserverContextInfoAttributeValue string, sqlserverCommandAttributeValue string, sqlserverCPUTimeAttributeValue float64, sqlserverDeadlockPriorityAttributeValue int64, sqlserverEstimatedCompletionTimeAttributeValue float64, sqlserverLockTimeoutAttributeValue float64, sqlserverLogicalReadsAttributeValue int64, sqlserverOpenTransactionCountAttributeValue int64, sqlserverPercentCompleteAttributeValue float64, sqlserverQueryHashAttributeValue string, sqlserverQueryPlanHashAttributeValue string, sqlserverQueryStartAttributeValue string, sqlserverReadsAttributeValue int64, sqlserverRequestStatusAttributeValue string, sqlserverRowCountAttributeValue int64, sqlserverSessionIDAttributeValue int64, sqlserverSessionStatusAttributeValue string, sqlserverTotalElapsedTimeAttributeValue float64, sqlserverTransactionIDAttributeValue int64, sqlserverTransactionIsolationLevelAttributeValue int64, sqlserverWaitResourceAttributeValue string, sqlserverWaitTimeAttributeValue float64, sqlserverWaitTypeAttributeValue string, sqlserverWritesAttributeValue int64, userNameAttributeValue string, sqlserverProcedureIDAttributeValue string, sqlserverProcedureNameAttributeValue string) {
if !e.config.Enabled {
return
}
@@ -63,6 +63,8 @@ func (e *eventDbServerQuerySample) recordEvent(ctx context.Context, timestamp pc
dp.Attributes().PutStr("sqlserver.wait_type", sqlserverWaitTypeAttributeValue)
dp.Attributes().PutInt("sqlserver.writes", sqlserverWritesAttributeValue)
dp.Attributes().PutStr("user.name", userNameAttributeValue)
+ dp.Attributes().PutStr("sqlserver.procedure_id", sqlserverProcedureIDAttributeValue)
+ dp.Attributes().PutStr("sqlserver.procedure_name", sqlserverProcedureNameAttributeValue)
}
@@ -86,7 +88,7 @@ type eventDbServerTopQuery struct {
config EventConfig // event config provided by user.
}
-func (e *eventDbServerTopQuery) recordEvent(ctx context.Context, timestamp pcommon.Timestamp, sqlserverTotalWorkerTimeAttributeValue float64, dbQueryTextAttributeValue string, sqlserverExecutionCountAttributeValue int64, sqlserverTotalLogicalReadsAttributeValue int64, sqlserverTotalLogicalWritesAttributeValue int64, sqlserverTotalPhysicalReadsAttributeValue int64, sqlserverQueryHashAttributeValue string, sqlserverQueryPlanAttributeValue string, sqlserverQueryPlanHashAttributeValue string, sqlserverTotalRowsAttributeValue int64, sqlserverTotalElapsedTimeAttributeValue float64, sqlserverTotalGrantKbAttributeValue int64, serverAddressAttributeValue string, serverPortAttributeValue int64, dbSystemNameAttributeValue string) {
+func (e *eventDbServerTopQuery) recordEvent(ctx context.Context, timestamp pcommon.Timestamp, sqlserverTotalWorkerTimeAttributeValue float64, dbQueryTextAttributeValue string, sqlserverExecutionCountAttributeValue int64, sqlserverTotalLogicalReadsAttributeValue int64, sqlserverTotalLogicalWritesAttributeValue int64, sqlserverTotalPhysicalReadsAttributeValue int64, sqlserverQueryHashAttributeValue string, sqlserverQueryPlanAttributeValue string, sqlserverQueryPlanHashAttributeValue string, sqlserverTotalRowsAttributeValue int64, sqlserverTotalElapsedTimeAttributeValue float64, sqlserverTotalGrantKbAttributeValue int64, serverAddressAttributeValue string, serverPortAttributeValue int64, dbSystemNameAttributeValue string, sqlserverProcedureIDAttributeValue string, sqlserverProcedureNameAttributeValue string) {
if !e.config.Enabled {
return
}
@@ -113,6 +115,8 @@ func (e *eventDbServerTopQuery) recordEvent(ctx context.Context, timestamp pcomm
dp.Attributes().PutStr("server.address", serverAddressAttributeValue)
dp.Attributes().PutInt("server.port", serverPortAttributeValue)
dp.Attributes().PutStr("db.system.name", dbSystemNameAttributeValue)
+ dp.Attributes().PutStr("sqlserver.procedure_id", sqlserverProcedureIDAttributeValue)
+ dp.Attributes().PutStr("sqlserver.procedure_name", sqlserverProcedureNameAttributeValue)
}
@@ -284,11 +288,11 @@ func (lb *LogsBuilder) Emit(options ...ResourceLogsOption) plog.Logs {
}
// RecordDbServerQuerySampleEvent adds a log record of db.server.query_sample event.
-func (lb *LogsBuilder) RecordDbServerQuerySampleEvent(ctx context.Context, timestamp pcommon.Timestamp, clientAddressAttributeValue string, clientPortAttributeValue int64, dbNamespaceAttributeValue string, dbQueryTextAttributeValue string, dbSystemNameAttributeValue string, networkPeerAddressAttributeValue string, networkPeerPortAttributeValue int64, sqlserverBlockingSessionIDAttributeValue int64, sqlserverContextInfoAttributeValue string, sqlserverCommandAttributeValue string, sqlserverCPUTimeAttributeValue float64, sqlserverDeadlockPriorityAttributeValue int64, sqlserverEstimatedCompletionTimeAttributeValue float64, sqlserverLockTimeoutAttributeValue float64, sqlserverLogicalReadsAttributeValue int64, sqlserverOpenTransactionCountAttributeValue int64, sqlserverPercentCompleteAttributeValue float64, sqlserverQueryHashAttributeValue string, sqlserverQueryPlanHashAttributeValue string, sqlserverQueryStartAttributeValue string, sqlserverReadsAttributeValue int64, sqlserverRequestStatusAttributeValue string, sqlserverRowCountAttributeValue int64, sqlserverSessionIDAttributeValue int64, sqlserverSessionStatusAttributeValue string, sqlserverTotalElapsedTimeAttributeValue float64, sqlserverTransactionIDAttributeValue int64, sqlserverTransactionIsolationLevelAttributeValue int64, sqlserverWaitResourceAttributeValue string, sqlserverWaitTimeAttributeValue float64, sqlserverWaitTypeAttributeValue string, sqlserverWritesAttributeValue int64, userNameAttributeValue string) {
- lb.eventDbServerQuerySample.recordEvent(ctx, timestamp, clientAddressAttributeValue, clientPortAttributeValue, dbNamespaceAttributeValue, dbQueryTextAttributeValue, dbSystemNameAttributeValue, networkPeerAddressAttributeValue, networkPeerPortAttributeValue, sqlserverBlockingSessionIDAttributeValue, sqlserverContextInfoAttributeValue, sqlserverCommandAttributeValue, sqlserverCPUTimeAttributeValue, sqlserverDeadlockPriorityAttributeValue, sqlserverEstimatedCompletionTimeAttributeValue, sqlserverLockTimeoutAttributeValue, sqlserverLogicalReadsAttributeValue, sqlserverOpenTransactionCountAttributeValue, sqlserverPercentCompleteAttributeValue, sqlserverQueryHashAttributeValue, sqlserverQueryPlanHashAttributeValue, sqlserverQueryStartAttributeValue, sqlserverReadsAttributeValue, sqlserverRequestStatusAttributeValue, sqlserverRowCountAttributeValue, sqlserverSessionIDAttributeValue, sqlserverSessionStatusAttributeValue, sqlserverTotalElapsedTimeAttributeValue, sqlserverTransactionIDAttributeValue, sqlserverTransactionIsolationLevelAttributeValue, sqlserverWaitResourceAttributeValue, sqlserverWaitTimeAttributeValue, sqlserverWaitTypeAttributeValue, sqlserverWritesAttributeValue, userNameAttributeValue)
+func (lb *LogsBuilder) RecordDbServerQuerySampleEvent(ctx context.Context, timestamp pcommon.Timestamp, clientAddressAttributeValue string, clientPortAttributeValue int64, dbNamespaceAttributeValue string, dbQueryTextAttributeValue string, dbSystemNameAttributeValue string, networkPeerAddressAttributeValue string, networkPeerPortAttributeValue int64, sqlserverBlockingSessionIDAttributeValue int64, sqlserverContextInfoAttributeValue string, sqlserverCommandAttributeValue string, sqlserverCPUTimeAttributeValue float64, sqlserverDeadlockPriorityAttributeValue int64, sqlserverEstimatedCompletionTimeAttributeValue float64, sqlserverLockTimeoutAttributeValue float64, sqlserverLogicalReadsAttributeValue int64, sqlserverOpenTransactionCountAttributeValue int64, sqlserverPercentCompleteAttributeValue float64, sqlserverQueryHashAttributeValue string, sqlserverQueryPlanHashAttributeValue string, sqlserverQueryStartAttributeValue string, sqlserverReadsAttributeValue int64, sqlserverRequestStatusAttributeValue string, sqlserverRowCountAttributeValue int64, sqlserverSessionIDAttributeValue int64, sqlserverSessionStatusAttributeValue string, sqlserverTotalElapsedTimeAttributeValue float64, sqlserverTransactionIDAttributeValue int64, sqlserverTransactionIsolationLevelAttributeValue int64, sqlserverWaitResourceAttributeValue string, sqlserverWaitTimeAttributeValue float64, sqlserverWaitTypeAttributeValue string, sqlserverWritesAttributeValue int64, userNameAttributeValue string, sqlserverProcedureIDAttributeValue string, sqlserverProcedureNameAttributeValue string) {
+ lb.eventDbServerQuerySample.recordEvent(ctx, timestamp, clientAddressAttributeValue, clientPortAttributeValue, dbNamespaceAttributeValue, dbQueryTextAttributeValue, dbSystemNameAttributeValue, networkPeerAddressAttributeValue, networkPeerPortAttributeValue, sqlserverBlockingSessionIDAttributeValue, sqlserverContextInfoAttributeValue, sqlserverCommandAttributeValue, sqlserverCPUTimeAttributeValue, sqlserverDeadlockPriorityAttributeValue, sqlserverEstimatedCompletionTimeAttributeValue, sqlserverLockTimeoutAttributeValue, sqlserverLogicalReadsAttributeValue, sqlserverOpenTransactionCountAttributeValue, sqlserverPercentCompleteAttributeValue, sqlserverQueryHashAttributeValue, sqlserverQueryPlanHashAttributeValue, sqlserverQueryStartAttributeValue, sqlserverReadsAttributeValue, sqlserverRequestStatusAttributeValue, sqlserverRowCountAttributeValue, sqlserverSessionIDAttributeValue, sqlserverSessionStatusAttributeValue, sqlserverTotalElapsedTimeAttributeValue, sqlserverTransactionIDAttributeValue, sqlserverTransactionIsolationLevelAttributeValue, sqlserverWaitResourceAttributeValue, sqlserverWaitTimeAttributeValue, sqlserverWaitTypeAttributeValue, sqlserverWritesAttributeValue, userNameAttributeValue, sqlserverProcedureIDAttributeValue, sqlserverProcedureNameAttributeValue)
}
// RecordDbServerTopQueryEvent adds a log record of db.server.top_query event.
-func (lb *LogsBuilder) RecordDbServerTopQueryEvent(ctx context.Context, timestamp pcommon.Timestamp, sqlserverTotalWorkerTimeAttributeValue float64, dbQueryTextAttributeValue string, sqlserverExecutionCountAttributeValue int64, sqlserverTotalLogicalReadsAttributeValue int64, sqlserverTotalLogicalWritesAttributeValue int64, sqlserverTotalPhysicalReadsAttributeValue int64, sqlserverQueryHashAttributeValue string, sqlserverQueryPlanAttributeValue string, sqlserverQueryPlanHashAttributeValue string, sqlserverTotalRowsAttributeValue int64, sqlserverTotalElapsedTimeAttributeValue float64, sqlserverTotalGrantKbAttributeValue int64, serverAddressAttributeValue string, serverPortAttributeValue int64, dbSystemNameAttributeValue string) {
- lb.eventDbServerTopQuery.recordEvent(ctx, timestamp, sqlserverTotalWorkerTimeAttributeValue, dbQueryTextAttributeValue, sqlserverExecutionCountAttributeValue, sqlserverTotalLogicalReadsAttributeValue, sqlserverTotalLogicalWritesAttributeValue, sqlserverTotalPhysicalReadsAttributeValue, sqlserverQueryHashAttributeValue, sqlserverQueryPlanAttributeValue, sqlserverQueryPlanHashAttributeValue, sqlserverTotalRowsAttributeValue, sqlserverTotalElapsedTimeAttributeValue, sqlserverTotalGrantKbAttributeValue, serverAddressAttributeValue, serverPortAttributeValue, dbSystemNameAttributeValue)
+func (lb *LogsBuilder) RecordDbServerTopQueryEvent(ctx context.Context, timestamp pcommon.Timestamp, sqlserverTotalWorkerTimeAttributeValue float64, dbQueryTextAttributeValue string, sqlserverExecutionCountAttributeValue int64, sqlserverTotalLogicalReadsAttributeValue int64, sqlserverTotalLogicalWritesAttributeValue int64, sqlserverTotalPhysicalReadsAttributeValue int64, sqlserverQueryHashAttributeValue string, sqlserverQueryPlanAttributeValue string, sqlserverQueryPlanHashAttributeValue string, sqlserverTotalRowsAttributeValue int64, sqlserverTotalElapsedTimeAttributeValue float64, sqlserverTotalGrantKbAttributeValue int64, serverAddressAttributeValue string, serverPortAttributeValue int64, dbSystemNameAttributeValue string, sqlserverProcedureIDAttributeValue string, sqlserverProcedureNameAttributeValue string) {
+ lb.eventDbServerTopQuery.recordEvent(ctx, timestamp, sqlserverTotalWorkerTimeAttributeValue, dbQueryTextAttributeValue, sqlserverExecutionCountAttributeValue, sqlserverTotalLogicalReadsAttributeValue, sqlserverTotalLogicalWritesAttributeValue, sqlserverTotalPhysicalReadsAttributeValue, sqlserverQueryHashAttributeValue, sqlserverQueryPlanAttributeValue, sqlserverQueryPlanHashAttributeValue, sqlserverTotalRowsAttributeValue, sqlserverTotalElapsedTimeAttributeValue, sqlserverTotalGrantKbAttributeValue, serverAddressAttributeValue, serverPortAttributeValue, dbSystemNameAttributeValue, sqlserverProcedureIDAttributeValue, sqlserverProcedureNameAttributeValue)
}
diff --git a/receiver/sqlserverreceiver/internal/metadata/generated_logs_test.go b/receiver/sqlserverreceiver/internal/metadata/generated_logs_test.go
index 53531d2d36903..7038dc4bf960c 100644
--- a/receiver/sqlserverreceiver/internal/metadata/generated_logs_test.go
+++ b/receiver/sqlserverreceiver/internal/metadata/generated_logs_test.go
@@ -135,10 +135,10 @@ func TestLogsBuilder(t *testing.T) {
allEventsCount := 0
allEventsCount++
- lb.RecordDbServerQuerySampleEvent(ctx, timestamp, "client.address-val", 11, "db.namespace-val", "db.query.text-val", "db.system.name-val", "network.peer.address-val", 17, 29, "sqlserver.context_info-val", "sqlserver.command-val", 18.100000, 27, 35.100000, 22.100000, 23, 32, 26.100000, "sqlserver.query_hash-val", "sqlserver.query_plan_hash-val", "sqlserver.query_start-val", 15, "sqlserver.request_status-val", 19, 20, "sqlserver.session_status-val", 28.100000, 24, 37, "sqlserver.wait_resource-val", 19.100000, "sqlserver.wait_type-val", 16, "user.name-val")
+ lb.RecordDbServerQuerySampleEvent(ctx, timestamp, "client.address-val", 11, "db.namespace-val", "db.query.text-val", "db.system.name-val", "network.peer.address-val", 17, 29, "sqlserver.context_info-val", "sqlserver.command-val", 18.100000, 27, 35.100000, 22.100000, 23, 32, 26.100000, "sqlserver.query_hash-val", "sqlserver.query_plan_hash-val", "sqlserver.query_start-val", 15, "sqlserver.request_status-val", 19, 20, "sqlserver.session_status-val", 28.100000, 24, 37, "sqlserver.wait_resource-val", 19.100000, "sqlserver.wait_type-val", 16, "user.name-val", "sqlserver.procedure_id-val", "sqlserver.procedure_name-val")
allEventsCount++
- lb.RecordDbServerTopQueryEvent(ctx, timestamp, 27.100000, "db.query.text-val", 25, 29, 30, 30, "sqlserver.query_hash-val", "sqlserver.query_plan-val", "sqlserver.query_plan_hash-val", 20, 28.100000, 24, "server.address-val", 11, "db.system.name-val")
+ lb.RecordDbServerTopQueryEvent(ctx, timestamp, 27.100000, "db.query.text-val", 25, 29, 30, 30, "sqlserver.query_hash-val", "sqlserver.query_plan-val", "sqlserver.query_plan_hash-val", 20, 28.100000, 24, "server.address-val", 11, "db.system.name-val", "sqlserver.procedure_id-val", "sqlserver.procedure_name-val")
rb := lb.NewResourceBuilder()
rb.SetHostName("host.name-val")
@@ -276,6 +276,12 @@ func TestLogsBuilder(t *testing.T) {
attrVal, ok = lr.Attributes().Get("user.name")
assert.True(t, ok)
assert.Equal(t, "user.name-val", attrVal.Str())
+ attrVal, ok = lr.Attributes().Get("sqlserver.procedure_id")
+ assert.True(t, ok)
+ assert.Equal(t, "sqlserver.procedure_id-val", attrVal.Str())
+ attrVal, ok = lr.Attributes().Get("sqlserver.procedure_name")
+ assert.True(t, ok)
+ assert.Equal(t, "sqlserver.procedure_name-val", attrVal.Str())
case "db.server.top_query":
assert.False(t, validatedEvents["db.server.top_query"], "Found a duplicate in the events slice: db.server.top_query")
validatedEvents["db.server.top_query"] = true
@@ -328,6 +334,12 @@ func TestLogsBuilder(t *testing.T) {
attrVal, ok = lr.Attributes().Get("db.system.name")
assert.True(t, ok)
assert.Equal(t, "db.system.name-val", attrVal.Str())
+ attrVal, ok = lr.Attributes().Get("sqlserver.procedure_id")
+ assert.True(t, ok)
+ assert.Equal(t, "sqlserver.procedure_id-val", attrVal.Str())
+ attrVal, ok = lr.Attributes().Get("sqlserver.procedure_name")
+ assert.True(t, ok)
+ assert.Equal(t, "sqlserver.procedure_name-val", attrVal.Str())
}
}
})
diff --git a/receiver/sqlserverreceiver/metadata.yaml b/receiver/sqlserverreceiver/metadata.yaml
index 3b1caab551324..aa686916b964d 100644
--- a/receiver/sqlserverreceiver/metadata.yaml
+++ b/receiver/sqlserverreceiver/metadata.yaml
@@ -133,6 +133,13 @@ attributes:
sqlserver.percent_complete:
description: Percentage of work completed.
type: double
+ # Stored Procedures
+ sqlserver.procedure_id:
+ description: The SQL Server ID of the stored procedure, if any
+ type: string
+ sqlserver.procedure_name:
+ description: The name of the stored procedure, if any
+ type: string
sqlserver.query_hash:
description: Binary hash value calculated on the query and used to identify queries with similar logic, reported in the HEX format.
type: string
@@ -262,6 +269,8 @@ events:
- sqlserver.wait_type
- sqlserver.writes
- user.name
+ - sqlserver.procedure_id
+ - sqlserver.procedure_name
db.server.top_query:
enabled: false
@@ -282,6 +291,8 @@ events:
- server.address
- server.port
- db.system.name
+ - sqlserver.procedure_id
+ - sqlserver.procedure_name
metrics:
sqlserver.batch.request.rate:
diff --git a/receiver/sqlserverreceiver/scraper.go b/receiver/sqlserverreceiver/scraper.go
index ea3d689138bbe..9632af991c14d 100644
--- a/receiver/sqlserverreceiver/scraper.go
+++ b/receiver/sqlserverreceiver/scraper.go
@@ -152,7 +152,7 @@ func (s *sqlServerScraperHelper) ScrapeLogs(ctx context.Context) (plog.Logs, err
s.logger.Debug("Skipping the collection of top queries because the current time has not yet exceeded the last execution time plus the specified collection interval")
return plog.NewLogs(), nil
}
- resources, err = s.recordDatabaseQueryTextAndPlan(ctx, s.config.TopQueryCount)
+ resources, err = s.recordDatabaseQueryTextAndPlan(ctx)
case getSQLServerQuerySamplesQuery():
resources, err = s.recordDatabaseSampleQuery(ctx)
default:
@@ -619,7 +619,7 @@ func (s *sqlServerScraperHelper) recordDatabaseWaitMetrics(ctx context.Context)
return errors.Join(errs...)
}
-func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Context, topQueryCount uint) (pcommon.Resource, error) {
+func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Context) (pcommon.Resource, error) {
// Constants are the column names of the database status
const (
executionCount = "execution_count"
@@ -638,6 +638,10 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont
totalWorkerTime = "total_worker_time"
dbSystemNameVal = "microsoft.sql_server"
+
+ // stored procedure columns
+ storedProcedureID = "procedure_id"
+ storedProcedureName = "procedure_name"
)
resources := pcommon.NewResource()
@@ -660,23 +664,23 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont
for i, row := range rows {
queryHashVal := hex.EncodeToString([]byte(row[queryHash]))
queryPlanHashVal := hex.EncodeToString([]byte(row[queryPlanHash]))
+ procID := row[storedProcedureID] // defaults to '0' if not present
elapsedTimeMicrosecond, err := strconv.ParseInt(row[totalElapsedTime], 10, 64)
if err != nil {
- s.logger.Info(fmt.Sprintf("sqlServerScraperHelper failed getting rows: %s", err))
+ s.logger.Warn(fmt.Sprintf("sqlServerScraperHelper failed getting rows: %s", err))
errs = append(errs, err)
} else {
// we're trying to get the queries that used the most time.
// caching the total elapsed time (in microsecond) and compare in the next scrape.
- if cached, diff := s.cacheAndDiff(queryHashVal, queryPlanHashVal, totalElapsedTime, elapsedTimeMicrosecond); cached && diff > 0 {
+ if cached, diff := s.cacheAndDiff(queryHashVal, queryPlanHashVal, procID, totalElapsedTime, elapsedTimeMicrosecond); cached && diff > 0 {
totalElapsedTimeDiffsMicrosecond[i] = diff
}
}
}
-
// sort the rows based on the totalElapsedTimeDiffs in descending order,
// only report first T(T=topQueryCount) rows.
- rows = sortRows(rows, totalElapsedTimeDiffsMicrosecond, topQueryCount)
+ rows = sortRows(rows, totalElapsedTimeDiffsMicrosecond, s.config.TopQueryCount)
// sort the totalElapsedTimeDiffs in descending order as well
sort.Slice(totalElapsedTimeDiffsMicrosecond, func(i, j int) bool { return totalElapsedTimeDiffsMicrosecond[i] > totalElapsedTimeDiffsMicrosecond[j] })
@@ -689,6 +693,7 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont
// reporting human-readable query hash and query hash plan
queryHashVal := hex.EncodeToString([]byte(row[queryHash]))
queryPlanHashVal := hex.EncodeToString([]byte(row[queryPlanHash]))
+ procID := row[storedProcedureID]
queryTextVal := s.retrieveValue(row, queryText, &errs, func(row sqlquery.StringMap, columnName string) (any, error) {
statement := row[columnName]
@@ -701,26 +706,28 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont
return obfuscated, nil
})
+ var cached bool
+
executionCountVal := s.retrieveValue(row, executionCount, &errs, retrieveInt)
- cached, executionCountVal := s.cacheAndDiff(queryHashVal, queryPlanHashVal, executionCount, executionCountVal.(int64))
+ cached, executionCountVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, procID, executionCount, executionCountVal.(int64))
if !cached {
executionCountVal = int64(0)
}
logicalReadsVal := s.retrieveValue(row, logicalReads, &errs, retrieveInt)
- cached, logicalReadsVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, logicalReads, logicalReadsVal.(int64))
+ cached, logicalReadsVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, procID, logicalReads, logicalReadsVal.(int64))
if !cached {
logicalReadsVal = int64(0)
}
logicalWritesVal := s.retrieveValue(row, logicalWrites, &errs, retrieveInt)
- cached, logicalWritesVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, logicalWrites, logicalWritesVal.(int64))
+ cached, logicalWritesVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, procID, logicalWrites, logicalWritesVal.(int64))
if !cached {
logicalWritesVal = int64(0)
}
physicalReadsVal := s.retrieveValue(row, physicalReads, &errs, retrieveInt)
- cached, physicalReadsVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, physicalReads, physicalReadsVal.(int64))
+ cached, physicalReadsVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, procID, physicalReads, physicalReadsVal.(int64))
if !cached {
physicalReadsVal = int64(0)
}
@@ -730,19 +737,19 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont
})
rowsReturnedVal := s.retrieveValue(row, rowsReturned, &errs, retrieveInt)
- cached, rowsReturnedVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, rowsReturned, rowsReturnedVal.(int64))
+ cached, rowsReturnedVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, procID, rowsReturned, rowsReturnedVal.(int64))
if !cached {
rowsReturnedVal = int64(0)
}
totalGrantVal := s.retrieveValue(row, totalGrant, &errs, retrieveInt)
- cached, totalGrantVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, totalGrant, totalGrantVal.(int64))
+ cached, totalGrantVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, procID, totalGrant, totalGrantVal.(int64))
if !cached {
totalGrantVal = int64(0)
}
totalWorkerTimeVal := s.retrieveValue(row, totalWorkerTime, &errs, retrieveInt)
- cached, totalWorkerTimeVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, totalWorkerTime, totalWorkerTimeVal.(int64))
+ cached, totalWorkerTimeVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, procID, totalWorkerTime, totalWorkerTimeVal.(int64))
totalWorkerTimeInSecVal := float64(0)
if cached {
totalWorkerTimeInSecVal = float64(totalWorkerTimeVal.(int64)) / 1_000_000
@@ -781,7 +788,10 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont
totalGrantVal.(int64),
s.config.Server,
int64(s.config.Port),
- dbSystemNameVal)
+ dbSystemNameVal,
+ row[storedProcedureID],
+ row[storedProcedureName],
+ )
}
return resources, errors.Join(errs...)
}
@@ -804,13 +814,15 @@ func (s *sqlServerScraperHelper) retrieveValue(
// cacheAndDiff store row(in int) with query hash and query plan hash variables
// (1) returns true if the key is cached before
// (2) returns positive value if the value is larger than the cached value
-func (s *sqlServerScraperHelper) cacheAndDiff(queryHash, queryPlanHash, column string, val int64) (bool, int64) {
+func (s *sqlServerScraperHelper) cacheAndDiff(queryHash, queryPlanHash, procedureID, column string, val int64) (bool, int64) {
if val < 0 {
return false, 0
}
key := queryHash + "-" + queryPlanHash + "-" + column
-
+ if procedureID != "0" { // procedureID is '0' when not a stored procedure
+ key = procedureID + "-" + key
+ }
cached, ok := s.cache.Get(key)
s.cache.Add(key, val)
if !ok {
@@ -820,7 +832,6 @@ func (s *sqlServerScraperHelper) cacheAndDiff(queryHash, queryPlanHash, column s
if val > cached {
return true, val - cached
}
-
return true, 0
}
@@ -928,6 +939,9 @@ func (s *sqlServerScraperHelper) recordDatabaseSampleQuery(ctx context.Context)
const waitTimeMillisecond = "wait_time"
const waitType = "wait_type"
const writes = "writes"
+ // stored procedure columns
+ const storedProcedureID = "procedure_id"
+ const storedProcedureName = "procedure_name"
rows, err := s.client.QueryRows(
ctx,
@@ -1021,7 +1035,9 @@ func (s *sqlServerScraperHelper) recordDatabaseSampleQuery(ctx context.Context)
} else {
clientAddressVal = row[clientAddress]
}
-
+ if s.logger.Level() == zap.DebugLevel && row[storedProcedureID] != "0" {
+ s.logger.Debug("Stored proc data", zap.String("id", row[storedProcedureID]), zap.String("name", row[storedProcedureName]))
+ }
s.lb.RecordDbServerQuerySampleEvent(
contextFromQuery,
timestamp, clientAddressVal, clientPortVal,
@@ -1037,6 +1053,7 @@ func (s *sqlServerScraperHelper) recordDatabaseSampleQuery(ctx context.Context)
sessionIDVal, sessionStatusVal,
totalElapsedTimeSecondVal, transactionIDVal, transactionIsolationLevelVal,
waitResourceVal, waitTimeSecondVal, waitTypeVal, writesVal, usernameVal,
+ row[storedProcedureID], row[storedProcedureName],
)
if !resourcesAdded {
diff --git a/receiver/sqlserverreceiver/scraper_test.go b/receiver/sqlserverreceiver/scraper_test.go
index 1ec36f87e77fc..8b80d467fb928 100644
--- a/receiver/sqlserverreceiver/scraper_test.go
+++ b/receiver/sqlserverreceiver/scraper_test.go
@@ -232,19 +232,19 @@ func TestScrapeCacheAndDiff(t *testing.T) {
assert.NotNil(t, scrapers)
scraper := scrapers[0]
- cached, val := scraper.cacheAndDiff("query_hash", "query_plan_hash", "column", -1)
+ cached, val := scraper.cacheAndDiff("query_hash", "query_plan_hash", "procedure_id", "column", -1)
assert.False(t, cached)
assert.Equal(t, int64(0), val)
- cached, val = scraper.cacheAndDiff("query_hash", "query_plan_hash", "column", 1)
+ cached, val = scraper.cacheAndDiff("query_hash", "query_plan_hash", "procedure_id", "column", 1)
assert.False(t, cached)
assert.Equal(t, int64(1), val)
- cached, val = scraper.cacheAndDiff("query_hash", "query_plan_hash", "column", 1)
+ cached, val = scraper.cacheAndDiff("query_hash", "query_plan_hash", "procedure_id", "column", 1)
assert.True(t, cached)
assert.Equal(t, int64(0), val)
- cached, val = scraper.cacheAndDiff("query_hash", "query_plan_hash", "column", 3)
+ cached, val = scraper.cacheAndDiff("query_hash", "query_plan_hash", "procedure_id", "column", 3)
assert.True(t, cached)
assert.Equal(t, int64(2), val)
}
@@ -476,14 +476,15 @@ func TestQueryTextAndPlanQuery(t *testing.T) {
queryHash := hex.EncodeToString([]byte("0x37849E874171E3F3"))
queryPlanHash := hex.EncodeToString([]byte("0xD3112909429A1B50"))
- scraper.cacheAndDiff(queryHash, queryPlanHash, totalElapsedTime, 846)
- scraper.cacheAndDiff(queryHash, queryPlanHash, rowsReturned, 1)
- scraper.cacheAndDiff(queryHash, queryPlanHash, logicalReads, 1)
- scraper.cacheAndDiff(queryHash, queryPlanHash, logicalWrites, 1)
- scraper.cacheAndDiff(queryHash, queryPlanHash, physicalReads, 1)
- scraper.cacheAndDiff(queryHash, queryPlanHash, executionCount, 1)
- scraper.cacheAndDiff(queryHash, queryPlanHash, totalWorkerTime, 845)
- scraper.cacheAndDiff(queryHash, queryPlanHash, totalGrant, 1)
+ procedureID := "0"
+ scraper.cacheAndDiff(queryHash, queryPlanHash, procedureID, totalElapsedTime, 846)
+ scraper.cacheAndDiff(queryHash, queryPlanHash, procedureID, rowsReturned, 1)
+ scraper.cacheAndDiff(queryHash, queryPlanHash, procedureID, logicalReads, 1)
+ scraper.cacheAndDiff(queryHash, queryPlanHash, procedureID, logicalWrites, 1)
+ scraper.cacheAndDiff(queryHash, queryPlanHash, procedureID, physicalReads, 1)
+ scraper.cacheAndDiff(queryHash, queryPlanHash, procedureID, executionCount, 1)
+ scraper.cacheAndDiff(queryHash, queryPlanHash, procedureID, totalWorkerTime, 845)
+ scraper.cacheAndDiff(queryHash, queryPlanHash, procedureID, totalGrant, 1)
scraper.client = mockClient{
instanceName: scraper.config.InstanceName,
@@ -535,14 +536,15 @@ func TestInvalidQueryTextAndPlanQuery(t *testing.T) {
queryHash := hex.EncodeToString([]byte("0x37849E874171E3F3"))
queryPlanHash := hex.EncodeToString([]byte("0xD3112909429A1B50"))
- scraper.cacheAndDiff(queryHash, queryPlanHash, totalElapsedTime, 1)
- scraper.cacheAndDiff(queryHash, queryPlanHash, rowsReturned, 1)
- scraper.cacheAndDiff(queryHash, queryPlanHash, logicalReads, 1)
- scraper.cacheAndDiff(queryHash, queryPlanHash, logicalWrites, 1)
- scraper.cacheAndDiff(queryHash, queryPlanHash, physicalReads, 1)
- scraper.cacheAndDiff(queryHash, queryPlanHash, executionCount, 1)
- scraper.cacheAndDiff(queryHash, queryPlanHash, totalWorkerTime, 1)
- scraper.cacheAndDiff(queryHash, queryPlanHash, totalGrant, 1)
+ procedureID := "0"
+ scraper.cacheAndDiff(queryHash, queryPlanHash, procedureID, totalElapsedTime, 1)
+ scraper.cacheAndDiff(queryHash, queryPlanHash, procedureID, rowsReturned, 1)
+ scraper.cacheAndDiff(queryHash, queryPlanHash, procedureID, logicalReads, 1)
+ scraper.cacheAndDiff(queryHash, queryPlanHash, procedureID, logicalWrites, 1)
+ scraper.cacheAndDiff(queryHash, queryPlanHash, procedureID, physicalReads, 1)
+ scraper.cacheAndDiff(queryHash, queryPlanHash, procedureID, executionCount, 1)
+ scraper.cacheAndDiff(queryHash, queryPlanHash, procedureID, totalWorkerTime, 1)
+ scraper.cacheAndDiff(queryHash, queryPlanHash, procedureID, totalGrant, 1)
scraper.client = mockInvalidClient{
mockClient: mockClient{
diff --git a/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl b/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl
index 933f1cc40caf3..7c0c129284a48 100644
--- a/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl
+++ b/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl
@@ -2,6 +2,7 @@ with qstats as (
SELECT TOP(@maxSampleCount)
REPLACE(@@SERVERNAME,'\',':') AS [sql_instance],
HOST_NAME() AS [computer_name],
+ ISNULL(st1.objectid, 0) AS object_id,
MAX(qs.plan_handle) AS query_plan_handle,
MAX(qs.last_elapsed_time) AS last_elapsed_time,
MAX(qs.last_execution_time) AS last_execution_time,
@@ -16,7 +17,9 @@ with qstats as (
SUM(qs.total_rows) AS total_rows,
SUM(qs.total_grant_kb) as total_grant_kb
FROM sys.dm_exec_query_stats AS qs
+ CROSS APPLY sys.dm_exec_sql_text(qs.plan_handle) AS st1
GROUP BY
+ st1.objectid,
qs.query_hash,
qs.query_plan_hash
HAVING MAX(DATEADD(ms, qs.last_elapsed_time / 1000, qs.last_execution_time)) > DATEADD(SECOND, @lookbackTime, GETDATE())
@@ -26,8 +29,14 @@ SELECT qs.*,
((CASE statement_end_offset
WHEN -1 THEN DATALENGTH(st.text)
ELSE stats.statement_end_offset END - stats.statement_start_offset) / 2) + 1) AS query_text,
- ISNULL(qp.query_plan, '') AS query_plan
+ ISNULL(qp.query_plan, '') AS query_plan,
+ ISNULL(CASE WHEN qs.object_id > 0 THEN qs.object_id END, '') AS procedure_id,
+ ISNULL(CASE WHEN qs.object_id > 0
+ THEN QUOTENAME(OBJECT_SCHEMA_NAME(qs.object_id, st.dbid))
+ + N'.' + QUOTENAME(OBJECT_NAME(qs.object_id, st.dbid))
+ END, '') AS procedure_name
FROM qstats AS qs
INNER JOIN sys.dm_exec_query_stats AS stats on qs.query_plan_handle = stats.plan_handle
CROSS APPLY sys.dm_exec_query_plan(qs.query_plan_handle) AS qp
- CROSS APPLY sys.dm_exec_sql_text(qs.query_plan_handle) AS st;
+ CROSS APPLY sys.dm_exec_sql_text(qs.query_plan_handle) AS st
+ WHERE st.text IS NOT NULL;
diff --git a/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl b/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl
index 48cd195e4fad7..5ff57fcee6d99 100644
--- a/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl
+++ b/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl
@@ -39,7 +39,12 @@ SELECT TOP(@top)
ISNULL(r.query_hash, CONVERT(VARBINARY, '')) AS query_hash,
ISNULL(r.query_plan_hash, CONVERT(VARBINARY, '')) AS query_plan_hash,
ISNULL(r.context_info, CONVERT(VARBINARY, '')) AS context_info,
- s.login_name AS username
+ s.login_name AS username,
+ ISNULL(CASE WHEN o.objectid > 0 THEN o.objectid END, '') AS procedure_id,
+ ISNULL(CASE WHEN o.objectid > 0
+ THEN QUOTENAME(OBJECT_SCHEMA_NAME(o.objectid, o.dbid))
+ + N'.' + QUOTENAME(OBJECT_NAME(o.objectid, o.dbid))
+ END, '') AS procedure_name
FROM sys.dm_exec_requests r
INNER JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
INNER JOIN sys.dm_exec_connections c ON s.session_id = c.session_id
diff --git a/receiver/sqlserverreceiver/testdata/databaseTopQueryWithInstanceName.txt b/receiver/sqlserverreceiver/testdata/databaseTopQueryWithInstanceName.txt
index 5d36da836b57b..aa97f3b60f60f 100644
--- a/receiver/sqlserverreceiver/testdata/databaseTopQueryWithInstanceName.txt
+++ b/receiver/sqlserverreceiver/testdata/databaseTopQueryWithInstanceName.txt
@@ -28,4 +28,5 @@ SELECT qs.*,
FROM qstats AS qs
INNER JOIN sys.dm_exec_query_stats AS stats on qs.query_plan_handle = stats.plan_handle
CROSS APPLY sys.dm_exec_query_plan(qs.query_plan_handle) AS qp
- CROSS APPLY sys.dm_exec_sql_text(qs.query_plan_handle) AS st;
+ CROSS APPLY sys.dm_exec_sql_text(qs.query_plan_handle) AS st
+ WHERE st.text IS NOT NULL;
diff --git a/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt b/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt
index 933f1cc40caf3..7c0c129284a48 100644
--- a/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt
+++ b/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt
@@ -2,6 +2,7 @@ with qstats as (
SELECT TOP(@maxSampleCount)
REPLACE(@@SERVERNAME,'\',':') AS [sql_instance],
HOST_NAME() AS [computer_name],
+ ISNULL(st1.objectid, 0) AS object_id,
MAX(qs.plan_handle) AS query_plan_handle,
MAX(qs.last_elapsed_time) AS last_elapsed_time,
MAX(qs.last_execution_time) AS last_execution_time,
@@ -16,7 +17,9 @@ with qstats as (
SUM(qs.total_rows) AS total_rows,
SUM(qs.total_grant_kb) as total_grant_kb
FROM sys.dm_exec_query_stats AS qs
+ CROSS APPLY sys.dm_exec_sql_text(qs.plan_handle) AS st1
GROUP BY
+ st1.objectid,
qs.query_hash,
qs.query_plan_hash
HAVING MAX(DATEADD(ms, qs.last_elapsed_time / 1000, qs.last_execution_time)) > DATEADD(SECOND, @lookbackTime, GETDATE())
@@ -26,8 +29,14 @@ SELECT qs.*,
((CASE statement_end_offset
WHEN -1 THEN DATALENGTH(st.text)
ELSE stats.statement_end_offset END - stats.statement_start_offset) / 2) + 1) AS query_text,
- ISNULL(qp.query_plan, '') AS query_plan
+ ISNULL(qp.query_plan, '') AS query_plan,
+ ISNULL(CASE WHEN qs.object_id > 0 THEN qs.object_id END, '') AS procedure_id,
+ ISNULL(CASE WHEN qs.object_id > 0
+ THEN QUOTENAME(OBJECT_SCHEMA_NAME(qs.object_id, st.dbid))
+ + N'.' + QUOTENAME(OBJECT_NAME(qs.object_id, st.dbid))
+ END, '') AS procedure_name
FROM qstats AS qs
INNER JOIN sys.dm_exec_query_stats AS stats on qs.query_plan_handle = stats.plan_handle
CROSS APPLY sys.dm_exec_query_plan(qs.query_plan_handle) AS qp
- CROSS APPLY sys.dm_exec_sql_text(qs.query_plan_handle) AS st;
+ CROSS APPLY sys.dm_exec_sql_text(qs.query_plan_handle) AS st
+ WHERE st.text IS NOT NULL;
diff --git a/receiver/sqlserverreceiver/testdata/expectedQueryTextAndPlanQuery.yaml b/receiver/sqlserverreceiver/testdata/expectedQueryTextAndPlanQuery.yaml
index 4042e9baab083..b68c276bed762 100644
--- a/receiver/sqlserverreceiver/testdata/expectedQueryTextAndPlanQuery.yaml
+++ b/receiver/sqlserverreceiver/testdata/expectedQueryTextAndPlanQuery.yaml
@@ -61,8 +61,14 @@ resourceLogs:
- key: db.system.name
value:
stringValue: microsoft.sql_server
+ - key: sqlserver.procedure_id
+ value:
+ stringValue: "0"
+ - key: sqlserver.procedure_name
+ value:
+ stringValue: ""
body: {}
- eventName: db.server.top_query
+ eventName: "db.server.top_query"
spanId: ""
timeUnixNano: "1749224037462260000"
traceId: ""
diff --git a/receiver/sqlserverreceiver/testdata/expectedRecordDatabaseSampleQuery.yaml b/receiver/sqlserverreceiver/testdata/expectedRecordDatabaseSampleQuery.yaml
index d0924bd35b480..b0babe6d17b09 100644
--- a/receiver/sqlserverreceiver/testdata/expectedRecordDatabaseSampleQuery.yaml
+++ b/receiver/sqlserverreceiver/testdata/expectedRecordDatabaseSampleQuery.yaml
@@ -115,6 +115,12 @@ resourceLogs:
- key: user.name
value:
stringValue: sa
+ - key: sqlserver.procedure_id
+ value:
+ stringValue: "0"
+ - key: sqlserver.procedure_name
+ value:
+ stringValue: ""
body: {}
eventName: db.server.query_sample
spanId: a7ad6a7169203331
diff --git a/receiver/sqlserverreceiver/testdata/expectedRecordDatabaseSampleQueryWithInvalidData.yaml b/receiver/sqlserverreceiver/testdata/expectedRecordDatabaseSampleQueryWithInvalidData.yaml
index 6a24c138b13c5..c91eabef757bc 100644
--- a/receiver/sqlserverreceiver/testdata/expectedRecordDatabaseSampleQueryWithInvalidData.yaml
+++ b/receiver/sqlserverreceiver/testdata/expectedRecordDatabaseSampleQueryWithInvalidData.yaml
@@ -115,6 +115,12 @@ resourceLogs:
- key: user.name
value:
stringValue: sa
+ - key: sqlserver.procedure_id
+ value:
+ stringValue: "0"
+ - key: sqlserver.procedure_name
+ value:
+ stringValue: ""
body: {}
eventName: db.server.query_sample
spanId: ""
diff --git a/receiver/sqlserverreceiver/testdata/queryTextAndPlanQueryData.txt b/receiver/sqlserverreceiver/testdata/queryTextAndPlanQueryData.txt
index abd3e31b681f7..7f7bf747a1c71 100644
--- a/receiver/sqlserverreceiver/testdata/queryTextAndPlanQueryData.txt
+++ b/receiver/sqlserverreceiver/testdata/queryTextAndPlanQueryData.txt
@@ -14,6 +14,8 @@
"total_rows": "2",
"total_grant_kb": "3096",
"query_text": "with qstats as (\n SELECT TOP(@topNValue)\n REPLACE(@@SERVERNAME,'\\',':') AS [sql_instance],\n HOST_NAME() AS [computer_name],\n MAX(qs.plan_handle) AS query_plan_handle,\n qs.query_hash AS query_hash,\n qs.query_plan_hash AS query_plan_hash,\n SUM(qs.execution_count) AS execution_count,\n SUM(qs.total_elapsed_time) AS total_elapsed_time,\n SUM(qs.total_worker_time) AS total_worker_time,\n SUM(qs.total_logical_reads) AS total_logical_reads,\n SUM(qs.total_physical_reads) AS total_physical_reads,\n SUM(qs.total_logical_writes) AS total_logical_writes,\n SUM(qs.total_rows) AS total_rows,\n SUM(qs.total_grant_kb) as total_grant_kb\n FROM sys.dm_exec_query_stats AS qs\n WHERE qs.last_execution_time BETWEEN DATEADD(SECOND, @granularity, GETDATE()) AND GETDATE()\n GROUP BY\n qs.query_hash,\n qs.query_plan_hash\n)\nSELECT qs.*,\n SUBSTRING(st.text, (stats.statement_start_offset / 2) + 1,\n ((CASE statement_end_offset\n WHEN -1 THEN DATALENGTH(st.text)\n ELSE stats.statement_end_offset END - stats.statement_start_offset) / 2) + 1) AS text,\n ISNULL(qp.query_plan, '') AS query_plan\nFROM qstats AS qs\n INNER JOIN sys.dm_exec_query_stats AS stats on qs.query_plan_handle = stats.plan_handle\n CROSS APPLY sys.dm_exec_query_plan(qs.query_plan_handle) AS qp\n CROSS APPLY sys.dm_exec_sql_text(qs.query_plan_handle) AS st",
- "query_plan": ""
+ "query_plan": "",
+ "procedure_id": "0",
+ "procedure_name": ""
}
]
diff --git a/receiver/sqlserverreceiver/testdata/queryTextAndPlanQueryInvalidData.txt b/receiver/sqlserverreceiver/testdata/queryTextAndPlanQueryInvalidData.txt
index da3925707bf19..4fad7195dd197 100644
--- a/receiver/sqlserverreceiver/testdata/queryTextAndPlanQueryInvalidData.txt
+++ b/receiver/sqlserverreceiver/testdata/queryTextAndPlanQueryInvalidData.txt
@@ -14,6 +14,8 @@
"total_rows": "2A",
"total_grant_kb": "3096A",
"query_text": "SELECT cpu_time AS [CPU Usage (time)",
- "query_plan": " 0 THEN o.objectid END, '') AS procedure_id,
+ ISNULL(CASE WHEN o.objectid > 0
+ THEN QUOTENAME(OBJECT_SCHEMA_NAME(o.objectid, o.dbid))
+ + N'.' + QUOTENAME(OBJECT_NAME(o.objectid, o.dbid))
+ END, '') AS procedure_name
FROM sys.dm_exec_requests r
INNER JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
INNER JOIN sys.dm_exec_connections c ON s.session_id = c.session_id