diff --git a/receiver/mysqlreceiver/client.go b/receiver/mysqlreceiver/client.go index 7ad7a4e14ef8..114080185936 100644 --- a/receiver/mysqlreceiver/client.go +++ b/receiver/mysqlreceiver/client.go @@ -5,6 +5,7 @@ package mysqlreceiver // import "github.com/open-telemetry/opentelemetry-collect import ( "database/sql" + "errors" "fmt" "regexp" "strconv" @@ -219,16 +220,26 @@ func (c *mySQLClient) getInnodbStats() (map[string]string, error) { } func ExtractInnodbTotalLargeMemoryAllocated(statusText string) (int64, error) { - re := regexp.MustCompile(`Total large memory allocated (\d+)`) + // fmt.Println(statusText) + re := regexp.MustCompile(`Total large memory allocated (-?\d+)`) matches := re.FindStringSubmatch(statusText) + fmt.Println("matches: ", matches) if len(matches) < 2 { - return 0, fmt.Errorf("could not find 'Total large memory allocated' in the status output") + return -1, fmt.Errorf("could not find 'Total large memory allocated' in the status output") } - totalMemoryAllocated, err := strconv.Atoi(matches[1]) + totalLargeMemoryAllocated, err := strconv.Atoi(matches[1]) if err != nil { - return 0, fmt.Errorf("failed to convert 'Total large memory allocated' value to int: %v", err) + return -1, fmt.Errorf("failed to convert 'Total large memory allocated' value to int: %v", err) } - return int64(totalMemoryAllocated), nil + const systemTotalMemory int64 = 1 << 40 // 1 TB of memory. + + if int64(totalLargeMemoryAllocated) < 0 { + return -1, errors.New("invalid memory allocation: 'Total Large Memory Allocated' value is negative, which is not possible") + } else if int64(totalLargeMemoryAllocated) > systemTotalMemory { + return -1, fmt.Errorf("invalid memory allocation: 'Total Large Memory Allocated' value exceeds the system's total memory capacity of %d bytes", systemTotalMemory) + } + + return int64(totalLargeMemoryAllocated), nil } func (c *mySQLClient) getInnodbStatus() (int64, error) { diff --git a/receiver/mysqlreceiver/scraper.go b/receiver/mysqlreceiver/scraper.go index e062477b67e5..228409cd0882 100644 --- a/receiver/mysqlreceiver/scraper.go +++ b/receiver/mysqlreceiver/scraper.go @@ -118,6 +118,9 @@ func (m *mySQLScraper) scrapeInnodbStatus(now pcommon.Timestamp, errs *scraperer errs.Add(err) } m.mb.RecordMysqlInnodbMemTotalDataPoint(now, int64(totalLargeMemoryAllocated)) + // rb := m.mb.NewResourceBuilder() + // rb.SetMysqlInstanceEndpoint(m.config.Endpoint) + // m.mb.EmitForResource(metadata.WithResource(rb.Emit())) } func (m *mySQLScraper) scrapeGlobalStats(now pcommon.Timestamp, errs *scrapererror.ScrapeErrors) { diff --git a/receiver/mysqlreceiver/scraper_test.go b/receiver/mysqlreceiver/scraper_test.go index 6fe3a181d3b5..7e9cf4e9e1ba 100644 --- a/receiver/mysqlreceiver/scraper_test.go +++ b/receiver/mysqlreceiver/scraper_test.go @@ -8,6 +8,7 @@ import ( "context" "database/sql" "errors" + "fmt" "os" "path/filepath" "strings" @@ -122,9 +123,42 @@ func TestScrape(t *testing.T) { require.True(t, errors.As(scrapeErr, &partialError), "returned error was not PartialScrapeError") // 5 comes from 4 failed "must-have" metrics that aren't present, // and the other failure comes from a row that fails to parse as a number + fmt.Println("Failed partial errors ", partialError.Failed) require.Equal(t, partialError.Failed, 5, "Expected partial error count to be 5") }) + t.Run("scrape is getting corrupted value", func(t *testing.T) { + cfg := createDefaultConfig().(*Config) + cfg.Username = "otel" + cfg.Password = "otel" + cfg.NetAddr = confignet.NetAddr{Endpoint: "localhost:3306"} + + cfg.MetricsBuilderConfig.Metrics.MysqlInnodbMemTotal.Enabled = true + + scraper := newMySQLScraper(receivertest.NewNopCreateSettings(), cfg) + scraper.sqlclient = &mockClient{ + innodbStatusFile: "innodb_status_corrupted", + } + + actualMetrics, scrapeErr := scraper.scrape(context.Background()) + require.Error(t, scrapeErr) + fmt.Print("actual error -----------", scrapeErr) + + expectedFile := filepath.Join("testdata", "scraper", "expected_corrupted_innodb_mem-total.yaml") + expectedMetrics, err := golden.ReadMetrics(expectedFile) + fmt.Print("\nexpected error ---------", err) + + require.NoError(t, err) + assert.NoError(t, pmetrictest.CompareMetrics(actualMetrics, expectedMetrics, + pmetrictest.IgnoreMetricDataPointsOrder(), pmetrictest.IgnoreStartTimestamp(), + pmetrictest.IgnoreTimestamp(), + )) + + var corruptedError scrapererror.PartialScrapeError + require.True(t, errors.As(scrapeErr, &corruptedError), "returned error was not PartialScrapeError") + require.Equal(t, corruptedError.Failed, 98, "Expected corrupted error count to be 98") + }) + } var _ client = (*mockClient)(nil) @@ -146,17 +180,25 @@ func (c *mockClient) getInnodbStatus() (int64, error) { if err != nil { return -1, err } - - totalLargeMemoryAllocate, err := ExtractInnodbTotalLargeMemoryAllocated(innodbStatus) + fmt.Println("Scrapping mock file----------------------------------------------------") + totalLargeMemoryAllocated, err := ExtractInnodbTotalLargeMemoryAllocated(innodbStatus) + const systemTotalMemory int64 = 1 << 40 // 1 TB of memory. if err != nil { return -1, err } + if totalLargeMemoryAllocated < 0 { + return -1, errors.New("invalid memory allocation: 'Total Large Memory Allocated' value is negative, which is not possible") + } else if totalLargeMemoryAllocated > systemTotalMemory { + return -1, fmt.Errorf("invalid memory allocation: 'Total Large Memory Allocated' value exceeds the system's total memory capacity of %d bytes", systemTotalMemory) + } - return totalLargeMemoryAllocate, nil + fmt.Println("Total Large mem allocated: ", totalLargeMemoryAllocated) + return totalLargeMemoryAllocated, nil } func readFileToString(fname string) (string, error) { content, err := os.ReadFile(filepath.Join("testdata", "scraper", fname+".txt")) + fmt.Println("file being scrapped is :", fname) if err != nil { return "", err } diff --git a/receiver/mysqlreceiver/testdata/scraper/expected_corrupted_innodb_mem-total.yaml b/receiver/mysqlreceiver/testdata/scraper/expected_corrupted_innodb_mem-total.yaml new file mode 100644 index 000000000000..d0c773908630 --- /dev/null +++ b/receiver/mysqlreceiver/testdata/scraper/expected_corrupted_innodb_mem-total.yaml @@ -0,0 +1,21 @@ +resourceMetrics: + - resource: + attributes: + - key: mysql.instance.endpoint + value: + stringValue: localhost:3306 + scopeMetrics: + - metrics: + - description: Total memory used by InnoDB, as shown in the BUFFER POOL AND MEMORY section of SHOW ENGINE INNODB STATUS. + name: mysql.innodb.mem_total + gauge: + dataPoints: + - asInt: "-1" + startTimeUnixNano: "1000000" + timeUnixNano: "2000000" + unit: By + scope: + name: otelcol/mysqlreceiver + version: latest + + \ No newline at end of file