Skip to content

Commit 4cf22c1

Browse files
committed
[reciver/sqlserver] Properly parse numbers to ints
1 parent 61f8c78 commit 4cf22c1

File tree

4 files changed

+105
-62
lines changed

4 files changed

+105
-62
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: bug_fix
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: receiver/sqlserver
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Properly parse numbers stored in scientific notation to integers
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [39124]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: []

receiver/sqlserverreceiver/scraper.go

Lines changed: 74 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ func (s *sqlServerScraperHelper) recordDatabaseIOMetrics(ctx context.Context) er
160160

161161
var errs []error
162162
now := pcommon.NewTimestampFromTime(time.Now())
163-
var val float64
163+
var val any
164164
for i, row := range rows {
165165
rb := s.mb.NewResourceBuilder()
166166
rb.SetSqlserverComputerName(row[computerNameKey])
@@ -169,20 +169,20 @@ func (s *sqlServerScraperHelper) recordDatabaseIOMetrics(ctx context.Context) er
169169
rb.SetServerAddress(s.config.Server)
170170
rb.SetServerPort(int64(s.config.Port))
171171

172-
val, err = strconv.ParseFloat(row[readLatencyMsKey], 64)
172+
val, err = retrieveFloat(row, readLatencyMsKey)
173173
if err != nil {
174174
err = fmt.Errorf("row %d: %w", i, err)
175175
errs = append(errs, err)
176176
} else {
177-
s.mb.RecordSqlserverDatabaseLatencyDataPoint(now, val/1e3, row[physicalFilenameKey], row[logicalFilenameKey], row[fileTypeKey], metadata.AttributeDirectionRead)
177+
s.mb.RecordSqlserverDatabaseLatencyDataPoint(now, val.(float64)/1e3, row[physicalFilenameKey], row[logicalFilenameKey], row[fileTypeKey], metadata.AttributeDirectionRead)
178178
}
179179

180-
val, err = strconv.ParseFloat(row[writeLatencyMsKey], 64)
180+
val, err = retrieveFloat(row, writeLatencyMsKey)
181181
if err != nil {
182182
err = fmt.Errorf("row %d: %w", i, err)
183183
errs = append(errs, err)
184184
} else {
185-
s.mb.RecordSqlserverDatabaseLatencyDataPoint(now, val/1e3, row[physicalFilenameKey], row[logicalFilenameKey], row[fileTypeKey], metadata.AttributeDirectionWrite)
185+
s.mb.RecordSqlserverDatabaseLatencyDataPoint(now, val.(float64)/1e3, row[physicalFilenameKey], row[logicalFilenameKey], row[fileTypeKey], metadata.AttributeDirectionWrite)
186186
}
187187

188188
errs = append(errs, s.mb.RecordSqlserverDatabaseOperationsDataPoint(now, row[readCountKey], row[physicalFilenameKey], row[logicalFilenameKey], row[fileTypeKey], metadata.AttributeDirectionRead))
@@ -253,210 +253,210 @@ func (s *sqlServerScraperHelper) recordDatabasePerfCounterMetrics(ctx context.Co
253253

254254
switch row[counterKey] {
255255
case activeTempTables:
256-
val, err := strconv.ParseInt(row[valueKey], 10, 64)
256+
val, err := retrieveInt(row, valueKey)
257257
if err != nil {
258258
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, activeTempTables)
259259
errs = append(errs, err)
260260
} else {
261-
s.mb.RecordSqlserverTableCountDataPoint(now, val, metadata.AttributeTableStateActive, metadata.AttributeTableStatusTemporary)
261+
s.mb.RecordSqlserverTableCountDataPoint(now, val.(int64), metadata.AttributeTableStateActive, metadata.AttributeTableStatusTemporary)
262262
}
263263
case backupRestoreThroughputPerSec:
264-
val, err := strconv.ParseFloat(row[valueKey], 64)
264+
val, err := retrieveFloat(row, valueKey)
265265
if err != nil {
266266
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, backupRestoreThroughputPerSec)
267267
errs = append(errs, err)
268268
} else {
269-
s.mb.RecordSqlserverDatabaseBackupOrRestoreRateDataPoint(now, val)
269+
s.mb.RecordSqlserverDatabaseBackupOrRestoreRateDataPoint(now, val.(float64))
270270
}
271271
case batchRequestRate:
272-
val, err := strconv.ParseFloat(row[valueKey], 64)
272+
val, err := retrieveFloat(row, valueKey)
273273
if err != nil {
274274
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, batchRequestRate)
275275
errs = append(errs, err)
276276
} else {
277-
s.mb.RecordSqlserverBatchRequestRateDataPoint(now, val)
277+
s.mb.RecordSqlserverBatchRequestRateDataPoint(now, val.(float64))
278278
}
279279
case bufferCacheHitRatio:
280-
val, err := strconv.ParseFloat(row[valueKey], 64)
280+
val, err := retrieveFloat(row, valueKey)
281281
if err != nil {
282282
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, bufferCacheHitRatio)
283283
errs = append(errs, err)
284284
} else {
285-
s.mb.RecordSqlserverPageBufferCacheHitRatioDataPoint(now, val)
285+
s.mb.RecordSqlserverPageBufferCacheHitRatioDataPoint(now, val.(float64))
286286
}
287287
case bytesReceivedFromReplicaPerSec:
288-
val, err := strconv.ParseFloat(row[valueKey], 64)
288+
val, err := retrieveFloat(row, valueKey)
289289
if err != nil {
290290
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, bytesReceivedFromReplicaPerSec)
291291
errs = append(errs, err)
292292
} else {
293-
s.mb.RecordSqlserverReplicaDataRateDataPoint(now, val, metadata.AttributeReplicaDirectionReceive)
293+
s.mb.RecordSqlserverReplicaDataRateDataPoint(now, val.(float64), metadata.AttributeReplicaDirectionReceive)
294294
}
295295
case bytesSentForReplicaPerSec:
296-
val, err := strconv.ParseFloat(row[valueKey], 64)
296+
val, err := retrieveFloat(row, valueKey)
297297
if err != nil {
298298
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, bytesReceivedFromReplicaPerSec)
299299
errs = append(errs, err)
300300
} else {
301-
s.mb.RecordSqlserverReplicaDataRateDataPoint(now, val, metadata.AttributeReplicaDirectionTransmit)
301+
s.mb.RecordSqlserverReplicaDataRateDataPoint(now, val.(float64), metadata.AttributeReplicaDirectionTransmit)
302302
}
303303
case diskReadIOThrottled:
304304
errs = append(errs, s.mb.RecordSqlserverResourcePoolDiskThrottledReadRateDataPoint(now, row[valueKey]))
305305
case diskWriteIOThrottled:
306306
errs = append(errs, s.mb.RecordSqlserverResourcePoolDiskThrottledWriteRateDataPoint(now, row[valueKey]))
307307
case executionErrors:
308-
val, err := strconv.ParseInt(row[valueKey], 10, 64)
308+
val, err := retrieveInt(row, valueKey)
309309
if err != nil {
310310
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, executionErrors)
311311
errs = append(errs, err)
312312
} else {
313-
s.mb.RecordSqlserverDatabaseExecutionErrorsDataPoint(now, val)
313+
s.mb.RecordSqlserverDatabaseExecutionErrorsDataPoint(now, val.(int64))
314314
}
315315
case freeListStalls:
316-
val, err := strconv.ParseInt(row[valueKey], 10, 64)
316+
val, err := retrieveInt(row, valueKey)
317317
if err != nil {
318318
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, freeListStalls)
319319
errs = append(errs, err)
320320
} else {
321-
s.mb.RecordSqlserverPageBufferCacheFreeListStallsRateDataPoint(now, val)
321+
s.mb.RecordSqlserverPageBufferCacheFreeListStallsRateDataPoint(now, val.(int64))
322322
}
323323
case fullScansPerSec:
324-
val, err := strconv.ParseFloat(row[valueKey], 64)
324+
val, err := retrieveFloat(row, valueKey)
325325
if err != nil {
326326
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, fullScansPerSec)
327327
errs = append(errs, err)
328328
} else {
329-
s.mb.RecordSqlserverDatabaseFullScanRateDataPoint(now, val)
329+
s.mb.RecordSqlserverDatabaseFullScanRateDataPoint(now, val.(float64))
330330
}
331331
case freeSpaceInTempdb:
332-
val, err := strconv.ParseInt(row[valueKey], 10, 64)
332+
val, err := retrieveInt(row, valueKey)
333333
if err != nil {
334334
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, freeSpaceInTempdb)
335335
errs = append(errs, err)
336336
} else {
337-
s.mb.RecordSqlserverDatabaseTempdbSpaceDataPoint(now, val, metadata.AttributeTempdbStateFree)
337+
s.mb.RecordSqlserverDatabaseTempdbSpaceDataPoint(now, val.(int64), metadata.AttributeTempdbStateFree)
338338
}
339339
case indexSearchesPerSec:
340-
val, err := strconv.ParseFloat(row[valueKey], 64)
340+
val, err := retrieveFloat(row, valueKey)
341341
if err != nil {
342342
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, indexSearchesPerSec)
343343
errs = append(errs, err)
344344
} else {
345-
s.mb.RecordSqlserverIndexSearchRateDataPoint(now, val)
345+
s.mb.RecordSqlserverIndexSearchRateDataPoint(now, val.(float64))
346346
}
347347
case lockTimeoutsPerSec:
348-
val, err := strconv.ParseFloat(row[valueKey], 64)
348+
val, err := retrieveFloat(row, valueKey)
349349
if err != nil {
350350
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, lockTimeoutsPerSec)
351351
errs = append(errs, err)
352352
} else {
353-
s.mb.RecordSqlserverLockTimeoutRateDataPoint(now, val)
353+
s.mb.RecordSqlserverLockTimeoutRateDataPoint(now, val.(float64))
354354
}
355355
case lockWaits:
356-
val, err := strconv.ParseFloat(row[valueKey], 64)
356+
val, err := retrieveFloat(row, valueKey)
357357
if err != nil {
358358
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, lockWaits)
359359
errs = append(errs, err)
360360
} else {
361-
s.mb.RecordSqlserverLockWaitRateDataPoint(now, val)
361+
s.mb.RecordSqlserverLockWaitRateDataPoint(now, val.(float64))
362362
}
363363
case loginsPerSec:
364-
val, err := strconv.ParseFloat(row[valueKey], 64)
364+
val, err := retrieveFloat(row, valueKey)
365365
if err != nil {
366366
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, loginsPerSec)
367367
errs = append(errs, err)
368368
} else {
369-
s.mb.RecordSqlserverLoginRateDataPoint(now, val)
369+
s.mb.RecordSqlserverLoginRateDataPoint(now, val.(float64))
370370
}
371371
case logoutPerSec:
372-
val, err := strconv.ParseFloat(row[valueKey], 64)
372+
val, err := retrieveFloat(row, valueKey)
373373
if err != nil {
374374
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, logoutPerSec)
375375
errs = append(errs, err)
376376
} else {
377-
s.mb.RecordSqlserverLogoutRateDataPoint(now, val)
377+
s.mb.RecordSqlserverLogoutRateDataPoint(now, val.(float64))
378378
}
379379
case memoryGrantsPending:
380-
val, err := strconv.ParseInt(row[valueKey], 10, 64)
380+
val, err := retrieveInt(row, valueKey)
381381
if err != nil {
382382
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, memoryGrantsPending)
383383
errs = append(errs, err)
384384
} else {
385-
s.mb.RecordSqlserverMemoryGrantsPendingCountDataPoint(now, val)
385+
s.mb.RecordSqlserverMemoryGrantsPendingCountDataPoint(now, val.(int64))
386386
}
387387
case mirrorWritesTransactionPerSec:
388-
val, err := strconv.ParseFloat(row[valueKey], 64)
388+
val, err := retrieveFloat(row, valueKey)
389389
if err != nil {
390390
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, mirrorWritesTransactionPerSec)
391391
errs = append(errs, err)
392392
} else {
393-
s.mb.RecordSqlserverTransactionMirrorWriteRateDataPoint(now, val)
393+
s.mb.RecordSqlserverTransactionMirrorWriteRateDataPoint(now, val.(float64))
394394
}
395395
case numberOfDeadlocksPerSec:
396-
val, err := strconv.ParseFloat(row[valueKey], 64)
396+
val, err := retrieveFloat(row, valueKey)
397397
if err != nil {
398398
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, numberOfDeadlocksPerSec)
399399
errs = append(errs, err)
400400
} else {
401-
s.mb.RecordSqlserverDeadlockRateDataPoint(now, val)
401+
s.mb.RecordSqlserverDeadlockRateDataPoint(now, val.(float64))
402402
}
403403
case pageLookupsPerSec:
404-
val, err := strconv.ParseFloat(row[valueKey], 64)
404+
val, err := retrieveFloat(row, valueKey)
405405
if err != nil {
406406
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, pageLookupsPerSec)
407407
errs = append(errs, err)
408408
} else {
409-
s.mb.RecordSqlserverPageLookupRateDataPoint(now, val)
409+
s.mb.RecordSqlserverPageLookupRateDataPoint(now, val.(float64))
410410
}
411411
case processesBlocked:
412412
errs = append(errs, s.mb.RecordSqlserverProcessesBlockedDataPoint(now, row[valueKey]))
413413
case sqlCompilationRate:
414-
val, err := strconv.ParseFloat(row[valueKey], 64)
414+
val, err := retrieveFloat(row, valueKey)
415415
if err != nil {
416416
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, sqlCompilationRate)
417417
errs = append(errs, err)
418418
} else {
419-
s.mb.RecordSqlserverBatchSQLCompilationRateDataPoint(now, val)
419+
s.mb.RecordSqlserverBatchSQLCompilationRateDataPoint(now, val.(float64))
420420
}
421421
case sqlReCompilationsRate:
422-
val, err := strconv.ParseFloat(row[valueKey], 64)
422+
val, err := retrieveFloat(row, valueKey)
423423
if err != nil {
424424
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, sqlReCompilationsRate)
425425
errs = append(errs, err)
426426
} else {
427-
s.mb.RecordSqlserverBatchSQLRecompilationRateDataPoint(now, val)
427+
s.mb.RecordSqlserverBatchSQLRecompilationRateDataPoint(now, val.(float64))
428428
}
429429
case transactionDelay:
430-
val, err := strconv.ParseFloat(row[valueKey], 64)
430+
val, err := retrieveFloat(row, valueKey)
431431
if err != nil {
432432
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, transactionDelay)
433433
errs = append(errs, err)
434434
} else {
435-
s.mb.RecordSqlserverTransactionDelayDataPoint(now, val)
435+
s.mb.RecordSqlserverTransactionDelayDataPoint(now, val.(float64))
436436
}
437437
case userConnCount:
438-
val, err := strconv.ParseInt(row[valueKey], 10, 64)
438+
val, err := retrieveInt(row, valueKey)
439439
if err != nil {
440440
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, userConnCount)
441441
errs = append(errs, err)
442442
} else {
443-
s.mb.RecordSqlserverUserConnectionCountDataPoint(now, val)
443+
s.mb.RecordSqlserverUserConnectionCountDataPoint(now, val.(int64))
444444
}
445445
case usedMemory:
446-
val, err := strconv.ParseFloat(row[valueKey], 64)
446+
val, err := retrieveFloat(row, valueKey)
447447
if err != nil {
448448
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, usedMemory)
449449
errs = append(errs, err)
450450
} else {
451-
s.mb.RecordSqlserverMemoryUsageDataPoint(now, val)
451+
s.mb.RecordSqlserverMemoryUsageDataPoint(now, val.(float64))
452452
}
453453
case versionStoreSize:
454-
val, err := strconv.ParseFloat(row[valueKey], 64)
454+
val, err := retrieveFloat(row, valueKey)
455455
if err != nil {
456456
err = fmt.Errorf("failed to parse valueKey for row %d: %w in %s", i, err, versionStoreSize)
457457
errs = append(errs, err)
458458
} else {
459-
s.mb.RecordSqlserverDatabaseTempdbVersionStoreSizeDataPoint(now, val)
459+
s.mb.RecordSqlserverDatabaseTempdbVersionStoreSizeDataPoint(now, val.(float64))
460460
}
461461
}
462462

