From 14fef6611abb133d5681251430a78a38cb45b174 Mon Sep 17 00:00:00 2001 From: Sreenath Date: Fri, 27 Jun 2025 09:23:08 +0100 Subject: [PATCH 01/51] [receiver/oracledb] events for oracledbreceiver - Adding top_query and query_sample collection --- ...eiver-top-n-queries-and-query-samples.yaml | 31 ++ receiver/oracledbreceiver/README.md | 4 +- receiver/oracledbreceiver/config.go | 36 +- receiver/oracledbreceiver/db_client.go | 6 +- receiver/oracledbreceiver/documentation.md | 82 ++++ receiver/oracledbreceiver/factory.go | 78 +++- receiver/oracledbreceiver/factory_test.go | 13 + receiver/oracledbreceiver/fake_db_client.go | 2 +- .../generated_component_test.go | 7 + receiver/oracledbreceiver/go.mod | 73 ++-- receiver/oracledbreceiver/go.sum | 171 +++++--- .../internal/metadata/generated_config.go | 60 +++ .../metadata/generated_config_test.go | 14 + .../internal/metadata/generated_logs.go | 259 ++++++++++++ .../internal/metadata/generated_logs_test.go | 310 ++++++++++++++ .../internal/metadata/generated_metrics.go | 6 + .../metadata/generated_metrics_test.go | 1 + .../internal/metadata/generated_resource.go | 7 + .../metadata/generated_resource_test.go | 12 +- .../internal/metadata/generated_status.go | 1 + .../internal/metadata/testdata/config.yaml | 30 ++ receiver/oracledbreceiver/metadata.yaml | 178 +++++++- receiver/oracledbreceiver/obfuscate.go | 40 ++ receiver/oracledbreceiver/obfuscate_test.go | 30 ++ receiver/oracledbreceiver/scraper.go | 390 +++++++++++++++++- receiver/oracledbreceiver/scraper_test.go | 234 +++++++++++ .../oracleQueryMetricsAndTextSql.tmpl | 24 ++ .../templates/oracleQueryPlanSql.tmpl | 16 + .../templates/oracleQuerySampleSql.tmpl | 30 ++ .../oracledbreceiver/testdata/config.yaml | 7 +- .../expectedQueryTextAndPlanQuery.yaml | 86 ++++ .../testdata/expectedSamplesFile.yaml | 83 ++++ .../testdata/oracleQueryMetricsData.txt | 1 + .../testdata/oracleQueryPlanData.txt | 1 + 34 files changed, 2217 insertions(+), 106 deletions(-) create mode 100644 .chloggen/oracledbreceiver-top-n-queries-and-query-samples.yaml create mode 100644 receiver/oracledbreceiver/internal/metadata/generated_logs.go create mode 100644 receiver/oracledbreceiver/internal/metadata/generated_logs_test.go create mode 100644 receiver/oracledbreceiver/obfuscate.go create mode 100644 receiver/oracledbreceiver/obfuscate_test.go create mode 100644 receiver/oracledbreceiver/templates/oracleQueryMetricsAndTextSql.tmpl create mode 100644 receiver/oracledbreceiver/templates/oracleQueryPlanSql.tmpl create mode 100644 receiver/oracledbreceiver/templates/oracleQuerySampleSql.tmpl create mode 100644 receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml create mode 100644 receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml create mode 100644 receiver/oracledbreceiver/testdata/oracleQueryMetricsData.txt create mode 100644 receiver/oracledbreceiver/testdata/oracleQueryPlanData.txt diff --git a/.chloggen/oracledbreceiver-top-n-queries-and-query-samples.yaml b/.chloggen/oracledbreceiver-top-n-queries-and-query-samples.yaml new file mode 100644 index 0000000000000..bd3a42f748496 --- /dev/null +++ b/.chloggen/oracledbreceiver-top-n-queries-and-query-samples.yaml @@ -0,0 +1,31 @@ +# 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. filelogreceiver) +component: oracledbreceiver + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Support query-level log collection, fetching top N query metrics and details of currently running queries (samples). + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [37478] + +# (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: | + With the introduction of query level log collection, the oracledbreceiver can now send metrics for Top N queries, + filtered based on the highest CPU time consumed. The number of queries can be configured. This helps the user to have + a better understanding of the database operations. In addition to this, query samples can be collected for the currently + executing queries. This enhancement enables users to proactively monitor and manage the database performance. + +# 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/oracledbreceiver/README.md b/receiver/oracledbreceiver/README.md index c8d4cb85e0f8f..cce8c83d9cd89 100644 --- a/receiver/oracledbreceiver/README.md +++ b/receiver/oracledbreceiver/README.md @@ -3,12 +3,14 @@ | Status | | | ------------- |-----------| -| Stability | [alpha]: metrics | +| Stability | [development]: logs | +| | [alpha]: metrics | | Distributions | [contrib] | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Areceiver%2Foracledb%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Areceiver%2Foracledb) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Areceiver%2Foracledb%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Areceiver%2Foracledb) | | Code coverage | [![codecov](https://codecov.io/github/open-telemetry/opentelemetry-collector-contrib/graph/main/badge.svg?component=receiver_oracledb)](https://app.codecov.io/gh/open-telemetry/opentelemetry-collector-contrib/tree/main/?components%5B0%5D=receiver_oracledb&displayType=list) | | [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@dmitryax](https://www.github.com/dmitryax), [@crobert-1](https://www.github.com/crobert-1), [@atoulme](https://www.github.com/atoulme) | +[development]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#development [alpha]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#alpha [contrib]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib diff --git a/receiver/oracledbreceiver/config.go b/receiver/oracledbreceiver/config.go index e243ca3670aa6..ee6a957511e6e 100644 --- a/receiver/oracledbreceiver/config.go +++ b/receiver/oracledbreceiver/config.go @@ -17,15 +17,24 @@ import ( ) var ( - errBadDataSource = errors.New("datasource is invalid") - errBadEndpoint = errors.New("endpoint must be specified as host:port") - errBadPort = errors.New("invalid port in endpoint") - errEmptyEndpoint = errors.New("endpoint must be specified") - errEmptyPassword = errors.New("password must be set") - errEmptyService = errors.New("service must be specified") - errEmptyUsername = errors.New("username must be set") + errBadDataSource = errors.New("datasource is invalid") + errBadEndpoint = errors.New("endpoint must be specified as host:port") + errBadPort = errors.New("invalid port in endpoint") + errEmptyEndpoint = errors.New("endpoint must be specified") + errEmptyPassword = errors.New("password must be set") + errEmptyService = errors.New("service must be specified") + errEmptyUsername = errors.New("username must be set") + errMaxQuerySampleCount = errors.New("`max_query_sample_count` must be between 1 and 10000") + errTopQueryCount = errors.New("`top_query_count` must be between 1 and 200 and less than or equal to `max_query_sample_count`") + errQueryCacheSize = errors.New("`query_cache_size` must be strictly positive") ) +type TopQueryCollection struct { + MaxQuerySampleCount uint `mapstructure:"max_query_sample_count"` + TopQueryCount uint `mapstructure:"top_query_count"` + QueryCacheSize int `mapstructure:"query_cache_size"` +} + type Config struct { DataSource string `mapstructure:"datasource"` Endpoint string `mapstructure:"endpoint"` @@ -34,6 +43,9 @@ type Config struct { Username string `mapstructure:"username"` scraperhelper.ControllerConfig `mapstructure:",squash"` metadata.MetricsBuilderConfig `mapstructure:",squash"` + metadata.LogsBuilderConfig `mapstructure:",squash"` + + TopQueryCollection `mapstructure:"top_query_collection"` } func (c Config) Validate() error { @@ -79,5 +91,15 @@ func (c Config) Validate() error { allErrs = multierr.Append(allErrs, fmt.Errorf("%w: %s", errBadDataSource, err.Error())) } } + + if c.MaxQuerySampleCount < 1 || c.MaxQuerySampleCount > 10000 { + allErrs = multierr.Append(allErrs, errMaxQuerySampleCount) + } + if c.TopQueryCount < 1 || c.TopQueryCount > 200 || c.TopQueryCount > c.MaxQuerySampleCount { + allErrs = multierr.Append(allErrs, errTopQueryCount) + } + if c.QueryCacheSize <= 0 { + allErrs = multierr.Append(allErrs, errQueryCacheSize) + } return allErrs } diff --git a/receiver/oracledbreceiver/db_client.go b/receiver/oracledbreceiver/db_client.go index cb3c171a8600b..619b6a320fd7d 100644 --- a/receiver/oracledbreceiver/db_client.go +++ b/receiver/oracledbreceiver/db_client.go @@ -16,7 +16,7 @@ import ( ) type dbClient interface { - metricRows(ctx context.Context) ([]metricRow, error) + metricRows(ctx context.Context, args ...any) ([]metricRow, error) } type metricRow map[string]string @@ -35,8 +35,8 @@ func newDbClient(db *sql.DB, sql string, logger *zap.Logger) dbClient { } } -func (cl dbSQLClient) metricRows(ctx context.Context) ([]metricRow, error) { - sqlRows, err := cl.db.QueryContext(ctx, cl.sql) +func (cl dbSQLClient) metricRows(ctx context.Context, args ...any) ([]metricRow, error) { + sqlRows, err := cl.db.QueryContext(ctx, cl.sql, args...) if err != nil { return nil, err } diff --git a/receiver/oracledbreceiver/documentation.md b/receiver/oracledbreceiver/documentation.md index ef1eb62832cc6..5355e99d7ca42 100644 --- a/receiver/oracledbreceiver/documentation.md +++ b/receiver/oracledbreceiver/documentation.md @@ -369,8 +369,90 @@ Number of SELECT statements executed in parallel | ---- | ----------- | ---------- | ----------------------- | --------- | | {queries} | Sum | Int | Cumulative | true | +## Default Events + +The following events are emitted by default. Each of them can be disabled by applying the following configuration: + +```yaml +events: + : + enabled: false +``` + +## Optional Events + +The following events are not emitted by default. Each of them can be enabled by applying the following configuration: + +```yaml +events: + : + enabled: true +``` + +### db.server.query_sample + +sample query + +#### Attributes + +| Name | Description | Values | +| ---- | ----------- | ------ | +| db.query.text | The text of the database query being executed. | Any Str | +| db.system.name | The database management system (DBMS) product as identified by the client instrumentation. | Any Str | +| user.name | Database user name under which a session is connected to | Any Str | +| client.address | Identifies the name of the machine (host) from which the database client is connecting to the Oracle database. | Any Str | +| oracledb.plan_hash_value | Binary hash value calculated on the query execution plan and used to identify similar query execution plans, reported in the HEX format. | Any Str | +| oracledb.sql_id | The SQL ID of the query. | Any Str | +| oracledb.child_number | The child number of the query. | Any Str | +| oracledb.sid | ID of the Oracle Server session. | Any Str | +| oracledb.serial | Serial number associated with a session. | Any Str | +| oracledb.process | The operating system process ID (PID) associated with a session. | Any Str | +| oracledb.schemaname | Oracle schema under which SQL statements are being executed | Any Str | +| oracledb.program | Name of the client program or tool that initiated the Oracle database session. | Any Str | +| oracledb.module | Logical module name of the client application that initiated a query or session. | Any Str | +| oracledb.status | Execution state or result of a database query or session. | Any Str | +| oracledb.state | Current state of the query or the session executing it. | Any Str | +| oracledb.wait_class | The category of wait events a query or session is currently experiencing in Oracle Database. | Any Str | +| oracledb.event | The specific wait event that a query or session is currently experiencing. | Any Str | +| oracledb.object_name | Name of the database object that a query is accessing. | Any Str | +| oracledb.object_type | Type of the database object that a query is accessing. | Any Str | +| oracledb.osuser | Name of the operating system user that initiated or is running the Oracle database session. | Any Str | +| oracledb.duration_sec | Total time taken by a database query to execute. | Any Double | + +### db.server.top_query + +top query + +#### Attributes + +| Name | Description | Values | +| ---- | ----------- | ------ | +| db.system.name | The database management system (DBMS) product as identified by the client instrumentation. | Any Str | +| db.server.name | The name of the server hosting the database. | Any Str | +| db.query.text | The text of the database query being executed. | Any Str | +| oracledb.query_plan | The query execution plan used by the SQL Server. | Any Str | +| oracledb.sql_id | The SQL ID of the query. | Any Str | +| oracledb.child_number | The child number of the query. | Any Str | +| oracledb.application_wait_time | The total time (in seconds) a query spent waiting on the application before it could proceed with execution (reporting delta). | Any Double | +| oracledb.buffer_gets | Number of logical reads (i.e., buffer cache accesses) performed by a query (reporting delta). | Any Int | +| oracledb.cluster_wait_time | Total time (in seconds) that a query waited due to Oracle Real Application Clusters (RAC) coordination (reporting delta). | Any Double | +| oracledb.concurrency_wait_time | Total time (in seconds) a query spent waiting on concurrency-related events (reporting delta). | Any Double | +| oracledb.cpu_time | Total time (in seconds) that the CPU spent actively processing a query, excluding time spent waiting (reporting delta). | Any Double | +| oracledb.direct_reads | The number of direct path reads performed by a query — i.e., data blocks read directly from disk into the session’s memory (reporting delta). | Any Int | +| oracledb.direct_writes | The number of direct path write operations, where data is written directly to disk from user memory (reporting delta). | Any Int | +| oracledb.disk_reads | The number of physical reads a query performs — that is, the number of data blocks read from disk (reporting delta). | Any Int | +| oracledb.elapsed_time | The total time (in seconds) taken by a query from start to finish, including CPU time and all types of waits (reporting delta). | Any Double | +| oracledb.executions | The number of times a specific SQL query has been executed (reporting delta). | Any Int | +| oracledb.physical_read_bytes | The total number of bytes read from disk by a query (reporting delta). | Any Int | +| oracledb.physical_read_requests | The number of physical I/O read operations performed by a query (reporting delta). | Any Int | +| oracledb.physical_write_bytes | The total number of bytes written to disk by a query (reporting delta). | Any Int | +| oracledb.physical_write_requests | The number of times a query requested to write data to disk (reporting delta). | Any Int | +| oracledb.rows_processed | The total number of rows that a query has read, returned, or affected during its execution (reporting delta). | Any Int | +| oracledb.user_io_wait_time | The total time (in seconds) a query spent waiting for user I/O operations—such as reading or writing data to disk or network file systems (reporting delta). | Any Double | + ## Resource Attributes | Name | Description | Values | Enabled | | ---- | ----------- | ------ | ------- | +| host.name | The host name of Oracle Server | Any Str | true | | oracledb.instance.name | The name of the instance that data is coming from. | Any Str | true | diff --git a/receiver/oracledbreceiver/factory.go b/receiver/oracledbreceiver/factory.go index 9a77ea5e1c1df..16067222f18f9 100644 --- a/receiver/oracledbreceiver/factory.go +++ b/receiver/oracledbreceiver/factory.go @@ -11,11 +11,14 @@ import ( "strconv" "time" + lru "github.com/hashicorp/golang-lru/v2" go_ora "github.com/sijms/go-ora/v2" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/receiver" + "go.opentelemetry.io/collector/scraper" "go.opentelemetry.io/collector/scraper/scraperhelper" + "go.uber.org/zap" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/oracledbreceiver/internal/metadata" ) @@ -27,7 +30,10 @@ func NewFactory() receiver.Factory { createDefaultConfig, receiver.WithMetrics(createReceiverFunc(func(dataSourceName string) (*sql.DB, error) { return sql.Open("oracle", dataSourceName) - }, newDbClient), metadata.MetricsStability)) + }, newDbClient), metadata.MetricsStability), + receiver.WithLogs(createLogsReceiverFunc(func(dataSourceName string) (*sql.DB, error) { + return sql.Open("oracle", dataSourceName) + }, newDbClient), metadata.LogsStability)) } func createDefaultConfig() component.Config { @@ -37,6 +43,12 @@ func createDefaultConfig() component.Config { return &Config{ ControllerConfig: cfg, MetricsBuilderConfig: metadata.DefaultMetricsBuilderConfig(), + LogsBuilderConfig: metadata.DefaultLogsBuilderConfig(), + TopQueryCollection: TopQueryCollection{ + MaxQuerySampleCount: 1000, + TopQueryCount: 200, + QueryCacheSize: 5000, + }, } } @@ -56,10 +68,14 @@ func createReceiverFunc(sqlOpenerFunc sqlOpenerFunc, clientProviderFunc clientPr if err != nil { return nil, err } + hostName, hostNameErr := getHostName(getDataSource(*sqlCfg)) + if hostNameErr != nil { + return nil, hostNameErr + } mp, err := newScraper(metricsBuilder, sqlCfg.MetricsBuilderConfig, sqlCfg.ControllerConfig, settings.Logger, func() (*sql.DB, error) { return sqlOpenerFunc(getDataSource(*sqlCfg)) - }, clientProviderFunc, instanceName) + }, clientProviderFunc, instanceName, hostName) if err != nil { return nil, err } @@ -74,6 +90,56 @@ func createReceiverFunc(sqlOpenerFunc sqlOpenerFunc, clientProviderFunc clientPr } } +func createLogsReceiverFunc(sqlOpenerFunc sqlOpenerFunc, clientProviderFunc clientProviderFunc) receiver.CreateLogsFunc { + return func( + _ context.Context, + settings receiver.Settings, + cfg component.Config, + logsConsumer consumer.Logs, + ) (receiver.Logs, error) { + sqlCfg := cfg.(*Config) + + logsBuilder := metadata.NewLogsBuilder(sqlCfg.LogsBuilderConfig, settings) + + instanceName, err := getInstanceName(getDataSource(*sqlCfg)) + if err != nil { + return nil, err + } + + hostName, hostNameErr := getHostName(getDataSource(*sqlCfg)) + if hostNameErr != nil { + return nil, hostNameErr + } + + cacheSize := sqlCfg.QueryCacheSize + metricCache, err := lru.New[string, map[string]int64](cacheSize) + if err != nil { + settings.Logger.Error("Failed to create LRU cache, skipping the current scraper", zap.Error(err)) + return nil, err + } + + mp, err := newLogsScraper(logsBuilder, sqlCfg.LogsBuilderConfig, sqlCfg.ControllerConfig, settings.Logger, func() (*sql.DB, error) { + return sqlOpenerFunc(getDataSource(*sqlCfg)) + }, clientProviderFunc, instanceName, metricCache, sqlCfg.TopQueryCollection, hostName) + if err != nil { + return nil, err + } + + f := scraper.NewFactory(metadata.Type, nil, + scraper.WithLogs(func(context.Context, scraper.Settings, component.Config) (scraper.Logs, error) { + return mp, nil + }, component.StabilityLevelAlpha)) + opt := scraperhelper.AddFactoryWithConfig(f, nil) + + return scraperhelper.NewLogsController( + &sqlCfg.ControllerConfig, + settings, + logsConsumer, + opt, + ) + } +} + func getDataSource(cfg Config) string { if cfg.DataSource != "" { return cfg.DataSource @@ -95,3 +161,11 @@ func getInstanceName(datasource string) (string, error) { instanceName := datasourceURL.Host + datasourceURL.Path return instanceName, nil } + +func getHostName(datasource string) (string, error) { + datasourceURL, err := url.Parse(datasource) + if err != nil { + return "", err + } + return datasourceURL.Host, nil +} diff --git a/receiver/oracledbreceiver/factory_test.go b/receiver/oracledbreceiver/factory_test.go index 3805097bab0bd..eb1f170a60d69 100644 --- a/receiver/oracledbreceiver/factory_test.go +++ b/receiver/oracledbreceiver/factory_test.go @@ -30,6 +30,19 @@ func TestNewFactory(t *testing.T) { consumertest.NewNop(), ) require.NoError(t, err) + + config := factory.CreateDefaultConfig().(*Config) + _, logsErr := factory.CreateLogs( + context.Background(), + receiver.Settings{ + ID: component.NewID(metadata.Type), + TelemetrySettings: componenttest.NewNopTelemetrySettings(), + }, + config, + + consumertest.NewNop(), + ) + require.NoError(t, logsErr) } func TestGetInstanceName(t *testing.T) { diff --git a/receiver/oracledbreceiver/fake_db_client.go b/receiver/oracledbreceiver/fake_db_client.go index 004f9630b30c6..6a22a276ac2a2 100644 --- a/receiver/oracledbreceiver/fake_db_client.go +++ b/receiver/oracledbreceiver/fake_db_client.go @@ -13,7 +13,7 @@ type fakeDbClient struct { RequestCounter int } -func (c *fakeDbClient) metricRows(context.Context) ([]metricRow, error) { +func (c *fakeDbClient) metricRows(context.Context, ...any) ([]metricRow, error) { if c.Err != nil { return nil, c.Err } diff --git a/receiver/oracledbreceiver/generated_component_test.go b/receiver/oracledbreceiver/generated_component_test.go index 94b9cd438a828..9c707cc9498e5 100644 --- a/receiver/oracledbreceiver/generated_component_test.go +++ b/receiver/oracledbreceiver/generated_component_test.go @@ -33,6 +33,13 @@ func TestComponentLifecycle(t *testing.T) { name string }{ + { + name: "logs", + createFn: func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) { + return factory.CreateLogs(ctx, set, cfg, consumertest.NewNop()) + }, + }, + { name: "metrics", createFn: func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) { diff --git a/receiver/oracledbreceiver/go.mod b/receiver/oracledbreceiver/go.mod index 69104a8517637..7c697ea87c632 100644 --- a/receiver/oracledbreceiver/go.mod +++ b/receiver/oracledbreceiver/go.mod @@ -3,30 +3,40 @@ module github.com/open-telemetry/opentelemetry-collector-contrib/receiver/oracle go 1.23.0 require ( + github.com/DataDog/datadog-agent/pkg/obfuscate v0.67.0 github.com/google/go-cmp v0.7.0 - github.com/sijms/go-ora/v2 v2.8.24 + github.com/hashicorp/golang-lru/v2 v2.0.7 + github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden v0.128.0 + github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.128.0 + github.com/sijms/go-ora/v2 v2.9.0 github.com/stretchr/testify v1.10.0 - go.opentelemetry.io/collector/component v1.34.0 - go.opentelemetry.io/collector/component/componenttest v0.128.0 - go.opentelemetry.io/collector/confmap v1.34.0 - go.opentelemetry.io/collector/consumer v1.34.0 - go.opentelemetry.io/collector/consumer/consumertest v0.128.0 - go.opentelemetry.io/collector/filter v0.128.0 - go.opentelemetry.io/collector/pdata v1.34.0 - go.opentelemetry.io/collector/receiver v1.34.0 - go.opentelemetry.io/collector/receiver/receivertest v0.128.0 - go.opentelemetry.io/collector/scraper v0.128.0 - go.opentelemetry.io/collector/scraper/scraperhelper v0.128.0 + go.opentelemetry.io/collector/component v1.34.1-0.20250610090210-188191247685 + go.opentelemetry.io/collector/component/componenttest v0.128.1-0.20250610090210-188191247685 + go.opentelemetry.io/collector/confmap v1.34.1-0.20250610090210-188191247685 + go.opentelemetry.io/collector/consumer v1.34.1-0.20250610090210-188191247685 + go.opentelemetry.io/collector/consumer/consumertest v0.128.1-0.20250610090210-188191247685 + go.opentelemetry.io/collector/filter v0.128.1-0.20250610090210-188191247685 + go.opentelemetry.io/collector/pdata v1.34.1-0.20250610090210-188191247685 + go.opentelemetry.io/collector/receiver v1.34.1-0.20250610090210-188191247685 + go.opentelemetry.io/collector/receiver/receivertest v0.128.1-0.20250610090210-188191247685 + go.opentelemetry.io/collector/scraper v0.128.1-0.20250610090210-188191247685 + go.opentelemetry.io/collector/scraper/scraperhelper v0.128.1-0.20250610090210-188191247685 + go.opentelemetry.io/otel/trace v1.36.0 go.uber.org/goleak v1.3.0 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.0 ) require ( - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/DataDog/datadog-go/v5 v5.6.0 // indirect + github.com/DataDog/go-sqllexer v0.1.6 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-viper/mapstructure/v2 v2.2.1 // indirect + github.com/go-viper/mapstructure/v2 v2.3.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/uuid v1.6.0 // indirect @@ -34,33 +44,36 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/knadh/koanf/maps v0.1.2 // indirect github.com/knadh/koanf/providers/confmap v1.0.0 // indirect - github.com/knadh/koanf/v2 v2.2.0 // indirect + github.com/knadh/koanf/v2 v2.2.1 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.128.0 // indirect + github.com/outcaste-io/ristretto v0.2.3 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/collector/consumer/consumererror v0.128.0 // indirect - go.opentelemetry.io/collector/consumer/xconsumer v0.128.0 // indirect - go.opentelemetry.io/collector/featuregate v1.34.0 // indirect - go.opentelemetry.io/collector/internal/telemetry v0.128.0 // indirect - go.opentelemetry.io/collector/pdata/pprofile v0.128.0 // indirect - go.opentelemetry.io/collector/pipeline v0.128.0 // indirect - go.opentelemetry.io/collector/receiver/receiverhelper v0.128.0 // indirect - go.opentelemetry.io/collector/receiver/xreceiver v0.128.0 // indirect + go.opentelemetry.io/collector/consumer/consumererror v0.128.1-0.20250610090210-188191247685 // indirect + go.opentelemetry.io/collector/consumer/xconsumer v0.128.1-0.20250610090210-188191247685 // indirect + go.opentelemetry.io/collector/featuregate v1.34.1-0.20250610090210-188191247685 // indirect + go.opentelemetry.io/collector/internal/telemetry v0.128.1-0.20250610090210-188191247685 // indirect + go.opentelemetry.io/collector/pdata/pprofile v0.128.1-0.20250610090210-188191247685 // indirect + go.opentelemetry.io/collector/pipeline v0.128.1-0.20250610090210-188191247685 // indirect + go.opentelemetry.io/collector/receiver/receiverhelper v0.128.1-0.20250610090210-188191247685 // indirect + go.opentelemetry.io/collector/receiver/xreceiver v0.128.1-0.20250610090210-188191247685 // indirect go.opentelemetry.io/contrib/bridges/otelzap v0.11.0 // indirect go.opentelemetry.io/otel v1.36.0 // indirect go.opentelemetry.io/otel/log v0.12.2 // indirect go.opentelemetry.io/otel/metric v1.36.0 // indirect go.opentelemetry.io/otel/sdk v1.36.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.36.0 // indirect - go.opentelemetry.io/otel/trace v1.36.0 // indirect - golang.org/x/net v0.39.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + golang.org/x/net v0.41.0 // indirect golang.org/x/sys v0.33.0 // indirect - golang.org/x/text v0.24.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect - google.golang.org/grpc v1.72.2 // indirect + golang.org/x/text v0.26.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect + google.golang.org/grpc v1.73.0 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect diff --git a/receiver/oracledbreceiver/go.sum b/receiver/oracledbreceiver/go.sum index cca7a8c3d5939..fd032fb1dd1af 100644 --- a/receiver/oracledbreceiver/go.sum +++ b/receiver/oracledbreceiver/go.sum @@ -1,17 +1,37 @@ +github.com/DataDog/datadog-agent/pkg/obfuscate v0.67.0 h1:NcvyDVIUA0NbBDbp7QJnsYhoBv548g8bXq886795mCQ= +github.com/DataDog/datadog-agent/pkg/obfuscate v0.67.0/go.mod h1:1oPcs3BUTQhiTkmk789rb7ob105MxNV6OuBa28BdukQ= +github.com/DataDog/datadog-go/v5 v5.6.0 h1:2oCLxjF/4htd55piM75baflj/KoE6VYS7alEUqFvRDw= +github.com/DataDog/datadog-go/v5 v5.6.0/go.mod h1:K9kcYBlxkcPP8tvvjZZKs/m1edNAUFzBbdpTUKfCsuw= +github.com/DataDog/go-sqllexer v0.1.6 h1:skEXpWEVCpeZFIiydoIa2f2rf+ymNpjiIMqpW4w3YAk= +github.com/DataDog/go-sqllexer v0.1.6/go.mod h1:GGpo1h9/BVSN+6NJKaEcJ9Jn44Hqc63Rakeb+24Mjgo= +github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa512G+w+Pxci9hJPB8oMnkcP3iZF38= +github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= -github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk= +github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -22,6 +42,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -30,8 +52,8 @@ github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpb github.com/knadh/koanf/maps v0.1.2/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= github.com/knadh/koanf/providers/confmap v1.0.0 h1:mHKLJTE7iXEys6deO5p6olAiZdG5zwp8Aebir+/EaRE= github.com/knadh/koanf/providers/confmap v1.0.0/go.mod h1:txHYHiI2hAtF0/0sCmcuol4IDcuQbKTybiB1nOcUo1A= -github.com/knadh/koanf/v2 v2.2.0 h1:FZFwd9bUjpb8DyCWARUBy5ovuhDs1lI87dOEn2K8UVU= -github.com/knadh/koanf/v2 v2.2.0/go.mod h1:PSFru3ufQgTsI7IF+95rf9s8XA1+aHxKuO/W+dPoHEY= +github.com/knadh/koanf/v2 v2.2.1 h1:jaleChtw85y3UdBnI0wCqcg1sj1gPoz6D3caGNHtrNE= +github.com/knadh/koanf/v2 v2.2.1/go.mod h1:PSFru3ufQgTsI7IF+95rf9s8XA1+aHxKuO/W+dPoHEY= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -45,60 +67,82 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden v0.128.0 h1:GJzARUS5NcCeYr7pwlrYMEK+fl92cmCDED2to7nPuCQ= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden v0.128.0/go.mod h1:YrULw8EK8Vj0LX2ZhtfqMaIlLATIGOlbII9RDR8lPeI= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.128.0 h1:+rUULr4xqOJjZK3SokFmRYzsiPq5onoWoSv3He4aaus= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.128.0/go.mod h1:Fh2SXPeFkr4J97w9CV/apFAib8TC9Hi0P08xtiT7Lng= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.128.0 h1:8OWwRSdIhm3DY3PEYJ0PtSEz1a1OjL0fghLXSr14JMk= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.128.0/go.mod h1:32OeaysZe4vkSmD1LJ18Q1DfooryYqpSzFNmz+5A5RU= +github.com/outcaste-io/ristretto v0.2.3 h1:AK4zt/fJ76kjlYObOeNwh4T3asEuaCmp26pOvUOL9w0= +github.com/outcaste-io/ristretto v0.2.3/go.mod h1:W8HywhmtlopSB1jeMg3JtdIhf+DYkLAr0VN/s4+MHac= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= -github.com/sijms/go-ora/v2 v2.8.24 h1:TODRWjWGwJ1VlBOhbTLat+diTYe8HXq2soJeB+HMjnw= -github.com/sijms/go-ora/v2 v2.8.24/go.mod h1:QgFInVi3ZWyqAiJwzBQA+nbKYKH77tdp1PYoCqhR2dU= +github.com/sijms/go-ora/v2 v2.9.0 h1:+iQbUeTeCOFMb5BsOMgUhV8KWyrv9yjKpcK4x7+MFrg= +github.com/sijms/go-ora/v2 v2.9.0/go.mod h1:QgFInVi3ZWyqAiJwzBQA+nbKYKH77tdp1PYoCqhR2dU= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/collector/component v1.34.0 h1:YONg7FaZ5zZbj5cLdARvwtMNuZHunuyxw2fWe5fcWqc= -go.opentelemetry.io/collector/component v1.34.0/go.mod h1:GvolsSVZskXuyfQdwYacqeBSZe/1tg4RJ0YK55KSvDA= -go.opentelemetry.io/collector/component/componenttest v0.128.0 h1:MGNh5lQQ0Qmz2SmNwOqLJYaWMDkMLYj/51wjMzTBR34= -go.opentelemetry.io/collector/component/componenttest v0.128.0/go.mod h1:hALNxcacqOaX/Gm/dE7sNOxAEFj41SbRqtvF57Yd6gs= -go.opentelemetry.io/collector/confmap v1.34.0 h1:PG4sYlLxgCMnA5F7daKXZV+NKjU1IzXBzVQeyvcwyh0= -go.opentelemetry.io/collector/confmap v1.34.0/go.mod h1:BbAit8+hAJg5vyFBQoDh9vOXOH8UzCdNu91jCh+b72E= -go.opentelemetry.io/collector/consumer v1.34.0 h1:oBhHH6mgViOGhVDPozE+sUdt7jFBo2Hh32lsSr2L3Tc= -go.opentelemetry.io/collector/consumer v1.34.0/go.mod h1:DVMCb56ZBlPNcmo0lSJKn3rp18oyZQCedRE4GKIMI+Q= -go.opentelemetry.io/collector/consumer/consumererror v0.128.0 h1:3htkWoHwXZ801ORmGeORdcMGqJHEbwdjaWhIj4LNbxw= -go.opentelemetry.io/collector/consumer/consumererror v0.128.0/go.mod h1:v3eUnvuIBSV2yBWiWoZELV1jki7HFMttWeBF311XIU0= -go.opentelemetry.io/collector/consumer/consumertest v0.128.0 h1:x50GB0I/QvU3sQuNCap5z/P2cnq2yHoRJ/8awkiT87w= -go.opentelemetry.io/collector/consumer/consumertest v0.128.0/go.mod h1:Wb3IAbMY/DOIwJPy81PuBiW2GnKoNIz4THE7wfJwovE= -go.opentelemetry.io/collector/consumer/xconsumer v0.128.0 h1:4E+KTdCjkRS3SIw0bsv5kpv9XFXHf8x9YiPEuxBVEHY= -go.opentelemetry.io/collector/consumer/xconsumer v0.128.0/go.mod h1:OmzilL/qbjCzPMHay+WEA7/cPe5xuX7Jbj5WPIpqaMo= -go.opentelemetry.io/collector/featuregate v1.34.0 h1:zqDHpEYy1UeudrfUCvlcJL2t13dXywrC6lwpNZ5DrCU= -go.opentelemetry.io/collector/featuregate v1.34.0/go.mod h1:Y/KsHbvREENKvvN9RlpiWk/IGBK+CATBYzIIpU7nccc= -go.opentelemetry.io/collector/filter v0.128.0 h1:+peqFQvWJeWU2HJfNOFZ5YA0y7iu1gJM0KK+o6i1eOE= -go.opentelemetry.io/collector/filter v0.128.0/go.mod h1:Kf/Ja0QjrHjICXIHG26qWmOOVj7I0LKS5yi+tRuFPRE= -go.opentelemetry.io/collector/internal/telemetry v0.128.0 h1:ySEYWoY7J8DAYdlw2xlF0w+ODQi3AhYj7TRNflsCbx8= -go.opentelemetry.io/collector/internal/telemetry v0.128.0/go.mod h1:572B/iJqjauv3aT+zcwnlNWBPqM7+KqrYGSUuOAStrM= -go.opentelemetry.io/collector/pdata v1.34.0 h1:2vwYftckXe7pWxI9mfSo+tw3wqdGNrYpMbDx/5q6rw8= -go.opentelemetry.io/collector/pdata v1.34.0/go.mod h1:StPHMFkhLBellRWrULq0DNjv4znCDJZP6La4UuC+JHI= -go.opentelemetry.io/collector/pdata/pprofile v0.128.0 h1:6DEtzs/liqv/ukz2EHbC5OMaj2V6K2pzuj/LaRg2YmY= -go.opentelemetry.io/collector/pdata/pprofile v0.128.0/go.mod h1:bVVRpz+zKFf1UCCRUFqy8LvnO3tHlXKkdqW2d+Wi/iA= +go.opentelemetry.io/collector/component v1.34.1-0.20250610090210-188191247685 h1:rolXmlkiJHy1G/xx2YXi3lMNGkwAz0UBMHfNCYsETT8= +go.opentelemetry.io/collector/component v1.34.1-0.20250610090210-188191247685/go.mod h1:GvolsSVZskXuyfQdwYacqeBSZe/1tg4RJ0YK55KSvDA= +go.opentelemetry.io/collector/component/componenttest v0.128.1-0.20250610090210-188191247685 h1:uWzmyuGyhNM22PSTfq4XjSZXaVjiJOSDFOyK4IP6dOk= +go.opentelemetry.io/collector/component/componenttest v0.128.1-0.20250610090210-188191247685/go.mod h1:hALNxcacqOaX/Gm/dE7sNOxAEFj41SbRqtvF57Yd6gs= +go.opentelemetry.io/collector/confmap v1.34.1-0.20250610090210-188191247685 h1:rg3hxtp0bqXLzX9UoZ0gqnwNGq3Wbb5CAJncvedPTe0= +go.opentelemetry.io/collector/confmap v1.34.1-0.20250610090210-188191247685/go.mod h1:BbAit8+hAJg5vyFBQoDh9vOXOH8UzCdNu91jCh+b72E= +go.opentelemetry.io/collector/consumer v1.34.1-0.20250610090210-188191247685 h1:4x5XWogfgcNKvtnRV3dpBlJHFhFDzfN4rg/AR/54KVU= +go.opentelemetry.io/collector/consumer v1.34.1-0.20250610090210-188191247685/go.mod h1:DVMCb56ZBlPNcmo0lSJKn3rp18oyZQCedRE4GKIMI+Q= +go.opentelemetry.io/collector/consumer/consumererror v0.128.1-0.20250610090210-188191247685 h1:biKVR68hnZGMgt8eKn78+/mfSU3OmeFm/P4YtKBNtO8= +go.opentelemetry.io/collector/consumer/consumererror v0.128.1-0.20250610090210-188191247685/go.mod h1:v3eUnvuIBSV2yBWiWoZELV1jki7HFMttWeBF311XIU0= +go.opentelemetry.io/collector/consumer/consumertest v0.128.1-0.20250610090210-188191247685 h1:de5gGscfgLvoTe6SYwk3j9qganr/xzp5FTu+ooy/jQo= +go.opentelemetry.io/collector/consumer/consumertest v0.128.1-0.20250610090210-188191247685/go.mod h1:Wb3IAbMY/DOIwJPy81PuBiW2GnKoNIz4THE7wfJwovE= +go.opentelemetry.io/collector/consumer/xconsumer v0.128.1-0.20250610090210-188191247685 h1:fV7oLPVEY8hVMU6dAKWaXH/3u8/iqjO4otkq46DwhFU= +go.opentelemetry.io/collector/consumer/xconsumer v0.128.1-0.20250610090210-188191247685/go.mod h1:OmzilL/qbjCzPMHay+WEA7/cPe5xuX7Jbj5WPIpqaMo= +go.opentelemetry.io/collector/featuregate v1.34.1-0.20250610090210-188191247685 h1:ASoACXY6N/lK4/7e3MD3SZJDjT8ox/PeNKXn/axguYw= +go.opentelemetry.io/collector/featuregate v1.34.1-0.20250610090210-188191247685/go.mod h1:Y/KsHbvREENKvvN9RlpiWk/IGBK+CATBYzIIpU7nccc= +go.opentelemetry.io/collector/filter v0.128.1-0.20250610090210-188191247685 h1:4acgrSMQ/2BUTUiTdGiPLWhsEPSP8VQyLyuSdUaMQMQ= +go.opentelemetry.io/collector/filter v0.128.1-0.20250610090210-188191247685/go.mod h1:Kf/Ja0QjrHjICXIHG26qWmOOVj7I0LKS5yi+tRuFPRE= +go.opentelemetry.io/collector/internal/telemetry v0.128.1-0.20250610090210-188191247685 h1:ikRMfQd0Seg/J3ltG23XNTKdanbvES5fLH/LucPEjqc= +go.opentelemetry.io/collector/internal/telemetry v0.128.1-0.20250610090210-188191247685/go.mod h1:572B/iJqjauv3aT+zcwnlNWBPqM7+KqrYGSUuOAStrM= +go.opentelemetry.io/collector/pdata v1.34.1-0.20250610090210-188191247685 h1:Z4Xkrhi13ghAjaYACZO9JCzzyE3qas2nTrTSvQq5iQU= +go.opentelemetry.io/collector/pdata v1.34.1-0.20250610090210-188191247685/go.mod h1:StPHMFkhLBellRWrULq0DNjv4znCDJZP6La4UuC+JHI= +go.opentelemetry.io/collector/pdata/pprofile v0.128.1-0.20250610090210-188191247685 h1:z/llmzFWfdWU6eEUPnp+LlACKc8jAzHPk2ApQxtVlHo= +go.opentelemetry.io/collector/pdata/pprofile v0.128.1-0.20250610090210-188191247685/go.mod h1:bVVRpz+zKFf1UCCRUFqy8LvnO3tHlXKkdqW2d+Wi/iA= go.opentelemetry.io/collector/pdata/testdata v0.128.0 h1:5xcsMtyzvb18AnS2skVtWreQP1nl6G3PiXaylKCZ6pA= go.opentelemetry.io/collector/pdata/testdata v0.128.0/go.mod h1:9/VYVgzv3JMuIyo19KsT3FwkVyxbh3Eg5QlabQEUczA= -go.opentelemetry.io/collector/pipeline v0.128.0 h1:WgNXdFbyf/QRLy5XbO/jtPQosWrSWX/TEnSYpJq8bgI= -go.opentelemetry.io/collector/pipeline v0.128.0/go.mod h1:TO02zju/K6E+oFIOdi372Wk0MXd+Szy72zcTsFQwXl4= -go.opentelemetry.io/collector/receiver v1.34.0 h1:un6iRBXZBz1zacEmyfDCVDDaBY4GP3TQLwor894fywg= -go.opentelemetry.io/collector/receiver v1.34.0/go.mod h1:4J9xhbXJiI/rYlvlMTskXRGbwFeczJiCkW5R2YfTe88= -go.opentelemetry.io/collector/receiver/receiverhelper v0.128.0 h1:/aCWmmj9tNGY6U16fYXscJEF9BOMrzrWkLmgQbBXYfs= -go.opentelemetry.io/collector/receiver/receiverhelper v0.128.0/go.mod h1:wwSFr/7jjv7yNBnH03wpiurnJiWjaJX9Y7Oj3XfhRYw= -go.opentelemetry.io/collector/receiver/receivertest v0.128.0 h1:lIWzLAeo7EssZ9d1t6CJvCN2imoM4Fj+9HSbEZ54fBw= -go.opentelemetry.io/collector/receiver/receivertest v0.128.0/go.mod h1:1aX38R6cYe2nfw5rYW6dbHwjtUjs8z2MxrfHbXBddx8= -go.opentelemetry.io/collector/receiver/xreceiver v0.128.0 h1:1C5vlkyacvuGJkn5J78FpnuF3AlVYMmA0TGF3LPfcZI= -go.opentelemetry.io/collector/receiver/xreceiver v0.128.0/go.mod h1:kut2p3qChyX8K/qhsokae1vgLQAn53i2J5ddsvxJ81s= -go.opentelemetry.io/collector/scraper v0.128.0 h1:LdKstTSO5uEylW5el8GqUZBoNB+RzksGZV+tlZFdwRE= -go.opentelemetry.io/collector/scraper v0.128.0/go.mod h1:/xB4sWDA8GBz9fH4QohQ3An67IO8Q+5dvQDFQFnKW3k= -go.opentelemetry.io/collector/scraper/scraperhelper v0.128.0 h1:dTOFCVDBWDGstbO2y3pH6xu7FPkZ2IpUIkVnW0+HoH0= -go.opentelemetry.io/collector/scraper/scraperhelper v0.128.0/go.mod h1:zFsX7QzQV05tyBraFlAIqYxn3uQjytLuvrnBmUP/cEA= +go.opentelemetry.io/collector/pipeline v0.128.1-0.20250610090210-188191247685 h1:BW4mzAGVI+DQhxyRCA5D2FX1N+C0fI0Lu2fXYOG1RW4= +go.opentelemetry.io/collector/pipeline v0.128.1-0.20250610090210-188191247685/go.mod h1:TO02zju/K6E+oFIOdi372Wk0MXd+Szy72zcTsFQwXl4= +go.opentelemetry.io/collector/receiver v1.34.1-0.20250610090210-188191247685 h1:g3jUEXsUtrMVzRYM/T/MIaosXlKljSFft1TtTUK0ETw= +go.opentelemetry.io/collector/receiver v1.34.1-0.20250610090210-188191247685/go.mod h1:4J9xhbXJiI/rYlvlMTskXRGbwFeczJiCkW5R2YfTe88= +go.opentelemetry.io/collector/receiver/receiverhelper v0.128.1-0.20250610090210-188191247685 h1:kjYfo5mstUsI0cOvHzR/xRtrfsuMxri9adItRZ62CM0= +go.opentelemetry.io/collector/receiver/receiverhelper v0.128.1-0.20250610090210-188191247685/go.mod h1:wwSFr/7jjv7yNBnH03wpiurnJiWjaJX9Y7Oj3XfhRYw= +go.opentelemetry.io/collector/receiver/receivertest v0.128.1-0.20250610090210-188191247685 h1:NbYmvU6uepdxwFgg1OJg8DEoPrlxq5Ii3GB5GaRMzl8= +go.opentelemetry.io/collector/receiver/receivertest v0.128.1-0.20250610090210-188191247685/go.mod h1:1aX38R6cYe2nfw5rYW6dbHwjtUjs8z2MxrfHbXBddx8= +go.opentelemetry.io/collector/receiver/xreceiver v0.128.1-0.20250610090210-188191247685 h1:hKUAv2wUfBk8XZ5wNpIVpcAT80Sqt13ZvbK24xRj/vM= +go.opentelemetry.io/collector/receiver/xreceiver v0.128.1-0.20250610090210-188191247685/go.mod h1:kut2p3qChyX8K/qhsokae1vgLQAn53i2J5ddsvxJ81s= +go.opentelemetry.io/collector/scraper v0.128.1-0.20250610090210-188191247685 h1:xjGLsf7Gt+BwDEGB/5ZOvHUaCmEqdoZwIZa3Rc19F40= +go.opentelemetry.io/collector/scraper v0.128.1-0.20250610090210-188191247685/go.mod h1:/xB4sWDA8GBz9fH4QohQ3An67IO8Q+5dvQDFQFnKW3k= +go.opentelemetry.io/collector/scraper/scraperhelper v0.128.1-0.20250610090210-188191247685 h1:7DvDPEYywSjox66bjNzHZjZfFIHpuQ/AtDXNpuMZRPg= +go.opentelemetry.io/collector/scraper/scraperhelper v0.128.1-0.20250610090210-188191247685/go.mod h1:zFsX7QzQV05tyBraFlAIqYxn3uQjytLuvrnBmUP/cEA= go.opentelemetry.io/contrib/bridges/otelzap v0.11.0 h1:u2E32P7j1a/gRgZDWhIXC+Shd4rLg70mnE7QLI/Ssnw= go.opentelemetry.io/contrib/bridges/otelzap v0.11.0/go.mod h1:pJPCLM8gzX4ASqLlyAXjHBEYxgbOQJ/9bidWxD6PEPQ= go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= @@ -115,6 +159,9 @@ go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFw go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -126,41 +173,53 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= -golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= -golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ= -google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8= -google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= +google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= diff --git a/receiver/oracledbreceiver/internal/metadata/generated_config.go b/receiver/oracledbreceiver/internal/metadata/generated_config.go index 68eb098e7afa3..8015aea85d87f 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_config.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_config.go @@ -199,6 +199,42 @@ func DefaultMetricsConfig() MetricsConfig { } } +// EventConfig provides common config for a particular event. +type EventConfig struct { + Enabled bool `mapstructure:"enabled"` + + enabledSetByUser bool +} + +func (ec *EventConfig) Unmarshal(parser *confmap.Conf) error { + if parser == nil { + return nil + } + err := parser.Unmarshal(ec) + if err != nil { + return err + } + ec.enabledSetByUser = parser.IsSet("enabled") + return nil +} + +// EventsConfig provides config for oracledb events. +type EventsConfig struct { + DbServerQuerySample EventConfig `mapstructure:"db.server.query_sample"` + DbServerTopQuery EventConfig `mapstructure:"db.server.top_query"` +} + +func DefaultEventsConfig() EventsConfig { + return EventsConfig{ + DbServerQuerySample: EventConfig{ + Enabled: false, + }, + DbServerTopQuery: EventConfig{ + Enabled: false, + }, + } +} + // ResourceAttributeConfig provides common config for a particular resource attribute. type ResourceAttributeConfig struct { Enabled bool `mapstructure:"enabled"` @@ -209,6 +245,13 @@ type ResourceAttributeConfig struct { // If the list is not empty, metrics with matching resource attribute values will not be emitted. // MetricsInclude has higher priority than MetricsExclude. MetricsExclude []filter.Config `mapstructure:"metrics_exclude"` + // Experimental: EventsInclude defines a list of filters for attribute values. + // If the list is not empty, only events with matching resource attribute values will be emitted. + EventsInclude []filter.Config `mapstructure:"events_include"` + // Experimental: EventsExclude defines a list of filters for attribute values. + // If the list is not empty, events with matching resource attribute values will not be emitted. + // EventsInclude has higher priority than EventsExclude. + EventsExclude []filter.Config `mapstructure:"events_exclude"` enabledSetByUser bool } @@ -227,11 +270,15 @@ func (rac *ResourceAttributeConfig) Unmarshal(parser *confmap.Conf) error { // ResourceAttributesConfig provides config for oracledb resource attributes. type ResourceAttributesConfig struct { + HostName ResourceAttributeConfig `mapstructure:"host.name"` OracledbInstanceName ResourceAttributeConfig `mapstructure:"oracledb.instance.name"` } func DefaultResourceAttributesConfig() ResourceAttributesConfig { return ResourceAttributesConfig{ + HostName: ResourceAttributeConfig{ + Enabled: true, + }, OracledbInstanceName: ResourceAttributeConfig{ Enabled: true, }, @@ -250,3 +297,16 @@ func DefaultMetricsBuilderConfig() MetricsBuilderConfig { ResourceAttributes: DefaultResourceAttributesConfig(), } } + +// LogsBuilderConfig is a configuration for oracledb logs builder. +type LogsBuilderConfig struct { + Events EventsConfig `mapstructure:"events"` + ResourceAttributes ResourceAttributesConfig `mapstructure:"resource_attributes"` +} + +func DefaultLogsBuilderConfig() LogsBuilderConfig { + return LogsBuilderConfig{ + Events: DefaultEventsConfig(), + ResourceAttributes: DefaultResourceAttributesConfig(), + } +} diff --git a/receiver/oracledbreceiver/internal/metadata/generated_config_test.go b/receiver/oracledbreceiver/internal/metadata/generated_config_test.go index e60c8699ac745..e242130eb0ee2 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_config_test.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_config_test.go @@ -70,6 +70,7 @@ func TestMetricsBuilderConfig(t *testing.T) { OracledbUserRollbacks: MetricConfig{Enabled: true}, }, ResourceAttributes: ResourceAttributesConfig{ + HostName: ResourceAttributeConfig{Enabled: true}, OracledbInstanceName: ResourceAttributeConfig{Enabled: true}, }, }, @@ -121,6 +122,7 @@ func TestMetricsBuilderConfig(t *testing.T) { OracledbUserRollbacks: MetricConfig{Enabled: false}, }, ResourceAttributes: ResourceAttributesConfig{ + HostName: ResourceAttributeConfig{Enabled: false}, OracledbInstanceName: ResourceAttributeConfig{Enabled: false}, }, }, @@ -145,6 +147,16 @@ func loadMetricsBuilderConfig(t *testing.T, name string) MetricsBuilderConfig { return cfg } +func loadLogsBuilderConfig(t *testing.T, name string) LogsBuilderConfig { + cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) + require.NoError(t, err) + sub, err := cm.Sub(name) + require.NoError(t, err) + cfg := DefaultLogsBuilderConfig() + require.NoError(t, sub.Unmarshal(&cfg, confmap.WithIgnoreUnused())) + return cfg +} + func TestResourceAttributesConfig(t *testing.T) { tests := []struct { name string @@ -157,12 +169,14 @@ func TestResourceAttributesConfig(t *testing.T) { { name: "all_set", want: ResourceAttributesConfig{ + HostName: ResourceAttributeConfig{Enabled: true}, OracledbInstanceName: ResourceAttributeConfig{Enabled: true}, }, }, { name: "none_set", want: ResourceAttributesConfig{ + HostName: ResourceAttributeConfig{Enabled: false}, OracledbInstanceName: ResourceAttributeConfig{Enabled: false}, }, }, diff --git a/receiver/oracledbreceiver/internal/metadata/generated_logs.go b/receiver/oracledbreceiver/internal/metadata/generated_logs.go new file mode 100644 index 0000000000000..b1449b2111d78 --- /dev/null +++ b/receiver/oracledbreceiver/internal/metadata/generated_logs.go @@ -0,0 +1,259 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package metadata + +import ( + "context" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/filter" + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/plog" + "go.opentelemetry.io/collector/receiver" + "go.opentelemetry.io/otel/trace" +) + +type eventDbServerQuerySample struct { + data plog.LogRecordSlice // data buffer for generated log records. + config EventConfig // event config provided by user. +} + +func (e *eventDbServerQuerySample) recordEvent(ctx context.Context, timestamp pcommon.Timestamp, dbQueryTextAttributeValue string, dbSystemNameAttributeValue string, userNameAttributeValue string, clientAddressAttributeValue string, oracledbPlanHashValueAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbSidAttributeValue string, oracledbSerialAttributeValue string, oracledbProcessAttributeValue string, oracledbSchemanameAttributeValue string, oracledbProgramAttributeValue string, oracledbModuleAttributeValue string, oracledbStatusAttributeValue string, oracledbStateAttributeValue string, oracledbWaitClassAttributeValue string, oracledbEventAttributeValue string, oracledbObjectNameAttributeValue string, oracledbObjectTypeAttributeValue string, oracledbOsuserAttributeValue string, oracledbDurationSecAttributeValue float64) { + if !e.config.Enabled { + return + } + lr := e.data.AppendEmpty() + lr.SetEventName("db.server.query_sample") + lr.SetTimestamp(timestamp) + + if span := trace.SpanContextFromContext(ctx); span.IsValid() { + lr.SetTraceID(pcommon.TraceID(span.TraceID())) + lr.SetSpanID(pcommon.SpanID(span.SpanID())) + } + + lr.Attributes().PutStr("db.query.text", dbQueryTextAttributeValue) + lr.Attributes().PutStr("db.system.name", dbSystemNameAttributeValue) + lr.Attributes().PutStr("user.name", userNameAttributeValue) + lr.Attributes().PutStr("client.address", clientAddressAttributeValue) + lr.Attributes().PutStr("oracledb.plan_hash_value", oracledbPlanHashValueAttributeValue) + lr.Attributes().PutStr("oracledb.sql_id", oracledbSQLIDAttributeValue) + lr.Attributes().PutStr("oracledb.child_number", oracledbChildNumberAttributeValue) + lr.Attributes().PutStr("oracledb.sid", oracledbSidAttributeValue) + lr.Attributes().PutStr("oracledb.serial", oracledbSerialAttributeValue) + lr.Attributes().PutStr("oracledb.process", oracledbProcessAttributeValue) + lr.Attributes().PutStr("oracledb.schemaname", oracledbSchemanameAttributeValue) + lr.Attributes().PutStr("oracledb.program", oracledbProgramAttributeValue) + lr.Attributes().PutStr("oracledb.module", oracledbModuleAttributeValue) + lr.Attributes().PutStr("oracledb.status", oracledbStatusAttributeValue) + lr.Attributes().PutStr("oracledb.state", oracledbStateAttributeValue) + lr.Attributes().PutStr("oracledb.wait_class", oracledbWaitClassAttributeValue) + lr.Attributes().PutStr("oracledb.event", oracledbEventAttributeValue) + lr.Attributes().PutStr("oracledb.object_name", oracledbObjectNameAttributeValue) + lr.Attributes().PutStr("oracledb.object_type", oracledbObjectTypeAttributeValue) + lr.Attributes().PutStr("oracledb.osuser", oracledbOsuserAttributeValue) + lr.Attributes().PutDouble("oracledb.duration_sec", oracledbDurationSecAttributeValue) +} + +// emit appends recorded event data to a events slice and prepares it for recording another set of log records. +func (e *eventDbServerQuerySample) emit(lrs plog.LogRecordSlice) { + if e.config.Enabled && e.data.Len() > 0 { + e.data.MoveAndAppendTo(lrs) + } +} + +func newEventDbServerQuerySample(cfg EventConfig) eventDbServerQuerySample { + e := eventDbServerQuerySample{config: cfg} + if cfg.Enabled { + e.data = plog.NewLogRecordSlice() + } + return e +} + +type eventDbServerTopQuery struct { + data plog.LogRecordSlice // data buffer for generated log records. + config EventConfig // event config provided by user. +} + +func (e *eventDbServerTopQuery) recordEvent(ctx context.Context, timestamp pcommon.Timestamp, dbSystemNameAttributeValue string, dbServerNameAttributeValue string, dbQueryTextAttributeValue string, oracledbQueryPlanAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbApplicationWaitTimeAttributeValue float64, oracledbBufferGetsAttributeValue int64, oracledbClusterWaitTimeAttributeValue float64, oracledbConcurrencyWaitTimeAttributeValue float64, oracledbCPUTimeAttributeValue float64, oracledbDirectReadsAttributeValue int64, oracledbDirectWritesAttributeValue int64, oracledbDiskReadsAttributeValue int64, oracledbElapsedTimeAttributeValue float64, oracledbExecutionsAttributeValue int64, oracledbPhysicalReadBytesAttributeValue int64, oracledbPhysicalReadRequestsAttributeValue int64, oracledbPhysicalWriteBytesAttributeValue int64, oracledbPhysicalWriteRequestsAttributeValue int64, oracledbRowsProcessedAttributeValue int64, oracledbUserIoWaitTimeAttributeValue float64) { + if !e.config.Enabled { + return + } + lr := e.data.AppendEmpty() + lr.SetEventName("db.server.top_query") + lr.SetTimestamp(timestamp) + + if span := trace.SpanContextFromContext(ctx); span.IsValid() { + lr.SetTraceID(pcommon.TraceID(span.TraceID())) + lr.SetSpanID(pcommon.SpanID(span.SpanID())) + } + + lr.Attributes().PutStr("db.system.name", dbSystemNameAttributeValue) + lr.Attributes().PutStr("db.server.name", dbServerNameAttributeValue) + lr.Attributes().PutStr("db.query.text", dbQueryTextAttributeValue) + lr.Attributes().PutStr("oracledb.query_plan", oracledbQueryPlanAttributeValue) + lr.Attributes().PutStr("oracledb.sql_id", oracledbSQLIDAttributeValue) + lr.Attributes().PutStr("oracledb.child_number", oracledbChildNumberAttributeValue) + lr.Attributes().PutDouble("oracledb.application_wait_time", oracledbApplicationWaitTimeAttributeValue) + lr.Attributes().PutInt("oracledb.buffer_gets", oracledbBufferGetsAttributeValue) + lr.Attributes().PutDouble("oracledb.cluster_wait_time", oracledbClusterWaitTimeAttributeValue) + lr.Attributes().PutDouble("oracledb.concurrency_wait_time", oracledbConcurrencyWaitTimeAttributeValue) + lr.Attributes().PutDouble("oracledb.cpu_time", oracledbCPUTimeAttributeValue) + lr.Attributes().PutInt("oracledb.direct_reads", oracledbDirectReadsAttributeValue) + lr.Attributes().PutInt("oracledb.direct_writes", oracledbDirectWritesAttributeValue) + lr.Attributes().PutInt("oracledb.disk_reads", oracledbDiskReadsAttributeValue) + lr.Attributes().PutDouble("oracledb.elapsed_time", oracledbElapsedTimeAttributeValue) + lr.Attributes().PutInt("oracledb.executions", oracledbExecutionsAttributeValue) + lr.Attributes().PutInt("oracledb.physical_read_bytes", oracledbPhysicalReadBytesAttributeValue) + lr.Attributes().PutInt("oracledb.physical_read_requests", oracledbPhysicalReadRequestsAttributeValue) + lr.Attributes().PutInt("oracledb.physical_write_bytes", oracledbPhysicalWriteBytesAttributeValue) + lr.Attributes().PutInt("oracledb.physical_write_requests", oracledbPhysicalWriteRequestsAttributeValue) + lr.Attributes().PutInt("oracledb.rows_processed", oracledbRowsProcessedAttributeValue) + lr.Attributes().PutDouble("oracledb.user_io_wait_time", oracledbUserIoWaitTimeAttributeValue) +} + +// emit appends recorded event data to a events slice and prepares it for recording another set of log records. +func (e *eventDbServerTopQuery) emit(lrs plog.LogRecordSlice) { + if e.config.Enabled && e.data.Len() > 0 { + e.data.MoveAndAppendTo(lrs) + } +} + +func newEventDbServerTopQuery(cfg EventConfig) eventDbServerTopQuery { + e := eventDbServerTopQuery{config: cfg} + if cfg.Enabled { + e.data = plog.NewLogRecordSlice() + } + return e +} + +// LogsBuilder provides an interface for scrapers to report logs while taking care of all the transformations +// required to produce log representation defined in metadata and user config. +type LogsBuilder struct { + config LogsBuilderConfig // config of the logs builder. + logsBuffer plog.Logs + logRecordsBuffer plog.LogRecordSlice + buildInfo component.BuildInfo // contains version information. + resourceAttributeIncludeFilter map[string]filter.Filter + resourceAttributeExcludeFilter map[string]filter.Filter + eventDbServerQuerySample eventDbServerQuerySample + eventDbServerTopQuery eventDbServerTopQuery +} + +// LogBuilderOption applies changes to default logs builder. +type LogBuilderOption interface { + apply(*LogsBuilder) +} + +func NewLogsBuilder(lbc LogsBuilderConfig, settings receiver.Settings) *LogsBuilder { + lb := &LogsBuilder{ + config: lbc, + logsBuffer: plog.NewLogs(), + logRecordsBuffer: plog.NewLogRecordSlice(), + buildInfo: settings.BuildInfo, + eventDbServerQuerySample: newEventDbServerQuerySample(lbc.Events.DbServerQuerySample), + eventDbServerTopQuery: newEventDbServerTopQuery(lbc.Events.DbServerTopQuery), + resourceAttributeIncludeFilter: make(map[string]filter.Filter), + resourceAttributeExcludeFilter: make(map[string]filter.Filter), + } + if lbc.ResourceAttributes.HostName.EventsInclude != nil { + lb.resourceAttributeIncludeFilter["host.name"] = filter.CreateFilter(lbc.ResourceAttributes.HostName.EventsInclude) + } + if lbc.ResourceAttributes.HostName.EventsExclude != nil { + lb.resourceAttributeExcludeFilter["host.name"] = filter.CreateFilter(lbc.ResourceAttributes.HostName.EventsExclude) + } + if lbc.ResourceAttributes.OracledbInstanceName.EventsInclude != nil { + lb.resourceAttributeIncludeFilter["oracledb.instance.name"] = filter.CreateFilter(lbc.ResourceAttributes.OracledbInstanceName.EventsInclude) + } + if lbc.ResourceAttributes.OracledbInstanceName.EventsExclude != nil { + lb.resourceAttributeExcludeFilter["oracledb.instance.name"] = filter.CreateFilter(lbc.ResourceAttributes.OracledbInstanceName.EventsExclude) + } + + return lb +} + +// NewResourceBuilder returns a new resource builder that should be used to build a resource associated with for the emitted logs. +func (lb *LogsBuilder) NewResourceBuilder() *ResourceBuilder { + return NewResourceBuilder(lb.config.ResourceAttributes) +} + +// ResourceLogsOption applies changes to provided resource logs. +type ResourceLogsOption interface { + apply(plog.ResourceLogs) +} + +type resourceLogsOptionFunc func(plog.ResourceLogs) + +func (rlof resourceLogsOptionFunc) apply(rl plog.ResourceLogs) { + rlof(rl) +} + +// WithLogsResource sets the provided resource on the emitted ResourceLogs. +// It's recommended to use ResourceBuilder to create the resource. +func WithLogsResource(res pcommon.Resource) ResourceLogsOption { + return resourceLogsOptionFunc(func(rl plog.ResourceLogs) { + res.CopyTo(rl.Resource()) + }) +} + +// AppendLogRecord adds a log record to the logs builder. +func (lb *LogsBuilder) AppendLogRecord(lr plog.LogRecord) { + lr.MoveTo(lb.logRecordsBuffer.AppendEmpty()) +} + +// EmitForResource saves all the generated logs under a new resource and updates the internal state to be ready for +// recording another set of log records as part of another resource. This function can be helpful when one scraper +// needs to emit logs from several resources. Otherwise calling this function is not required, +// just `Emit` function can be called instead. +// Resource attributes should be provided as ResourceLogsOption arguments. +func (lb *LogsBuilder) EmitForResource(options ...ResourceLogsOption) { + rl := plog.NewResourceLogs() + ils := rl.ScopeLogs().AppendEmpty() + ils.Scope().SetName(ScopeName) + ils.Scope().SetVersion(lb.buildInfo.Version) + lb.eventDbServerQuerySample.emit(ils.LogRecords()) + lb.eventDbServerTopQuery.emit(ils.LogRecords()) + + for _, op := range options { + op.apply(rl) + } + + if lb.logRecordsBuffer.Len() > 0 { + lb.logRecordsBuffer.MoveAndAppendTo(ils.LogRecords()) + lb.logRecordsBuffer = plog.NewLogRecordSlice() + } + + for attr, filter := range lb.resourceAttributeIncludeFilter { + if val, ok := rl.Resource().Attributes().Get(attr); ok && !filter.Matches(val.AsString()) { + return + } + } + for attr, filter := range lb.resourceAttributeExcludeFilter { + if val, ok := rl.Resource().Attributes().Get(attr); ok && filter.Matches(val.AsString()) { + return + } + } + + if ils.LogRecords().Len() > 0 { + rl.MoveTo(lb.logsBuffer.ResourceLogs().AppendEmpty()) + } +} + +// Emit returns all the logs accumulated by the logs builder and updates the internal state to be ready for +// recording another set of logs. This function will be responsible for applying all the transformations required to +// produce logs representation defined in metadata and user config. +func (lb *LogsBuilder) Emit(options ...ResourceLogsOption) plog.Logs { + lb.EmitForResource(options...) + logs := lb.logsBuffer + lb.logsBuffer = plog.NewLogs() + return logs +} + +// RecordDbServerQuerySampleEvent adds a log record of db.server.query_sample event. +func (lb *LogsBuilder) RecordDbServerQuerySampleEvent(ctx context.Context, timestamp pcommon.Timestamp, dbQueryTextAttributeValue string, dbSystemNameAttributeValue string, userNameAttributeValue string, clientAddressAttributeValue string, oracledbPlanHashValueAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbSidAttributeValue string, oracledbSerialAttributeValue string, oracledbProcessAttributeValue string, oracledbSchemanameAttributeValue string, oracledbProgramAttributeValue string, oracledbModuleAttributeValue string, oracledbStatusAttributeValue string, oracledbStateAttributeValue string, oracledbWaitClassAttributeValue string, oracledbEventAttributeValue string, oracledbObjectNameAttributeValue string, oracledbObjectTypeAttributeValue string, oracledbOsuserAttributeValue string, oracledbDurationSecAttributeValue float64) { + lb.eventDbServerQuerySample.recordEvent(ctx, timestamp, dbQueryTextAttributeValue, dbSystemNameAttributeValue, userNameAttributeValue, clientAddressAttributeValue, oracledbPlanHashValueAttributeValue, oracledbSQLIDAttributeValue, oracledbChildNumberAttributeValue, oracledbSidAttributeValue, oracledbSerialAttributeValue, oracledbProcessAttributeValue, oracledbSchemanameAttributeValue, oracledbProgramAttributeValue, oracledbModuleAttributeValue, oracledbStatusAttributeValue, oracledbStateAttributeValue, oracledbWaitClassAttributeValue, oracledbEventAttributeValue, oracledbObjectNameAttributeValue, oracledbObjectTypeAttributeValue, oracledbOsuserAttributeValue, oracledbDurationSecAttributeValue) +} + +// RecordDbServerTopQueryEvent adds a log record of db.server.top_query event. +func (lb *LogsBuilder) RecordDbServerTopQueryEvent(ctx context.Context, timestamp pcommon.Timestamp, dbSystemNameAttributeValue string, dbServerNameAttributeValue string, dbQueryTextAttributeValue string, oracledbQueryPlanAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbApplicationWaitTimeAttributeValue float64, oracledbBufferGetsAttributeValue int64, oracledbClusterWaitTimeAttributeValue float64, oracledbConcurrencyWaitTimeAttributeValue float64, oracledbCPUTimeAttributeValue float64, oracledbDirectReadsAttributeValue int64, oracledbDirectWritesAttributeValue int64, oracledbDiskReadsAttributeValue int64, oracledbElapsedTimeAttributeValue float64, oracledbExecutionsAttributeValue int64, oracledbPhysicalReadBytesAttributeValue int64, oracledbPhysicalReadRequestsAttributeValue int64, oracledbPhysicalWriteBytesAttributeValue int64, oracledbPhysicalWriteRequestsAttributeValue int64, oracledbRowsProcessedAttributeValue int64, oracledbUserIoWaitTimeAttributeValue float64) { + lb.eventDbServerTopQuery.recordEvent(ctx, timestamp, dbSystemNameAttributeValue, dbServerNameAttributeValue, dbQueryTextAttributeValue, oracledbQueryPlanAttributeValue, oracledbSQLIDAttributeValue, oracledbChildNumberAttributeValue, oracledbApplicationWaitTimeAttributeValue, oracledbBufferGetsAttributeValue, oracledbClusterWaitTimeAttributeValue, oracledbConcurrencyWaitTimeAttributeValue, oracledbCPUTimeAttributeValue, oracledbDirectReadsAttributeValue, oracledbDirectWritesAttributeValue, oracledbDiskReadsAttributeValue, oracledbElapsedTimeAttributeValue, oracledbExecutionsAttributeValue, oracledbPhysicalReadBytesAttributeValue, oracledbPhysicalReadRequestsAttributeValue, oracledbPhysicalWriteBytesAttributeValue, oracledbPhysicalWriteRequestsAttributeValue, oracledbRowsProcessedAttributeValue, oracledbUserIoWaitTimeAttributeValue) +} diff --git a/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go b/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go new file mode 100644 index 0000000000000..a41cff94246ac --- /dev/null +++ b/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go @@ -0,0 +1,310 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package metadata + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/plog" + "go.opentelemetry.io/collector/receiver/receivertest" + "go.opentelemetry.io/otel/trace" + "go.uber.org/zap" + "go.uber.org/zap/zaptest/observer" +) + +type eventsTestDataSet int + +const ( + eventTestDataSetDefault eventsTestDataSet = iota + eventTestDataSetAll + eventTestDataSetNone +) + +func TestLogsBuilderAppendLogRecord(t *testing.T) { + observedZapCore, _ := observer.New(zap.WarnLevel) + settings := receivertest.NewNopSettings(receivertest.NopType) + settings.Logger = zap.New(observedZapCore) + lb := NewLogsBuilder(loadLogsBuilderConfig(t, "all_set"), settings) + + rb := lb.NewResourceBuilder() + rb.SetHostName("host.name-val") + rb.SetOracledbInstanceName("oracledb.instance.name-val") + res := rb.Emit() + + // append the first log record + lr := plog.NewLogRecord() + lr.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) + lr.Attributes().PutStr("type", "log") + lr.Body().SetStr("the first log record") + + // append the second log record + lr2 := plog.NewLogRecord() + lr2.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) + lr2.Attributes().PutStr("type", "event") + lr2.Body().SetStr("the second log record") + + lb.AppendLogRecord(lr) + lb.AppendLogRecord(lr2) + + logs := lb.Emit(WithLogsResource(res)) + assert.Equal(t, 1, logs.ResourceLogs().Len()) + + rl := logs.ResourceLogs().At(0) + assert.Equal(t, 1, rl.ScopeLogs().Len()) + + sl := rl.ScopeLogs().At(0) + assert.Equal(t, ScopeName, sl.Scope().Name()) + assert.Equal(t, lb.buildInfo.Version, sl.Scope().Version()) + + assert.Equal(t, 2, sl.LogRecords().Len()) + + attrVal, ok := sl.LogRecords().At(0).Attributes().Get("type") + assert.True(t, ok) + assert.Equal(t, "log", attrVal.Str()) + + assert.Equal(t, pcommon.ValueTypeStr, sl.LogRecords().At(0).Body().Type()) + assert.Equal(t, "the first log record", sl.LogRecords().At(0).Body().Str()) + + attrVal, ok = sl.LogRecords().At(1).Attributes().Get("type") + assert.True(t, ok) + assert.Equal(t, "event", attrVal.Str()) + + assert.Equal(t, pcommon.ValueTypeStr, sl.LogRecords().At(1).Body().Type()) + assert.Equal(t, "the second log record", sl.LogRecords().At(1).Body().Str()) +} +func TestLogsBuilder(t *testing.T) { + tests := []struct { + name string + eventsSet eventsTestDataSet + resAttrsSet eventsTestDataSet + expectEmpty bool + }{ + { + name: "default", + }, + { + name: "all_set", + eventsSet: eventTestDataSetAll, + resAttrsSet: eventTestDataSetAll, + }, + { + name: "none_set", + eventsSet: eventTestDataSetNone, + resAttrsSet: eventTestDataSetNone, + expectEmpty: true, + }, + { + name: "filter_set_include", + resAttrsSet: eventTestDataSetAll, + }, + { + name: "filter_set_exclude", + resAttrsSet: eventTestDataSetAll, + expectEmpty: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + timestamp := pcommon.Timestamp(1_000_001_000) + traceID := [16]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} + spanID := [8]byte{0, 1, 2, 3, 4, 5, 6, 7} + ctx := trace.ContextWithSpanContext(context.Background(), trace.NewSpanContext(trace.SpanContextConfig{ + TraceID: trace.TraceID(traceID), + SpanID: trace.SpanID(spanID), + TraceFlags: trace.FlagsSampled, + })) + observedZapCore, observedLogs := observer.New(zap.WarnLevel) + settings := receivertest.NewNopSettings(receivertest.NopType) + settings.Logger = zap.New(observedZapCore) + lb := NewLogsBuilder(loadLogsBuilderConfig(t, tt.name), settings) + + expectedWarnings := 0 + + assert.Equal(t, expectedWarnings, observedLogs.Len()) + + defaultEventsCount := 0 + allEventsCount := 0 + + allEventsCount++ + lb.RecordDbServerQuerySampleEvent(ctx, timestamp, "db.query.text-val", "db.system.name-val", "user.name-val", "client.address-val", "oracledb.plan_hash_value-val", "oracledb.sql_id-val", "oracledb.child_number-val", "oracledb.sid-val", "oracledb.serial-val", "oracledb.process-val", "oracledb.schemaname-val", "oracledb.program-val", "oracledb.module-val", "oracledb.status-val", "oracledb.state-val", "oracledb.wait_class-val", "oracledb.event-val", "oracledb.object_name-val", "oracledb.object_type-val", "oracledb.osuser-val", 21.100000) + + allEventsCount++ + lb.RecordDbServerTopQueryEvent(ctx, timestamp, "db.system.name-val", "db.server.name-val", "db.query.text-val", "oracledb.query_plan-val", "oracledb.sql_id-val", "oracledb.child_number-val", 30.100000, 20, 26.100000, 30.100000, 17.100000, 21, 22, 19, 21.100000, 19, 28, 31, 29, 32, 23, 26.100000) + + rb := lb.NewResourceBuilder() + rb.SetHostName("host.name-val") + rb.SetOracledbInstanceName("oracledb.instance.name-val") + res := rb.Emit() + logs := lb.Emit(WithLogsResource(res)) + + if tt.expectEmpty || ((tt.name == "default" || tt.name == "filter_set_include") && defaultEventsCount == 0) { + assert.Equal(t, 0, logs.ResourceLogs().Len()) + return + } + + assert.Equal(t, 1, logs.ResourceLogs().Len()) + rl := logs.ResourceLogs().At(0) + assert.Equal(t, res, rl.Resource()) + assert.Equal(t, 1, rl.ScopeLogs().Len()) + lrs := rl.ScopeLogs().At(0).LogRecords() + if tt.eventsSet == eventTestDataSetDefault { + assert.Equal(t, defaultEventsCount, lrs.Len()) + } + if tt.eventsSet == eventTestDataSetAll { + assert.Equal(t, allEventsCount, lrs.Len()) + } + validatedEvents := make(map[string]bool) + for i := 0; i < lrs.Len(); i++ { + switch lrs.At(i).EventName() { + case "db.server.query_sample": + assert.False(t, validatedEvents["db.server.query_sample"], "Found a duplicate in the events slice: db.server.query_sample") + validatedEvents["db.server.query_sample"] = true + lr := lrs.At(i) + assert.Equal(t, timestamp, lr.Timestamp()) + assert.Equal(t, pcommon.TraceID(traceID), lr.TraceID()) + assert.Equal(t, pcommon.SpanID(spanID), lr.SpanID()) + attrVal, ok := lr.Attributes().Get("db.query.text") + assert.True(t, ok) + assert.Equal(t, "db.query.text-val", attrVal.Str()) + 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("user.name") + assert.True(t, ok) + assert.Equal(t, "user.name-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("client.address") + assert.True(t, ok) + assert.Equal(t, "client.address-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.plan_hash_value") + assert.True(t, ok) + assert.Equal(t, "oracledb.plan_hash_value-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.sql_id") + assert.True(t, ok) + assert.Equal(t, "oracledb.sql_id-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.child_number") + assert.True(t, ok) + assert.Equal(t, "oracledb.child_number-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.sid") + assert.True(t, ok) + assert.Equal(t, "oracledb.sid-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.serial") + assert.True(t, ok) + assert.Equal(t, "oracledb.serial-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.process") + assert.True(t, ok) + assert.Equal(t, "oracledb.process-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.schemaname") + assert.True(t, ok) + assert.Equal(t, "oracledb.schemaname-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.program") + assert.True(t, ok) + assert.Equal(t, "oracledb.program-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.module") + assert.True(t, ok) + assert.Equal(t, "oracledb.module-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.status") + assert.True(t, ok) + assert.Equal(t, "oracledb.status-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.state") + assert.True(t, ok) + assert.Equal(t, "oracledb.state-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.wait_class") + assert.True(t, ok) + assert.Equal(t, "oracledb.wait_class-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.event") + assert.True(t, ok) + assert.Equal(t, "oracledb.event-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.object_name") + assert.True(t, ok) + assert.Equal(t, "oracledb.object_name-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.object_type") + assert.True(t, ok) + assert.Equal(t, "oracledb.object_type-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.osuser") + assert.True(t, ok) + assert.Equal(t, "oracledb.osuser-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.duration_sec") + assert.True(t, ok) + assert.Equal(t, 21.100000, attrVal.Double()) + 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 + lr := lrs.At(i) + assert.Equal(t, timestamp, lr.Timestamp()) + assert.Equal(t, pcommon.TraceID(traceID), lr.TraceID()) + assert.Equal(t, pcommon.SpanID(spanID), lr.SpanID()) + 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("db.server.name") + assert.True(t, ok) + assert.Equal(t, "db.server.name-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("db.query.text") + assert.True(t, ok) + assert.Equal(t, "db.query.text-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.query_plan") + assert.True(t, ok) + assert.Equal(t, "oracledb.query_plan-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.sql_id") + assert.True(t, ok) + assert.Equal(t, "oracledb.sql_id-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.child_number") + assert.True(t, ok) + assert.Equal(t, "oracledb.child_number-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.application_wait_time") + assert.True(t, ok) + assert.Equal(t, 30.100000, attrVal.Double()) + attrVal, ok = lr.Attributes().Get("oracledb.buffer_gets") + assert.True(t, ok) + assert.EqualValues(t, 20, attrVal.Int()) + attrVal, ok = lr.Attributes().Get("oracledb.cluster_wait_time") + assert.True(t, ok) + assert.Equal(t, 26.100000, attrVal.Double()) + attrVal, ok = lr.Attributes().Get("oracledb.concurrency_wait_time") + assert.True(t, ok) + assert.Equal(t, 30.100000, attrVal.Double()) + attrVal, ok = lr.Attributes().Get("oracledb.cpu_time") + assert.True(t, ok) + assert.Equal(t, 17.100000, attrVal.Double()) + attrVal, ok = lr.Attributes().Get("oracledb.direct_reads") + assert.True(t, ok) + assert.EqualValues(t, 21, attrVal.Int()) + attrVal, ok = lr.Attributes().Get("oracledb.direct_writes") + assert.True(t, ok) + assert.EqualValues(t, 22, attrVal.Int()) + attrVal, ok = lr.Attributes().Get("oracledb.disk_reads") + assert.True(t, ok) + assert.EqualValues(t, 19, attrVal.Int()) + attrVal, ok = lr.Attributes().Get("oracledb.elapsed_time") + assert.True(t, ok) + assert.Equal(t, 21.100000, attrVal.Double()) + attrVal, ok = lr.Attributes().Get("oracledb.executions") + assert.True(t, ok) + assert.EqualValues(t, 19, attrVal.Int()) + attrVal, ok = lr.Attributes().Get("oracledb.physical_read_bytes") + assert.True(t, ok) + assert.EqualValues(t, 28, attrVal.Int()) + attrVal, ok = lr.Attributes().Get("oracledb.physical_read_requests") + assert.True(t, ok) + assert.EqualValues(t, 31, attrVal.Int()) + attrVal, ok = lr.Attributes().Get("oracledb.physical_write_bytes") + assert.True(t, ok) + assert.EqualValues(t, 29, attrVal.Int()) + attrVal, ok = lr.Attributes().Get("oracledb.physical_write_requests") + assert.True(t, ok) + assert.EqualValues(t, 32, attrVal.Int()) + attrVal, ok = lr.Attributes().Get("oracledb.rows_processed") + assert.True(t, ok) + assert.EqualValues(t, 23, attrVal.Int()) + attrVal, ok = lr.Attributes().Get("oracledb.user_io_wait_time") + assert.True(t, ok) + assert.Equal(t, 26.100000, attrVal.Double()) + } + } + }) + } +} diff --git a/receiver/oracledbreceiver/internal/metadata/generated_metrics.go b/receiver/oracledbreceiver/internal/metadata/generated_metrics.go index 1c602ce202d08..f8093c3954cba 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_metrics.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_metrics.go @@ -2378,6 +2378,12 @@ func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, opt resourceAttributeIncludeFilter: make(map[string]filter.Filter), resourceAttributeExcludeFilter: make(map[string]filter.Filter), } + if mbc.ResourceAttributes.HostName.MetricsInclude != nil { + mb.resourceAttributeIncludeFilter["host.name"] = filter.CreateFilter(mbc.ResourceAttributes.HostName.MetricsInclude) + } + if mbc.ResourceAttributes.HostName.MetricsExclude != nil { + mb.resourceAttributeExcludeFilter["host.name"] = filter.CreateFilter(mbc.ResourceAttributes.HostName.MetricsExclude) + } if mbc.ResourceAttributes.OracledbInstanceName.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["oracledb.instance.name"] = filter.CreateFilter(mbc.ResourceAttributes.OracledbInstanceName.MetricsInclude) } diff --git a/receiver/oracledbreceiver/internal/metadata/generated_metrics_test.go b/receiver/oracledbreceiver/internal/metadata/generated_metrics_test.go index a4b2cefc10ef7..a6d4082e5bdff 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_metrics_test.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_metrics_test.go @@ -217,6 +217,7 @@ func TestMetricsBuilder(t *testing.T) { mb.RecordOracledbUserRollbacksDataPoint(ts, "1") rb := mb.NewResourceBuilder() + rb.SetHostName("host.name-val") rb.SetOracledbInstanceName("oracledb.instance.name-val") res := rb.Emit() metrics := mb.Emit(WithResource(res)) diff --git a/receiver/oracledbreceiver/internal/metadata/generated_resource.go b/receiver/oracledbreceiver/internal/metadata/generated_resource.go index 77f4561fbb3f0..805f84f280c0c 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_resource.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_resource.go @@ -21,6 +21,13 @@ func NewResourceBuilder(rac ResourceAttributesConfig) *ResourceBuilder { } } +// SetHostName sets provided value as "host.name" attribute. +func (rb *ResourceBuilder) SetHostName(val string) { + if rb.config.HostName.Enabled { + rb.res.Attributes().PutStr("host.name", val) + } +} + // SetOracledbInstanceName sets provided value as "oracledb.instance.name" attribute. func (rb *ResourceBuilder) SetOracledbInstanceName(val string) { if rb.config.OracledbInstanceName.Enabled { diff --git a/receiver/oracledbreceiver/internal/metadata/generated_resource_test.go b/receiver/oracledbreceiver/internal/metadata/generated_resource_test.go index b41c9a4668e65..7995f73df8462 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_resource_test.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_resource_test.go @@ -13,6 +13,7 @@ func TestResourceBuilder(t *testing.T) { t.Run(tt, func(t *testing.T) { cfg := loadResourceAttributesConfig(t, tt) rb := NewResourceBuilder(cfg) + rb.SetHostName("host.name-val") rb.SetOracledbInstanceName("oracledb.instance.name-val") res := rb.Emit() @@ -20,9 +21,9 @@ func TestResourceBuilder(t *testing.T) { switch tt { case "default": - assert.Equal(t, 1, res.Attributes().Len()) + assert.Equal(t, 2, res.Attributes().Len()) case "all_set": - assert.Equal(t, 1, res.Attributes().Len()) + assert.Equal(t, 2, res.Attributes().Len()) case "none_set": assert.Equal(t, 0, res.Attributes().Len()) return @@ -30,7 +31,12 @@ func TestResourceBuilder(t *testing.T) { assert.Failf(t, "unexpected test case: %s", tt) } - val, ok := res.Attributes().Get("oracledb.instance.name") + val, ok := res.Attributes().Get("host.name") + assert.True(t, ok) + if ok { + assert.Equal(t, "host.name-val", val.Str()) + } + val, ok = res.Attributes().Get("oracledb.instance.name") assert.True(t, ok) if ok { assert.Equal(t, "oracledb.instance.name-val", val.Str()) diff --git a/receiver/oracledbreceiver/internal/metadata/generated_status.go b/receiver/oracledbreceiver/internal/metadata/generated_status.go index 0ec80a0a3d764..e1e83752f623a 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_status.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_status.go @@ -12,5 +12,6 @@ var ( ) const ( + LogsStability = component.StabilityLevelDevelopment MetricsStability = component.StabilityLevelAlpha ) diff --git a/receiver/oracledbreceiver/internal/metadata/testdata/config.yaml b/receiver/oracledbreceiver/internal/metadata/testdata/config.yaml index bfeaebecaa0e0..13a19e6fe9d70 100644 --- a/receiver/oracledbreceiver/internal/metadata/testdata/config.yaml +++ b/receiver/oracledbreceiver/internal/metadata/testdata/config.yaml @@ -83,7 +83,14 @@ all_set: enabled: true oracledb.user_rollbacks: enabled: true + events: + db.server.query_sample: + enabled: true + db.server.top_query: + enabled: true resource_attributes: + host.name: + enabled: true oracledb.instance.name: enabled: true none_set: @@ -170,18 +177,41 @@ none_set: enabled: false oracledb.user_rollbacks: enabled: false + events: + db.server.query_sample: + enabled: false + db.server.top_query: + enabled: false resource_attributes: + host.name: + enabled: false oracledb.instance.name: enabled: false filter_set_include: resource_attributes: + host.name: + enabled: true + metrics_include: + - regexp: ".*" + events_include: + - regexp: ".*" oracledb.instance.name: enabled: true metrics_include: - regexp: ".*" + events_include: + - regexp: ".*" filter_set_exclude: resource_attributes: + host.name: + enabled: true + metrics_exclude: + - strict: "host.name-val" + events_exclude: + - strict: "host.name-val" oracledb.instance.name: enabled: true metrics_exclude: - strict: "oracledb.instance.name-val" + events_exclude: + - strict: "oracledb.instance.name-val" diff --git a/receiver/oracledbreceiver/metadata.yaml b/receiver/oracledbreceiver/metadata.yaml index cf1987d8cd492..0479d15746125 100644 --- a/receiver/oracledbreceiver/metadata.yaml +++ b/receiver/oracledbreceiver/metadata.yaml @@ -4,6 +4,7 @@ status: class: receiver stability: alpha: [metrics] + development: [logs] distributions: [contrib] codeowners: active: [dmitryax, crobert-1, atoulme] @@ -13,6 +14,10 @@ resource_attributes: description: The name of the instance that data is coming from. enabled: true type: string + host.name: + description: The host name of Oracle Server + enabled: true + type: string attributes: session_status: @@ -24,7 +29,178 @@ attributes: tablespace_name: description: Tablespace name type: string + # attributes for events + ## top query + db.query.text: + description: The text of the database query being executed. + type: string + oracledb.query_plan: + description: The query execution plan used by the SQL Server. + type: string + oracledb.sql_id: + description: The SQL ID of the query. + type: string + oracledb.child_number: + description: The child number of the query. + type: string + oracledb.application_wait_time: + description: The total time (in seconds) a query spent waiting on the application before it could proceed with execution (reporting delta). + type: double + oracledb.buffer_gets: + description: Number of logical reads (i.e., buffer cache accesses) performed by a query (reporting delta). + type: int + oracledb.cluster_wait_time: + description: Total time (in seconds) that a query waited due to Oracle Real Application Clusters (RAC) coordination (reporting delta). + type: double + oracledb.concurrency_wait_time: + description: Total time (in seconds) a query spent waiting on concurrency-related events (reporting delta). + type: double + oracledb.cpu_time: + description: Total time (in seconds) that the CPU spent actively processing a query, excluding time spent waiting (reporting delta). + type: double + oracledb.direct_reads: + description: The number of direct path reads performed by a query — i.e., data blocks read directly from disk into the session’s memory (reporting delta). + type: int + oracledb.direct_writes: + description: The number of direct path write operations, where data is written directly to disk from user memory (reporting delta). + type: int + oracledb.disk_reads: + description: The number of physical reads a query performs — that is, the number of data blocks read from disk (reporting delta). + type: int + oracledb.elapsed_time: + description: The total time (in seconds) taken by a query from start to finish, including CPU time and all types of waits (reporting delta). + type: double + oracledb.executions: + description: The number of times a specific SQL query has been executed (reporting delta). + type: int + oracledb.physical_read_bytes: + description: The total number of bytes read from disk by a query (reporting delta). + type: int + oracledb.physical_read_requests: + description: The number of physical I/O read operations performed by a query (reporting delta). + type: int + oracledb.physical_write_bytes: + description: The total number of bytes written to disk by a query (reporting delta). + type: int + oracledb.physical_write_requests: + description: The number of times a query requested to write data to disk (reporting delta). + type: int + oracledb.rows_processed: + description: The total number of rows that a query has read, returned, or affected during its execution (reporting delta). + type: int + oracledb.user_io_wait_time: + description: The total time (in seconds) a query spent waiting for user I/O operations—such as reading or writing data to disk or network file systems (reporting delta). + type: double + db.server.name: + description: The name of the server hosting the database. + type: string + db.system.name: + description: The database management system (DBMS) product as identified by the client instrumentation. + type: string + oracledb.plan_hash_value: + description: Binary hash value calculated on the query execution plan and used to identify similar query execution plans, reported in the HEX format. + type: string + client.address: + description: Identifies the name of the machine (host) from which the database client is connecting to the Oracle database. + type: string + oracledb.sid: + description: ID of the Oracle Server session. + type: string + oracledb.serial: + description: Serial number associated with a session. + type: string + oracledb.process: + description: The operating system process ID (PID) associated with a session. + type: string + user.name: + description: Database user name under which a session is connected to + type: string + oracledb.schemaname: + description: Oracle schema under which SQL statements are being executed + type: string + oracledb.program: + description: Name of the client program or tool that initiated the Oracle database session. + type: string + oracledb.module: + description: Logical module name of the client application that initiated a query or session. + type: string + oracledb.status: + description: Execution state or result of a database query or session. + type: string + oracledb.state: + description: Current state of the query or the session executing it. + type: string + oracledb.wait_class: + description: The category of wait events a query or session is currently experiencing in Oracle Database. + type: string + oracledb.event: + description: The specific wait event that a query or session is currently experiencing. + type: string + oracledb.object_name: + description: Name of the database object that a query is accessing. + type: string + oracledb.object_type: + description: Type of the database object that a query is accessing. + type: string + oracledb.osuser: + description: Name of the operating system user that initiated or is running the Oracle database session. + type: string + oracledb.duration_sec: + description: Total time taken by a database query to execute. + type: double +events: + db.server.top_query: + enabled: false + description: top query + attributes: + - db.system.name + - db.server.name + - db.query.text + - oracledb.query_plan + - oracledb.sql_id + - oracledb.child_number + - oracledb.application_wait_time + - oracledb.buffer_gets + - oracledb.cluster_wait_time + - oracledb.concurrency_wait_time + - oracledb.cpu_time + - oracledb.direct_reads + - oracledb.direct_writes + - oracledb.disk_reads + - oracledb.elapsed_time + - oracledb.executions + - oracledb.physical_read_bytes + - oracledb.physical_read_requests + - oracledb.physical_write_bytes + - oracledb.physical_write_requests + - oracledb.rows_processed + - oracledb.user_io_wait_time + db.server.query_sample: + enabled: false + description: sample query + attributes: + - db.query.text + - db.system.name + - user.name + - client.address + - oracledb.plan_hash_value + - oracledb.sql_id + - oracledb.child_number + - oracledb.sid + - oracledb.serial + - oracledb.process + - oracledb.schemaname + - oracledb.program + - oracledb.module + - oracledb.status + - oracledb.state + - oracledb.wait_class + - oracledb.event + - oracledb.object_name + - oracledb.object_type + - oracledb.osuser + - oracledb.duration_sec metrics: oracledb.cpu_time: description: Cumulative CPU time, in seconds @@ -386,4 +562,4 @@ metrics: monotonic: true value_type: int input_type: string - unit: "{executions}" + unit: "{executions}" \ No newline at end of file diff --git a/receiver/oracledbreceiver/obfuscate.go b/receiver/oracledbreceiver/obfuscate.go new file mode 100644 index 0000000000000..460390fb05248 --- /dev/null +++ b/receiver/oracledbreceiver/obfuscate.go @@ -0,0 +1,40 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2016-present Datadog, Inc. + +// source: https://github.com/DataDog/datadog-agent/blob/main/pkg/collector/python/datadog_agent.go + +package oracledbreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/oracledbreceiver" + +import ( + "sync" + + "github.com/DataDog/datadog-agent/pkg/obfuscate" +) + +var ( + obfuscator *obfuscate.Obfuscator + obfuscatorLoader sync.Once +) + +// lazyInitObfuscator initializes the obfuscator the first time it is used. +func lazyInitObfuscator() *obfuscate.Obfuscator { + obfuscatorLoader.Do(func() { + obfuscator = obfuscate.NewObfuscator(obfuscate.Config{}) + }) + return obfuscator +} + +// ObfuscateSQL obfuscates the provided SQL query, writing the error into errResult if the operation fails +func ObfuscateSQL(rawQuery string) (string, error) { + obfuscatedQuery, err := lazyInitObfuscator().ObfuscateSQLStringWithOptions(rawQuery, &obfuscate.SQLConfig{DBMS: "oracle"}) + if err != nil { + return "", err + } + + return obfuscatedQuery.Query, nil +} diff --git a/receiver/oracledbreceiver/obfuscate_test.go b/receiver/oracledbreceiver/obfuscate_test.go new file mode 100644 index 0000000000000..2a83ddbdbf971 --- /dev/null +++ b/receiver/oracledbreceiver/obfuscate_test.go @@ -0,0 +1,30 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package oracledbreceiver + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestObfuscateSQL(t *testing.T) { + expected := `SELECT e.employee_id, e.first_name, e.last_name, e.department_id, s.salary, d.department_name FROM employees e INNER JOIN ( SELECT department_id FROM employees GROUP BY department_id HAVING COUNT ( employee_id ) > ? ) ON e.department_id = subquery.department_id INNER JOIN salaries s ON e.employee_id = s.employee_id INNER JOIN departments d ON e.department_id = d.department_id WHERE s.salary > ? AND d.department_name LIKE ? ORDER BY e.salary DESC` + + origin := `SELECT e.employee_id, e.first_name, e.last_name, e.department_id, s.salary, d.department_name + FROM employees e + INNER JOIN + ( SELECT department_id FROM employees GROUP BY department_id HAVING COUNT(employee_id) > 10) AS subquery + ON e.department_id = subquery.department_id + INNER JOIN + salaries s ON e.employee_id = s.employee_id + INNER JOIN + departments d ON e.department_id = d.department_id + WHERE s.salary > 50000 + AND d.department_name LIKE 'IT%' + ORDER BY e.salary DESC;` + result, err := ObfuscateSQL(origin) + assert.NoError(t, err) + assert.Equal(t, expected, result) +} diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index 1cb845a682378..cc8f57bd1459d 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -6,12 +6,20 @@ package oracledbreceiver // import "github.com/open-telemetry/opentelemetry-coll import ( "context" "database/sql" + _ "embed" + "encoding/hex" + "encoding/json" + "errors" "fmt" + "sort" "strconv" + "strings" "time" + lru "github.com/hashicorp/golang-lru/v2" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/scraper" "go.opentelemetry.io/collector/scraper/scrapererror" @@ -57,6 +65,40 @@ const ( select um.TABLESPACE_NAME, um.USED_SPACE, um.TABLESPACE_SIZE, ts.BLOCK_SIZE FROM DBA_TABLESPACE_USAGE_METRICS um INNER JOIN DBA_TABLESPACES ts ON um.TABLESPACE_NAME = ts.TABLESPACE_NAME` + + dbTimeReferenceFormat = "2006-01-02 15:04:05" + sqlIDAttr = "SQL_ID" + childAddressAttr = "CHILD_ADDRESS" + childNumberAttr = "CHILD_NUMBER" + sqlTextAttr = "SQL_FULLTEXT" + dbSystemNameVal = "oracle" + + queryExecutionMetric = "EXECUTIONS" + elapsedTimeMetric = "ELAPSED_TIME" + cpuTimeMetric = "CPU_TIME" + applicationWaitTimeMetric = "APPLICATION_WAIT_TIME" + concurrencyWaitTimeMetric = "CONCURRENCY_WAIT_TIME" + userIoWaitTimeMetric = "USER_IO_WAIT_TIME" + clusterWaitTimeMetric = "CLUSTER_WAIT_TIME" + rowsProcessedMetric = "ROWS_PROCESSED" + bufferGetsMetric = "BUFFER_GETS" + physicalReadRequestsMetric = "PHYSICAL_READ_REQUESTS" + physicalWriteRequestsMetric = "PHYSICAL_WRITE_REQUESTS" + physicalReadBytesMetric = "PHYSICAL_READ_BYTES" + physicalWriteBytesMetric = "PHYSICAL_WRITE_BYTES" + queryDiskReadsMetric = "DISK_READS" + queryDirectReadsMetric = "DIRECT_READS" + queryDirectWritesMetric = "DIRECT_WRITES" +) + +var ( + + //go:embed templates/oracleQuerySampleSql.tmpl + samplesQuery string + //go:embed templates/oracleQueryMetricsAndTextSql.tmpl + oracleQueryMetricsSQL string + //go:embed templates/oracleQueryPlanSql.tmpl + oracleQueryPlanDataSQL string ) type dbProviderFunc func() (*sql.DB, error) @@ -68,19 +110,27 @@ type oracleScraper struct { tablespaceUsageClient dbClient systemResourceLimitsClient dbClient sessionCountClient dbClient + samplesQueryClient dbClient + oracleQueryMetricsClient dbClient + oraclePlanDataClient dbClient db *sql.DB clientProviderFunc clientProviderFunc mb *metadata.MetricsBuilder + lb *metadata.LogsBuilder dbProviderFunc dbProviderFunc logger *zap.Logger id component.ID instanceName string + hostName string scrapeCfg scraperhelper.ControllerConfig startTime pcommon.Timestamp metricsBuilderConfig metadata.MetricsBuilderConfig + logsBuilderConfig metadata.LogsBuilderConfig + metricCache *lru.Cache[string, map[string]int64] + topQueryCollectCfg TopQueryCollection } -func newScraper(metricsBuilder *metadata.MetricsBuilder, metricsBuilderConfig metadata.MetricsBuilderConfig, scrapeCfg scraperhelper.ControllerConfig, logger *zap.Logger, providerFunc dbProviderFunc, clientProviderFunc clientProviderFunc, instanceName string) (scraper.Metrics, error) { +func newScraper(metricsBuilder *metadata.MetricsBuilder, metricsBuilderConfig metadata.MetricsBuilderConfig, scrapeCfg scraperhelper.ControllerConfig, logger *zap.Logger, providerFunc dbProviderFunc, clientProviderFunc clientProviderFunc, instanceName string, hostName string) (scraper.Metrics, error) { s := &oracleScraper{ mb: metricsBuilder, metricsBuilderConfig: metricsBuilderConfig, @@ -89,10 +139,30 @@ func newScraper(metricsBuilder *metadata.MetricsBuilder, metricsBuilderConfig me dbProviderFunc: providerFunc, clientProviderFunc: clientProviderFunc, instanceName: instanceName, + hostName: hostName, } return scraper.NewMetrics(s.scrape, scraper.WithShutdown(s.shutdown), scraper.WithStart(s.start)) } +func newLogsScraper(logsBuilder *metadata.LogsBuilder, logsBuilderConfig metadata.LogsBuilderConfig, scrapeCfg scraperhelper.ControllerConfig, + logger *zap.Logger, providerFunc dbProviderFunc, clientProviderFunc clientProviderFunc, instanceName string, metricCache *lru.Cache[string, map[string]int64], + topQueryCollectCfg TopQueryCollection, hostName string, +) (scraper.Logs, error) { + s := &oracleScraper{ + lb: logsBuilder, + logsBuilderConfig: logsBuilderConfig, + scrapeCfg: scrapeCfg, + logger: logger, + dbProviderFunc: providerFunc, + clientProviderFunc: clientProviderFunc, + instanceName: instanceName, + metricCache: metricCache, + topQueryCollectCfg: topQueryCollectCfg, + hostName: hostName, + } + return scraper.NewLogs(s.scrapeLogs, scraper.WithShutdown(s.shutdown), scraper.WithStart(s.start)) +} + func (s *oracleScraper) start(context.Context, component.Host) error { s.startTime = pcommon.NewTimestampFromTime(time.Now()) var err error @@ -104,6 +174,7 @@ func (s *oracleScraper) start(context.Context, component.Host) error { s.sessionCountClient = s.clientProviderFunc(s.db, sessionCountSQL, s.logger) s.systemResourceLimitsClient = s.clientProviderFunc(s.db, systemResourceLimitsSQL, s.logger) s.tablespaceUsageClient = s.clientProviderFunc(s.db, tablespaceUsageSQL, s.logger) + s.samplesQueryClient = s.clientProviderFunc(s.db, samplesQuery, s.logger) return nil } @@ -422,6 +493,7 @@ func (s *oracleScraper) scrape(ctx context.Context) (pmetric.Metrics, error) { rb := s.mb.NewResourceBuilder() rb.SetOracledbInstanceName(s.instanceName) + rb.SetHostName(s.hostName) out := s.mb.Emit(metadata.WithResource(rb.Emit())) s.logger.Debug("Done scraping") if len(scrapeErrors) > 0 { @@ -430,6 +502,322 @@ func (s *oracleScraper) scrape(ctx context.Context) (pmetric.Metrics, error) { return out, nil } +type queryMetricCacheHit struct { + sqlID string + childNumber string + childAddress string + queryText string + metrics map[string]int64 +} + +func (s *oracleScraper) scrapeLogs(ctx context.Context) (plog.Logs, error) { + logs := plog.NewLogs() + var scrapeErrors []error + + if s.logsBuilderConfig.Events.DbServerTopQuery.Enabled { + topNLogs, topNCollectionErrors := s.collectTopNMetricData(ctx) + if topNCollectionErrors != nil { + scrapeErrors = append(scrapeErrors, topNCollectionErrors) + } else { + topNLogs.ResourceLogs().CopyTo(logs.ResourceLogs()) + } + } + + if s.logsBuilderConfig.Events.DbServerQuerySample.Enabled { + sampleLogs, samplesCollectionErrors := s.collectQuerySamples(ctx) + if samplesCollectionErrors != nil { + scrapeErrors = append(scrapeErrors, samplesCollectionErrors) + } else { + sampleLogs.ResourceLogs().MoveAndAppendTo(logs.ResourceLogs()) + } + } + + return logs, errors.Join(scrapeErrors...) +} + +func (s *oracleScraper) collectQuerySamples(ctx context.Context) (plog.Logs, error) { + const duration = "DURATION_SEC" + const event = "EVENT" + const hostName = "MACHINE" + const module = "MODULE" + const osUser = "OSUSER" + const objectName = "OBJECT_NAME" + const objectType = "OBJECT_TYPE" + const process = "PROCESS" + const program = "PROGRAM" + const planHashValue = "PLAN_HASH_VALUE" + const sqlID = "SQL_ID" + const schemaName = "SCHEMANAME" + const sqlChildNumber = "SQL_CHILD_NUMBER" + const sid = "SID" + const serialNumber = "SERIAL" + const status = "STATUS" + const state = "STATE" + const sqlText = "SQL_FULLTEXT" + const username = "USERNAME" + const waitclass = "WAIT_CLASS" + + var scrapeErrors []error + + dbClients := s.samplesQueryClient + timestamp := pcommon.NewTimestampFromTime(time.Now()) + + rows, err := dbClients.metricRows(ctx) + if err != nil { + scrapeErrors = append(scrapeErrors, fmt.Errorf("error executing %s: %w", samplesQuery, err)) + } + + rb := s.lb.NewResourceBuilder() + rb.SetOracledbInstanceName(s.instanceName) + rb.SetHostName(s.hostName) + + for _, row := range rows { + if row[sqlText] == "" { + continue + } + + obfuscatedSQL, err := ObfuscateSQL(row[sqlText]) + if err != nil { + s.logger.Error(fmt.Sprintf("oracleScraper failed updating this metric row: %s", err)) + continue + } + + queryPlanHashVal := hex.EncodeToString([]byte(row[planHashValue])) + + queryDuration, err := strconv.ParseFloat(row[duration], 64) + if err != nil { + scrapeErrors = append(scrapeErrors, fmt.Errorf("failed to parse int64 for Duration, value was %s: %w", row[duration], err)) + } + + s.lb.RecordDbServerQuerySampleEvent(ctx, timestamp, obfuscatedSQL, dbSystemNameVal, row[username], row[hostName], queryPlanHashVal, row[sqlID], row[sqlChildNumber], + row[sid], row[serialNumber], row[process], row[schemaName], row[program], row[module], row[status], row[state], row[waitclass], + row[event], row[objectName], row[objectType], row[osUser], queryDuration) + } + + out := s.lb.Emit(metadata.WithLogsResource(rb.Emit())) + + return out, errors.Join(scrapeErrors...) +} + +func (s *oracleScraper) collectTopNMetricData(ctx context.Context) (plog.Logs, error) { + var errs []error + // get metrics and query texts from DB + timestamp := pcommon.NewTimestampFromTime(time.Now()) + intervalSeconds := int(s.scrapeCfg.CollectionInterval.Seconds()) + s.oracleQueryMetricsClient = s.clientProviderFunc(s.db, oracleQueryMetricsSQL, s.logger) + now := timestamp.AsTime().Format(dbTimeReferenceFormat) + metricRows, metricError := s.oracleQueryMetricsClient.metricRows(ctx, now, intervalSeconds, s.topQueryCollectCfg.MaxQuerySampleCount) + + if metricError != nil { + errs = append(errs, fmt.Errorf("error executing %s: %w", oracleQueryMetricsSQL, metricError)) + return plog.NewLogs(), errors.Join(errs...) + } + + if len(metricRows) == 0 { + errs = append(errs, errors.New("no data returned from oracleQueryMetricsClient")) + return plog.NewLogs(), errors.Join(errs...) + } + + metricNames := s.getTopNMetricNames() + s.logger.Debug("Metric columns", zap.Strings("names", metricNames)) + s.logger.Debug("Cache", zap.Int("size", s.metricCache.Len())) + var hits []queryMetricCacheHit + var cacheUpdates, discardedHits int + for _, row := range metricRows { + newCacheVal := make(map[string]int64, len(metricNames)) + for _, columnName := range metricNames { + val := row[columnName] + valInt64, err := strconv.ParseInt(val, 10, 64) + if err != nil { + errs = append(errs, err) + } else { + newCacheVal[columnName] = valInt64 + } + } + + cacheKey := fmt.Sprintf("%v:%v", row[sqlIDAttr], row[childNumberAttr]) + // if we have a cache hit and the query doesn't belong to top N, cache is updated anyway + // as a result, once it finally makes its way to the top N queries, only the latest delta will be sent downstream + if oldCacheVal, ok := s.metricCache.Get(cacheKey); ok { + hit := queryMetricCacheHit{ + sqlID: row[sqlIDAttr], + queryText: row[sqlTextAttr], + childNumber: row[childNumberAttr], + childAddress: row[childAddressAttr], + metrics: make(map[string]int64, len(metricNames)), + } + + // it is possible we get a record with all deltas equal to zero. we don't want to process it any further + var possiblePurge, positiveDelta bool + for _, columnName := range metricNames { + delta := newCacheVal[columnName] - oldCacheVal[columnName] + + // if any of the deltas is less than zero, cursor was likely purged from the shared pool + if delta < 0 { + possiblePurge = true + break + } else if delta > 0 { + positiveDelta = true + } + + hit.metrics[columnName] = delta + } + + // skip if possible purge or all the deltas are equal to zero + if !possiblePurge && positiveDelta { + hits = append(hits, hit) + } else { + discardedHits++ + } + } + s.metricCache.Add(cacheKey, newCacheVal) + cacheUpdates++ + } + + // if cache updates is not equal to rows returned, that indicates there is problem somewhere + s.logger.Debug("Cache update", zap.Int("update-count", cacheUpdates), zap.Int("new-size", s.metricCache.Len())) + + if len(hits) == 0 { + s.logger.Info("No log records for this scrape") + return plog.NewLogs(), errors.Join(errs...) + } + + s.logger.Debug("Cache hits", zap.Int("hit-count", len(hits)), zap.Int("discarded-hit-count", discardedHits)) + for _, hit := range hits { + s.logger.Debug(fmt.Sprintf("Cache hit, SQL_ID: %v, CHILD_NUMBER: %v", hit.sqlID, hit.childNumber), zap.Int64("elapsed-time", hit.metrics[elapsedTimeMetric])) + } + + // order by elapsed time delta, descending + sort.Slice(hits, func(i, j int) bool { + return hits[i].metrics[elapsedTimeMetric] > hits[j].metrics[elapsedTimeMetric] + }) + + for _, hit := range hits { + s.logger.Debug(fmt.Sprintf("Cache hit after sorting, SQL_ID: %v, CHILD_NUMBER: %v", hit.sqlID, hit.childNumber), zap.String("child-address", hit.childAddress), zap.Int64("elapsed-time", hit.metrics[elapsedTimeMetric])) + } + + // keep at most maxHitSize + hitCountBefore := len(hits) + maxHitsSize := min(len(hits), int(s.topQueryCollectCfg.TopQueryCount)) + hits = hits[:maxHitsSize] + skippedCacheHits := hitCountBefore - len(hits) + s.logger.Debug("Skipped cache hits", zap.Int("count", skippedCacheHits)) + + for _, hit := range hits { + s.logger.Debug(fmt.Sprintf("Final cache hit, SQL_ID: %v, CHILD_NUMBER: %v", hit.sqlID, hit.childNumber), zap.String("child-address", hit.childAddress), zap.Any("metrics", hit.metrics)) + } + hits = s.obfuscateCacheHits(hits) + childAddressToPlanMap := s.getChildAddressToPlanMap(ctx, hits) + + rb := s.lb.NewResourceBuilder() + rb.SetOracledbInstanceName(s.instanceName) + rb.SetHostName(s.hostName) + + for _, hit := range hits { + planBytes, err := json.Marshal(childAddressToPlanMap[hit.childAddress]) + if err != nil { + s.logger.Error("Error marshaling plan data to JSON", zap.Error(err)) + } + planString := string(planBytes) + + s.lb.RecordDbServerTopQueryEvent(context.Background(), + timestamp, + dbSystemNameVal, + s.hostName, + hit.queryText, + planString, hit.sqlID, hit.childNumber, + asFloatInSeconds(hit.metrics[applicationWaitTimeMetric]), + hit.metrics[bufferGetsMetric], + asFloatInSeconds(hit.metrics[clusterWaitTimeMetric]), + asFloatInSeconds(hit.metrics[concurrencyWaitTimeMetric]), + asFloatInSeconds(hit.metrics[cpuTimeMetric]), + hit.metrics[queryDirectReadsMetric], + hit.metrics[queryDirectWritesMetric], + hit.metrics[queryDiskReadsMetric], + asFloatInSeconds(hit.metrics[elapsedTimeMetric]), + hit.metrics[queryExecutionMetric], + hit.metrics[physicalReadBytesMetric], + hit.metrics[physicalReadRequestsMetric], + hit.metrics[physicalWriteBytesMetric], + hit.metrics[physicalWriteRequestsMetric], + hit.metrics[rowsProcessedMetric], + asFloatInSeconds(hit.metrics[userIoWaitTimeMetric])) + } + + hitCount := len(hits) + if hitCount > 0 { + s.logger.Debug("Log records for this scrape", zap.Int("count", hitCount)) + } + + out := s.lb.Emit(metadata.WithLogsResource(rb.Emit())) + + return out, errors.Join(errs...) +} + +func asFloatInSeconds(value int64) float64 { + return float64(value) / 1_000_000 +} + +func (s *oracleScraper) obfuscateCacheHits(hits []queryMetricCacheHit) []queryMetricCacheHit { + var obfuscatedHits []queryMetricCacheHit + for _, hit := range hits { + // obfuscate and normalize the query text + obfuscatedSQL, err := ObfuscateSQL(hit.queryText) + if err != nil { + s.logger.Error("oracleScraper failed getting metric rows", zap.Error(err)) + } else { + obfuscatedSQLLowerCase := strings.ToLower(obfuscatedSQL) + hit.queryText = obfuscatedSQLLowerCase + obfuscatedHits = append(obfuscatedHits, hit) + } + } + return obfuscatedHits +} + +func (s *oracleScraper) getChildAddressToPlanMap(ctx context.Context, hits []queryMetricCacheHit) map[string][]metricRow { + childAddressToPlanMap := map[string][]metricRow{} + if len(hits) == 0 { + return childAddressToPlanMap + } + + var childAddressSlice []any + placeholders := make([]string, len(hits)) + for i, hit := range hits { + placeholders[i] = fmt.Sprintf("HEXTORAW(:%d)", i+1) + childAddressSlice = append(childAddressSlice, hit.childAddress) + } + + placeholdersCombined := strings.Join(placeholders, ", ") + sqlQuery := fmt.Sprintf(oracleQueryPlanDataSQL, placeholdersCombined) + + s.logger.Debug("Fetching execution plans") + s.oraclePlanDataClient = s.clientProviderFunc(s.db, sqlQuery, s.logger) + planData, _ := s.oraclePlanDataClient.metricRows(ctx, childAddressSlice...) + + for _, row := range planData { + currentChildAddress := row[childAddressAttr] + jsonPlansSlice, ok := childAddressToPlanMap[currentChildAddress] + // child address was for internal use only, it's not going to be used beyond this point + delete(row, childAddressAttr) + if ok { + childAddressToPlanMap[currentChildAddress] = append(jsonPlansSlice, row) + } else { + childAddressToPlanMap[currentChildAddress] = []metricRow{row} + } + } + + return childAddressToPlanMap +} + +func (s *oracleScraper) getTopNMetricNames() []string { + return []string{ + elapsedTimeMetric, queryExecutionMetric, cpuTimeMetric, applicationWaitTimeMetric, + concurrencyWaitTimeMetric, userIoWaitTimeMetric, clusterWaitTimeMetric, rowsProcessedMetric, bufferGetsMetric, + physicalReadRequestsMetric, physicalWriteRequestsMetric, physicalReadBytesMetric, physicalWriteBytesMetric, + queryDirectReadsMetric, queryDirectWritesMetric, queryDiskReadsMetric, + } +} + func (s *oracleScraper) shutdown(_ context.Context) error { if s.db == nil { return nil diff --git a/receiver/oracledbreceiver/scraper_test.go b/receiver/oracledbreceiver/scraper_test.go index 718ae2395f52d..0a983a662f8ac 100644 --- a/receiver/oracledbreceiver/scraper_test.go +++ b/receiver/oracledbreceiver/scraper_test.go @@ -6,9 +6,19 @@ package oracledbreceiver import ( "context" "database/sql" + "encoding/json" "errors" + "fmt" + "log" + "os" + "path/filepath" + "strings" "testing" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest/plogtest" + + lru "github.com/hashicorp/golang-lru/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" @@ -41,6 +51,25 @@ var queryResponses = map[string][]metricRow{ tablespaceUsageSQL: {{"TABLESPACE_NAME": "SYS", "USED_SPACE": "111288", "TABLESPACE_SIZE": "3518587", "BLOCK_SIZE": "8192"}}, } +var cacheValue = map[string]int64{ + "APPLICATION_WAIT_TIME": 0, + "BUFFER_GETS": 3808197, + "CLUSTER_WAIT_TIME": 1000, + "CONCURRENCY_WAIT_TIME": 20, + "CPU_TIME": 29821063, + "DIRECT_READS": 3, + "DIRECT_WRITES": 6, + "DISK_READS": 12, + "ELAPSED_TIME": 38172810, + "EXECUTIONS": 200413, + "PHYSICAL_READ_BYTES": 300, + "PHYSICAL_READ_REQUESTS": 100, + "PHYSICAL_WRITE_BYTES": 12, + "PHYSICAL_WRITE_REQUESTS": 120, + "ROWS_PROCESSED": 200413, + "USER_IO_WAIT_TIME": 200, +} + func TestScraper_Scrape(t *testing.T) { tests := []struct { name string @@ -152,6 +181,9 @@ func TestScraper_Scrape(t *testing.T) { require.NoError(t, err) assert.Equal(t, 18, m.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().Len()) } + hostName, ok := m.ResourceMetrics().At(0).Resource().Attributes().Get("host.name") + assert.True(t, ok) + assert.Empty(t, hostName.Str()) name, ok := m.ResourceMetrics().At(0).Resource().Attributes().Get("oracledb.instance.name") assert.True(t, ok) assert.Empty(t, name.Str()) @@ -167,3 +199,205 @@ func TestScraper_Scrape(t *testing.T) { }) } } + +var samplesQueryResponses = map[string][]metricRow{ + samplesQuery: {{ + "S.MACHINE": "TEST-MACHINE", "S.USERNAME": "ADMIN", "S.SCHEMANAME": "ADMIN", "S.SQL_ID": "48bc50b6fuz4y", + "S.SQL_CHILD_NUMBER": "0", "S.SID": "675", "S.SERIAL#": "51295", "SQL_FULLTEXT": "test_query", "S.OSUSER": "test-user", "S.PROCESS": "1115", + "S.PORT": "54440", "S.PROGRAM": "Oracle SQL Developer for VS Code", "S.MODULE": "Oracle SQL Developer for VS Code", "S.STATUS": "ACTIVE", "S.STATE": "WAITED KNOWN TIME", "Q.PLAN_HASH_VALUE": "4199919568", "DURATION_SEC": "1", + }}, + "invalidQuery": {{ + "S.MACHINE": "TEST-MACHINE", "S.USERNAME": "ADMIN", "S.SCHEMANAME": "ADMIN", "S.SQL_ID": "48bc50b6fuz4y", + "S.SQL_CHILD_NUMBER": "0", "S.SID": "675", "S.SERIAL#": "51295", "SQL_FULLTEXT": "test_query", "S.OSUSER": "test-user", "S.PROCESS": "1115", + "S.PORT": "54440", "S.PROGRAM": "Oracle SQL Developer for VS Code", "S.MODULE": "Oracle SQL Developer for VS Code", "S.STATUS": "ACTIVE", "S.STATE": "WAITED KNOWN TIME", "Q.PLAN_HASH_VALUE": "4199919568", "DURATION_SEC": "", + }}, +} + +func TestSamplesQuery(t *testing.T) { + tests := []struct { + name string + dbclientFn func(db *sql.DB, s string, logger *zap.Logger) dbClient + errWanted string + }{ + { + name: "valid", + dbclientFn: func(_ *sql.DB, s string, _ *zap.Logger) dbClient { + return &fakeDbClient{ + Responses: [][]metricRow{ + samplesQueryResponses[s], + }, + } + }, + }, + { + name: "bad samples data", + dbclientFn: func(_ *sql.DB, _ string, _ *zap.Logger) dbClient { + return &fakeDbClient{Responses: [][]metricRow{ + samplesQueryResponses["invalidQuery"], + }} + }, + errWanted: `failed to parse int64 for Duration, value was : strconv.ParseFloat: parsing "": invalid syntax`, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + logsCfg := metadata.DefaultLogsBuilderConfig() + logsCfg.ResourceAttributes.OracledbInstanceName.Enabled = true + logsCfg.ResourceAttributes.HostName.Enabled = true + logsCfg.Events.DbServerTopQuery.Enabled = false + logsCfg.Events.DbServerQuerySample.Enabled = true + scrpr := oracleScraper{ + logger: zap.NewNop(), + dbProviderFunc: func() (*sql.DB, error) { + return nil, nil + }, + clientProviderFunc: test.dbclientFn, + id: component.ID{}, + lb: metadata.NewLogsBuilder(logsCfg, receivertest.NewNopSettings(metadata.Type)), + logsBuilderConfig: metadata.DefaultLogsBuilderConfig(), + } + scrpr.logsBuilderConfig.Events.DbServerTopQuery.Enabled = false + scrpr.logsBuilderConfig.Events.DbServerQuerySample.Enabled = true + err := scrpr.start(context.Background(), componenttest.NewNopHost()) + defer func() { + assert.NoError(t, scrpr.shutdown(context.Background())) + }() + require.NoError(t, err) + logs, err := scrpr.scrapeLogs(context.Background()) + expectedSamplesFile := filepath.Join("testdata", "expectedSamplesFile.yaml") + + if test.errWanted != "" { + require.EqualError(t, err, test.errWanted) + } else { + // Uncomment line below to re-generate expected logs. + // golden.WriteLogs(t, expectedSamplesFile, logs) + require.NoError(t, err) + expectedLogs, _ := golden.ReadLogs(expectedSamplesFile) + errs := plogtest.CompareLogs(expectedLogs, logs, plogtest.IgnoreTimestamp()) + assert.Equal(t, "db.server.query_sample", logs.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).EventName()) + assert.NoError(t, errs) + + } + }) + } +} + +func TestScraper_ScrapeTopNLogs(t *testing.T) { + var metricRowData []metricRow + var logRowData []metricRow + tests := []struct { + name string + dbclientFn func(db *sql.DB, s string, logger *zap.Logger) dbClient + errWanted string + }{ + { + name: "valid collection", + dbclientFn: func(_ *sql.DB, s string, _ *zap.Logger) dbClient { + if strings.Contains(s, "V$SQL_PLAN") { + metricRowFile := readFile("oracleQueryPlanData.txt") + unmarshalErr := json.Unmarshal(metricRowFile, &logRowData) + if unmarshalErr == nil { + return &fakeDbClient{ + Responses: [][]metricRow{ + logRowData, + }, + } + } + } else { + metricRowFile := readFile("oracleQueryMetricsData.txt") + unmarshalErr := json.Unmarshal(metricRowFile, &metricRowData) + if unmarshalErr == nil { + return &fakeDbClient{ + Responses: [][]metricRow{ + metricRowData, + }, + } + } + } + return nil + }, + }, { + name: "No metrics collected", + dbclientFn: func(_ *sql.DB, _ string, _ *zap.Logger) dbClient { + return &fakeDbClient{ + Responses: [][]metricRow{ + nil, + }, + } + }, + errWanted: `no data returned from oracleQueryMetricsClient`, + }, { + name: "Error on collecting metrics", + dbclientFn: func(_ *sql.DB, _ string, _ *zap.Logger) dbClient { + return &fakeDbClient{ + Responses: [][]metricRow{ + nil, + }, + Err: errors.New("Mock error"), + } + }, + errWanted: fmt.Sprintf("error executing %s: %s", oracleQueryMetricsSQL, "Mock error"), + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + logsCfg := metadata.DefaultLogsBuilderConfig() + logsCfg.ResourceAttributes.HostName.Enabled = true + logsCfg.Events.DbServerTopQuery.Enabled = true + logsCfg.Events.DbServerQuerySample.Enabled = false + metricsCfg := metadata.DefaultMetricsBuilderConfig() + lruCache, _ := lru.New[string, map[string]int64](500) + lruCache.Add("fxk8aq3nds8aw:0", cacheValue) + + scrpr := oracleScraper{ + logger: zap.NewNop(), + mb: metadata.NewMetricsBuilder(metricsCfg, receivertest.NewNopSettings(metadata.Type)), + lb: metadata.NewLogsBuilder(logsCfg, receivertest.NewNopSettings(metadata.Type)), + dbProviderFunc: func() (*sql.DB, error) { + return nil, nil + }, + clientProviderFunc: test.dbclientFn, + id: component.ID{}, + metricsBuilderConfig: metadata.DefaultMetricsBuilderConfig(), + logsBuilderConfig: metadata.DefaultLogsBuilderConfig(), + metricCache: lruCache, + topQueryCollectCfg: TopQueryCollection{MaxQuerySampleCount: 5000, TopQueryCount: 200}, + instanceName: "oracle-instance-sample-1", + hostName: "oracle-host-sample-1", + } + + scrpr.logsBuilderConfig.Events.DbServerTopQuery.Enabled = true + scrpr.logsBuilderConfig.Events.DbServerQuerySample.Enabled = false + + err := scrpr.start(context.Background(), componenttest.NewNopHost()) + defer func() { + assert.NoError(t, scrpr.shutdown(context.Background())) + }() + require.NoError(t, err) + expectedQueryPlanFile := filepath.Join("testdata", "expectedQueryTextAndPlanQuery.yaml") + + logs, err := scrpr.scrapeLogs(context.Background()) + + if test.errWanted != "" { + require.EqualError(t, err, test.errWanted) + } else { + // Uncomment line below to re-generate expected logs. + // golden.WriteLogs(t, expectedQueryPlanFile, logs) + expectedLogs, _ := golden.ReadLogs(expectedQueryPlanFile) + errs := plogtest.CompareLogs(expectedLogs, logs, plogtest.IgnoreTimestamp()) + assert.NoError(t, errs) + assert.Equal(t, "db.server.top_query", logs.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).EventName()) + assert.NoError(t, errs) + } + }) + } +} + +func readFile(fname string) []byte { + file, err := os.ReadFile(filepath.Join("testdata", fname)) + if err != nil { + log.Fatal(err) + } + return file +} diff --git a/receiver/oracledbreceiver/templates/oracleQueryMetricsAndTextSql.tmpl b/receiver/oracledbreceiver/templates/oracleQueryMetricsAndTextSql.tmpl new file mode 100644 index 0000000000000..b21afa484894c --- /dev/null +++ b/receiver/oracledbreceiver/templates/oracleQueryMetricsAndTextSql.tmpl @@ -0,0 +1,24 @@ +/* otel-collector */ SELECT +SQL_ID, +SQL_FULLTEXT, +CHILD_NUMBER, +RAWTOHEX(CHILD_ADDRESS) AS CHILD_ADDRESS, +EXECUTIONS, +ELAPSED_TIME, +CPU_TIME, +APPLICATION_WAIT_TIME, +CONCURRENCY_WAIT_TIME, +USER_IO_WAIT_TIME, +CLUSTER_WAIT_TIME, +ROWS_PROCESSED, +BUFFER_GETS, +PHYSICAL_WRITE_REQUESTS, +PHYSICAL_READ_REQUESTS, +PHYSICAL_WRITE_BYTES, +PHYSICAL_READ_BYTES, +DISK_READS, +DIRECT_WRITES, +DIRECT_READS +FROM V$SQL +WHERE LAST_ACTIVE_TIME >= TO_DATE(:1, 'yyyy-mm-dd hh24:mi:ss') - NUMTODSINTERVAL(:2, 'SECOND') +FETCH FIRST :3 ROWS ONLY \ No newline at end of file diff --git a/receiver/oracledbreceiver/templates/oracleQueryPlanSql.tmpl b/receiver/oracledbreceiver/templates/oracleQueryPlanSql.tmpl new file mode 100644 index 0000000000000..6a29bbc27a4ee --- /dev/null +++ b/receiver/oracledbreceiver/templates/oracleQueryPlanSql.tmpl @@ -0,0 +1,16 @@ +/* otel-collector */ SELECT +RAWTOHEX(CHILD_ADDRESS) AS CHILD_ADDRESS, +ACCESS_PREDICATES, +COST, +IO_COST, +CARDINALITY, +DEPTH, +BYTES, +PARENT_ID, +CPU_COST, +ID, +POSITION, +PROJECTION, +OPERATION +FROM V$SQL_PLAN +WHERE CHILD_ADDRESS IN (%s) \ No newline at end of file diff --git a/receiver/oracledbreceiver/templates/oracleQuerySampleSql.tmpl b/receiver/oracledbreceiver/templates/oracleQuerySampleSql.tmpl new file mode 100644 index 0000000000000..a3dc846c947f1 --- /dev/null +++ b/receiver/oracledbreceiver/templates/oracleQuerySampleSql.tmpl @@ -0,0 +1,30 @@ +/* otel-collector */ SELECT +S.MACHINE, +S.USERNAME, +S.SCHEMANAME, +S.SQL_ID, +S.SQL_CHILD_NUMBER, +S.SID, +S.SERIAL#, +Q.SQL_FULLTEXT, +S.OSUSER, +S.PROCESS, +S.PORT, +S.PROGRAM, +S.MODULE, +S.STATUS, +S.STATE, +Q.PLAN_HASH_VALUE, +NVL((SYSDATE - SQL_EXEC_START) * 86400,0) AS DURATION_SEC, +CASE WHEN S.TIME_REMAINING_MICRO IS NOT NULL + THEN S.WAIT_CLASS END AS WAIT_CLASS, +CASE WHEN S.TIME_REMAINING_MICRO IS NOT NULL + THEN S.EVENT END AS EVENT, +CASE WHEN S.PLSQL_ENTRY_OBJECT_ID IS NOT NULL + THEN CASE WHEN P.PROCEDURE_NAME IS NULL + THEN P.OWNER || '.' || P.OBJECT_NAME ELSE P.OWNER || '.' || P.OBJECT_NAME || '.' || P.PROCEDURE_NAME END + END AS OBJECT_NAME, P.OBJECT_TYPE +FROM V$SESSION S LEFT JOIN DBA_PROCEDURES P ON S.PLSQL_ENTRY_OBJECT_ID = P.OBJECT_ID + AND S.PLSQL_ENTRY_SUBPROGRAM_ID = P.SUBPROGRAM_ID + LEFT JOIN V$SQL Q ON S.SQL_ID = Q.SQL_ID + WHERE S.SQL_ID IS NOT NULL AND S.STATUS = 'ACTIVE' \ No newline at end of file diff --git a/receiver/oracledbreceiver/testdata/config.yaml b/receiver/oracledbreceiver/testdata/config.yaml index 2e30ba2652eef..d3f038d59c292 100644 --- a/receiver/oracledbreceiver/testdata/config.yaml +++ b/receiver/oracledbreceiver/testdata/config.yaml @@ -10,4 +10,9 @@ oracledb: oracledb.exchange_deadlocks: enabled: false oracledb.tablespace_size.usage: - enabled: false \ No newline at end of file + enabled: false + events: + db.server.query_sample: + enabled: true + db.server.top_query: + enabled: true \ No newline at end of file diff --git a/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml b/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml new file mode 100644 index 0000000000000..1f3ea343b0c18 --- /dev/null +++ b/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml @@ -0,0 +1,86 @@ +resourceLogs: + - resource: + attributes: + - key: oracledb.instance.name + value: + stringValue: oracle-instance-sample-1 + - key: host.name + value: + stringValue: oracle-host-sample-1 + scopeLogs: + - logRecords: + - attributes: + - key: db.system.name + value: + stringValue: oracle + - key: db.server.name + value: + stringValue: oracle-host-sample-1 + - key: db.query.text + value: + stringValue: select count ( * ) from admin. employee e join admin. person p on e. businessentityid = ? join admin. employeepayhistory eph on e. businessentityid = eph. businessentityid where eph. rate > ( select avg ( rate ) from admin. employeepayhistory ) + - key: oracledb.query_plan + value: + stringValue: '[{"ACCESS_PREDICATES":"","BYTES":"","CARDINALITY":"","COST":"1","CPU_COST":"","DEPTH":"0","ID":"0","IO_COST":"","OPERATION":"SELECT STATEMENT","PARENT_ID":"","POSITION":"1","PROJECTION":""}]' + - key: oracledb.sql_id + value: + stringValue: fxk8aq3nds8aw + - key: oracledb.child_number + value: + stringValue: "0" + - key: oracledb.application_wait_time + value: + doubleValue: 0 + - key: oracledb.buffer_gets + value: + intValue: "189417" + - key: oracledb.cluster_wait_time + value: + doubleValue: 0.001 + - key: oracledb.concurrency_wait_time + value: + doubleValue: 1e-05 + - key: oracledb.cpu_time + value: + doubleValue: 9.915824 + - key: oracledb.direct_reads + value: + intValue: "2" + - key: oracledb.direct_writes + value: + intValue: "4" + - key: oracledb.disk_reads + value: + intValue: "3" + - key: oracledb.elapsed_time + value: + doubleValue: 61 + - key: oracledb.executions + value: + intValue: "100000" + - key: oracledb.physical_read_bytes + value: + intValue: "100" + - key: oracledb.physical_read_requests + value: + intValue: "400" + - key: oracledb.physical_write_bytes + value: + intValue: "6" + - key: oracledb.physical_write_requests + value: + intValue: "30" + - key: oracledb.rows_processed + value: + intValue: "199443" + - key: oracledb.user_io_wait_time + value: + doubleValue: 2e-05 + body: {} + eventName: db.server.top_query + spanId: "" + timeUnixNano: "1750963641750185000" + traceId: "" + scope: + name: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/oracledbreceiver + version: latest diff --git a/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml b/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml new file mode 100644 index 0000000000000..9c233996ddcc1 --- /dev/null +++ b/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml @@ -0,0 +1,83 @@ +resourceLogs: + - resource: + attributes: + - key: oracledb.instance.name + value: + stringValue: "" + - key: host.name + value: + stringValue: "" + scopeLogs: + - logRecords: + - attributes: + - key: db.query.text + value: + stringValue: test_query + - key: db.system.name + value: + stringValue: oracle + - key: user.name + value: + stringValue: "" + - key: client.address + value: + stringValue: "" + - key: oracledb.plan_hash_value + value: + stringValue: "" + - key: oracledb.sql_id + value: + stringValue: "" + - key: oracledb.child_number + value: + stringValue: "" + - key: oracledb.sid + value: + stringValue: "" + - key: oracledb.serial + value: + stringValue: "" + - key: oracledb.process + value: + stringValue: "" + - key: oracledb.schemaname + value: + stringValue: "" + - key: oracledb.program + value: + stringValue: "" + - key: oracledb.module + value: + stringValue: "" + - key: oracledb.status + value: + stringValue: "" + - key: oracledb.state + value: + stringValue: "" + - key: oracledb.wait_class + value: + stringValue: "" + - key: oracledb.event + value: + stringValue: "" + - key: oracledb.object_name + value: + stringValue: "" + - key: oracledb.object_type + value: + stringValue: "" + - key: oracledb.osuser + value: + stringValue: "" + - key: oracledb.duration_sec + value: + doubleValue: 1 + body: {} + eventName: db.server.query_sample + spanId: "" + timeUnixNano: "1750964071570576000" + traceId: "" + scope: + name: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/oracledbreceiver + version: latest diff --git a/receiver/oracledbreceiver/testdata/oracleQueryMetricsData.txt b/receiver/oracledbreceiver/testdata/oracleQueryMetricsData.txt new file mode 100644 index 0000000000000..819714862f933 --- /dev/null +++ b/receiver/oracledbreceiver/testdata/oracleQueryMetricsData.txt @@ -0,0 +1 @@ +[{"APPLICATION_WAIT_TIME": "0", "BUFFER_GETS": "3997614", "CHILD_ADDRESS": "0000000074C6E830", "CHILD_NUMBER": "0", "CLUSTER_WAIT_TIME": "2000", "CONCURRENCY_WAIT_TIME": "30", "CPU_TIME": "39736887", "DIRECT_READS": "5", "DIRECT_WRITES": "10", "DISK_READS": "15", "ELAPSED_TIME": "99172810", "EXECUTIONS": "300413", "PHYSICAL_READ_BYTES": "400", "PHYSICAL_READ_REQUESTS": "500", "PHYSICAL_WRITE_BYTES": "18", "PHYSICAL_WRITE_REQUESTS": "150", "ROWS_PROCESSED": "399856", "SQL_FULLTEXT": "SELECT COUNT(*) AS TotalHighRateEmployees FROM ADMIN.\"Employee\" e \nJOIN ADMIN.\"Person\" p ON e.\"BusinessEntityID\" = \"BusId1234\" \nJOIN ADMIN.\"EmployeePayHistory\" eph ON e.\"BusinessEntityID\" = eph.\"BusinessEntityID\" WHERE eph.\"Rate\" \u003e \n(SELECT AVG(\"Rate\") FROM ADMIN.\"EmployeePayHistory\")", "SQL_ID": "fxk8aq3nds8aw", "USER_IO_WAIT_TIME": "220"}] \ No newline at end of file diff --git a/receiver/oracledbreceiver/testdata/oracleQueryPlanData.txt b/receiver/oracledbreceiver/testdata/oracleQueryPlanData.txt new file mode 100644 index 0000000000000..fd17e61ea94ba --- /dev/null +++ b/receiver/oracledbreceiver/testdata/oracleQueryPlanData.txt @@ -0,0 +1 @@ +[{"ACCESS_PREDICATES": "", "BYTES": "", "CARDINALITY": "", "CHILD_ADDRESS": "0000000074C6E830", "COST": "1", "CPU_COST": "", "DEPTH": "0", "ID": "0", "IO_COST": "", "OPERATION": "SELECT STATEMENT", "PARENT_ID": "", "POSITION": "1", "PROJECTION": ""}] \ No newline at end of file From 9dae10e6a17c7405650e681b8e66dc2b576ed996 Mon Sep 17 00:00:00 2001 From: Sreenath Date: Fri, 27 Jun 2025 11:05:38 +0100 Subject: [PATCH 02/51] Adding limit for query samples collection --- receiver/oracledbreceiver/config.go | 8 ++++++++ receiver/oracledbreceiver/factory.go | 5 ++++- receiver/oracledbreceiver/scraper.go | 6 ++++-- .../oracledbreceiver/templates/oracleQuerySampleSql.tmpl | 3 ++- receiver/oracledbreceiver/testdata/config.yaml | 6 ++++++ 5 files changed, 24 insertions(+), 4 deletions(-) diff --git a/receiver/oracledbreceiver/config.go b/receiver/oracledbreceiver/config.go index ee6a957511e6e..753ae540387b5 100644 --- a/receiver/oracledbreceiver/config.go +++ b/receiver/oracledbreceiver/config.go @@ -35,6 +35,13 @@ type TopQueryCollection struct { QueryCacheSize int `mapstructure:"query_cache_size"` } +type QuerySample struct { + MaxRowsPerQuery uint64 `mapstructure:"max_rows_per_query"` + + // prevent unkeyed literal initialization + _ struct{} +} + type Config struct { DataSource string `mapstructure:"datasource"` Endpoint string `mapstructure:"endpoint"` @@ -46,6 +53,7 @@ type Config struct { metadata.LogsBuilderConfig `mapstructure:",squash"` TopQueryCollection `mapstructure:"top_query_collection"` + QuerySample `mapstructure:"query_sample_collection"` } func (c Config) Validate() error { diff --git a/receiver/oracledbreceiver/factory.go b/receiver/oracledbreceiver/factory.go index 16067222f18f9..84f7a38ab5d3d 100644 --- a/receiver/oracledbreceiver/factory.go +++ b/receiver/oracledbreceiver/factory.go @@ -44,6 +44,9 @@ func createDefaultConfig() component.Config { ControllerConfig: cfg, MetricsBuilderConfig: metadata.DefaultMetricsBuilderConfig(), LogsBuilderConfig: metadata.DefaultLogsBuilderConfig(), + QuerySample: QuerySample{ + MaxRowsPerQuery: 100, + }, TopQueryCollection: TopQueryCollection{ MaxQuerySampleCount: 1000, TopQueryCount: 200, @@ -120,7 +123,7 @@ func createLogsReceiverFunc(sqlOpenerFunc sqlOpenerFunc, clientProviderFunc clie mp, err := newLogsScraper(logsBuilder, sqlCfg.LogsBuilderConfig, sqlCfg.ControllerConfig, settings.Logger, func() (*sql.DB, error) { return sqlOpenerFunc(getDataSource(*sqlCfg)) - }, clientProviderFunc, instanceName, metricCache, sqlCfg.TopQueryCollection, hostName) + }, clientProviderFunc, instanceName, metricCache, sqlCfg.TopQueryCollection, sqlCfg.QuerySample, hostName) if err != nil { return nil, err } diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index cc8f57bd1459d..c1edb11ab4d1c 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -128,6 +128,7 @@ type oracleScraper struct { logsBuilderConfig metadata.LogsBuilderConfig metricCache *lru.Cache[string, map[string]int64] topQueryCollectCfg TopQueryCollection + querySampleCfg QuerySample } func newScraper(metricsBuilder *metadata.MetricsBuilder, metricsBuilderConfig metadata.MetricsBuilderConfig, scrapeCfg scraperhelper.ControllerConfig, logger *zap.Logger, providerFunc dbProviderFunc, clientProviderFunc clientProviderFunc, instanceName string, hostName string) (scraper.Metrics, error) { @@ -146,7 +147,7 @@ func newScraper(metricsBuilder *metadata.MetricsBuilder, metricsBuilderConfig me func newLogsScraper(logsBuilder *metadata.LogsBuilder, logsBuilderConfig metadata.LogsBuilderConfig, scrapeCfg scraperhelper.ControllerConfig, logger *zap.Logger, providerFunc dbProviderFunc, clientProviderFunc clientProviderFunc, instanceName string, metricCache *lru.Cache[string, map[string]int64], - topQueryCollectCfg TopQueryCollection, hostName string, + topQueryCollectCfg TopQueryCollection, querySampleCfg QuerySample, hostName string, ) (scraper.Logs, error) { s := &oracleScraper{ lb: logsBuilder, @@ -158,6 +159,7 @@ func newLogsScraper(logsBuilder *metadata.LogsBuilder, logsBuilderConfig metadat instanceName: instanceName, metricCache: metricCache, topQueryCollectCfg: topQueryCollectCfg, + querySampleCfg: querySampleCfg, hostName: hostName, } return scraper.NewLogs(s.scrapeLogs, scraper.WithShutdown(s.shutdown), scraper.WithStart(s.start)) @@ -562,7 +564,7 @@ func (s *oracleScraper) collectQuerySamples(ctx context.Context) (plog.Logs, err dbClients := s.samplesQueryClient timestamp := pcommon.NewTimestampFromTime(time.Now()) - rows, err := dbClients.metricRows(ctx) + rows, err := dbClients.metricRows(ctx, s.querySampleCfg.MaxRowsPerQuery) if err != nil { scrapeErrors = append(scrapeErrors, fmt.Errorf("error executing %s: %w", samplesQuery, err)) } diff --git a/receiver/oracledbreceiver/templates/oracleQuerySampleSql.tmpl b/receiver/oracledbreceiver/templates/oracleQuerySampleSql.tmpl index a3dc846c947f1..f958279ea47ac 100644 --- a/receiver/oracledbreceiver/templates/oracleQuerySampleSql.tmpl +++ b/receiver/oracledbreceiver/templates/oracleQuerySampleSql.tmpl @@ -27,4 +27,5 @@ CASE WHEN S.PLSQL_ENTRY_OBJECT_ID IS NOT NULL FROM V$SESSION S LEFT JOIN DBA_PROCEDURES P ON S.PLSQL_ENTRY_OBJECT_ID = P.OBJECT_ID AND S.PLSQL_ENTRY_SUBPROGRAM_ID = P.SUBPROGRAM_ID LEFT JOIN V$SQL Q ON S.SQL_ID = Q.SQL_ID - WHERE S.SQL_ID IS NOT NULL AND S.STATUS = 'ACTIVE' \ No newline at end of file + WHERE S.SQL_ID IS NOT NULL AND S.STATUS = 'ACTIVE' +FETCH FIRST :1 ROWS ONLY \ No newline at end of file diff --git a/receiver/oracledbreceiver/testdata/config.yaml b/receiver/oracledbreceiver/testdata/config.yaml index d3f038d59c292..9bd305ddbea2f 100644 --- a/receiver/oracledbreceiver/testdata/config.yaml +++ b/receiver/oracledbreceiver/testdata/config.yaml @@ -6,6 +6,12 @@ oracledb: username: otel # Refer to Oracle Go Driver go_ora documentation for full connection string options datasource: "oracle://otel:password@localhost:51521/XE" + top_query_collection: + max_query_sample_count: 222 + top_query_count: 200 + query_cache_size: 1000 + query_sample_collection: + max_rows_per_query: 200 metrics: oracledb.exchange_deadlocks: enabled: false From 7481e69b2068a2884eed0eff7498d58c853330be Mon Sep 17 00:00:00 2001 From: Sreenath Date: Fri, 27 Jun 2025 12:06:52 +0100 Subject: [PATCH 03/51] lint fixes and generated files. --- receiver/oracledbreceiver/documentation.md | 81 +++++++++++++++++++ .../generated_package_test.go | 3 +- .../internal/metadata/generated_logs.go | 28 +++++-- .../internal/metadata/generated_logs_test.go | 24 ++++-- receiver/oracledbreceiver/scraper_test.go | 7 +- 5 files changed, 125 insertions(+), 18 deletions(-) diff --git a/receiver/oracledbreceiver/documentation.md b/receiver/oracledbreceiver/documentation.md index 1be4e19bd85d1..5355e99d7ca42 100644 --- a/receiver/oracledbreceiver/documentation.md +++ b/receiver/oracledbreceiver/documentation.md @@ -369,6 +369,87 @@ Number of SELECT statements executed in parallel | ---- | ----------- | ---------- | ----------------------- | --------- | | {queries} | Sum | Int | Cumulative | true | +## Default Events + +The following events are emitted by default. Each of them can be disabled by applying the following configuration: + +```yaml +events: + : + enabled: false +``` + +## Optional Events + +The following events are not emitted by default. Each of them can be enabled by applying the following configuration: + +```yaml +events: + : + enabled: true +``` + +### db.server.query_sample + +sample query + +#### Attributes + +| Name | Description | Values | +| ---- | ----------- | ------ | +| db.query.text | The text of the database query being executed. | Any Str | +| db.system.name | The database management system (DBMS) product as identified by the client instrumentation. | Any Str | +| user.name | Database user name under which a session is connected to | Any Str | +| client.address | Identifies the name of the machine (host) from which the database client is connecting to the Oracle database. | Any Str | +| oracledb.plan_hash_value | Binary hash value calculated on the query execution plan and used to identify similar query execution plans, reported in the HEX format. | Any Str | +| oracledb.sql_id | The SQL ID of the query. | Any Str | +| oracledb.child_number | The child number of the query. | Any Str | +| oracledb.sid | ID of the Oracle Server session. | Any Str | +| oracledb.serial | Serial number associated with a session. | Any Str | +| oracledb.process | The operating system process ID (PID) associated with a session. | Any Str | +| oracledb.schemaname | Oracle schema under which SQL statements are being executed | Any Str | +| oracledb.program | Name of the client program or tool that initiated the Oracle database session. | Any Str | +| oracledb.module | Logical module name of the client application that initiated a query or session. | Any Str | +| oracledb.status | Execution state or result of a database query or session. | Any Str | +| oracledb.state | Current state of the query or the session executing it. | Any Str | +| oracledb.wait_class | The category of wait events a query or session is currently experiencing in Oracle Database. | Any Str | +| oracledb.event | The specific wait event that a query or session is currently experiencing. | Any Str | +| oracledb.object_name | Name of the database object that a query is accessing. | Any Str | +| oracledb.object_type | Type of the database object that a query is accessing. | Any Str | +| oracledb.osuser | Name of the operating system user that initiated or is running the Oracle database session. | Any Str | +| oracledb.duration_sec | Total time taken by a database query to execute. | Any Double | + +### db.server.top_query + +top query + +#### Attributes + +| Name | Description | Values | +| ---- | ----------- | ------ | +| db.system.name | The database management system (DBMS) product as identified by the client instrumentation. | Any Str | +| db.server.name | The name of the server hosting the database. | Any Str | +| db.query.text | The text of the database query being executed. | Any Str | +| oracledb.query_plan | The query execution plan used by the SQL Server. | Any Str | +| oracledb.sql_id | The SQL ID of the query. | Any Str | +| oracledb.child_number | The child number of the query. | Any Str | +| oracledb.application_wait_time | The total time (in seconds) a query spent waiting on the application before it could proceed with execution (reporting delta). | Any Double | +| oracledb.buffer_gets | Number of logical reads (i.e., buffer cache accesses) performed by a query (reporting delta). | Any Int | +| oracledb.cluster_wait_time | Total time (in seconds) that a query waited due to Oracle Real Application Clusters (RAC) coordination (reporting delta). | Any Double | +| oracledb.concurrency_wait_time | Total time (in seconds) a query spent waiting on concurrency-related events (reporting delta). | Any Double | +| oracledb.cpu_time | Total time (in seconds) that the CPU spent actively processing a query, excluding time spent waiting (reporting delta). | Any Double | +| oracledb.direct_reads | The number of direct path reads performed by a query — i.e., data blocks read directly from disk into the session’s memory (reporting delta). | Any Int | +| oracledb.direct_writes | The number of direct path write operations, where data is written directly to disk from user memory (reporting delta). | Any Int | +| oracledb.disk_reads | The number of physical reads a query performs — that is, the number of data blocks read from disk (reporting delta). | Any Int | +| oracledb.elapsed_time | The total time (in seconds) taken by a query from start to finish, including CPU time and all types of waits (reporting delta). | Any Double | +| oracledb.executions | The number of times a specific SQL query has been executed (reporting delta). | Any Int | +| oracledb.physical_read_bytes | The total number of bytes read from disk by a query (reporting delta). | Any Int | +| oracledb.physical_read_requests | The number of physical I/O read operations performed by a query (reporting delta). | Any Int | +| oracledb.physical_write_bytes | The total number of bytes written to disk by a query (reporting delta). | Any Int | +| oracledb.physical_write_requests | The number of times a query requested to write data to disk (reporting delta). | Any Int | +| oracledb.rows_processed | The total number of rows that a query has read, returned, or affected during its execution (reporting delta). | Any Int | +| oracledb.user_io_wait_time | The total time (in seconds) a query spent waiting for user I/O operations—such as reading or writing data to disk or network file systems (reporting delta). | Any Double | + ## Resource Attributes | Name | Description | Values | Enabled | diff --git a/receiver/oracledbreceiver/generated_package_test.go b/receiver/oracledbreceiver/generated_package_test.go index 97ba6f17b5fe1..4e4d6283a7062 100644 --- a/receiver/oracledbreceiver/generated_package_test.go +++ b/receiver/oracledbreceiver/generated_package_test.go @@ -3,8 +3,9 @@ package oracledbreceiver import ( - "go.uber.org/goleak" "testing" + + "go.uber.org/goleak" ) func TestMain(m *testing.M) { diff --git a/receiver/oracledbreceiver/internal/metadata/generated_logs.go b/receiver/oracledbreceiver/internal/metadata/generated_logs.go index ccf1b3723ae8a..b1449b2111d78 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_logs.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_logs.go @@ -3,10 +3,14 @@ package metadata import ( + "context" + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/filter" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/receiver" + "go.opentelemetry.io/otel/trace" ) type eventDbServerQuerySample struct { @@ -14,13 +18,19 @@ type eventDbServerQuerySample struct { config EventConfig // event config provided by user. } -func (e *eventDbServerQuerySample) recordEvent(timestamp pcommon.Timestamp, dbQueryTextAttributeValue string, dbSystemNameAttributeValue string, userNameAttributeValue string, clientAddressAttributeValue string, oracledbPlanHashValueAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbSidAttributeValue string, oracledbSerialAttributeValue string, oracledbProcessAttributeValue string, oracledbSchemanameAttributeValue string, oracledbProgramAttributeValue string, oracledbModuleAttributeValue string, oracledbStatusAttributeValue string, oracledbStateAttributeValue string, oracledbWaitClassAttributeValue string, oracledbEventAttributeValue string, oracledbObjectNameAttributeValue string, oracledbObjectTypeAttributeValue string, oracledbOsuserAttributeValue string, oracledbDurationSecAttributeValue float64) { +func (e *eventDbServerQuerySample) recordEvent(ctx context.Context, timestamp pcommon.Timestamp, dbQueryTextAttributeValue string, dbSystemNameAttributeValue string, userNameAttributeValue string, clientAddressAttributeValue string, oracledbPlanHashValueAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbSidAttributeValue string, oracledbSerialAttributeValue string, oracledbProcessAttributeValue string, oracledbSchemanameAttributeValue string, oracledbProgramAttributeValue string, oracledbModuleAttributeValue string, oracledbStatusAttributeValue string, oracledbStateAttributeValue string, oracledbWaitClassAttributeValue string, oracledbEventAttributeValue string, oracledbObjectNameAttributeValue string, oracledbObjectTypeAttributeValue string, oracledbOsuserAttributeValue string, oracledbDurationSecAttributeValue float64) { if !e.config.Enabled { return } lr := e.data.AppendEmpty() lr.SetEventName("db.server.query_sample") lr.SetTimestamp(timestamp) + + if span := trace.SpanContextFromContext(ctx); span.IsValid() { + lr.SetTraceID(pcommon.TraceID(span.TraceID())) + lr.SetSpanID(pcommon.SpanID(span.SpanID())) + } + lr.Attributes().PutStr("db.query.text", dbQueryTextAttributeValue) lr.Attributes().PutStr("db.system.name", dbSystemNameAttributeValue) lr.Attributes().PutStr("user.name", userNameAttributeValue) @@ -64,13 +74,19 @@ type eventDbServerTopQuery struct { config EventConfig // event config provided by user. } -func (e *eventDbServerTopQuery) recordEvent(timestamp pcommon.Timestamp, dbSystemNameAttributeValue string, dbServerNameAttributeValue string, dbQueryTextAttributeValue string, oracledbQueryPlanAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbApplicationWaitTimeAttributeValue float64, oracledbBufferGetsAttributeValue int64, oracledbClusterWaitTimeAttributeValue float64, oracledbConcurrencyWaitTimeAttributeValue float64, oracledbCPUTimeAttributeValue float64, oracledbDirectReadsAttributeValue int64, oracledbDirectWritesAttributeValue int64, oracledbDiskReadsAttributeValue int64, oracledbElapsedTimeAttributeValue float64, oracledbExecutionsAttributeValue int64, oracledbPhysicalReadBytesAttributeValue int64, oracledbPhysicalReadRequestsAttributeValue int64, oracledbPhysicalWriteBytesAttributeValue int64, oracledbPhysicalWriteRequestsAttributeValue int64, oracledbRowsProcessedAttributeValue int64, oracledbUserIoWaitTimeAttributeValue float64) { +func (e *eventDbServerTopQuery) recordEvent(ctx context.Context, timestamp pcommon.Timestamp, dbSystemNameAttributeValue string, dbServerNameAttributeValue string, dbQueryTextAttributeValue string, oracledbQueryPlanAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbApplicationWaitTimeAttributeValue float64, oracledbBufferGetsAttributeValue int64, oracledbClusterWaitTimeAttributeValue float64, oracledbConcurrencyWaitTimeAttributeValue float64, oracledbCPUTimeAttributeValue float64, oracledbDirectReadsAttributeValue int64, oracledbDirectWritesAttributeValue int64, oracledbDiskReadsAttributeValue int64, oracledbElapsedTimeAttributeValue float64, oracledbExecutionsAttributeValue int64, oracledbPhysicalReadBytesAttributeValue int64, oracledbPhysicalReadRequestsAttributeValue int64, oracledbPhysicalWriteBytesAttributeValue int64, oracledbPhysicalWriteRequestsAttributeValue int64, oracledbRowsProcessedAttributeValue int64, oracledbUserIoWaitTimeAttributeValue float64) { if !e.config.Enabled { return } lr := e.data.AppendEmpty() lr.SetEventName("db.server.top_query") lr.SetTimestamp(timestamp) + + if span := trace.SpanContextFromContext(ctx); span.IsValid() { + lr.SetTraceID(pcommon.TraceID(span.TraceID())) + lr.SetSpanID(pcommon.SpanID(span.SpanID())) + } + lr.Attributes().PutStr("db.system.name", dbSystemNameAttributeValue) lr.Attributes().PutStr("db.server.name", dbServerNameAttributeValue) lr.Attributes().PutStr("db.query.text", dbQueryTextAttributeValue) @@ -233,11 +249,11 @@ func (lb *LogsBuilder) Emit(options ...ResourceLogsOption) plog.Logs { } // RecordDbServerQuerySampleEvent adds a log record of db.server.query_sample event. -func (lb *LogsBuilder) RecordDbServerQuerySampleEvent(timestamp pcommon.Timestamp, dbQueryTextAttributeValue string, dbSystemNameAttributeValue string, userNameAttributeValue string, clientAddressAttributeValue string, oracledbPlanHashValueAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbSidAttributeValue string, oracledbSerialAttributeValue string, oracledbProcessAttributeValue string, oracledbSchemanameAttributeValue string, oracledbProgramAttributeValue string, oracledbModuleAttributeValue string, oracledbStatusAttributeValue string, oracledbStateAttributeValue string, oracledbWaitClassAttributeValue string, oracledbEventAttributeValue string, oracledbObjectNameAttributeValue string, oracledbObjectTypeAttributeValue string, oracledbOsuserAttributeValue string, oracledbDurationSecAttributeValue float64) { - lb.eventDbServerQuerySample.recordEvent(timestamp, dbQueryTextAttributeValue, dbSystemNameAttributeValue, userNameAttributeValue, clientAddressAttributeValue, oracledbPlanHashValueAttributeValue, oracledbSQLIDAttributeValue, oracledbChildNumberAttributeValue, oracledbSidAttributeValue, oracledbSerialAttributeValue, oracledbProcessAttributeValue, oracledbSchemanameAttributeValue, oracledbProgramAttributeValue, oracledbModuleAttributeValue, oracledbStatusAttributeValue, oracledbStateAttributeValue, oracledbWaitClassAttributeValue, oracledbEventAttributeValue, oracledbObjectNameAttributeValue, oracledbObjectTypeAttributeValue, oracledbOsuserAttributeValue, oracledbDurationSecAttributeValue) +func (lb *LogsBuilder) RecordDbServerQuerySampleEvent(ctx context.Context, timestamp pcommon.Timestamp, dbQueryTextAttributeValue string, dbSystemNameAttributeValue string, userNameAttributeValue string, clientAddressAttributeValue string, oracledbPlanHashValueAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbSidAttributeValue string, oracledbSerialAttributeValue string, oracledbProcessAttributeValue string, oracledbSchemanameAttributeValue string, oracledbProgramAttributeValue string, oracledbModuleAttributeValue string, oracledbStatusAttributeValue string, oracledbStateAttributeValue string, oracledbWaitClassAttributeValue string, oracledbEventAttributeValue string, oracledbObjectNameAttributeValue string, oracledbObjectTypeAttributeValue string, oracledbOsuserAttributeValue string, oracledbDurationSecAttributeValue float64) { + lb.eventDbServerQuerySample.recordEvent(ctx, timestamp, dbQueryTextAttributeValue, dbSystemNameAttributeValue, userNameAttributeValue, clientAddressAttributeValue, oracledbPlanHashValueAttributeValue, oracledbSQLIDAttributeValue, oracledbChildNumberAttributeValue, oracledbSidAttributeValue, oracledbSerialAttributeValue, oracledbProcessAttributeValue, oracledbSchemanameAttributeValue, oracledbProgramAttributeValue, oracledbModuleAttributeValue, oracledbStatusAttributeValue, oracledbStateAttributeValue, oracledbWaitClassAttributeValue, oracledbEventAttributeValue, oracledbObjectNameAttributeValue, oracledbObjectTypeAttributeValue, oracledbOsuserAttributeValue, oracledbDurationSecAttributeValue) } // RecordDbServerTopQueryEvent adds a log record of db.server.top_query event. -func (lb *LogsBuilder) RecordDbServerTopQueryEvent(timestamp pcommon.Timestamp, dbSystemNameAttributeValue string, dbServerNameAttributeValue string, dbQueryTextAttributeValue string, oracledbQueryPlanAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbApplicationWaitTimeAttributeValue float64, oracledbBufferGetsAttributeValue int64, oracledbClusterWaitTimeAttributeValue float64, oracledbConcurrencyWaitTimeAttributeValue float64, oracledbCPUTimeAttributeValue float64, oracledbDirectReadsAttributeValue int64, oracledbDirectWritesAttributeValue int64, oracledbDiskReadsAttributeValue int64, oracledbElapsedTimeAttributeValue float64, oracledbExecutionsAttributeValue int64, oracledbPhysicalReadBytesAttributeValue int64, oracledbPhysicalReadRequestsAttributeValue int64, oracledbPhysicalWriteBytesAttributeValue int64, oracledbPhysicalWriteRequestsAttributeValue int64, oracledbRowsProcessedAttributeValue int64, oracledbUserIoWaitTimeAttributeValue float64) { - lb.eventDbServerTopQuery.recordEvent(timestamp, dbSystemNameAttributeValue, dbServerNameAttributeValue, dbQueryTextAttributeValue, oracledbQueryPlanAttributeValue, oracledbSQLIDAttributeValue, oracledbChildNumberAttributeValue, oracledbApplicationWaitTimeAttributeValue, oracledbBufferGetsAttributeValue, oracledbClusterWaitTimeAttributeValue, oracledbConcurrencyWaitTimeAttributeValue, oracledbCPUTimeAttributeValue, oracledbDirectReadsAttributeValue, oracledbDirectWritesAttributeValue, oracledbDiskReadsAttributeValue, oracledbElapsedTimeAttributeValue, oracledbExecutionsAttributeValue, oracledbPhysicalReadBytesAttributeValue, oracledbPhysicalReadRequestsAttributeValue, oracledbPhysicalWriteBytesAttributeValue, oracledbPhysicalWriteRequestsAttributeValue, oracledbRowsProcessedAttributeValue, oracledbUserIoWaitTimeAttributeValue) +func (lb *LogsBuilder) RecordDbServerTopQueryEvent(ctx context.Context, timestamp pcommon.Timestamp, dbSystemNameAttributeValue string, dbServerNameAttributeValue string, dbQueryTextAttributeValue string, oracledbQueryPlanAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbApplicationWaitTimeAttributeValue float64, oracledbBufferGetsAttributeValue int64, oracledbClusterWaitTimeAttributeValue float64, oracledbConcurrencyWaitTimeAttributeValue float64, oracledbCPUTimeAttributeValue float64, oracledbDirectReadsAttributeValue int64, oracledbDirectWritesAttributeValue int64, oracledbDiskReadsAttributeValue int64, oracledbElapsedTimeAttributeValue float64, oracledbExecutionsAttributeValue int64, oracledbPhysicalReadBytesAttributeValue int64, oracledbPhysicalReadRequestsAttributeValue int64, oracledbPhysicalWriteBytesAttributeValue int64, oracledbPhysicalWriteRequestsAttributeValue int64, oracledbRowsProcessedAttributeValue int64, oracledbUserIoWaitTimeAttributeValue float64) { + lb.eventDbServerTopQuery.recordEvent(ctx, timestamp, dbSystemNameAttributeValue, dbServerNameAttributeValue, dbQueryTextAttributeValue, oracledbQueryPlanAttributeValue, oracledbSQLIDAttributeValue, oracledbChildNumberAttributeValue, oracledbApplicationWaitTimeAttributeValue, oracledbBufferGetsAttributeValue, oracledbClusterWaitTimeAttributeValue, oracledbConcurrencyWaitTimeAttributeValue, oracledbCPUTimeAttributeValue, oracledbDirectReadsAttributeValue, oracledbDirectWritesAttributeValue, oracledbDiskReadsAttributeValue, oracledbElapsedTimeAttributeValue, oracledbExecutionsAttributeValue, oracledbPhysicalReadBytesAttributeValue, oracledbPhysicalReadRequestsAttributeValue, oracledbPhysicalWriteBytesAttributeValue, oracledbPhysicalWriteRequestsAttributeValue, oracledbRowsProcessedAttributeValue, oracledbUserIoWaitTimeAttributeValue) } diff --git a/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go b/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go index 2843800140a75..a41cff94246ac 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go @@ -3,16 +3,17 @@ package metadata import ( + "context" "testing" "time" "github.com/stretchr/testify/assert" - "go.uber.org/zap" - "go.uber.org/zap/zaptest/observer" - "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/receiver/receivertest" + "go.opentelemetry.io/otel/trace" + "go.uber.org/zap" + "go.uber.org/zap/zaptest/observer" ) type eventsTestDataSet int @@ -109,6 +110,13 @@ func TestLogsBuilder(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { timestamp := pcommon.Timestamp(1_000_001_000) + traceID := [16]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} + spanID := [8]byte{0, 1, 2, 3, 4, 5, 6, 7} + ctx := trace.ContextWithSpanContext(context.Background(), trace.NewSpanContext(trace.SpanContextConfig{ + TraceID: trace.TraceID(traceID), + SpanID: trace.SpanID(spanID), + TraceFlags: trace.FlagsSampled, + })) observedZapCore, observedLogs := observer.New(zap.WarnLevel) settings := receivertest.NewNopSettings(receivertest.NopType) settings.Logger = zap.New(observedZapCore) @@ -122,10 +130,10 @@ func TestLogsBuilder(t *testing.T) { allEventsCount := 0 allEventsCount++ - lb.RecordDbServerQuerySampleEvent(timestamp, "db.query.text-val", "db.system.name-val", "user.name-val", "client.address-val", "oracledb.plan_hash_value-val", "oracledb.sql_id-val", "oracledb.child_number-val", "oracledb.sid-val", "oracledb.serial-val", "oracledb.process-val", "oracledb.schemaname-val", "oracledb.program-val", "oracledb.module-val", "oracledb.status-val", "oracledb.state-val", "oracledb.wait_class-val", "oracledb.event-val", "oracledb.object_name-val", "oracledb.object_type-val", "oracledb.osuser-val", 21.100000) + lb.RecordDbServerQuerySampleEvent(ctx, timestamp, "db.query.text-val", "db.system.name-val", "user.name-val", "client.address-val", "oracledb.plan_hash_value-val", "oracledb.sql_id-val", "oracledb.child_number-val", "oracledb.sid-val", "oracledb.serial-val", "oracledb.process-val", "oracledb.schemaname-val", "oracledb.program-val", "oracledb.module-val", "oracledb.status-val", "oracledb.state-val", "oracledb.wait_class-val", "oracledb.event-val", "oracledb.object_name-val", "oracledb.object_type-val", "oracledb.osuser-val", 21.100000) allEventsCount++ - lb.RecordDbServerTopQueryEvent(timestamp, "db.system.name-val", "db.server.name-val", "db.query.text-val", "oracledb.query_plan-val", "oracledb.sql_id-val", "oracledb.child_number-val", 30.100000, 20, 26.100000, 30.100000, 17.100000, 21, 22, 19, 21.100000, 19, 28, 31, 29, 32, 23, 26.100000) + lb.RecordDbServerTopQueryEvent(ctx, timestamp, "db.system.name-val", "db.server.name-val", "db.query.text-val", "oracledb.query_plan-val", "oracledb.sql_id-val", "oracledb.child_number-val", 30.100000, 20, 26.100000, 30.100000, 17.100000, 21, 22, 19, 21.100000, 19, 28, 31, 29, 32, 23, 26.100000) rb := lb.NewResourceBuilder() rb.SetHostName("host.name-val") @@ -133,7 +141,7 @@ func TestLogsBuilder(t *testing.T) { res := rb.Emit() logs := lb.Emit(WithLogsResource(res)) - if tt.expectEmpty { + if tt.expectEmpty || ((tt.name == "default" || tt.name == "filter_set_include") && defaultEventsCount == 0) { assert.Equal(t, 0, logs.ResourceLogs().Len()) return } @@ -157,6 +165,8 @@ func TestLogsBuilder(t *testing.T) { validatedEvents["db.server.query_sample"] = true lr := lrs.At(i) assert.Equal(t, timestamp, lr.Timestamp()) + assert.Equal(t, pcommon.TraceID(traceID), lr.TraceID()) + assert.Equal(t, pcommon.SpanID(spanID), lr.SpanID()) attrVal, ok := lr.Attributes().Get("db.query.text") assert.True(t, ok) assert.Equal(t, "db.query.text-val", attrVal.Str()) @@ -225,6 +235,8 @@ func TestLogsBuilder(t *testing.T) { validatedEvents["db.server.top_query"] = true lr := lrs.At(i) assert.Equal(t, timestamp, lr.Timestamp()) + assert.Equal(t, pcommon.TraceID(traceID), lr.TraceID()) + assert.Equal(t, pcommon.SpanID(spanID), lr.SpanID()) attrVal, ok := lr.Attributes().Get("db.system.name") assert.True(t, ok) assert.Equal(t, "db.system.name-val", attrVal.Str()) diff --git a/receiver/oracledbreceiver/scraper_test.go b/receiver/oracledbreceiver/scraper_test.go index 0a983a662f8ac..ff6bd5299aeb6 100644 --- a/receiver/oracledbreceiver/scraper_test.go +++ b/receiver/oracledbreceiver/scraper_test.go @@ -15,10 +15,10 @@ import ( "strings" "testing" + lru "github.com/hashicorp/golang-lru/v2" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest/plogtest" - - lru "github.com/hashicorp/golang-lru/v2" + "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/oracledbreceiver/internal/metadata" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" @@ -27,8 +27,6 @@ import ( "go.opentelemetry.io/collector/receiver/receivertest" "go.opentelemetry.io/collector/scraper/scrapererror" "go.uber.org/zap" - - "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/oracledbreceiver/internal/metadata" ) func TestScraper_ErrorOnStart(t *testing.T) { @@ -276,7 +274,6 @@ func TestSamplesQuery(t *testing.T) { errs := plogtest.CompareLogs(expectedLogs, logs, plogtest.IgnoreTimestamp()) assert.Equal(t, "db.server.query_sample", logs.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).EventName()) assert.NoError(t, errs) - } }) } From 5400baf1399dcf398170dda553241a5157825a3c Mon Sep 17 00:00:00 2001 From: Sreenath Date: Mon, 30 Jun 2025 13:43:03 +0100 Subject: [PATCH 04/51] cleaning logs --- receiver/oracledbreceiver/scraper.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index c1edb11ab4d1c..8e24d09858f42 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -580,7 +580,7 @@ func (s *oracleScraper) collectQuerySamples(ctx context.Context) (plog.Logs, err obfuscatedSQL, err := ObfuscateSQL(row[sqlText]) if err != nil { - s.logger.Error(fmt.Sprintf("oracleScraper failed updating this metric row: %s", err)) + s.logger.Error(fmt.Sprintf("oracleScraper failed updating this log record: %s", err)) continue } From d258f51a3a52a04e3eb000bfda881f7a281cac09 Mon Sep 17 00:00:00 2001 From: Sreenath Date: Mon, 30 Jun 2025 23:51:13 +0100 Subject: [PATCH 05/51] Adding additional attributes --- receiver/oracledbreceiver/documentation.md | 6 +++++- .../internal/metadata/generated_logs.go | 10 +++++++--- .../internal/metadata/generated_logs_test.go | 14 +++++++++++++- receiver/oracledbreceiver/metadata.yaml | 18 +++++++++++++++++- receiver/oracledbreceiver/scraper.go | 19 +++++++++++++++---- .../templates/oracleQuerySampleSql.tmpl | 2 ++ 6 files changed, 59 insertions(+), 10 deletions(-) diff --git a/receiver/oracledbreceiver/documentation.md b/receiver/oracledbreceiver/documentation.md index 5355e99d7ca42..b176be39c5a45 100644 --- a/receiver/oracledbreceiver/documentation.md +++ b/receiver/oracledbreceiver/documentation.md @@ -400,7 +400,11 @@ sample query | db.query.text | The text of the database query being executed. | Any Str | | db.system.name | The database management system (DBMS) product as identified by the client instrumentation. | Any Str | | user.name | Database user name under which a session is connected to | Any Str | -| client.address | Identifies the name of the machine (host) from which the database client is connecting to the Oracle database. | Any Str | +| db.namespace | The database name. | Any Str | +| client.address | Hostname or address of the client. | Any Str | +| client.port | TCP port used by the client. | Any Int | +| network.peer.address | IP address of the peer client. | Any Str | +| network.peer.port | TCP port used by the peer client. | Any Int | | oracledb.plan_hash_value | Binary hash value calculated on the query execution plan and used to identify similar query execution plans, reported in the HEX format. | Any Str | | oracledb.sql_id | The SQL ID of the query. | Any Str | | oracledb.child_number | The child number of the query. | Any Str | diff --git a/receiver/oracledbreceiver/internal/metadata/generated_logs.go b/receiver/oracledbreceiver/internal/metadata/generated_logs.go index b1449b2111d78..4271b6c85785f 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_logs.go +++ b/receiver/oracledbreceiver/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, dbQueryTextAttributeValue string, dbSystemNameAttributeValue string, userNameAttributeValue string, clientAddressAttributeValue string, oracledbPlanHashValueAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbSidAttributeValue string, oracledbSerialAttributeValue string, oracledbProcessAttributeValue string, oracledbSchemanameAttributeValue string, oracledbProgramAttributeValue string, oracledbModuleAttributeValue string, oracledbStatusAttributeValue string, oracledbStateAttributeValue string, oracledbWaitClassAttributeValue string, oracledbEventAttributeValue string, oracledbObjectNameAttributeValue string, oracledbObjectTypeAttributeValue string, oracledbOsuserAttributeValue string, oracledbDurationSecAttributeValue float64) { +func (e *eventDbServerQuerySample) recordEvent(ctx context.Context, timestamp pcommon.Timestamp, dbQueryTextAttributeValue string, dbSystemNameAttributeValue string, userNameAttributeValue string, dbNamespaceAttributeValue string, clientAddressAttributeValue string, clientPortAttributeValue int64, networkPeerAddressAttributeValue string, networkPeerPortAttributeValue int64, oracledbPlanHashValueAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbSidAttributeValue string, oracledbSerialAttributeValue string, oracledbProcessAttributeValue string, oracledbSchemanameAttributeValue string, oracledbProgramAttributeValue string, oracledbModuleAttributeValue string, oracledbStatusAttributeValue string, oracledbStateAttributeValue string, oracledbWaitClassAttributeValue string, oracledbEventAttributeValue string, oracledbObjectNameAttributeValue string, oracledbObjectTypeAttributeValue string, oracledbOsuserAttributeValue string, oracledbDurationSecAttributeValue float64) { if !e.config.Enabled { return } @@ -34,7 +34,11 @@ func (e *eventDbServerQuerySample) recordEvent(ctx context.Context, timestamp pc lr.Attributes().PutStr("db.query.text", dbQueryTextAttributeValue) lr.Attributes().PutStr("db.system.name", dbSystemNameAttributeValue) lr.Attributes().PutStr("user.name", userNameAttributeValue) + lr.Attributes().PutStr("db.namespace", dbNamespaceAttributeValue) lr.Attributes().PutStr("client.address", clientAddressAttributeValue) + lr.Attributes().PutInt("client.port", clientPortAttributeValue) + lr.Attributes().PutStr("network.peer.address", networkPeerAddressAttributeValue) + lr.Attributes().PutInt("network.peer.port", networkPeerPortAttributeValue) lr.Attributes().PutStr("oracledb.plan_hash_value", oracledbPlanHashValueAttributeValue) lr.Attributes().PutStr("oracledb.sql_id", oracledbSQLIDAttributeValue) lr.Attributes().PutStr("oracledb.child_number", oracledbChildNumberAttributeValue) @@ -249,8 +253,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, dbQueryTextAttributeValue string, dbSystemNameAttributeValue string, userNameAttributeValue string, clientAddressAttributeValue string, oracledbPlanHashValueAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbSidAttributeValue string, oracledbSerialAttributeValue string, oracledbProcessAttributeValue string, oracledbSchemanameAttributeValue string, oracledbProgramAttributeValue string, oracledbModuleAttributeValue string, oracledbStatusAttributeValue string, oracledbStateAttributeValue string, oracledbWaitClassAttributeValue string, oracledbEventAttributeValue string, oracledbObjectNameAttributeValue string, oracledbObjectTypeAttributeValue string, oracledbOsuserAttributeValue string, oracledbDurationSecAttributeValue float64) { - lb.eventDbServerQuerySample.recordEvent(ctx, timestamp, dbQueryTextAttributeValue, dbSystemNameAttributeValue, userNameAttributeValue, clientAddressAttributeValue, oracledbPlanHashValueAttributeValue, oracledbSQLIDAttributeValue, oracledbChildNumberAttributeValue, oracledbSidAttributeValue, oracledbSerialAttributeValue, oracledbProcessAttributeValue, oracledbSchemanameAttributeValue, oracledbProgramAttributeValue, oracledbModuleAttributeValue, oracledbStatusAttributeValue, oracledbStateAttributeValue, oracledbWaitClassAttributeValue, oracledbEventAttributeValue, oracledbObjectNameAttributeValue, oracledbObjectTypeAttributeValue, oracledbOsuserAttributeValue, oracledbDurationSecAttributeValue) +func (lb *LogsBuilder) RecordDbServerQuerySampleEvent(ctx context.Context, timestamp pcommon.Timestamp, dbQueryTextAttributeValue string, dbSystemNameAttributeValue string, userNameAttributeValue string, dbNamespaceAttributeValue string, clientAddressAttributeValue string, clientPortAttributeValue int64, networkPeerAddressAttributeValue string, networkPeerPortAttributeValue int64, oracledbPlanHashValueAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbSidAttributeValue string, oracledbSerialAttributeValue string, oracledbProcessAttributeValue string, oracledbSchemanameAttributeValue string, oracledbProgramAttributeValue string, oracledbModuleAttributeValue string, oracledbStatusAttributeValue string, oracledbStateAttributeValue string, oracledbWaitClassAttributeValue string, oracledbEventAttributeValue string, oracledbObjectNameAttributeValue string, oracledbObjectTypeAttributeValue string, oracledbOsuserAttributeValue string, oracledbDurationSecAttributeValue float64) { + lb.eventDbServerQuerySample.recordEvent(ctx, timestamp, dbQueryTextAttributeValue, dbSystemNameAttributeValue, userNameAttributeValue, dbNamespaceAttributeValue, clientAddressAttributeValue, clientPortAttributeValue, networkPeerAddressAttributeValue, networkPeerPortAttributeValue, oracledbPlanHashValueAttributeValue, oracledbSQLIDAttributeValue, oracledbChildNumberAttributeValue, oracledbSidAttributeValue, oracledbSerialAttributeValue, oracledbProcessAttributeValue, oracledbSchemanameAttributeValue, oracledbProgramAttributeValue, oracledbModuleAttributeValue, oracledbStatusAttributeValue, oracledbStateAttributeValue, oracledbWaitClassAttributeValue, oracledbEventAttributeValue, oracledbObjectNameAttributeValue, oracledbObjectTypeAttributeValue, oracledbOsuserAttributeValue, oracledbDurationSecAttributeValue) } // RecordDbServerTopQueryEvent adds a log record of db.server.top_query event. diff --git a/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go b/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go index a41cff94246ac..a22897eed35a6 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go @@ -130,7 +130,7 @@ func TestLogsBuilder(t *testing.T) { allEventsCount := 0 allEventsCount++ - lb.RecordDbServerQuerySampleEvent(ctx, timestamp, "db.query.text-val", "db.system.name-val", "user.name-val", "client.address-val", "oracledb.plan_hash_value-val", "oracledb.sql_id-val", "oracledb.child_number-val", "oracledb.sid-val", "oracledb.serial-val", "oracledb.process-val", "oracledb.schemaname-val", "oracledb.program-val", "oracledb.module-val", "oracledb.status-val", "oracledb.state-val", "oracledb.wait_class-val", "oracledb.event-val", "oracledb.object_name-val", "oracledb.object_type-val", "oracledb.osuser-val", 21.100000) + lb.RecordDbServerQuerySampleEvent(ctx, timestamp, "db.query.text-val", "db.system.name-val", "user.name-val", "db.namespace-val", "client.address-val", 11, "network.peer.address-val", 17, "oracledb.plan_hash_value-val", "oracledb.sql_id-val", "oracledb.child_number-val", "oracledb.sid-val", "oracledb.serial-val", "oracledb.process-val", "oracledb.schemaname-val", "oracledb.program-val", "oracledb.module-val", "oracledb.status-val", "oracledb.state-val", "oracledb.wait_class-val", "oracledb.event-val", "oracledb.object_name-val", "oracledb.object_type-val", "oracledb.osuser-val", 21.100000) allEventsCount++ lb.RecordDbServerTopQueryEvent(ctx, timestamp, "db.system.name-val", "db.server.name-val", "db.query.text-val", "oracledb.query_plan-val", "oracledb.sql_id-val", "oracledb.child_number-val", 30.100000, 20, 26.100000, 30.100000, 17.100000, 21, 22, 19, 21.100000, 19, 28, 31, 29, 32, 23, 26.100000) @@ -176,9 +176,21 @@ 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("db.namespace") + assert.True(t, ok) + assert.Equal(t, "db.namespace-val", attrVal.Str()) attrVal, ok = lr.Attributes().Get("client.address") assert.True(t, ok) assert.Equal(t, "client.address-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("client.port") + assert.True(t, ok) + assert.EqualValues(t, 11, attrVal.Int()) + attrVal, ok = lr.Attributes().Get("network.peer.address") + assert.True(t, ok) + assert.Equal(t, "network.peer.address-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("network.peer.port") + assert.True(t, ok) + assert.EqualValues(t, 17, attrVal.Int()) attrVal, ok = lr.Attributes().Get("oracledb.plan_hash_value") assert.True(t, ok) assert.Equal(t, "oracledb.plan_hash_value-val", attrVal.Str()) diff --git a/receiver/oracledbreceiver/metadata.yaml b/receiver/oracledbreceiver/metadata.yaml index 0479d15746125..558b856a4229e 100644 --- a/receiver/oracledbreceiver/metadata.yaml +++ b/receiver/oracledbreceiver/metadata.yaml @@ -101,8 +101,20 @@ attributes: description: Binary hash value calculated on the query execution plan and used to identify similar query execution plans, reported in the HEX format. type: string client.address: - description: Identifies the name of the machine (host) from which the database client is connecting to the Oracle database. + description: Hostname or address of the client. type: string + client.port: + description: TCP port used by the client. + type: int + db.namespace: + description: The database name. + type: string + network.peer.address: + description: IP address of the peer client. + type: string + network.peer.port: + description: TCP port used by the peer client. + type: int oracledb.sid: description: ID of the Oracle Server session. type: string @@ -183,7 +195,11 @@ events: - db.query.text - db.system.name - user.name + - db.namespace - client.address + - client.port + - network.peer.address + - network.peer.port - oracledb.plan_hash_value - oracledb.sql_id - oracledb.child_number diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index c1edb11ab4d1c..340416cbbb331 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -525,6 +525,8 @@ func (s *oracleScraper) scrapeLogs(ctx context.Context) (plog.Logs, error) { } } + s.logger.Info("Done scraping 1") + if s.logsBuilderConfig.Events.DbServerQuerySample.Enabled { sampleLogs, samplesCollectionErrors := s.collectQuerySamples(ctx) if samplesCollectionErrors != nil { @@ -534,6 +536,7 @@ func (s *oracleScraper) scrapeLogs(ctx context.Context) (plog.Logs, error) { } } + s.logger.Info("Done scraping 2") return logs, errors.Join(scrapeErrors...) } @@ -558,6 +561,8 @@ func (s *oracleScraper) collectQuerySamples(ctx context.Context) (plog.Logs, err const sqlText = "SQL_FULLTEXT" const username = "USERNAME" const waitclass = "WAIT_CLASS" + const port = "PORT" + const serviceName = "SERVICE_NAME" var scrapeErrors []error @@ -580,7 +585,7 @@ func (s *oracleScraper) collectQuerySamples(ctx context.Context) (plog.Logs, err obfuscatedSQL, err := ObfuscateSQL(row[sqlText]) if err != nil { - s.logger.Error(fmt.Sprintf("oracleScraper failed updating this metric row: %s", err)) + s.logger.Error(fmt.Sprintf("oracleScraper failed updating this log record: %s", err)) continue } @@ -591,9 +596,15 @@ func (s *oracleScraper) collectQuerySamples(ctx context.Context) (plog.Logs, err scrapeErrors = append(scrapeErrors, fmt.Errorf("failed to parse int64 for Duration, value was %s: %w", row[duration], err)) } - s.lb.RecordDbServerQuerySampleEvent(ctx, timestamp, obfuscatedSQL, dbSystemNameVal, row[username], row[hostName], queryPlanHashVal, row[sqlID], row[sqlChildNumber], - row[sid], row[serialNumber], row[process], row[schemaName], row[program], row[module], row[status], row[state], row[waitclass], - row[event], row[objectName], row[objectType], row[osUser], queryDuration) + clientPort, err := strconv.ParseInt(row[port], 10, 64) + if err != nil { + clientPort = 0 + } + + s.lb.RecordDbServerQuerySampleEvent(ctx, timestamp, obfuscatedSQL, dbSystemNameVal, row[username], row[serviceName], row[hostName], + clientPort, row[hostName], clientPort, queryPlanHashVal, row[sqlID], row[sqlChildNumber], row[sid], row[serialNumber], row[process], + row[schemaName], row[program], row[module], row[status], row[state], row[waitclass], row[event], row[objectName], row[objectType], + row[osUser], queryDuration) } out := s.lb.Emit(metadata.WithLogsResource(rb.Emit())) diff --git a/receiver/oracledbreceiver/templates/oracleQuerySampleSql.tmpl b/receiver/oracledbreceiver/templates/oracleQuerySampleSql.tmpl index f958279ea47ac..e1047bea99e92 100644 --- a/receiver/oracledbreceiver/templates/oracleQuerySampleSql.tmpl +++ b/receiver/oracledbreceiver/templates/oracleQuerySampleSql.tmpl @@ -14,6 +14,8 @@ S.PROGRAM, S.MODULE, S.STATUS, S.STATE, +S.PORT, +S.SERVICE_NAME, Q.PLAN_HASH_VALUE, NVL((SYSDATE - SQL_EXEC_START) * 86400,0) AS DURATION_SEC, CASE WHEN S.TIME_REMAINING_MICRO IS NOT NULL From 50999088d8acb5b3decc170018621337a83a1034 Mon Sep 17 00:00:00 2001 From: Sreenath Date: Tue, 1 Jul 2025 00:09:35 +0100 Subject: [PATCH 06/51] Lint & tests --- receiver/oracledbreceiver/scraper.go | 3 --- receiver/oracledbreceiver/scraper_test.go | 6 ++---- .../testdata/expectedSamplesFile.yaml | 14 +++++++++++++- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index 340416cbbb331..82e34ac91fd1d 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -525,8 +525,6 @@ func (s *oracleScraper) scrapeLogs(ctx context.Context) (plog.Logs, error) { } } - s.logger.Info("Done scraping 1") - if s.logsBuilderConfig.Events.DbServerQuerySample.Enabled { sampleLogs, samplesCollectionErrors := s.collectQuerySamples(ctx) if samplesCollectionErrors != nil { @@ -536,7 +534,6 @@ func (s *oracleScraper) scrapeLogs(ctx context.Context) (plog.Logs, error) { } } - s.logger.Info("Done scraping 2") return logs, errors.Join(scrapeErrors...) } diff --git a/receiver/oracledbreceiver/scraper_test.go b/receiver/oracledbreceiver/scraper_test.go index 0a983a662f8ac..65fc75b39e22a 100644 --- a/receiver/oracledbreceiver/scraper_test.go +++ b/receiver/oracledbreceiver/scraper_test.go @@ -15,9 +15,6 @@ import ( "strings" "testing" - "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden" - "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest/plogtest" - lru "github.com/hashicorp/golang-lru/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -28,6 +25,8 @@ import ( "go.opentelemetry.io/collector/scraper/scrapererror" "go.uber.org/zap" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest/plogtest" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/oracledbreceiver/internal/metadata" ) @@ -276,7 +275,6 @@ func TestSamplesQuery(t *testing.T) { errs := plogtest.CompareLogs(expectedLogs, logs, plogtest.IgnoreTimestamp()) assert.Equal(t, "db.server.query_sample", logs.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).EventName()) assert.NoError(t, errs) - } }) } diff --git a/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml b/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml index 9c233996ddcc1..a57d31d8afd23 100644 --- a/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml +++ b/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml @@ -19,9 +19,21 @@ resourceLogs: - key: user.name value: stringValue: "" + - key: db.namespace + value: + stringValue: "" - key: client.address value: stringValue: "" + - key: client.port + value: + intValue: "0" + - key: network.peer.address + value: + stringValue: "" + - key: network.peer.port + value: + intValue: "0" - key: oracledb.plan_hash_value value: stringValue: "" @@ -76,7 +88,7 @@ resourceLogs: body: {} eventName: db.server.query_sample spanId: "" - timeUnixNano: "1750964071570576000" + timeUnixNano: "1751324007889535000" traceId: "" scope: name: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/oracledbreceiver From 5c6a451768d3d9ae421cd582661c2732694aa44a Mon Sep 17 00:00:00 2001 From: Sreenath Date: Tue, 1 Jul 2025 11:38:14 +0100 Subject: [PATCH 07/51] merge from upstream --- receiver/oracledbreceiver/go.mod | 12 ++++++------ receiver/oracledbreceiver/go.sum | 12 ++++++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/receiver/oracledbreceiver/go.mod b/receiver/oracledbreceiver/go.mod index 2ee03ed7da71a..b769ccc03b7b0 100644 --- a/receiver/oracledbreceiver/go.mod +++ b/receiver/oracledbreceiver/go.mod @@ -6,8 +6,8 @@ require ( github.com/DataDog/datadog-agent/pkg/obfuscate v0.67.0 github.com/google/go-cmp v0.7.0 github.com/hashicorp/golang-lru/v2 v2.0.7 - github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden v0.128.0 - github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.128.0 + github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden v0.129.0 + github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.129.0 github.com/sijms/go-ora/v2 v2.9.0 github.com/stretchr/testify v1.10.0 go.opentelemetry.io/collector/component v1.35.1-0.20250630174123-18b3b578b0b3 @@ -49,7 +49,7 @@ require ( github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.128.0 // indirect + github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.129.0 // indirect github.com/outcaste-io/ristretto v0.2.3 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect @@ -69,11 +69,11 @@ require ( go.opentelemetry.io/otel/sdk v1.37.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect go.uber.org/atomic v1.11.0 // indirect - go.yaml.in/yaml/v3 v3.0.3 // indirect - golang.org/x/net v0.39.0 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/net v0.41.0 // indirect golang.org/x/sys v0.33.0 // indirect golang.org/x/text v0.26.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/grpc v1.73.0 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/receiver/oracledbreceiver/go.sum b/receiver/oracledbreceiver/go.sum index d0ece358ea7a4..c8532bac63850 100644 --- a/receiver/oracledbreceiver/go.sum +++ b/receiver/oracledbreceiver/go.sum @@ -68,10 +68,16 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden v0.128.0 h1:GJzARUS5NcCeYr7pwlrYMEK+fl92cmCDED2to7nPuCQ= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden v0.128.0/go.mod h1:YrULw8EK8Vj0LX2ZhtfqMaIlLATIGOlbII9RDR8lPeI= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden v0.129.0 h1:ib4F7Rsefrpcq3Uo72UUb58+PE8uZs5rBYs1cyHGSJs= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden v0.129.0/go.mod h1:U0i/4xJl9xpII4DnpHBWP3Kang7ZZuDTf7XDuBjYxKo= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.128.0 h1:+rUULr4xqOJjZK3SokFmRYzsiPq5onoWoSv3He4aaus= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.128.0/go.mod h1:Fh2SXPeFkr4J97w9CV/apFAib8TC9Hi0P08xtiT7Lng= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.129.0 h1:ydkfqpZ5BWZfEJEs7OUhTHW59og5aZspbUYxoGcAEok= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.129.0/go.mod h1:oA+49dkzmhUx0YFC9JXGuPPSBL0TOTp6jkv7qSr2n0Q= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.128.0 h1:8OWwRSdIhm3DY3PEYJ0PtSEz1a1OjL0fghLXSr14JMk= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.128.0/go.mod h1:32OeaysZe4vkSmD1LJ18Q1DfooryYqpSzFNmz+5A5RU= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.129.0 h1:AOVxBvCZfTPj0GLGqBVHpAnlC9t9pl1JXUQXymHliiY= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.129.0/go.mod h1:0CAJ32V/bCUBhNTEvnN9wlOG5IsyZ+Bmhe9e3Eri7CU= github.com/outcaste-io/ristretto v0.2.3 h1:AK4zt/fJ76kjlYObOeNwh4T3asEuaCmp26pOvUOL9w0= github.com/outcaste-io/ristretto v0.2.3/go.mod h1:W8HywhmtlopSB1jeMg3JtdIhf+DYkLAr0VN/s4+MHac= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -169,6 +175,8 @@ go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE= go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -182,6 +190,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -213,6 +223,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 h1:e0AIkUUhxyBKh6ssZNrAMeqhA7RKUj42346d1y02i2g= google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= From 1f145fc5006ef5b0188cab393ff4f8851f16d5b8 Mon Sep 17 00:00:00 2001 From: Sreenath Date: Mon, 7 Jul 2025 10:57:19 +0100 Subject: [PATCH 08/51] Merge from upstream --- receiver/oracledbreceiver/go.mod | 2 +- receiver/oracledbreceiver/go.sum | 2 + .../internal/metadata/generated_logs.go | 114 +++++++++--------- 3 files changed, 60 insertions(+), 58 deletions(-) diff --git a/receiver/oracledbreceiver/go.mod b/receiver/oracledbreceiver/go.mod index 542f3485850fc..0012be4605b02 100644 --- a/receiver/oracledbreceiver/go.mod +++ b/receiver/oracledbreceiver/go.mod @@ -70,7 +70,7 @@ require ( go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/net v0.39.0 // indirect + golang.org/x/net v0.41.0 // indirect golang.org/x/sys v0.33.0 // indirect golang.org/x/text v0.26.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect diff --git a/receiver/oracledbreceiver/go.sum b/receiver/oracledbreceiver/go.sum index f30f16ecb3599..ae5ac57a85d3c 100644 --- a/receiver/oracledbreceiver/go.sum +++ b/receiver/oracledbreceiver/go.sum @@ -182,6 +182,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/receiver/oracledbreceiver/internal/metadata/generated_logs.go b/receiver/oracledbreceiver/internal/metadata/generated_logs.go index 4271b6c85785f..722cfbedc4269 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_logs.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_logs.go @@ -22,40 +22,40 @@ func (e *eventDbServerQuerySample) recordEvent(ctx context.Context, timestamp pc if !e.config.Enabled { return } - lr := e.data.AppendEmpty() - lr.SetEventName("db.server.query_sample") - lr.SetTimestamp(timestamp) + dp := e.data.AppendEmpty() + dp.SetEventName("db.server.query_sample") + dp.SetTimestamp(timestamp) if span := trace.SpanContextFromContext(ctx); span.IsValid() { - lr.SetTraceID(pcommon.TraceID(span.TraceID())) - lr.SetSpanID(pcommon.SpanID(span.SpanID())) + dp.SetTraceID(pcommon.TraceID(span.TraceID())) + dp.SetSpanID(pcommon.SpanID(span.SpanID())) } + dp.Attributes().PutStr("db.query.text", dbQueryTextAttributeValue) + dp.Attributes().PutStr("db.system.name", dbSystemNameAttributeValue) + dp.Attributes().PutStr("user.name", userNameAttributeValue) + dp.Attributes().PutStr("db.namespace", dbNamespaceAttributeValue) + dp.Attributes().PutStr("client.address", clientAddressAttributeValue) + dp.Attributes().PutInt("client.port", clientPortAttributeValue) + dp.Attributes().PutStr("network.peer.address", networkPeerAddressAttributeValue) + dp.Attributes().PutInt("network.peer.port", networkPeerPortAttributeValue) + dp.Attributes().PutStr("oracledb.plan_hash_value", oracledbPlanHashValueAttributeValue) + dp.Attributes().PutStr("oracledb.sql_id", oracledbSQLIDAttributeValue) + dp.Attributes().PutStr("oracledb.child_number", oracledbChildNumberAttributeValue) + dp.Attributes().PutStr("oracledb.sid", oracledbSidAttributeValue) + dp.Attributes().PutStr("oracledb.serial", oracledbSerialAttributeValue) + dp.Attributes().PutStr("oracledb.process", oracledbProcessAttributeValue) + dp.Attributes().PutStr("oracledb.schemaname", oracledbSchemanameAttributeValue) + dp.Attributes().PutStr("oracledb.program", oracledbProgramAttributeValue) + dp.Attributes().PutStr("oracledb.module", oracledbModuleAttributeValue) + dp.Attributes().PutStr("oracledb.status", oracledbStatusAttributeValue) + dp.Attributes().PutStr("oracledb.state", oracledbStateAttributeValue) + dp.Attributes().PutStr("oracledb.wait_class", oracledbWaitClassAttributeValue) + dp.Attributes().PutStr("oracledb.event", oracledbEventAttributeValue) + dp.Attributes().PutStr("oracledb.object_name", oracledbObjectNameAttributeValue) + dp.Attributes().PutStr("oracledb.object_type", oracledbObjectTypeAttributeValue) + dp.Attributes().PutStr("oracledb.osuser", oracledbOsuserAttributeValue) + dp.Attributes().PutDouble("oracledb.duration_sec", oracledbDurationSecAttributeValue) - lr.Attributes().PutStr("db.query.text", dbQueryTextAttributeValue) - lr.Attributes().PutStr("db.system.name", dbSystemNameAttributeValue) - lr.Attributes().PutStr("user.name", userNameAttributeValue) - lr.Attributes().PutStr("db.namespace", dbNamespaceAttributeValue) - lr.Attributes().PutStr("client.address", clientAddressAttributeValue) - lr.Attributes().PutInt("client.port", clientPortAttributeValue) - lr.Attributes().PutStr("network.peer.address", networkPeerAddressAttributeValue) - lr.Attributes().PutInt("network.peer.port", networkPeerPortAttributeValue) - lr.Attributes().PutStr("oracledb.plan_hash_value", oracledbPlanHashValueAttributeValue) - lr.Attributes().PutStr("oracledb.sql_id", oracledbSQLIDAttributeValue) - lr.Attributes().PutStr("oracledb.child_number", oracledbChildNumberAttributeValue) - lr.Attributes().PutStr("oracledb.sid", oracledbSidAttributeValue) - lr.Attributes().PutStr("oracledb.serial", oracledbSerialAttributeValue) - lr.Attributes().PutStr("oracledb.process", oracledbProcessAttributeValue) - lr.Attributes().PutStr("oracledb.schemaname", oracledbSchemanameAttributeValue) - lr.Attributes().PutStr("oracledb.program", oracledbProgramAttributeValue) - lr.Attributes().PutStr("oracledb.module", oracledbModuleAttributeValue) - lr.Attributes().PutStr("oracledb.status", oracledbStatusAttributeValue) - lr.Attributes().PutStr("oracledb.state", oracledbStateAttributeValue) - lr.Attributes().PutStr("oracledb.wait_class", oracledbWaitClassAttributeValue) - lr.Attributes().PutStr("oracledb.event", oracledbEventAttributeValue) - lr.Attributes().PutStr("oracledb.object_name", oracledbObjectNameAttributeValue) - lr.Attributes().PutStr("oracledb.object_type", oracledbObjectTypeAttributeValue) - lr.Attributes().PutStr("oracledb.osuser", oracledbOsuserAttributeValue) - lr.Attributes().PutDouble("oracledb.duration_sec", oracledbDurationSecAttributeValue) } // emit appends recorded event data to a events slice and prepares it for recording another set of log records. @@ -82,37 +82,37 @@ func (e *eventDbServerTopQuery) recordEvent(ctx context.Context, timestamp pcomm if !e.config.Enabled { return } - lr := e.data.AppendEmpty() - lr.SetEventName("db.server.top_query") - lr.SetTimestamp(timestamp) + dp := e.data.AppendEmpty() + dp.SetEventName("db.server.top_query") + dp.SetTimestamp(timestamp) if span := trace.SpanContextFromContext(ctx); span.IsValid() { - lr.SetTraceID(pcommon.TraceID(span.TraceID())) - lr.SetSpanID(pcommon.SpanID(span.SpanID())) + dp.SetTraceID(pcommon.TraceID(span.TraceID())) + dp.SetSpanID(pcommon.SpanID(span.SpanID())) } + dp.Attributes().PutStr("db.system.name", dbSystemNameAttributeValue) + dp.Attributes().PutStr("db.server.name", dbServerNameAttributeValue) + dp.Attributes().PutStr("db.query.text", dbQueryTextAttributeValue) + dp.Attributes().PutStr("oracledb.query_plan", oracledbQueryPlanAttributeValue) + dp.Attributes().PutStr("oracledb.sql_id", oracledbSQLIDAttributeValue) + dp.Attributes().PutStr("oracledb.child_number", oracledbChildNumberAttributeValue) + dp.Attributes().PutDouble("oracledb.application_wait_time", oracledbApplicationWaitTimeAttributeValue) + dp.Attributes().PutInt("oracledb.buffer_gets", oracledbBufferGetsAttributeValue) + dp.Attributes().PutDouble("oracledb.cluster_wait_time", oracledbClusterWaitTimeAttributeValue) + dp.Attributes().PutDouble("oracledb.concurrency_wait_time", oracledbConcurrencyWaitTimeAttributeValue) + dp.Attributes().PutDouble("oracledb.cpu_time", oracledbCPUTimeAttributeValue) + dp.Attributes().PutInt("oracledb.direct_reads", oracledbDirectReadsAttributeValue) + dp.Attributes().PutInt("oracledb.direct_writes", oracledbDirectWritesAttributeValue) + dp.Attributes().PutInt("oracledb.disk_reads", oracledbDiskReadsAttributeValue) + dp.Attributes().PutDouble("oracledb.elapsed_time", oracledbElapsedTimeAttributeValue) + dp.Attributes().PutInt("oracledb.executions", oracledbExecutionsAttributeValue) + dp.Attributes().PutInt("oracledb.physical_read_bytes", oracledbPhysicalReadBytesAttributeValue) + dp.Attributes().PutInt("oracledb.physical_read_requests", oracledbPhysicalReadRequestsAttributeValue) + dp.Attributes().PutInt("oracledb.physical_write_bytes", oracledbPhysicalWriteBytesAttributeValue) + dp.Attributes().PutInt("oracledb.physical_write_requests", oracledbPhysicalWriteRequestsAttributeValue) + dp.Attributes().PutInt("oracledb.rows_processed", oracledbRowsProcessedAttributeValue) + dp.Attributes().PutDouble("oracledb.user_io_wait_time", oracledbUserIoWaitTimeAttributeValue) - lr.Attributes().PutStr("db.system.name", dbSystemNameAttributeValue) - lr.Attributes().PutStr("db.server.name", dbServerNameAttributeValue) - lr.Attributes().PutStr("db.query.text", dbQueryTextAttributeValue) - lr.Attributes().PutStr("oracledb.query_plan", oracledbQueryPlanAttributeValue) - lr.Attributes().PutStr("oracledb.sql_id", oracledbSQLIDAttributeValue) - lr.Attributes().PutStr("oracledb.child_number", oracledbChildNumberAttributeValue) - lr.Attributes().PutDouble("oracledb.application_wait_time", oracledbApplicationWaitTimeAttributeValue) - lr.Attributes().PutInt("oracledb.buffer_gets", oracledbBufferGetsAttributeValue) - lr.Attributes().PutDouble("oracledb.cluster_wait_time", oracledbClusterWaitTimeAttributeValue) - lr.Attributes().PutDouble("oracledb.concurrency_wait_time", oracledbConcurrencyWaitTimeAttributeValue) - lr.Attributes().PutDouble("oracledb.cpu_time", oracledbCPUTimeAttributeValue) - lr.Attributes().PutInt("oracledb.direct_reads", oracledbDirectReadsAttributeValue) - lr.Attributes().PutInt("oracledb.direct_writes", oracledbDirectWritesAttributeValue) - lr.Attributes().PutInt("oracledb.disk_reads", oracledbDiskReadsAttributeValue) - lr.Attributes().PutDouble("oracledb.elapsed_time", oracledbElapsedTimeAttributeValue) - lr.Attributes().PutInt("oracledb.executions", oracledbExecutionsAttributeValue) - lr.Attributes().PutInt("oracledb.physical_read_bytes", oracledbPhysicalReadBytesAttributeValue) - lr.Attributes().PutInt("oracledb.physical_read_requests", oracledbPhysicalReadRequestsAttributeValue) - lr.Attributes().PutInt("oracledb.physical_write_bytes", oracledbPhysicalWriteBytesAttributeValue) - lr.Attributes().PutInt("oracledb.physical_write_requests", oracledbPhysicalWriteRequestsAttributeValue) - lr.Attributes().PutInt("oracledb.rows_processed", oracledbRowsProcessedAttributeValue) - lr.Attributes().PutDouble("oracledb.user_io_wait_time", oracledbUserIoWaitTimeAttributeValue) } // emit appends recorded event data to a events slice and prepares it for recording another set of log records. From 425797ddb463f45033667f615eab0f4c680f3cc3 Mon Sep 17 00:00:00 2001 From: Sreenath Date: Mon, 7 Jul 2025 12:02:54 +0100 Subject: [PATCH 09/51] Removing 'Query sample' implementaion. Will be raising separate PR --- receiver/oracledbreceiver/config.go | 8 -- receiver/oracledbreceiver/documentation.md | 34 ------- receiver/oracledbreceiver/factory.go | 5 +- .../internal/metadata/generated_config.go | 6 +- .../internal/metadata/generated_logs.go | 68 ------------- .../internal/metadata/generated_logs_test.go | 85 ----------------- .../internal/metadata/testdata/config.yaml | 4 - receiver/oracledbreceiver/metadata.yaml | 94 +----------------- receiver/oracledbreceiver/scraper.go | 95 +------------------ receiver/oracledbreceiver/scraper_test.go | 83 ---------------- .../templates/oracleQuerySampleSql.tmpl | 33 ------- .../oracledbreceiver/testdata/config.yaml | 4 - .../testdata/expectedSamplesFile.yaml | 95 ------------------- 13 files changed, 6 insertions(+), 608 deletions(-) delete mode 100644 receiver/oracledbreceiver/templates/oracleQuerySampleSql.tmpl delete mode 100644 receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml diff --git a/receiver/oracledbreceiver/config.go b/receiver/oracledbreceiver/config.go index 753ae540387b5..ee6a957511e6e 100644 --- a/receiver/oracledbreceiver/config.go +++ b/receiver/oracledbreceiver/config.go @@ -35,13 +35,6 @@ type TopQueryCollection struct { QueryCacheSize int `mapstructure:"query_cache_size"` } -type QuerySample struct { - MaxRowsPerQuery uint64 `mapstructure:"max_rows_per_query"` - - // prevent unkeyed literal initialization - _ struct{} -} - type Config struct { DataSource string `mapstructure:"datasource"` Endpoint string `mapstructure:"endpoint"` @@ -53,7 +46,6 @@ type Config struct { metadata.LogsBuilderConfig `mapstructure:",squash"` TopQueryCollection `mapstructure:"top_query_collection"` - QuerySample `mapstructure:"query_sample_collection"` } func (c Config) Validate() error { diff --git a/receiver/oracledbreceiver/documentation.md b/receiver/oracledbreceiver/documentation.md index 9ce0f2b5d1297..44ec1858f1149 100644 --- a/receiver/oracledbreceiver/documentation.md +++ b/receiver/oracledbreceiver/documentation.md @@ -389,40 +389,6 @@ events: enabled: true ``` -### db.server.query_sample - -sample query - -#### Attributes - -| Name | Description | Values | -| ---- | ----------- | ------ | -| db.query.text | The text of the database query being executed. | Any Str | -| db.system.name | The database management system (DBMS) product as identified by the client instrumentation. | Any Str | -| user.name | Database user name under which a session is connected to | Any Str | -| db.namespace | The database name. | Any Str | -| client.address | Hostname or address of the client. | Any Str | -| client.port | TCP port used by the client. | Any Int | -| network.peer.address | IP address of the peer client. | Any Str | -| network.peer.port | TCP port used by the peer client. | Any Int | -| oracledb.plan_hash_value | Binary hash value calculated on the query execution plan and used to identify similar query execution plans, reported in the HEX format. | Any Str | -| oracledb.sql_id | The SQL ID of the query. | Any Str | -| oracledb.child_number | The child number of the query. | Any Str | -| oracledb.sid | ID of the Oracle Server session. | Any Str | -| oracledb.serial | Serial number associated with a session. | Any Str | -| oracledb.process | The operating system process ID (PID) associated with a session. | Any Str | -| oracledb.schemaname | Oracle schema under which SQL statements are being executed | Any Str | -| oracledb.program | Name of the client program or tool that initiated the Oracle database session. | Any Str | -| oracledb.module | Logical module name of the client application that initiated a query or session. | Any Str | -| oracledb.status | Execution state or result of a database query or session. | Any Str | -| oracledb.state | Current state of the query or the session executing it. | Any Str | -| oracledb.wait_class | The category of wait events a query or session is currently experiencing in Oracle Database. | Any Str | -| oracledb.event | The specific wait event that a query or session is currently experiencing. | Any Str | -| oracledb.object_name | Name of the database object that a query is accessing. | Any Str | -| oracledb.object_type | Type of the database object that a query is accessing. | Any Str | -| oracledb.osuser | Name of the operating system user that initiated or is running the Oracle database session. | Any Str | -| oracledb.duration_sec | Total time taken by a database query to execute. | Any Double | - ### db.server.top_query top query diff --git a/receiver/oracledbreceiver/factory.go b/receiver/oracledbreceiver/factory.go index 84f7a38ab5d3d..16067222f18f9 100644 --- a/receiver/oracledbreceiver/factory.go +++ b/receiver/oracledbreceiver/factory.go @@ -44,9 +44,6 @@ func createDefaultConfig() component.Config { ControllerConfig: cfg, MetricsBuilderConfig: metadata.DefaultMetricsBuilderConfig(), LogsBuilderConfig: metadata.DefaultLogsBuilderConfig(), - QuerySample: QuerySample{ - MaxRowsPerQuery: 100, - }, TopQueryCollection: TopQueryCollection{ MaxQuerySampleCount: 1000, TopQueryCount: 200, @@ -123,7 +120,7 @@ func createLogsReceiverFunc(sqlOpenerFunc sqlOpenerFunc, clientProviderFunc clie mp, err := newLogsScraper(logsBuilder, sqlCfg.LogsBuilderConfig, sqlCfg.ControllerConfig, settings.Logger, func() (*sql.DB, error) { return sqlOpenerFunc(getDataSource(*sqlCfg)) - }, clientProviderFunc, instanceName, metricCache, sqlCfg.TopQueryCollection, sqlCfg.QuerySample, hostName) + }, clientProviderFunc, instanceName, metricCache, sqlCfg.TopQueryCollection, hostName) if err != nil { return nil, err } diff --git a/receiver/oracledbreceiver/internal/metadata/generated_config.go b/receiver/oracledbreceiver/internal/metadata/generated_config.go index 8015aea85d87f..d1b9fae144832 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_config.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_config.go @@ -220,15 +220,11 @@ func (ec *EventConfig) Unmarshal(parser *confmap.Conf) error { // EventsConfig provides config for oracledb events. type EventsConfig struct { - DbServerQuerySample EventConfig `mapstructure:"db.server.query_sample"` - DbServerTopQuery EventConfig `mapstructure:"db.server.top_query"` + DbServerTopQuery EventConfig `mapstructure:"db.server.top_query"` } func DefaultEventsConfig() EventsConfig { return EventsConfig{ - DbServerQuerySample: EventConfig{ - Enabled: false, - }, DbServerTopQuery: EventConfig{ Enabled: false, }, diff --git a/receiver/oracledbreceiver/internal/metadata/generated_logs.go b/receiver/oracledbreceiver/internal/metadata/generated_logs.go index 722cfbedc4269..4ff64cec54bc7 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_logs.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_logs.go @@ -13,66 +13,6 @@ import ( "go.opentelemetry.io/otel/trace" ) -type eventDbServerQuerySample struct { - data plog.LogRecordSlice // data buffer for generated log records. - config EventConfig // event config provided by user. -} - -func (e *eventDbServerQuerySample) recordEvent(ctx context.Context, timestamp pcommon.Timestamp, dbQueryTextAttributeValue string, dbSystemNameAttributeValue string, userNameAttributeValue string, dbNamespaceAttributeValue string, clientAddressAttributeValue string, clientPortAttributeValue int64, networkPeerAddressAttributeValue string, networkPeerPortAttributeValue int64, oracledbPlanHashValueAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbSidAttributeValue string, oracledbSerialAttributeValue string, oracledbProcessAttributeValue string, oracledbSchemanameAttributeValue string, oracledbProgramAttributeValue string, oracledbModuleAttributeValue string, oracledbStatusAttributeValue string, oracledbStateAttributeValue string, oracledbWaitClassAttributeValue string, oracledbEventAttributeValue string, oracledbObjectNameAttributeValue string, oracledbObjectTypeAttributeValue string, oracledbOsuserAttributeValue string, oracledbDurationSecAttributeValue float64) { - if !e.config.Enabled { - return - } - dp := e.data.AppendEmpty() - dp.SetEventName("db.server.query_sample") - dp.SetTimestamp(timestamp) - - if span := trace.SpanContextFromContext(ctx); span.IsValid() { - dp.SetTraceID(pcommon.TraceID(span.TraceID())) - dp.SetSpanID(pcommon.SpanID(span.SpanID())) - } - dp.Attributes().PutStr("db.query.text", dbQueryTextAttributeValue) - dp.Attributes().PutStr("db.system.name", dbSystemNameAttributeValue) - dp.Attributes().PutStr("user.name", userNameAttributeValue) - dp.Attributes().PutStr("db.namespace", dbNamespaceAttributeValue) - dp.Attributes().PutStr("client.address", clientAddressAttributeValue) - dp.Attributes().PutInt("client.port", clientPortAttributeValue) - dp.Attributes().PutStr("network.peer.address", networkPeerAddressAttributeValue) - dp.Attributes().PutInt("network.peer.port", networkPeerPortAttributeValue) - dp.Attributes().PutStr("oracledb.plan_hash_value", oracledbPlanHashValueAttributeValue) - dp.Attributes().PutStr("oracledb.sql_id", oracledbSQLIDAttributeValue) - dp.Attributes().PutStr("oracledb.child_number", oracledbChildNumberAttributeValue) - dp.Attributes().PutStr("oracledb.sid", oracledbSidAttributeValue) - dp.Attributes().PutStr("oracledb.serial", oracledbSerialAttributeValue) - dp.Attributes().PutStr("oracledb.process", oracledbProcessAttributeValue) - dp.Attributes().PutStr("oracledb.schemaname", oracledbSchemanameAttributeValue) - dp.Attributes().PutStr("oracledb.program", oracledbProgramAttributeValue) - dp.Attributes().PutStr("oracledb.module", oracledbModuleAttributeValue) - dp.Attributes().PutStr("oracledb.status", oracledbStatusAttributeValue) - dp.Attributes().PutStr("oracledb.state", oracledbStateAttributeValue) - dp.Attributes().PutStr("oracledb.wait_class", oracledbWaitClassAttributeValue) - dp.Attributes().PutStr("oracledb.event", oracledbEventAttributeValue) - dp.Attributes().PutStr("oracledb.object_name", oracledbObjectNameAttributeValue) - dp.Attributes().PutStr("oracledb.object_type", oracledbObjectTypeAttributeValue) - dp.Attributes().PutStr("oracledb.osuser", oracledbOsuserAttributeValue) - dp.Attributes().PutDouble("oracledb.duration_sec", oracledbDurationSecAttributeValue) - -} - -// emit appends recorded event data to a events slice and prepares it for recording another set of log records. -func (e *eventDbServerQuerySample) emit(lrs plog.LogRecordSlice) { - if e.config.Enabled && e.data.Len() > 0 { - e.data.MoveAndAppendTo(lrs) - } -} - -func newEventDbServerQuerySample(cfg EventConfig) eventDbServerQuerySample { - e := eventDbServerQuerySample{config: cfg} - if cfg.Enabled { - e.data = plog.NewLogRecordSlice() - } - return e -} - type eventDbServerTopQuery struct { data plog.LogRecordSlice // data buffer for generated log records. config EventConfig // event config provided by user. @@ -139,7 +79,6 @@ type LogsBuilder struct { buildInfo component.BuildInfo // contains version information. resourceAttributeIncludeFilter map[string]filter.Filter resourceAttributeExcludeFilter map[string]filter.Filter - eventDbServerQuerySample eventDbServerQuerySample eventDbServerTopQuery eventDbServerTopQuery } @@ -154,7 +93,6 @@ func NewLogsBuilder(lbc LogsBuilderConfig, settings receiver.Settings) *LogsBuil logsBuffer: plog.NewLogs(), logRecordsBuffer: plog.NewLogRecordSlice(), buildInfo: settings.BuildInfo, - eventDbServerQuerySample: newEventDbServerQuerySample(lbc.Events.DbServerQuerySample), eventDbServerTopQuery: newEventDbServerTopQuery(lbc.Events.DbServerTopQuery), resourceAttributeIncludeFilter: make(map[string]filter.Filter), resourceAttributeExcludeFilter: make(map[string]filter.Filter), @@ -214,7 +152,6 @@ func (lb *LogsBuilder) EmitForResource(options ...ResourceLogsOption) { ils := rl.ScopeLogs().AppendEmpty() ils.Scope().SetName(ScopeName) ils.Scope().SetVersion(lb.buildInfo.Version) - lb.eventDbServerQuerySample.emit(ils.LogRecords()) lb.eventDbServerTopQuery.emit(ils.LogRecords()) for _, op := range options { @@ -252,11 +189,6 @@ func (lb *LogsBuilder) Emit(options ...ResourceLogsOption) plog.Logs { return logs } -// RecordDbServerQuerySampleEvent adds a log record of db.server.query_sample event. -func (lb *LogsBuilder) RecordDbServerQuerySampleEvent(ctx context.Context, timestamp pcommon.Timestamp, dbQueryTextAttributeValue string, dbSystemNameAttributeValue string, userNameAttributeValue string, dbNamespaceAttributeValue string, clientAddressAttributeValue string, clientPortAttributeValue int64, networkPeerAddressAttributeValue string, networkPeerPortAttributeValue int64, oracledbPlanHashValueAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbSidAttributeValue string, oracledbSerialAttributeValue string, oracledbProcessAttributeValue string, oracledbSchemanameAttributeValue string, oracledbProgramAttributeValue string, oracledbModuleAttributeValue string, oracledbStatusAttributeValue string, oracledbStateAttributeValue string, oracledbWaitClassAttributeValue string, oracledbEventAttributeValue string, oracledbObjectNameAttributeValue string, oracledbObjectTypeAttributeValue string, oracledbOsuserAttributeValue string, oracledbDurationSecAttributeValue float64) { - lb.eventDbServerQuerySample.recordEvent(ctx, timestamp, dbQueryTextAttributeValue, dbSystemNameAttributeValue, userNameAttributeValue, dbNamespaceAttributeValue, clientAddressAttributeValue, clientPortAttributeValue, networkPeerAddressAttributeValue, networkPeerPortAttributeValue, oracledbPlanHashValueAttributeValue, oracledbSQLIDAttributeValue, oracledbChildNumberAttributeValue, oracledbSidAttributeValue, oracledbSerialAttributeValue, oracledbProcessAttributeValue, oracledbSchemanameAttributeValue, oracledbProgramAttributeValue, oracledbModuleAttributeValue, oracledbStatusAttributeValue, oracledbStateAttributeValue, oracledbWaitClassAttributeValue, oracledbEventAttributeValue, oracledbObjectNameAttributeValue, oracledbObjectTypeAttributeValue, oracledbOsuserAttributeValue, oracledbDurationSecAttributeValue) -} - // RecordDbServerTopQueryEvent adds a log record of db.server.top_query event. func (lb *LogsBuilder) RecordDbServerTopQueryEvent(ctx context.Context, timestamp pcommon.Timestamp, dbSystemNameAttributeValue string, dbServerNameAttributeValue string, dbQueryTextAttributeValue string, oracledbQueryPlanAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbApplicationWaitTimeAttributeValue float64, oracledbBufferGetsAttributeValue int64, oracledbClusterWaitTimeAttributeValue float64, oracledbConcurrencyWaitTimeAttributeValue float64, oracledbCPUTimeAttributeValue float64, oracledbDirectReadsAttributeValue int64, oracledbDirectWritesAttributeValue int64, oracledbDiskReadsAttributeValue int64, oracledbElapsedTimeAttributeValue float64, oracledbExecutionsAttributeValue int64, oracledbPhysicalReadBytesAttributeValue int64, oracledbPhysicalReadRequestsAttributeValue int64, oracledbPhysicalWriteBytesAttributeValue int64, oracledbPhysicalWriteRequestsAttributeValue int64, oracledbRowsProcessedAttributeValue int64, oracledbUserIoWaitTimeAttributeValue float64) { lb.eventDbServerTopQuery.recordEvent(ctx, timestamp, dbSystemNameAttributeValue, dbServerNameAttributeValue, dbQueryTextAttributeValue, oracledbQueryPlanAttributeValue, oracledbSQLIDAttributeValue, oracledbChildNumberAttributeValue, oracledbApplicationWaitTimeAttributeValue, oracledbBufferGetsAttributeValue, oracledbClusterWaitTimeAttributeValue, oracledbConcurrencyWaitTimeAttributeValue, oracledbCPUTimeAttributeValue, oracledbDirectReadsAttributeValue, oracledbDirectWritesAttributeValue, oracledbDiskReadsAttributeValue, oracledbElapsedTimeAttributeValue, oracledbExecutionsAttributeValue, oracledbPhysicalReadBytesAttributeValue, oracledbPhysicalReadRequestsAttributeValue, oracledbPhysicalWriteBytesAttributeValue, oracledbPhysicalWriteRequestsAttributeValue, oracledbRowsProcessedAttributeValue, oracledbUserIoWaitTimeAttributeValue) diff --git a/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go b/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go index a22897eed35a6..c4962a4c4d33f 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go @@ -129,9 +129,6 @@ func TestLogsBuilder(t *testing.T) { defaultEventsCount := 0 allEventsCount := 0 - allEventsCount++ - lb.RecordDbServerQuerySampleEvent(ctx, timestamp, "db.query.text-val", "db.system.name-val", "user.name-val", "db.namespace-val", "client.address-val", 11, "network.peer.address-val", 17, "oracledb.plan_hash_value-val", "oracledb.sql_id-val", "oracledb.child_number-val", "oracledb.sid-val", "oracledb.serial-val", "oracledb.process-val", "oracledb.schemaname-val", "oracledb.program-val", "oracledb.module-val", "oracledb.status-val", "oracledb.state-val", "oracledb.wait_class-val", "oracledb.event-val", "oracledb.object_name-val", "oracledb.object_type-val", "oracledb.osuser-val", 21.100000) - allEventsCount++ lb.RecordDbServerTopQueryEvent(ctx, timestamp, "db.system.name-val", "db.server.name-val", "db.query.text-val", "oracledb.query_plan-val", "oracledb.sql_id-val", "oracledb.child_number-val", 30.100000, 20, 26.100000, 30.100000, 17.100000, 21, 22, 19, 21.100000, 19, 28, 31, 29, 32, 23, 26.100000) @@ -160,88 +157,6 @@ func TestLogsBuilder(t *testing.T) { validatedEvents := make(map[string]bool) for i := 0; i < lrs.Len(); i++ { switch lrs.At(i).EventName() { - case "db.server.query_sample": - assert.False(t, validatedEvents["db.server.query_sample"], "Found a duplicate in the events slice: db.server.query_sample") - validatedEvents["db.server.query_sample"] = true - lr := lrs.At(i) - assert.Equal(t, timestamp, lr.Timestamp()) - assert.Equal(t, pcommon.TraceID(traceID), lr.TraceID()) - assert.Equal(t, pcommon.SpanID(spanID), lr.SpanID()) - attrVal, ok := lr.Attributes().Get("db.query.text") - assert.True(t, ok) - assert.Equal(t, "db.query.text-val", attrVal.Str()) - 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("user.name") - assert.True(t, ok) - assert.Equal(t, "user.name-val", attrVal.Str()) - attrVal, ok = lr.Attributes().Get("db.namespace") - assert.True(t, ok) - assert.Equal(t, "db.namespace-val", attrVal.Str()) - attrVal, ok = lr.Attributes().Get("client.address") - assert.True(t, ok) - assert.Equal(t, "client.address-val", attrVal.Str()) - attrVal, ok = lr.Attributes().Get("client.port") - assert.True(t, ok) - assert.EqualValues(t, 11, attrVal.Int()) - attrVal, ok = lr.Attributes().Get("network.peer.address") - assert.True(t, ok) - assert.Equal(t, "network.peer.address-val", attrVal.Str()) - attrVal, ok = lr.Attributes().Get("network.peer.port") - assert.True(t, ok) - assert.EqualValues(t, 17, attrVal.Int()) - attrVal, ok = lr.Attributes().Get("oracledb.plan_hash_value") - assert.True(t, ok) - assert.Equal(t, "oracledb.plan_hash_value-val", attrVal.Str()) - attrVal, ok = lr.Attributes().Get("oracledb.sql_id") - assert.True(t, ok) - assert.Equal(t, "oracledb.sql_id-val", attrVal.Str()) - attrVal, ok = lr.Attributes().Get("oracledb.child_number") - assert.True(t, ok) - assert.Equal(t, "oracledb.child_number-val", attrVal.Str()) - attrVal, ok = lr.Attributes().Get("oracledb.sid") - assert.True(t, ok) - assert.Equal(t, "oracledb.sid-val", attrVal.Str()) - attrVal, ok = lr.Attributes().Get("oracledb.serial") - assert.True(t, ok) - assert.Equal(t, "oracledb.serial-val", attrVal.Str()) - attrVal, ok = lr.Attributes().Get("oracledb.process") - assert.True(t, ok) - assert.Equal(t, "oracledb.process-val", attrVal.Str()) - attrVal, ok = lr.Attributes().Get("oracledb.schemaname") - assert.True(t, ok) - assert.Equal(t, "oracledb.schemaname-val", attrVal.Str()) - attrVal, ok = lr.Attributes().Get("oracledb.program") - assert.True(t, ok) - assert.Equal(t, "oracledb.program-val", attrVal.Str()) - attrVal, ok = lr.Attributes().Get("oracledb.module") - assert.True(t, ok) - assert.Equal(t, "oracledb.module-val", attrVal.Str()) - attrVal, ok = lr.Attributes().Get("oracledb.status") - assert.True(t, ok) - assert.Equal(t, "oracledb.status-val", attrVal.Str()) - attrVal, ok = lr.Attributes().Get("oracledb.state") - assert.True(t, ok) - assert.Equal(t, "oracledb.state-val", attrVal.Str()) - attrVal, ok = lr.Attributes().Get("oracledb.wait_class") - assert.True(t, ok) - assert.Equal(t, "oracledb.wait_class-val", attrVal.Str()) - attrVal, ok = lr.Attributes().Get("oracledb.event") - assert.True(t, ok) - assert.Equal(t, "oracledb.event-val", attrVal.Str()) - attrVal, ok = lr.Attributes().Get("oracledb.object_name") - assert.True(t, ok) - assert.Equal(t, "oracledb.object_name-val", attrVal.Str()) - attrVal, ok = lr.Attributes().Get("oracledb.object_type") - assert.True(t, ok) - assert.Equal(t, "oracledb.object_type-val", attrVal.Str()) - attrVal, ok = lr.Attributes().Get("oracledb.osuser") - assert.True(t, ok) - assert.Equal(t, "oracledb.osuser-val", attrVal.Str()) - attrVal, ok = lr.Attributes().Get("oracledb.duration_sec") - assert.True(t, ok) - assert.Equal(t, 21.100000, attrVal.Double()) 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/oracledbreceiver/internal/metadata/testdata/config.yaml b/receiver/oracledbreceiver/internal/metadata/testdata/config.yaml index 13a19e6fe9d70..7c525e5c0968c 100644 --- a/receiver/oracledbreceiver/internal/metadata/testdata/config.yaml +++ b/receiver/oracledbreceiver/internal/metadata/testdata/config.yaml @@ -84,8 +84,6 @@ all_set: oracledb.user_rollbacks: enabled: true events: - db.server.query_sample: - enabled: true db.server.top_query: enabled: true resource_attributes: @@ -178,8 +176,6 @@ none_set: oracledb.user_rollbacks: enabled: false events: - db.server.query_sample: - enabled: false db.server.top_query: enabled: false resource_attributes: diff --git a/receiver/oracledbreceiver/metadata.yaml b/receiver/oracledbreceiver/metadata.yaml index 558b856a4229e..a791324d73bc2 100644 --- a/receiver/oracledbreceiver/metadata.yaml +++ b/receiver/oracledbreceiver/metadata.yaml @@ -97,74 +97,11 @@ attributes: db.system.name: description: The database management system (DBMS) product as identified by the client instrumentation. type: string - oracledb.plan_hash_value: - description: Binary hash value calculated on the query execution plan and used to identify similar query execution plans, reported in the HEX format. - type: string - client.address: - description: Hostname or address of the client. - type: string - client.port: - description: TCP port used by the client. - type: int - db.namespace: - description: The database name. - type: string - network.peer.address: - description: IP address of the peer client. - type: string - network.peer.port: - description: TCP port used by the peer client. - type: int - oracledb.sid: - description: ID of the Oracle Server session. - type: string - oracledb.serial: - description: Serial number associated with a session. - type: string - oracledb.process: - description: The operating system process ID (PID) associated with a session. - type: string - user.name: - description: Database user name under which a session is connected to - type: string - oracledb.schemaname: - description: Oracle schema under which SQL statements are being executed - type: string - oracledb.program: - description: Name of the client program or tool that initiated the Oracle database session. - type: string - oracledb.module: - description: Logical module name of the client application that initiated a query or session. - type: string - oracledb.status: - description: Execution state or result of a database query or session. - type: string - oracledb.state: - description: Current state of the query or the session executing it. - type: string - oracledb.wait_class: - description: The category of wait events a query or session is currently experiencing in Oracle Database. - type: string - oracledb.event: - description: The specific wait event that a query or session is currently experiencing. - type: string - oracledb.object_name: - description: Name of the database object that a query is accessing. - type: string - oracledb.object_type: - description: Type of the database object that a query is accessing. - type: string - oracledb.osuser: - description: Name of the operating system user that initiated or is running the Oracle database session. - type: string - oracledb.duration_sec: - description: Total time taken by a database query to execute. - type: double events: db.server.top_query: enabled: false - description: top query + description: Collection of event metrics for top N queries, filtered based on the highest CPU time consumed (oracledb.elapsed_time). attributes: - db.system.name - db.server.name @@ -188,35 +125,6 @@ events: - oracledb.physical_write_requests - oracledb.rows_processed - oracledb.user_io_wait_time - db.server.query_sample: - enabled: false - description: sample query - attributes: - - db.query.text - - db.system.name - - user.name - - db.namespace - - client.address - - client.port - - network.peer.address - - network.peer.port - - oracledb.plan_hash_value - - oracledb.sql_id - - oracledb.child_number - - oracledb.sid - - oracledb.serial - - oracledb.process - - oracledb.schemaname - - oracledb.program - - oracledb.module - - oracledb.status - - oracledb.state - - oracledb.wait_class - - oracledb.event - - oracledb.object_name - - oracledb.object_type - - oracledb.osuser - - oracledb.duration_sec metrics: oracledb.cpu_time: description: Cumulative CPU time, in seconds diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index 82e34ac91fd1d..76ec15777c0fc 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -7,7 +7,6 @@ import ( "context" "database/sql" _ "embed" - "encoding/hex" "encoding/json" "errors" "fmt" @@ -92,9 +91,6 @@ const ( ) var ( - - //go:embed templates/oracleQuerySampleSql.tmpl - samplesQuery string //go:embed templates/oracleQueryMetricsAndTextSql.tmpl oracleQueryMetricsSQL string //go:embed templates/oracleQueryPlanSql.tmpl @@ -128,7 +124,6 @@ type oracleScraper struct { logsBuilderConfig metadata.LogsBuilderConfig metricCache *lru.Cache[string, map[string]int64] topQueryCollectCfg TopQueryCollection - querySampleCfg QuerySample } func newScraper(metricsBuilder *metadata.MetricsBuilder, metricsBuilderConfig metadata.MetricsBuilderConfig, scrapeCfg scraperhelper.ControllerConfig, logger *zap.Logger, providerFunc dbProviderFunc, clientProviderFunc clientProviderFunc, instanceName string, hostName string) (scraper.Metrics, error) { @@ -147,7 +142,7 @@ func newScraper(metricsBuilder *metadata.MetricsBuilder, metricsBuilderConfig me func newLogsScraper(logsBuilder *metadata.LogsBuilder, logsBuilderConfig metadata.LogsBuilderConfig, scrapeCfg scraperhelper.ControllerConfig, logger *zap.Logger, providerFunc dbProviderFunc, clientProviderFunc clientProviderFunc, instanceName string, metricCache *lru.Cache[string, map[string]int64], - topQueryCollectCfg TopQueryCollection, querySampleCfg QuerySample, hostName string, + topQueryCollectCfg TopQueryCollection, hostName string, ) (scraper.Logs, error) { s := &oracleScraper{ lb: logsBuilder, @@ -159,7 +154,6 @@ func newLogsScraper(logsBuilder *metadata.LogsBuilder, logsBuilderConfig metadat instanceName: instanceName, metricCache: metricCache, topQueryCollectCfg: topQueryCollectCfg, - querySampleCfg: querySampleCfg, hostName: hostName, } return scraper.NewLogs(s.scrapeLogs, scraper.WithShutdown(s.shutdown), scraper.WithStart(s.start)) @@ -176,7 +170,6 @@ func (s *oracleScraper) start(context.Context, component.Host) error { s.sessionCountClient = s.clientProviderFunc(s.db, sessionCountSQL, s.logger) s.systemResourceLimitsClient = s.clientProviderFunc(s.db, systemResourceLimitsSQL, s.logger) s.tablespaceUsageClient = s.clientProviderFunc(s.db, tablespaceUsageSQL, s.logger) - s.samplesQueryClient = s.clientProviderFunc(s.db, samplesQuery, s.logger) return nil } @@ -513,7 +506,6 @@ type queryMetricCacheHit struct { } func (s *oracleScraper) scrapeLogs(ctx context.Context) (plog.Logs, error) { - logs := plog.NewLogs() var scrapeErrors []error if s.logsBuilderConfig.Events.DbServerTopQuery.Enabled { @@ -521,92 +513,11 @@ func (s *oracleScraper) scrapeLogs(ctx context.Context) (plog.Logs, error) { if topNCollectionErrors != nil { scrapeErrors = append(scrapeErrors, topNCollectionErrors) } else { - topNLogs.ResourceLogs().CopyTo(logs.ResourceLogs()) - } - } - - if s.logsBuilderConfig.Events.DbServerQuerySample.Enabled { - sampleLogs, samplesCollectionErrors := s.collectQuerySamples(ctx) - if samplesCollectionErrors != nil { - scrapeErrors = append(scrapeErrors, samplesCollectionErrors) - } else { - sampleLogs.ResourceLogs().MoveAndAppendTo(logs.ResourceLogs()) + return topNLogs, errors.Join(scrapeErrors...) } } - return logs, errors.Join(scrapeErrors...) -} - -func (s *oracleScraper) collectQuerySamples(ctx context.Context) (plog.Logs, error) { - const duration = "DURATION_SEC" - const event = "EVENT" - const hostName = "MACHINE" - const module = "MODULE" - const osUser = "OSUSER" - const objectName = "OBJECT_NAME" - const objectType = "OBJECT_TYPE" - const process = "PROCESS" - const program = "PROGRAM" - const planHashValue = "PLAN_HASH_VALUE" - const sqlID = "SQL_ID" - const schemaName = "SCHEMANAME" - const sqlChildNumber = "SQL_CHILD_NUMBER" - const sid = "SID" - const serialNumber = "SERIAL" - const status = "STATUS" - const state = "STATE" - const sqlText = "SQL_FULLTEXT" - const username = "USERNAME" - const waitclass = "WAIT_CLASS" - const port = "PORT" - const serviceName = "SERVICE_NAME" - - var scrapeErrors []error - - dbClients := s.samplesQueryClient - timestamp := pcommon.NewTimestampFromTime(time.Now()) - - rows, err := dbClients.metricRows(ctx, s.querySampleCfg.MaxRowsPerQuery) - if err != nil { - scrapeErrors = append(scrapeErrors, fmt.Errorf("error executing %s: %w", samplesQuery, err)) - } - - rb := s.lb.NewResourceBuilder() - rb.SetOracledbInstanceName(s.instanceName) - rb.SetHostName(s.hostName) - - for _, row := range rows { - if row[sqlText] == "" { - continue - } - - obfuscatedSQL, err := ObfuscateSQL(row[sqlText]) - if err != nil { - s.logger.Error(fmt.Sprintf("oracleScraper failed updating this log record: %s", err)) - continue - } - - queryPlanHashVal := hex.EncodeToString([]byte(row[planHashValue])) - - queryDuration, err := strconv.ParseFloat(row[duration], 64) - if err != nil { - scrapeErrors = append(scrapeErrors, fmt.Errorf("failed to parse int64 for Duration, value was %s: %w", row[duration], err)) - } - - clientPort, err := strconv.ParseInt(row[port], 10, 64) - if err != nil { - clientPort = 0 - } - - s.lb.RecordDbServerQuerySampleEvent(ctx, timestamp, obfuscatedSQL, dbSystemNameVal, row[username], row[serviceName], row[hostName], - clientPort, row[hostName], clientPort, queryPlanHashVal, row[sqlID], row[sqlChildNumber], row[sid], row[serialNumber], row[process], - row[schemaName], row[program], row[module], row[status], row[state], row[waitclass], row[event], row[objectName], row[objectType], - row[osUser], queryDuration) - } - - out := s.lb.Emit(metadata.WithLogsResource(rb.Emit())) - - return out, errors.Join(scrapeErrors...) + return plog.NewLogs(), errors.Join(scrapeErrors...) } func (s *oracleScraper) collectTopNMetricData(ctx context.Context) (plog.Logs, error) { diff --git a/receiver/oracledbreceiver/scraper_test.go b/receiver/oracledbreceiver/scraper_test.go index 65fc75b39e22a..ba2e826537de3 100644 --- a/receiver/oracledbreceiver/scraper_test.go +++ b/receiver/oracledbreceiver/scraper_test.go @@ -199,87 +199,6 @@ func TestScraper_Scrape(t *testing.T) { } } -var samplesQueryResponses = map[string][]metricRow{ - samplesQuery: {{ - "S.MACHINE": "TEST-MACHINE", "S.USERNAME": "ADMIN", "S.SCHEMANAME": "ADMIN", "S.SQL_ID": "48bc50b6fuz4y", - "S.SQL_CHILD_NUMBER": "0", "S.SID": "675", "S.SERIAL#": "51295", "SQL_FULLTEXT": "test_query", "S.OSUSER": "test-user", "S.PROCESS": "1115", - "S.PORT": "54440", "S.PROGRAM": "Oracle SQL Developer for VS Code", "S.MODULE": "Oracle SQL Developer for VS Code", "S.STATUS": "ACTIVE", "S.STATE": "WAITED KNOWN TIME", "Q.PLAN_HASH_VALUE": "4199919568", "DURATION_SEC": "1", - }}, - "invalidQuery": {{ - "S.MACHINE": "TEST-MACHINE", "S.USERNAME": "ADMIN", "S.SCHEMANAME": "ADMIN", "S.SQL_ID": "48bc50b6fuz4y", - "S.SQL_CHILD_NUMBER": "0", "S.SID": "675", "S.SERIAL#": "51295", "SQL_FULLTEXT": "test_query", "S.OSUSER": "test-user", "S.PROCESS": "1115", - "S.PORT": "54440", "S.PROGRAM": "Oracle SQL Developer for VS Code", "S.MODULE": "Oracle SQL Developer for VS Code", "S.STATUS": "ACTIVE", "S.STATE": "WAITED KNOWN TIME", "Q.PLAN_HASH_VALUE": "4199919568", "DURATION_SEC": "", - }}, -} - -func TestSamplesQuery(t *testing.T) { - tests := []struct { - name string - dbclientFn func(db *sql.DB, s string, logger *zap.Logger) dbClient - errWanted string - }{ - { - name: "valid", - dbclientFn: func(_ *sql.DB, s string, _ *zap.Logger) dbClient { - return &fakeDbClient{ - Responses: [][]metricRow{ - samplesQueryResponses[s], - }, - } - }, - }, - { - name: "bad samples data", - dbclientFn: func(_ *sql.DB, _ string, _ *zap.Logger) dbClient { - return &fakeDbClient{Responses: [][]metricRow{ - samplesQueryResponses["invalidQuery"], - }} - }, - errWanted: `failed to parse int64 for Duration, value was : strconv.ParseFloat: parsing "": invalid syntax`, - }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - logsCfg := metadata.DefaultLogsBuilderConfig() - logsCfg.ResourceAttributes.OracledbInstanceName.Enabled = true - logsCfg.ResourceAttributes.HostName.Enabled = true - logsCfg.Events.DbServerTopQuery.Enabled = false - logsCfg.Events.DbServerQuerySample.Enabled = true - scrpr := oracleScraper{ - logger: zap.NewNop(), - dbProviderFunc: func() (*sql.DB, error) { - return nil, nil - }, - clientProviderFunc: test.dbclientFn, - id: component.ID{}, - lb: metadata.NewLogsBuilder(logsCfg, receivertest.NewNopSettings(metadata.Type)), - logsBuilderConfig: metadata.DefaultLogsBuilderConfig(), - } - scrpr.logsBuilderConfig.Events.DbServerTopQuery.Enabled = false - scrpr.logsBuilderConfig.Events.DbServerQuerySample.Enabled = true - err := scrpr.start(context.Background(), componenttest.NewNopHost()) - defer func() { - assert.NoError(t, scrpr.shutdown(context.Background())) - }() - require.NoError(t, err) - logs, err := scrpr.scrapeLogs(context.Background()) - expectedSamplesFile := filepath.Join("testdata", "expectedSamplesFile.yaml") - - if test.errWanted != "" { - require.EqualError(t, err, test.errWanted) - } else { - // Uncomment line below to re-generate expected logs. - // golden.WriteLogs(t, expectedSamplesFile, logs) - require.NoError(t, err) - expectedLogs, _ := golden.ReadLogs(expectedSamplesFile) - errs := plogtest.CompareLogs(expectedLogs, logs, plogtest.IgnoreTimestamp()) - assert.Equal(t, "db.server.query_sample", logs.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).EventName()) - assert.NoError(t, errs) - } - }) - } -} - func TestScraper_ScrapeTopNLogs(t *testing.T) { var metricRowData []metricRow var logRowData []metricRow @@ -343,7 +262,6 @@ func TestScraper_ScrapeTopNLogs(t *testing.T) { logsCfg := metadata.DefaultLogsBuilderConfig() logsCfg.ResourceAttributes.HostName.Enabled = true logsCfg.Events.DbServerTopQuery.Enabled = true - logsCfg.Events.DbServerQuerySample.Enabled = false metricsCfg := metadata.DefaultMetricsBuilderConfig() lruCache, _ := lru.New[string, map[string]int64](500) lruCache.Add("fxk8aq3nds8aw:0", cacheValue) @@ -366,7 +284,6 @@ func TestScraper_ScrapeTopNLogs(t *testing.T) { } scrpr.logsBuilderConfig.Events.DbServerTopQuery.Enabled = true - scrpr.logsBuilderConfig.Events.DbServerQuerySample.Enabled = false err := scrpr.start(context.Background(), componenttest.NewNopHost()) defer func() { diff --git a/receiver/oracledbreceiver/templates/oracleQuerySampleSql.tmpl b/receiver/oracledbreceiver/templates/oracleQuerySampleSql.tmpl deleted file mode 100644 index e1047bea99e92..0000000000000 --- a/receiver/oracledbreceiver/templates/oracleQuerySampleSql.tmpl +++ /dev/null @@ -1,33 +0,0 @@ -/* otel-collector */ SELECT -S.MACHINE, -S.USERNAME, -S.SCHEMANAME, -S.SQL_ID, -S.SQL_CHILD_NUMBER, -S.SID, -S.SERIAL#, -Q.SQL_FULLTEXT, -S.OSUSER, -S.PROCESS, -S.PORT, -S.PROGRAM, -S.MODULE, -S.STATUS, -S.STATE, -S.PORT, -S.SERVICE_NAME, -Q.PLAN_HASH_VALUE, -NVL((SYSDATE - SQL_EXEC_START) * 86400,0) AS DURATION_SEC, -CASE WHEN S.TIME_REMAINING_MICRO IS NOT NULL - THEN S.WAIT_CLASS END AS WAIT_CLASS, -CASE WHEN S.TIME_REMAINING_MICRO IS NOT NULL - THEN S.EVENT END AS EVENT, -CASE WHEN S.PLSQL_ENTRY_OBJECT_ID IS NOT NULL - THEN CASE WHEN P.PROCEDURE_NAME IS NULL - THEN P.OWNER || '.' || P.OBJECT_NAME ELSE P.OWNER || '.' || P.OBJECT_NAME || '.' || P.PROCEDURE_NAME END - END AS OBJECT_NAME, P.OBJECT_TYPE -FROM V$SESSION S LEFT JOIN DBA_PROCEDURES P ON S.PLSQL_ENTRY_OBJECT_ID = P.OBJECT_ID - AND S.PLSQL_ENTRY_SUBPROGRAM_ID = P.SUBPROGRAM_ID - LEFT JOIN V$SQL Q ON S.SQL_ID = Q.SQL_ID - WHERE S.SQL_ID IS NOT NULL AND S.STATUS = 'ACTIVE' -FETCH FIRST :1 ROWS ONLY \ No newline at end of file diff --git a/receiver/oracledbreceiver/testdata/config.yaml b/receiver/oracledbreceiver/testdata/config.yaml index 9bd305ddbea2f..f46eb0eb020a4 100644 --- a/receiver/oracledbreceiver/testdata/config.yaml +++ b/receiver/oracledbreceiver/testdata/config.yaml @@ -10,15 +10,11 @@ oracledb: max_query_sample_count: 222 top_query_count: 200 query_cache_size: 1000 - query_sample_collection: - max_rows_per_query: 200 metrics: oracledb.exchange_deadlocks: enabled: false oracledb.tablespace_size.usage: enabled: false events: - db.server.query_sample: - enabled: true db.server.top_query: enabled: true \ No newline at end of file diff --git a/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml b/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml deleted file mode 100644 index a57d31d8afd23..0000000000000 --- a/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml +++ /dev/null @@ -1,95 +0,0 @@ -resourceLogs: - - resource: - attributes: - - key: oracledb.instance.name - value: - stringValue: "" - - key: host.name - value: - stringValue: "" - scopeLogs: - - logRecords: - - attributes: - - key: db.query.text - value: - stringValue: test_query - - key: db.system.name - value: - stringValue: oracle - - key: user.name - value: - stringValue: "" - - key: db.namespace - value: - stringValue: "" - - key: client.address - value: - stringValue: "" - - key: client.port - value: - intValue: "0" - - key: network.peer.address - value: - stringValue: "" - - key: network.peer.port - value: - intValue: "0" - - key: oracledb.plan_hash_value - value: - stringValue: "" - - key: oracledb.sql_id - value: - stringValue: "" - - key: oracledb.child_number - value: - stringValue: "" - - key: oracledb.sid - value: - stringValue: "" - - key: oracledb.serial - value: - stringValue: "" - - key: oracledb.process - value: - stringValue: "" - - key: oracledb.schemaname - value: - stringValue: "" - - key: oracledb.program - value: - stringValue: "" - - key: oracledb.module - value: - stringValue: "" - - key: oracledb.status - value: - stringValue: "" - - key: oracledb.state - value: - stringValue: "" - - key: oracledb.wait_class - value: - stringValue: "" - - key: oracledb.event - value: - stringValue: "" - - key: oracledb.object_name - value: - stringValue: "" - - key: oracledb.object_type - value: - stringValue: "" - - key: oracledb.osuser - value: - stringValue: "" - - key: oracledb.duration_sec - value: - doubleValue: 1 - body: {} - eventName: db.server.query_sample - spanId: "" - timeUnixNano: "1751324007889535000" - traceId: "" - scope: - name: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/oracledbreceiver - version: latest From dcf0adaa7b7279bef3eb0caac3d0673cd16d4ca2 Mon Sep 17 00:00:00 2001 From: Sreenath Date: Mon, 7 Jul 2025 12:43:28 +0100 Subject: [PATCH 10/51] Updating chloggen --- .../oracledbreceiver-top-n-queries-and-query-samples.yaml | 5 ++--- receiver/oracledbreceiver/go.sum | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.chloggen/oracledbreceiver-top-n-queries-and-query-samples.yaml b/.chloggen/oracledbreceiver-top-n-queries-and-query-samples.yaml index bd3a42f748496..f3b173fd87755 100644 --- a/.chloggen/oracledbreceiver-top-n-queries-and-query-samples.yaml +++ b/.chloggen/oracledbreceiver-top-n-queries-and-query-samples.yaml @@ -7,7 +7,7 @@ change_type: enhancement component: oracledbreceiver # A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). -note: Support query-level log collection, fetching top N query metrics and details of currently running queries (samples). +note: Support query-level log collection, fetching top N query metrics. # Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. issues: [37478] @@ -18,8 +18,7 @@ issues: [37478] subtext: | With the introduction of query level log collection, the oracledbreceiver can now send metrics for Top N queries, filtered based on the highest CPU time consumed. The number of queries can be configured. This helps the user to have - a better understanding of the database operations. In addition to this, query samples can be collected for the currently - executing queries. This enhancement enables users to proactively monitor and manage the database performance. + a better understanding of the database operations. # 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/oracledbreceiver/go.sum b/receiver/oracledbreceiver/go.sum index ae5ac57a85d3c..541b29a303c51 100644 --- a/receiver/oracledbreceiver/go.sum +++ b/receiver/oracledbreceiver/go.sum @@ -180,8 +180,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= -golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= From c3f9ff5a1e932b5e4c42f96995a049e7a5e702c7 Mon Sep 17 00:00:00 2001 From: Sreenath Date: Tue, 8 Jul 2025 15:31:29 +0100 Subject: [PATCH 11/51] Update description --- receiver/oracledbreceiver/documentation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/receiver/oracledbreceiver/documentation.md b/receiver/oracledbreceiver/documentation.md index 44ec1858f1149..0347229d31c94 100644 --- a/receiver/oracledbreceiver/documentation.md +++ b/receiver/oracledbreceiver/documentation.md @@ -391,7 +391,7 @@ events: ### db.server.top_query -top query +Collection of event metrics for top N queries, filtered based on the highest CPU time consumed (oracledb.elapsed_time). #### Attributes From 5fd856ae836cc2645d87bc9f8236f60c67bb27c8 Mon Sep 17 00:00:00 2001 From: Sreenath Date: Wed, 9 Jul 2025 12:24:35 +0100 Subject: [PATCH 12/51] Addressing review comments --- receiver/oracledbreceiver/obfuscate.go | 11 ++---- receiver/oracledbreceiver/obfuscate_test.go | 4 +-- receiver/oracledbreceiver/scraper.go | 38 ++++----------------- receiver/oracledbreceiver/scraper_test.go | 2 +- 4 files changed, 12 insertions(+), 43 deletions(-) diff --git a/receiver/oracledbreceiver/obfuscate.go b/receiver/oracledbreceiver/obfuscate.go index 460390fb05248..5918adbcdfdf3 100644 --- a/receiver/oracledbreceiver/obfuscate.go +++ b/receiver/oracledbreceiver/obfuscate.go @@ -29,12 +29,7 @@ func lazyInitObfuscator() *obfuscate.Obfuscator { return obfuscator } -// ObfuscateSQL obfuscates the provided SQL query, writing the error into errResult if the operation fails -func ObfuscateSQL(rawQuery string) (string, error) { - obfuscatedQuery, err := lazyInitObfuscator().ObfuscateSQLStringWithOptions(rawQuery, &obfuscate.SQLConfig{DBMS: "oracle"}) - if err != nil { - return "", err - } - - return obfuscatedQuery.Query, nil +// obfuscateSQL obfuscates the provided SQL query, writing the error into errResult if the operation fails +func obfuscateSQL(rawQuery string) (*obfuscate.ObfuscatedQuery, error) { + return lazyInitObfuscator().ObfuscateSQLStringWithOptions(rawQuery, &obfuscate.SQLConfig{DBMS: "oracle"}) } diff --git a/receiver/oracledbreceiver/obfuscate_test.go b/receiver/oracledbreceiver/obfuscate_test.go index 2a83ddbdbf971..009ba24dbfdf7 100644 --- a/receiver/oracledbreceiver/obfuscate_test.go +++ b/receiver/oracledbreceiver/obfuscate_test.go @@ -24,7 +24,7 @@ func TestObfuscateSQL(t *testing.T) { WHERE s.salary > 50000 AND d.department_name LIKE 'IT%' ORDER BY e.salary DESC;` - result, err := ObfuscateSQL(origin) + result, err := obfuscateSQL(origin) assert.NoError(t, err) - assert.Equal(t, expected, result) + assert.Equal(t, expected, result.Query) } diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index 76ec15777c0fc..85a674774376b 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -506,18 +506,10 @@ type queryMetricCacheHit struct { } func (s *oracleScraper) scrapeLogs(ctx context.Context) (plog.Logs, error) { - var scrapeErrors []error - if s.logsBuilderConfig.Events.DbServerTopQuery.Enabled { - topNLogs, topNCollectionErrors := s.collectTopNMetricData(ctx) - if topNCollectionErrors != nil { - scrapeErrors = append(scrapeErrors, topNCollectionErrors) - } else { - return topNLogs, errors.Join(scrapeErrors...) - } + return s.collectTopNMetricData(ctx) } - - return plog.NewLogs(), errors.Join(scrapeErrors...) + return plog.NewLogs(), nil } func (s *oracleScraper) collectTopNMetricData(ctx context.Context) (plog.Logs, error) { @@ -530,18 +522,13 @@ func (s *oracleScraper) collectTopNMetricData(ctx context.Context) (plog.Logs, e metricRows, metricError := s.oracleQueryMetricsClient.metricRows(ctx, now, intervalSeconds, s.topQueryCollectCfg.MaxQuerySampleCount) if metricError != nil { - errs = append(errs, fmt.Errorf("error executing %s: %w", oracleQueryMetricsSQL, metricError)) - return plog.NewLogs(), errors.Join(errs...) + return plog.NewLogs(), fmt.Errorf("error executing oracleQueryMetricsSQL: %w", metricError) } - if len(metricRows) == 0 { - errs = append(errs, errors.New("no data returned from oracleQueryMetricsClient")) - return plog.NewLogs(), errors.Join(errs...) + return plog.NewLogs(), errors.New("no data returned from oracleQueryMetricsClient") } metricNames := s.getTopNMetricNames() - s.logger.Debug("Metric columns", zap.Strings("names", metricNames)) - s.logger.Debug("Cache", zap.Int("size", s.metricCache.Len())) var hits []queryMetricCacheHit var cacheUpdates, discardedHits int for _, row := range metricRows { @@ -604,29 +591,16 @@ func (s *oracleScraper) collectTopNMetricData(ctx context.Context) (plog.Logs, e } s.logger.Debug("Cache hits", zap.Int("hit-count", len(hits)), zap.Int("discarded-hit-count", discardedHits)) - for _, hit := range hits { - s.logger.Debug(fmt.Sprintf("Cache hit, SQL_ID: %v, CHILD_NUMBER: %v", hit.sqlID, hit.childNumber), zap.Int64("elapsed-time", hit.metrics[elapsedTimeMetric])) - } // order by elapsed time delta, descending sort.Slice(hits, func(i, j int) bool { return hits[i].metrics[elapsedTimeMetric] > hits[j].metrics[elapsedTimeMetric] }) - for _, hit := range hits { - s.logger.Debug(fmt.Sprintf("Cache hit after sorting, SQL_ID: %v, CHILD_NUMBER: %v", hit.sqlID, hit.childNumber), zap.String("child-address", hit.childAddress), zap.Int64("elapsed-time", hit.metrics[elapsedTimeMetric])) - } - // keep at most maxHitSize - hitCountBefore := len(hits) maxHitsSize := min(len(hits), int(s.topQueryCollectCfg.TopQueryCount)) hits = hits[:maxHitsSize] - skippedCacheHits := hitCountBefore - len(hits) - s.logger.Debug("Skipped cache hits", zap.Int("count", skippedCacheHits)) - for _, hit := range hits { - s.logger.Debug(fmt.Sprintf("Final cache hit, SQL_ID: %v, CHILD_NUMBER: %v", hit.sqlID, hit.childNumber), zap.String("child-address", hit.childAddress), zap.Any("metrics", hit.metrics)) - } hits = s.obfuscateCacheHits(hits) childAddressToPlanMap := s.getChildAddressToPlanMap(ctx, hits) @@ -683,11 +657,11 @@ func (s *oracleScraper) obfuscateCacheHits(hits []queryMetricCacheHit) []queryMe var obfuscatedHits []queryMetricCacheHit for _, hit := range hits { // obfuscate and normalize the query text - obfuscatedSQL, err := ObfuscateSQL(hit.queryText) + obfuscatedSQL, err := obfuscateSQL(hit.queryText) if err != nil { s.logger.Error("oracleScraper failed getting metric rows", zap.Error(err)) } else { - obfuscatedSQLLowerCase := strings.ToLower(obfuscatedSQL) + obfuscatedSQLLowerCase := strings.ToLower(obfuscatedSQL.Query) hit.queryText = obfuscatedSQLLowerCase obfuscatedHits = append(obfuscatedHits, hit) } diff --git a/receiver/oracledbreceiver/scraper_test.go b/receiver/oracledbreceiver/scraper_test.go index ba2e826537de3..05ca5f36a0aad 100644 --- a/receiver/oracledbreceiver/scraper_test.go +++ b/receiver/oracledbreceiver/scraper_test.go @@ -253,7 +253,7 @@ func TestScraper_ScrapeTopNLogs(t *testing.T) { Err: errors.New("Mock error"), } }, - errWanted: fmt.Sprintf("error executing %s: %s", oracleQueryMetricsSQL, "Mock error"), + errWanted: fmt.Sprintf("error executing oracleQueryMetricsSQL: Mock error"), }, } From 0b610519d012c61f7c0195e31fdf29dc56aba6af Mon Sep 17 00:00:00 2001 From: Sreenath Date: Thu, 10 Jul 2025 14:51:55 +0100 Subject: [PATCH 13/51] Updating cacheSize to be alligned to MaxQuerySampleCount --- receiver/oracledbreceiver/config.go | 5 ----- receiver/oracledbreceiver/factory.go | 6 +++--- receiver/oracledbreceiver/testdata/config.yaml | 1 - 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/receiver/oracledbreceiver/config.go b/receiver/oracledbreceiver/config.go index ee6a957511e6e..abcb5b1e52ec0 100644 --- a/receiver/oracledbreceiver/config.go +++ b/receiver/oracledbreceiver/config.go @@ -26,13 +26,11 @@ var ( errEmptyUsername = errors.New("username must be set") errMaxQuerySampleCount = errors.New("`max_query_sample_count` must be between 1 and 10000") errTopQueryCount = errors.New("`top_query_count` must be between 1 and 200 and less than or equal to `max_query_sample_count`") - errQueryCacheSize = errors.New("`query_cache_size` must be strictly positive") ) type TopQueryCollection struct { MaxQuerySampleCount uint `mapstructure:"max_query_sample_count"` TopQueryCount uint `mapstructure:"top_query_count"` - QueryCacheSize int `mapstructure:"query_cache_size"` } type Config struct { @@ -98,8 +96,5 @@ func (c Config) Validate() error { if c.TopQueryCount < 1 || c.TopQueryCount > 200 || c.TopQueryCount > c.MaxQuerySampleCount { allErrs = multierr.Append(allErrs, errTopQueryCount) } - if c.QueryCacheSize <= 0 { - allErrs = multierr.Append(allErrs, errQueryCacheSize) - } return allErrs } diff --git a/receiver/oracledbreceiver/factory.go b/receiver/oracledbreceiver/factory.go index 16067222f18f9..cda697e3f3cdd 100644 --- a/receiver/oracledbreceiver/factory.go +++ b/receiver/oracledbreceiver/factory.go @@ -47,7 +47,6 @@ func createDefaultConfig() component.Config { TopQueryCollection: TopQueryCollection{ MaxQuerySampleCount: 1000, TopQueryCount: 200, - QueryCacheSize: 5000, }, } } @@ -111,8 +110,9 @@ func createLogsReceiverFunc(sqlOpenerFunc sqlOpenerFunc, clientProviderFunc clie return nil, hostNameErr } - cacheSize := sqlCfg.QueryCacheSize - metricCache, err := lru.New[string, map[string]int64](cacheSize) + // cacheSize is kept at 2 times MaxQuerySampleCount to keep queries of adjacent collections available for delta calculation. + cacheSize := sqlCfg.MaxQuerySampleCount * 2 + metricCache, err := lru.New[string, map[string]int64](int(cacheSize)) if err != nil { settings.Logger.Error("Failed to create LRU cache, skipping the current scraper", zap.Error(err)) return nil, err diff --git a/receiver/oracledbreceiver/testdata/config.yaml b/receiver/oracledbreceiver/testdata/config.yaml index f46eb0eb020a4..75fdd02ff25f6 100644 --- a/receiver/oracledbreceiver/testdata/config.yaml +++ b/receiver/oracledbreceiver/testdata/config.yaml @@ -9,7 +9,6 @@ oracledb: top_query_collection: max_query_sample_count: 222 top_query_count: 200 - query_cache_size: 1000 metrics: oracledb.exchange_deadlocks: enabled: false From a207210e5b75ec1e27e842555285743d73363603 Mon Sep 17 00:00:00 2001 From: Sreenath Date: Thu, 10 Jul 2025 15:01:11 +0100 Subject: [PATCH 14/51] fix lint --- receiver/oracledbreceiver/scraper.go | 1 - receiver/oracledbreceiver/scraper_test.go | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index 85a674774376b..69491069a8936 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -106,7 +106,6 @@ type oracleScraper struct { tablespaceUsageClient dbClient systemResourceLimitsClient dbClient sessionCountClient dbClient - samplesQueryClient dbClient oracleQueryMetricsClient dbClient oraclePlanDataClient dbClient db *sql.DB diff --git a/receiver/oracledbreceiver/scraper_test.go b/receiver/oracledbreceiver/scraper_test.go index 05ca5f36a0aad..8fb48ef3798d8 100644 --- a/receiver/oracledbreceiver/scraper_test.go +++ b/receiver/oracledbreceiver/scraper_test.go @@ -8,7 +8,6 @@ import ( "database/sql" "encoding/json" "errors" - "fmt" "log" "os" "path/filepath" @@ -253,7 +252,7 @@ func TestScraper_ScrapeTopNLogs(t *testing.T) { Err: errors.New("Mock error"), } }, - errWanted: fmt.Sprintf("error executing oracleQueryMetricsSQL: Mock error"), + errWanted: "error executing oracleQueryMetricsSQL: Mock error", }, } From eede7b68876d2bd9011342425d13667d9ac10be0 Mon Sep 17 00:00:00 2001 From: Sreenath Date: Fri, 11 Jul 2025 16:44:32 +0100 Subject: [PATCH 15/51] crosslink fix --- receiver/oracledbreceiver/go.mod | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/receiver/oracledbreceiver/go.mod b/receiver/oracledbreceiver/go.mod index 6b38c05327007..d07aad94ce249 100644 --- a/receiver/oracledbreceiver/go.mod +++ b/receiver/oracledbreceiver/go.mod @@ -84,3 +84,9 @@ retract ( v0.76.1 v0.65.0 ) + +replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden => ../../pkg/golden + +replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil => ../../pkg/pdatautil + +replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest => ../../pkg/pdatatest From b60a3e972d76305a1c4f84a278896ab3145ddb0d Mon Sep 17 00:00:00 2001 From: Sreenath Date: Mon, 14 Jul 2025 09:29:53 +0100 Subject: [PATCH 16/51] lint fixes --- receiver/oracledbreceiver/go.sum | 6 ------ 1 file changed, 6 deletions(-) diff --git a/receiver/oracledbreceiver/go.sum b/receiver/oracledbreceiver/go.sum index b641067dbaa4d..738e1187c0abe 100644 --- a/receiver/oracledbreceiver/go.sum +++ b/receiver/oracledbreceiver/go.sum @@ -66,12 +66,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden v0.129.0 h1:ib4F7Rsefrpcq3Uo72UUb58+PE8uZs5rBYs1cyHGSJs= -github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden v0.129.0/go.mod h1:U0i/4xJl9xpII4DnpHBWP3Kang7ZZuDTf7XDuBjYxKo= -github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.129.0 h1:ydkfqpZ5BWZfEJEs7OUhTHW59og5aZspbUYxoGcAEok= -github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.129.0/go.mod h1:oA+49dkzmhUx0YFC9JXGuPPSBL0TOTp6jkv7qSr2n0Q= -github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.129.0 h1:AOVxBvCZfTPj0GLGqBVHpAnlC9t9pl1JXUQXymHliiY= -github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.129.0/go.mod h1:0CAJ32V/bCUBhNTEvnN9wlOG5IsyZ+Bmhe9e3Eri7CU= github.com/outcaste-io/ristretto v0.2.3 h1:AK4zt/fJ76kjlYObOeNwh4T3asEuaCmp26pOvUOL9w0= github.com/outcaste-io/ristretto v0.2.3/go.mod h1:W8HywhmtlopSB1jeMg3JtdIhf+DYkLAr0VN/s4+MHac= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= From d9a9d6d70c73110d8eeff2393d9b3b32ede44c93 Mon Sep 17 00:00:00 2001 From: Sreenath Date: Mon, 14 Jul 2025 19:41:58 +0100 Subject: [PATCH 17/51] Fixing obfuscator --- receiver/oracledbreceiver/obfuscate.go | 33 +++++++-------------- receiver/oracledbreceiver/obfuscate_test.go | 5 ++-- receiver/oracledbreceiver/scraper.go | 6 ++-- receiver/oracledbreceiver/scraper_test.go | 1 + 4 files changed, 19 insertions(+), 26 deletions(-) diff --git a/receiver/oracledbreceiver/obfuscate.go b/receiver/oracledbreceiver/obfuscate.go index 5918adbcdfdf3..94b654ff3a611 100644 --- a/receiver/oracledbreceiver/obfuscate.go +++ b/receiver/oracledbreceiver/obfuscate.go @@ -1,35 +1,24 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -// Unless explicitly stated otherwise all files in this repository are licensed -// under the Apache License Version 2.0. -// This product includes software developed at Datadog (https://www.datadoghq.com/). -// Copyright 2016-present Datadog, Inc. - -// source: https://github.com/DataDog/datadog-agent/blob/main/pkg/collector/python/datadog_agent.go - package oracledbreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/oracledbreceiver" import ( - "sync" - "github.com/DataDog/datadog-agent/pkg/obfuscate" ) -var ( - obfuscator *obfuscate.Obfuscator - obfuscatorLoader sync.Once -) +var obfuscateSQLConfig = obfuscate.SQLConfig{DBMS: "oracle"} + +type obfuscator obfuscate.Obfuscator -// lazyInitObfuscator initializes the obfuscator the first time it is used. -func lazyInitObfuscator() *obfuscate.Obfuscator { - obfuscatorLoader.Do(func() { - obfuscator = obfuscate.NewObfuscator(obfuscate.Config{}) - }) - return obfuscator +func newObfuscator() *obfuscator { + return (*obfuscator)(obfuscate.NewObfuscator(obfuscate.Config{})) } -// obfuscateSQL obfuscates the provided SQL query, writing the error into errResult if the operation fails -func obfuscateSQL(rawQuery string) (*obfuscate.ObfuscatedQuery, error) { - return lazyInitObfuscator().ObfuscateSQLStringWithOptions(rawQuery, &obfuscate.SQLConfig{DBMS: "oracle"}) +func (o *obfuscator) obfuscateSQLString(sql string) (string, error) { + obfuscatedQuery, err := (*obfuscate.Obfuscator)(o).ObfuscateSQLStringWithOptions(sql, &obfuscateSQLConfig) + if err != nil { + return "", err + } + return obfuscatedQuery.Query, nil } diff --git a/receiver/oracledbreceiver/obfuscate_test.go b/receiver/oracledbreceiver/obfuscate_test.go index 009ba24dbfdf7..9c50d649118c0 100644 --- a/receiver/oracledbreceiver/obfuscate_test.go +++ b/receiver/oracledbreceiver/obfuscate_test.go @@ -24,7 +24,8 @@ func TestObfuscateSQL(t *testing.T) { WHERE s.salary > 50000 AND d.department_name LIKE 'IT%' ORDER BY e.salary DESC;` - result, err := obfuscateSQL(origin) + obf := newObfuscator() + result, err := obf.obfuscateSQLString(origin) assert.NoError(t, err) - assert.Equal(t, expected, result.Query) + assert.Equal(t, expected, result) } diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index 69491069a8936..0da7e7261736f 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -123,6 +123,7 @@ type oracleScraper struct { logsBuilderConfig metadata.LogsBuilderConfig metricCache *lru.Cache[string, map[string]int64] topQueryCollectCfg TopQueryCollection + obfuscator *obfuscator } func newScraper(metricsBuilder *metadata.MetricsBuilder, metricsBuilderConfig metadata.MetricsBuilderConfig, scrapeCfg scraperhelper.ControllerConfig, logger *zap.Logger, providerFunc dbProviderFunc, clientProviderFunc clientProviderFunc, instanceName string, hostName string) (scraper.Metrics, error) { @@ -154,6 +155,7 @@ func newLogsScraper(logsBuilder *metadata.LogsBuilder, logsBuilderConfig metadat metricCache: metricCache, topQueryCollectCfg: topQueryCollectCfg, hostName: hostName, + obfuscator: newObfuscator(), } return scraper.NewLogs(s.scrapeLogs, scraper.WithShutdown(s.shutdown), scraper.WithStart(s.start)) } @@ -656,11 +658,11 @@ func (s *oracleScraper) obfuscateCacheHits(hits []queryMetricCacheHit) []queryMe var obfuscatedHits []queryMetricCacheHit for _, hit := range hits { // obfuscate and normalize the query text - obfuscatedSQL, err := obfuscateSQL(hit.queryText) + obfuscatedSQL, err := s.obfuscator.obfuscateSQLString(hit.queryText) if err != nil { s.logger.Error("oracleScraper failed getting metric rows", zap.Error(err)) } else { - obfuscatedSQLLowerCase := strings.ToLower(obfuscatedSQL.Query) + obfuscatedSQLLowerCase := strings.ToLower(obfuscatedSQL) hit.queryText = obfuscatedSQLLowerCase obfuscatedHits = append(obfuscatedHits, hit) } diff --git a/receiver/oracledbreceiver/scraper_test.go b/receiver/oracledbreceiver/scraper_test.go index 8fb48ef3798d8..46043025aa194 100644 --- a/receiver/oracledbreceiver/scraper_test.go +++ b/receiver/oracledbreceiver/scraper_test.go @@ -280,6 +280,7 @@ func TestScraper_ScrapeTopNLogs(t *testing.T) { topQueryCollectCfg: TopQueryCollection{MaxQuerySampleCount: 5000, TopQueryCount: 200}, instanceName: "oracle-instance-sample-1", hostName: "oracle-host-sample-1", + obfuscator: newObfuscator(), } scrpr.logsBuilderConfig.Events.DbServerTopQuery.Enabled = true From b734b81ae32ca19a6a593b3dbcf13311044e4417 Mon Sep 17 00:00:00 2001 From: Sreenath Date: Tue, 15 Jul 2025 14:09:45 +0100 Subject: [PATCH 18/51] [receiver/oracledb] Support query-level log collection - Query samples implementation --- receiver/oracledbreceiver/config.go | 8 ++ receiver/oracledbreceiver/documentation.md | 34 ++++++ receiver/oracledbreceiver/factory.go | 5 +- .../internal/metadata/generated_config.go | 6 +- .../internal/metadata/generated_logs.go | 68 +++++++++++ .../internal/metadata/generated_logs_test.go | 85 ++++++++++++++ .../internal/metadata/testdata/config.yaml | 4 + receiver/oracledbreceiver/metadata.yaml | 92 +++++++++++++++ receiver/oracledbreceiver/scraper.go | 111 ++++++++++++++++-- receiver/oracledbreceiver/scraper_test.go | 82 +++++++++++++ .../templates/oracleQuerySampleSql.tmpl | 33 ++++++ .../oracledbreceiver/testdata/config.yaml | 2 + .../testdata/expectedSamplesFile.yaml | 95 +++++++++++++++ 13 files changed, 614 insertions(+), 11 deletions(-) create mode 100644 receiver/oracledbreceiver/templates/oracleQuerySampleSql.tmpl create mode 100644 receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml diff --git a/receiver/oracledbreceiver/config.go b/receiver/oracledbreceiver/config.go index abcb5b1e52ec0..cb59804bf5ec5 100644 --- a/receiver/oracledbreceiver/config.go +++ b/receiver/oracledbreceiver/config.go @@ -33,6 +33,13 @@ type TopQueryCollection struct { TopQueryCount uint `mapstructure:"top_query_count"` } +type QuerySample struct { + MaxRowsPerQuery uint64 `mapstructure:"max_rows_per_query"` + + // prevent unkeyed literal initialization + _ struct{} +} + type Config struct { DataSource string `mapstructure:"datasource"` Endpoint string `mapstructure:"endpoint"` @@ -44,6 +51,7 @@ type Config struct { metadata.LogsBuilderConfig `mapstructure:",squash"` TopQueryCollection `mapstructure:"top_query_collection"` + QuerySample `mapstructure:"query_sample_collection"` } func (c Config) Validate() error { diff --git a/receiver/oracledbreceiver/documentation.md b/receiver/oracledbreceiver/documentation.md index 0347229d31c94..525ded48d732d 100644 --- a/receiver/oracledbreceiver/documentation.md +++ b/receiver/oracledbreceiver/documentation.md @@ -389,6 +389,40 @@ events: enabled: true ``` +### db.server.query_sample + +sample query + +#### Attributes + +| Name | Description | Values | +| ---- | ----------- | ------ | +| db.query.text | The text of the database query being executed. | Any Str | +| db.system.name | The database management system (DBMS) product as identified by the client instrumentation. | Any Str | +| user.name | Database user name under which a session is connected to | Any Str | +| db.namespace | The database name. | Any Str | +| client.address | Hostname or address of the client. | Any Str | +| client.port | TCP port used by the client. | Any Int | +| network.peer.address | IP address of the peer client. | Any Str | +| network.peer.port | TCP port used by the peer client. | Any Int | +| oracledb.plan_hash_value | Binary hash value calculated on the query execution plan and used to identify similar query execution plans, reported in the HEX format. | Any Str | +| oracledb.sql_id | The SQL ID of the query. | Any Str | +| oracledb.child_number | The child number of the query. | Any Str | +| oracledb.sid | ID of the Oracle Server session. | Any Str | +| oracledb.serial | Serial number associated with a session. | Any Str | +| oracledb.process | The operating system process ID (PID) associated with a session. | Any Str | +| oracledb.schemaname | Oracle schema under which SQL statements are being executed | Any Str | +| oracledb.program | Name of the client program or tool that initiated the Oracle database session. | Any Str | +| oracledb.module | Logical module name of the client application that initiated a query or session. | Any Str | +| oracledb.status | Execution state or result of a database query or session. | Any Str | +| oracledb.state | Current state of the query or the session executing it. | Any Str | +| oracledb.wait_class | The category of wait events a query or session is currently experiencing in Oracle Database. | Any Str | +| oracledb.event | The specific wait event that a query or session is currently experiencing. | Any Str | +| oracledb.object_name | Name of the database object that a query is accessing. | Any Str | +| oracledb.object_type | Type of the database object that a query is accessing. | Any Str | +| oracledb.osuser | Name of the operating system user that initiated or is running the Oracle database session. | Any Str | +| oracledb.duration_sec | Total time taken by a database query to execute. | Any Double | + ### db.server.top_query Collection of event metrics for top N queries, filtered based on the highest CPU time consumed (oracledb.elapsed_time). diff --git a/receiver/oracledbreceiver/factory.go b/receiver/oracledbreceiver/factory.go index cda697e3f3cdd..6302b10345248 100644 --- a/receiver/oracledbreceiver/factory.go +++ b/receiver/oracledbreceiver/factory.go @@ -44,6 +44,9 @@ func createDefaultConfig() component.Config { ControllerConfig: cfg, MetricsBuilderConfig: metadata.DefaultMetricsBuilderConfig(), LogsBuilderConfig: metadata.DefaultLogsBuilderConfig(), + QuerySample: QuerySample{ + MaxRowsPerQuery: 100, + }, TopQueryCollection: TopQueryCollection{ MaxQuerySampleCount: 1000, TopQueryCount: 200, @@ -120,7 +123,7 @@ func createLogsReceiverFunc(sqlOpenerFunc sqlOpenerFunc, clientProviderFunc clie mp, err := newLogsScraper(logsBuilder, sqlCfg.LogsBuilderConfig, sqlCfg.ControllerConfig, settings.Logger, func() (*sql.DB, error) { return sqlOpenerFunc(getDataSource(*sqlCfg)) - }, clientProviderFunc, instanceName, metricCache, sqlCfg.TopQueryCollection, hostName) + }, clientProviderFunc, instanceName, metricCache, sqlCfg.TopQueryCollection, sqlCfg.QuerySample, hostName) if err != nil { return nil, err } diff --git a/receiver/oracledbreceiver/internal/metadata/generated_config.go b/receiver/oracledbreceiver/internal/metadata/generated_config.go index d1b9fae144832..8015aea85d87f 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_config.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_config.go @@ -220,11 +220,15 @@ func (ec *EventConfig) Unmarshal(parser *confmap.Conf) error { // EventsConfig provides config for oracledb events. type EventsConfig struct { - DbServerTopQuery EventConfig `mapstructure:"db.server.top_query"` + DbServerQuerySample EventConfig `mapstructure:"db.server.query_sample"` + DbServerTopQuery EventConfig `mapstructure:"db.server.top_query"` } func DefaultEventsConfig() EventsConfig { return EventsConfig{ + DbServerQuerySample: EventConfig{ + Enabled: false, + }, DbServerTopQuery: EventConfig{ Enabled: false, }, diff --git a/receiver/oracledbreceiver/internal/metadata/generated_logs.go b/receiver/oracledbreceiver/internal/metadata/generated_logs.go index 4ff64cec54bc7..722cfbedc4269 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_logs.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_logs.go @@ -13,6 +13,66 @@ import ( "go.opentelemetry.io/otel/trace" ) +type eventDbServerQuerySample struct { + data plog.LogRecordSlice // data buffer for generated log records. + config EventConfig // event config provided by user. +} + +func (e *eventDbServerQuerySample) recordEvent(ctx context.Context, timestamp pcommon.Timestamp, dbQueryTextAttributeValue string, dbSystemNameAttributeValue string, userNameAttributeValue string, dbNamespaceAttributeValue string, clientAddressAttributeValue string, clientPortAttributeValue int64, networkPeerAddressAttributeValue string, networkPeerPortAttributeValue int64, oracledbPlanHashValueAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbSidAttributeValue string, oracledbSerialAttributeValue string, oracledbProcessAttributeValue string, oracledbSchemanameAttributeValue string, oracledbProgramAttributeValue string, oracledbModuleAttributeValue string, oracledbStatusAttributeValue string, oracledbStateAttributeValue string, oracledbWaitClassAttributeValue string, oracledbEventAttributeValue string, oracledbObjectNameAttributeValue string, oracledbObjectTypeAttributeValue string, oracledbOsuserAttributeValue string, oracledbDurationSecAttributeValue float64) { + if !e.config.Enabled { + return + } + dp := e.data.AppendEmpty() + dp.SetEventName("db.server.query_sample") + dp.SetTimestamp(timestamp) + + if span := trace.SpanContextFromContext(ctx); span.IsValid() { + dp.SetTraceID(pcommon.TraceID(span.TraceID())) + dp.SetSpanID(pcommon.SpanID(span.SpanID())) + } + dp.Attributes().PutStr("db.query.text", dbQueryTextAttributeValue) + dp.Attributes().PutStr("db.system.name", dbSystemNameAttributeValue) + dp.Attributes().PutStr("user.name", userNameAttributeValue) + dp.Attributes().PutStr("db.namespace", dbNamespaceAttributeValue) + dp.Attributes().PutStr("client.address", clientAddressAttributeValue) + dp.Attributes().PutInt("client.port", clientPortAttributeValue) + dp.Attributes().PutStr("network.peer.address", networkPeerAddressAttributeValue) + dp.Attributes().PutInt("network.peer.port", networkPeerPortAttributeValue) + dp.Attributes().PutStr("oracledb.plan_hash_value", oracledbPlanHashValueAttributeValue) + dp.Attributes().PutStr("oracledb.sql_id", oracledbSQLIDAttributeValue) + dp.Attributes().PutStr("oracledb.child_number", oracledbChildNumberAttributeValue) + dp.Attributes().PutStr("oracledb.sid", oracledbSidAttributeValue) + dp.Attributes().PutStr("oracledb.serial", oracledbSerialAttributeValue) + dp.Attributes().PutStr("oracledb.process", oracledbProcessAttributeValue) + dp.Attributes().PutStr("oracledb.schemaname", oracledbSchemanameAttributeValue) + dp.Attributes().PutStr("oracledb.program", oracledbProgramAttributeValue) + dp.Attributes().PutStr("oracledb.module", oracledbModuleAttributeValue) + dp.Attributes().PutStr("oracledb.status", oracledbStatusAttributeValue) + dp.Attributes().PutStr("oracledb.state", oracledbStateAttributeValue) + dp.Attributes().PutStr("oracledb.wait_class", oracledbWaitClassAttributeValue) + dp.Attributes().PutStr("oracledb.event", oracledbEventAttributeValue) + dp.Attributes().PutStr("oracledb.object_name", oracledbObjectNameAttributeValue) + dp.Attributes().PutStr("oracledb.object_type", oracledbObjectTypeAttributeValue) + dp.Attributes().PutStr("oracledb.osuser", oracledbOsuserAttributeValue) + dp.Attributes().PutDouble("oracledb.duration_sec", oracledbDurationSecAttributeValue) + +} + +// emit appends recorded event data to a events slice and prepares it for recording another set of log records. +func (e *eventDbServerQuerySample) emit(lrs plog.LogRecordSlice) { + if e.config.Enabled && e.data.Len() > 0 { + e.data.MoveAndAppendTo(lrs) + } +} + +func newEventDbServerQuerySample(cfg EventConfig) eventDbServerQuerySample { + e := eventDbServerQuerySample{config: cfg} + if cfg.Enabled { + e.data = plog.NewLogRecordSlice() + } + return e +} + type eventDbServerTopQuery struct { data plog.LogRecordSlice // data buffer for generated log records. config EventConfig // event config provided by user. @@ -79,6 +139,7 @@ type LogsBuilder struct { buildInfo component.BuildInfo // contains version information. resourceAttributeIncludeFilter map[string]filter.Filter resourceAttributeExcludeFilter map[string]filter.Filter + eventDbServerQuerySample eventDbServerQuerySample eventDbServerTopQuery eventDbServerTopQuery } @@ -93,6 +154,7 @@ func NewLogsBuilder(lbc LogsBuilderConfig, settings receiver.Settings) *LogsBuil logsBuffer: plog.NewLogs(), logRecordsBuffer: plog.NewLogRecordSlice(), buildInfo: settings.BuildInfo, + eventDbServerQuerySample: newEventDbServerQuerySample(lbc.Events.DbServerQuerySample), eventDbServerTopQuery: newEventDbServerTopQuery(lbc.Events.DbServerTopQuery), resourceAttributeIncludeFilter: make(map[string]filter.Filter), resourceAttributeExcludeFilter: make(map[string]filter.Filter), @@ -152,6 +214,7 @@ func (lb *LogsBuilder) EmitForResource(options ...ResourceLogsOption) { ils := rl.ScopeLogs().AppendEmpty() ils.Scope().SetName(ScopeName) ils.Scope().SetVersion(lb.buildInfo.Version) + lb.eventDbServerQuerySample.emit(ils.LogRecords()) lb.eventDbServerTopQuery.emit(ils.LogRecords()) for _, op := range options { @@ -189,6 +252,11 @@ func (lb *LogsBuilder) Emit(options ...ResourceLogsOption) plog.Logs { return logs } +// RecordDbServerQuerySampleEvent adds a log record of db.server.query_sample event. +func (lb *LogsBuilder) RecordDbServerQuerySampleEvent(ctx context.Context, timestamp pcommon.Timestamp, dbQueryTextAttributeValue string, dbSystemNameAttributeValue string, userNameAttributeValue string, dbNamespaceAttributeValue string, clientAddressAttributeValue string, clientPortAttributeValue int64, networkPeerAddressAttributeValue string, networkPeerPortAttributeValue int64, oracledbPlanHashValueAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbSidAttributeValue string, oracledbSerialAttributeValue string, oracledbProcessAttributeValue string, oracledbSchemanameAttributeValue string, oracledbProgramAttributeValue string, oracledbModuleAttributeValue string, oracledbStatusAttributeValue string, oracledbStateAttributeValue string, oracledbWaitClassAttributeValue string, oracledbEventAttributeValue string, oracledbObjectNameAttributeValue string, oracledbObjectTypeAttributeValue string, oracledbOsuserAttributeValue string, oracledbDurationSecAttributeValue float64) { + lb.eventDbServerQuerySample.recordEvent(ctx, timestamp, dbQueryTextAttributeValue, dbSystemNameAttributeValue, userNameAttributeValue, dbNamespaceAttributeValue, clientAddressAttributeValue, clientPortAttributeValue, networkPeerAddressAttributeValue, networkPeerPortAttributeValue, oracledbPlanHashValueAttributeValue, oracledbSQLIDAttributeValue, oracledbChildNumberAttributeValue, oracledbSidAttributeValue, oracledbSerialAttributeValue, oracledbProcessAttributeValue, oracledbSchemanameAttributeValue, oracledbProgramAttributeValue, oracledbModuleAttributeValue, oracledbStatusAttributeValue, oracledbStateAttributeValue, oracledbWaitClassAttributeValue, oracledbEventAttributeValue, oracledbObjectNameAttributeValue, oracledbObjectTypeAttributeValue, oracledbOsuserAttributeValue, oracledbDurationSecAttributeValue) +} + // RecordDbServerTopQueryEvent adds a log record of db.server.top_query event. func (lb *LogsBuilder) RecordDbServerTopQueryEvent(ctx context.Context, timestamp pcommon.Timestamp, dbSystemNameAttributeValue string, dbServerNameAttributeValue string, dbQueryTextAttributeValue string, oracledbQueryPlanAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbApplicationWaitTimeAttributeValue float64, oracledbBufferGetsAttributeValue int64, oracledbClusterWaitTimeAttributeValue float64, oracledbConcurrencyWaitTimeAttributeValue float64, oracledbCPUTimeAttributeValue float64, oracledbDirectReadsAttributeValue int64, oracledbDirectWritesAttributeValue int64, oracledbDiskReadsAttributeValue int64, oracledbElapsedTimeAttributeValue float64, oracledbExecutionsAttributeValue int64, oracledbPhysicalReadBytesAttributeValue int64, oracledbPhysicalReadRequestsAttributeValue int64, oracledbPhysicalWriteBytesAttributeValue int64, oracledbPhysicalWriteRequestsAttributeValue int64, oracledbRowsProcessedAttributeValue int64, oracledbUserIoWaitTimeAttributeValue float64) { lb.eventDbServerTopQuery.recordEvent(ctx, timestamp, dbSystemNameAttributeValue, dbServerNameAttributeValue, dbQueryTextAttributeValue, oracledbQueryPlanAttributeValue, oracledbSQLIDAttributeValue, oracledbChildNumberAttributeValue, oracledbApplicationWaitTimeAttributeValue, oracledbBufferGetsAttributeValue, oracledbClusterWaitTimeAttributeValue, oracledbConcurrencyWaitTimeAttributeValue, oracledbCPUTimeAttributeValue, oracledbDirectReadsAttributeValue, oracledbDirectWritesAttributeValue, oracledbDiskReadsAttributeValue, oracledbElapsedTimeAttributeValue, oracledbExecutionsAttributeValue, oracledbPhysicalReadBytesAttributeValue, oracledbPhysicalReadRequestsAttributeValue, oracledbPhysicalWriteBytesAttributeValue, oracledbPhysicalWriteRequestsAttributeValue, oracledbRowsProcessedAttributeValue, oracledbUserIoWaitTimeAttributeValue) diff --git a/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go b/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go index c4962a4c4d33f..a22897eed35a6 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go @@ -129,6 +129,9 @@ func TestLogsBuilder(t *testing.T) { defaultEventsCount := 0 allEventsCount := 0 + allEventsCount++ + lb.RecordDbServerQuerySampleEvent(ctx, timestamp, "db.query.text-val", "db.system.name-val", "user.name-val", "db.namespace-val", "client.address-val", 11, "network.peer.address-val", 17, "oracledb.plan_hash_value-val", "oracledb.sql_id-val", "oracledb.child_number-val", "oracledb.sid-val", "oracledb.serial-val", "oracledb.process-val", "oracledb.schemaname-val", "oracledb.program-val", "oracledb.module-val", "oracledb.status-val", "oracledb.state-val", "oracledb.wait_class-val", "oracledb.event-val", "oracledb.object_name-val", "oracledb.object_type-val", "oracledb.osuser-val", 21.100000) + allEventsCount++ lb.RecordDbServerTopQueryEvent(ctx, timestamp, "db.system.name-val", "db.server.name-val", "db.query.text-val", "oracledb.query_plan-val", "oracledb.sql_id-val", "oracledb.child_number-val", 30.100000, 20, 26.100000, 30.100000, 17.100000, 21, 22, 19, 21.100000, 19, 28, 31, 29, 32, 23, 26.100000) @@ -157,6 +160,88 @@ func TestLogsBuilder(t *testing.T) { validatedEvents := make(map[string]bool) for i := 0; i < lrs.Len(); i++ { switch lrs.At(i).EventName() { + case "db.server.query_sample": + assert.False(t, validatedEvents["db.server.query_sample"], "Found a duplicate in the events slice: db.server.query_sample") + validatedEvents["db.server.query_sample"] = true + lr := lrs.At(i) + assert.Equal(t, timestamp, lr.Timestamp()) + assert.Equal(t, pcommon.TraceID(traceID), lr.TraceID()) + assert.Equal(t, pcommon.SpanID(spanID), lr.SpanID()) + attrVal, ok := lr.Attributes().Get("db.query.text") + assert.True(t, ok) + assert.Equal(t, "db.query.text-val", attrVal.Str()) + 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("user.name") + assert.True(t, ok) + assert.Equal(t, "user.name-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("db.namespace") + assert.True(t, ok) + assert.Equal(t, "db.namespace-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("client.address") + assert.True(t, ok) + assert.Equal(t, "client.address-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("client.port") + assert.True(t, ok) + assert.EqualValues(t, 11, attrVal.Int()) + attrVal, ok = lr.Attributes().Get("network.peer.address") + assert.True(t, ok) + assert.Equal(t, "network.peer.address-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("network.peer.port") + assert.True(t, ok) + assert.EqualValues(t, 17, attrVal.Int()) + attrVal, ok = lr.Attributes().Get("oracledb.plan_hash_value") + assert.True(t, ok) + assert.Equal(t, "oracledb.plan_hash_value-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.sql_id") + assert.True(t, ok) + assert.Equal(t, "oracledb.sql_id-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.child_number") + assert.True(t, ok) + assert.Equal(t, "oracledb.child_number-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.sid") + assert.True(t, ok) + assert.Equal(t, "oracledb.sid-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.serial") + assert.True(t, ok) + assert.Equal(t, "oracledb.serial-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.process") + assert.True(t, ok) + assert.Equal(t, "oracledb.process-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.schemaname") + assert.True(t, ok) + assert.Equal(t, "oracledb.schemaname-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.program") + assert.True(t, ok) + assert.Equal(t, "oracledb.program-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.module") + assert.True(t, ok) + assert.Equal(t, "oracledb.module-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.status") + assert.True(t, ok) + assert.Equal(t, "oracledb.status-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.state") + assert.True(t, ok) + assert.Equal(t, "oracledb.state-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.wait_class") + assert.True(t, ok) + assert.Equal(t, "oracledb.wait_class-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.event") + assert.True(t, ok) + assert.Equal(t, "oracledb.event-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.object_name") + assert.True(t, ok) + assert.Equal(t, "oracledb.object_name-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.object_type") + assert.True(t, ok) + assert.Equal(t, "oracledb.object_type-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.osuser") + assert.True(t, ok) + assert.Equal(t, "oracledb.osuser-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.duration_sec") + assert.True(t, ok) + assert.Equal(t, 21.100000, attrVal.Double()) 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/oracledbreceiver/internal/metadata/testdata/config.yaml b/receiver/oracledbreceiver/internal/metadata/testdata/config.yaml index 7c525e5c0968c..13a19e6fe9d70 100644 --- a/receiver/oracledbreceiver/internal/metadata/testdata/config.yaml +++ b/receiver/oracledbreceiver/internal/metadata/testdata/config.yaml @@ -84,6 +84,8 @@ all_set: oracledb.user_rollbacks: enabled: true events: + db.server.query_sample: + enabled: true db.server.top_query: enabled: true resource_attributes: @@ -176,6 +178,8 @@ none_set: oracledb.user_rollbacks: enabled: false events: + db.server.query_sample: + enabled: false db.server.top_query: enabled: false resource_attributes: diff --git a/receiver/oracledbreceiver/metadata.yaml b/receiver/oracledbreceiver/metadata.yaml index a791324d73bc2..ae60cd49b400b 100644 --- a/receiver/oracledbreceiver/metadata.yaml +++ b/receiver/oracledbreceiver/metadata.yaml @@ -97,6 +97,69 @@ attributes: db.system.name: description: The database management system (DBMS) product as identified by the client instrumentation. type: string + oracledb.plan_hash_value: + description: Binary hash value calculated on the query execution plan and used to identify similar query execution plans, reported in the HEX format. + type: string + client.address: + description: Hostname or address of the client. + type: string + client.port: + description: TCP port used by the client. + type: int + db.namespace: + description: The database name. + type: string + network.peer.address: + description: IP address of the peer client. + type: string + network.peer.port: + description: TCP port used by the peer client. + type: int + oracledb.sid: + description: ID of the Oracle Server session. + type: string + oracledb.serial: + description: Serial number associated with a session. + type: string + oracledb.process: + description: The operating system process ID (PID) associated with a session. + type: string + user.name: + description: Database user name under which a session is connected to + type: string + oracledb.schemaname: + description: Oracle schema under which SQL statements are being executed + type: string + oracledb.program: + description: Name of the client program or tool that initiated the Oracle database session. + type: string + oracledb.module: + description: Logical module name of the client application that initiated a query or session. + type: string + oracledb.status: + description: Execution state or result of a database query or session. + type: string + oracledb.state: + description: Current state of the query or the session executing it. + type: string + oracledb.wait_class: + description: The category of wait events a query or session is currently experiencing in Oracle Database. + type: string + oracledb.event: + description: The specific wait event that a query or session is currently experiencing. + type: string + oracledb.object_name: + description: Name of the database object that a query is accessing. + type: string + oracledb.object_type: + description: Type of the database object that a query is accessing. + type: string + oracledb.osuser: + description: Name of the operating system user that initiated or is running the Oracle database session. + type: string + oracledb.duration_sec: + description: Total time taken by a database query to execute. + type: double events: db.server.top_query: @@ -125,6 +188,35 @@ events: - oracledb.physical_write_requests - oracledb.rows_processed - oracledb.user_io_wait_time + db.server.query_sample: + enabled: false + description: sample query + attributes: + - db.query.text + - db.system.name + - user.name + - db.namespace + - client.address + - client.port + - network.peer.address + - network.peer.port + - oracledb.plan_hash_value + - oracledb.sql_id + - oracledb.child_number + - oracledb.sid + - oracledb.serial + - oracledb.process + - oracledb.schemaname + - oracledb.program + - oracledb.module + - oracledb.status + - oracledb.state + - oracledb.wait_class + - oracledb.event + - oracledb.object_name + - oracledb.object_type + - oracledb.osuser + - oracledb.duration_sec metrics: oracledb.cpu_time: description: Cumulative CPU time, in seconds diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index 0da7e7261736f..4428abfc22067 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -7,6 +7,7 @@ import ( "context" "database/sql" _ "embed" + "encoding/hex" "encoding/json" "errors" "fmt" @@ -91,6 +92,8 @@ const ( ) var ( + //go:embed templates/oracleQuerySampleSql.tmpl + samplesQuery string //go:embed templates/oracleQueryMetricsAndTextSql.tmpl oracleQueryMetricsSQL string //go:embed templates/oracleQueryPlanSql.tmpl @@ -108,6 +111,7 @@ type oracleScraper struct { sessionCountClient dbClient oracleQueryMetricsClient dbClient oraclePlanDataClient dbClient + samplesQueryClient dbClient db *sql.DB clientProviderFunc clientProviderFunc mb *metadata.MetricsBuilder @@ -124,6 +128,7 @@ type oracleScraper struct { metricCache *lru.Cache[string, map[string]int64] topQueryCollectCfg TopQueryCollection obfuscator *obfuscator + querySampleCfg QuerySample } func newScraper(metricsBuilder *metadata.MetricsBuilder, metricsBuilderConfig metadata.MetricsBuilderConfig, scrapeCfg scraperhelper.ControllerConfig, logger *zap.Logger, providerFunc dbProviderFunc, clientProviderFunc clientProviderFunc, instanceName string, hostName string) (scraper.Metrics, error) { @@ -142,7 +147,7 @@ func newScraper(metricsBuilder *metadata.MetricsBuilder, metricsBuilderConfig me func newLogsScraper(logsBuilder *metadata.LogsBuilder, logsBuilderConfig metadata.LogsBuilderConfig, scrapeCfg scraperhelper.ControllerConfig, logger *zap.Logger, providerFunc dbProviderFunc, clientProviderFunc clientProviderFunc, instanceName string, metricCache *lru.Cache[string, map[string]int64], - topQueryCollectCfg TopQueryCollection, hostName string, + topQueryCollectCfg TopQueryCollection, querySampleCfg QuerySample, hostName string, ) (scraper.Logs, error) { s := &oracleScraper{ lb: logsBuilder, @@ -154,6 +159,7 @@ func newLogsScraper(logsBuilder *metadata.LogsBuilder, logsBuilderConfig metadat instanceName: instanceName, metricCache: metricCache, topQueryCollectCfg: topQueryCollectCfg, + querySampleCfg: querySampleCfg, hostName: hostName, obfuscator: newObfuscator(), } @@ -171,6 +177,7 @@ func (s *oracleScraper) start(context.Context, component.Host) error { s.sessionCountClient = s.clientProviderFunc(s.db, sessionCountSQL, s.logger) s.systemResourceLimitsClient = s.clientProviderFunc(s.db, systemResourceLimitsSQL, s.logger) s.tablespaceUsageClient = s.clientProviderFunc(s.db, tablespaceUsageSQL, s.logger) + s.samplesQueryClient = s.clientProviderFunc(s.db, samplesQuery, s.logger) return nil } @@ -507,13 +514,27 @@ type queryMetricCacheHit struct { } func (s *oracleScraper) scrapeLogs(ctx context.Context) (plog.Logs, error) { + logs := plog.NewLogs() + var scrapeErrors []error + if s.logsBuilderConfig.Events.DbServerTopQuery.Enabled { - return s.collectTopNMetricData(ctx) + topNCollectionErrors := s.collectTopNMetricData(ctx, logs) + if topNCollectionErrors != nil { + scrapeErrors = append(scrapeErrors, topNCollectionErrors) + } } - return plog.NewLogs(), nil + + if s.logsBuilderConfig.Events.DbServerQuerySample.Enabled { + samplesCollectionErrors := s.collectQuerySamples(ctx, logs) + if samplesCollectionErrors != nil { + scrapeErrors = append(scrapeErrors, samplesCollectionErrors) + } + } + + return logs, errors.Join(scrapeErrors...) } -func (s *oracleScraper) collectTopNMetricData(ctx context.Context) (plog.Logs, error) { +func (s *oracleScraper) collectTopNMetricData(ctx context.Context, logs plog.Logs) error { var errs []error // get metrics and query texts from DB timestamp := pcommon.NewTimestampFromTime(time.Now()) @@ -523,10 +544,10 @@ func (s *oracleScraper) collectTopNMetricData(ctx context.Context) (plog.Logs, e metricRows, metricError := s.oracleQueryMetricsClient.metricRows(ctx, now, intervalSeconds, s.topQueryCollectCfg.MaxQuerySampleCount) if metricError != nil { - return plog.NewLogs(), fmt.Errorf("error executing oracleQueryMetricsSQL: %w", metricError) + return fmt.Errorf("error executing oracleQueryMetricsSQL: %w", metricError) } if len(metricRows) == 0 { - return plog.NewLogs(), errors.New("no data returned from oracleQueryMetricsClient") + return errors.New("no data returned from oracleQueryMetricsClient") } metricNames := s.getTopNMetricNames() @@ -588,7 +609,7 @@ func (s *oracleScraper) collectTopNMetricData(ctx context.Context) (plog.Logs, e if len(hits) == 0 { s.logger.Info("No log records for this scrape") - return plog.NewLogs(), errors.Join(errs...) + return errors.Join(errs...) } s.logger.Debug("Cache hits", zap.Int("hit-count", len(hits)), zap.Int("discarded-hit-count", discardedHits)) @@ -645,9 +666,81 @@ func (s *oracleScraper) collectTopNMetricData(ctx context.Context) (plog.Logs, e s.logger.Debug("Log records for this scrape", zap.Int("count", hitCount)) } - out := s.lb.Emit(metadata.WithLogsResource(rb.Emit())) + s.lb.Emit(metadata.WithLogsResource(rb.Emit())).ResourceLogs().MoveAndAppendTo(logs.ResourceLogs()) + + return errors.Join(errs...) +} + +func (s *oracleScraper) collectQuerySamples(ctx context.Context, logs plog.Logs) error { + const duration = "DURATION_SEC" + const event = "EVENT" + const hostName = "MACHINE" + const module = "MODULE" + const osUser = "OSUSER" + const objectName = "OBJECT_NAME" + const objectType = "OBJECT_TYPE" + const process = "PROCESS" + const program = "PROGRAM" + const planHashValue = "PLAN_HASH_VALUE" + const sqlID = "SQL_ID" + const schemaName = "SCHEMANAME" + const sqlChildNumber = "SQL_CHILD_NUMBER" + const sid = "SID" + const serialNumber = "SERIAL#" + const status = "STATUS" + const state = "STATE" + const sqlText = "SQL_FULLTEXT" + const username = "USERNAME" + const waitclass = "WAIT_CLASS" + const port = "PORT" + const serviceName = "SERVICE_NAME" + + var scrapeErrors []error + + dbClients := s.samplesQueryClient + timestamp := pcommon.NewTimestampFromTime(time.Now()) + + rows, err := dbClients.metricRows(ctx, s.querySampleCfg.MaxRowsPerQuery) + if err != nil { + scrapeErrors = append(scrapeErrors, fmt.Errorf("error executing %s: %w", samplesQuery, err)) + } + + rb := s.lb.NewResourceBuilder() + rb.SetOracledbInstanceName(s.instanceName) + rb.SetHostName(s.hostName) + + for _, row := range rows { + if row[sqlText] == "" { + continue + } + + obfuscatedSQL, err := s.obfuscator.obfuscateSQLString(row[sqlText]) + if err != nil { + s.logger.Error(fmt.Sprintf("oracleScraper failed updating this log record: %s", err)) + continue + } + + queryPlanHashVal := hex.EncodeToString([]byte(row[planHashValue])) + + queryDuration, err := strconv.ParseFloat(row[duration], 64) + if err != nil { + scrapeErrors = append(scrapeErrors, fmt.Errorf("failed to parse int64 for Duration, value was %s: %w", row[duration], err)) + } + + clientPort, err := strconv.ParseInt(row[port], 10, 64) + if err != nil { + clientPort = 0 + } + + s.lb.RecordDbServerQuerySampleEvent(ctx, timestamp, obfuscatedSQL, dbSystemNameVal, row[username], row[serviceName], row[hostName], + clientPort, row[hostName], clientPort, queryPlanHashVal, row[sqlID], row[sqlChildNumber], row[sid], row[serialNumber], row[process], + row[schemaName], row[program], row[module], row[status], row[state], row[waitclass], row[event], row[objectName], row[objectType], + row[osUser], queryDuration) + } + + s.lb.Emit(metadata.WithLogsResource(rb.Emit())).ResourceLogs().MoveAndAppendTo(logs.ResourceLogs()) - return out, errors.Join(errs...) + return errors.Join(scrapeErrors...) } func asFloatInSeconds(value int64) float64 { diff --git a/receiver/oracledbreceiver/scraper_test.go b/receiver/oracledbreceiver/scraper_test.go index 46043025aa194..bb4af428db4bd 100644 --- a/receiver/oracledbreceiver/scraper_test.go +++ b/receiver/oracledbreceiver/scraper_test.go @@ -309,6 +309,88 @@ func TestScraper_ScrapeTopNLogs(t *testing.T) { } } +var samplesQueryResponses = map[string][]metricRow{ + samplesQuery: {{ + "MACHINE": "TEST-MACHINE", "USERNAME": "ADMIN", "SCHEMANAME": "ADMIN", "SQL_ID": "48bc50b6fuz4y", "WAIT_CLASS": "ONE", "OBJECT_NAME": "BLAH", + "SQL_CHILD_NUMBER": "0", "SID": "675", "SERIAL#": "51295", "SQL_FULLTEXT": "test_query", "OSUSER": "test-user", "PROCESS": "1115", "OBJECT_TYPE": "OBJECT_TYPE-A", + "PORT": "54440", "PROGRAM": "Oracle SQL Developer for VS Code", "MODULE": "Oracle SQL Developer for VS Code", "STATUS": "ACTIVE", "STATE": "WAITED KNOWN TIME", "PLAN_HASH_VALUE": "4199919568", "DURATION_SEC": "1", + }}, + "invalidQuery": {{ + "MACHINE": "TEST-MACHINE", "USERNAME": "ADMIN", "SCHEMANAME": "ADMIN", "SQL_ID": "48bc50b6fuz4y", + "SQL_CHILD_NUMBER": "0", "S.SID": "675", "SERIAL#": "51295", "SQL_FULLTEXT": "test_query", "OSUSER": "test-user", "PROCESS": "1115", + "PORT": "54440", "PROGRAM": "Oracle SQL Developer for VS Code", "MODULE": "Oracle SQL Developer for VS Code", "STATUS": "ACTIVE", "STATE": "WAITED KNOWN TIME", "PLAN_HASH_VALUE": "4199919568", "DURATION_SEC": "", + }}, +} + +func TestSamplesQuery(t *testing.T) { + tests := []struct { + name string + dbclientFn func(db *sql.DB, s string, logger *zap.Logger) dbClient + errWanted string + }{ + { + name: "valid", + dbclientFn: func(_ *sql.DB, s string, _ *zap.Logger) dbClient { + return &fakeDbClient{ + Responses: [][]metricRow{ + samplesQueryResponses[s], + }, + } + }, + }, + { + name: "bad samples data", + dbclientFn: func(_ *sql.DB, _ string, _ *zap.Logger) dbClient { + return &fakeDbClient{Responses: [][]metricRow{ + samplesQueryResponses["invalidQuery"], + }} + }, + errWanted: `failed to parse int64 for Duration, value was : strconv.ParseFloat: parsing "": invalid syntax`, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + logsCfg := metadata.DefaultLogsBuilderConfig() + logsCfg.ResourceAttributes.OracledbInstanceName.Enabled = true + logsCfg.ResourceAttributes.HostName.Enabled = true + logsCfg.Events.DbServerTopQuery.Enabled = false + logsCfg.Events.DbServerQuerySample.Enabled = true + scrpr := oracleScraper{ + logger: zap.NewNop(), + dbProviderFunc: func() (*sql.DB, error) { + return nil, nil + }, + clientProviderFunc: test.dbclientFn, + id: component.ID{}, + lb: metadata.NewLogsBuilder(logsCfg, receivertest.NewNopSettings(metadata.Type)), + logsBuilderConfig: metadata.DefaultLogsBuilderConfig(), + obfuscator: newObfuscator(), + } + scrpr.logsBuilderConfig.Events.DbServerTopQuery.Enabled = false + scrpr.logsBuilderConfig.Events.DbServerQuerySample.Enabled = true + err := scrpr.start(context.Background(), componenttest.NewNopHost()) + defer func() { + assert.NoError(t, scrpr.shutdown(context.Background())) + }() + require.NoError(t, err) + logs, err := scrpr.scrapeLogs(context.Background()) + expectedSamplesFile := filepath.Join("testdata", "expectedSamplesFile.yaml") + + if test.errWanted != "" { + require.EqualError(t, err, test.errWanted) + } else { + // Uncomment line below to re-generate expected logs. + // golden.WriteLogs(t, expectedSamplesFile, logs) + require.NoError(t, err) + expectedLogs, _ := golden.ReadLogs(expectedSamplesFile) + errs := plogtest.CompareLogs(expectedLogs, logs, plogtest.IgnoreTimestamp()) + assert.Equal(t, "db.server.query_sample", logs.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).EventName()) + assert.NoError(t, errs) + } + }) + } +} + func readFile(fname string) []byte { file, err := os.ReadFile(filepath.Join("testdata", fname)) if err != nil { diff --git a/receiver/oracledbreceiver/templates/oracleQuerySampleSql.tmpl b/receiver/oracledbreceiver/templates/oracleQuerySampleSql.tmpl new file mode 100644 index 0000000000000..e1047bea99e92 --- /dev/null +++ b/receiver/oracledbreceiver/templates/oracleQuerySampleSql.tmpl @@ -0,0 +1,33 @@ +/* otel-collector */ SELECT +S.MACHINE, +S.USERNAME, +S.SCHEMANAME, +S.SQL_ID, +S.SQL_CHILD_NUMBER, +S.SID, +S.SERIAL#, +Q.SQL_FULLTEXT, +S.OSUSER, +S.PROCESS, +S.PORT, +S.PROGRAM, +S.MODULE, +S.STATUS, +S.STATE, +S.PORT, +S.SERVICE_NAME, +Q.PLAN_HASH_VALUE, +NVL((SYSDATE - SQL_EXEC_START) * 86400,0) AS DURATION_SEC, +CASE WHEN S.TIME_REMAINING_MICRO IS NOT NULL + THEN S.WAIT_CLASS END AS WAIT_CLASS, +CASE WHEN S.TIME_REMAINING_MICRO IS NOT NULL + THEN S.EVENT END AS EVENT, +CASE WHEN S.PLSQL_ENTRY_OBJECT_ID IS NOT NULL + THEN CASE WHEN P.PROCEDURE_NAME IS NULL + THEN P.OWNER || '.' || P.OBJECT_NAME ELSE P.OWNER || '.' || P.OBJECT_NAME || '.' || P.PROCEDURE_NAME END + END AS OBJECT_NAME, P.OBJECT_TYPE +FROM V$SESSION S LEFT JOIN DBA_PROCEDURES P ON S.PLSQL_ENTRY_OBJECT_ID = P.OBJECT_ID + AND S.PLSQL_ENTRY_SUBPROGRAM_ID = P.SUBPROGRAM_ID + LEFT JOIN V$SQL Q ON S.SQL_ID = Q.SQL_ID + WHERE S.SQL_ID IS NOT NULL AND S.STATUS = 'ACTIVE' +FETCH FIRST :1 ROWS ONLY \ No newline at end of file diff --git a/receiver/oracledbreceiver/testdata/config.yaml b/receiver/oracledbreceiver/testdata/config.yaml index 75fdd02ff25f6..f4ec50cd5efba 100644 --- a/receiver/oracledbreceiver/testdata/config.yaml +++ b/receiver/oracledbreceiver/testdata/config.yaml @@ -16,4 +16,6 @@ oracledb: enabled: false events: db.server.top_query: + enabled: true + db.server.query_sample: enabled: true \ No newline at end of file diff --git a/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml b/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml new file mode 100644 index 0000000000000..05fb4ee8f7a3b --- /dev/null +++ b/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml @@ -0,0 +1,95 @@ +resourceLogs: + - resource: + attributes: + - key: oracledb.instance.name + value: + stringValue: "" + - key: host.name + value: + stringValue: "" + scopeLogs: + - logRecords: + - attributes: + - key: db.query.text + value: + stringValue: test_query + - key: db.system.name + value: + stringValue: oracle + - key: user.name + value: + stringValue: ADMIN + - key: db.namespace + value: + stringValue: "" + - key: client.address + value: + stringValue: TEST-MACHINE + - key: client.port + value: + intValue: "54440" + - key: network.peer.address + value: + stringValue: TEST-MACHINE + - key: network.peer.port + value: + intValue: "54440" + - key: oracledb.plan_hash_value + value: + stringValue: "34313939393139353638" + - key: oracledb.sql_id + value: + stringValue: 48bc50b6fuz4y + - key: oracledb.child_number + value: + stringValue: "0" + - key: oracledb.sid + value: + stringValue: "675" + - key: oracledb.serial + value: + stringValue: "51295" + - key: oracledb.process + value: + stringValue: "1115" + - key: oracledb.schemaname + value: + stringValue: ADMIN + - key: oracledb.program + value: + stringValue: Oracle SQL Developer for VS Code + - key: oracledb.module + value: + stringValue: Oracle SQL Developer for VS Code + - key: oracledb.status + value: + stringValue: ACTIVE + - key: oracledb.state + value: + stringValue: WAITED KNOWN TIME + - key: oracledb.wait_class + value: + stringValue: ONE + - key: oracledb.event + value: + stringValue: "" + - key: oracledb.object_name + value: + stringValue: BLAH + - key: oracledb.object_type + value: + stringValue: OBJECT_TYPE-A + - key: oracledb.osuser + value: + stringValue: test-user + - key: oracledb.duration_sec + value: + doubleValue: 1 + body: {} + eventName: db.server.query_sample + spanId: "" + timeUnixNano: "1752581882636677000" + traceId: "" + scope: + name: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/oracledbreceiver + version: latest From eefae2e8e9cf674db431b776eaec66785eecccdc Mon Sep 17 00:00:00 2001 From: Sreenath Date: Tue, 15 Jul 2025 15:36:04 +0100 Subject: [PATCH 19/51] Adding chloggen --- .chloggen/oracledbreceiver-query-samples.yaml | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .chloggen/oracledbreceiver-query-samples.yaml diff --git a/.chloggen/oracledbreceiver-query-samples.yaml b/.chloggen/oracledbreceiver-query-samples.yaml new file mode 100644 index 0000000000000..3edb75e14b686 --- /dev/null +++ b/.chloggen/oracledbreceiver-query-samples.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: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: oracledbreceiver + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Support query-level log collection, fetching query samples. + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [37478] + +# (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: | + With the introduction of query level log collection, details about currently running queries can be collected. + The maximum number of queries to be collected can be configured. This feature helps the user to have a better understanding of the database operations. + +# 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 78e445a38bd5933411a72fc6f22b37537b011326 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Wed, 30 Jul 2025 14:09:17 +0100 Subject: [PATCH 20/51] Updates to include CHILD_ADDRESS and OPTIONS in the Oracle query plan --- ...ons_and_childaddress_into_oracle_plan.yaml | 28 +++++++++++++++++++ receiver/oracledbreceiver/scraper.go | 2 -- .../templates/oracleQueryPlanSql.tmpl | 3 +- 3 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 .chloggen/add_options_and_childaddress_into_oracle_plan.yaml diff --git a/.chloggen/add_options_and_childaddress_into_oracle_plan.yaml b/.chloggen/add_options_and_childaddress_into_oracle_plan.yaml new file mode 100644 index 0000000000000..34d8866858768 --- /dev/null +++ b/.chloggen/add_options_and_childaddress_into_oracle_plan.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. filelogreceiver) +component: oracledbreceiver + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Add options and child_address into oracle plan + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [37478] + +# (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: | + Adding options and child_address into oracle plan to enhance the details + +# 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/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index 4e258821fc11f..19a1607e6f6e2 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -793,8 +793,6 @@ func (s *oracleScraper) getChildAddressToPlanMap(ctx context.Context, hits []que for _, row := range planData { currentChildAddress := row[childAddressAttr] jsonPlansSlice, ok := childAddressToPlanMap[currentChildAddress] - // child address was for internal use only, it's not going to be used beyond this point - delete(row, childAddressAttr) if ok { childAddressToPlanMap[currentChildAddress] = append(jsonPlansSlice, row) } else { diff --git a/receiver/oracledbreceiver/templates/oracleQueryPlanSql.tmpl b/receiver/oracledbreceiver/templates/oracleQueryPlanSql.tmpl index 6a29bbc27a4ee..cd24056a601d3 100644 --- a/receiver/oracledbreceiver/templates/oracleQueryPlanSql.tmpl +++ b/receiver/oracledbreceiver/templates/oracleQueryPlanSql.tmpl @@ -11,6 +11,7 @@ CPU_COST, ID, POSITION, PROJECTION, -OPERATION +OPERATION, +OPTIONS FROM V$SQL_PLAN WHERE CHILD_ADDRESS IN (%s) \ No newline at end of file From baa59cc4b0914f6dca747f841707e57e75b98142 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Wed, 30 Jul 2025 15:04:47 +0100 Subject: [PATCH 21/51] Fixing test data --- .../testdata/expectedQueryTextAndPlanQuery.yaml | 4 ++-- receiver/oracledbreceiver/testdata/oracleQueryPlanData.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml b/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml index 1f3ea343b0c18..41aa5dc449b41 100644 --- a/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml +++ b/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml @@ -21,7 +21,7 @@ resourceLogs: stringValue: select count ( * ) from admin. employee e join admin. person p on e. businessentityid = ? join admin. employeepayhistory eph on e. businessentityid = eph. businessentityid where eph. rate > ( select avg ( rate ) from admin. employeepayhistory ) - key: oracledb.query_plan value: - stringValue: '[{"ACCESS_PREDICATES":"","BYTES":"","CARDINALITY":"","COST":"1","CPU_COST":"","DEPTH":"0","ID":"0","IO_COST":"","OPERATION":"SELECT STATEMENT","PARENT_ID":"","POSITION":"1","PROJECTION":""}]' + stringValue: '[{"ACCESS_PREDICATES":"","BYTES":"","CARDINALITY":"","CHILD_ADDRESS":"0000000074C6E830","COST":"1","CPU_COST":"","DEPTH":"0","ID":"0","IO_COST":"","OPERATION":"SELECT STATEMENT","OPTIONS":"FULL","PARENT_ID":"","POSITION":"1","PROJECTION":""}]' - key: oracledb.sql_id value: stringValue: fxk8aq3nds8aw @@ -79,7 +79,7 @@ resourceLogs: body: {} eventName: db.server.top_query spanId: "" - timeUnixNano: "1750963641750185000" + timeUnixNano: "1752581882636677000" traceId: "" scope: name: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/oracledbreceiver diff --git a/receiver/oracledbreceiver/testdata/oracleQueryPlanData.txt b/receiver/oracledbreceiver/testdata/oracleQueryPlanData.txt index fd17e61ea94ba..8f986e70da254 100644 --- a/receiver/oracledbreceiver/testdata/oracleQueryPlanData.txt +++ b/receiver/oracledbreceiver/testdata/oracleQueryPlanData.txt @@ -1 +1 @@ -[{"ACCESS_PREDICATES": "", "BYTES": "", "CARDINALITY": "", "CHILD_ADDRESS": "0000000074C6E830", "COST": "1", "CPU_COST": "", "DEPTH": "0", "ID": "0", "IO_COST": "", "OPERATION": "SELECT STATEMENT", "PARENT_ID": "", "POSITION": "1", "PROJECTION": ""}] \ No newline at end of file +[{"ACCESS_PREDICATES": "", "BYTES": "", "CARDINALITY": "", "CHILD_ADDRESS": "0000000074C6E830", "COST": "1", "CPU_COST": "", "DEPTH": "0", "ID": "0", "IO_COST": "", "OPERATION": "SELECT STATEMENT", "OPTIONS": "FULL", "PARENT_ID": "", "POSITION": "1", "PROJECTION": ""}] \ No newline at end of file From 4f7d16cce055e904a8961b1c73df238e224dbb6e Mon Sep 17 00:00:00 2001 From: sreenathv Date: Thu, 31 Jul 2025 23:36:50 +0100 Subject: [PATCH 22/51] [receiver/oracledb] moving child_address from plan details to attributes --- ...child_address_from_plan_to_attributes.yaml | 27 +++++++++++++++++++ cmd/otelcontribcol/builder-config.yaml | 1 + receiver/oracledbreceiver/documentation.md | 1 + .../internal/metadata/generated_logs.go | 7 ++--- .../internal/metadata/generated_logs_test.go | 5 +++- receiver/oracledbreceiver/metadata.yaml | 4 +++ receiver/oracledbreceiver/scraper.go | 3 +++ .../expectedQueryTextAndPlanQuery.yaml | 5 +++- 8 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 .chloggen/moving_child_address_from_plan_to_attributes.yaml diff --git a/.chloggen/moving_child_address_from_plan_to_attributes.yaml b/.chloggen/moving_child_address_from_plan_to_attributes.yaml new file mode 100644 index 0000000000000..d450156a775fc --- /dev/null +++ b/.chloggen/moving_child_address_from_plan_to_attributes.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. filelogreceiver) +component: oracledbreceiver + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Moving child_address from plan details to attributes in top N query collection. + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [37478] + +# (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] diff --git a/cmd/otelcontribcol/builder-config.yaml b/cmd/otelcontribcol/builder-config.yaml index f50c00c7258a6..2b30d06b95433 100644 --- a/cmd/otelcontribcol/builder-config.yaml +++ b/cmd/otelcontribcol/builder-config.yaml @@ -279,3 +279,4 @@ providers: # file before passing it to OCB, to ensure that local versions are used for all # Contrib modules. replaces: + - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/oracledbreceiver => ../../receiver/oracledbreceiver diff --git a/receiver/oracledbreceiver/documentation.md b/receiver/oracledbreceiver/documentation.md index 2ab0b56bbd509..5697e29f81faa 100644 --- a/receiver/oracledbreceiver/documentation.md +++ b/receiver/oracledbreceiver/documentation.md @@ -445,6 +445,7 @@ Collection of event metrics for top N queries, filtered based on the highest CPU | oracledb.query_plan | The query execution plan used by the SQL Server. | Any Str | | oracledb.sql_id | The SQL ID of the query. | Any Str | | oracledb.child_number | The child number of the query. | Any Str | +| oracledb.child_address | Address of the child cursor. | Any Str | | oracledb.application_wait_time | The total time (in seconds) a query spent waiting on the application before it could proceed with execution (reporting delta). | Any Double | | oracledb.buffer_gets | Number of logical reads (i.e., buffer cache accesses) performed by a query (reporting delta). | Any Int | | oracledb.cluster_wait_time | Total time (in seconds) that a query waited due to Oracle Real Application Clusters (RAC) coordination (reporting delta). | Any Double | diff --git a/receiver/oracledbreceiver/internal/metadata/generated_logs.go b/receiver/oracledbreceiver/internal/metadata/generated_logs.go index 722cfbedc4269..5d92fbddba142 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_logs.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_logs.go @@ -78,7 +78,7 @@ type eventDbServerTopQuery struct { config EventConfig // event config provided by user. } -func (e *eventDbServerTopQuery) recordEvent(ctx context.Context, timestamp pcommon.Timestamp, dbSystemNameAttributeValue string, dbServerNameAttributeValue string, dbQueryTextAttributeValue string, oracledbQueryPlanAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbApplicationWaitTimeAttributeValue float64, oracledbBufferGetsAttributeValue int64, oracledbClusterWaitTimeAttributeValue float64, oracledbConcurrencyWaitTimeAttributeValue float64, oracledbCPUTimeAttributeValue float64, oracledbDirectReadsAttributeValue int64, oracledbDirectWritesAttributeValue int64, oracledbDiskReadsAttributeValue int64, oracledbElapsedTimeAttributeValue float64, oracledbExecutionsAttributeValue int64, oracledbPhysicalReadBytesAttributeValue int64, oracledbPhysicalReadRequestsAttributeValue int64, oracledbPhysicalWriteBytesAttributeValue int64, oracledbPhysicalWriteRequestsAttributeValue int64, oracledbRowsProcessedAttributeValue int64, oracledbUserIoWaitTimeAttributeValue float64) { +func (e *eventDbServerTopQuery) recordEvent(ctx context.Context, timestamp pcommon.Timestamp, dbSystemNameAttributeValue string, dbServerNameAttributeValue string, dbQueryTextAttributeValue string, oracledbQueryPlanAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbChildAddressAttributeValue string, oracledbApplicationWaitTimeAttributeValue float64, oracledbBufferGetsAttributeValue int64, oracledbClusterWaitTimeAttributeValue float64, oracledbConcurrencyWaitTimeAttributeValue float64, oracledbCPUTimeAttributeValue float64, oracledbDirectReadsAttributeValue int64, oracledbDirectWritesAttributeValue int64, oracledbDiskReadsAttributeValue int64, oracledbElapsedTimeAttributeValue float64, oracledbExecutionsAttributeValue int64, oracledbPhysicalReadBytesAttributeValue int64, oracledbPhysicalReadRequestsAttributeValue int64, oracledbPhysicalWriteBytesAttributeValue int64, oracledbPhysicalWriteRequestsAttributeValue int64, oracledbRowsProcessedAttributeValue int64, oracledbUserIoWaitTimeAttributeValue float64) { if !e.config.Enabled { return } @@ -96,6 +96,7 @@ func (e *eventDbServerTopQuery) recordEvent(ctx context.Context, timestamp pcomm dp.Attributes().PutStr("oracledb.query_plan", oracledbQueryPlanAttributeValue) dp.Attributes().PutStr("oracledb.sql_id", oracledbSQLIDAttributeValue) dp.Attributes().PutStr("oracledb.child_number", oracledbChildNumberAttributeValue) + dp.Attributes().PutStr("oracledb.child_address", oracledbChildAddressAttributeValue) dp.Attributes().PutDouble("oracledb.application_wait_time", oracledbApplicationWaitTimeAttributeValue) dp.Attributes().PutInt("oracledb.buffer_gets", oracledbBufferGetsAttributeValue) dp.Attributes().PutDouble("oracledb.cluster_wait_time", oracledbClusterWaitTimeAttributeValue) @@ -258,6 +259,6 @@ func (lb *LogsBuilder) RecordDbServerQuerySampleEvent(ctx context.Context, times } // RecordDbServerTopQueryEvent adds a log record of db.server.top_query event. -func (lb *LogsBuilder) RecordDbServerTopQueryEvent(ctx context.Context, timestamp pcommon.Timestamp, dbSystemNameAttributeValue string, dbServerNameAttributeValue string, dbQueryTextAttributeValue string, oracledbQueryPlanAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbApplicationWaitTimeAttributeValue float64, oracledbBufferGetsAttributeValue int64, oracledbClusterWaitTimeAttributeValue float64, oracledbConcurrencyWaitTimeAttributeValue float64, oracledbCPUTimeAttributeValue float64, oracledbDirectReadsAttributeValue int64, oracledbDirectWritesAttributeValue int64, oracledbDiskReadsAttributeValue int64, oracledbElapsedTimeAttributeValue float64, oracledbExecutionsAttributeValue int64, oracledbPhysicalReadBytesAttributeValue int64, oracledbPhysicalReadRequestsAttributeValue int64, oracledbPhysicalWriteBytesAttributeValue int64, oracledbPhysicalWriteRequestsAttributeValue int64, oracledbRowsProcessedAttributeValue int64, oracledbUserIoWaitTimeAttributeValue float64) { - lb.eventDbServerTopQuery.recordEvent(ctx, timestamp, dbSystemNameAttributeValue, dbServerNameAttributeValue, dbQueryTextAttributeValue, oracledbQueryPlanAttributeValue, oracledbSQLIDAttributeValue, oracledbChildNumberAttributeValue, oracledbApplicationWaitTimeAttributeValue, oracledbBufferGetsAttributeValue, oracledbClusterWaitTimeAttributeValue, oracledbConcurrencyWaitTimeAttributeValue, oracledbCPUTimeAttributeValue, oracledbDirectReadsAttributeValue, oracledbDirectWritesAttributeValue, oracledbDiskReadsAttributeValue, oracledbElapsedTimeAttributeValue, oracledbExecutionsAttributeValue, oracledbPhysicalReadBytesAttributeValue, oracledbPhysicalReadRequestsAttributeValue, oracledbPhysicalWriteBytesAttributeValue, oracledbPhysicalWriteRequestsAttributeValue, oracledbRowsProcessedAttributeValue, oracledbUserIoWaitTimeAttributeValue) +func (lb *LogsBuilder) RecordDbServerTopQueryEvent(ctx context.Context, timestamp pcommon.Timestamp, dbSystemNameAttributeValue string, dbServerNameAttributeValue string, dbQueryTextAttributeValue string, oracledbQueryPlanAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbChildAddressAttributeValue string, oracledbApplicationWaitTimeAttributeValue float64, oracledbBufferGetsAttributeValue int64, oracledbClusterWaitTimeAttributeValue float64, oracledbConcurrencyWaitTimeAttributeValue float64, oracledbCPUTimeAttributeValue float64, oracledbDirectReadsAttributeValue int64, oracledbDirectWritesAttributeValue int64, oracledbDiskReadsAttributeValue int64, oracledbElapsedTimeAttributeValue float64, oracledbExecutionsAttributeValue int64, oracledbPhysicalReadBytesAttributeValue int64, oracledbPhysicalReadRequestsAttributeValue int64, oracledbPhysicalWriteBytesAttributeValue int64, oracledbPhysicalWriteRequestsAttributeValue int64, oracledbRowsProcessedAttributeValue int64, oracledbUserIoWaitTimeAttributeValue float64) { + lb.eventDbServerTopQuery.recordEvent(ctx, timestamp, dbSystemNameAttributeValue, dbServerNameAttributeValue, dbQueryTextAttributeValue, oracledbQueryPlanAttributeValue, oracledbSQLIDAttributeValue, oracledbChildNumberAttributeValue, oracledbChildAddressAttributeValue, oracledbApplicationWaitTimeAttributeValue, oracledbBufferGetsAttributeValue, oracledbClusterWaitTimeAttributeValue, oracledbConcurrencyWaitTimeAttributeValue, oracledbCPUTimeAttributeValue, oracledbDirectReadsAttributeValue, oracledbDirectWritesAttributeValue, oracledbDiskReadsAttributeValue, oracledbElapsedTimeAttributeValue, oracledbExecutionsAttributeValue, oracledbPhysicalReadBytesAttributeValue, oracledbPhysicalReadRequestsAttributeValue, oracledbPhysicalWriteBytesAttributeValue, oracledbPhysicalWriteRequestsAttributeValue, oracledbRowsProcessedAttributeValue, oracledbUserIoWaitTimeAttributeValue) } diff --git a/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go b/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go index a22897eed35a6..2e0f3e86e1230 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go @@ -133,7 +133,7 @@ func TestLogsBuilder(t *testing.T) { lb.RecordDbServerQuerySampleEvent(ctx, timestamp, "db.query.text-val", "db.system.name-val", "user.name-val", "db.namespace-val", "client.address-val", 11, "network.peer.address-val", 17, "oracledb.plan_hash_value-val", "oracledb.sql_id-val", "oracledb.child_number-val", "oracledb.sid-val", "oracledb.serial-val", "oracledb.process-val", "oracledb.schemaname-val", "oracledb.program-val", "oracledb.module-val", "oracledb.status-val", "oracledb.state-val", "oracledb.wait_class-val", "oracledb.event-val", "oracledb.object_name-val", "oracledb.object_type-val", "oracledb.osuser-val", 21.100000) allEventsCount++ - lb.RecordDbServerTopQueryEvent(ctx, timestamp, "db.system.name-val", "db.server.name-val", "db.query.text-val", "oracledb.query_plan-val", "oracledb.sql_id-val", "oracledb.child_number-val", 30.100000, 20, 26.100000, 30.100000, 17.100000, 21, 22, 19, 21.100000, 19, 28, 31, 29, 32, 23, 26.100000) + lb.RecordDbServerTopQueryEvent(ctx, timestamp, "db.system.name-val", "db.server.name-val", "db.query.text-val", "oracledb.query_plan-val", "oracledb.sql_id-val", "oracledb.child_number-val", "oracledb.child_address-val", 30.100000, 20, 26.100000, 30.100000, 17.100000, 21, 22, 19, 21.100000, 19, 28, 31, 29, 32, 23, 26.100000) rb := lb.NewResourceBuilder() rb.SetHostName("host.name-val") @@ -267,6 +267,9 @@ func TestLogsBuilder(t *testing.T) { attrVal, ok = lr.Attributes().Get("oracledb.child_number") assert.True(t, ok) assert.Equal(t, "oracledb.child_number-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.child_address") + assert.True(t, ok) + assert.Equal(t, "oracledb.child_address-val", attrVal.Str()) attrVal, ok = lr.Attributes().Get("oracledb.application_wait_time") assert.True(t, ok) assert.Equal(t, 30.100000, attrVal.Double()) diff --git a/receiver/oracledbreceiver/metadata.yaml b/receiver/oracledbreceiver/metadata.yaml index eb39d41a8fa11..d23b279a8f245 100644 --- a/receiver/oracledbreceiver/metadata.yaml +++ b/receiver/oracledbreceiver/metadata.yaml @@ -43,6 +43,9 @@ attributes: oracledb.child_number: description: The child number of the query. type: string + oracledb.child_address: + description: Address of the child cursor. + type: string oracledb.application_wait_time: description: The total time (in seconds) a query spent waiting on the application before it could proceed with execution (reporting delta). type: double @@ -172,6 +175,7 @@ events: - oracledb.query_plan - oracledb.sql_id - oracledb.child_number + - oracledb.child_address - oracledb.application_wait_time - oracledb.buffer_gets - oracledb.cluster_wait_time diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index 19a1607e6f6e2..bcb2428174b93 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -650,6 +650,7 @@ func (s *oracleScraper) collectTopNMetricData(ctx context.Context, logs plog.Log s.hostName, hit.queryText, planString, hit.sqlID, hit.childNumber, + hit.childAddress, asFloatInSeconds(hit.metrics[applicationWaitTimeMetric]), hit.metrics[bufferGetsMetric], asFloatInSeconds(hit.metrics[clusterWaitTimeMetric]), @@ -793,6 +794,8 @@ func (s *oracleScraper) getChildAddressToPlanMap(ctx context.Context, hits []que for _, row := range planData { currentChildAddress := row[childAddressAttr] jsonPlansSlice, ok := childAddressToPlanMap[currentChildAddress] + // child address was for internal use only, it's not going to be used beyond this point + delete(row, childAddressAttr) if ok { childAddressToPlanMap[currentChildAddress] = append(jsonPlansSlice, row) } else { diff --git a/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml b/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml index 41aa5dc449b41..3909a3e3cd306 100644 --- a/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml +++ b/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml @@ -21,13 +21,16 @@ resourceLogs: stringValue: select count ( * ) from admin. employee e join admin. person p on e. businessentityid = ? join admin. employeepayhistory eph on e. businessentityid = eph. businessentityid where eph. rate > ( select avg ( rate ) from admin. employeepayhistory ) - key: oracledb.query_plan value: - stringValue: '[{"ACCESS_PREDICATES":"","BYTES":"","CARDINALITY":"","CHILD_ADDRESS":"0000000074C6E830","COST":"1","CPU_COST":"","DEPTH":"0","ID":"0","IO_COST":"","OPERATION":"SELECT STATEMENT","OPTIONS":"FULL","PARENT_ID":"","POSITION":"1","PROJECTION":""}]' + stringValue: '[{"ACCESS_PREDICATES":"","BYTES":"","CARDINALITY":"","COST":"1","CPU_COST":"","DEPTH":"0","ID":"0","IO_COST":"","OPERATION":"SELECT STATEMENT","OPTIONS":"FULL","PARENT_ID":"","POSITION":"1","PROJECTION":""}]' - key: oracledb.sql_id value: stringValue: fxk8aq3nds8aw - key: oracledb.child_number value: stringValue: "0" + - key: oracledb.child_address + value: + stringValue: 0000000074C6E830 - key: oracledb.application_wait_time value: doubleValue: 0 From cd5c712a5574e1224da45103af80b8b5f902ca5b Mon Sep 17 00:00:00 2001 From: sreenathv Date: Thu, 31 Jul 2025 23:47:15 +0100 Subject: [PATCH 23/51] revert builder-config --- cmd/otelcontribcol/builder-config.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/otelcontribcol/builder-config.yaml b/cmd/otelcontribcol/builder-config.yaml index 2b30d06b95433..f50c00c7258a6 100644 --- a/cmd/otelcontribcol/builder-config.yaml +++ b/cmd/otelcontribcol/builder-config.yaml @@ -279,4 +279,3 @@ providers: # file before passing it to OCB, to ensure that local versions are used for all # Contrib modules. replaces: - - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/oracledbreceiver => ../../receiver/oracledbreceiver From 6674daa26eba24b28d4f24eb83ce22f366cf15bf Mon Sep 17 00:00:00 2001 From: sreenathv Date: Tue, 19 Aug 2025 13:39:32 +0100 Subject: [PATCH 24/51] Adding child_address to samples payload --- receiver/oracledbreceiver/documentation.md | 1 + .../oracledbreceiver/internal/metadata/generated_logs.go | 7 ++++--- .../internal/metadata/generated_logs_test.go | 5 ++++- receiver/oracledbreceiver/metadata.yaml | 1 + receiver/oracledbreceiver/scraper.go | 3 ++- .../oracledbreceiver/templates/oracleQuerySampleSql.tmpl | 3 ++- .../oracledbreceiver/testdata/expectedSamplesFile.yaml | 7 ++++--- 7 files changed, 18 insertions(+), 9 deletions(-) diff --git a/receiver/oracledbreceiver/documentation.md b/receiver/oracledbreceiver/documentation.md index 5697e29f81faa..026c88fc56dbb 100644 --- a/receiver/oracledbreceiver/documentation.md +++ b/receiver/oracledbreceiver/documentation.md @@ -416,6 +416,7 @@ sample query | oracledb.plan_hash_value | Binary hash value calculated on the query execution plan and used to identify similar query execution plans, reported in the HEX format. | Any Str | | oracledb.sql_id | The SQL ID of the query. | Any Str | | oracledb.child_number | The child number of the query. | Any Str | +| oracledb.child_address | Address of the child cursor. | Any Str | | oracledb.sid | ID of the Oracle Server session. | Any Str | | oracledb.serial | Serial number associated with a session. | Any Str | | oracledb.process | The operating system process ID (PID) associated with a session. | Any Str | diff --git a/receiver/oracledbreceiver/internal/metadata/generated_logs.go b/receiver/oracledbreceiver/internal/metadata/generated_logs.go index 5d92fbddba142..0f6fc7e3d10d7 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_logs.go +++ b/receiver/oracledbreceiver/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, dbQueryTextAttributeValue string, dbSystemNameAttributeValue string, userNameAttributeValue string, dbNamespaceAttributeValue string, clientAddressAttributeValue string, clientPortAttributeValue int64, networkPeerAddressAttributeValue string, networkPeerPortAttributeValue int64, oracledbPlanHashValueAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbSidAttributeValue string, oracledbSerialAttributeValue string, oracledbProcessAttributeValue string, oracledbSchemanameAttributeValue string, oracledbProgramAttributeValue string, oracledbModuleAttributeValue string, oracledbStatusAttributeValue string, oracledbStateAttributeValue string, oracledbWaitClassAttributeValue string, oracledbEventAttributeValue string, oracledbObjectNameAttributeValue string, oracledbObjectTypeAttributeValue string, oracledbOsuserAttributeValue string, oracledbDurationSecAttributeValue float64) { +func (e *eventDbServerQuerySample) recordEvent(ctx context.Context, timestamp pcommon.Timestamp, dbQueryTextAttributeValue string, dbSystemNameAttributeValue string, userNameAttributeValue string, dbNamespaceAttributeValue string, clientAddressAttributeValue string, clientPortAttributeValue int64, networkPeerAddressAttributeValue string, networkPeerPortAttributeValue int64, oracledbPlanHashValueAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbChildAddressAttributeValue string, oracledbSidAttributeValue string, oracledbSerialAttributeValue string, oracledbProcessAttributeValue string, oracledbSchemanameAttributeValue string, oracledbProgramAttributeValue string, oracledbModuleAttributeValue string, oracledbStatusAttributeValue string, oracledbStateAttributeValue string, oracledbWaitClassAttributeValue string, oracledbEventAttributeValue string, oracledbObjectNameAttributeValue string, oracledbObjectTypeAttributeValue string, oracledbOsuserAttributeValue string, oracledbDurationSecAttributeValue float64) { if !e.config.Enabled { return } @@ -41,6 +41,7 @@ func (e *eventDbServerQuerySample) recordEvent(ctx context.Context, timestamp pc dp.Attributes().PutStr("oracledb.plan_hash_value", oracledbPlanHashValueAttributeValue) dp.Attributes().PutStr("oracledb.sql_id", oracledbSQLIDAttributeValue) dp.Attributes().PutStr("oracledb.child_number", oracledbChildNumberAttributeValue) + dp.Attributes().PutStr("oracledb.child_address", oracledbChildAddressAttributeValue) dp.Attributes().PutStr("oracledb.sid", oracledbSidAttributeValue) dp.Attributes().PutStr("oracledb.serial", oracledbSerialAttributeValue) dp.Attributes().PutStr("oracledb.process", oracledbProcessAttributeValue) @@ -254,8 +255,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, dbQueryTextAttributeValue string, dbSystemNameAttributeValue string, userNameAttributeValue string, dbNamespaceAttributeValue string, clientAddressAttributeValue string, clientPortAttributeValue int64, networkPeerAddressAttributeValue string, networkPeerPortAttributeValue int64, oracledbPlanHashValueAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbSidAttributeValue string, oracledbSerialAttributeValue string, oracledbProcessAttributeValue string, oracledbSchemanameAttributeValue string, oracledbProgramAttributeValue string, oracledbModuleAttributeValue string, oracledbStatusAttributeValue string, oracledbStateAttributeValue string, oracledbWaitClassAttributeValue string, oracledbEventAttributeValue string, oracledbObjectNameAttributeValue string, oracledbObjectTypeAttributeValue string, oracledbOsuserAttributeValue string, oracledbDurationSecAttributeValue float64) { - lb.eventDbServerQuerySample.recordEvent(ctx, timestamp, dbQueryTextAttributeValue, dbSystemNameAttributeValue, userNameAttributeValue, dbNamespaceAttributeValue, clientAddressAttributeValue, clientPortAttributeValue, networkPeerAddressAttributeValue, networkPeerPortAttributeValue, oracledbPlanHashValueAttributeValue, oracledbSQLIDAttributeValue, oracledbChildNumberAttributeValue, oracledbSidAttributeValue, oracledbSerialAttributeValue, oracledbProcessAttributeValue, oracledbSchemanameAttributeValue, oracledbProgramAttributeValue, oracledbModuleAttributeValue, oracledbStatusAttributeValue, oracledbStateAttributeValue, oracledbWaitClassAttributeValue, oracledbEventAttributeValue, oracledbObjectNameAttributeValue, oracledbObjectTypeAttributeValue, oracledbOsuserAttributeValue, oracledbDurationSecAttributeValue) +func (lb *LogsBuilder) RecordDbServerQuerySampleEvent(ctx context.Context, timestamp pcommon.Timestamp, dbQueryTextAttributeValue string, dbSystemNameAttributeValue string, userNameAttributeValue string, dbNamespaceAttributeValue string, clientAddressAttributeValue string, clientPortAttributeValue int64, networkPeerAddressAttributeValue string, networkPeerPortAttributeValue int64, oracledbPlanHashValueAttributeValue string, oracledbSQLIDAttributeValue string, oracledbChildNumberAttributeValue string, oracledbChildAddressAttributeValue string, oracledbSidAttributeValue string, oracledbSerialAttributeValue string, oracledbProcessAttributeValue string, oracledbSchemanameAttributeValue string, oracledbProgramAttributeValue string, oracledbModuleAttributeValue string, oracledbStatusAttributeValue string, oracledbStateAttributeValue string, oracledbWaitClassAttributeValue string, oracledbEventAttributeValue string, oracledbObjectNameAttributeValue string, oracledbObjectTypeAttributeValue string, oracledbOsuserAttributeValue string, oracledbDurationSecAttributeValue float64) { + lb.eventDbServerQuerySample.recordEvent(ctx, timestamp, dbQueryTextAttributeValue, dbSystemNameAttributeValue, userNameAttributeValue, dbNamespaceAttributeValue, clientAddressAttributeValue, clientPortAttributeValue, networkPeerAddressAttributeValue, networkPeerPortAttributeValue, oracledbPlanHashValueAttributeValue, oracledbSQLIDAttributeValue, oracledbChildNumberAttributeValue, oracledbChildAddressAttributeValue, oracledbSidAttributeValue, oracledbSerialAttributeValue, oracledbProcessAttributeValue, oracledbSchemanameAttributeValue, oracledbProgramAttributeValue, oracledbModuleAttributeValue, oracledbStatusAttributeValue, oracledbStateAttributeValue, oracledbWaitClassAttributeValue, oracledbEventAttributeValue, oracledbObjectNameAttributeValue, oracledbObjectTypeAttributeValue, oracledbOsuserAttributeValue, oracledbDurationSecAttributeValue) } // RecordDbServerTopQueryEvent adds a log record of db.server.top_query event. diff --git a/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go b/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go index 2e0f3e86e1230..50d8d146f74c1 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go @@ -130,7 +130,7 @@ func TestLogsBuilder(t *testing.T) { allEventsCount := 0 allEventsCount++ - lb.RecordDbServerQuerySampleEvent(ctx, timestamp, "db.query.text-val", "db.system.name-val", "user.name-val", "db.namespace-val", "client.address-val", 11, "network.peer.address-val", 17, "oracledb.plan_hash_value-val", "oracledb.sql_id-val", "oracledb.child_number-val", "oracledb.sid-val", "oracledb.serial-val", "oracledb.process-val", "oracledb.schemaname-val", "oracledb.program-val", "oracledb.module-val", "oracledb.status-val", "oracledb.state-val", "oracledb.wait_class-val", "oracledb.event-val", "oracledb.object_name-val", "oracledb.object_type-val", "oracledb.osuser-val", 21.100000) + lb.RecordDbServerQuerySampleEvent(ctx, timestamp, "db.query.text-val", "db.system.name-val", "user.name-val", "db.namespace-val", "client.address-val", 11, "network.peer.address-val", 17, "oracledb.plan_hash_value-val", "oracledb.sql_id-val", "oracledb.child_number-val", "oracledb.child_address-val", "oracledb.sid-val", "oracledb.serial-val", "oracledb.process-val", "oracledb.schemaname-val", "oracledb.program-val", "oracledb.module-val", "oracledb.status-val", "oracledb.state-val", "oracledb.wait_class-val", "oracledb.event-val", "oracledb.object_name-val", "oracledb.object_type-val", "oracledb.osuser-val", 21.100000) allEventsCount++ lb.RecordDbServerTopQueryEvent(ctx, timestamp, "db.system.name-val", "db.server.name-val", "db.query.text-val", "oracledb.query_plan-val", "oracledb.sql_id-val", "oracledb.child_number-val", "oracledb.child_address-val", 30.100000, 20, 26.100000, 30.100000, 17.100000, 21, 22, 19, 21.100000, 19, 28, 31, 29, 32, 23, 26.100000) @@ -200,6 +200,9 @@ func TestLogsBuilder(t *testing.T) { attrVal, ok = lr.Attributes().Get("oracledb.child_number") assert.True(t, ok) assert.Equal(t, "oracledb.child_number-val", attrVal.Str()) + attrVal, ok = lr.Attributes().Get("oracledb.child_address") + assert.True(t, ok) + assert.Equal(t, "oracledb.child_address-val", attrVal.Str()) attrVal, ok = lr.Attributes().Get("oracledb.sid") assert.True(t, ok) assert.Equal(t, "oracledb.sid-val", attrVal.Str()) diff --git a/receiver/oracledbreceiver/metadata.yaml b/receiver/oracledbreceiver/metadata.yaml index d23b279a8f245..ba4844aef6a13 100644 --- a/receiver/oracledbreceiver/metadata.yaml +++ b/receiver/oracledbreceiver/metadata.yaml @@ -207,6 +207,7 @@ events: - oracledb.plan_hash_value - oracledb.sql_id - oracledb.child_number + - oracledb.child_address - oracledb.sid - oracledb.serial - oracledb.process diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index bcb2428174b93..3730dbe0b05ef 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -693,6 +693,7 @@ func (s *oracleScraper) collectQuerySamples(ctx context.Context, logs plog.Logs) const sqlID = "SQL_ID" const schemaName = "SCHEMANAME" const sqlChildNumber = "SQL_CHILD_NUMBER" + const childAddress = "CHILD_ADDRESS" const sid = "SID" const serialNumber = "SERIAL#" const status = "STATUS" @@ -741,7 +742,7 @@ func (s *oracleScraper) collectQuerySamples(ctx context.Context, logs plog.Logs) } s.lb.RecordDbServerQuerySampleEvent(ctx, timestamp, obfuscatedSQL, dbSystemNameVal, row[username], row[serviceName], row[hostName], - clientPort, row[hostName], clientPort, queryPlanHashVal, row[sqlID], row[sqlChildNumber], row[sid], row[serialNumber], row[process], + clientPort, row[hostName], clientPort, queryPlanHashVal, row[sqlID], row[sqlChildNumber], row[childAddress], row[sid], row[serialNumber], row[process], row[schemaName], row[program], row[module], row[status], row[state], row[waitclass], row[event], row[objectName], row[objectType], row[osUser], queryDuration) } diff --git a/receiver/oracledbreceiver/templates/oracleQuerySampleSql.tmpl b/receiver/oracledbreceiver/templates/oracleQuerySampleSql.tmpl index e1047bea99e92..55297cf8d7135 100644 --- a/receiver/oracledbreceiver/templates/oracleQuerySampleSql.tmpl +++ b/receiver/oracledbreceiver/templates/oracleQuerySampleSql.tmpl @@ -4,6 +4,7 @@ S.USERNAME, S.SCHEMANAME, S.SQL_ID, S.SQL_CHILD_NUMBER, +RAWTOHEX(Q.CHILD_ADDRESS) AS CHILD_ADDRESS, S.SID, S.SERIAL#, Q.SQL_FULLTEXT, @@ -28,6 +29,6 @@ CASE WHEN S.PLSQL_ENTRY_OBJECT_ID IS NOT NULL END AS OBJECT_NAME, P.OBJECT_TYPE FROM V$SESSION S LEFT JOIN DBA_PROCEDURES P ON S.PLSQL_ENTRY_OBJECT_ID = P.OBJECT_ID AND S.PLSQL_ENTRY_SUBPROGRAM_ID = P.SUBPROGRAM_ID - LEFT JOIN V$SQL Q ON S.SQL_ID = Q.SQL_ID + LEFT JOIN V$SQL Q ON S.SQL_ID = Q.SQL_ID AND S.SQL_CHILD_NUMBER = Q.CHILD_NUMBER WHERE S.SQL_ID IS NOT NULL AND S.STATUS = 'ACTIVE' FETCH FIRST :1 ROWS ONLY \ No newline at end of file diff --git a/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml b/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml index 05fb4ee8f7a3b..7d3507d25d75d 100644 --- a/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml +++ b/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml @@ -43,6 +43,9 @@ resourceLogs: - key: oracledb.child_number value: stringValue: "0" + - key: oracledb.child_address + value: + stringValue: "" - key: oracledb.sid value: stringValue: "675" @@ -87,9 +90,7 @@ resourceLogs: doubleValue: 1 body: {} eventName: db.server.query_sample - spanId: "" - timeUnixNano: "1752581882636677000" - traceId: "" + timeUnixNano: "1755606249243744000" scope: name: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/oracledbreceiver version: latest From c0424c6949db48588ce52db2f48b1077babc5163 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Tue, 19 Aug 2025 13:48:08 +0100 Subject: [PATCH 25/51] Fix test --- receiver/oracledbreceiver/scraper_test.go | 2 +- receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/receiver/oracledbreceiver/scraper_test.go b/receiver/oracledbreceiver/scraper_test.go index 2559ff2b3d742..99e3118dc088a 100644 --- a/receiver/oracledbreceiver/scraper_test.go +++ b/receiver/oracledbreceiver/scraper_test.go @@ -310,7 +310,7 @@ func TestScraper_ScrapeTopNLogs(t *testing.T) { var samplesQueryResponses = map[string][]metricRow{ samplesQuery: {{ - "MACHINE": "TEST-MACHINE", "USERNAME": "ADMIN", "SCHEMANAME": "ADMIN", "SQL_ID": "48bc50b6fuz4y", "WAIT_CLASS": "ONE", "OBJECT_NAME": "BLAH", + "MACHINE": "TEST-MACHINE", "USERNAME": "ADMIN", "SCHEMANAME": "ADMIN", "SQL_ID": "48bc50b6fuz4y", "WAIT_CLASS": "ONE", "OBJECT_NAME": "BLAH", "CHILD_ADDRESS": "SDF3SDF1234D", "SQL_CHILD_NUMBER": "0", "SID": "675", "SERIAL#": "51295", "SQL_FULLTEXT": "test_query", "OSUSER": "test-user", "PROCESS": "1115", "OBJECT_TYPE": "OBJECT_TYPE-A", "PORT": "54440", "PROGRAM": "Oracle SQL Developer for VS Code", "MODULE": "Oracle SQL Developer for VS Code", "STATUS": "ACTIVE", "STATE": "WAITED KNOWN TIME", "PLAN_HASH_VALUE": "4199919568", "DURATION_SEC": "1", }}, diff --git a/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml b/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml index 7d3507d25d75d..e0f6c5371f8dd 100644 --- a/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml +++ b/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml @@ -45,7 +45,7 @@ resourceLogs: stringValue: "0" - key: oracledb.child_address value: - stringValue: "" + stringValue: "SDF3SDF1234D" - key: oracledb.sid value: stringValue: "675" @@ -90,7 +90,9 @@ resourceLogs: doubleValue: 1 body: {} eventName: db.server.query_sample - timeUnixNano: "1755606249243744000" + spanId: "" + timeUnixNano: "1752581882636677000" + traceId: "" scope: name: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/oracledbreceiver version: latest From a8370026ba4a42a3bbe8b4a34e1645ba92aa9dd0 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Tue, 19 Aug 2025 14:01:29 +0100 Subject: [PATCH 26/51] Adding chlog --- .chloggen/oracle_sql_case_fix.yaml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .chloggen/oracle_sql_case_fix.yaml diff --git a/.chloggen/oracle_sql_case_fix.yaml b/.chloggen/oracle_sql_case_fix.yaml new file mode 100644 index 0000000000000..bf10cba37b4c5 --- /dev/null +++ b/.chloggen/oracle_sql_case_fix.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. filelogreceiver) +component: oracledbreceiver + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Removing the toLowercase conversion on sql text in top_query payload. Also, adding child_address into the query_samples payload. + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [37478] + +# (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 999e0de9ac2865c5226ef93e226f49427855b21a Mon Sep 17 00:00:00 2001 From: sreenathv Date: Tue, 19 Aug 2025 14:24:23 +0100 Subject: [PATCH 27/51] removing toLowercase on sql_text --- receiver/oracledbreceiver/scraper.go | 3 +-- .../testdata/expectedQueryTextAndPlanQuery.yaml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index 3730dbe0b05ef..69a71bfeea621 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -764,8 +764,7 @@ func (s *oracleScraper) obfuscateCacheHits(hits []queryMetricCacheHit) []queryMe if err != nil { s.logger.Error("oracleScraper failed getting metric rows", zap.Error(err)) } else { - obfuscatedSQLLowerCase := strings.ToLower(obfuscatedSQL) - hit.queryText = obfuscatedSQLLowerCase + hit.queryText = obfuscatedSQL obfuscatedHits = append(obfuscatedHits, hit) } } diff --git a/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml b/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml index 3909a3e3cd306..bb36e8c1e56f7 100644 --- a/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml +++ b/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml @@ -18,7 +18,7 @@ resourceLogs: stringValue: oracle-host-sample-1 - key: db.query.text value: - stringValue: select count ( * ) from admin. employee e join admin. person p on e. businessentityid = ? join admin. employeepayhistory eph on e. businessentityid = eph. businessentityid where eph. rate > ( select avg ( rate ) from admin. employeepayhistory ) + stringValue: SELECT COUNT ( * ) FROM ADMIN. Employee e JOIN ADMIN. Person p ON e. BusinessEntityID = ? JOIN ADMIN. EmployeePayHistory eph ON e. BusinessEntityID = eph. BusinessEntityID WHERE eph. Rate > ( SELECT AVG ( Rate ) FROM ADMIN. EmployeePayHistory ) - key: oracledb.query_plan value: stringValue: '[{"ACCESS_PREDICATES":"","BYTES":"","CARDINALITY":"","COST":"1","CPU_COST":"","DEPTH":"0","ID":"0","IO_COST":"","OPERATION":"SELECT STATEMENT","OPTIONS":"FULL","PARENT_ID":"","POSITION":"1","PROJECTION":""}]' From 8a51a7439172c1d635563ae05dfa7b1abe89de37 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Thu, 21 Aug 2025 15:49:26 +0100 Subject: [PATCH 28/51] cleanup --- receiver/oracledbreceiver/scraper.go | 1 - 1 file changed, 1 deletion(-) diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index 31c41fc679a06..5982168132851 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -681,7 +681,6 @@ func (s *oracleScraper) collectTopNMetricData(ctx context.Context, logs plog.Log } func (s *oracleScraper) collectQuerySamples(ctx context.Context, logs plog.Logs) error { - s.logger.Info(">>>> collecting sqmples") const action = "ACTION" const duration = "DURATION_SEC" const event = "EVENT" From 98bbc5cd27f0e742569de87fd63c51d82ee6b47f Mon Sep 17 00:00:00 2001 From: sreenathv Date: Mon, 1 Sep 2025 22:56:46 +0100 Subject: [PATCH 29/51] [oracledbreceiver] Add service.instance.id in resource attributes --- receiver/oracledbreceiver/documentation.md | 1 + .../internal/metadata/generated_config.go | 4 ++++ .../metadata/generated_config_test.go | 4 ++++ .../internal/metadata/generated_logs.go | 6 +++++ .../internal/metadata/generated_logs_test.go | 2 ++ .../internal/metadata/generated_metrics.go | 6 +++++ .../metadata/generated_metrics_test.go | 1 + .../internal/metadata/generated_resource.go | 7 ++++++ .../metadata/generated_resource_test.go | 10 ++++++-- .../internal/metadata/testdata/config.yaml | 16 +++++++++++++ receiver/oracledbreceiver/metadata.yaml | 4 ++++ receiver/oracledbreceiver/scraper.go | 20 ++++++++++++++++ receiver/oracledbreceiver/scraper_test.go | 23 +++++++++++++++++++ .../expectedQueryTextAndPlanQuery.yaml | 7 +++--- .../testdata/expectedSamplesFile.yaml | 7 ++++-- 15 files changed, 111 insertions(+), 7 deletions(-) diff --git a/receiver/oracledbreceiver/documentation.md b/receiver/oracledbreceiver/documentation.md index 026c88fc56dbb..0cc00f33e3a95 100644 --- a/receiver/oracledbreceiver/documentation.md +++ b/receiver/oracledbreceiver/documentation.md @@ -470,3 +470,4 @@ Collection of event metrics for top N queries, filtered based on the highest CPU | ---- | ----------- | ------ | ------- | | host.name | The host name of Oracle Server | Any Str | true | | oracledb.instance.name | The name of the instance that data is coming from. | Any Str | true | +| service.instance.id | A unique identifier of the Oracle db instance in the format host:port | Any Str | true | diff --git a/receiver/oracledbreceiver/internal/metadata/generated_config.go b/receiver/oracledbreceiver/internal/metadata/generated_config.go index 61b93fbd50df8..1d8d20609ae80 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_config.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_config.go @@ -276,6 +276,7 @@ func (rac *ResourceAttributeConfig) Unmarshal(parser *confmap.Conf) error { type ResourceAttributesConfig struct { HostName ResourceAttributeConfig `mapstructure:"host.name"` OracledbInstanceName ResourceAttributeConfig `mapstructure:"oracledb.instance.name"` + ServiceInstanceID ResourceAttributeConfig `mapstructure:"service.instance.id"` } func DefaultResourceAttributesConfig() ResourceAttributesConfig { @@ -286,6 +287,9 @@ func DefaultResourceAttributesConfig() ResourceAttributesConfig { OracledbInstanceName: ResourceAttributeConfig{ Enabled: true, }, + ServiceInstanceID: ResourceAttributeConfig{ + Enabled: true, + }, } } diff --git a/receiver/oracledbreceiver/internal/metadata/generated_config_test.go b/receiver/oracledbreceiver/internal/metadata/generated_config_test.go index 84a4824de125d..83a0df54c694d 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_config_test.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_config_test.go @@ -73,6 +73,7 @@ func TestMetricsBuilderConfig(t *testing.T) { ResourceAttributes: ResourceAttributesConfig{ HostName: ResourceAttributeConfig{Enabled: true}, OracledbInstanceName: ResourceAttributeConfig{Enabled: true}, + ServiceInstanceID: ResourceAttributeConfig{Enabled: true}, }, }, }, @@ -126,6 +127,7 @@ func TestMetricsBuilderConfig(t *testing.T) { ResourceAttributes: ResourceAttributesConfig{ HostName: ResourceAttributeConfig{Enabled: false}, OracledbInstanceName: ResourceAttributeConfig{Enabled: false}, + ServiceInstanceID: ResourceAttributeConfig{Enabled: false}, }, }, }, @@ -173,6 +175,7 @@ func TestResourceAttributesConfig(t *testing.T) { want: ResourceAttributesConfig{ HostName: ResourceAttributeConfig{Enabled: true}, OracledbInstanceName: ResourceAttributeConfig{Enabled: true}, + ServiceInstanceID: ResourceAttributeConfig{Enabled: true}, }, }, { @@ -180,6 +183,7 @@ func TestResourceAttributesConfig(t *testing.T) { want: ResourceAttributesConfig{ HostName: ResourceAttributeConfig{Enabled: false}, OracledbInstanceName: ResourceAttributeConfig{Enabled: false}, + ServiceInstanceID: ResourceAttributeConfig{Enabled: false}, }, }, } diff --git a/receiver/oracledbreceiver/internal/metadata/generated_logs.go b/receiver/oracledbreceiver/internal/metadata/generated_logs.go index 0f6fc7e3d10d7..a9683732cc3d6 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_logs.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_logs.go @@ -173,6 +173,12 @@ func NewLogsBuilder(lbc LogsBuilderConfig, settings receiver.Settings) *LogsBuil if lbc.ResourceAttributes.OracledbInstanceName.EventsExclude != nil { lb.resourceAttributeExcludeFilter["oracledb.instance.name"] = filter.CreateFilter(lbc.ResourceAttributes.OracledbInstanceName.EventsExclude) } + if lbc.ResourceAttributes.ServiceInstanceID.EventsInclude != nil { + lb.resourceAttributeIncludeFilter["service.instance.id"] = filter.CreateFilter(lbc.ResourceAttributes.ServiceInstanceID.EventsInclude) + } + if lbc.ResourceAttributes.ServiceInstanceID.EventsExclude != nil { + lb.resourceAttributeExcludeFilter["service.instance.id"] = filter.CreateFilter(lbc.ResourceAttributes.ServiceInstanceID.EventsExclude) + } return lb } diff --git a/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go b/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go index 50d8d146f74c1..7e08396da8dae 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_logs_test.go @@ -33,6 +33,7 @@ func TestLogsBuilderAppendLogRecord(t *testing.T) { rb := lb.NewResourceBuilder() rb.SetHostName("host.name-val") rb.SetOracledbInstanceName("oracledb.instance.name-val") + rb.SetServiceInstanceID("service.instance.id-val") res := rb.Emit() // append the first log record @@ -138,6 +139,7 @@ func TestLogsBuilder(t *testing.T) { rb := lb.NewResourceBuilder() rb.SetHostName("host.name-val") rb.SetOracledbInstanceName("oracledb.instance.name-val") + rb.SetServiceInstanceID("service.instance.id-val") res := rb.Emit() logs := lb.Emit(WithLogsResource(res)) diff --git a/receiver/oracledbreceiver/internal/metadata/generated_metrics.go b/receiver/oracledbreceiver/internal/metadata/generated_metrics.go index b3e487958562f..a8f0a1f12d959 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_metrics.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_metrics.go @@ -2447,6 +2447,12 @@ func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, opt if mbc.ResourceAttributes.OracledbInstanceName.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["oracledb.instance.name"] = filter.CreateFilter(mbc.ResourceAttributes.OracledbInstanceName.MetricsExclude) } + if mbc.ResourceAttributes.ServiceInstanceID.MetricsInclude != nil { + mb.resourceAttributeIncludeFilter["service.instance.id"] = filter.CreateFilter(mbc.ResourceAttributes.ServiceInstanceID.MetricsInclude) + } + if mbc.ResourceAttributes.ServiceInstanceID.MetricsExclude != nil { + mb.resourceAttributeExcludeFilter["service.instance.id"] = filter.CreateFilter(mbc.ResourceAttributes.ServiceInstanceID.MetricsExclude) + } for _, op := range options { op.apply(mb) diff --git a/receiver/oracledbreceiver/internal/metadata/generated_metrics_test.go b/receiver/oracledbreceiver/internal/metadata/generated_metrics_test.go index 498b63974869d..78778724407cc 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_metrics_test.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_metrics_test.go @@ -222,6 +222,7 @@ func TestMetricsBuilder(t *testing.T) { rb := mb.NewResourceBuilder() rb.SetHostName("host.name-val") rb.SetOracledbInstanceName("oracledb.instance.name-val") + rb.SetServiceInstanceID("service.instance.id-val") res := rb.Emit() metrics := mb.Emit(WithResource(res)) diff --git a/receiver/oracledbreceiver/internal/metadata/generated_resource.go b/receiver/oracledbreceiver/internal/metadata/generated_resource.go index 805f84f280c0c..0825fb20f8c10 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_resource.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_resource.go @@ -35,6 +35,13 @@ func (rb *ResourceBuilder) SetOracledbInstanceName(val string) { } } +// SetServiceInstanceID sets provided value as "service.instance.id" attribute. +func (rb *ResourceBuilder) SetServiceInstanceID(val string) { + if rb.config.ServiceInstanceID.Enabled { + rb.res.Attributes().PutStr("service.instance.id", val) + } +} + // Emit returns the built resource and resets the internal builder state. func (rb *ResourceBuilder) Emit() pcommon.Resource { r := rb.res diff --git a/receiver/oracledbreceiver/internal/metadata/generated_resource_test.go b/receiver/oracledbreceiver/internal/metadata/generated_resource_test.go index 7995f73df8462..748a7c59f7777 100644 --- a/receiver/oracledbreceiver/internal/metadata/generated_resource_test.go +++ b/receiver/oracledbreceiver/internal/metadata/generated_resource_test.go @@ -15,15 +15,16 @@ func TestResourceBuilder(t *testing.T) { rb := NewResourceBuilder(cfg) rb.SetHostName("host.name-val") rb.SetOracledbInstanceName("oracledb.instance.name-val") + rb.SetServiceInstanceID("service.instance.id-val") res := rb.Emit() assert.Equal(t, 0, rb.Emit().Attributes().Len()) // Second call should return empty Resource switch tt { case "default": - assert.Equal(t, 2, res.Attributes().Len()) + assert.Equal(t, 3, res.Attributes().Len()) case "all_set": - assert.Equal(t, 2, res.Attributes().Len()) + assert.Equal(t, 3, res.Attributes().Len()) case "none_set": assert.Equal(t, 0, res.Attributes().Len()) return @@ -41,6 +42,11 @@ func TestResourceBuilder(t *testing.T) { if ok { assert.Equal(t, "oracledb.instance.name-val", val.Str()) } + val, ok = res.Attributes().Get("service.instance.id") + assert.True(t, ok) + if ok { + assert.Equal(t, "service.instance.id-val", val.Str()) + } }) } } diff --git a/receiver/oracledbreceiver/internal/metadata/testdata/config.yaml b/receiver/oracledbreceiver/internal/metadata/testdata/config.yaml index c0cd319251fd0..6158dbbeea194 100644 --- a/receiver/oracledbreceiver/internal/metadata/testdata/config.yaml +++ b/receiver/oracledbreceiver/internal/metadata/testdata/config.yaml @@ -95,6 +95,8 @@ all_set: enabled: true oracledb.instance.name: enabled: true + service.instance.id: + enabled: true none_set: metrics: oracledb.consistent_gets: @@ -191,6 +193,8 @@ none_set: enabled: false oracledb.instance.name: enabled: false + service.instance.id: + enabled: false filter_set_include: resource_attributes: host.name: @@ -205,6 +209,12 @@ filter_set_include: - regexp: ".*" events_include: - regexp: ".*" + service.instance.id: + enabled: true + metrics_include: + - regexp: ".*" + events_include: + - regexp: ".*" filter_set_exclude: resource_attributes: host.name: @@ -219,3 +229,9 @@ filter_set_exclude: - strict: "oracledb.instance.name-val" events_exclude: - strict: "oracledb.instance.name-val" + service.instance.id: + enabled: true + metrics_exclude: + - strict: "service.instance.id-val" + events_exclude: + - strict: "service.instance.id-val" diff --git a/receiver/oracledbreceiver/metadata.yaml b/receiver/oracledbreceiver/metadata.yaml index ba4844aef6a13..6105f732f2e00 100644 --- a/receiver/oracledbreceiver/metadata.yaml +++ b/receiver/oracledbreceiver/metadata.yaml @@ -18,6 +18,10 @@ resource_attributes: description: The host name of Oracle Server enabled: true type: string + service.instance.id: + description: A unique identifier of the Oracle db instance in the format host:port + enabled: true + type: string attributes: session_status: diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index 5982168132851..e4ddd1b3436fa 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -11,6 +11,8 @@ import ( "encoding/json" "errors" "fmt" + "net" + "os" "sort" "strconv" "strings" @@ -131,6 +133,7 @@ type oracleScraper struct { topQueryCollectCfg TopQueryCollection obfuscator *obfuscator querySampleCfg QuerySample + serviceInstanceID string } func newScraper(metricsBuilder *metadata.MetricsBuilder, metricsBuilderConfig metadata.MetricsBuilderConfig, scrapeCfg scraperhelper.ControllerConfig, logger *zap.Logger, providerFunc dbProviderFunc, clientProviderFunc clientProviderFunc, instanceName, hostName string) (scraper.Metrics, error) { @@ -164,6 +167,7 @@ func newLogsScraper(logsBuilder *metadata.LogsBuilder, logsBuilderConfig metadat querySampleCfg: querySampleCfg, hostName: hostName, obfuscator: newObfuscator(), + serviceInstanceID: getInstanceId(hostName, logger), } return scraper.NewLogs(s.scrapeLogs, scraper.WithShutdown(s.shutdown), scraper.WithStart(s.start)) } @@ -637,6 +641,7 @@ func (s *oracleScraper) collectTopNMetricData(ctx context.Context, logs plog.Log rb := s.lb.NewResourceBuilder() rb.SetOracledbInstanceName(s.instanceName) rb.SetHostName(s.hostName) + rb.SetServiceInstanceID(s.serviceInstanceID) for _, hit := range hits { planBytes, err := json.Marshal(childAddressToPlanMap[hit.childAddress]) @@ -720,6 +725,7 @@ func (s *oracleScraper) collectQuerySamples(ctx context.Context, logs plog.Logs) rb := s.lb.NewResourceBuilder() rb.SetOracledbInstanceName(s.instanceName) rb.SetHostName(s.hostName) + rb.SetServiceInstanceID(s.serviceInstanceID) for _, row := range rows { if row[sqlText] == "" { @@ -828,3 +834,17 @@ func (s *oracleScraper) shutdown(_ context.Context) error { } return s.db.Close() } + +func getInstanceId(hostString string, logger *zap.Logger) string { + host, port, err := net.SplitHostPort(hostString) + if err == nil && (strings.EqualFold(host, "localhost") || net.ParseIP(host).IsLoopback()) { + host, err = os.Hostname() + } + + if err != nil { + logger.Warn("Failed to compute service.instance.id", zap.Error(err)) + return "unknown:1521" + } + + return host + ":" + port +} diff --git a/receiver/oracledbreceiver/scraper_test.go b/receiver/oracledbreceiver/scraper_test.go index 9ccf1da1d9e2f..64e93f5fde0af 100644 --- a/receiver/oracledbreceiver/scraper_test.go +++ b/receiver/oracledbreceiver/scraper_test.go @@ -390,6 +390,29 @@ func TestSamplesQuery(t *testing.T) { } } +func TestGetInstanceId(t *testing.T) { + localhostName, _ := os.Hostname() + + hostString := "example.com:1521" + instanceId := getInstanceId(hostString, zap.NewNop()) + assert.Equal(t, "example.com:1521", instanceId) + + localHostStringUppercase := "Localhost:1521" + localInstanceId := getInstanceId(localHostStringUppercase, zap.NewNop()) + assert.NotNil(t, localInstanceId) + assert.Equal(t, localhostName+":1521", localInstanceId) + + localHostString := "127.0.0.1:1521" + localInstanceId = getInstanceId(localHostString, zap.NewNop()) + assert.NotNil(t, localInstanceId) + assert.Equal(t, localhostName+":1521", localInstanceId) + + localHostStringIPV6 := "[::1]:1521" + localInstanceId = getInstanceId(localHostStringIPV6, zap.NewNop()) + assert.NotNil(t, localInstanceId) + assert.Equal(t, localhostName+":1521", localInstanceId) +} + func readFile(fname string) []byte { file, err := os.ReadFile(filepath.Join("testdata", fname)) if err != nil { diff --git a/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml b/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml index bb36e8c1e56f7..93d3144e8c8d2 100644 --- a/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml +++ b/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml @@ -7,6 +7,9 @@ resourceLogs: - key: host.name value: stringValue: oracle-host-sample-1 + - key: service.instance.id + value: + stringValue: "" scopeLogs: - logRecords: - attributes: @@ -81,9 +84,7 @@ resourceLogs: doubleValue: 2e-05 body: {} eventName: db.server.top_query - spanId: "" - timeUnixNano: "1752581882636677000" - traceId: "" + timeUnixNano: "1756763669220332000" scope: name: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/oracledbreceiver version: latest diff --git a/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml b/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml index 097b8c6a7609e..c01a6f3d7ca07 100644 --- a/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml +++ b/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml @@ -7,6 +7,9 @@ resourceLogs: - key: host.name value: stringValue: "" + - key: service.instance.id + value: + stringValue: "" scopeLogs: - logRecords: - attributes: @@ -45,7 +48,7 @@ resourceLogs: stringValue: "0" - key: oracledb.child_address value: - stringValue: "SDF3SDF1234D" + stringValue: SDF3SDF1234D - key: oracledb.sid value: stringValue: "675" @@ -91,7 +94,7 @@ resourceLogs: body: {} eventName: db.server.query_sample spanId: a7ad6b7169203331 - timeUnixNano: "1754828794690056000" + timeUnixNano: "1756763648441865000" traceId: 0af7651916cd43dd8448eb211c80319c scope: name: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/oracledbreceiver From ef87cd235f3bf664ab96f750634fc9b448a883e1 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Mon, 1 Sep 2025 23:00:30 +0100 Subject: [PATCH 30/51] lint fixes --- receiver/oracledbreceiver/scraper.go | 4 ++-- receiver/oracledbreceiver/scraper_test.go | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index e4ddd1b3436fa..4b517022ecd60 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -167,7 +167,7 @@ func newLogsScraper(logsBuilder *metadata.LogsBuilder, logsBuilderConfig metadat querySampleCfg: querySampleCfg, hostName: hostName, obfuscator: newObfuscator(), - serviceInstanceID: getInstanceId(hostName, logger), + serviceInstanceID: getInstanceID(hostName, logger), } return scraper.NewLogs(s.scrapeLogs, scraper.WithShutdown(s.shutdown), scraper.WithStart(s.start)) } @@ -835,7 +835,7 @@ func (s *oracleScraper) shutdown(_ context.Context) error { return s.db.Close() } -func getInstanceId(hostString string, logger *zap.Logger) string { +func getInstanceID(hostString string, logger *zap.Logger) string { host, port, err := net.SplitHostPort(hostString) if err == nil && (strings.EqualFold(host, "localhost") || net.ParseIP(host).IsLoopback()) { host, err = os.Hostname() diff --git a/receiver/oracledbreceiver/scraper_test.go b/receiver/oracledbreceiver/scraper_test.go index 64e93f5fde0af..96938294bf436 100644 --- a/receiver/oracledbreceiver/scraper_test.go +++ b/receiver/oracledbreceiver/scraper_test.go @@ -394,23 +394,23 @@ func TestGetInstanceId(t *testing.T) { localhostName, _ := os.Hostname() hostString := "example.com:1521" - instanceId := getInstanceId(hostString, zap.NewNop()) - assert.Equal(t, "example.com:1521", instanceId) + instanceID := getInstanceID(hostString, zap.NewNop()) + assert.Equal(t, "example.com:1521", instanceID) localHostStringUppercase := "Localhost:1521" - localInstanceId := getInstanceId(localHostStringUppercase, zap.NewNop()) - assert.NotNil(t, localInstanceId) - assert.Equal(t, localhostName+":1521", localInstanceId) + localInstanceID := getInstanceID(localHostStringUppercase, zap.NewNop()) + assert.NotNil(t, localInstanceID) + assert.Equal(t, localhostName+":1521", localInstanceID) localHostString := "127.0.0.1:1521" - localInstanceId = getInstanceId(localHostString, zap.NewNop()) - assert.NotNil(t, localInstanceId) - assert.Equal(t, localhostName+":1521", localInstanceId) + localInstanceID = getInstanceID(localHostString, zap.NewNop()) + assert.NotNil(t, localInstanceID) + assert.Equal(t, localhostName+":1521", localInstanceID) localHostStringIPV6 := "[::1]:1521" - localInstanceId = getInstanceId(localHostStringIPV6, zap.NewNop()) - assert.NotNil(t, localInstanceId) - assert.Equal(t, localhostName+":1521", localInstanceId) + localInstanceID = getInstanceID(localHostStringIPV6, zap.NewNop()) + assert.NotNil(t, localInstanceID) + assert.Equal(t, localhostName+":1521", localInstanceID) } func readFile(fname string) []byte { From aa0b9ebc6c5a334ef9d14b6e98f5e8911e72cc93 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Mon, 1 Sep 2025 23:39:52 +0100 Subject: [PATCH 31/51] chlog & other refactor --- receiver/oracledbreceiver/scraper.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index 4b517022ecd60..3f7ea7ad1e763 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -506,9 +506,8 @@ func (s *oracleScraper) scrape(ctx context.Context) (pmetric.Metrics, error) { } } - rb := s.mb.NewResourceBuilder() - rb.SetOracledbInstanceName(s.instanceName) - rb.SetHostName(s.hostName) + rb := s.setupResourceBuilder(s.mb.NewResourceBuilder()) + out := s.mb.Emit(metadata.WithResource(rb.Emit())) s.logger.Debug("Done scraping") if len(scrapeErrors) > 0 { @@ -638,10 +637,7 @@ func (s *oracleScraper) collectTopNMetricData(ctx context.Context, logs plog.Log hits = s.obfuscateCacheHits(hits) childAddressToPlanMap := s.getChildAddressToPlanMap(ctx, hits) - rb := s.lb.NewResourceBuilder() - rb.SetOracledbInstanceName(s.instanceName) - rb.SetHostName(s.hostName) - rb.SetServiceInstanceID(s.serviceInstanceID) + rb := s.setupResourceBuilder(s.lb.NewResourceBuilder()) for _, hit := range hits { planBytes, err := json.Marshal(childAddressToPlanMap[hit.childAddress]) @@ -722,10 +718,7 @@ func (s *oracleScraper) collectQuerySamples(ctx context.Context, logs plog.Logs) scrapeErrors = append(scrapeErrors, fmt.Errorf("error executing %s: %w", samplesQuery, err)) } - rb := s.lb.NewResourceBuilder() - rb.SetOracledbInstanceName(s.instanceName) - rb.SetHostName(s.hostName) - rb.SetServiceInstanceID(s.serviceInstanceID) + rb := s.setupResourceBuilder(s.lb.NewResourceBuilder()) for _, row := range rows { if row[sqlText] == "" { @@ -835,6 +828,13 @@ func (s *oracleScraper) shutdown(_ context.Context) error { return s.db.Close() } +func (s *oracleScraper) setupResourceBuilder(rb *metadata.ResourceBuilder) *metadata.ResourceBuilder { + rb.SetOracledbInstanceName(s.instanceName) + rb.SetHostName(s.hostName) + rb.SetServiceInstanceID(s.serviceInstanceID) + return rb +} + func getInstanceID(hostString string, logger *zap.Logger) string { host, port, err := net.SplitHostPort(hostString) if err == nil && (strings.EqualFold(host, "localhost") || net.ParseIP(host).IsLoopback()) { From ea60e09206655c5b72c45aa1c8c62f8be38db5bc Mon Sep 17 00:00:00 2001 From: sreenathv Date: Mon, 1 Sep 2025 23:40:27 +0100 Subject: [PATCH 32/51] chlog & other refactor --- .chloggen/main.yaml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .chloggen/main.yaml diff --git a/.chloggen/main.yaml b/.chloggen/main.yaml new file mode 100644 index 0000000000000..0b2707a944f2e --- /dev/null +++ b/.chloggen/main.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: + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: + +# 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: + +# 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: [] From 3df3c2b12433e4a7d9a61b327bc9860151b6bda8 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Mon, 1 Sep 2025 23:56:38 +0100 Subject: [PATCH 33/51] chlog --- .chloggen/main.yaml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.chloggen/main.yaml b/.chloggen/main.yaml index 0b2707a944f2e..4156c0b96317b 100644 --- a/.chloggen/main.yaml +++ b/.chloggen/main.yaml @@ -1,21 +1,23 @@ # Use this changelog template to create an entry for release notes. # One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' -change_type: +change_type: enhancement # The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) -component: +component: oracledbreceiver # A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). -note: +note: `service.instance.id` attribute is added in resourceAttributes of all metrics and logs in oracledbreceiver # Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. -issues: [] +issues: [42402] # (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: +subtext: | + The `service.instance.id` attribute is added in the format `:` to uniquely identify + Oracle db hosts. # 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. @@ -24,4 +26,4 @@ subtext: # 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: [] +change_logs: [user] From d7b3a9cf606ca2d0e9781feddcf450900bd82b0e Mon Sep 17 00:00:00 2001 From: sreenathv Date: Mon, 1 Sep 2025 23:58:40 +0100 Subject: [PATCH 34/51] chlog --- .chloggen/oracle_sql_case_fix.yaml | 27 ------------------- ...ice_instance_id_for_oracledbreceiver.yaml} | 0 2 files changed, 27 deletions(-) delete mode 100644 .chloggen/oracle_sql_case_fix.yaml rename .chloggen/{main.yaml => service_instance_id_for_oracledbreceiver.yaml} (100%) diff --git a/.chloggen/oracle_sql_case_fix.yaml b/.chloggen/oracle_sql_case_fix.yaml deleted file mode 100644 index bf10cba37b4c5..0000000000000 --- a/.chloggen/oracle_sql_case_fix.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. filelogreceiver) -component: oracledbreceiver - -# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). -note: Removing the toLowercase conversion on sql text in top_query payload. Also, adding child_address into the query_samples payload. - -# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. -issues: [37478] - -# (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] diff --git a/.chloggen/main.yaml b/.chloggen/service_instance_id_for_oracledbreceiver.yaml similarity index 100% rename from .chloggen/main.yaml rename to .chloggen/service_instance_id_for_oracledbreceiver.yaml From 5719fbdc2265becaff29b99e75642410269a6e76 Mon Sep 17 00:00:00 2001 From: Sreenath Date: Tue, 2 Sep 2025 13:52:18 +0100 Subject: [PATCH 35/51] fix chlog --- .chloggen/service_instance_id_for_oracledbreceiver.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.chloggen/service_instance_id_for_oracledbreceiver.yaml b/.chloggen/service_instance_id_for_oracledbreceiver.yaml index 4156c0b96317b..61a5969ca452d 100644 --- a/.chloggen/service_instance_id_for_oracledbreceiver.yaml +++ b/.chloggen/service_instance_id_for_oracledbreceiver.yaml @@ -7,7 +7,7 @@ change_type: enhancement component: oracledbreceiver # A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). -note: `service.instance.id` attribute is added in resourceAttributes of all metrics and logs in oracledbreceiver +note: service.instance.id attribute is added in resourceAttributes of all metrics and logs in oracledbreceiver # Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. issues: [42402] From 349978b45f89aa67859f5abb549c23a409ecd798 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Wed, 3 Sep 2025 12:09:05 +0100 Subject: [PATCH 36/51] changes to preserve original port if failed to resolve hostname --- receiver/oracledbreceiver/scraper.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index 3f7ea7ad1e763..140bdf018d9f7 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -836,6 +836,8 @@ func (s *oracleScraper) setupResourceBuilder(rb *metadata.ResourceBuilder) *meta } func getInstanceID(hostString string, logger *zap.Logger) string { + const fallback = "unknown:1521" + host, port, err := net.SplitHostPort(hostString) if err == nil && (strings.EqualFold(host, "localhost") || net.ParseIP(host).IsLoopback()) { host, err = os.Hostname() @@ -843,7 +845,10 @@ func getInstanceID(hostString string, logger *zap.Logger) string { if err != nil { logger.Warn("Failed to compute service.instance.id", zap.Error(err)) - return "unknown:1521" + if port == "" { + return fallback + } + return "unknown:" + port } return host + ":" + port From c3c9abd0aa62bbb37fb606e10549b16b85e5ec38 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Wed, 3 Sep 2025 13:56:57 +0100 Subject: [PATCH 37/51] fix --- receiver/oracledbreceiver/scraper.go | 1 + 1 file changed, 1 insertion(+) diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index 140bdf018d9f7..7d1ea19943612 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -146,6 +146,7 @@ func newScraper(metricsBuilder *metadata.MetricsBuilder, metricsBuilderConfig me clientProviderFunc: clientProviderFunc, instanceName: instanceName, hostName: hostName, + serviceInstanceID: getInstanceID(hostName, logger), } return scraper.NewMetrics(s.scrape, scraper.WithShutdown(s.shutdown), scraper.WithStart(s.start)) } From cdf397cd11f3bede8c0ccdbf76c285ac3519f5f9 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Mon, 8 Sep 2025 09:33:37 +0100 Subject: [PATCH 38/51] Appending service name to the instnceID --- receiver/oracledbreceiver/scraper.go | 21 ++++++++++++++------- receiver/oracledbreceiver/scraper_test.go | 21 +++++++++++++-------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index 7d1ea19943612..2d976ac55e8b0 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -146,7 +146,7 @@ func newScraper(metricsBuilder *metadata.MetricsBuilder, metricsBuilderConfig me clientProviderFunc: clientProviderFunc, instanceName: instanceName, hostName: hostName, - serviceInstanceID: getInstanceID(hostName, logger), + serviceInstanceID: getInstanceID(instanceName, logger), } return scraper.NewMetrics(s.scrape, scraper.WithShutdown(s.shutdown), scraper.WithStart(s.start)) } @@ -168,7 +168,7 @@ func newLogsScraper(logsBuilder *metadata.LogsBuilder, logsBuilderConfig metadat querySampleCfg: querySampleCfg, hostName: hostName, obfuscator: newObfuscator(), - serviceInstanceID: getInstanceID(hostName, logger), + serviceInstanceID: getInstanceID(instanceName, logger), } return scraper.NewLogs(s.scrapeLogs, scraper.WithShutdown(s.shutdown), scraper.WithStart(s.start)) } @@ -836,10 +836,17 @@ func (s *oracleScraper) setupResourceBuilder(rb *metadata.ResourceBuilder) *meta return rb } -func getInstanceID(hostString string, logger *zap.Logger) string { +func getInstanceID(instanceString string, logger *zap.Logger) string { const fallback = "unknown:1521" - host, port, err := net.SplitHostPort(hostString) + parts := strings.SplitN(instanceString, "/", 2) + hostAndPort := parts[0] + service := "" + if len(parts) == 2 { + service = "/" + parts[1] + } + + host, port, err := net.SplitHostPort(hostAndPort) if err == nil && (strings.EqualFold(host, "localhost") || net.ParseIP(host).IsLoopback()) { host, err = os.Hostname() } @@ -847,10 +854,10 @@ func getInstanceID(hostString string, logger *zap.Logger) string { if err != nil { logger.Warn("Failed to compute service.instance.id", zap.Error(err)) if port == "" { - return fallback + return fallback + service } - return "unknown:" + port + return "unknown:" + port + service } - return host + ":" + port + return host + ":" + port + service } diff --git a/receiver/oracledbreceiver/scraper_test.go b/receiver/oracledbreceiver/scraper_test.go index 96938294bf436..a4775d7a264a1 100644 --- a/receiver/oracledbreceiver/scraper_test.go +++ b/receiver/oracledbreceiver/scraper_test.go @@ -393,23 +393,28 @@ func TestSamplesQuery(t *testing.T) { func TestGetInstanceId(t *testing.T) { localhostName, _ := os.Hostname() - hostString := "example.com:1521" - instanceID := getInstanceID(hostString, zap.NewNop()) - assert.Equal(t, "example.com:1521", instanceID) + instanceString := "example.com:1521/XE" + instanceID := getInstanceID(instanceString, zap.NewNop()) + assert.Equal(t, "example.com:1521/XE", instanceID) - localHostStringUppercase := "Localhost:1521" + localHostStringUppercase := "Localhost:1521/XE" localInstanceID := getInstanceID(localHostStringUppercase, zap.NewNop()) assert.NotNil(t, localInstanceID) - assert.Equal(t, localhostName+":1521", localInstanceID) + assert.Equal(t, localhostName+":1521/XE", localInstanceID) - localHostString := "127.0.0.1:1521" + localHostString := "127.0.0.1:1521/XE" localInstanceID = getInstanceID(localHostString, zap.NewNop()) assert.NotNil(t, localInstanceID) - assert.Equal(t, localhostName+":1521", localInstanceID) + assert.Equal(t, localhostName+":1521/XE", localInstanceID) - localHostStringIPV6 := "[::1]:1521" + localHostStringIPV6 := "[::1]:1521/XE" localInstanceID = getInstanceID(localHostStringIPV6, zap.NewNop()) assert.NotNil(t, localInstanceID) + assert.Equal(t, localhostName+":1521/XE", localInstanceID) + + hostWithoutService := "127.0.0.1:1521" + localInstanceID = getInstanceID(hostWithoutService, zap.NewNop()) + assert.NotNil(t, localInstanceID) assert.Equal(t, localhostName+":1521", localInstanceID) } From ade0bb33de98e0c30b675a931d86c1fcd990c567 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Mon, 8 Sep 2025 12:12:50 +0100 Subject: [PATCH 39/51] Moving err handling --- receiver/oracledbreceiver/scraper.go | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index 2d976ac55e8b0..fdfd27e64cae8 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -837,8 +837,6 @@ func (s *oracleScraper) setupResourceBuilder(rb *metadata.ResourceBuilder) *meta } func getInstanceID(instanceString string, logger *zap.Logger) string { - const fallback = "unknown:1521" - parts := strings.SplitN(instanceString, "/", 2) hostAndPort := parts[0] service := "" @@ -847,17 +845,26 @@ func getInstanceID(instanceString string, logger *zap.Logger) string { } host, port, err := net.SplitHostPort(hostAndPort) - if err == nil && (strings.EqualFold(host, "localhost") || net.ParseIP(host).IsLoopback()) { - host, err = os.Hostname() + if err != nil { + return handleInstanceIdErr(err, logger, port, service) } + if strings.EqualFold(host, "localhost") || net.ParseIP(host).IsLoopback() { + host, err = os.Hostname() + } if err != nil { - logger.Warn("Failed to compute service.instance.id", zap.Error(err)) - if port == "" { - return fallback + service - } - return "unknown:" + port + service + return handleInstanceIdErr(err, logger, port, service) } return host + ":" + port + service } + +func handleInstanceIdErr(err error, logger *zap.Logger, port string, service string) string { + const fallback = "unknown:1521" + + logger.Warn("Failed to compute service.instance.id", zap.Error(err)) + if port == "" { + return fallback + service + } + return "unknown:" + port + service +} From 012ec0f28b104534762bc0d647542a524a404b32 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Mon, 8 Sep 2025 12:22:25 +0100 Subject: [PATCH 40/51] Moving err handling --- receiver/oracledbreceiver/scraper.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index fdfd27e64cae8..90a71ea71afe0 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -846,20 +846,20 @@ func getInstanceID(instanceString string, logger *zap.Logger) string { host, port, err := net.SplitHostPort(hostAndPort) if err != nil { - return handleInstanceIdErr(err, logger, port, service) + return handleInstanceIDErr(err, logger, port, service) } if strings.EqualFold(host, "localhost") || net.ParseIP(host).IsLoopback() { host, err = os.Hostname() } if err != nil { - return handleInstanceIdErr(err, logger, port, service) + return handleInstanceIDErr(err, logger, port, service) } return host + ":" + port + service } -func handleInstanceIdErr(err error, logger *zap.Logger, port string, service string) string { +func handleInstanceIDErr(err error, logger *zap.Logger, port string, service string) string { const fallback = "unknown:1521" logger.Warn("Failed to compute service.instance.id", zap.Error(err)) From f99d57c4e0c29390a6c2136eee5e5e76d4b1eafa Mon Sep 17 00:00:00 2001 From: sreenathv Date: Mon, 8 Sep 2025 12:23:34 +0100 Subject: [PATCH 41/51] Update chlog --- .chloggen/service_instance_id_for_oracledbreceiver.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.chloggen/service_instance_id_for_oracledbreceiver.yaml b/.chloggen/service_instance_id_for_oracledbreceiver.yaml index 61a5969ca452d..244ee502c33bc 100644 --- a/.chloggen/service_instance_id_for_oracledbreceiver.yaml +++ b/.chloggen/service_instance_id_for_oracledbreceiver.yaml @@ -16,7 +16,7 @@ issues: [42402] # These lines will be padded with 2 spaces and then inserted directly into the document. # Use pipe (|) for multiline entries. subtext: | - The `service.instance.id` attribute is added in the format `:` to uniquely identify + The `service.instance.id` attribute is added in the format `:/` to uniquely identify Oracle db hosts. # If your change doesn't affect end users or the exported elements of any package, From 88fedff52df2239d4d10666bfa690150695c164a Mon Sep 17 00:00:00 2001 From: sreenathv Date: Mon, 8 Sep 2025 12:35:37 +0100 Subject: [PATCH 42/51] re-generate --- receiver/oracledbreceiver/scraper.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index 90a71ea71afe0..76a3257a33ea3 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -859,7 +859,7 @@ func getInstanceID(instanceString string, logger *zap.Logger) string { return host + ":" + port + service } -func handleInstanceIDErr(err error, logger *zap.Logger, port string, service string) string { +func handleInstanceIDErr(err error, logger *zap.Logger, port, service string) string { const fallback = "unknown:1521" logger.Warn("Failed to compute service.instance.id", zap.Error(err)) From ee76b52deb8c5aa5da56f3bd31662060da8527b6 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Tue, 23 Sep 2025 08:01:27 +0100 Subject: [PATCH 43/51] Addressing PR comments --- receiver/oracledbreceiver/metadata.yaml | 2 +- receiver/oracledbreceiver/scraper.go | 30 ++++++++----------- receiver/oracledbreceiver/scraper_test.go | 5 ++++ .../expectedQueryTextAndPlanQuery.yaml | 2 +- .../testdata/expectedSamplesFile.yaml | 2 +- 5 files changed, 21 insertions(+), 20 deletions(-) diff --git a/receiver/oracledbreceiver/metadata.yaml b/receiver/oracledbreceiver/metadata.yaml index 6105f732f2e00..e9704303f183b 100644 --- a/receiver/oracledbreceiver/metadata.yaml +++ b/receiver/oracledbreceiver/metadata.yaml @@ -19,7 +19,7 @@ resource_attributes: enabled: true type: string service.instance.id: - description: A unique identifier of the Oracle db instance in the format host:port + description: A unique identifier of the Oracle DB instance in the format host:port/serviceName. (defaults to 'unknown:1521', in case of error in generating this value) enabled: true type: string diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index 76a3257a33ea3..b8d441d29a09a 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -837,34 +837,30 @@ func (s *oracleScraper) setupResourceBuilder(rb *metadata.ResourceBuilder) *meta } func getInstanceID(instanceString string, logger *zap.Logger) string { - parts := strings.SplitN(instanceString, "/", 2) - hostAndPort := parts[0] - service := "" - if len(parts) == 2 { - service = "/" + parts[1] + hostAndPort, service, found := strings.Cut(instanceString, "/") + if !found { + logger.Info("No serviceName found in the connection string", zap.String("instanceString", instanceString)) } host, port, err := net.SplitHostPort(hostAndPort) if err != nil { - return handleInstanceIDErr(err, logger, port, service) + logger.Warn("Computing service.instance.id failed. Couldn't extract host and port from the connection data.", zap.Error(err)) + return constructInstanceID("unknown", "1521", service) } + // Replace the host value with machine name if connecting to localhost target if strings.EqualFold(host, "localhost") || net.ParseIP(host).IsLoopback() { host, err = os.Hostname() } - if err != nil { - return handleInstanceIDErr(err, logger, port, service) - } - return host + ":" + port + service + return constructInstanceID(host, port, service) } -func handleInstanceIDErr(err error, logger *zap.Logger, port, service string) string { - const fallback = "unknown:1521" - - logger.Warn("Failed to compute service.instance.id", zap.Error(err)) - if port == "" { - return fallback + service +func constructInstanceID(host, port, service string) (id string) { + if service != "" { + id = fmt.Sprintf("%s:%s/%s", host, port, service) + } else { + id = fmt.Sprintf("%s:%s", host, port) } - return "unknown:" + port + service + return } diff --git a/receiver/oracledbreceiver/scraper_test.go b/receiver/oracledbreceiver/scraper_test.go index a4775d7a264a1..6b23a3aac28de 100644 --- a/receiver/oracledbreceiver/scraper_test.go +++ b/receiver/oracledbreceiver/scraper_test.go @@ -416,6 +416,11 @@ func TestGetInstanceId(t *testing.T) { localInstanceID = getInstanceID(hostWithoutService, zap.NewNop()) assert.NotNil(t, localInstanceID) assert.Equal(t, localhostName+":1521", localInstanceID) + + hostNameErrorSample := "" + localInstanceID = getInstanceID(hostNameErrorSample, zap.NewNop()) + assert.NotNil(t, localInstanceID) + assert.Equal(t, "unknown:1521", localInstanceID) } func readFile(fname string) []byte { diff --git a/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml b/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml index 93d3144e8c8d2..caceca578dc74 100644 --- a/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml +++ b/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml @@ -84,7 +84,7 @@ resourceLogs: doubleValue: 2e-05 body: {} eventName: db.server.top_query - timeUnixNano: "1756763669220332000" + timeUnixNano: "1758608906406938000" scope: name: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/oracledbreceiver version: latest diff --git a/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml b/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml index c01a6f3d7ca07..96ae178dd9846 100644 --- a/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml +++ b/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml @@ -94,7 +94,7 @@ resourceLogs: body: {} eventName: db.server.query_sample spanId: a7ad6b7169203331 - timeUnixNano: "1756763648441865000" + timeUnixNano: "1758608929036258000" traceId: 0af7651916cd43dd8448eb211c80319c scope: name: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/oracledbreceiver From 05e4876c6f07ad53fc1d3d7b6ce22ec7a80c03d4 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Tue, 23 Sep 2025 08:08:41 +0100 Subject: [PATCH 44/51] make generate --- receiver/oracledbreceiver/documentation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/receiver/oracledbreceiver/documentation.md b/receiver/oracledbreceiver/documentation.md index 0cc00f33e3a95..3d6a4c7f07643 100644 --- a/receiver/oracledbreceiver/documentation.md +++ b/receiver/oracledbreceiver/documentation.md @@ -470,4 +470,4 @@ Collection of event metrics for top N queries, filtered based on the highest CPU | ---- | ----------- | ------ | ------- | | host.name | The host name of Oracle Server | Any Str | true | | oracledb.instance.name | The name of the instance that data is coming from. | Any Str | true | -| service.instance.id | A unique identifier of the Oracle db instance in the format host:port | Any Str | true | +| service.instance.id | A unique identifier of the Oracle DB instance in the format host:port/serviceName. (defaults to 'unknown:1521', in case of error in generating this value) | Any Str | true | From aa23fb1945e8dd27b6f5fc090eac27be76f31c95 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Tue, 23 Sep 2025 08:34:40 +0100 Subject: [PATCH 45/51] Updating err log --- receiver/oracledbreceiver/scraper.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index b8d441d29a09a..be808ef1c3aa4 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -851,6 +851,9 @@ func getInstanceID(instanceString string, logger *zap.Logger) string { // Replace the host value with machine name if connecting to localhost target if strings.EqualFold(host, "localhost") || net.ParseIP(host).IsLoopback() { host, err = os.Hostname() + if err != nil { + logger.Warn("Error getting localhost machine name for generating service.instance.id.") + } } return constructInstanceID(host, port, service) From b0735398f3f93357177f9c8a371db8d066023377 Mon Sep 17 00:00:00 2001 From: Sreenath Date: Mon, 29 Sep 2025 11:43:06 +0100 Subject: [PATCH 46/51] Update .chloggen/service_instance_id_for_oracledbreceiver.yaml Co-authored-by: Curtis Robert --- .chloggen/service_instance_id_for_oracledbreceiver.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.chloggen/service_instance_id_for_oracledbreceiver.yaml b/.chloggen/service_instance_id_for_oracledbreceiver.yaml index 244ee502c33bc..bdf9d74224070 100644 --- a/.chloggen/service_instance_id_for_oracledbreceiver.yaml +++ b/.chloggen/service_instance_id_for_oracledbreceiver.yaml @@ -17,7 +17,7 @@ issues: [42402] # Use pipe (|) for multiline entries. subtext: | The `service.instance.id` attribute is added in the format `:/` to uniquely identify - Oracle db hosts. + Oracle DB hosts. This resource attribute is enabled by default for metrics and logs. # 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 38f13d050f7fa75e53c8b482151cce83004c86ef Mon Sep 17 00:00:00 2001 From: Sreenath Date: Mon, 29 Sep 2025 11:43:40 +0100 Subject: [PATCH 47/51] Update .chloggen/service_instance_id_for_oracledbreceiver.yaml Co-authored-by: Curtis Robert --- .chloggen/service_instance_id_for_oracledbreceiver.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.chloggen/service_instance_id_for_oracledbreceiver.yaml b/.chloggen/service_instance_id_for_oracledbreceiver.yaml index bdf9d74224070..330279cc7da6c 100644 --- a/.chloggen/service_instance_id_for_oracledbreceiver.yaml +++ b/.chloggen/service_instance_id_for_oracledbreceiver.yaml @@ -7,7 +7,7 @@ change_type: enhancement component: oracledbreceiver # A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). -note: service.instance.id attribute is added in resourceAttributes of all metrics and logs in oracledbreceiver +note: Add `service.instance.id` resource attribute # Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. issues: [42402] From 9882a9d3590e65211cf5cdf775f12ba96fd1886f Mon Sep 17 00:00:00 2001 From: Sreenath Date: Mon, 29 Sep 2025 11:43:57 +0100 Subject: [PATCH 48/51] Update .chloggen/service_instance_id_for_oracledbreceiver.yaml Co-authored-by: Curtis Robert --- .chloggen/service_instance_id_for_oracledbreceiver.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.chloggen/service_instance_id_for_oracledbreceiver.yaml b/.chloggen/service_instance_id_for_oracledbreceiver.yaml index 330279cc7da6c..c760329dd34aa 100644 --- a/.chloggen/service_instance_id_for_oracledbreceiver.yaml +++ b/.chloggen/service_instance_id_for_oracledbreceiver.yaml @@ -16,7 +16,7 @@ issues: [42402] # These lines will be padded with 2 spaces and then inserted directly into the document. # Use pipe (|) for multiline entries. subtext: | - The `service.instance.id` attribute is added in the format `:/` to uniquely identify + The `service.instance.id` resource attribute is added in the format `:/` to uniquely identify Oracle DB hosts. This resource attribute is enabled by default for metrics and logs. # If your change doesn't affect end users or the exported elements of any package, From 4dbf6becaeb674abcc4a1521dff32713ee6cd2a5 Mon Sep 17 00:00:00 2001 From: Sreenath Date: Mon, 29 Sep 2025 11:44:37 +0100 Subject: [PATCH 49/51] Update receiver/oracledbreceiver/scraper.go Co-authored-by: Curtis Robert --- receiver/oracledbreceiver/scraper.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index be808ef1c3aa4..4a78d7f1a494b 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -839,7 +839,7 @@ func (s *oracleScraper) setupResourceBuilder(rb *metadata.ResourceBuilder) *meta func getInstanceID(instanceString string, logger *zap.Logger) string { hostAndPort, service, found := strings.Cut(instanceString, "/") if !found { - logger.Info("No serviceName found in the connection string", zap.String("instanceString", instanceString)) + logger.Info("No service name found in the connection string", zap.String("instanceString", instanceString)) } host, port, err := net.SplitHostPort(hostAndPort) From 81e69e34877d767840ba7f575586162a8ff45586 Mon Sep 17 00:00:00 2001 From: sreenathv Date: Mon, 29 Sep 2025 11:46:57 +0100 Subject: [PATCH 50/51] Updating tests - Adding test value for service.instance.id --- receiver/oracledbreceiver/scraper_test.go | 7 +++++-- .../testdata/expectedQueryTextAndPlanQuery.yaml | 10 +++++----- .../oracledbreceiver/testdata/expectedSamplesFile.yaml | 6 +++--- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/receiver/oracledbreceiver/scraper_test.go b/receiver/oracledbreceiver/scraper_test.go index 6b23a3aac28de..4300a1fc512f0 100644 --- a/receiver/oracledbreceiver/scraper_test.go +++ b/receiver/oracledbreceiver/scraper_test.go @@ -277,9 +277,10 @@ func TestScraper_ScrapeTopNLogs(t *testing.T) { logsBuilderConfig: metadata.DefaultLogsBuilderConfig(), metricCache: lruCache, topQueryCollectCfg: TopQueryCollection{MaxQuerySampleCount: 5000, TopQueryCount: 200}, - instanceName: "oracle-instance-sample-1", - hostName: "oracle-host-sample-1", + instanceName: "oraclehost:1521/ORCL", + hostName: "oraclehost:1521", obfuscator: newObfuscator(), + serviceInstanceID: getInstanceID("oraclehost:1521/ORCL", zap.NewNop()), } scrpr.logsBuilderConfig.Events.DbServerTopQuery.Enabled = true @@ -364,6 +365,8 @@ func TestSamplesQuery(t *testing.T) { lb: metadata.NewLogsBuilder(logsCfg, receivertest.NewNopSettings(metadata.Type)), logsBuilderConfig: metadata.DefaultLogsBuilderConfig(), obfuscator: newObfuscator(), + instanceName: "oraclehost:1521/ORCL", + serviceInstanceID: getInstanceID("oraclehost:1521/ORCL", zap.NewNop()), } scrpr.logsBuilderConfig.Events.DbServerTopQuery.Enabled = false scrpr.logsBuilderConfig.Events.DbServerQuerySample.Enabled = true diff --git a/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml b/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml index caceca578dc74..b98e017159b59 100644 --- a/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml +++ b/receiver/oracledbreceiver/testdata/expectedQueryTextAndPlanQuery.yaml @@ -3,13 +3,13 @@ resourceLogs: attributes: - key: oracledb.instance.name value: - stringValue: oracle-instance-sample-1 + stringValue: oraclehost:1521/ORCL - key: host.name value: - stringValue: oracle-host-sample-1 + stringValue: oraclehost:1521 - key: service.instance.id value: - stringValue: "" + stringValue: oraclehost:1521/ORCL scopeLogs: - logRecords: - attributes: @@ -18,7 +18,7 @@ resourceLogs: stringValue: oracle - key: db.server.name value: - stringValue: oracle-host-sample-1 + stringValue: oraclehost:1521 - key: db.query.text value: stringValue: SELECT COUNT ( * ) FROM ADMIN. Employee e JOIN ADMIN. Person p ON e. BusinessEntityID = ? JOIN ADMIN. EmployeePayHistory eph ON e. BusinessEntityID = eph. BusinessEntityID WHERE eph. Rate > ( SELECT AVG ( Rate ) FROM ADMIN. EmployeePayHistory ) @@ -84,7 +84,7 @@ resourceLogs: doubleValue: 2e-05 body: {} eventName: db.server.top_query - timeUnixNano: "1758608906406938000" + timeUnixNano: "1759142512777891000" scope: name: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/oracledbreceiver version: latest diff --git a/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml b/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml index 96ae178dd9846..350327bfcb62a 100644 --- a/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml +++ b/receiver/oracledbreceiver/testdata/expectedSamplesFile.yaml @@ -3,13 +3,13 @@ resourceLogs: attributes: - key: oracledb.instance.name value: - stringValue: "" + stringValue: oraclehost:1521/ORCL - key: host.name value: stringValue: "" - key: service.instance.id value: - stringValue: "" + stringValue: oraclehost:1521/ORCL scopeLogs: - logRecords: - attributes: @@ -94,7 +94,7 @@ resourceLogs: body: {} eventName: db.server.query_sample spanId: a7ad6b7169203331 - timeUnixNano: "1758608929036258000" + timeUnixNano: "1759142300369458000" traceId: 0af7651916cd43dd8448eb211c80319c scope: name: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/oracledbreceiver From 57d25ee39d1fdea475dfececa8963a69e7d05def Mon Sep 17 00:00:00 2001 From: sreenathv Date: Mon, 29 Sep 2025 22:26:52 +0100 Subject: [PATCH 51/51] Update method constructInstanceID() --- receiver/oracledbreceiver/scraper.go | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/receiver/oracledbreceiver/scraper.go b/receiver/oracledbreceiver/scraper.go index 4a78d7f1a494b..6ef450cbb7376 100644 --- a/receiver/oracledbreceiver/scraper.go +++ b/receiver/oracledbreceiver/scraper.go @@ -850,20 +850,27 @@ func getInstanceID(instanceString string, logger *zap.Logger) string { // Replace the host value with machine name if connecting to localhost target if strings.EqualFold(host, "localhost") || net.ParseIP(host).IsLoopback() { - host, err = os.Hostname() + localhost, err := os.Hostname() if err != nil { - logger.Warn("Error getting localhost machine name for generating service.instance.id.") + logger.Warn("Failed getting localhost machine name for the service.instance.id.") + } else { + host = localhost } } return constructInstanceID(host, port, service) } -func constructInstanceID(host, port, service string) (id string) { +func constructInstanceID(host, port, service string) string { + if strings.TrimSpace(host) == "" { + host = "unknown" + } + if strings.TrimSpace(port) == "" { + port = "1521" + } + if service != "" { - id = fmt.Sprintf("%s:%s/%s", host, port, service) - } else { - id = fmt.Sprintf("%s:%s", host, port) + return fmt.Sprintf("%s:%s/%s", host, port, service) } - return + return fmt.Sprintf("%s:%s", host, port) }