From 71759f160c0e2fd58a2d31c3e05000e2fcaca781 Mon Sep 17 00:00:00 2001 From: cjk Date: Mon, 24 Nov 2025 10:09:51 +0000 Subject: [PATCH 01/43] Adding the query and tracking of stored procedures to events --- receiver/sqlserverreceiver/documentation.md | 6 ++ receiver/sqlserverreceiver/factory.go | 2 +- .../generated_package_test.go | 3 +- .../internal/metadata/generated_logs.go | 19 ++-- .../internal/metadata/generated_logs_test.go | 27 +++++- receiver/sqlserverreceiver/metadata.yaml | 18 +++- receiver/sqlserverreceiver/scraper.go | 55 +++++++---- .../templates/dbQueryAndTextQuery.tmpl | 74 ++++++++------ .../templates/sqlServerQuerySample.tmpl | 97 ++++++++++--------- 9 files changed, 193 insertions(+), 108 deletions(-) diff --git a/receiver/sqlserverreceiver/documentation.md b/receiver/sqlserverreceiver/documentation.md index a018477cf1617..75f691ead994d 100644 --- a/receiver/sqlserverreceiver/documentation.md +++ b/receiver/sqlserverreceiver/documentation.md @@ -606,6 +606,9 @@ 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 | +| sqlserver.procedure_type | The type code of the stored procedure, if any. Typically 'P' | Any Str | ### db.server.top_query @@ -630,6 +633,9 @@ 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 | +| sqlserver.procedure_type | The type code of the stored procedure, if any. Typically 'P' | Any Str | ## Resource Attributes diff --git a/receiver/sqlserverreceiver/factory.go b/receiver/sqlserverreceiver/factory.go index 572d45e2e2bb6..87499ad5c8864 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/generated_package_test.go b/receiver/sqlserverreceiver/generated_package_test.go index ce3721511beef..86266f5f36641 100644 --- a/receiver/sqlserverreceiver/generated_package_test.go +++ b/receiver/sqlserverreceiver/generated_package_test.go @@ -3,9 +3,8 @@ package sqlserverreceiver import ( - "testing" - "go.uber.org/goleak" + "testing" ) func TestMain(m *testing.M) { diff --git a/receiver/sqlserverreceiver/internal/metadata/generated_logs.go b/receiver/sqlserverreceiver/internal/metadata/generated_logs.go index 2224f758a2990..ae30196ca3b95 100644 --- a/receiver/sqlserverreceiver/internal/metadata/generated_logs.go +++ b/receiver/sqlserverreceiver/internal/metadata/generated_logs.go @@ -4,7 +4,6 @@ package metadata import ( "context" - "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/filter" "go.opentelemetry.io/collector/pdata/pcommon" @@ -18,7 +17,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, sqlserverProcedureTypeAttributeValue string) { if !e.config.Enabled { return } @@ -63,6 +62,9 @@ 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) + dp.Attributes().PutStr("sqlserver.procedure_type", sqlserverProcedureTypeAttributeValue) } @@ -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, sqlserverProcedureTypeAttributeValue string) { if !e.config.Enabled { return } @@ -113,6 +115,9 @@ 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) + dp.Attributes().PutStr("sqlserver.procedure_type", sqlserverProcedureTypeAttributeValue) } @@ -284,11 +289,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, sqlserverProcedureTypeAttributeValue 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, sqlserverProcedureTypeAttributeValue) } // 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, sqlserverProcedureTypeAttributeValue string) { + lb.eventDbServerTopQuery.recordEvent(ctx, timestamp, sqlserverTotalWorkerTimeAttributeValue, dbQueryTextAttributeValue, sqlserverExecutionCountAttributeValue, sqlserverTotalLogicalReadsAttributeValue, sqlserverTotalLogicalWritesAttributeValue, sqlserverTotalPhysicalReadsAttributeValue, sqlserverQueryHashAttributeValue, sqlserverQueryPlanAttributeValue, sqlserverQueryPlanHashAttributeValue, sqlserverTotalRowsAttributeValue, sqlserverTotalElapsedTimeAttributeValue, sqlserverTotalGrantKbAttributeValue, serverAddressAttributeValue, serverPortAttributeValue, dbSystemNameAttributeValue, sqlserverProcedureIDAttributeValue, sqlserverProcedureNameAttributeValue, sqlserverProcedureTypeAttributeValue) } diff --git a/receiver/sqlserverreceiver/internal/metadata/generated_logs_test.go b/receiver/sqlserverreceiver/internal/metadata/generated_logs_test.go index 53531d2d36903..4b9270d807ae4 100644 --- a/receiver/sqlserverreceiver/internal/metadata/generated_logs_test.go +++ b/receiver/sqlserverreceiver/internal/metadata/generated_logs_test.go @@ -4,9 +4,6 @@ package metadata import ( "context" - "testing" - "time" - "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" @@ -14,6 +11,8 @@ import ( "go.opentelemetry.io/otel/trace" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" + "testing" + "time" ) type eventsTestDataSet int @@ -135,10 +134,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", "sqlserver.procedure_type-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", "sqlserver.procedure_type-val") rb := lb.NewResourceBuilder() rb.SetHostName("host.name-val") @@ -276,6 +275,15 @@ 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()) + attrVal, ok = lr.Attributes().Get("sqlserver.procedure_type") + assert.True(t, ok) + assert.Equal(t, "sqlserver.procedure_type-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 +336,15 @@ 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()) + attrVal, ok = lr.Attributes().Get("sqlserver.procedure_type") + assert.True(t, ok) + assert.Equal(t, "sqlserver.procedure_type-val", attrVal.Str()) } } }) diff --git a/receiver/sqlserverreceiver/metadata.yaml b/receiver/sqlserverreceiver/metadata.yaml index 3b1caab551324..f7935b97d873f 100644 --- a/receiver/sqlserverreceiver/metadata.yaml +++ b/receiver/sqlserverreceiver/metadata.yaml @@ -1,5 +1,5 @@ type: sqlserver - +#generated_package_name: sqlserverreceiver status: class: receiver stability: @@ -133,6 +133,16 @@ attributes: sqlserver.percent_complete: description: Percentage of work completed. type: double + # Stored Procedures + sqlserver.procedure_id: + description: The SQLServer ID of the stored procedure, if any + type: string + sqlserver.procedure_name: + description: The name of the stored procedure, if any + type: string + sqlserver.procedure_type: + description: The type code of the stored procedure, if any. Typically 'P' + 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 +272,9 @@ events: - sqlserver.wait_type - sqlserver.writes - user.name + - sqlserver.procedure_id + - sqlserver.procedure_name + - sqlserver.procedure_type db.server.top_query: enabled: false @@ -282,6 +295,9 @@ events: - server.address - server.port - db.system.name + - sqlserver.procedure_id + - sqlserver.procedure_name + - sqlserver.procedure_type metrics: sqlserver.batch.request.rate: diff --git a/receiver/sqlserverreceiver/scraper.go b/receiver/sqlserverreceiver/scraper.go index 861a8155bf358..ad2026f4cf3fd 100644 --- a/receiver/sqlserverreceiver/scraper.go +++ b/receiver/sqlserverreceiver/scraper.go @@ -151,7 +151,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, s.config.TopQueryCount, s.config.MaxQuerySampleCount) case getSQLServerQuerySamplesQuery(): resources, err = s.recordDatabaseSampleQuery(ctx) default: @@ -618,7 +618,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, topQueryCount, maxQuerySampleCount uint) (pcommon.Resource, error) { // Constants are the column names of the database status const ( executionCount = "execution_count" @@ -637,6 +637,11 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont totalWorkerTime = "total_worker_time" dbSystemNameVal = "microsoft.sql_server" + + // stored procedure columns + storedProcedureId = "procedure_id" + storedProcedureName = "procedure_name" + storedProcedureType = "procedure_type" ) resources := pcommon.NewResource() @@ -659,20 +664,20 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont for i, row := range rows { queryHashVal := hex.EncodeToString([]byte(row[queryHash])) queryPlanHashVal := hex.EncodeToString([]byte(row[queryPlanHash])) + planId := row[storedProcedureId] 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, planId, 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) @@ -694,6 +699,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] @@ -707,25 +713,25 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont }) 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) } @@ -735,19 +741,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 +787,11 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont totalGrantVal.(int64), s.config.Server, int64(s.config.Port), - dbSystemNameVal) + dbSystemNameVal, + row[storedProcedureId], + row[storedProcedureName], + row[storedProcedureType], + ) } return resources, errors.Join(errs...) } @@ -804,24 +814,28 @@ 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 != "" { + key = procedureId + "-" + key + } cached, ok := s.cache.Get(key) if !ok { s.cache.Add(key, val) + // s.logger.Info("Adding key", zap.String("key", key), zap.Int64("val", val)) return false, val } if val > cached { s.cache.Add(key, val) + // s.logger.Info("Returning cached diff for ", zap.String("key", key), zap.Int64("val", val)) return true, val - cached } - + // s.logger.Info("Returning 0", zap.String("key", key), zap.Int64("val", val)) return true, 0 } @@ -929,6 +943,10 @@ 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" + const storedProcedureType = "procedure_type" rows, err := s.client.QueryRows( ctx, @@ -1022,7 +1040,9 @@ func (s *sqlServerScraperHelper) recordDatabaseSampleQuery(ctx context.Context) } else { clientAddressVal = row[clientAddress] } - + if row[storedProcedureId] != "0" { + s.logger.Info("Stored proc data", zap.String("id", row[storedProcedureId]), zap.String("name", row[storedProcedureName]), zap.String("type", row[storedProcedureType])) + } s.lb.RecordDbServerQuerySampleEvent( contextFromQuery, timestamp, clientAddressVal, clientPortVal, @@ -1038,6 +1058,7 @@ func (s *sqlServerScraperHelper) recordDatabaseSampleQuery(ctx context.Context) sessionIDVal, sessionStatusVal, totalElapsedTimeSecondVal, transactionIDVal, transactionIsolationLevelVal, waitResourceVal, waitTimeSecondVal, waitTypeVal, writesVal, usernameVal, + row[storedProcedureId], row[storedProcedureName], row[storedProcedureType], ) if !resourcesAdded { diff --git a/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl b/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl index 75fed75c75fb5..9a62148a2db5a 100644 --- a/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl +++ b/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl @@ -1,31 +1,43 @@ -with qstats as ( - SELECT TOP(@topNValue) - REPLACE(@@SERVERNAME,'\',':') AS [sql_instance], - HOST_NAME() AS [computer_name], - MAX(qs.plan_handle) AS query_plan_handle, - qs.query_hash AS query_hash, - qs.query_plan_hash AS query_plan_hash, - SUM(qs.execution_count) AS execution_count, - SUM(qs.total_elapsed_time) AS total_elapsed_time, - SUM(qs.total_worker_time) AS total_worker_time, - SUM(qs.total_logical_reads) AS total_logical_reads, - SUM(qs.total_physical_reads) AS total_physical_reads, - SUM(qs.total_logical_writes) AS total_logical_writes, - SUM(qs.total_rows) AS total_rows, - SUM(qs.total_grant_kb) as total_grant_kb - FROM sys.dm_exec_query_stats AS qs - WHERE qs.last_execution_time BETWEEN DATEADD(SECOND, @lookbackTime, GETDATE()) AND GETDATE() - GROUP BY - qs.query_hash, - qs.query_plan_hash -) -SELECT qs.*, - SUBSTRING(st.text, (stats.statement_start_offset / 2) + 1, - ((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 -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; +;WITH qstats AS + ( + SELECT TOP 1000 + REPLACE(@@SERVERNAME,'\',':') AS [sql_instance], + HOST_NAME() AS [computer_name], + max(qs.plan_handle) AS plan_handle, + ISNULL(st1.objectid, 0) AS object_id, + qs.query_hash AS query_hash, + qs.query_plan_hash AS query_plan_hash, + SUM(qs.execution_count) AS execution_count, + SUM(qs.total_elapsed_time) AS total_elapsed_time, + SUM(qs.total_worker_time) AS total_worker_time, + SUM(qs.total_logical_reads) AS total_logical_reads, + SUM(qs.total_physical_reads) AS total_physical_reads, + SUM(qs.total_logical_writes) AS total_logical_writes, + 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 + WHERE qs.last_execution_time BETWEEN DATEADD(SECOND, -1200, GETDATE()) AND GETDATE() + GROUP BY st1.objectid, qs.query_hash, qs.query_plan_hash + ) + SELECT + qs.*, + SUBSTRING(st.text, + (stats.statement_start_offset / 2) + 1, + ((CASE stats.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(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, + ISNULL(CASE WHEN qs.object_id > 0 + THEN CONVERT(sysname, OBJECTPROPERTYEX(qs.object_id, 'BaseType')) -- 'P' (T-SQL) or 'PC' (CLR), '')) + END, '') AS procedure_type + FROM qstats AS qs + JOIN sys.dm_exec_query_stats AS stats + ON stats.plan_handle = qs.plan_handle + CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) AS qp + CROSS APPLY sys.dm_exec_sql_text(qs.plan_handle) AS st; \ No newline at end of file diff --git a/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl b/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl index 48cd195e4fad7..8412b25487eac 100644 --- a/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl +++ b/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl @@ -1,46 +1,55 @@ SELECT TOP(@top) - REPLACE(@@SERVERNAME,'\',':') AS [sql_instance], - HOST_NAME() AS [computer_name], - DB_NAME(r.database_id) AS db_name, - ISNULL(c.client_net_address, '') as client_address, - ISNULL(c.client_tcp_port, '') AS client_port, - CONVERT(NVARCHAR, TODATETIMEOFFSET(r.start_time, DATEPART(TZOFFSET, SYSDATETIMEOFFSET())), 126) AS query_start, - s.session_id, - s.STATUS AS session_status, - r.STATUS AS request_status, - ISNULL(s.host_name, '') AS host_name, - r.command, - SUBSTRING(o.TEXT, (r.statement_start_offset / 2) + 1, ( - ( - CASE r.statement_end_offset - WHEN - 1 - THEN DATALENGTH(o.TEXT) - ELSE r.statement_end_offset - END - r.statement_start_offset - ) / 2 - ) + 1) AS statement_text, - r.blocking_session_id, - ISNULL(r.wait_type, '') AS wait_type, - r.wait_time, - r.wait_resource, - r.open_transaction_count, - r.transaction_id, - r.percent_complete, - r.estimated_completion_time, - r.cpu_time, - r.total_elapsed_time, - r.reads, - r.writes, - r.logical_reads, - r.transaction_isolation_level, - r.lock_timeout, - r.deadlock_priority, - r.row_count, - 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 + REPLACE(@@SERVERNAME,'\',':') AS [sql_instance], + HOST_NAME() AS [computer_name], + DB_NAME(r.database_id) AS db_name, + ISNULL(c.client_net_address, '') as client_address, + ISNULL(c.client_tcp_port, '') AS client_port, + CONVERT(NVARCHAR, TODATETIMEOFFSET(r.start_time, DATEPART(TZOFFSET, SYSDATETIMEOFFSET())), 126) AS query_start, + s.session_id, + s.STATUS AS session_status, + r.STATUS AS request_status, + ISNULL(s.host_name, '') AS host_name, + r.command, + SUBSTRING(o.TEXT, (r.statement_start_offset / 2) + 1, ( + ( + CASE r.statement_end_offset + WHEN - 1 + THEN DATALENGTH(o.TEXT) + ELSE r.statement_end_offset + END - r.statement_start_offset + ) / 2 + ) + 1) AS statement_text, + r.blocking_session_id, + ISNULL(r.wait_type, '') AS wait_type, + r.wait_time, + r.wait_resource, + r.open_transaction_count, + r.transaction_id, + r.percent_complete, + r.estimated_completion_time, + r.cpu_time, + r.total_elapsed_time, + r.reads, + r.writes, + r.logical_reads, + r.transaction_isolation_level, + r.lock_timeout, + r.deadlock_priority, + r.row_count, + 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, + 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, + ISNULL(CASE WHEN o.objectid > 0 + THEN CONVERT(sysname, OBJECTPROPERTYEX(o.objectid, 'BaseType')) + END, '') AS procedure_type 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 -CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS o; \ No newline at end of file + 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 + CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS o; + From 3b5ca90e5e707c5152c66f754e37a19a3ca6a64e Mon Sep 17 00:00:00 2001 From: cjk Date: Mon, 24 Nov 2025 15:10:09 +0000 Subject: [PATCH 02/43] Fixed missing process id --- receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl | 1 + 1 file changed, 1 insertion(+) diff --git a/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl b/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl index 9a62148a2db5a..8868d930a144c 100644 --- a/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl +++ b/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl @@ -29,6 +29,7 @@ ELSE stats.statement_end_offset END - stats.statement_start_offset) / 2) + 1) AS query_text, 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)) From a8ffaeff15ebdf33e54f712a33f475adee1a207a Mon Sep 17 00:00:00 2001 From: cjk Date: Tue, 25 Nov 2025 14:33:28 +0000 Subject: [PATCH 03/43] Removing stored procedure type Updating tests --- receiver/sqlserverreceiver/documentation.md | 2 - receiver/sqlserverreceiver/factory_test.go | 2 +- .../internal/metadata/generated_logs.go | 14 ++- .../internal/metadata/generated_logs_test.go | 10 +- receiver/sqlserverreceiver/metadata.yaml | 5 - receiver/sqlserverreceiver/scraper.go | 16 +--- receiver/sqlserverreceiver/scraper_test.go | 42 +++++---- .../templates/dbQueryAndTextQuery.tmpl | 5 +- .../templates/sqlServerQuerySample.tmpl | 5 +- .../databaseTopQueryWithoutInstanceName.txt | 72 ++++++++------ .../expectedQueryTextAndPlanQuery.yaml | 8 +- ...dQueryTextAndPlanQueryWithInvalidData.yaml | 6 ++ .../expectedRecordDatabaseSampleQuery.yaml | 6 ++ ...ordDatabaseSampleQueryWithInvalidData.yaml | 6 ++ .../testdata/queryTextAndPlanQueryData.txt | 4 +- .../queryTextAndPlanQueryInvalidData.txt | 4 +- .../recordDatabaseSampleQueryData.txt | 4 +- .../recordInvalidDatabaseSampleQueryData.txt | 6 +- .../testdata/testQuerySampleQuery.txt | 94 ++++++++++--------- 19 files changed, 167 insertions(+), 144 deletions(-) diff --git a/receiver/sqlserverreceiver/documentation.md b/receiver/sqlserverreceiver/documentation.md index 75f691ead994d..55fb14a46e8ae 100644 --- a/receiver/sqlserverreceiver/documentation.md +++ b/receiver/sqlserverreceiver/documentation.md @@ -608,7 +608,6 @@ query sample | 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 | -| sqlserver.procedure_type | The type code of the stored procedure, if any. Typically 'P' | Any Str | ### db.server.top_query @@ -635,7 +634,6 @@ top query | 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 | -| sqlserver.procedure_type | The type code of the stored procedure, if any. Typically 'P' | Any Str | ## Resource Attributes 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 ae30196ca3b95..3f492b17762aa 100644 --- a/receiver/sqlserverreceiver/internal/metadata/generated_logs.go +++ b/receiver/sqlserverreceiver/internal/metadata/generated_logs.go @@ -17,7 +17,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, sqlserverProcedureIDAttributeValue string, sqlserverProcedureNameAttributeValue string, sqlserverProcedureTypeAttributeValue 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 } @@ -64,7 +64,6 @@ func (e *eventDbServerQuerySample) recordEvent(ctx context.Context, timestamp pc dp.Attributes().PutStr("user.name", userNameAttributeValue) dp.Attributes().PutStr("sqlserver.procedure_id", sqlserverProcedureIDAttributeValue) dp.Attributes().PutStr("sqlserver.procedure_name", sqlserverProcedureNameAttributeValue) - dp.Attributes().PutStr("sqlserver.procedure_type", sqlserverProcedureTypeAttributeValue) } @@ -88,7 +87,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, sqlserverProcedureIDAttributeValue string, sqlserverProcedureNameAttributeValue string, sqlserverProcedureTypeAttributeValue 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 } @@ -117,7 +116,6 @@ func (e *eventDbServerTopQuery) recordEvent(ctx context.Context, timestamp pcomm dp.Attributes().PutStr("db.system.name", dbSystemNameAttributeValue) dp.Attributes().PutStr("sqlserver.procedure_id", sqlserverProcedureIDAttributeValue) dp.Attributes().PutStr("sqlserver.procedure_name", sqlserverProcedureNameAttributeValue) - dp.Attributes().PutStr("sqlserver.procedure_type", sqlserverProcedureTypeAttributeValue) } @@ -289,11 +287,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, sqlserverProcedureIDAttributeValue string, sqlserverProcedureNameAttributeValue string, sqlserverProcedureTypeAttributeValue 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, sqlserverProcedureTypeAttributeValue) +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, sqlserverProcedureIDAttributeValue string, sqlserverProcedureNameAttributeValue string, sqlserverProcedureTypeAttributeValue string) { - lb.eventDbServerTopQuery.recordEvent(ctx, timestamp, sqlserverTotalWorkerTimeAttributeValue, dbQueryTextAttributeValue, sqlserverExecutionCountAttributeValue, sqlserverTotalLogicalReadsAttributeValue, sqlserverTotalLogicalWritesAttributeValue, sqlserverTotalPhysicalReadsAttributeValue, sqlserverQueryHashAttributeValue, sqlserverQueryPlanAttributeValue, sqlserverQueryPlanHashAttributeValue, sqlserverTotalRowsAttributeValue, sqlserverTotalElapsedTimeAttributeValue, sqlserverTotalGrantKbAttributeValue, serverAddressAttributeValue, serverPortAttributeValue, dbSystemNameAttributeValue, sqlserverProcedureIDAttributeValue, sqlserverProcedureNameAttributeValue, sqlserverProcedureTypeAttributeValue) +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 4b9270d807ae4..e5ac43e808729 100644 --- a/receiver/sqlserverreceiver/internal/metadata/generated_logs_test.go +++ b/receiver/sqlserverreceiver/internal/metadata/generated_logs_test.go @@ -134,10 +134,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", "sqlserver.procedure_id-val", "sqlserver.procedure_name-val", "sqlserver.procedure_type-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", "sqlserver.procedure_id-val", "sqlserver.procedure_name-val", "sqlserver.procedure_type-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") @@ -281,9 +281,6 @@ func TestLogsBuilder(t *testing.T) { attrVal, ok = lr.Attributes().Get("sqlserver.procedure_name") assert.True(t, ok) assert.Equal(t, "sqlserver.procedure_name-val", attrVal.Str()) - attrVal, ok = lr.Attributes().Get("sqlserver.procedure_type") - assert.True(t, ok) - assert.Equal(t, "sqlserver.procedure_type-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 @@ -342,9 +339,6 @@ func TestLogsBuilder(t *testing.T) { attrVal, ok = lr.Attributes().Get("sqlserver.procedure_name") assert.True(t, ok) assert.Equal(t, "sqlserver.procedure_name-val", attrVal.Str()) - attrVal, ok = lr.Attributes().Get("sqlserver.procedure_type") - assert.True(t, ok) - assert.Equal(t, "sqlserver.procedure_type-val", attrVal.Str()) } } }) diff --git a/receiver/sqlserverreceiver/metadata.yaml b/receiver/sqlserverreceiver/metadata.yaml index f7935b97d873f..90131ae0f091b 100644 --- a/receiver/sqlserverreceiver/metadata.yaml +++ b/receiver/sqlserverreceiver/metadata.yaml @@ -140,9 +140,6 @@ attributes: sqlserver.procedure_name: description: The name of the stored procedure, if any type: string - sqlserver.procedure_type: - description: The type code of the stored procedure, if any. Typically 'P' - 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 @@ -274,7 +271,6 @@ events: - user.name - sqlserver.procedure_id - sqlserver.procedure_name - - sqlserver.procedure_type db.server.top_query: enabled: false @@ -297,7 +293,6 @@ events: - db.system.name - sqlserver.procedure_id - sqlserver.procedure_name - - sqlserver.procedure_type metrics: sqlserver.batch.request.rate: diff --git a/receiver/sqlserverreceiver/scraper.go b/receiver/sqlserverreceiver/scraper.go index f891bcb72c369..559ea762743aa 100644 --- a/receiver/sqlserverreceiver/scraper.go +++ b/receiver/sqlserverreceiver/scraper.go @@ -642,7 +642,6 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont // stored procedure columns storedProcedureId = "procedure_id" storedProcedureName = "procedure_name" - storedProcedureType = "procedure_type" ) resources := pcommon.NewResource() @@ -665,7 +664,7 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont for i, row := range rows { queryHashVal := hex.EncodeToString([]byte(row[queryHash])) queryPlanHashVal := hex.EncodeToString([]byte(row[queryPlanHash])) - planId := row[storedProcedureId] + planId := row[storedProcedureId] // defaulted to '0' if not present elapsedTimeMicrosecond, err := strconv.ParseInt(row[totalElapsedTime], 10, 64) if err != nil { @@ -791,7 +790,6 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont dbSystemNameVal, row[storedProcedureId], row[storedProcedureName], - row[storedProcedureType], ) } return resources, errors.Join(errs...) @@ -821,22 +819,19 @@ func (s *sqlServerScraperHelper) cacheAndDiff(queryHash, queryPlanHash, procedur } key := queryHash + "-" + queryPlanHash + "-" + column - if procedureId != "" { + if procedureId != "0" { // procedureId is '0' when not a stored procedure key = procedureId + "-" + key } cached, ok := s.cache.Get(key) if !ok { s.cache.Add(key, val) - // s.logger.Info("Adding key", zap.String("key", key), zap.Int64("val", val)) return false, val } if val > cached { s.cache.Add(key, val) - // s.logger.Info("Returning cached diff for ", zap.String("key", key), zap.Int64("val", val)) return true, val - cached } - // s.logger.Info("Returning 0", zap.String("key", key), zap.Int64("val", val)) return true, 0 } @@ -947,7 +942,6 @@ func (s *sqlServerScraperHelper) recordDatabaseSampleQuery(ctx context.Context) // stored procedure columns const storedProcedureId = "procedure_id" const storedProcedureName = "procedure_name" - const storedProcedureType = "procedure_type" rows, err := s.client.QueryRows( ctx, @@ -1041,8 +1035,8 @@ func (s *sqlServerScraperHelper) recordDatabaseSampleQuery(ctx context.Context) } else { clientAddressVal = row[clientAddress] } - if row[storedProcedureId] != "0" { - s.logger.Info("Stored proc data", zap.String("id", row[storedProcedureId]), zap.String("name", row[storedProcedureName]), zap.String("type", row[storedProcedureType])) + 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, @@ -1059,7 +1053,7 @@ func (s *sqlServerScraperHelper) recordDatabaseSampleQuery(ctx context.Context) sessionIDVal, sessionStatusVal, totalElapsedTimeSecondVal, transactionIDVal, transactionIsolationLevelVal, waitResourceVal, waitTimeSecondVal, waitTypeVal, writesVal, usernameVal, - row[storedProcedureId], row[storedProcedureName], row[storedProcedureType], + row[storedProcedureId], row[storedProcedureName], ) if !resourcesAdded { diff --git a/receiver/sqlserverreceiver/scraper_test.go b/receiver/sqlserverreceiver/scraper_test.go index cbb751a447e2b..1107edd79c47b 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) } @@ -401,14 +401,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, @@ -460,14 +461,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 8868d930a144c..7dcbc0df5851f 100644 --- a/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl +++ b/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl @@ -33,10 +33,7 @@ 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, - ISNULL(CASE WHEN qs.object_id > 0 - THEN CONVERT(sysname, OBJECTPROPERTYEX(qs.object_id, 'BaseType')) -- 'P' (T-SQL) or 'PC' (CLR), '')) - END, '') AS procedure_type + END, '') AS procedure_name FROM qstats AS qs JOIN sys.dm_exec_query_stats AS stats ON stats.plan_handle = qs.plan_handle diff --git a/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl b/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl index 8412b25487eac..96774ccaf08a9 100644 --- a/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl +++ b/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl @@ -44,10 +44,7 @@ SELECT TOP(@top) 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, - ISNULL(CASE WHEN o.objectid > 0 - THEN CONVERT(sysname, OBJECTPROPERTYEX(o.objectid, 'BaseType')) - END, '') AS procedure_type + 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/databaseTopQueryWithoutInstanceName.txt b/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt index cc3ceef5bfc2e..7dcbc0df5851f 100644 --- a/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt +++ b/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt @@ -1,31 +1,41 @@ -with qstats as ( - SELECT TOP(@maxSampleCount) - REPLACE(@@SERVERNAME,'\',':') AS [sql_instance], - HOST_NAME() AS [computer_name], - MAX(qs.plan_handle) AS query_plan_handle, - qs.query_hash AS query_hash, - qs.query_plan_hash AS query_plan_hash, - SUM(qs.execution_count) AS execution_count, - SUM(qs.total_elapsed_time) AS total_elapsed_time, - SUM(qs.total_worker_time) AS total_worker_time, - SUM(qs.total_logical_reads) AS total_logical_reads, - SUM(qs.total_physical_reads) AS total_physical_reads, - SUM(qs.total_logical_writes) AS total_logical_writes, - SUM(qs.total_rows) AS total_rows, - SUM(qs.total_grant_kb) as total_grant_kb - FROM sys.dm_exec_query_stats AS qs - WHERE qs.last_execution_time BETWEEN DATEADD(SECOND, @lookbackTime, GETDATE()) AND GETDATE() - GROUP BY - qs.query_hash, - qs.query_plan_hash -) -SELECT qs.*, - SUBSTRING(st.text, (stats.statement_start_offset / 2) + 1, - ((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 -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; +;WITH qstats AS + ( + SELECT TOP 1000 + REPLACE(@@SERVERNAME,'\',':') AS [sql_instance], + HOST_NAME() AS [computer_name], + max(qs.plan_handle) AS plan_handle, + ISNULL(st1.objectid, 0) AS object_id, + qs.query_hash AS query_hash, + qs.query_plan_hash AS query_plan_hash, + SUM(qs.execution_count) AS execution_count, + SUM(qs.total_elapsed_time) AS total_elapsed_time, + SUM(qs.total_worker_time) AS total_worker_time, + SUM(qs.total_logical_reads) AS total_logical_reads, + SUM(qs.total_physical_reads) AS total_physical_reads, + SUM(qs.total_logical_writes) AS total_logical_writes, + 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 + WHERE qs.last_execution_time BETWEEN DATEADD(SECOND, -1200, GETDATE()) AND GETDATE() + GROUP BY st1.objectid, qs.query_hash, qs.query_plan_hash + ) + SELECT + qs.*, + SUBSTRING(st.text, + (stats.statement_start_offset / 2) + 1, + ((CASE stats.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(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 + JOIN sys.dm_exec_query_stats AS stats + ON stats.plan_handle = qs.plan_handle + CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) AS qp + CROSS APPLY sys.dm_exec_sql_text(qs.plan_handle) AS st; \ No newline at end of file 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/expectedQueryTextAndPlanQueryWithInvalidData.yaml b/receiver/sqlserverreceiver/testdata/expectedQueryTextAndPlanQueryWithInvalidData.yaml index b9c8b65d2503b..5d0c6d0036769 100644 --- a/receiver/sqlserverreceiver/testdata/expectedQueryTextAndPlanQueryWithInvalidData.yaml +++ b/receiver/sqlserverreceiver/testdata/expectedQueryTextAndPlanQueryWithInvalidData.yaml @@ -61,6 +61,12 @@ 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 spanId: "" 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 -CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS o; \ No newline at end of file + 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 + CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS o; + From 0e855367f49b64da1aa7e87ee814491aa67cb401 Mon Sep 17 00:00:00 2001 From: cjk Date: Wed, 26 Nov 2025 14:44:53 +0000 Subject: [PATCH 04/43] Added changelog entry --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24b0fcdd44b29..8010d523d177f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,8 @@ Starting with version v0.83.0, this changelog includes only user-facing changes. If you are looking for developer-facing changes, check out [CHANGELOG-API.md](./CHANGELOG-API.md). - - +- +- `receiver/sqlserverreceiver`: For TopQuery and Samples events, added stored procedure attributes sqlserver.procedure_id and sqlserver.procedure_name ## v0.140.1 From c155be3c5823c7f795d15faa78e2ecdb35aa3191 Mon Sep 17 00:00:00 2001 From: cjk Date: Wed, 26 Nov 2025 15:03:20 +0000 Subject: [PATCH 05/43] Added changelog entry --- ...sqlserver-stored-procedure-monitoring.yaml | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .chloggen/sqlserver-stored-procedure-monitoring.yaml diff --git a/.chloggen/sqlserver-stored-procedure-monitoring.yaml b/.chloggen/sqlserver-stored-procedure-monitoring.yaml new file mode 100644 index 0000000000000..14d58653587da --- /dev/null +++ b/.chloggen/sqlserver-stored-procedure-monitoring.yaml @@ -0,0 +1,27 @@ +# 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/sqlserverreceiver + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: adding 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: [1] + +# (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: + +# 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] From c1d747cf420a7a29301f830d6deeac3c0431ffe7 Mon Sep 17 00:00:00 2001 From: cjk Date: Wed, 26 Nov 2025 15:25:29 +0000 Subject: [PATCH 06/43] reverted changelog entry --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8010d523d177f..24b0fcdd44b29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,8 @@ Starting with version v0.83.0, this changelog includes only user-facing changes. If you are looking for developer-facing changes, check out [CHANGELOG-API.md](./CHANGELOG-API.md). -- -- `receiver/sqlserverreceiver`: For TopQuery and Samples events, added stored procedure attributes sqlserver.procedure_id and sqlserver.procedure_name + + ## v0.140.1 From f5a90a205848e5e4b24ad8e40bd56f6dd9af0d34 Mon Sep 17 00:00:00 2001 From: cjk Date: Wed, 26 Nov 2025 15:40:15 +0000 Subject: [PATCH 07/43] fix changelog entry --- .chloggen/sqlserver-stored-procedure-monitoring.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.chloggen/sqlserver-stored-procedure-monitoring.yaml b/.chloggen/sqlserver-stored-procedure-monitoring.yaml index 14d58653587da..73ea8f7213c26 100644 --- a/.chloggen/sqlserver-stored-procedure-monitoring.yaml +++ b/.chloggen/sqlserver-stored-procedure-monitoring.yaml @@ -4,7 +4,7 @@ change_type: enhancement # The name of the component, or a single word describing the area of concern, (e.g. receiver/filelog) -component: receiver/sqlserverreceiver +component: receiver/sqlserver # A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). note: adding sqlserver.procedure_id and sqlserver.procedure_name attributes to TopQuery and Sample Events From 0bc478534b7c82e6cd0f7c9012d27802ad9eba3b Mon Sep 17 00:00:00 2001 From: cjk Date: Wed, 26 Nov 2025 16:36:18 +0000 Subject: [PATCH 08/43] updates to variable naming and usage --- receiver/sqlserverreceiver/scraper.go | 24 +++++++-------- receiver/sqlserverreceiver/scraper_test.go | 36 +++++++++++----------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/receiver/sqlserverreceiver/scraper.go b/receiver/sqlserverreceiver/scraper.go index 559ea762743aa..52d71bdc0df68 100644 --- a/receiver/sqlserverreceiver/scraper.go +++ b/receiver/sqlserverreceiver/scraper.go @@ -640,7 +640,7 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont dbSystemNameVal = "microsoft.sql_server" // stored procedure columns - storedProcedureId = "procedure_id" + storedProcedureID = "procedure_id" storedProcedureName = "procedure_name" ) @@ -649,7 +649,7 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont rows, err := s.client.QueryRows( ctx, sql.Named("lookbackTime", -int(s.config.EffectiveLookbackTime().Seconds())), - sql.Named("maxSampleCount", s.config.MaxQuerySampleCount), + sql.Named("maxSampleCount", maxQuerySampleCount), ) if err != nil { if !errors.Is(err, sqlquery.ErrNullValueWarning) { @@ -664,7 +664,7 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont for i, row := range rows { queryHashVal := hex.EncodeToString([]byte(row[queryHash])) queryPlanHashVal := hex.EncodeToString([]byte(row[queryPlanHash])) - planId := row[storedProcedureId] // defaulted to '0' if not present + planId := row[storedProcedureID] // defaulted to '0' if not present elapsedTimeMicrosecond, err := strconv.ParseInt(row[totalElapsedTime], 10, 64) if err != nil { @@ -699,7 +699,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] + procId := row[storedProcedureID] queryTextVal := s.retrieveValue(row, queryText, &errs, func(row sqlquery.StringMap, columnName string) (any, error) { statement := row[columnName] @@ -788,7 +788,7 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont s.config.Server, int64(s.config.Port), dbSystemNameVal, - row[storedProcedureId], + row[storedProcedureID], row[storedProcedureName], ) } @@ -813,14 +813,14 @@ 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, procedureId, 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 + if procedureID != "0" { // procedureID is '0' when not a stored procedure + key = procedureID + "-" + key } cached, ok := s.cache.Get(key) if !ok { @@ -940,7 +940,7 @@ func (s *sqlServerScraperHelper) recordDatabaseSampleQuery(ctx context.Context) const waitType = "wait_type" const writes = "writes" // stored procedure columns - const storedProcedureId = "procedure_id" + const storedProcedureID = "procedure_id" const storedProcedureName = "procedure_name" rows, err := s.client.QueryRows( @@ -1035,8 +1035,8 @@ 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])) + 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, @@ -1053,7 +1053,7 @@ func (s *sqlServerScraperHelper) recordDatabaseSampleQuery(ctx context.Context) sessionIDVal, sessionStatusVal, totalElapsedTimeSecondVal, transactionIDVal, transactionIsolationLevelVal, waitResourceVal, waitTimeSecondVal, waitTypeVal, writesVal, usernameVal, - row[storedProcedureId], row[storedProcedureName], + row[storedProcedureID], row[storedProcedureName], ) if !resourcesAdded { diff --git a/receiver/sqlserverreceiver/scraper_test.go b/receiver/sqlserverreceiver/scraper_test.go index 1107edd79c47b..66ceff39043b3 100644 --- a/receiver/sqlserverreceiver/scraper_test.go +++ b/receiver/sqlserverreceiver/scraper_test.go @@ -401,15 +401,15 @@ func TestQueryTextAndPlanQuery(t *testing.T) { queryHash := hex.EncodeToString([]byte("0x37849E874171E3F3")) queryPlanHash := hex.EncodeToString([]byte("0xD3112909429A1B50")) - 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) + 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, @@ -461,15 +461,15 @@ func TestInvalidQueryTextAndPlanQuery(t *testing.T) { queryHash := hex.EncodeToString([]byte("0x37849E874171E3F3")) queryPlanHash := hex.EncodeToString([]byte("0xD3112909429A1B50")) - 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) + 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{ From f4eea598a95f211d12dd738ac707528850465b3c Mon Sep 17 00:00:00 2001 From: cjk Date: Wed, 26 Nov 2025 16:47:27 +0000 Subject: [PATCH 09/43] updates to variable naming and usage --- receiver/sqlserverreceiver/scraper.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/receiver/sqlserverreceiver/scraper.go b/receiver/sqlserverreceiver/scraper.go index 52d71bdc0df68..66f61ab59b722 100644 --- a/receiver/sqlserverreceiver/scraper.go +++ b/receiver/sqlserverreceiver/scraper.go @@ -664,7 +664,7 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont for i, row := range rows { queryHashVal := hex.EncodeToString([]byte(row[queryHash])) queryPlanHashVal := hex.EncodeToString([]byte(row[queryPlanHash])) - planId := row[storedProcedureID] // defaulted to '0' if not present + procID := row[storedProcedureID] // defaulted to '0' if not present elapsedTimeMicrosecond, err := strconv.ParseInt(row[totalElapsedTime], 10, 64) if err != nil { @@ -673,7 +673,7 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont } 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, planId, totalElapsedTime, elapsedTimeMicrosecond); cached && diff > 0 { + if cached, diff := s.cacheAndDiff(queryHashVal, queryPlanHashVal, procID, totalElapsedTime, elapsedTimeMicrosecond); cached && diff > 0 { totalElapsedTimeDiffsMicrosecond[i] = diff } } From 81d191fe2823ea0ae32d2c6f88eacd67a452d7e8 Mon Sep 17 00:00:00 2001 From: cjk Date: Wed, 26 Nov 2025 16:56:36 +0000 Subject: [PATCH 10/43] updates to variable naming and usage --- receiver/sqlserverreceiver/scraper.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/receiver/sqlserverreceiver/scraper.go b/receiver/sqlserverreceiver/scraper.go index 66f61ab59b722..77bfb54b9f7f1 100644 --- a/receiver/sqlserverreceiver/scraper.go +++ b/receiver/sqlserverreceiver/scraper.go @@ -699,7 +699,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] + procID := row[storedProcedureID] queryTextVal := s.retrieveValue(row, queryText, &errs, func(row sqlquery.StringMap, columnName string) (any, error) { statement := row[columnName] @@ -713,25 +713,25 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont }) executionCountVal := s.retrieveValue(row, executionCount, &errs, retrieveInt) - cached, executionCountVal := s.cacheAndDiff(queryHashVal, queryPlanHashVal, procId, 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, procId, 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, procId, 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, procId, physicalReads, physicalReadsVal.(int64)) + cached, physicalReadsVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, procID, physicalReads, physicalReadsVal.(int64)) if !cached { physicalReadsVal = int64(0) } @@ -741,19 +741,19 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont }) rowsReturnedVal := s.retrieveValue(row, rowsReturned, &errs, retrieveInt) - cached, rowsReturnedVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, procId, 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, procId, 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, procId, 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 From 8a2b5edb3af607701f38eab750f1a19595c08f5a Mon Sep 17 00:00:00 2001 From: cjk Date: Thu, 27 Nov 2025 10:01:57 +0000 Subject: [PATCH 11/43] ran make generate --- receiver/sqlserverreceiver/generated_package_test.go | 3 ++- .../sqlserverreceiver/internal/metadata/generated_logs.go | 1 + .../internal/metadata/generated_logs_test.go | 5 +++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/receiver/sqlserverreceiver/generated_package_test.go b/receiver/sqlserverreceiver/generated_package_test.go index 86266f5f36641..ce3721511beef 100644 --- a/receiver/sqlserverreceiver/generated_package_test.go +++ b/receiver/sqlserverreceiver/generated_package_test.go @@ -3,8 +3,9 @@ package sqlserverreceiver import ( - "go.uber.org/goleak" "testing" + + "go.uber.org/goleak" ) func TestMain(m *testing.M) { diff --git a/receiver/sqlserverreceiver/internal/metadata/generated_logs.go b/receiver/sqlserverreceiver/internal/metadata/generated_logs.go index 3f492b17762aa..0d7489892146a 100644 --- a/receiver/sqlserverreceiver/internal/metadata/generated_logs.go +++ b/receiver/sqlserverreceiver/internal/metadata/generated_logs.go @@ -4,6 +4,7 @@ package metadata import ( "context" + "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/filter" "go.opentelemetry.io/collector/pdata/pcommon" diff --git a/receiver/sqlserverreceiver/internal/metadata/generated_logs_test.go b/receiver/sqlserverreceiver/internal/metadata/generated_logs_test.go index e5ac43e808729..7038dc4bf960c 100644 --- a/receiver/sqlserverreceiver/internal/metadata/generated_logs_test.go +++ b/receiver/sqlserverreceiver/internal/metadata/generated_logs_test.go @@ -4,6 +4,9 @@ package metadata import ( "context" + "testing" + "time" + "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" @@ -11,8 +14,6 @@ import ( "go.opentelemetry.io/otel/trace" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" - "testing" - "time" ) type eventsTestDataSet int From 8024074db3666117ff74fcb1261e548a4f882dc2 Mon Sep 17 00:00:00 2001 From: cjk Date: Thu, 27 Nov 2025 15:07:02 +0000 Subject: [PATCH 12/43] Moved QuerySampleCount and TopQueryCount ot of params and reference config obj directly --- receiver/sqlserverreceiver/scraper.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/receiver/sqlserverreceiver/scraper.go b/receiver/sqlserverreceiver/scraper.go index 77bfb54b9f7f1..677e22a739965 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, s.config.MaxQuerySampleCount) + 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, maxQuerySampleCount 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" @@ -649,7 +649,7 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont rows, err := s.client.QueryRows( ctx, sql.Named("lookbackTime", -int(s.config.EffectiveLookbackTime().Seconds())), - sql.Named("maxSampleCount", maxQuerySampleCount), + sql.Named("maxSampleCount", s.config.MaxQuerySampleCount), ) if err != nil { if !errors.Is(err, sqlquery.ErrNullValueWarning) { @@ -680,7 +680,7 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont } // 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] }) From 08900201d6e619d0150593c3322b4568dd4c0275 Mon Sep 17 00:00:00 2001 From: cjk Date: Mon, 1 Dec 2025 10:29:15 +0000 Subject: [PATCH 13/43] Added issue to changelog --- .chloggen/sqlserver-stored-procedure-monitoring.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.chloggen/sqlserver-stored-procedure-monitoring.yaml b/.chloggen/sqlserver-stored-procedure-monitoring.yaml index 73ea8f7213c26..7b2f6e03d325a 100644 --- a/.chloggen/sqlserver-stored-procedure-monitoring.yaml +++ b/.chloggen/sqlserver-stored-procedure-monitoring.yaml @@ -10,7 +10,7 @@ component: receiver/sqlserver note: adding 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: [1] +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. From fb96860cbdbe0b10828f7c195b259fb1ab2ea63c Mon Sep 17 00:00:00 2001 From: cjk Date: Tue, 2 Dec 2025 10:33:27 +0000 Subject: [PATCH 14/43] Replaced values with vars --- receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl b/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl index 7dcbc0df5851f..20da91dea8a26 100644 --- a/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl +++ b/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl @@ -1,6 +1,6 @@ ;WITH qstats AS ( - SELECT TOP 1000 + SELECT TOP (@maxSampleCount) REPLACE(@@SERVERNAME,'\',':') AS [sql_instance], HOST_NAME() AS [computer_name], max(qs.plan_handle) AS plan_handle, @@ -17,7 +17,7 @@ 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 - WHERE qs.last_execution_time BETWEEN DATEADD(SECOND, -1200, GETDATE()) AND GETDATE() + WHERE qs.last_execution_time BETWEEN DATEADD(SECOND, @lookbackTime, GETDATE()) AND GETDATE() GROUP BY st1.objectid, qs.query_hash, qs.query_plan_hash ) SELECT From c5d313a9479ae361bb09731b8478c30a82f948cb Mon Sep 17 00:00:00 2001 From: cjk Date: Tue, 2 Dec 2025 13:12:27 +0000 Subject: [PATCH 15/43] Integrating stored procedure values for samples --- receiver/postgresqlreceiver/documentation.md | 2 ++ .../internal/metadata/generated_logs.go | 8 +++++--- .../internal/metadata/generated_logs_test.go | 8 +++++++- receiver/postgresqlreceiver/metadata.yaml | 8 ++++++++ receiver/postgresqlreceiver/scraper.go | 2 ++ 5 files changed, 24 insertions(+), 4 deletions(-) diff --git a/receiver/postgresqlreceiver/documentation.md b/receiver/postgresqlreceiver/documentation.md index a5376dd9388cf..38316fb9f4f20 100644 --- a/receiver/postgresqlreceiver/documentation.md +++ b/receiver/postgresqlreceiver/documentation.md @@ -422,6 +422,8 @@ query sample | postgresql.wait_event_type | The type of event for which the backend is waiting, if any; otherwise NULL. | Any Str | | postgresql.query_id | Identifier of this backend's most recent query. If state is active this field shows the identifier of the currently executing query. In all other states, it shows the identifier of last query that was executed. | Any Str | | postgresql.total_exec_time | Total time spent executing the statement, in delta milliseconds. | Any Double | +| postgresql.procedure_id | Identifier of the stored procedure. | Any Str | +| postgresql.procedure_name | Name of the stored procedure. | Any Str | ### db.server.top_query diff --git a/receiver/postgresqlreceiver/internal/metadata/generated_logs.go b/receiver/postgresqlreceiver/internal/metadata/generated_logs.go index 2c7e326e7817b..467a6edb2a1f0 100644 --- a/receiver/postgresqlreceiver/internal/metadata/generated_logs.go +++ b/receiver/postgresqlreceiver/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, dbSystemNameAttributeValue string, dbNamespaceAttributeValue string, dbQueryTextAttributeValue string, userNameAttributeValue string, postgresqlStateAttributeValue string, postgresqlPidAttributeValue int64, postgresqlApplicationNameAttributeValue string, networkPeerAddressAttributeValue string, networkPeerPortAttributeValue int64, postgresqlClientHostnameAttributeValue string, postgresqlQueryStartAttributeValue string, postgresqlWaitEventAttributeValue string, postgresqlWaitEventTypeAttributeValue string, postgresqlQueryIDAttributeValue string, postgresqlTotalExecTimeAttributeValue float64) { +func (e *eventDbServerQuerySample) recordEvent(ctx context.Context, timestamp pcommon.Timestamp, dbSystemNameAttributeValue string, dbNamespaceAttributeValue string, dbQueryTextAttributeValue string, userNameAttributeValue string, postgresqlStateAttributeValue string, postgresqlPidAttributeValue int64, postgresqlApplicationNameAttributeValue string, networkPeerAddressAttributeValue string, networkPeerPortAttributeValue int64, postgresqlClientHostnameAttributeValue string, postgresqlQueryStartAttributeValue string, postgresqlWaitEventAttributeValue string, postgresqlWaitEventTypeAttributeValue string, postgresqlQueryIDAttributeValue string, postgresqlTotalExecTimeAttributeValue float64, postgresqlProcedureIDAttributeValue string, postgresqlProcedureNameAttributeValue string) { if !e.config.Enabled { return } @@ -45,6 +45,8 @@ func (e *eventDbServerQuerySample) recordEvent(ctx context.Context, timestamp pc dp.Attributes().PutStr("postgresql.wait_event_type", postgresqlWaitEventTypeAttributeValue) dp.Attributes().PutStr("postgresql.query_id", postgresqlQueryIDAttributeValue) dp.Attributes().PutDouble("postgresql.total_exec_time", postgresqlTotalExecTimeAttributeValue) + dp.Attributes().PutStr("postgresql.procedure_id", postgresqlProcedureIDAttributeValue) + dp.Attributes().PutStr("postgresql.procedure_name", postgresqlProcedureNameAttributeValue) } @@ -249,8 +251,8 @@ 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, dbSystemNameAttributeValue AttributeDbSystemName, dbNamespaceAttributeValue string, dbQueryTextAttributeValue string, userNameAttributeValue string, postgresqlStateAttributeValue string, postgresqlPidAttributeValue int64, postgresqlApplicationNameAttributeValue string, networkPeerAddressAttributeValue string, networkPeerPortAttributeValue int64, postgresqlClientHostnameAttributeValue string, postgresqlQueryStartAttributeValue string, postgresqlWaitEventAttributeValue string, postgresqlWaitEventTypeAttributeValue string, postgresqlQueryIDAttributeValue string, postgresqlTotalExecTimeAttributeValue float64) { - lb.eventDbServerQuerySample.recordEvent(ctx, timestamp, dbSystemNameAttributeValue.String(), dbNamespaceAttributeValue, dbQueryTextAttributeValue, userNameAttributeValue, postgresqlStateAttributeValue, postgresqlPidAttributeValue, postgresqlApplicationNameAttributeValue, networkPeerAddressAttributeValue, networkPeerPortAttributeValue, postgresqlClientHostnameAttributeValue, postgresqlQueryStartAttributeValue, postgresqlWaitEventAttributeValue, postgresqlWaitEventTypeAttributeValue, postgresqlQueryIDAttributeValue, postgresqlTotalExecTimeAttributeValue) +func (lb *LogsBuilder) RecordDbServerQuerySampleEvent(ctx context.Context, timestamp pcommon.Timestamp, dbSystemNameAttributeValue AttributeDbSystemName, dbNamespaceAttributeValue string, dbQueryTextAttributeValue string, userNameAttributeValue string, postgresqlStateAttributeValue string, postgresqlPidAttributeValue int64, postgresqlApplicationNameAttributeValue string, networkPeerAddressAttributeValue string, networkPeerPortAttributeValue int64, postgresqlClientHostnameAttributeValue string, postgresqlQueryStartAttributeValue string, postgresqlWaitEventAttributeValue string, postgresqlWaitEventTypeAttributeValue string, postgresqlQueryIDAttributeValue string, postgresqlTotalExecTimeAttributeValue float64, postgresqlProcedureIDAttributeValue string, postgresqlProcedureNameAttributeValue string) { + lb.eventDbServerQuerySample.recordEvent(ctx, timestamp, dbSystemNameAttributeValue.String(), dbNamespaceAttributeValue, dbQueryTextAttributeValue, userNameAttributeValue, postgresqlStateAttributeValue, postgresqlPidAttributeValue, postgresqlApplicationNameAttributeValue, networkPeerAddressAttributeValue, networkPeerPortAttributeValue, postgresqlClientHostnameAttributeValue, postgresqlQueryStartAttributeValue, postgresqlWaitEventAttributeValue, postgresqlWaitEventTypeAttributeValue, postgresqlQueryIDAttributeValue, postgresqlTotalExecTimeAttributeValue, postgresqlProcedureIDAttributeValue, postgresqlProcedureNameAttributeValue) } // RecordDbServerTopQueryEvent adds a log record of db.server.top_query event. diff --git a/receiver/postgresqlreceiver/internal/metadata/generated_logs_test.go b/receiver/postgresqlreceiver/internal/metadata/generated_logs_test.go index 3eec76a985dd8..5f3d26d9bb1d9 100644 --- a/receiver/postgresqlreceiver/internal/metadata/generated_logs_test.go +++ b/receiver/postgresqlreceiver/internal/metadata/generated_logs_test.go @@ -132,7 +132,7 @@ func TestLogsBuilder(t *testing.T) { allEventsCount := 0 defaultEventsCount++ allEventsCount++ - lb.RecordDbServerQuerySampleEvent(ctx, timestamp, AttributeDbSystemNamePostgresql, "db.namespace-val", "db.query.text-val", "user.name-val", "postgresql.state-val", 14, "postgresql.application_name-val", "network.peer.address-val", 17, "postgresql.client_hostname-val", "postgresql.query_start-val", "postgresql.wait_event-val", "postgresql.wait_event_type-val", "postgresql.query_id-val", 26.100000) + lb.RecordDbServerQuerySampleEvent(ctx, timestamp, AttributeDbSystemNamePostgresql, "db.namespace-val", "db.query.text-val", "user.name-val", "postgresql.state-val", 14, "postgresql.application_name-val", "network.peer.address-val", 17, "postgresql.client_hostname-val", "postgresql.query_start-val", "postgresql.wait_event-val", "postgresql.wait_event_type-val", "postgresql.query_id-val", 26.100000, "postgresql.procedure_id-val", "postgresql.procedure_name-val") defaultEventsCount++ allEventsCount++ lb.RecordDbServerTopQueryEvent(ctx, timestamp, AttributeDbSystemNamePostgresql, "db.namespace-val", "db.query.text-val", 16, 15, 30, 26, 27, 30, 25, 28, "postgresql.queryid-val", "postgresql.rolname-val", 26.100000, 26.100000, "postgresql.query_plan-val") @@ -216,6 +216,12 @@ func TestLogsBuilder(t *testing.T) { attrVal, ok = lr.Attributes().Get("postgresql.total_exec_time") assert.True(t, ok) assert.Equal(t, 26.100000, attrVal.Double()) + attrVal, ok = lr.Attributes().Get("postgresql.procedure_id") + assert.True(t, ok) + assert.Equal(t, "postgresql.procedure_id-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("postgresql.procedure_name") + assert.True(t, ok) + assert.Equal(t, "postgresql.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 diff --git a/receiver/postgresqlreceiver/metadata.yaml b/receiver/postgresqlreceiver/metadata.yaml index 4275c1dd70bf0..e4ef5e6fb962f 100644 --- a/receiver/postgresqlreceiver/metadata.yaml +++ b/receiver/postgresqlreceiver/metadata.yaml @@ -94,6 +94,12 @@ attributes: postgresql.pid: description: Process ID of this backend. type: int + postgresql.procedure_id: + description: Identifier of the stored procedure. + type: string + postgresql.procedure_name: + description: Name of the stored procedure. + type: string postgresql.query_id: description: Identifier of this backend's most recent query. If state is active this field shows the identifier of the currently executing query. In all other states, it shows the identifier of last query that was executed. type: string @@ -196,6 +202,8 @@ events: - postgresql.wait_event_type - postgresql.query_id - postgresql.total_exec_time + - postgresql.procedure_id + - postgresql.procedure_name db.server.top_query: enabled: true description: top query diff --git a/receiver/postgresqlreceiver/scraper.go b/receiver/postgresqlreceiver/scraper.go index b06a4856e0e35..5b8d2164e2f1f 100644 --- a/receiver/postgresqlreceiver/scraper.go +++ b/receiver/postgresqlreceiver/scraper.go @@ -227,6 +227,8 @@ func (p *postgreSQLScraper) collectQuerySamples(ctx context.Context, dbClient cl atts[dbAttributePrefix+"wait_event_type"].(string), atts[dbAttributePrefix+"query_id"].(string), atts["duration"].(float64), + atts[dbAttributePrefix+"procedure_id"].(string), + atts[dbAttributePrefix+"procedure_name"].(string), ) } } From 28fa28f3b3e7b02c5373658403b5e7d4a8622ddb Mon Sep 17 00:00:00 2001 From: cjk Date: Tue, 2 Dec 2025 13:34:27 +0000 Subject: [PATCH 16/43] updates to test data --- .../databaseTopQueryWithInstanceName.txt | 72 +++++++++++-------- .../databaseTopQueryWithoutInstanceName.txt | 4 +- 2 files changed, 43 insertions(+), 33 deletions(-) diff --git a/receiver/sqlserverreceiver/testdata/databaseTopQueryWithInstanceName.txt b/receiver/sqlserverreceiver/testdata/databaseTopQueryWithInstanceName.txt index 29228f5aba2e4..6e223d1ae7dc0 100644 --- a/receiver/sqlserverreceiver/testdata/databaseTopQueryWithInstanceName.txt +++ b/receiver/sqlserverreceiver/testdata/databaseTopQueryWithInstanceName.txt @@ -1,31 +1,41 @@ -with qstats as ( - SELECT TOP(@topNValue) - REPLACE(@@SERVERNAME,'\',':') AS [sql_instance], - HOST_NAME() AS [computer_name], - MAX(qs.plan_handle) AS query_plan_handle, - qs.query_hash AS query_hash, - qs.query_plan_hash AS query_plan_hash, - SUM(qs.execution_count) AS execution_count, - SUM(qs.total_elapsed_time) AS total_elapsed_time, - SUM(qs.total_worker_time) AS total_worker_time, - SUM(qs.total_logical_reads) AS total_logical_reads, - SUM(qs.total_physical_reads) AS total_physical_reads, - SUM(qs.total_logical_writes) AS total_logical_writes, - SUM(qs.total_rows) AS total_rows, - SUM(qs.total_grant_kb) as total_grant_kb - FROM sys.dm_exec_query_stats AS qs - WHERE qs.last_execution_time BETWEEN DATEADD(SECOND, @lookbackTime, GETDATE()) AND GETDATE() AND (@instanceName = '' OR @@SERVERNAME = @instanceName) - GROUP BY - qs.query_hash, - qs.query_plan_hash -) -SELECT qs.*, - SUBSTRING(st.text, (stats.statement_start_offset / 2) + 1, - ((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 -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; +;WITH qstats AS + ( + SELECT TOP 1000 + REPLACE(@@SERVERNAME,'\',':') AS [sql_instance], + HOST_NAME() AS [computer_name], + max(qs.plan_handle) AS plan_handle, + ISNULL(st1.objectid, 0) AS object_id, + qs.query_hash AS query_hash, + qs.query_plan_hash AS query_plan_hash, + SUM(qs.execution_count) AS execution_count, + SUM(qs.total_elapsed_time) AS total_elapsed_time, + SUM(qs.total_worker_time) AS total_worker_time, + SUM(qs.total_logical_reads) AS total_logical_reads, + SUM(qs.total_physical_reads) AS total_physical_reads, + SUM(qs.total_logical_writes) AS total_logical_writes, + 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 + WHERE qs.last_execution_time BETWEEN DATEADD(SECOND, -60, GETDATE()) AND GETDATE() + GROUP BY st1.objectid, qs.query_hash, qs.query_plan_hash + ) + SELECT + qs.*, + SUBSTRING(st.text, + (stats.statement_start_offset / 2) + 1, + ((CASE stats.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(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 + JOIN sys.dm_exec_query_stats AS stats + ON stats.plan_handle = qs.plan_handle + CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) AS qp + CROSS APPLY sys.dm_exec_sql_text(qs.plan_handle) AS st; \ No newline at end of file diff --git a/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt b/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt index 7dcbc0df5851f..20da91dea8a26 100644 --- a/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt +++ b/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt @@ -1,6 +1,6 @@ ;WITH qstats AS ( - SELECT TOP 1000 + SELECT TOP (@maxSampleCount) REPLACE(@@SERVERNAME,'\',':') AS [sql_instance], HOST_NAME() AS [computer_name], max(qs.plan_handle) AS plan_handle, @@ -17,7 +17,7 @@ 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 - WHERE qs.last_execution_time BETWEEN DATEADD(SECOND, -1200, GETDATE()) AND GETDATE() + WHERE qs.last_execution_time BETWEEN DATEADD(SECOND, @lookbackTime, GETDATE()) AND GETDATE() GROUP BY st1.objectid, qs.query_hash, qs.query_plan_hash ) SELECT From c8efaec35a8df964a7bef461098889265b4b0f67 Mon Sep 17 00:00:00 2001 From: cjk Date: Tue, 2 Dec 2025 13:39:01 +0000 Subject: [PATCH 17/43] Backout unintended merge --- receiver/postgresqlreceiver/documentation.md | 2 -- .../internal/metadata/generated_logs.go | 8 +++----- .../internal/metadata/generated_logs_test.go | 8 +------- receiver/postgresqlreceiver/metadata.yaml | 8 -------- receiver/postgresqlreceiver/scraper.go | 2 -- 5 files changed, 4 insertions(+), 24 deletions(-) diff --git a/receiver/postgresqlreceiver/documentation.md b/receiver/postgresqlreceiver/documentation.md index 38316fb9f4f20..a5376dd9388cf 100644 --- a/receiver/postgresqlreceiver/documentation.md +++ b/receiver/postgresqlreceiver/documentation.md @@ -422,8 +422,6 @@ query sample | postgresql.wait_event_type | The type of event for which the backend is waiting, if any; otherwise NULL. | Any Str | | postgresql.query_id | Identifier of this backend's most recent query. If state is active this field shows the identifier of the currently executing query. In all other states, it shows the identifier of last query that was executed. | Any Str | | postgresql.total_exec_time | Total time spent executing the statement, in delta milliseconds. | Any Double | -| postgresql.procedure_id | Identifier of the stored procedure. | Any Str | -| postgresql.procedure_name | Name of the stored procedure. | Any Str | ### db.server.top_query diff --git a/receiver/postgresqlreceiver/internal/metadata/generated_logs.go b/receiver/postgresqlreceiver/internal/metadata/generated_logs.go index 467a6edb2a1f0..2c7e326e7817b 100644 --- a/receiver/postgresqlreceiver/internal/metadata/generated_logs.go +++ b/receiver/postgresqlreceiver/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, dbSystemNameAttributeValue string, dbNamespaceAttributeValue string, dbQueryTextAttributeValue string, userNameAttributeValue string, postgresqlStateAttributeValue string, postgresqlPidAttributeValue int64, postgresqlApplicationNameAttributeValue string, networkPeerAddressAttributeValue string, networkPeerPortAttributeValue int64, postgresqlClientHostnameAttributeValue string, postgresqlQueryStartAttributeValue string, postgresqlWaitEventAttributeValue string, postgresqlWaitEventTypeAttributeValue string, postgresqlQueryIDAttributeValue string, postgresqlTotalExecTimeAttributeValue float64, postgresqlProcedureIDAttributeValue string, postgresqlProcedureNameAttributeValue string) { +func (e *eventDbServerQuerySample) recordEvent(ctx context.Context, timestamp pcommon.Timestamp, dbSystemNameAttributeValue string, dbNamespaceAttributeValue string, dbQueryTextAttributeValue string, userNameAttributeValue string, postgresqlStateAttributeValue string, postgresqlPidAttributeValue int64, postgresqlApplicationNameAttributeValue string, networkPeerAddressAttributeValue string, networkPeerPortAttributeValue int64, postgresqlClientHostnameAttributeValue string, postgresqlQueryStartAttributeValue string, postgresqlWaitEventAttributeValue string, postgresqlWaitEventTypeAttributeValue string, postgresqlQueryIDAttributeValue string, postgresqlTotalExecTimeAttributeValue float64) { if !e.config.Enabled { return } @@ -45,8 +45,6 @@ func (e *eventDbServerQuerySample) recordEvent(ctx context.Context, timestamp pc dp.Attributes().PutStr("postgresql.wait_event_type", postgresqlWaitEventTypeAttributeValue) dp.Attributes().PutStr("postgresql.query_id", postgresqlQueryIDAttributeValue) dp.Attributes().PutDouble("postgresql.total_exec_time", postgresqlTotalExecTimeAttributeValue) - dp.Attributes().PutStr("postgresql.procedure_id", postgresqlProcedureIDAttributeValue) - dp.Attributes().PutStr("postgresql.procedure_name", postgresqlProcedureNameAttributeValue) } @@ -251,8 +249,8 @@ 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, dbSystemNameAttributeValue AttributeDbSystemName, dbNamespaceAttributeValue string, dbQueryTextAttributeValue string, userNameAttributeValue string, postgresqlStateAttributeValue string, postgresqlPidAttributeValue int64, postgresqlApplicationNameAttributeValue string, networkPeerAddressAttributeValue string, networkPeerPortAttributeValue int64, postgresqlClientHostnameAttributeValue string, postgresqlQueryStartAttributeValue string, postgresqlWaitEventAttributeValue string, postgresqlWaitEventTypeAttributeValue string, postgresqlQueryIDAttributeValue string, postgresqlTotalExecTimeAttributeValue float64, postgresqlProcedureIDAttributeValue string, postgresqlProcedureNameAttributeValue string) { - lb.eventDbServerQuerySample.recordEvent(ctx, timestamp, dbSystemNameAttributeValue.String(), dbNamespaceAttributeValue, dbQueryTextAttributeValue, userNameAttributeValue, postgresqlStateAttributeValue, postgresqlPidAttributeValue, postgresqlApplicationNameAttributeValue, networkPeerAddressAttributeValue, networkPeerPortAttributeValue, postgresqlClientHostnameAttributeValue, postgresqlQueryStartAttributeValue, postgresqlWaitEventAttributeValue, postgresqlWaitEventTypeAttributeValue, postgresqlQueryIDAttributeValue, postgresqlTotalExecTimeAttributeValue, postgresqlProcedureIDAttributeValue, postgresqlProcedureNameAttributeValue) +func (lb *LogsBuilder) RecordDbServerQuerySampleEvent(ctx context.Context, timestamp pcommon.Timestamp, dbSystemNameAttributeValue AttributeDbSystemName, dbNamespaceAttributeValue string, dbQueryTextAttributeValue string, userNameAttributeValue string, postgresqlStateAttributeValue string, postgresqlPidAttributeValue int64, postgresqlApplicationNameAttributeValue string, networkPeerAddressAttributeValue string, networkPeerPortAttributeValue int64, postgresqlClientHostnameAttributeValue string, postgresqlQueryStartAttributeValue string, postgresqlWaitEventAttributeValue string, postgresqlWaitEventTypeAttributeValue string, postgresqlQueryIDAttributeValue string, postgresqlTotalExecTimeAttributeValue float64) { + lb.eventDbServerQuerySample.recordEvent(ctx, timestamp, dbSystemNameAttributeValue.String(), dbNamespaceAttributeValue, dbQueryTextAttributeValue, userNameAttributeValue, postgresqlStateAttributeValue, postgresqlPidAttributeValue, postgresqlApplicationNameAttributeValue, networkPeerAddressAttributeValue, networkPeerPortAttributeValue, postgresqlClientHostnameAttributeValue, postgresqlQueryStartAttributeValue, postgresqlWaitEventAttributeValue, postgresqlWaitEventTypeAttributeValue, postgresqlQueryIDAttributeValue, postgresqlTotalExecTimeAttributeValue) } // RecordDbServerTopQueryEvent adds a log record of db.server.top_query event. diff --git a/receiver/postgresqlreceiver/internal/metadata/generated_logs_test.go b/receiver/postgresqlreceiver/internal/metadata/generated_logs_test.go index 5f3d26d9bb1d9..3eec76a985dd8 100644 --- a/receiver/postgresqlreceiver/internal/metadata/generated_logs_test.go +++ b/receiver/postgresqlreceiver/internal/metadata/generated_logs_test.go @@ -132,7 +132,7 @@ func TestLogsBuilder(t *testing.T) { allEventsCount := 0 defaultEventsCount++ allEventsCount++ - lb.RecordDbServerQuerySampleEvent(ctx, timestamp, AttributeDbSystemNamePostgresql, "db.namespace-val", "db.query.text-val", "user.name-val", "postgresql.state-val", 14, "postgresql.application_name-val", "network.peer.address-val", 17, "postgresql.client_hostname-val", "postgresql.query_start-val", "postgresql.wait_event-val", "postgresql.wait_event_type-val", "postgresql.query_id-val", 26.100000, "postgresql.procedure_id-val", "postgresql.procedure_name-val") + lb.RecordDbServerQuerySampleEvent(ctx, timestamp, AttributeDbSystemNamePostgresql, "db.namespace-val", "db.query.text-val", "user.name-val", "postgresql.state-val", 14, "postgresql.application_name-val", "network.peer.address-val", 17, "postgresql.client_hostname-val", "postgresql.query_start-val", "postgresql.wait_event-val", "postgresql.wait_event_type-val", "postgresql.query_id-val", 26.100000) defaultEventsCount++ allEventsCount++ lb.RecordDbServerTopQueryEvent(ctx, timestamp, AttributeDbSystemNamePostgresql, "db.namespace-val", "db.query.text-val", 16, 15, 30, 26, 27, 30, 25, 28, "postgresql.queryid-val", "postgresql.rolname-val", 26.100000, 26.100000, "postgresql.query_plan-val") @@ -216,12 +216,6 @@ func TestLogsBuilder(t *testing.T) { attrVal, ok = lr.Attributes().Get("postgresql.total_exec_time") assert.True(t, ok) assert.Equal(t, 26.100000, attrVal.Double()) - attrVal, ok = lr.Attributes().Get("postgresql.procedure_id") - assert.True(t, ok) - assert.Equal(t, "postgresql.procedure_id-val", attrVal.Str()) - attrVal, ok = lr.Attributes().Get("postgresql.procedure_name") - assert.True(t, ok) - assert.Equal(t, "postgresql.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 diff --git a/receiver/postgresqlreceiver/metadata.yaml b/receiver/postgresqlreceiver/metadata.yaml index e4ef5e6fb962f..4275c1dd70bf0 100644 --- a/receiver/postgresqlreceiver/metadata.yaml +++ b/receiver/postgresqlreceiver/metadata.yaml @@ -94,12 +94,6 @@ attributes: postgresql.pid: description: Process ID of this backend. type: int - postgresql.procedure_id: - description: Identifier of the stored procedure. - type: string - postgresql.procedure_name: - description: Name of the stored procedure. - type: string postgresql.query_id: description: Identifier of this backend's most recent query. If state is active this field shows the identifier of the currently executing query. In all other states, it shows the identifier of last query that was executed. type: string @@ -202,8 +196,6 @@ events: - postgresql.wait_event_type - postgresql.query_id - postgresql.total_exec_time - - postgresql.procedure_id - - postgresql.procedure_name db.server.top_query: enabled: true description: top query diff --git a/receiver/postgresqlreceiver/scraper.go b/receiver/postgresqlreceiver/scraper.go index 5b8d2164e2f1f..b06a4856e0e35 100644 --- a/receiver/postgresqlreceiver/scraper.go +++ b/receiver/postgresqlreceiver/scraper.go @@ -227,8 +227,6 @@ func (p *postgreSQLScraper) collectQuerySamples(ctx context.Context, dbClient cl atts[dbAttributePrefix+"wait_event_type"].(string), atts[dbAttributePrefix+"query_id"].(string), atts["duration"].(float64), - atts[dbAttributePrefix+"procedure_id"].(string), - atts[dbAttributePrefix+"procedure_name"].(string), ) } } From 7ba3c74aeab51b127f1953cd69af466f1d9d627c Mon Sep 17 00:00:00 2001 From: cjk Date: Wed, 17 Dec 2025 10:08:52 +0000 Subject: [PATCH 18/43] updating change log --- ...sqlserver-stored-procedure-monitoring.yaml | 27 ------------------- 1 file changed, 27 deletions(-) delete mode 100644 .chloggen/sqlserver-stored-procedure-monitoring.yaml diff --git a/.chloggen/sqlserver-stored-procedure-monitoring.yaml b/.chloggen/sqlserver-stored-procedure-monitoring.yaml deleted file mode 100644 index 7b2f6e03d325a..0000000000000 --- a/.chloggen/sqlserver-stored-procedure-monitoring.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# 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: adding 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: - -# 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] From f9531c39b36145e778a6431633ccda92e83a6ba8 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Mon, 5 Jan 2026 15:57:08 +0000 Subject: [PATCH 19/43] Fix for inaccurate query count being reported in postgresql query metrics collection --- receiver/sqlserverreceiver/scraper.go | 66 ++++++++++++------- receiver/sqlserverreceiver/scraper_test.go | 62 +++++++++++++++++ .../templates/dbQueryAndTextQuery.tmpl | 4 +- .../databaseTopQueryWithoutInstanceName.txt | 4 +- .../expectedQueryTextAndPlanQuery.yaml | 59 +++++++++++++++-- .../testdata/queryTextAndPlanQueryData.txt | 19 +++++- 6 files changed, 179 insertions(+), 35 deletions(-) diff --git a/receiver/sqlserverreceiver/scraper.go b/receiver/sqlserverreceiver/scraper.go index a04218f62ca4a..7f52155afe69f 100644 --- a/receiver/sqlserverreceiver/scraper.go +++ b/receiver/sqlserverreceiver/scraper.go @@ -686,11 +686,7 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont timestamp := pcommon.NewTimestampFromTime(now) s.lastExecutionTimestamp = now for i, row := range rows { - // skipping the rest of the rows as totalElapsedTimeDiffs is sorted in descending order - if totalElapsedTimeDiffsMicrosecond[i] == 0 { - break - } - totalElapsedTimeVal := float64(totalElapsedTimeDiffsMicrosecond[i]) / 1_000_000 + totalElapsedTimeValDiff := float64(totalElapsedTimeDiffsMicrosecond[i]) / 1_000_000 // reporting human-readable query hash and query hash plan queryHashVal := hex.EncodeToString([]byte(row[queryHash])) @@ -707,28 +703,30 @@ 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, executionCountValDiff := s.cacheAndDiff(queryHashVal, queryPlanHashVal, executionCount, executionCountVal.(int64)) if !cached { - executionCountVal = int64(0) + executionCountValDiff = int64(0) } logicalReadsVal := s.retrieveValue(row, logicalReads, &errs, retrieveInt) - cached, logicalReadsVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, logicalReads, logicalReadsVal.(int64)) + cached, logicalReadsValDiff := s.cacheAndDiff(queryHashVal, queryPlanHashVal, logicalReads, logicalReadsVal.(int64)) if !cached { - logicalReadsVal = int64(0) + logicalReadsValDiff = int64(0) } logicalWritesVal := s.retrieveValue(row, logicalWrites, &errs, retrieveInt) - cached, logicalWritesVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, logicalWrites, logicalWritesVal.(int64)) + cached, logicalWritesValDiff := s.cacheAndDiff(queryHashVal, queryPlanHashVal, logicalWrites, logicalWritesVal.(int64)) if !cached { - logicalWritesVal = int64(0) + logicalWritesValDiff = int64(0) } physicalReadsVal := s.retrieveValue(row, physicalReads, &errs, retrieveInt) - cached, physicalReadsVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, physicalReads, physicalReadsVal.(int64)) + cached, physicalReadsValDiff := s.cacheAndDiff(queryHashVal, queryPlanHashVal, physicalReads, physicalReadsVal.(int64)) if !cached { - physicalReadsVal = int64(0) + physicalReadsValDiff = int64(0) } queryPlanVal := s.retrieveValue(row, queryPlan, &errs, func(row sqlquery.StringMap, columnName string) (any, error) { @@ -736,22 +734,43 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont }) rowsReturnedVal := s.retrieveValue(row, rowsReturned, &errs, retrieveInt) - cached, rowsReturnedVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, rowsReturned, rowsReturnedVal.(int64)) + cached, rowsReturnedValDiff := s.cacheAndDiff(queryHashVal, queryPlanHashVal, rowsReturned, rowsReturnedVal.(int64)) if !cached { - rowsReturnedVal = int64(0) + rowsReturnedValDiff = int64(0) } totalGrantVal := s.retrieveValue(row, totalGrant, &errs, retrieveInt) - cached, totalGrantVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, totalGrant, totalGrantVal.(int64)) + cached, totalGrantValDiff := s.cacheAndDiff(queryHashVal, queryPlanHashVal, totalGrant, totalGrantVal.(int64)) if !cached { - totalGrantVal = int64(0) + totalGrantValDiff = int64(0) } - totalWorkerTimeVal := s.retrieveValue(row, totalWorkerTime, &errs, retrieveInt) - cached, totalWorkerTimeVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, totalWorkerTime, totalWorkerTimeVal.(int64)) - totalWorkerTimeInSecVal := float64(0) + totalWorkerTimeVal := float64(s.retrieveValue(row, totalWorkerTime, &errs, retrieveInt).(int64)) + cached, totalWorkerTimeValCached := s.cacheAndDiff(queryHashVal, queryPlanHashVal, totalWorkerTime, int64(totalWorkerTimeVal)) + totalWorkerTimeValDiff := float64(0) if cached { - totalWorkerTimeInSecVal = float64(totalWorkerTimeVal.(int64)) / 1_000_000 + totalWorkerTimeValDiff = float64(totalWorkerTimeValCached) / 1_000_000 + } + + totalElapsedTimeVal := s.retrieveValue(row, totalElapsedTime, &errs, retrieveFloat).(float64) / 1_000_000 + + // If execution count in the db is 1 that would mean there is no past records to compare with. + // We just send down the metrics corresponding to that single execution as it is. + // If execution count is not 1 then we send down the delta values. + execCount := executionCountVal.(int64) + if execCount != 1 { + executionCountVal = executionCountValDiff + logicalReadsVal = logicalReadsValDiff + logicalWritesVal = logicalWritesValDiff + physicalReadsVal = physicalReadsValDiff + rowsReturnedVal = rowsReturnedValDiff + totalGrantVal = totalGrantValDiff + totalWorkerTimeVal = totalWorkerTimeValDiff + totalElapsedTimeVal = totalElapsedTimeValDiff + } + + if totalElapsedTimeVal == 0 { + continue } s.logger.Debug(fmt.Sprintf("QueryHash: %v, PlanHash: %v, DataRow: %v", queryHashVal, queryPlanHashVal, row)) @@ -768,7 +787,7 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont s.lb.RecordDbServerTopQueryEvent( context.Background(), timestamp, - totalWorkerTimeInSecVal, + totalWorkerTimeVal, queryTextVal.(string), executionCountVal.(int64), logicalReadsVal.(int64), @@ -813,13 +832,12 @@ func (s *sqlServerScraperHelper) cacheAndDiff(queryHash, queryPlanHash, column s key := queryHash + "-" + queryPlanHash + "-" + column cached, ok := s.cache.Get(key) + s.cache.Add(key, val) if !ok { - s.cache.Add(key, val) return false, val } if val > cached { - s.cache.Add(key, val) return true, val - cached } diff --git a/receiver/sqlserverreceiver/scraper_test.go b/receiver/sqlserverreceiver/scraper_test.go index cbb751a447e2b..92bddbfaa245f 100644 --- a/receiver/sqlserverreceiver/scraper_test.go +++ b/receiver/sqlserverreceiver/scraper_test.go @@ -370,6 +370,68 @@ func (mc mockInvalidClient) QueryRows(context.Context, ...any) ([]sqlquery.Strin return queryResults, nil } +func TestQueryTextAndPlanQueryMetricsShouldBeCachedSinceFirstCollection(t *testing.T) { + cfg := createDefaultConfig().(*Config) + cfg.Username = "sa" + cfg.Password = "password" + cfg.Port = 1433 + cfg.Server = "0.0.0.0" + cfg.MetricsBuilderConfig.ResourceAttributes.SqlserverInstanceName.Enabled = true + cfg.Events.DbServerTopQuery.Enabled = true + assert.NoError(t, cfg.Validate()) + + configureAllScraperMetricsAndEvents(cfg, false) + cfg.Events.DbServerTopQuery.Enabled = true + cfg.TopQueryCollection.CollectionInterval = cfg.ControllerConfig.CollectionInterval + + scrapers := setupSQLServerLogsScrapers(receivertest.NewNopSettings(metadata.Type), cfg) + assert.NotNil(t, scrapers) + + scraper := scrapers[0] + assert.NotNil(t, scraper.cache) + + const totalElapsedTime = "total_elapsed_time" + const rowsReturned = "total_rows" + const totalWorkerTime = "total_worker_time" + const logicalReads = "total_logical_reads" + const logicalWrites = "total_logical_writes" + const physicalReads = "total_physical_reads" + const executionCount = "execution_count" + const totalGrant = "total_grant_kb" + + scraper.client = mockClient{ + instanceName: scraper.config.InstanceName, + SQL: scraper.sqlQuery, + maxQuerySampleCount: 1000, + lookbackTime: 20, + topQueryCount: 200, + } + + actualLogs, err := scraper.ScrapeLogs(t.Context()) + assert.NoError(t, err) + + expectedFile := filepath.Join("testdata", "expectedQueryTextAndPlanQuery.yaml") + expectedLogs, _ := golden.ReadLogs(expectedFile) + + queryHash, _ := expectedLogs.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).Attributes().Get("sqlserver.query_hash") + planHash, _ := expectedLogs.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).Attributes().Get("sqlserver.query_plan_hash") + keyPrefix := queryHash.Str() + "-" + planHash.Str() + + assert.True(t, scraper.cache.Contains(keyPrefix+"-"+totalElapsedTime)) + assert.True(t, scraper.cache.Contains(keyPrefix+"-"+rowsReturned)) + assert.True(t, scraper.cache.Contains(keyPrefix+"-"+totalWorkerTime)) + assert.True(t, scraper.cache.Contains(keyPrefix+"-"+logicalReads)) + assert.True(t, scraper.cache.Contains(keyPrefix+"-"+logicalWrites)) + assert.True(t, scraper.cache.Contains(keyPrefix+"-"+physicalReads)) + assert.True(t, scraper.cache.Contains(keyPrefix+"-"+executionCount)) + assert.True(t, scraper.cache.Contains(keyPrefix+"-"+totalGrant)) + + assert.True(t, actualLogs.LogRecordCount() == 1) + collectQueryHash, _ := actualLogs.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).Attributes().Get("sqlserver.query_hash") + assert.Equal(t, hex.EncodeToString([]byte("0x37849E874171E3F4")), collectQueryHash.Str(), "Metrics for the record with 1 execution_count in db should be reported always regardless of cache record presence") + +} + func TestQueryTextAndPlanQuery(t *testing.T) { cfg := createDefaultConfig().(*Config) cfg.Username = "sa" diff --git a/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl b/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl index 7dddd011ac9fe..d59a29ac3888b 100644 --- a/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl +++ b/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl @@ -16,7 +16,6 @@ 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 - WHERE DATEADD(ms, last_elapsed_time / 1000, last_execution_time) > DATEADD(SECOND, @lookbackTime, GETDATE()) GROUP BY qs.query_hash, qs.query_plan_hash @@ -30,4 +29,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 DATEADD(ms, qs.last_elapsed_time / 1000, qs.last_execution_time) > DATEADD(SECOND, @lookbackTime, GETDATE()); diff --git a/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt b/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt index 7dddd011ac9fe..d59a29ac3888b 100644 --- a/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt +++ b/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt @@ -16,7 +16,6 @@ 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 - WHERE DATEADD(ms, last_elapsed_time / 1000, last_execution_time) > DATEADD(SECOND, @lookbackTime, GETDATE()) GROUP BY qs.query_hash, qs.query_plan_hash @@ -30,4 +29,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 DATEADD(ms, qs.last_elapsed_time / 1000, qs.last_execution_time) > DATEADD(SECOND, @lookbackTime, GETDATE()); diff --git a/receiver/sqlserverreceiver/testdata/expectedQueryTextAndPlanQuery.yaml b/receiver/sqlserverreceiver/testdata/expectedQueryTextAndPlanQuery.yaml index 4042e9baab083..690af0a54bb32 100644 --- a/receiver/sqlserverreceiver/testdata/expectedQueryTextAndPlanQuery.yaml +++ b/receiver/sqlserverreceiver/testdata/expectedQueryTextAndPlanQuery.yaml @@ -4,15 +4,15 @@ resourceLogs: - key: host.name value: stringValue: 0.0.0.0 - - key: service.instance.id - value: - stringValue: 0.0.0.0:1433 - key: sqlserver.computer.name value: stringValue: DESKTOP-GHAEGRD - key: sqlserver.instance.name value: stringValue: sqlserver + - key: service.instance.id + value: + stringValue: 0.0.0.0:1433 scopeLogs: - logRecords: - attributes: @@ -63,9 +63,56 @@ resourceLogs: stringValue: microsoft.sql_server body: {} eventName: db.server.top_query - spanId: "" - timeUnixNano: "1749224037462260000" - traceId: "" + timeUnixNano: "1767627037097600000" + - attributes: + - key: sqlserver.total_worker_time + value: + doubleValue: 3845 + - key: db.query.text + value: + stringValue: with qstats SELECT TOP ( @topNValue ) REPLACE ( @@SERVERNAME, ? ), HOST_NAME ( ), MAX ( qs.plan_handle ), qs.query_hash, qs.query_plan_hash, SUM ( qs.execution_count ), SUM ( qs.total_elapsed_time ), SUM ( qs.total_worker_time ), SUM ( qs.total_logical_reads ), SUM ( qs.total_physical_reads ), SUM ( qs.total_logical_writes ), SUM ( qs.total_rows ), SUM ( qs.total_grant_kb ) FROM sys.dm_exec_query_stats WHERE qs.last_execution_time BETWEEN DATEADD ( SECOND, @granularity, GETDATE ( ) ) AND GETDATE ( ) GROUP BY qs.query_hash, qs.query_plan_hash ) SELECT qs.*, SUBSTRING ( st.text, ( stats.statement_start_offset / ? ) + ? ( ( CASE statement_end_offset WHEN ? THEN DATALENGTH ( st.text ) ELSE stats.statement_end_offset END - stats.statement_start_offset ) / ? ) + ? ), ISNULL ( qp.query_plan, ? ) FROM qstats INNER JOIN sys.dm_exec_query_stats on qs.query_plan_handle = stats.plan_handle CROSS APPLY sys.dm_exec_query_plan ( qs.query_plan_handle ) CROSS APPLY sys.dm_exec_sql_text ( qs.query_plan_handle ) + - key: sqlserver.execution_count + value: + intValue: "1" + - key: sqlserver.total_logical_reads + value: + intValue: "3" + - key: sqlserver.total_logical_writes + value: + intValue: "4" + - key: sqlserver.total_physical_reads + value: + intValue: "5" + - key: sqlserver.query_hash + value: + stringValue: "307833373834394538373431373145334634" + - key: sqlserver.query_plan + value: + stringValue: + - key: sqlserver.query_plan_hash + value: + stringValue: "307844333131323930393432394131423534" + - key: sqlserver.total_rows + value: + intValue: "2" + - key: sqlserver.total_elapsed_time + value: + doubleValue: 0.003846 + - key: sqlserver.total_grant_kb + value: + intValue: "3096" + - key: server.address + value: + stringValue: 0.0.0.0 + - key: server.port + value: + intValue: "1433" + - key: db.system.name + value: + stringValue: microsoft.sql_server + body: {} + eventName: db.server.top_query + timeUnixNano: "1767627037097600000" scope: name: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/sqlserverreceiver version: latest diff --git a/receiver/sqlserverreceiver/testdata/queryTextAndPlanQueryData.txt b/receiver/sqlserverreceiver/testdata/queryTextAndPlanQueryData.txt index abd3e31b681f7..69dc183f9fb6b 100644 --- a/receiver/sqlserverreceiver/testdata/queryTextAndPlanQueryData.txt +++ b/receiver/sqlserverreceiver/testdata/queryTextAndPlanQueryData.txt @@ -15,5 +15,22 @@ "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": "" - } + }, + { + "sql_instance": "sqlserver", + "computer_name": "DESKTOP-GHAEGRD", + "query_plan_handle": "0x06000100E2B3C02AA042A7001000000001000000000000000000000000000000000000000000000000000000", + "query_hash": "0x37849E874171E3F4", + "query_plan_hash": "0xD3112909429A1B54", + "execution_count": "1", + "total_elapsed_time": "3846", + "total_worker_time": "3845", + "total_logical_reads": "3", + "total_physical_reads": "5", + "total_logical_writes": "4", + "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": "" + } ] From 42432a7a16031caf7c8a65a80418b56e23e77205 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Mon, 5 Jan 2026 16:31:21 +0000 Subject: [PATCH 20/43] change log --- ...postgresql_fix_for_inaccurate_metrics.yaml | 29 +++++++++++++++++++ receiver/sqlserverreceiver/scraper.go | 8 ++--- 2 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 .chloggen/postgresql_fix_for_inaccurate_metrics.yaml diff --git a/.chloggen/postgresql_fix_for_inaccurate_metrics.yaml b/.chloggen/postgresql_fix_for_inaccurate_metrics.yaml new file mode 100644 index 0000000000000..0fe003919275f --- /dev/null +++ b/.chloggen/postgresql_fix_for_inaccurate_metrics.yaml @@ -0,0 +1,29 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: bug_fix + +# The name of the component, or a single word describing the area of concern, (e.g. receiver/filelog) +component: receiver/postgresql + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Accuracy improvements for top-query metrics + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [] + +# (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: | + PostgreSQL metrics reporting is improved by reducing the warm-up delay and providing accurate insights sooner. + +# 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/scraper.go b/receiver/sqlserverreceiver/scraper.go index 7f52155afe69f..c7e515c4656b0 100644 --- a/receiver/sqlserverreceiver/scraper.go +++ b/receiver/sqlserverreceiver/scraper.go @@ -754,11 +754,11 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont totalElapsedTimeVal := s.retrieveValue(row, totalElapsedTime, &errs, retrieveFloat).(float64) / 1_000_000 - // If execution count in the db is 1 that would mean there is no past records to compare with. + // If execution count in the DB is 1 that would mean there is no past records to compare with to find a delta. // We just send down the metrics corresponding to that single execution as it is. - // If execution count is not 1 then we send down the delta values. - execCount := executionCountVal.(int64) - if execCount != 1 { + // If execution count in DB is not 1 then we send down the delta values. + execCountInDB := executionCountVal.(int64) + if execCountInDB != 1 { executionCountVal = executionCountValDiff logicalReadsVal = logicalReadsValDiff logicalWritesVal = logicalWritesValDiff From a06028f92499c0859254edb53b2fff24878e3780 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Mon, 5 Jan 2026 16:53:50 +0000 Subject: [PATCH 21/43] this fix is for sqlserver --- ...metrics.yaml => sqlserver_fix_for_inaccurate_metrics.yaml} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename .chloggen/{postgresql_fix_for_inaccurate_metrics.yaml => sqlserver_fix_for_inaccurate_metrics.yaml} (89%) diff --git a/.chloggen/postgresql_fix_for_inaccurate_metrics.yaml b/.chloggen/sqlserver_fix_for_inaccurate_metrics.yaml similarity index 89% rename from .chloggen/postgresql_fix_for_inaccurate_metrics.yaml rename to .chloggen/sqlserver_fix_for_inaccurate_metrics.yaml index 0fe003919275f..6fbbd4e573f38 100644 --- a/.chloggen/postgresql_fix_for_inaccurate_metrics.yaml +++ b/.chloggen/sqlserver_fix_for_inaccurate_metrics.yaml @@ -4,7 +4,7 @@ change_type: bug_fix # The name of the component, or a single word describing the area of concern, (e.g. receiver/filelog) -component: receiver/postgresql +component: receiver/sqlserver # A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). note: Accuracy improvements for top-query metrics @@ -16,7 +16,7 @@ issues: [] # These lines will be padded with 2 spaces and then inserted directly into the document. # Use pipe (|) for multiline entries. subtext: | - PostgreSQL metrics reporting is improved by reducing the warm-up delay and providing accurate insights sooner. + SQLServer metrics reporting is improved by reducing the warm-up delay and providing accurate insights sooner. # 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. From 98e2e15e75322326566c2706cea4f85f61ae7a84 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Mon, 5 Jan 2026 16:54:44 +0000 Subject: [PATCH 22/43] fill issue details --- .chloggen/sqlserver_fix_for_inaccurate_metrics.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.chloggen/sqlserver_fix_for_inaccurate_metrics.yaml b/.chloggen/sqlserver_fix_for_inaccurate_metrics.yaml index 6fbbd4e573f38..7fc9b3a3901ee 100644 --- a/.chloggen/sqlserver_fix_for_inaccurate_metrics.yaml +++ b/.chloggen/sqlserver_fix_for_inaccurate_metrics.yaml @@ -10,7 +10,7 @@ component: receiver/sqlserver note: Accuracy improvements for top-query metrics # Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. -issues: [] +issues: [45228] # (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. From ca3a16a89763e8ecb3f2414a46a34f37b986f01e Mon Sep 17 00:00:00 2001 From: sreenathv Date: Tue, 6 Jan 2026 09:19:59 +0000 Subject: [PATCH 23/43] go generate --- receiver/sqlserverreceiver/documentation.md | 166 +++++++++--------- .../generated_package_test.go | 3 +- .../metadata/generated_config_test.go | 1 + .../internal/metadata/generated_logs.go | 1 - .../internal/metadata/generated_logs_test.go | 5 +- receiver/sqlserverreceiver/scraper_test.go | 1 - 6 files changed, 87 insertions(+), 90 deletions(-) diff --git a/receiver/sqlserverreceiver/documentation.md b/receiver/sqlserverreceiver/documentation.md index a018477cf1617..fcd433289df41 100644 --- a/receiver/sqlserverreceiver/documentation.md +++ b/receiver/sqlserverreceiver/documentation.md @@ -18,7 +18,7 @@ Number of batch requests received by SQL Server. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {requests}/s | Gauge | Double | Development | +| {requests}/s | Gauge | Double | development | ### sqlserver.batch.sql_compilation.rate @@ -26,7 +26,7 @@ Number of SQL compilations needed. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {compilations}/s | Gauge | Double | Development | +| {compilations}/s | Gauge | Double | development | ### sqlserver.batch.sql_recompilation.rate @@ -34,7 +34,7 @@ Number of SQL recompilations needed. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {compilations}/s | Gauge | Double | Development | +| {compilations}/s | Gauge | Double | development | ### sqlserver.lock.wait.rate @@ -42,7 +42,7 @@ Number of lock requests resulting in a wait. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {requests}/s | Gauge | Double | Development | +| {requests}/s | Gauge | Double | development | ### sqlserver.lock.wait_time.avg @@ -52,7 +52,7 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| ms | Gauge | Double | Development | +| ms | Gauge | Double | development | ### sqlserver.page.buffer_cache.hit_ratio @@ -60,7 +60,7 @@ Pages found in the buffer pool without having to read from disk. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| % | Gauge | Double | Development | +| % | Gauge | Double | development | ### sqlserver.page.checkpoint.flush.rate @@ -70,7 +70,7 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {pages}/s | Gauge | Double | Development | +| {pages}/s | Gauge | Double | development | ### sqlserver.page.lazy_write.rate @@ -80,7 +80,7 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {writes}/s | Gauge | Double | Development | +| {writes}/s | Gauge | Double | development | ### sqlserver.page.life_expectancy @@ -88,13 +88,13 @@ Time a page will stay in the buffer pool. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| s | Gauge | Int | Development | +| s | Gauge | Int | development | #### Attributes -| Name | Description | Values | Requirement Level | +| Name | Description | Values | Optional | | ---- | ----------- | ------ | -------- | -| performance_counter.object_name | Category to which this counter belongs | Any Str | Recommended | +| performance_counter.object_name | Category to which this counter belongs | Any Str | false | ### sqlserver.page.operation.rate @@ -104,13 +104,13 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {operations}/s | Gauge | Double | Development | +| {operations}/s | Gauge | Double | development | #### Attributes -| Name | Description | Values | Requirement Level | +| Name | Description | Values | Optional | | ---- | ----------- | ------ | -------- | -| type | The page operation types. | Str: ``read``, ``write`` | Recommended | +| type | The page operation types. | Str: ``read``, ``write`` | false | ### sqlserver.page.split.rate @@ -120,7 +120,7 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {pages}/s | Gauge | Double | Development | +| {pages}/s | Gauge | Double | development | ### sqlserver.transaction.rate @@ -130,7 +130,7 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {transactions}/s | Gauge | Double | Development | +| {transactions}/s | Gauge | Double | development | ### sqlserver.transaction.write.rate @@ -140,7 +140,7 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {transactions}/s | Gauge | Double | Development | +| {transactions}/s | Gauge | Double | development | ### sqlserver.transaction_log.flush.data.rate @@ -150,7 +150,7 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| By/s | Gauge | Double | Development | +| By/s | Gauge | Double | development | ### sqlserver.transaction_log.flush.rate @@ -160,7 +160,7 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {flushes}/s | Gauge | Double | Development | +| {flushes}/s | Gauge | Double | development | ### sqlserver.transaction_log.flush.wait.rate @@ -170,7 +170,7 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {commits}/s | Gauge | Double | Development | +| {commits}/s | Gauge | Double | development | ### sqlserver.transaction_log.growth.count @@ -180,7 +180,7 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | -| {growths} | Sum | Int | Cumulative | true | Development | +| {growths} | Sum | Int | Cumulative | true | development | ### sqlserver.transaction_log.shrink.count @@ -190,7 +190,7 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | -| {shrinks} | Sum | Int | Cumulative | true | Development | +| {shrinks} | Sum | Int | Cumulative | true | development | ### sqlserver.transaction_log.usage @@ -200,7 +200,7 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| % | Gauge | Int | Development | +| % | Gauge | Int | development | ### sqlserver.user.connection.count @@ -208,7 +208,7 @@ Number of users connected to the SQL Server. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {connections} | Gauge | Int | Development | +| {connections} | Gauge | Int | development | ## Optional Metrics @@ -226,7 +226,7 @@ Computer uptime. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {seconds} | Gauge | Int | Development | +| {seconds} | Gauge | Int | development | ### sqlserver.cpu.count @@ -234,7 +234,7 @@ Number of CPUs. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {CPUs} | Gauge | Int | Development | +| {CPUs} | Gauge | Int | development | ### sqlserver.database.backup_or_restore.rate @@ -242,7 +242,7 @@ Total number of backups/restores. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| “{backups_or_restores}/s” | Gauge | Double | Development | +| “{backups_or_restores}/s” | Gauge | Double | development | ### sqlserver.database.count @@ -252,13 +252,13 @@ This metric is only available when the receiver is configured to directly connec | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {databases} | Gauge | Int | Development | +| {databases} | Gauge | Int | development | #### Attributes -| Name | Description | Values | Requirement Level | +| Name | Description | Values | Optional | | ---- | ----------- | ------ | -------- | -| database.status | The current status of a database | Str: ``online``, ``restoring``, ``recovering``, ``pending_recovery``, ``suspect``, ``offline`` | Recommended | +| database.status | The current status of a database | Str: ``online``, ``restoring``, ``recovering``, ``pending_recovery``, ``suspect``, ``offline`` | false | ### sqlserver.database.execution.errors @@ -266,7 +266,7 @@ Number of execution errors. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| “{errors}” | Gauge | Int | Development | +| “{errors}” | Gauge | Int | development | ### sqlserver.database.full_scan.rate @@ -274,7 +274,7 @@ The number of unrestricted full table or index scans. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {scans}/s | Gauge | Double | Development | +| {scans}/s | Gauge | Double | development | ### sqlserver.database.io @@ -284,16 +284,16 @@ This metric is only available when the receiver is configured to directly connec | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | -| By | Sum | Int | Cumulative | true | Development | +| By | Sum | Int | Cumulative | true | development | #### Attributes -| Name | Description | Values | Requirement Level | +| Name | Description | Values | Optional | | ---- | ----------- | ------ | -------- | -| physical_filename | The physical filename of the file being monitored. | Any Str | Recommended | -| logical_filename | The logical filename of the file being monitored. | Any Str | Recommended | -| file_type | The type of file being monitored. | Any Str | Recommended | -| direction | The direction of flow of bytes or operations. | Str: ``read``, ``write`` | Recommended | +| physical_filename | The physical filename of the file being monitored. | Any Str | false | +| logical_filename | The logical filename of the file being monitored. | Any Str | false | +| file_type | The type of file being monitored. | Any Str | false | +| direction | The direction of flow of bytes or operations. | Str: ``read``, ``write`` | false | ### sqlserver.database.latency @@ -303,16 +303,16 @@ This metric is only available when the receiver is configured to directly connec | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | -| s | Sum | Double | Cumulative | true | Development | +| s | Sum | Double | Cumulative | true | development | #### Attributes -| Name | Description | Values | Requirement Level | +| Name | Description | Values | Optional | | ---- | ----------- | ------ | -------- | -| physical_filename | The physical filename of the file being monitored. | Any Str | Recommended | -| logical_filename | The logical filename of the file being monitored. | Any Str | Recommended | -| file_type | The type of file being monitored. | Any Str | Recommended | -| direction | The direction of flow of bytes or operations. | Str: ``read``, ``write`` | Recommended | +| physical_filename | The physical filename of the file being monitored. | Any Str | false | +| logical_filename | The logical filename of the file being monitored. | Any Str | false | +| file_type | The type of file being monitored. | Any Str | false | +| direction | The direction of flow of bytes or operations. | Str: ``read``, ``write`` | false | ### sqlserver.database.operations @@ -322,16 +322,16 @@ This metric is only available when the receiver is configured to directly connec | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | -| {operations} | Sum | Int | Cumulative | true | Development | +| {operations} | Sum | Int | Cumulative | true | development | #### Attributes -| Name | Description | Values | Requirement Level | +| Name | Description | Values | Optional | | ---- | ----------- | ------ | -------- | -| physical_filename | The physical filename of the file being monitored. | Any Str | Recommended | -| logical_filename | The logical filename of the file being monitored. | Any Str | Recommended | -| file_type | The type of file being monitored. | Any Str | Recommended | -| direction | The direction of flow of bytes or operations. | Str: ``read``, ``write`` | Recommended | +| physical_filename | The physical filename of the file being monitored. | Any Str | false | +| logical_filename | The logical filename of the file being monitored. | Any Str | false | +| file_type | The type of file being monitored. | Any Str | false | +| direction | The direction of flow of bytes or operations. | Str: ``read``, ``write`` | false | ### sqlserver.database.tempdb.space @@ -339,13 +339,13 @@ Total free space in temporary DB. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | -| “KB” | Sum | Int | Cumulative | false | Development | +| “KB” | Sum | Int | Cumulative | false | development | #### Attributes -| Name | Description | Values | Requirement Level | +| Name | Description | Values | Optional | | ---- | ----------- | ------ | -------- | -| tempdb.state | The status of the tempdb space usage. | Str: ``free``, ``used`` | Recommended | +| tempdb.state | The status of the tempdb space usage. | Str: ``free``, ``used`` | false | ### sqlserver.database.tempdb.version_store.size @@ -353,7 +353,7 @@ TempDB version store size. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| “KB” | Gauge | Double | Development | +| “KB” | Gauge | Double | development | ### sqlserver.deadlock.rate @@ -361,7 +361,7 @@ Total number of deadlocks. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| “{deadlocks}/s” | Gauge | Double | Development | +| “{deadlocks}/s” | Gauge | Double | development | ### sqlserver.index.search.rate @@ -369,7 +369,7 @@ Total number of index searches. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| “{searches}/s” | Gauge | Double | Development | +| “{searches}/s” | Gauge | Double | development | ### sqlserver.lock.timeout.rate @@ -377,7 +377,7 @@ Total number of lock timeouts. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| “{timeouts}/s” | Gauge | Double | Development | +| “{timeouts}/s” | Gauge | Double | development | ### sqlserver.lock.wait.count @@ -387,7 +387,7 @@ This metric is only available when the receiver is configured to directly connec | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | -| {wait} | Sum | Int | Cumulative | true | Development | +| {wait} | Sum | Int | Cumulative | true | development | ### sqlserver.login.rate @@ -395,7 +395,7 @@ Total number of logins. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| “{logins}/s” | Gauge | Double | Development | +| “{logins}/s” | Gauge | Double | development | ### sqlserver.logout.rate @@ -403,7 +403,7 @@ Total number of logouts. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| “{logouts}/s” | Gauge | Double | Development | +| “{logouts}/s” | Gauge | Double | development | ### sqlserver.memory.grants.pending.count @@ -411,7 +411,7 @@ Total number of memory grants pending. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | -| “{grants}” | Sum | Int | Cumulative | false | Development | +| “{grants}” | Sum | Int | Cumulative | false | development | ### sqlserver.memory.usage @@ -419,7 +419,7 @@ Total memory in use. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | -| “KB” | Sum | Double | Cumulative | false | Development | +| “KB” | Sum | Double | Cumulative | false | development | ### sqlserver.os.wait.duration @@ -429,14 +429,14 @@ This metric is only available when the receiver is configured to directly connec | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | -| s | Sum | Double | Cumulative | true | Development | +| s | Sum | Double | Cumulative | true | development | #### Attributes -| Name | Description | Values | Requirement Level | +| Name | Description | Values | Optional | | ---- | ----------- | ------ | -------- | -| wait.category | Category of the reason for a wait. | Any Str | Recommended | -| wait.type | Type of the wait, view [WaitTypes documentation](https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-os-wait-stats-transact-sql?view=sql-server-ver16#WaitTypes) for more information. | Any Str | Recommended | +| wait.category | Category of the reason for a wait. | Any Str | false | +| wait.type | Type of the wait, view [WaitTypes documentation](https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-os-wait-stats-transact-sql?view=sql-server-ver16#WaitTypes) for more information. | Any Str | false | ### sqlserver.page.buffer_cache.free_list.stalls.rate @@ -444,7 +444,7 @@ Number of free list stalls. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| “{stalls}/s” | Gauge | Int | Development | +| “{stalls}/s” | Gauge | Int | development | ### sqlserver.page.lookup.rate @@ -452,7 +452,7 @@ Total number of page lookups. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| “{lookups}/s” | Gauge | Double | Development | +| “{lookups}/s” | Gauge | Double | development | ### sqlserver.processes.blocked @@ -462,7 +462,7 @@ This metric is only available when the receiver is configured to directly connec | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {processes} | Gauge | Int | Development | +| {processes} | Gauge | Int | development | ### sqlserver.replica.data.rate @@ -470,13 +470,13 @@ Throughput rate of replica data. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| By/s | Gauge | Double | Development | +| By/s | Gauge | Double | development | #### Attributes -| Name | Description | Values | Requirement Level | +| Name | Description | Values | Optional | | ---- | ----------- | ------ | -------- | -| replica.direction | The direction of flow of bytes for replica. | Str: ``transmit``, ``receive`` | Recommended | +| replica.direction | The direction of flow of bytes for replica. | Str: ``transmit``, ``receive`` | false | ### sqlserver.resource_pool.disk.operations @@ -486,13 +486,13 @@ This metric is only available when the receiver is configured to directly connec | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {operations}/s | Gauge | Double | Development | +| {operations}/s | Gauge | Double | development | #### Attributes -| Name | Description | Values | Requirement Level | +| Name | Description | Values | Optional | | ---- | ----------- | ------ | -------- | -| direction | The direction of flow of bytes or operations. | Str: ``read``, ``write`` | Recommended | +| direction | The direction of flow of bytes or operations. | Str: ``read``, ``write`` | false | ### sqlserver.resource_pool.disk.throttled.read.rate @@ -502,7 +502,7 @@ This metric is only available when the receiver is configured to directly connec | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {reads}/s | Gauge | Int | Development | +| {reads}/s | Gauge | Int | development | ### sqlserver.resource_pool.disk.throttled.write.rate @@ -512,7 +512,7 @@ This metric is only available when the receiver is configured to directly connec | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {writes}/s | Gauge | Double | Development | +| {writes}/s | Gauge | Double | development | ### sqlserver.table.count @@ -520,14 +520,14 @@ The number of tables. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | -| “{tables}” | Sum | Int | Cumulative | false | Development | +| “{tables}” | Sum | Int | Cumulative | false | development | #### Attributes -| Name | Description | Values | Requirement Level | +| Name | Description | Values | Optional | | ---- | ----------- | ------ | -------- | -| table.state | The state of the table. | Str: ``active``, ``inactive`` | Recommended | -| table.status | The status of the table. | Str: ``temporary``, ``permanent`` | Recommended | +| table.state | The state of the table. | Str: ``active``, ``inactive`` | false | +| table.status | The status of the table. | Str: ``temporary``, ``permanent`` | false | ### sqlserver.transaction.delay @@ -535,7 +535,7 @@ Time consumed in transaction delays. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | -| ms | Sum | Double | Cumulative | false | Development | +| ms | Sum | Double | Cumulative | false | development | ### sqlserver.transaction.mirror_write.rate @@ -543,7 +543,7 @@ Total number of mirror write transactions. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| “{transactions}/s” | Gauge | Double | Development | +| “{transactions}/s” | Gauge | Double | development | ## Default Events diff --git a/receiver/sqlserverreceiver/generated_package_test.go b/receiver/sqlserverreceiver/generated_package_test.go index ce3721511beef..86266f5f36641 100644 --- a/receiver/sqlserverreceiver/generated_package_test.go +++ b/receiver/sqlserverreceiver/generated_package_test.go @@ -3,9 +3,8 @@ package sqlserverreceiver import ( - "testing" - "go.uber.org/goleak" + "testing" ) func TestMain(m *testing.M) { diff --git a/receiver/sqlserverreceiver/internal/metadata/generated_config_test.go b/receiver/sqlserverreceiver/internal/metadata/generated_config_test.go index 6f28022a39a7a..94073cc60b8c3 100644 --- a/receiver/sqlserverreceiver/internal/metadata/generated_config_test.go +++ b/receiver/sqlserverreceiver/internal/metadata/generated_config_test.go @@ -9,6 +9,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/confmaptest" ) diff --git a/receiver/sqlserverreceiver/internal/metadata/generated_logs.go b/receiver/sqlserverreceiver/internal/metadata/generated_logs.go index 2224f758a2990..18d6d211b3788 100644 --- a/receiver/sqlserverreceiver/internal/metadata/generated_logs.go +++ b/receiver/sqlserverreceiver/internal/metadata/generated_logs.go @@ -4,7 +4,6 @@ package metadata import ( "context" - "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/filter" "go.opentelemetry.io/collector/pdata/pcommon" diff --git a/receiver/sqlserverreceiver/internal/metadata/generated_logs_test.go b/receiver/sqlserverreceiver/internal/metadata/generated_logs_test.go index 53531d2d36903..fb265c194d02c 100644 --- a/receiver/sqlserverreceiver/internal/metadata/generated_logs_test.go +++ b/receiver/sqlserverreceiver/internal/metadata/generated_logs_test.go @@ -4,9 +4,6 @@ package metadata import ( "context" - "testing" - "time" - "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" @@ -14,6 +11,8 @@ import ( "go.opentelemetry.io/otel/trace" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" + "testing" + "time" ) type eventsTestDataSet int diff --git a/receiver/sqlserverreceiver/scraper_test.go b/receiver/sqlserverreceiver/scraper_test.go index 92bddbfaa245f..1ae3a9f6b0556 100644 --- a/receiver/sqlserverreceiver/scraper_test.go +++ b/receiver/sqlserverreceiver/scraper_test.go @@ -429,7 +429,6 @@ func TestQueryTextAndPlanQueryMetricsShouldBeCachedSinceFirstCollection(t *testi assert.True(t, actualLogs.LogRecordCount() == 1) collectQueryHash, _ := actualLogs.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).Attributes().Get("sqlserver.query_hash") assert.Equal(t, hex.EncodeToString([]byte("0x37849E874171E3F4")), collectQueryHash.Str(), "Metrics for the record with 1 execution_count in db should be reported always regardless of cache record presence") - } func TestQueryTextAndPlanQuery(t *testing.T) { From e521c6fbb5114f7a59d870897af914c3c76c19e0 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Tue, 6 Jan 2026 09:39:38 +0000 Subject: [PATCH 24/43] fix lint --- receiver/sqlserverreceiver/scraper_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/receiver/sqlserverreceiver/scraper_test.go b/receiver/sqlserverreceiver/scraper_test.go index 1ae3a9f6b0556..3fb6e410cd530 100644 --- a/receiver/sqlserverreceiver/scraper_test.go +++ b/receiver/sqlserverreceiver/scraper_test.go @@ -426,7 +426,7 @@ func TestQueryTextAndPlanQueryMetricsShouldBeCachedSinceFirstCollection(t *testi assert.True(t, scraper.cache.Contains(keyPrefix+"-"+executionCount)) assert.True(t, scraper.cache.Contains(keyPrefix+"-"+totalGrant)) - assert.True(t, actualLogs.LogRecordCount() == 1) + assert.Equal(t, 1, actualLogs.LogRecordCount()) collectQueryHash, _ := actualLogs.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).Attributes().Get("sqlserver.query_hash") assert.Equal(t, hex.EncodeToString([]byte("0x37849E874171E3F4")), collectQueryHash.Str(), "Metrics for the record with 1 execution_count in db should be reported always regardless of cache record presence") } From 3cf3d01b28ac7a6c4f40dc305696cbc99e8f4f94 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Tue, 6 Jan 2026 14:20:23 +0000 Subject: [PATCH 25/43] make gogci --- receiver/sqlserverreceiver/documentation.md | 166 +++++++++--------- .../generated_package_test.go | 3 +- .../metadata/generated_config_test.go | 1 - .../internal/metadata/generated_logs.go | 1 + .../internal/metadata/generated_logs_test.go | 5 +- 5 files changed, 89 insertions(+), 87 deletions(-) diff --git a/receiver/sqlserverreceiver/documentation.md b/receiver/sqlserverreceiver/documentation.md index fcd433289df41..a018477cf1617 100644 --- a/receiver/sqlserverreceiver/documentation.md +++ b/receiver/sqlserverreceiver/documentation.md @@ -18,7 +18,7 @@ Number of batch requests received by SQL Server. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {requests}/s | Gauge | Double | development | +| {requests}/s | Gauge | Double | Development | ### sqlserver.batch.sql_compilation.rate @@ -26,7 +26,7 @@ Number of SQL compilations needed. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {compilations}/s | Gauge | Double | development | +| {compilations}/s | Gauge | Double | Development | ### sqlserver.batch.sql_recompilation.rate @@ -34,7 +34,7 @@ Number of SQL recompilations needed. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {compilations}/s | Gauge | Double | development | +| {compilations}/s | Gauge | Double | Development | ### sqlserver.lock.wait.rate @@ -42,7 +42,7 @@ Number of lock requests resulting in a wait. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {requests}/s | Gauge | Double | development | +| {requests}/s | Gauge | Double | Development | ### sqlserver.lock.wait_time.avg @@ -52,7 +52,7 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| ms | Gauge | Double | development | +| ms | Gauge | Double | Development | ### sqlserver.page.buffer_cache.hit_ratio @@ -60,7 +60,7 @@ Pages found in the buffer pool without having to read from disk. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| % | Gauge | Double | development | +| % | Gauge | Double | Development | ### sqlserver.page.checkpoint.flush.rate @@ -70,7 +70,7 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {pages}/s | Gauge | Double | development | +| {pages}/s | Gauge | Double | Development | ### sqlserver.page.lazy_write.rate @@ -80,7 +80,7 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {writes}/s | Gauge | Double | development | +| {writes}/s | Gauge | Double | Development | ### sqlserver.page.life_expectancy @@ -88,13 +88,13 @@ Time a page will stay in the buffer pool. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| s | Gauge | Int | development | +| s | Gauge | Int | Development | #### Attributes -| Name | Description | Values | Optional | +| Name | Description | Values | Requirement Level | | ---- | ----------- | ------ | -------- | -| performance_counter.object_name | Category to which this counter belongs | Any Str | false | +| performance_counter.object_name | Category to which this counter belongs | Any Str | Recommended | ### sqlserver.page.operation.rate @@ -104,13 +104,13 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {operations}/s | Gauge | Double | development | +| {operations}/s | Gauge | Double | Development | #### Attributes -| Name | Description | Values | Optional | +| Name | Description | Values | Requirement Level | | ---- | ----------- | ------ | -------- | -| type | The page operation types. | Str: ``read``, ``write`` | false | +| type | The page operation types. | Str: ``read``, ``write`` | Recommended | ### sqlserver.page.split.rate @@ -120,7 +120,7 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {pages}/s | Gauge | Double | development | +| {pages}/s | Gauge | Double | Development | ### sqlserver.transaction.rate @@ -130,7 +130,7 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {transactions}/s | Gauge | Double | development | +| {transactions}/s | Gauge | Double | Development | ### sqlserver.transaction.write.rate @@ -140,7 +140,7 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {transactions}/s | Gauge | Double | development | +| {transactions}/s | Gauge | Double | Development | ### sqlserver.transaction_log.flush.data.rate @@ -150,7 +150,7 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| By/s | Gauge | Double | development | +| By/s | Gauge | Double | Development | ### sqlserver.transaction_log.flush.rate @@ -160,7 +160,7 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {flushes}/s | Gauge | Double | development | +| {flushes}/s | Gauge | Double | Development | ### sqlserver.transaction_log.flush.wait.rate @@ -170,7 +170,7 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {commits}/s | Gauge | Double | development | +| {commits}/s | Gauge | Double | Development | ### sqlserver.transaction_log.growth.count @@ -180,7 +180,7 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | -| {growths} | Sum | Int | Cumulative | true | development | +| {growths} | Sum | Int | Cumulative | true | Development | ### sqlserver.transaction_log.shrink.count @@ -190,7 +190,7 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | -| {shrinks} | Sum | Int | Cumulative | true | development | +| {shrinks} | Sum | Int | Cumulative | true | Development | ### sqlserver.transaction_log.usage @@ -200,7 +200,7 @@ This metric is only available when running on Windows. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| % | Gauge | Int | development | +| % | Gauge | Int | Development | ### sqlserver.user.connection.count @@ -208,7 +208,7 @@ Number of users connected to the SQL Server. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {connections} | Gauge | Int | development | +| {connections} | Gauge | Int | Development | ## Optional Metrics @@ -226,7 +226,7 @@ Computer uptime. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {seconds} | Gauge | Int | development | +| {seconds} | Gauge | Int | Development | ### sqlserver.cpu.count @@ -234,7 +234,7 @@ Number of CPUs. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {CPUs} | Gauge | Int | development | +| {CPUs} | Gauge | Int | Development | ### sqlserver.database.backup_or_restore.rate @@ -242,7 +242,7 @@ Total number of backups/restores. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| “{backups_or_restores}/s” | Gauge | Double | development | +| “{backups_or_restores}/s” | Gauge | Double | Development | ### sqlserver.database.count @@ -252,13 +252,13 @@ This metric is only available when the receiver is configured to directly connec | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {databases} | Gauge | Int | development | +| {databases} | Gauge | Int | Development | #### Attributes -| Name | Description | Values | Optional | +| Name | Description | Values | Requirement Level | | ---- | ----------- | ------ | -------- | -| database.status | The current status of a database | Str: ``online``, ``restoring``, ``recovering``, ``pending_recovery``, ``suspect``, ``offline`` | false | +| database.status | The current status of a database | Str: ``online``, ``restoring``, ``recovering``, ``pending_recovery``, ``suspect``, ``offline`` | Recommended | ### sqlserver.database.execution.errors @@ -266,7 +266,7 @@ Number of execution errors. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| “{errors}” | Gauge | Int | development | +| “{errors}” | Gauge | Int | Development | ### sqlserver.database.full_scan.rate @@ -274,7 +274,7 @@ The number of unrestricted full table or index scans. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {scans}/s | Gauge | Double | development | +| {scans}/s | Gauge | Double | Development | ### sqlserver.database.io @@ -284,16 +284,16 @@ This metric is only available when the receiver is configured to directly connec | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | -| By | Sum | Int | Cumulative | true | development | +| By | Sum | Int | Cumulative | true | Development | #### Attributes -| Name | Description | Values | Optional | +| Name | Description | Values | Requirement Level | | ---- | ----------- | ------ | -------- | -| physical_filename | The physical filename of the file being monitored. | Any Str | false | -| logical_filename | The logical filename of the file being monitored. | Any Str | false | -| file_type | The type of file being monitored. | Any Str | false | -| direction | The direction of flow of bytes or operations. | Str: ``read``, ``write`` | false | +| physical_filename | The physical filename of the file being monitored. | Any Str | Recommended | +| logical_filename | The logical filename of the file being monitored. | Any Str | Recommended | +| file_type | The type of file being monitored. | Any Str | Recommended | +| direction | The direction of flow of bytes or operations. | Str: ``read``, ``write`` | Recommended | ### sqlserver.database.latency @@ -303,16 +303,16 @@ This metric is only available when the receiver is configured to directly connec | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | -| s | Sum | Double | Cumulative | true | development | +| s | Sum | Double | Cumulative | true | Development | #### Attributes -| Name | Description | Values | Optional | +| Name | Description | Values | Requirement Level | | ---- | ----------- | ------ | -------- | -| physical_filename | The physical filename of the file being monitored. | Any Str | false | -| logical_filename | The logical filename of the file being monitored. | Any Str | false | -| file_type | The type of file being monitored. | Any Str | false | -| direction | The direction of flow of bytes or operations. | Str: ``read``, ``write`` | false | +| physical_filename | The physical filename of the file being monitored. | Any Str | Recommended | +| logical_filename | The logical filename of the file being monitored. | Any Str | Recommended | +| file_type | The type of file being monitored. | Any Str | Recommended | +| direction | The direction of flow of bytes or operations. | Str: ``read``, ``write`` | Recommended | ### sqlserver.database.operations @@ -322,16 +322,16 @@ This metric is only available when the receiver is configured to directly connec | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | -| {operations} | Sum | Int | Cumulative | true | development | +| {operations} | Sum | Int | Cumulative | true | Development | #### Attributes -| Name | Description | Values | Optional | +| Name | Description | Values | Requirement Level | | ---- | ----------- | ------ | -------- | -| physical_filename | The physical filename of the file being monitored. | Any Str | false | -| logical_filename | The logical filename of the file being monitored. | Any Str | false | -| file_type | The type of file being monitored. | Any Str | false | -| direction | The direction of flow of bytes or operations. | Str: ``read``, ``write`` | false | +| physical_filename | The physical filename of the file being monitored. | Any Str | Recommended | +| logical_filename | The logical filename of the file being monitored. | Any Str | Recommended | +| file_type | The type of file being monitored. | Any Str | Recommended | +| direction | The direction of flow of bytes or operations. | Str: ``read``, ``write`` | Recommended | ### sqlserver.database.tempdb.space @@ -339,13 +339,13 @@ Total free space in temporary DB. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | -| “KB” | Sum | Int | Cumulative | false | development | +| “KB” | Sum | Int | Cumulative | false | Development | #### Attributes -| Name | Description | Values | Optional | +| Name | Description | Values | Requirement Level | | ---- | ----------- | ------ | -------- | -| tempdb.state | The status of the tempdb space usage. | Str: ``free``, ``used`` | false | +| tempdb.state | The status of the tempdb space usage. | Str: ``free``, ``used`` | Recommended | ### sqlserver.database.tempdb.version_store.size @@ -353,7 +353,7 @@ TempDB version store size. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| “KB” | Gauge | Double | development | +| “KB” | Gauge | Double | Development | ### sqlserver.deadlock.rate @@ -361,7 +361,7 @@ Total number of deadlocks. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| “{deadlocks}/s” | Gauge | Double | development | +| “{deadlocks}/s” | Gauge | Double | Development | ### sqlserver.index.search.rate @@ -369,7 +369,7 @@ Total number of index searches. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| “{searches}/s” | Gauge | Double | development | +| “{searches}/s” | Gauge | Double | Development | ### sqlserver.lock.timeout.rate @@ -377,7 +377,7 @@ Total number of lock timeouts. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| “{timeouts}/s” | Gauge | Double | development | +| “{timeouts}/s” | Gauge | Double | Development | ### sqlserver.lock.wait.count @@ -387,7 +387,7 @@ This metric is only available when the receiver is configured to directly connec | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | -| {wait} | Sum | Int | Cumulative | true | development | +| {wait} | Sum | Int | Cumulative | true | Development | ### sqlserver.login.rate @@ -395,7 +395,7 @@ Total number of logins. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| “{logins}/s” | Gauge | Double | development | +| “{logins}/s” | Gauge | Double | Development | ### sqlserver.logout.rate @@ -403,7 +403,7 @@ Total number of logouts. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| “{logouts}/s” | Gauge | Double | development | +| “{logouts}/s” | Gauge | Double | Development | ### sqlserver.memory.grants.pending.count @@ -411,7 +411,7 @@ Total number of memory grants pending. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | -| “{grants}” | Sum | Int | Cumulative | false | development | +| “{grants}” | Sum | Int | Cumulative | false | Development | ### sqlserver.memory.usage @@ -419,7 +419,7 @@ Total memory in use. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | -| “KB” | Sum | Double | Cumulative | false | development | +| “KB” | Sum | Double | Cumulative | false | Development | ### sqlserver.os.wait.duration @@ -429,14 +429,14 @@ This metric is only available when the receiver is configured to directly connec | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | -| s | Sum | Double | Cumulative | true | development | +| s | Sum | Double | Cumulative | true | Development | #### Attributes -| Name | Description | Values | Optional | +| Name | Description | Values | Requirement Level | | ---- | ----------- | ------ | -------- | -| wait.category | Category of the reason for a wait. | Any Str | false | -| wait.type | Type of the wait, view [WaitTypes documentation](https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-os-wait-stats-transact-sql?view=sql-server-ver16#WaitTypes) for more information. | Any Str | false | +| wait.category | Category of the reason for a wait. | Any Str | Recommended | +| wait.type | Type of the wait, view [WaitTypes documentation](https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-os-wait-stats-transact-sql?view=sql-server-ver16#WaitTypes) for more information. | Any Str | Recommended | ### sqlserver.page.buffer_cache.free_list.stalls.rate @@ -444,7 +444,7 @@ Number of free list stalls. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| “{stalls}/s” | Gauge | Int | development | +| “{stalls}/s” | Gauge | Int | Development | ### sqlserver.page.lookup.rate @@ -452,7 +452,7 @@ Total number of page lookups. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| “{lookups}/s” | Gauge | Double | development | +| “{lookups}/s” | Gauge | Double | Development | ### sqlserver.processes.blocked @@ -462,7 +462,7 @@ This metric is only available when the receiver is configured to directly connec | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {processes} | Gauge | Int | development | +| {processes} | Gauge | Int | Development | ### sqlserver.replica.data.rate @@ -470,13 +470,13 @@ Throughput rate of replica data. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| By/s | Gauge | Double | development | +| By/s | Gauge | Double | Development | #### Attributes -| Name | Description | Values | Optional | +| Name | Description | Values | Requirement Level | | ---- | ----------- | ------ | -------- | -| replica.direction | The direction of flow of bytes for replica. | Str: ``transmit``, ``receive`` | false | +| replica.direction | The direction of flow of bytes for replica. | Str: ``transmit``, ``receive`` | Recommended | ### sqlserver.resource_pool.disk.operations @@ -486,13 +486,13 @@ This metric is only available when the receiver is configured to directly connec | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {operations}/s | Gauge | Double | development | +| {operations}/s | Gauge | Double | Development | #### Attributes -| Name | Description | Values | Optional | +| Name | Description | Values | Requirement Level | | ---- | ----------- | ------ | -------- | -| direction | The direction of flow of bytes or operations. | Str: ``read``, ``write`` | false | +| direction | The direction of flow of bytes or operations. | Str: ``read``, ``write`` | Recommended | ### sqlserver.resource_pool.disk.throttled.read.rate @@ -502,7 +502,7 @@ This metric is only available when the receiver is configured to directly connec | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {reads}/s | Gauge | Int | development | +| {reads}/s | Gauge | Int | Development | ### sqlserver.resource_pool.disk.throttled.write.rate @@ -512,7 +512,7 @@ This metric is only available when the receiver is configured to directly connec | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| {writes}/s | Gauge | Double | development | +| {writes}/s | Gauge | Double | Development | ### sqlserver.table.count @@ -520,14 +520,14 @@ The number of tables. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | -| “{tables}” | Sum | Int | Cumulative | false | development | +| “{tables}” | Sum | Int | Cumulative | false | Development | #### Attributes -| Name | Description | Values | Optional | +| Name | Description | Values | Requirement Level | | ---- | ----------- | ------ | -------- | -| table.state | The state of the table. | Str: ``active``, ``inactive`` | false | -| table.status | The status of the table. | Str: ``temporary``, ``permanent`` | false | +| table.state | The state of the table. | Str: ``active``, ``inactive`` | Recommended | +| table.status | The status of the table. | Str: ``temporary``, ``permanent`` | Recommended | ### sqlserver.transaction.delay @@ -535,7 +535,7 @@ Time consumed in transaction delays. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | -| ms | Sum | Double | Cumulative | false | development | +| ms | Sum | Double | Cumulative | false | Development | ### sqlserver.transaction.mirror_write.rate @@ -543,7 +543,7 @@ Total number of mirror write transactions. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | -| “{transactions}/s” | Gauge | Double | development | +| “{transactions}/s” | Gauge | Double | Development | ## Default Events diff --git a/receiver/sqlserverreceiver/generated_package_test.go b/receiver/sqlserverreceiver/generated_package_test.go index 86266f5f36641..ce3721511beef 100644 --- a/receiver/sqlserverreceiver/generated_package_test.go +++ b/receiver/sqlserverreceiver/generated_package_test.go @@ -3,8 +3,9 @@ package sqlserverreceiver import ( - "go.uber.org/goleak" "testing" + + "go.uber.org/goleak" ) func TestMain(m *testing.M) { diff --git a/receiver/sqlserverreceiver/internal/metadata/generated_config_test.go b/receiver/sqlserverreceiver/internal/metadata/generated_config_test.go index 94073cc60b8c3..6f28022a39a7a 100644 --- a/receiver/sqlserverreceiver/internal/metadata/generated_config_test.go +++ b/receiver/sqlserverreceiver/internal/metadata/generated_config_test.go @@ -9,7 +9,6 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/stretchr/testify/require" - "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/confmaptest" ) diff --git a/receiver/sqlserverreceiver/internal/metadata/generated_logs.go b/receiver/sqlserverreceiver/internal/metadata/generated_logs.go index 18d6d211b3788..2224f758a2990 100644 --- a/receiver/sqlserverreceiver/internal/metadata/generated_logs.go +++ b/receiver/sqlserverreceiver/internal/metadata/generated_logs.go @@ -4,6 +4,7 @@ package metadata import ( "context" + "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/filter" "go.opentelemetry.io/collector/pdata/pcommon" diff --git a/receiver/sqlserverreceiver/internal/metadata/generated_logs_test.go b/receiver/sqlserverreceiver/internal/metadata/generated_logs_test.go index fb265c194d02c..53531d2d36903 100644 --- a/receiver/sqlserverreceiver/internal/metadata/generated_logs_test.go +++ b/receiver/sqlserverreceiver/internal/metadata/generated_logs_test.go @@ -4,6 +4,9 @@ package metadata import ( "context" + "testing" + "time" + "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" @@ -11,8 +14,6 @@ import ( "go.opentelemetry.io/otel/trace" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" - "testing" - "time" ) type eventsTestDataSet int From 87935cd28596509ac01a40b922fee84820ac11af Mon Sep 17 00:00:00 2001 From: cjk Date: Wed, 7 Jan 2026 14:41:20 +0000 Subject: [PATCH 26/43] tweak to samples sql --- .../templates/sqlServerQuerySample.tmpl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl b/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl index 96774ccaf08a9..c4cd34f97f892 100644 --- a/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl +++ b/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl @@ -11,14 +11,14 @@ SELECT TOP(@top) ISNULL(s.host_name, '') AS host_name, r.command, SUBSTRING(o.TEXT, (r.statement_start_offset / 2) + 1, ( - ( - CASE r.statement_end_offset - WHEN - 1 - THEN DATALENGTH(o.TEXT) - ELSE r.statement_end_offset - END - r.statement_start_offset - ) / 2 - ) + 1) AS statement_text, + ( + CASE r.statement_end_offset + WHEN - 1 + THEN DATALENGTH(o.TEXT) + ELSE r.statement_end_offset + END - r.statement_start_offset + ) / 2 + ) + 1) AS statement_text, r.blocking_session_id, ISNULL(r.wait_type, '') AS wait_type, r.wait_time, From 9433fdf6c6c64d948a7b75b2712ab0b4e5d4741d Mon Sep 17 00:00:00 2001 From: sreenathv Date: Wed, 7 Jan 2026 17:39:18 +0000 Subject: [PATCH 27/43] Revert checks around sending metrics for countInDb=1, since it's addressing a negligable edge case. --- receiver/sqlserverreceiver/scraper.go | 56 ++++++------------ receiver/sqlserverreceiver/scraper_test.go | 42 ++++++++----- .../expectedQueryTextAndPlanQuery.yaml | 59 ++----------------- .../testdata/queryTextAndPlanQueryData.txt | 19 +----- 4 files changed, 54 insertions(+), 122 deletions(-) diff --git a/receiver/sqlserverreceiver/scraper.go b/receiver/sqlserverreceiver/scraper.go index c7e515c4656b0..ffa8bb11a9507 100644 --- a/receiver/sqlserverreceiver/scraper.go +++ b/receiver/sqlserverreceiver/scraper.go @@ -686,8 +686,6 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont timestamp := pcommon.NewTimestampFromTime(now) s.lastExecutionTimestamp = now for i, row := range rows { - totalElapsedTimeValDiff := float64(totalElapsedTimeDiffsMicrosecond[i]) / 1_000_000 - // reporting human-readable query hash and query hash plan queryHashVal := hex.EncodeToString([]byte(row[queryHash])) queryPlanHashVal := hex.EncodeToString([]byte(row[queryPlanHash])) @@ -706,27 +704,27 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont var cached bool executionCountVal := s.retrieveValue(row, executionCount, &errs, retrieveInt) - cached, executionCountValDiff := s.cacheAndDiff(queryHashVal, queryPlanHashVal, executionCount, executionCountVal.(int64)) + cached, executionCountVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, executionCount, executionCountVal.(int64)) if !cached { - executionCountValDiff = int64(0) + executionCountVal = int64(0) } logicalReadsVal := s.retrieveValue(row, logicalReads, &errs, retrieveInt) - cached, logicalReadsValDiff := s.cacheAndDiff(queryHashVal, queryPlanHashVal, logicalReads, logicalReadsVal.(int64)) + cached, logicalReadsVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, logicalReads, logicalReadsVal.(int64)) if !cached { - logicalReadsValDiff = int64(0) + logicalReadsVal = int64(0) } logicalWritesVal := s.retrieveValue(row, logicalWrites, &errs, retrieveInt) - cached, logicalWritesValDiff := s.cacheAndDiff(queryHashVal, queryPlanHashVal, logicalWrites, logicalWritesVal.(int64)) + cached, logicalWritesVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, logicalWrites, logicalWritesVal.(int64)) if !cached { - logicalWritesValDiff = int64(0) + logicalWritesVal = int64(0) } physicalReadsVal := s.retrieveValue(row, physicalReads, &errs, retrieveInt) - cached, physicalReadsValDiff := s.cacheAndDiff(queryHashVal, queryPlanHashVal, physicalReads, physicalReadsVal.(int64)) + cached, physicalReadsVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, physicalReads, physicalReadsVal.(int64)) if !cached { - physicalReadsValDiff = int64(0) + physicalReadsVal = int64(0) } queryPlanVal := s.retrieveValue(row, queryPlan, &errs, func(row sqlquery.StringMap, columnName string) (any, error) { @@ -734,42 +732,26 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont }) rowsReturnedVal := s.retrieveValue(row, rowsReturned, &errs, retrieveInt) - cached, rowsReturnedValDiff := s.cacheAndDiff(queryHashVal, queryPlanHashVal, rowsReturned, rowsReturnedVal.(int64)) + cached, rowsReturnedVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, rowsReturned, rowsReturnedVal.(int64)) if !cached { - rowsReturnedValDiff = int64(0) + rowsReturnedVal = int64(0) } totalGrantVal := s.retrieveValue(row, totalGrant, &errs, retrieveInt) - cached, totalGrantValDiff := s.cacheAndDiff(queryHashVal, queryPlanHashVal, totalGrant, totalGrantVal.(int64)) + cached, totalGrantVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, totalGrant, totalGrantVal.(int64)) if !cached { - totalGrantValDiff = int64(0) + totalGrantVal = int64(0) } - totalWorkerTimeVal := float64(s.retrieveValue(row, totalWorkerTime, &errs, retrieveInt).(int64)) - cached, totalWorkerTimeValCached := s.cacheAndDiff(queryHashVal, queryPlanHashVal, totalWorkerTime, int64(totalWorkerTimeVal)) - totalWorkerTimeValDiff := float64(0) + totalWorkerTimeVal := s.retrieveValue(row, totalWorkerTime, &errs, retrieveInt) + cached, totalWorkerTimeVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, totalWorkerTime, totalWorkerTimeVal.(int64)) + totalWorkerTimeInSecVal := float64(0) if cached { - totalWorkerTimeValDiff = float64(totalWorkerTimeValCached) / 1_000_000 - } - - totalElapsedTimeVal := s.retrieveValue(row, totalElapsedTime, &errs, retrieveFloat).(float64) / 1_000_000 - - // If execution count in the DB is 1 that would mean there is no past records to compare with to find a delta. - // We just send down the metrics corresponding to that single execution as it is. - // If execution count in DB is not 1 then we send down the delta values. - execCountInDB := executionCountVal.(int64) - if execCountInDB != 1 { - executionCountVal = executionCountValDiff - logicalReadsVal = logicalReadsValDiff - logicalWritesVal = logicalWritesValDiff - physicalReadsVal = physicalReadsValDiff - rowsReturnedVal = rowsReturnedValDiff - totalGrantVal = totalGrantValDiff - totalWorkerTimeVal = totalWorkerTimeValDiff - totalElapsedTimeVal = totalElapsedTimeValDiff + totalWorkerTimeInSecVal = float64(totalWorkerTimeVal.(int64)) / 1_000_000 } - if totalElapsedTimeVal == 0 { + totalElapsedTimeVal := float64(totalElapsedTimeDiffsMicrosecond[i]) / 1_000_000 + if totalElapsedTimeVal == 0 || executionCountVal == 0 { continue } @@ -787,7 +769,7 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont s.lb.RecordDbServerTopQueryEvent( context.Background(), timestamp, - totalWorkerTimeVal, + totalWorkerTimeInSecVal, queryTextVal.(string), executionCountVal.(int64), logicalReadsVal.(int64), diff --git a/receiver/sqlserverreceiver/scraper_test.go b/receiver/sqlserverreceiver/scraper_test.go index 3fb6e410cd530..b84775492cae7 100644 --- a/receiver/sqlserverreceiver/scraper_test.go +++ b/receiver/sqlserverreceiver/scraper_test.go @@ -407,8 +407,7 @@ func TestQueryTextAndPlanQueryMetricsShouldBeCachedSinceFirstCollection(t *testi topQueryCount: 200, } - actualLogs, err := scraper.ScrapeLogs(t.Context()) - assert.NoError(t, err) + scraper.ScrapeLogs(t.Context()) expectedFile := filepath.Join("testdata", "expectedQueryTextAndPlanQuery.yaml") expectedLogs, _ := golden.ReadLogs(expectedFile) @@ -417,18 +416,33 @@ func TestQueryTextAndPlanQueryMetricsShouldBeCachedSinceFirstCollection(t *testi planHash, _ := expectedLogs.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).Attributes().Get("sqlserver.query_plan_hash") keyPrefix := queryHash.Str() + "-" + planHash.Str() - assert.True(t, scraper.cache.Contains(keyPrefix+"-"+totalElapsedTime)) - assert.True(t, scraper.cache.Contains(keyPrefix+"-"+rowsReturned)) - assert.True(t, scraper.cache.Contains(keyPrefix+"-"+totalWorkerTime)) - assert.True(t, scraper.cache.Contains(keyPrefix+"-"+logicalReads)) - assert.True(t, scraper.cache.Contains(keyPrefix+"-"+logicalWrites)) - assert.True(t, scraper.cache.Contains(keyPrefix+"-"+physicalReads)) - assert.True(t, scraper.cache.Contains(keyPrefix+"-"+executionCount)) - assert.True(t, scraper.cache.Contains(keyPrefix+"-"+totalGrant)) - - assert.Equal(t, 1, actualLogs.LogRecordCount()) - collectQueryHash, _ := actualLogs.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).Attributes().Get("sqlserver.query_hash") - assert.Equal(t, hex.EncodeToString([]byte("0x37849E874171E3F4")), collectQueryHash.Str(), "Metrics for the record with 1 execution_count in db should be reported always regardless of cache record presence") + tetValue, ok := scraper.cache.Get(keyPrefix + "-" + totalElapsedTime) + assert.True(t, ok, "Expected to find elapsed time in cache right after the first collection") + assert.Equal(t, 3846, int(tetValue)) + + rtValue, ok := scraper.cache.Get(keyPrefix + "-" + rowsReturned) + assert.True(t, ok, "Expected to find rowsReturned time in cache right after the first collection") + assert.Equal(t, 2, int(rtValue)) + + twtValue, ok := scraper.cache.Get(keyPrefix + "-" + totalWorkerTime) + assert.True(t, ok, "Expected to find totalWorkerTime time in cache right after the first collection") + assert.Equal(t, 3845, int(twtValue)) + + lrValue, ok := scraper.cache.Get(keyPrefix + "-" + logicalReads) + assert.True(t, ok, "Expected to find logicalReads time in cache right after the first collection") + assert.Equal(t, 3, int(lrValue)) + + prValue, ok := scraper.cache.Get(keyPrefix + "-" + physicalReads) + assert.True(t, ok, "Expected to find physicalReads time in cache right after the first collection") + assert.Equal(t, 5, int(prValue)) + + ecValue, ok := scraper.cache.Get(keyPrefix + "-" + executionCount) + assert.True(t, ok, "Expected to find executionCount time in cache right after the first collection") + assert.Equal(t, 6, int(ecValue)) + + tgValue, ok := scraper.cache.Get(keyPrefix + "-" + totalGrant) + assert.True(t, ok, "Expected to find totalGrant time in cache right after the first collection") + assert.Equal(t, 3096, int(tgValue)) } func TestQueryTextAndPlanQuery(t *testing.T) { diff --git a/receiver/sqlserverreceiver/testdata/expectedQueryTextAndPlanQuery.yaml b/receiver/sqlserverreceiver/testdata/expectedQueryTextAndPlanQuery.yaml index 690af0a54bb32..4042e9baab083 100644 --- a/receiver/sqlserverreceiver/testdata/expectedQueryTextAndPlanQuery.yaml +++ b/receiver/sqlserverreceiver/testdata/expectedQueryTextAndPlanQuery.yaml @@ -4,15 +4,15 @@ resourceLogs: - key: host.name value: stringValue: 0.0.0.0 + - key: service.instance.id + value: + stringValue: 0.0.0.0:1433 - key: sqlserver.computer.name value: stringValue: DESKTOP-GHAEGRD - key: sqlserver.instance.name value: stringValue: sqlserver - - key: service.instance.id - value: - stringValue: 0.0.0.0:1433 scopeLogs: - logRecords: - attributes: @@ -63,56 +63,9 @@ resourceLogs: stringValue: microsoft.sql_server body: {} eventName: db.server.top_query - timeUnixNano: "1767627037097600000" - - attributes: - - key: sqlserver.total_worker_time - value: - doubleValue: 3845 - - key: db.query.text - value: - stringValue: with qstats SELECT TOP ( @topNValue ) REPLACE ( @@SERVERNAME, ? ), HOST_NAME ( ), MAX ( qs.plan_handle ), qs.query_hash, qs.query_plan_hash, SUM ( qs.execution_count ), SUM ( qs.total_elapsed_time ), SUM ( qs.total_worker_time ), SUM ( qs.total_logical_reads ), SUM ( qs.total_physical_reads ), SUM ( qs.total_logical_writes ), SUM ( qs.total_rows ), SUM ( qs.total_grant_kb ) FROM sys.dm_exec_query_stats WHERE qs.last_execution_time BETWEEN DATEADD ( SECOND, @granularity, GETDATE ( ) ) AND GETDATE ( ) GROUP BY qs.query_hash, qs.query_plan_hash ) SELECT qs.*, SUBSTRING ( st.text, ( stats.statement_start_offset / ? ) + ? ( ( CASE statement_end_offset WHEN ? THEN DATALENGTH ( st.text ) ELSE stats.statement_end_offset END - stats.statement_start_offset ) / ? ) + ? ), ISNULL ( qp.query_plan, ? ) FROM qstats INNER JOIN sys.dm_exec_query_stats on qs.query_plan_handle = stats.plan_handle CROSS APPLY sys.dm_exec_query_plan ( qs.query_plan_handle ) CROSS APPLY sys.dm_exec_sql_text ( qs.query_plan_handle ) - - key: sqlserver.execution_count - value: - intValue: "1" - - key: sqlserver.total_logical_reads - value: - intValue: "3" - - key: sqlserver.total_logical_writes - value: - intValue: "4" - - key: sqlserver.total_physical_reads - value: - intValue: "5" - - key: sqlserver.query_hash - value: - stringValue: "307833373834394538373431373145334634" - - key: sqlserver.query_plan - value: - stringValue: - - key: sqlserver.query_plan_hash - value: - stringValue: "307844333131323930393432394131423534" - - key: sqlserver.total_rows - value: - intValue: "2" - - key: sqlserver.total_elapsed_time - value: - doubleValue: 0.003846 - - key: sqlserver.total_grant_kb - value: - intValue: "3096" - - key: server.address - value: - stringValue: 0.0.0.0 - - key: server.port - value: - intValue: "1433" - - key: db.system.name - value: - stringValue: microsoft.sql_server - body: {} - eventName: db.server.top_query - timeUnixNano: "1767627037097600000" + spanId: "" + timeUnixNano: "1749224037462260000" + traceId: "" scope: name: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/sqlserverreceiver version: latest diff --git a/receiver/sqlserverreceiver/testdata/queryTextAndPlanQueryData.txt b/receiver/sqlserverreceiver/testdata/queryTextAndPlanQueryData.txt index 69dc183f9fb6b..abd3e31b681f7 100644 --- a/receiver/sqlserverreceiver/testdata/queryTextAndPlanQueryData.txt +++ b/receiver/sqlserverreceiver/testdata/queryTextAndPlanQueryData.txt @@ -15,22 +15,5 @@ "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": "" - }, - { - "sql_instance": "sqlserver", - "computer_name": "DESKTOP-GHAEGRD", - "query_plan_handle": "0x06000100E2B3C02AA042A7001000000001000000000000000000000000000000000000000000000000000000", - "query_hash": "0x37849E874171E3F4", - "query_plan_hash": "0xD3112909429A1B54", - "execution_count": "1", - "total_elapsed_time": "3846", - "total_worker_time": "3845", - "total_logical_reads": "3", - "total_physical_reads": "5", - "total_logical_writes": "4", - "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": "" - } + } ] From 4db323b681e5def573c7c370a2b92e6f759d3282 Mon Sep 17 00:00:00 2001 From: cjk Date: Thu, 8 Jan 2026 11:49:55 +0000 Subject: [PATCH 28/43] Updates in prep for testing --- .../templates/dbQueryAndTextQuery.tmpl | 79 +++++++-------- .../templates/sqlServerQuerySample.tmpl | 99 +++++++++---------- 2 files changed, 87 insertions(+), 91 deletions(-) diff --git a/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl b/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl index 20da91dea8a26..d971262d91bf0 100644 --- a/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl +++ b/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl @@ -1,41 +1,38 @@ -;WITH qstats AS - ( - SELECT TOP (@maxSampleCount) - REPLACE(@@SERVERNAME,'\',':') AS [sql_instance], - HOST_NAME() AS [computer_name], - max(qs.plan_handle) AS plan_handle, - ISNULL(st1.objectid, 0) AS object_id, - qs.query_hash AS query_hash, - qs.query_plan_hash AS query_plan_hash, - SUM(qs.execution_count) AS execution_count, - SUM(qs.total_elapsed_time) AS total_elapsed_time, - SUM(qs.total_worker_time) AS total_worker_time, - SUM(qs.total_logical_reads) AS total_logical_reads, - SUM(qs.total_physical_reads) AS total_physical_reads, - SUM(qs.total_logical_writes) AS total_logical_writes, - 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 - WHERE qs.last_execution_time BETWEEN DATEADD(SECOND, @lookbackTime, GETDATE()) AND GETDATE() - GROUP BY st1.objectid, qs.query_hash, qs.query_plan_hash - ) - SELECT - qs.*, - SUBSTRING(st.text, - (stats.statement_start_offset / 2) + 1, - ((CASE stats.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(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 - JOIN sys.dm_exec_query_stats AS stats - ON stats.plan_handle = qs.plan_handle - CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) AS qp - CROSS APPLY sys.dm_exec_sql_text(qs.plan_handle) AS st; \ No newline at end of file +with qstats as ( + SELECT TOP(@maxSampleCount) + REPLACE(@@SERVERNAME,'\',':') AS [sql_instance], + HOST_NAME() AS [computer_name], + 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, + qs.query_hash AS query_hash, + qs.query_plan_hash AS query_plan_hash, + SUM(qs.execution_count) AS execution_count, + SUM(qs.total_elapsed_time) AS total_elapsed_time, + SUM(qs.total_worker_time) AS total_worker_time, + SUM(qs.total_logical_reads) AS total_logical_reads, + SUM(qs.total_physical_reads) AS total_physical_reads, + SUM(qs.total_logical_writes) AS total_logical_writes, + SUM(qs.total_rows) AS total_rows, + SUM(qs.total_grant_kb) as total_grant_kb + FROM sys.dm_exec_query_stats AS qs + GROUP BY + qs.query_hash, + qs.query_plan_hash +) +SELECT qs.*, + SUBSTRING(st.text, (stats.statement_start_offset / 2) + 1, + ((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(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 +WHERE DATEADD(ms, qs.last_elapsed_time / 1000, qs.last_execution_time) > DATEADD(SECOND, @lookbackTime, GETDATE()); \ No newline at end of file diff --git a/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl b/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl index c4cd34f97f892..5ff57fcee6d99 100644 --- a/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl +++ b/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl @@ -1,52 +1,51 @@ SELECT TOP(@top) - REPLACE(@@SERVERNAME,'\',':') AS [sql_instance], - HOST_NAME() AS [computer_name], - DB_NAME(r.database_id) AS db_name, - ISNULL(c.client_net_address, '') as client_address, - ISNULL(c.client_tcp_port, '') AS client_port, - CONVERT(NVARCHAR, TODATETIMEOFFSET(r.start_time, DATEPART(TZOFFSET, SYSDATETIMEOFFSET())), 126) AS query_start, - s.session_id, - s.STATUS AS session_status, - r.STATUS AS request_status, - ISNULL(s.host_name, '') AS host_name, - r.command, - SUBSTRING(o.TEXT, (r.statement_start_offset / 2) + 1, ( - ( - CASE r.statement_end_offset - WHEN - 1 - THEN DATALENGTH(o.TEXT) - ELSE r.statement_end_offset - END - r.statement_start_offset - ) / 2 - ) + 1) AS statement_text, - r.blocking_session_id, - ISNULL(r.wait_type, '') AS wait_type, - r.wait_time, - r.wait_resource, - r.open_transaction_count, - r.transaction_id, - r.percent_complete, - r.estimated_completion_time, - r.cpu_time, - r.total_elapsed_time, - r.reads, - r.writes, - r.logical_reads, - r.transaction_isolation_level, - r.lock_timeout, - r.deadlock_priority, - r.row_count, - 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, - 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 + REPLACE(@@SERVERNAME,'\',':') AS [sql_instance], + HOST_NAME() AS [computer_name], + DB_NAME(r.database_id) AS db_name, + ISNULL(c.client_net_address, '') as client_address, + ISNULL(c.client_tcp_port, '') AS client_port, + CONVERT(NVARCHAR, TODATETIMEOFFSET(r.start_time, DATEPART(TZOFFSET, SYSDATETIMEOFFSET())), 126) AS query_start, + s.session_id, + s.STATUS AS session_status, + r.STATUS AS request_status, + ISNULL(s.host_name, '') AS host_name, + r.command, + SUBSTRING(o.TEXT, (r.statement_start_offset / 2) + 1, ( + ( + CASE r.statement_end_offset + WHEN - 1 + THEN DATALENGTH(o.TEXT) + ELSE r.statement_end_offset + END - r.statement_start_offset + ) / 2 + ) + 1) AS statement_text, + r.blocking_session_id, + ISNULL(r.wait_type, '') AS wait_type, + r.wait_time, + r.wait_resource, + r.open_transaction_count, + r.transaction_id, + r.percent_complete, + r.estimated_completion_time, + r.cpu_time, + r.total_elapsed_time, + r.reads, + r.writes, + r.logical_reads, + r.transaction_isolation_level, + r.lock_timeout, + r.deadlock_priority, + r.row_count, + 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, + 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 - CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS o; - +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 +CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS o; \ No newline at end of file From bb78240db51f2a0dc1d32dbadfe26b69767651d5 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Thu, 8 Jan 2026 13:07:51 +0000 Subject: [PATCH 29/43] fix lint --- receiver/sqlserverreceiver/scraper_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/receiver/sqlserverreceiver/scraper_test.go b/receiver/sqlserverreceiver/scraper_test.go index b84775492cae7..0ee9a899791f7 100644 --- a/receiver/sqlserverreceiver/scraper_test.go +++ b/receiver/sqlserverreceiver/scraper_test.go @@ -394,7 +394,6 @@ func TestQueryTextAndPlanQueryMetricsShouldBeCachedSinceFirstCollection(t *testi const rowsReturned = "total_rows" const totalWorkerTime = "total_worker_time" const logicalReads = "total_logical_reads" - const logicalWrites = "total_logical_writes" const physicalReads = "total_physical_reads" const executionCount = "execution_count" const totalGrant = "total_grant_kb" @@ -407,7 +406,8 @@ func TestQueryTextAndPlanQueryMetricsShouldBeCachedSinceFirstCollection(t *testi topQueryCount: 200, } - scraper.ScrapeLogs(t.Context()) + _, err := scraper.ScrapeLogs(t.Context()) + assert.NoError(t, err) expectedFile := filepath.Join("testdata", "expectedQueryTextAndPlanQuery.yaml") expectedLogs, _ := golden.ReadLogs(expectedFile) From b47bd3e85df55432273f5388352716df0ffb7336 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Thu, 8 Jan 2026 15:33:12 +0000 Subject: [PATCH 30/43] cleanup --- receiver/sqlserverreceiver/scraper_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/receiver/sqlserverreceiver/scraper_test.go b/receiver/sqlserverreceiver/scraper_test.go index 0ee9a899791f7..a149bfffc5e66 100644 --- a/receiver/sqlserverreceiver/scraper_test.go +++ b/receiver/sqlserverreceiver/scraper_test.go @@ -421,27 +421,27 @@ func TestQueryTextAndPlanQueryMetricsShouldBeCachedSinceFirstCollection(t *testi assert.Equal(t, 3846, int(tetValue)) rtValue, ok := scraper.cache.Get(keyPrefix + "-" + rowsReturned) - assert.True(t, ok, "Expected to find rowsReturned time in cache right after the first collection") + assert.True(t, ok, "Expected to find rowsReturned in cache right after the first collection") assert.Equal(t, 2, int(rtValue)) twtValue, ok := scraper.cache.Get(keyPrefix + "-" + totalWorkerTime) - assert.True(t, ok, "Expected to find totalWorkerTime time in cache right after the first collection") + assert.True(t, ok, "Expected to find totalWorkerTime in cache right after the first collection") assert.Equal(t, 3845, int(twtValue)) lrValue, ok := scraper.cache.Get(keyPrefix + "-" + logicalReads) - assert.True(t, ok, "Expected to find logicalReads time in cache right after the first collection") + assert.True(t, ok, "Expected to find logicalReads in cache right after the first collection") assert.Equal(t, 3, int(lrValue)) prValue, ok := scraper.cache.Get(keyPrefix + "-" + physicalReads) - assert.True(t, ok, "Expected to find physicalReads time in cache right after the first collection") + assert.True(t, ok, "Expected to find physicalReads in cache right after the first collection") assert.Equal(t, 5, int(prValue)) ecValue, ok := scraper.cache.Get(keyPrefix + "-" + executionCount) - assert.True(t, ok, "Expected to find executionCount time in cache right after the first collection") + assert.True(t, ok, "Expected to find executionCount in cache right after the first collection") assert.Equal(t, 6, int(ecValue)) tgValue, ok := scraper.cache.Get(keyPrefix + "-" + totalGrant) - assert.True(t, ok, "Expected to find totalGrant time in cache right after the first collection") + assert.True(t, ok, "Expected to find totalGrant in cache right after the first collection") assert.Equal(t, 3096, int(tgValue)) } From d0514119cea971026c0206987fab189110f949d2 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Fri, 9 Jan 2026 15:25:26 +0000 Subject: [PATCH 31/43] Fix invalid casting and update old test --- receiver/sqlserverreceiver/scraper.go | 2 +- receiver/sqlserverreceiver/scraper_test.go | 12 +--- ...dQueryTextAndPlanQueryWithInvalidData.yaml | 71 ------------------- 3 files changed, 2 insertions(+), 83 deletions(-) delete mode 100644 receiver/sqlserverreceiver/testdata/expectedQueryTextAndPlanQueryWithInvalidData.yaml diff --git a/receiver/sqlserverreceiver/scraper.go b/receiver/sqlserverreceiver/scraper.go index ffa8bb11a9507..c40b554d480ff 100644 --- a/receiver/sqlserverreceiver/scraper.go +++ b/receiver/sqlserverreceiver/scraper.go @@ -751,7 +751,7 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont } totalElapsedTimeVal := float64(totalElapsedTimeDiffsMicrosecond[i]) / 1_000_000 - if totalElapsedTimeVal == 0 || executionCountVal == 0 { + if count, ok := executionCountVal.(int64); !ok || count == 0 || totalElapsedTimeVal == 0 { continue } diff --git a/receiver/sqlserverreceiver/scraper_test.go b/receiver/sqlserverreceiver/scraper_test.go index a149bfffc5e66..1ec36f87e77fc 100644 --- a/receiver/sqlserverreceiver/scraper_test.go +++ b/receiver/sqlserverreceiver/scraper_test.go @@ -556,17 +556,7 @@ func TestInvalidQueryTextAndPlanQuery(t *testing.T) { actualLogs, err := scraper.ScrapeLogs(t.Context()) assert.Error(t, err) - expectedFile := "expectedQueryTextAndPlanQueryWithInvalidData.yaml" - - // Uncomment line below to re-generate expected logs. - // golden.WriteLogs(t, filepath.Join("testdata", expectedFile), actualLogs) - - expectedLogs, err := golden.ReadLogs(filepath.Join("testdata", expectedFile)) - assert.NoError(t, err) - - errs := plogtest.CompareLogs(expectedLogs, actualLogs, plogtest.IgnoreTimestamp()) - assert.Equal(t, "db.server.top_query", actualLogs.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).EventName()) - assert.NoError(t, errs) + assert.Zero(t, actualLogs.LogRecordCount(), "If the metrics does not hold meaningful values then those records need not be exported by the receiver") } func TestRecordDatabaseSampleQuery(t *testing.T) { diff --git a/receiver/sqlserverreceiver/testdata/expectedQueryTextAndPlanQueryWithInvalidData.yaml b/receiver/sqlserverreceiver/testdata/expectedQueryTextAndPlanQueryWithInvalidData.yaml deleted file mode 100644 index b9c8b65d2503b..0000000000000 --- a/receiver/sqlserverreceiver/testdata/expectedQueryTextAndPlanQueryWithInvalidData.yaml +++ /dev/null @@ -1,71 +0,0 @@ -resourceLogs: - - resource: - attributes: - - key: host.name - value: - stringValue: 0.0.0.0 - - key: service.instance.id - value: - stringValue: 0.0.0.0:1433 - - key: sqlserver.computer.name - value: - stringValue: DESKTOP-GHAEGRD - - key: sqlserver.instance.name - value: - stringValue: sqlserver - scopeLogs: - - logRecords: - - attributes: - - key: sqlserver.total_worker_time - value: - doubleValue: 0 - - key: db.query.text - value: - stringValue: "" - - key: sqlserver.execution_count - value: - intValue: "0" - - key: sqlserver.total_logical_reads - value: - intValue: "0" - - key: sqlserver.total_logical_writes - value: - intValue: "0" - - key: sqlserver.total_physical_reads - value: - intValue: "0" - - key: sqlserver.query_hash - value: - stringValue: "307833373834394538373431373145334633" - - key: sqlserver.query_plan - value: - stringValue: "" - - key: sqlserver.query_plan_hash - value: - stringValue: "307844333131323930393432394131423530" - - key: sqlserver.total_rows - value: - intValue: "0" - - key: sqlserver.total_elapsed_time - value: - doubleValue: 0.003845 - - key: sqlserver.total_grant_kb - value: - intValue: "0" - - key: server.address - value: - stringValue: 0.0.0.0 - - key: server.port - value: - intValue: "1433" - - key: db.system.name - value: - stringValue: microsoft.sql_server - body: {} - eventName: db.server.top_query - spanId: "" - timeUnixNano: "1748501969782683000" - traceId: "" - scope: - name: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/sqlserverreceiver - version: latest From e32d34ceda53391fd2eb2aeffdab07ced2e142f8 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Fri, 9 Jan 2026 15:26:59 +0000 Subject: [PATCH 32/43] Updating topN query to use HAVING instead of external WHERE clause --- receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl | 4 ++-- .../testdata/databaseTopQueryWithInstanceName.txt | 2 +- .../testdata/databaseTopQueryWithoutInstanceName.txt | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl b/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl index d59a29ac3888b..933f1cc40caf3 100644 --- a/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl +++ b/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl @@ -19,6 +19,7 @@ with qstats as ( GROUP BY qs.query_hash, qs.query_plan_hash + HAVING MAX(DATEADD(ms, qs.last_elapsed_time / 1000, qs.last_execution_time)) > DATEADD(SECOND, @lookbackTime, GETDATE()) ) SELECT qs.*, SUBSTRING(st.text, (stats.statement_start_offset / 2) + 1, @@ -29,5 +30,4 @@ 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 -WHERE DATEADD(ms, qs.last_elapsed_time / 1000, qs.last_execution_time) > DATEADD(SECOND, @lookbackTime, GETDATE()); + CROSS APPLY sys.dm_exec_sql_text(qs.query_plan_handle) AS st; diff --git a/receiver/sqlserverreceiver/testdata/databaseTopQueryWithInstanceName.txt b/receiver/sqlserverreceiver/testdata/databaseTopQueryWithInstanceName.txt index 29228f5aba2e4..5d36da836b57b 100644 --- a/receiver/sqlserverreceiver/testdata/databaseTopQueryWithInstanceName.txt +++ b/receiver/sqlserverreceiver/testdata/databaseTopQueryWithInstanceName.txt @@ -14,10 +14,10 @@ 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 - WHERE qs.last_execution_time BETWEEN DATEADD(SECOND, @lookbackTime, GETDATE()) AND GETDATE() AND (@instanceName = '' OR @@SERVERNAME = @instanceName) GROUP BY qs.query_hash, qs.query_plan_hash + HAVING MAX(DATEADD(ms, qs.last_elapsed_time / 1000, qs.last_execution_time)) > DATEADD(SECOND, @lookbackTime, GETDATE()) ) SELECT qs.*, SUBSTRING(st.text, (stats.statement_start_offset / 2) + 1, diff --git a/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt b/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt index d59a29ac3888b..933f1cc40caf3 100644 --- a/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt +++ b/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt @@ -19,6 +19,7 @@ with qstats as ( GROUP BY qs.query_hash, qs.query_plan_hash + HAVING MAX(DATEADD(ms, qs.last_elapsed_time / 1000, qs.last_execution_time)) > DATEADD(SECOND, @lookbackTime, GETDATE()) ) SELECT qs.*, SUBSTRING(st.text, (stats.statement_start_offset / 2) + 1, @@ -29,5 +30,4 @@ 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 -WHERE DATEADD(ms, qs.last_elapsed_time / 1000, qs.last_execution_time) > DATEADD(SECOND, @lookbackTime, GETDATE()); + CROSS APPLY sys.dm_exec_sql_text(qs.query_plan_handle) AS st; From 53e83a29d48bdb02ce6a13df28b11bc738f0c4d9 Mon Sep 17 00:00:00 2001 From: cjk Date: Thu, 15 Jan 2026 10:20:27 +0000 Subject: [PATCH 33/43] Query Tuning --- .../templates/dbQueryAndTextQuery.tmpl | 10 +- .../databaseTopQueryWithoutInstanceName.txt | 10 +- .../testdata/testQuerySampleQuery.txt | 99 +++++++++---------- 3 files changed, 67 insertions(+), 52 deletions(-) diff --git a/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl b/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl index 933f1cc40caf3..20883d5360b61 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,7 +29,12 @@ 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 diff --git a/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt b/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt index 933f1cc40caf3..20883d5360b61 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,7 +29,12 @@ 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 diff --git a/receiver/sqlserverreceiver/testdata/testQuerySampleQuery.txt b/receiver/sqlserverreceiver/testdata/testQuerySampleQuery.txt index 96774ccaf08a9..5ff57fcee6d99 100644 --- a/receiver/sqlserverreceiver/testdata/testQuerySampleQuery.txt +++ b/receiver/sqlserverreceiver/testdata/testQuerySampleQuery.txt @@ -1,52 +1,51 @@ SELECT TOP(@top) - REPLACE(@@SERVERNAME,'\',':') AS [sql_instance], - HOST_NAME() AS [computer_name], - DB_NAME(r.database_id) AS db_name, - ISNULL(c.client_net_address, '') as client_address, - ISNULL(c.client_tcp_port, '') AS client_port, - CONVERT(NVARCHAR, TODATETIMEOFFSET(r.start_time, DATEPART(TZOFFSET, SYSDATETIMEOFFSET())), 126) AS query_start, - s.session_id, - s.STATUS AS session_status, - r.STATUS AS request_status, - ISNULL(s.host_name, '') AS host_name, - r.command, - SUBSTRING(o.TEXT, (r.statement_start_offset / 2) + 1, ( - ( - CASE r.statement_end_offset - WHEN - 1 - THEN DATALENGTH(o.TEXT) - ELSE r.statement_end_offset - END - r.statement_start_offset - ) / 2 - ) + 1) AS statement_text, - r.blocking_session_id, - ISNULL(r.wait_type, '') AS wait_type, - r.wait_time, - r.wait_resource, - r.open_transaction_count, - r.transaction_id, - r.percent_complete, - r.estimated_completion_time, - r.cpu_time, - r.total_elapsed_time, - r.reads, - r.writes, - r.logical_reads, - r.transaction_isolation_level, - r.lock_timeout, - r.deadlock_priority, - r.row_count, - 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, - 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 + REPLACE(@@SERVERNAME,'\',':') AS [sql_instance], + HOST_NAME() AS [computer_name], + DB_NAME(r.database_id) AS db_name, + ISNULL(c.client_net_address, '') as client_address, + ISNULL(c.client_tcp_port, '') AS client_port, + CONVERT(NVARCHAR, TODATETIMEOFFSET(r.start_time, DATEPART(TZOFFSET, SYSDATETIMEOFFSET())), 126) AS query_start, + s.session_id, + s.STATUS AS session_status, + r.STATUS AS request_status, + ISNULL(s.host_name, '') AS host_name, + r.command, + SUBSTRING(o.TEXT, (r.statement_start_offset / 2) + 1, ( + ( + CASE r.statement_end_offset + WHEN - 1 + THEN DATALENGTH(o.TEXT) + ELSE r.statement_end_offset + END - r.statement_start_offset + ) / 2 + ) + 1) AS statement_text, + r.blocking_session_id, + ISNULL(r.wait_type, '') AS wait_type, + r.wait_time, + r.wait_resource, + r.open_transaction_count, + r.transaction_id, + r.percent_complete, + r.estimated_completion_time, + r.cpu_time, + r.total_elapsed_time, + r.reads, + r.writes, + r.logical_reads, + r.transaction_isolation_level, + r.lock_timeout, + r.deadlock_priority, + r.row_count, + 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, + 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 - CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS o; - +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 +CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS o; \ No newline at end of file From 45b217331132b4a4071614a52627d3c4b36c7f77 Mon Sep 17 00:00:00 2001 From: cjk Date: Tue, 20 Jan 2026 10:25:09 +0000 Subject: [PATCH 34/43] Adding '''WHERE st.text IS NOT NULL; ''' to topx and samples queries --- receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl | 3 ++- receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl | 3 ++- .../testdata/databaseTopQueryWithInstanceName.txt | 3 ++- .../testdata/databaseTopQueryWithoutInstanceName.txt | 3 ++- receiver/sqlserverreceiver/testdata/testQuerySampleQuery.txt | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl b/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl index 20883d5360b61..7c0c129284a48 100644 --- a/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl +++ b/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl @@ -38,4 +38,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/templates/sqlServerQuerySample.tmpl b/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl index 5ff57fcee6d99..2fbc90607539c 100644 --- a/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl +++ b/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl @@ -48,4 +48,5 @@ SELECT TOP(@top) 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 -CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS o; \ No newline at end of file +CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS o +WHERE st.text IS NOT NULL; \ No newline at end of file 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 20883d5360b61..7c0c129284a48 100644 --- a/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt +++ b/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt @@ -38,4 +38,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/testQuerySampleQuery.txt b/receiver/sqlserverreceiver/testdata/testQuerySampleQuery.txt index 5ff57fcee6d99..2fbc90607539c 100644 --- a/receiver/sqlserverreceiver/testdata/testQuerySampleQuery.txt +++ b/receiver/sqlserverreceiver/testdata/testQuerySampleQuery.txt @@ -48,4 +48,5 @@ SELECT TOP(@top) 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 -CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS o; \ No newline at end of file +CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS o +WHERE st.text IS NOT NULL; \ No newline at end of file From e52062a0ce5991669f2992dfea1c5c29b172054b Mon Sep 17 00:00:00 2001 From: cjk Date: Wed, 21 Jan 2026 16:05:13 +0000 Subject: [PATCH 35/43] Backed out changes to samples query --- receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl | 3 +-- receiver/sqlserverreceiver/testdata/testQuerySampleQuery.txt | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl b/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl index 2fbc90607539c..5ff57fcee6d99 100644 --- a/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl +++ b/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl @@ -48,5 +48,4 @@ SELECT TOP(@top) 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 -CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS o -WHERE st.text IS NOT NULL; \ No newline at end of file +CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS o; \ No newline at end of file diff --git a/receiver/sqlserverreceiver/testdata/testQuerySampleQuery.txt b/receiver/sqlserverreceiver/testdata/testQuerySampleQuery.txt index 2fbc90607539c..5ff57fcee6d99 100644 --- a/receiver/sqlserverreceiver/testdata/testQuerySampleQuery.txt +++ b/receiver/sqlserverreceiver/testdata/testQuerySampleQuery.txt @@ -48,5 +48,4 @@ SELECT TOP(@top) 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 -CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS o -WHERE st.text IS NOT NULL; \ No newline at end of file +CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS o; \ No newline at end of file From 088a342f1ef26978462c1c72c4ca22ce8ab25239 Mon Sep 17 00:00:00 2001 From: cjk Date: Thu, 22 Jan 2026 10:30:26 +0000 Subject: [PATCH 36/43] Adding documentation for default samples count --- ...dd-stored-procedure-columns-to-events.yaml | 28 +++++++++++++++++++ receiver/sqlserverreceiver/README.md | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 .chloggen/add-stored-procedure-columns-to-events.yaml 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..b24371d6c0c98 --- /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: adding 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. + Expanded default samples count from 200 to 250 to account for teh addition of stored procedure events. + +# 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..791308fc5d1cf 100644 --- a/receiver/sqlserverreceiver/README.md +++ b/receiver/sqlserverreceiver/README.md @@ -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`. From 135c98803642651e35fb9e5b75bcc6b0474c6012 Mon Sep 17 00:00:00 2001 From: cjk Date: Thu, 22 Jan 2026 10:38:06 +0000 Subject: [PATCH 37/43] Revert "Add stored procedure columns to events (#1)" This reverts commit 75b17b23bf89526233620c4da9390acb51e2cf65. --- receiver/sqlserverreceiver/documentation.md | 4 -- receiver/sqlserverreceiver/factory.go | 2 +- receiver/sqlserverreceiver/factory_test.go | 2 +- .../internal/metadata/generated_logs.go | 16 +++--- .../internal/metadata/generated_logs_test.go | 16 +----- receiver/sqlserverreceiver/metadata.yaml | 13 +---- receiver/sqlserverreceiver/scraper.go | 53 +++++++------------ receiver/sqlserverreceiver/scraper_test.go | 42 +++++++-------- .../templates/dbQueryAndTextQuery.tmpl | 10 +--- .../templates/sqlServerQuerySample.tmpl | 7 +-- .../databaseTopQueryWithoutInstanceName.txt | 10 +--- .../expectedQueryTextAndPlanQuery.yaml | 8 +-- .../expectedRecordDatabaseSampleQuery.yaml | 6 --- ...ordDatabaseSampleQueryWithInvalidData.yaml | 6 --- .../testdata/queryTextAndPlanQueryData.txt | 4 +- .../queryTextAndPlanQueryInvalidData.txt | 4 +- .../recordDatabaseSampleQueryData.txt | 4 +- .../recordInvalidDatabaseSampleQueryData.txt | 6 +-- .../testdata/testQuerySampleQuery.txt | 7 +-- 19 files changed, 59 insertions(+), 161 deletions(-) diff --git a/receiver/sqlserverreceiver/documentation.md b/receiver/sqlserverreceiver/documentation.md index 55fb14a46e8ae..a018477cf1617 100644 --- a/receiver/sqlserverreceiver/documentation.md +++ b/receiver/sqlserverreceiver/documentation.md @@ -606,8 +606,6 @@ 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 @@ -632,8 +630,6 @@ 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 faa73392b8cff..e2079934fc7a9 100644 --- a/receiver/sqlserverreceiver/factory.go +++ b/receiver/sqlserverreceiver/factory.go @@ -57,7 +57,7 @@ func createDefaultConfig() component.Config { }, TopQueryCollection: TopQueryCollection{ MaxQuerySampleCount: 1000, - TopQueryCount: 250, + TopQueryCount: 200, CollectionInterval: time.Minute, }, } diff --git a/receiver/sqlserverreceiver/factory_test.go b/receiver/sqlserverreceiver/factory_test.go index 228d9b8236430..27300a46fe0f3 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: 250, + TopQueryCount: 200, CollectionInterval: time.Minute, }, QuerySample: QuerySample{ diff --git a/receiver/sqlserverreceiver/internal/metadata/generated_logs.go b/receiver/sqlserverreceiver/internal/metadata/generated_logs.go index 0d7489892146a..2224f758a2990 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, sqlserverProcedureIDAttributeValue string, sqlserverProcedureNameAttributeValue 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) { if !e.config.Enabled { return } @@ -63,8 +63,6 @@ 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) } @@ -88,7 +86,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, sqlserverProcedureIDAttributeValue string, sqlserverProcedureNameAttributeValue 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) { if !e.config.Enabled { return } @@ -115,8 +113,6 @@ 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) } @@ -288,11 +284,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, 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) +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) } // 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, 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) +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) } diff --git a/receiver/sqlserverreceiver/internal/metadata/generated_logs_test.go b/receiver/sqlserverreceiver/internal/metadata/generated_logs_test.go index 7038dc4bf960c..53531d2d36903 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", "sqlserver.procedure_id-val", "sqlserver.procedure_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") 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", "sqlserver.procedure_id-val", "sqlserver.procedure_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") rb := lb.NewResourceBuilder() rb.SetHostName("host.name-val") @@ -276,12 +276,6 @@ 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 @@ -334,12 +328,6 @@ 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 90131ae0f091b..3b1caab551324 100644 --- a/receiver/sqlserverreceiver/metadata.yaml +++ b/receiver/sqlserverreceiver/metadata.yaml @@ -1,5 +1,5 @@ type: sqlserver -#generated_package_name: sqlserverreceiver + status: class: receiver stability: @@ -133,13 +133,6 @@ attributes: sqlserver.percent_complete: description: Percentage of work completed. type: double - # Stored Procedures - sqlserver.procedure_id: - description: The SQLServer 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 @@ -269,8 +262,6 @@ events: - sqlserver.wait_type - sqlserver.writes - user.name - - sqlserver.procedure_id - - sqlserver.procedure_name db.server.top_query: enabled: false @@ -291,8 +282,6 @@ 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 c37320f1c9ec6..ea3d689138bbe 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) + resources, err = s.recordDatabaseQueryTextAndPlan(ctx, s.config.TopQueryCount) 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) (pcommon.Resource, error) { +func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Context, topQueryCount uint) (pcommon.Resource, error) { // Constants are the column names of the database status const ( executionCount = "execution_count" @@ -638,10 +638,6 @@ 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() @@ -664,23 +660,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] // defaulted to '0' if not present elapsedTimeMicrosecond, err := strconv.ParseInt(row[totalElapsedTime], 10, 64) if err != nil { - s.logger.Warn(fmt.Sprintf("sqlServerScraperHelper failed getting rows: %s", err)) + s.logger.Info(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, procID, totalElapsedTime, elapsedTimeMicrosecond); cached && diff > 0 { + if cached, diff := s.cacheAndDiff(queryHashVal, queryPlanHashVal, 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, s.config.TopQueryCount) + rows = sortRows(rows, totalElapsedTimeDiffsMicrosecond, topQueryCount) // sort the totalElapsedTimeDiffs in descending order as well sort.Slice(totalElapsedTimeDiffsMicrosecond, func(i, j int) bool { return totalElapsedTimeDiffsMicrosecond[i] > totalElapsedTimeDiffsMicrosecond[j] }) @@ -693,7 +689,6 @@ 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] @@ -706,28 +701,26 @@ 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, procID, executionCount, executionCountVal.(int64)) + cached, executionCountVal := s.cacheAndDiff(queryHashVal, queryPlanHashVal, executionCount, executionCountVal.(int64)) if !cached { executionCountVal = int64(0) } logicalReadsVal := s.retrieveValue(row, logicalReads, &errs, retrieveInt) - cached, logicalReadsVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, procID, logicalReads, logicalReadsVal.(int64)) + cached, logicalReadsVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, logicalReads, logicalReadsVal.(int64)) if !cached { logicalReadsVal = int64(0) } logicalWritesVal := s.retrieveValue(row, logicalWrites, &errs, retrieveInt) - cached, logicalWritesVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, procID, logicalWrites, logicalWritesVal.(int64)) + cached, logicalWritesVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, logicalWrites, logicalWritesVal.(int64)) if !cached { logicalWritesVal = int64(0) } physicalReadsVal := s.retrieveValue(row, physicalReads, &errs, retrieveInt) - cached, physicalReadsVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, procID, physicalReads, physicalReadsVal.(int64)) + cached, physicalReadsVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, physicalReads, physicalReadsVal.(int64)) if !cached { physicalReadsVal = int64(0) } @@ -737,19 +730,19 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont }) rowsReturnedVal := s.retrieveValue(row, rowsReturned, &errs, retrieveInt) - cached, rowsReturnedVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, procID, rowsReturned, rowsReturnedVal.(int64)) + cached, rowsReturnedVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, rowsReturned, rowsReturnedVal.(int64)) if !cached { rowsReturnedVal = int64(0) } totalGrantVal := s.retrieveValue(row, totalGrant, &errs, retrieveInt) - cached, totalGrantVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, procID, totalGrant, totalGrantVal.(int64)) + cached, totalGrantVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, totalGrant, totalGrantVal.(int64)) if !cached { totalGrantVal = int64(0) } totalWorkerTimeVal := s.retrieveValue(row, totalWorkerTime, &errs, retrieveInt) - cached, totalWorkerTimeVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, procID, totalWorkerTime, totalWorkerTimeVal.(int64)) + cached, totalWorkerTimeVal = s.cacheAndDiff(queryHashVal, queryPlanHashVal, totalWorkerTime, totalWorkerTimeVal.(int64)) totalWorkerTimeInSecVal := float64(0) if cached { totalWorkerTimeInSecVal = float64(totalWorkerTimeVal.(int64)) / 1_000_000 @@ -788,10 +781,7 @@ func (s *sqlServerScraperHelper) recordDatabaseQueryTextAndPlan(ctx context.Cont totalGrantVal.(int64), s.config.Server, int64(s.config.Port), - dbSystemNameVal, - row[storedProcedureID], - row[storedProcedureName], - ) + dbSystemNameVal) } return resources, errors.Join(errs...) } @@ -814,15 +804,13 @@ 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, procedureID, column string, val int64) (bool, int64) { +func (s *sqlServerScraperHelper) cacheAndDiff(queryHash, queryPlanHash, 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 { @@ -832,6 +820,7 @@ func (s *sqlServerScraperHelper) cacheAndDiff(queryHash, queryPlanHash, procedur if val > cached { return true, val - cached } + return true, 0 } @@ -939,9 +928,6 @@ 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, @@ -1035,9 +1021,7 @@ 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, @@ -1053,7 +1037,6 @@ 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 8b80d467fb928..1ec36f87e77fc 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", "procedure_id", "column", -1) + cached, val := scraper.cacheAndDiff("query_hash", "query_plan_hash", "column", -1) assert.False(t, cached) assert.Equal(t, int64(0), val) - cached, val = scraper.cacheAndDiff("query_hash", "query_plan_hash", "procedure_id", "column", 1) + cached, val = scraper.cacheAndDiff("query_hash", "query_plan_hash", "column", 1) assert.False(t, cached) assert.Equal(t, int64(1), val) - cached, val = scraper.cacheAndDiff("query_hash", "query_plan_hash", "procedure_id", "column", 1) + cached, val = scraper.cacheAndDiff("query_hash", "query_plan_hash", "column", 1) assert.True(t, cached) assert.Equal(t, int64(0), val) - cached, val = scraper.cacheAndDiff("query_hash", "query_plan_hash", "procedure_id", "column", 3) + cached, val = scraper.cacheAndDiff("query_hash", "query_plan_hash", "column", 3) assert.True(t, cached) assert.Equal(t, int64(2), val) } @@ -476,15 +476,14 @@ func TestQueryTextAndPlanQuery(t *testing.T) { queryHash := hex.EncodeToString([]byte("0x37849E874171E3F3")) queryPlanHash := hex.EncodeToString([]byte("0xD3112909429A1B50")) - 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.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) scraper.client = mockClient{ instanceName: scraper.config.InstanceName, @@ -536,15 +535,14 @@ func TestInvalidQueryTextAndPlanQuery(t *testing.T) { queryHash := hex.EncodeToString([]byte("0x37849E874171E3F3")) queryPlanHash := hex.EncodeToString([]byte("0xD3112909429A1B50")) - 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.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) scraper.client = mockInvalidClient{ mockClient: mockClient{ diff --git a/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl b/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl index 7c0c129284a48..1369dca3f8763 100644 --- a/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl +++ b/receiver/sqlserverreceiver/templates/dbQueryAndTextQuery.tmpl @@ -2,7 +2,6 @@ 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, @@ -17,9 +16,7 @@ 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()) @@ -29,12 +26,7 @@ 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(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 + ISNULL(qp.query_plan, '') AS query_plan 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 diff --git a/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl b/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl index 5ff57fcee6d99..48cd195e4fad7 100644 --- a/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl +++ b/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl @@ -39,12 +39,7 @@ 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, - 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 + s.login_name AS username 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/databaseTopQueryWithoutInstanceName.txt b/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt index 7c0c129284a48..1369dca3f8763 100644 --- a/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt +++ b/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt @@ -2,7 +2,6 @@ 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, @@ -17,9 +16,7 @@ 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()) @@ -29,12 +26,7 @@ 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(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 + ISNULL(qp.query_plan, '') AS query_plan 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 diff --git a/receiver/sqlserverreceiver/testdata/expectedQueryTextAndPlanQuery.yaml b/receiver/sqlserverreceiver/testdata/expectedQueryTextAndPlanQuery.yaml index b68c276bed762..4042e9baab083 100644 --- a/receiver/sqlserverreceiver/testdata/expectedQueryTextAndPlanQuery.yaml +++ b/receiver/sqlserverreceiver/testdata/expectedQueryTextAndPlanQuery.yaml @@ -61,14 +61,8 @@ 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 b0babe6d17b09..d0924bd35b480 100644 --- a/receiver/sqlserverreceiver/testdata/expectedRecordDatabaseSampleQuery.yaml +++ b/receiver/sqlserverreceiver/testdata/expectedRecordDatabaseSampleQuery.yaml @@ -115,12 +115,6 @@ 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 c91eabef757bc..6a24c138b13c5 100644 --- a/receiver/sqlserverreceiver/testdata/expectedRecordDatabaseSampleQueryWithInvalidData.yaml +++ b/receiver/sqlserverreceiver/testdata/expectedRecordDatabaseSampleQueryWithInvalidData.yaml @@ -115,12 +115,6 @@ 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 7f7bf747a1c71..abd3e31b681f7 100644 --- a/receiver/sqlserverreceiver/testdata/queryTextAndPlanQueryData.txt +++ b/receiver/sqlserverreceiver/testdata/queryTextAndPlanQueryData.txt @@ -14,8 +14,6 @@ "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": "", - "procedure_id": "0", - "procedure_name": "" + "query_plan": "" } ] diff --git a/receiver/sqlserverreceiver/testdata/queryTextAndPlanQueryInvalidData.txt b/receiver/sqlserverreceiver/testdata/queryTextAndPlanQueryInvalidData.txt index 4fad7195dd197..da3925707bf19 100644 --- a/receiver/sqlserverreceiver/testdata/queryTextAndPlanQueryInvalidData.txt +++ b/receiver/sqlserverreceiver/testdata/queryTextAndPlanQueryInvalidData.txt @@ -14,8 +14,6 @@ "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 + s.login_name AS username 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 From 0712589dba7c041956f81033bcb4ffe74dea0ce3 Mon Sep 17 00:00:00 2001 From: cjk Date: Thu, 22 Jan 2026 11:16:13 +0000 Subject: [PATCH 38/43] Reapply "Add stored procedure columns to events (#1)" This reverts commit 135c98803642651e35fb9e5b75bcc6b0474c6012. --- receiver/sqlserverreceiver/documentation.md | 4 ++ receiver/sqlserverreceiver/factory.go | 2 +- receiver/sqlserverreceiver/factory_test.go | 2 +- .../internal/metadata/generated_logs.go | 16 +++--- .../internal/metadata/generated_logs_test.go | 16 +++++- receiver/sqlserverreceiver/metadata.yaml | 13 ++++- receiver/sqlserverreceiver/scraper.go | 53 ++++++++++++------- receiver/sqlserverreceiver/scraper_test.go | 42 ++++++++------- .../templates/dbQueryAndTextQuery.tmpl | 10 +++- .../templates/sqlServerQuerySample.tmpl | 7 ++- .../databaseTopQueryWithoutInstanceName.txt | 10 +++- .../expectedQueryTextAndPlanQuery.yaml | 8 ++- .../expectedRecordDatabaseSampleQuery.yaml | 6 +++ ...ordDatabaseSampleQueryWithInvalidData.yaml | 6 +++ .../testdata/queryTextAndPlanQueryData.txt | 4 +- .../queryTextAndPlanQueryInvalidData.txt | 4 +- .../recordDatabaseSampleQueryData.txt | 4 +- .../recordInvalidDatabaseSampleQueryData.txt | 6 ++- .../testdata/testQuerySampleQuery.txt | 7 ++- 19 files changed, 161 insertions(+), 59 deletions(-) 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..90131ae0f091b 100644 --- a/receiver/sqlserverreceiver/metadata.yaml +++ b/receiver/sqlserverreceiver/metadata.yaml @@ -1,5 +1,5 @@ type: sqlserver - +#generated_package_name: sqlserverreceiver status: class: receiver stability: @@ -133,6 +133,13 @@ attributes: sqlserver.percent_complete: description: Percentage of work completed. type: double + # Stored Procedures + sqlserver.procedure_id: + description: The SQLServer 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..c37320f1c9ec6 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] // defaulted 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 1369dca3f8763..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,7 +29,12 @@ 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 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/databaseTopQueryWithoutInstanceName.txt b/receiver/sqlserverreceiver/testdata/databaseTopQueryWithoutInstanceName.txt index 1369dca3f8763..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,7 +29,12 @@ 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 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 From 5b3bf23fac0d8199ce164c817fb3937cf2994863 Mon Sep 17 00:00:00 2001 From: cjk Date: Thu, 22 Jan 2026 11:30:41 +0000 Subject: [PATCH 39/43] removing not null from samples again --- receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl | 3 +-- receiver/sqlserverreceiver/testdata/testQuerySampleQuery.txt | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl b/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl index 2fbc90607539c..5ff57fcee6d99 100644 --- a/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl +++ b/receiver/sqlserverreceiver/templates/sqlServerQuerySample.tmpl @@ -48,5 +48,4 @@ SELECT TOP(@top) 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 -CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS o -WHERE st.text IS NOT NULL; \ No newline at end of file +CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS o; \ No newline at end of file diff --git a/receiver/sqlserverreceiver/testdata/testQuerySampleQuery.txt b/receiver/sqlserverreceiver/testdata/testQuerySampleQuery.txt index 2fbc90607539c..5ff57fcee6d99 100644 --- a/receiver/sqlserverreceiver/testdata/testQuerySampleQuery.txt +++ b/receiver/sqlserverreceiver/testdata/testQuerySampleQuery.txt @@ -48,5 +48,4 @@ SELECT TOP(@top) 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 -CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS o -WHERE st.text IS NOT NULL; \ No newline at end of file +CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS o; \ No newline at end of file From 961984b492c8976768df5ef0e64237dc5249322c Mon Sep 17 00:00:00 2001 From: cjk Date: Fri, 23 Jan 2026 12:00:24 +0000 Subject: [PATCH 40/43] Updating documentation --- .chloggen/add-stored-procedure-columns-to-events.yaml | 2 +- receiver/sqlserverreceiver/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.chloggen/add-stored-procedure-columns-to-events.yaml b/.chloggen/add-stored-procedure-columns-to-events.yaml index b24371d6c0c98..f643b6d439db2 100644 --- a/.chloggen/add-stored-procedure-columns-to-events.yaml +++ b/.chloggen/add-stored-procedure-columns-to-events.yaml @@ -16,7 +16,7 @@ issues: [44656] # 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. - Expanded default samples count from 200 to 250 to account for teh addition of stored procedure events. + 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. diff --git a/receiver/sqlserverreceiver/README.md b/receiver/sqlserverreceiver/README.md index 791308fc5d1cf..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. From ed1e63b481b848a4840d76996e74e6ad9a032c6f Mon Sep 17 00:00:00 2001 From: cjk Date: Tue, 27 Jan 2026 10:56:25 +0000 Subject: [PATCH 41/43] Updates made per PR feedback. --- .chloggen/add-stored-procedure-columns-to-events.yaml | 2 +- receiver/sqlserverreceiver/metadata.yaml | 4 ++-- receiver/sqlserverreceiver/scraper.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.chloggen/add-stored-procedure-columns-to-events.yaml b/.chloggen/add-stored-procedure-columns-to-events.yaml index f643b6d439db2..60a138e7d2a9d 100644 --- a/.chloggen/add-stored-procedure-columns-to-events.yaml +++ b/.chloggen/add-stored-procedure-columns-to-events.yaml @@ -7,7 +7,7 @@ change_type: enhancement component: receiver/sqlserver # A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). -note: adding sqlserver.procedure_id and sqlserver.procedure_name attributes to TopQuery and Sample Events +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] diff --git a/receiver/sqlserverreceiver/metadata.yaml b/receiver/sqlserverreceiver/metadata.yaml index 90131ae0f091b..aa686916b964d 100644 --- a/receiver/sqlserverreceiver/metadata.yaml +++ b/receiver/sqlserverreceiver/metadata.yaml @@ -1,5 +1,5 @@ type: sqlserver -#generated_package_name: sqlserverreceiver + status: class: receiver stability: @@ -135,7 +135,7 @@ attributes: type: double # Stored Procedures sqlserver.procedure_id: - description: The SQLServer ID of the stored procedure, if any + 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 diff --git a/receiver/sqlserverreceiver/scraper.go b/receiver/sqlserverreceiver/scraper.go index c37320f1c9ec6..9632af991c14d 100644 --- a/receiver/sqlserverreceiver/scraper.go +++ b/receiver/sqlserverreceiver/scraper.go @@ -664,7 +664,7 @@ 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] // defaulted to '0' if not present + procID := row[storedProcedureID] // defaults to '0' if not present elapsedTimeMicrosecond, err := strconv.ParseInt(row[totalElapsedTime], 10, 64) if err != nil { From 4057f5255b42f0873913ace997e4af3d1d50cd23 Mon Sep 17 00:00:00 2001 From: cjk Date: Tue, 27 Jan 2026 11:07:26 +0000 Subject: [PATCH 42/43] Removing unused comment --- receiver/sqlserverreceiver/metadata.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/receiver/sqlserverreceiver/metadata.yaml b/receiver/sqlserverreceiver/metadata.yaml index 52a4219783ffd..aa686916b964d 100644 --- a/receiver/sqlserverreceiver/metadata.yaml +++ b/receiver/sqlserverreceiver/metadata.yaml @@ -1,5 +1,5 @@ type: sqlserver -#generated_package_name: sqlserverreceiver + status: class: receiver stability: From f08ed4be71f5294cb0138e634009f244c0909d57 Mon Sep 17 00:00:00 2001 From: cjk Date: Fri, 30 Jan 2026 15:13:14 +0000 Subject: [PATCH 43/43] updated autogen docs --- receiver/sqlserverreceiver/documentation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/receiver/sqlserverreceiver/documentation.md b/receiver/sqlserverreceiver/documentation.md index 55fb14a46e8ae..1ff0a6ddc34f1 100644 --- a/receiver/sqlserverreceiver/documentation.md +++ b/receiver/sqlserverreceiver/documentation.md @@ -606,7 +606,7 @@ 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_id | The SQL Server 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 @@ -632,7 +632,7 @@ 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_id | The SQL Server ID of the stored procedure, if any | Any Str | | sqlserver.procedure_name | The name of the stored procedure, if any | Any Str | ## Resource Attributes