@@ -831,11 +831,25 @@ func vanillaRetriever(row sqlquery.StringMap, columnName string) (any, error) {
831831

832832
func retrieveInt(row sqlquery.StringMap, columnName string) (any, error) {
833833
var err error
834-
result := 0
834+
var result int64
835835
if row[columnName] != "" {
836-
result, err = strconv.Atoi(row[columnName])
836+
result, err = strconv.ParseInt(row[columnName], 10, 64)
837+
if err != nil {
838+
// SQL Server stores large integers in scientific e notation
839+
// (eg 123456 is stored as 1.23456e+5)
840+
// This value cannot be parsed by strconv.ParseInt, but is successfully
841+
// parsed by strconv.ParseFloat. The goal is here to convert to int
842+
// even if the stored value is in scientific e notation.
843+
var resultFloat float64
844+
resultFloat, err = strconv.ParseFloat(row[columnName], 64)
845+
if err == nil {
846+
result = int64(resultFloat)
847+
}
848+
}
849+
} else {
850+
err = fmt.Errorf("no value found for column %s", columnName)
837851
}
838-
return int64(result), err
852+
return result, err
839853
}
840854

841855
func retrieveIntAndConvert(convert func(int64) any) func(row sqlquery.StringMap, columnName string) (any, error) {
@@ -851,6 +865,8 @@ func retrieveFloat(row sqlquery.StringMap, columnName string) (any, error) {
851865
var result float64
852866
if row[columnName] != "" {
853867
result, err = strconv.ParseFloat(row[columnName], 64)
868+
} else {
869+
err = fmt.Errorf("no value found for column %s", columnName)
854870
}
855871
return result, err
856872
}

receiver/sqlserverreceiver/testdata/expectedPerfCounters.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ resourceMetrics:
3939
- description: Number of execution errors.
4040
gauge:
4141
dataPoints:
42-
- asInt: 1048
42+
- asInt: 18256656
4343
startTimeUnixNano: "1000000"
4444
timeUnixNano: "2000000"
4545
name: sqlserver.database.execution.errors
@@ -900,7 +900,7 @@ resourceMetrics:
900900
sum:
901901
aggregationTemporality: 2
902902
dataPoints:
903-
- asInt: 61824
903+
- asInt: 18256656
904904
attributes:
905905
- key: tempdb.state
906906
value:

receiver/sqlserverreceiver/testdata/perfCounterQueryData.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"object":"SQLServer:Access Methods",
2929
"sql_instance":"8cac97ac9b8f",
3030
"computer_name":"abcde",
31-
"value":"1048"
31+
"value":"1.8256656e+07"
3232
},
3333
{
3434
"counter":"Index Searches/sec",
@@ -2708,7 +2708,7 @@
27082708
"object":"SQLServer:Transactions",
27092709
"sql_instance":"8cac97ac9b8f",
27102710
"computer_name":"abcde",
2711-
"value":"61824"
2711+
"value":"1.8256656e+07"
27122712
},
27132713
{
27142714
"counter":"Version Store Size (KB)",

0 commit comments

Comments
 (0)