[receiver/oracledb] Add session, JVM, and OS resource metrics - #49068
Conversation
Surfaces session non-idle activity, in-database JVM (OJVM) call-heap, and OS CPU/swap statistics already returned by the existing system-statistics query as seven opt-in metrics. No new SQL queries are introduced.
c03749c to
92912db
Compare
| oracledb.os.cpu.state: | ||
| description: Whether the OS CPU time was consumed in system (kernel) or user mode, as accounted by Oracle. Mirrors the semconv system.cpu.state value set. | ||
| type: string | ||
| enum: [system, user] |
There was a problem hiding this comment.
| oracledb.os.cpu.state: | |
| description: Whether the OS CPU time was consumed in system (kernel) or user mode, as accounted by Oracle. Mirrors the semconv system.cpu.state value set. | |
| type: string | |
| enum: [system, user] | |
| cpu.mode: | |
| description: The mode of the CPU | |
| type: string | |
| enum: [system, user] |
As per https://opentelemetry.io/docs/specs/semconv/registry/attributes/cpu/#cpu-mode
There was a problem hiding this comment.
Good call — switched to the semconv cpu.mode attribute and dropped the custom oracledb.os.cpu.state.
| oracledb.java.heap.state: | ||
| description: Which portion of the in-database JVM call heap the measurement reports (live, total, or used). | ||
| type: string | ||
| enum: [live, total, used] |
There was a problem hiding this comment.
| oracledb.java.heap.state: | |
| description: Which portion of the in-database JVM call heap the measurement reports (live, total, or used). | |
| type: string | |
| enum: [live, total, used] |
There was a problem hiding this comment.
Removed — it's no longer needed now that the heap metric is split
| oracledb.java.heap.usage: | ||
| attributes: | ||
| - oracledb.java.heap.state | ||
| description: Size of Oracle's in-database JVM (OJVM) call heap in bytes. Sourced from v$sysstat names java call heap live size (oracledb.java.heap.state=live), java call heap total size (oracledb.java.heap.state=total), and java call heap used size (oracledb.java.heap.state=used). | ||
| enabled: false | ||
| stability: development | ||
| gauge: | ||
| value_type: int | ||
| input_type: string | ||
| unit: By |
There was a problem hiding this comment.
Let's have dedicated metrics for the states and in fact couldn't we just use https://opentelemetry.io/docs/specs/semconv/runtime/jvm-metrics/#jvm-memory for 2 of them & the third use case?
There was a problem hiding this comment.
Split into three dedicated gauges: oracledb.java.heap.used and oracledb.java.heap.committed mirror jvm.memory.used / jvm.memory.committed; oracledb.java.heap.live (live-object size) has no semconv equivalent. I kept the oracledb. namespace rather than emitting bare jvm.memory.* because this is Oracle's embedded OJVM call heap read from v$sysstat, not a standard JVM runtime — emitting jvm.memory.* from the DB receiver would collide with real JVM instrumentation in the same pipeline. Happy to switch to the literal names if you prefer.
There was a problem hiding this comment.
Hmmm, i still feel we can be closer aligned in naming even when keeping it under the oracledb namespace.
Options would be:
- oracledb.memory.used etc
- oracledb.jvm.memory.used etc
I like the first as don't see jvm being necessary in name.
There was a problem hiding this comment.
Renamed to oracledb.jvm.memory.used/committed/live to align the leaves with semconv jvm.memory.*. I kept jvm in the path rather than oracledb.memory.* because the latter reads as Oracle's overall memory (SGA/PGA) and would clash with the in-flight SGA work (#48542) — jvm scopes it unambiguously to the embedded OJVM. Happy to drop jvm if you still prefer.
| oracledb.os.cpu.time: | ||
| attributes: | ||
| - oracledb.os.cpu.state | ||
| description: Cumulative OS CPU time consumed, in seconds (converted from centiseconds), as accounted by Oracle. Sourced from v$sysstat names OS System time used (oracledb.os.cpu.state=system) and OS User time used (oracledb.os.cpu.state=user). | ||
| enabled: false | ||
| stability: development | ||
| sum: | ||
| aggregation_temporality: cumulative | ||
| monotonic: true | ||
| value_type: double | ||
| unit: s |
There was a problem hiding this comment.
How does this differ to jvm.cpu.time?
There was a problem hiding this comment.
They're unrelated. oracledb.os.cpu.time is OS-level CPU time (kernel + user) consumed by the Oracle server/background processes, as Oracle accounts it in v$sysstat (OS System/User time used, getrusage-derived) — not a JVM's CPU. Even vs system.cpu.time (hostmetrics), this is Oracle's per-instance self-accounting that DBAs correlate with DB workload and that differs from host totals in containers/VMs.
There was a problem hiding this comment.
In that case what about process.cpu.time aka https://opentelemetry.io/docs/specs/semconv/system/process-metrics/#metric-processcputime
There was a problem hiding this comment.
Renamed to oracledb.process.cpu.time to match semconv process.cpu.time; it keeps the cpu.mode attribute. The description notes it's Oracle's own process accounting from v$sysstat
There was a problem hiding this comment.
"Following up on this — I've removed oracledb.process.cpu.time (and the cpu.mode attribute) rather than keep it. It was sourced from the v$sysstat stats OS System time used / OS User time used, which I found during integration testing read 0 on Oracle 19c even under sustained CPU load. They're gated by timed_os_statistics (off by default, documented as 'very expensive'), are never populated on Windows, and can't be enabled on Amazon RDS. The reliable OS-CPU split lives in V$OSSTAT (USER_TIME/SYS_TIME) — a different view that's the domain of #48459 — so it shouldn't be surfaced from these always-zero v$sysstat statistics. PR is now 7 metrics.
| oracledb.process.last_non_idle.time: | ||
| description: Epoch time in seconds at which the process was last active (non-idle), as reported by Oracle. Sourced from v$sysstat name process last non-idle time. | ||
| enabled: false | ||
| stability: development | ||
| gauge: | ||
| value_type: int | ||
| input_type: string | ||
| unit: s |
There was a problem hiding this comment.
Not following on this use case. Wouldn't it be more useful to capture how long it has been idle for? Perhaps even have a status metric to capture if it is idle or active.
There was a problem hiding this comment.
Dropped it. The intent was a coarse liveness signal (if the last-non-idle epoch stops advancing, processes are stuck), but you're right a raw epoch gauge is awkward and a useful idle-duration would need now − value math in the scraper, which the project discourages. Removed from this PR.
| oracledb.session.non_idle.time: | ||
| description: Cumulative time sessions spent in non-idle waits, in seconds (converted from centiseconds). Sourced from v$sysstat name non-idle wait time. | ||
| enabled: false | ||
| stability: development | ||
| sum: | ||
| aggregation_temporality: cumulative | ||
| monotonic: true | ||
| value_type: double | ||
| unit: s | ||
| oracledb.session.non_idle.waits: | ||
| description: Cumulative number of non-idle waits across sessions. Sourced from v$sysstat name non-idle wait count. | ||
| enabled: false | ||
| stability: development | ||
| sum: | ||
| aggregation_temporality: cumulative | ||
| monotonic: true | ||
| value_type: int | ||
| input_type: string | ||
| unit: "{waits}" |
There was a problem hiding this comment.
Do we really need non_idle in the name couldn't we remove it & for the first metric have a state attribute to indicate non_idle
There was a problem hiding this comment.
Renamed to oracledb.session.waits / oracledb.session.wait.time, with 'non-idle' kept in the descriptions. I didn't add a state attribute because v$sysstat only exposes the non-idle counters (no symmetric idle count/time), so it'd be single-valued — but I'm happy to add it for future extensibility if you'd rather.
There was a problem hiding this comment.
Let's add it as an attribute for future extensibility and making the definition clear.
There was a problem hiding this comment.
Added the oracledb.session.wait.state attribute (value non_idle) to both metrics — documents the non-idle semantics and leaves room for an idle value if Oracle ever exposes that counter.
…sion wait state
- Rename java.heap.* to oracledb.jvm.memory.{used,committed,live}
- Rename os.cpu.time to oracledb.process.cpu.time (keeps cpu.mode)
- Add oracledb.session.wait.state (non_idle) to session waits/wait time
# Conflicts: # receiver/oracledbreceiver/internal/metadata/generated_metrics_test.go
…OS CPU stats are always 0) OS System/User time used require timed_os_statistics (off by default, expensive, unsettable on RDS, absent on Windows) and read 0 even under load on 19c/Linux. DB CPU is already covered by oracledb.cpu_time; host CPU is V$OSSTAT (open-telemetry#48459).
…riptions, simpler tests
…on-jvm-os # Conflicts: # receiver/oracledbreceiver/documentation.md # receiver/oracledbreceiver/internal/metadata/config.schema.yaml # receiver/oracledbreceiver/internal/metadata/generated_config.go # receiver/oracledbreceiver/internal/metadata/generated_config_test.go # receiver/oracledbreceiver/internal/metadata/generated_metrics.go # receiver/oracledbreceiver/internal/metadata/generated_metrics_test.go # receiver/oracledbreceiver/internal/metadata/testdata/config.yaml # receiver/oracledbreceiver/metadata.yaml # receiver/oracledbreceiver/scraper.go # receiver/oracledbreceiver/scraper_test.go
| component: receiver/oracledb | ||
|
|
||
| # A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). | ||
| note: Add session, in-database JVM, and OS resource metrics sourced from the existing v$sysstat query. |
There was a problem hiding this comment.
| note: Add session, in-database JVM, and OS resource metrics sourced from the existing v$sysstat query. | |
| note: Add session, in-database JVM, and OS resource metrics |
The subtext provides enough context for the end user
There was a problem hiding this comment.
Please remove all unit references from metric descriptions. It will be clear enough from unit in the generated documentation.
There was a problem hiding this comment.
Done — removed all unit references
| input_type: string | ||
| unit: "{row}" | ||
| oracledb.session.stored_procedure.usage: | ||
| description: Memory in bytes currently allocated for stored procedures in the session. |
There was a problem hiding this comment.
The description states this is memory, but the name has no memory reference. We should either add memory in the name or clarify.
There was a problem hiding this comment.
Agreed — the name didn't convey memory. Renamed to oracledb.session.stored_procedure.memory (Gauge, By) so the metric name itself signals memory.
| oracledb.session.wait.time: | ||
| attributes: | ||
| - oracledb.session.wait.state | ||
| description: Cumulative time sessions spent in non-idle waits, in seconds. |
There was a problem hiding this comment.
The description should be more generic in case of future updates to the metric to account for other attribute values.
There was a problem hiding this comment.
Done — updated the descriptions be generic
| oracledb.session.waits: | ||
| attributes: | ||
| - oracledb.session.wait.state | ||
| description: Cumulative number of non-idle waits across sessions. |
There was a problem hiding this comment.
The description should be more generic in case of future updates to the metric to account for other attribute values.
There was a problem hiding this comment.
Groups of strings/variables should be alphabetized
…ons/scraper Rename oracledb.session.stored_procedure.usage to oracledb.session.stored_procedure.memory so the name signals memory; trim the changelog note, remove unit references from descriptions, make the session-wait descriptions attribute-generic, and alphabetize the added constant/gate/case groups in scraper.go
There was a problem hiding this comment.
File should be updated to have lists in alphabetical order
|
Hi @thompson-tomo, thanks again for the review here. I'm working toward OpenTelemetry org membership and would like to ask if you'd be willing to sponsor my application. My contribution track is focused on |
…on-jvm-os # Conflicts: # receiver/oracledbreceiver/documentation.md # receiver/oracledbreceiver/internal/metadata/generated_config_test.go # receiver/oracledbreceiver/internal/metadata/generated_metrics.go # receiver/oracledbreceiver/metadata.yaml
| } | ||
| // Session, JVM & OS resources | ||
| case javaCallHeapLiveSize: | ||
| if err := s.mb.RecordOracledbJvmMemoryLiveDataPoint(now, row["VALUE"]); err != nil { |
There was a problem hiding this comment.
Can we use the file's colValue constant here? (I know we're just using "VALUE" directly earlier, but may as well start using the constant now)
| @@ -393,6 +401,55 @@ func TestScraper_ScrapeOperationalMetrics(t *testing.T) { | |||
| } | |||
|
|
|||
| // scrapeWithConfig starts a scraper over the shared fake responses and returns one scrape. | |||
There was a problem hiding this comment.
This comment needs to be moved to be kept above the relevant method.
|
This PR has review comments. Review suggestions, whether from maintainers or automated reviewers, aren't always correct or required. Please evaluate each comment on its merits, then make sure each thread has a clear outcome. For example, link to the commit if you applied a suggestion, explain why it wasn't applied, or ask a follow-up question. Automation flags a PR for human review once every review thread has a reply or is marked as resolved. Status across open PRs is visible on the pull request dashboard. |
…on-jvm-os # Conflicts: # receiver/oracledbreceiver/internal/metadata/generated_config_test.go # receiver/oracledbreceiver/scraper_test.go
…on-jvm-os # Conflicts: # receiver/oracledbreceiver/documentation.md # receiver/oracledbreceiver/internal/metadata/config.schema.yaml # receiver/oracledbreceiver/internal/metadata/generated_config.go # receiver/oracledbreceiver/internal/metadata/generated_config_test.go # receiver/oracledbreceiver/internal/metadata/generated_metrics.go # receiver/oracledbreceiver/internal/metadata/generated_metrics_test.go # receiver/oracledbreceiver/internal/metadata/testdata/config.yaml # receiver/oracledbreceiver/metadata.yaml
|
Done — conflicts resolved. |
|
@rluidash please rebase once more |
…on-jvm-os # Conflicts: # receiver/oracledbreceiver/internal/metadata/config.schema.yaml # receiver/oracledbreceiver/internal/metadata/generated_config_test.go # receiver/oracledbreceiver/metadata.yaml # receiver/oracledbreceiver/scraper.go # receiver/oracledbreceiver/scraper_test.go
…edbreceiver (open-telemetry#49068) Brings nroracledbreceiver to metric parity with base oracledbreceiver (93 -> 112) by porting the 19 metrics added upstream in open-telemetry#49068 and related commits: JVM call-heap memory (committed/live/used), OS swaps, non-idle session waits/wait-time, session stored-procedure memory, GC current-block time, recovery blocks, SMON posts, transaction lock time, transaction rollbacks, plus the sysmetric-derived cpu/host-cpu usage rates, cursor/PGA cache utilization, transaction response time, single-block read latency, and average active sessions. Adds the oracledb.session.wait.state and oracledb.smon.type attributes and extends oracledb.session.type to [background, foreground]. Wires the new stat names into the existing v$sysstat switch and the sysmetric names into recordSysmetric; no new query required. NR-specific behavior (per-PDB sysmetric/sysstat, SetOracleDbPdb, session-wait db.namespace) is preserved.
Description
The Oracle DB receiver scrapes
v$sysstatwithSELECT * FROM v$sysstat, which returns all system-statistics rows. However, the scraper only processes a subset of those rows in itsswitchblock and silently discards the rest — including the session-activity, in-database JVM, and OS-resource statistics. This change surfaces 8 discardedv$sysstatstatistics as 7 new opt-in metrics, giving operators visibility into how much real work sessions perform versus idle waiting, Oracle's embedded JVM (OJVM) call-heap pressure, and OS swap activity as the database process accounts for it.This change adds 7 new opt-in metrics (disabled by default, stability: development):
oracledb.session.waits— Cumulative number of non-idle waits across sessions. Attribute:oracledb.session.wait.state(non_idle). Coversv$sysstat:non-idle wait count.oracledb.session.wait.time— Cumulative time, in seconds, sessions spent in non-idle waits. Attribute:oracledb.session.wait.state(non_idle). Coversv$sysstat:non-idle wait time(the raw centisecond value is divided by 100 in the scraper).oracledb.session.stored_procedure.memory— Memory, in bytes, currently allocated for stored procedures in the session. No attributes. Coversv$sysstat:session stored procedure space.oracledb.jvm.memory.used— Used size, in bytes, of Oracle's in-database JVM (OJVM) call heap. No attributes. Coversv$sysstat:java call heap used size. Mirrors semconvjvm.memory.usedfor the embedded OJVM.oracledb.jvm.memory.committed— Committed (total) size, in bytes, of the OJVM call heap. No attributes. Coversv$sysstat:java call heap total size. Mirrors semconvjvm.memory.committed.oracledb.jvm.memory.live— Size, in bytes, of live objects in the OJVM call heap. No attributes. Coversv$sysstat:java call heap live size.oracledb.os.swaps— Number of OS swap operations, as accounted by Oracle. No attributes. Coversv$sysstat:OS Swaps.Types/units:
oracledb.session.waits(Sum int,{wait}),oracledb.session.wait.time(Sum double,s),oracledb.os.swaps(Sum int,{swap}) are cumulative monotonic Sums;oracledb.session.stored_procedure.memoryand the threeoracledb.jvm.memory.*are Gauges (int,By). The one time metric (oracledb.session.wait.time) converts centiseconds → seconds (÷100), matching the existingoracledb.cpu_time.These metrics can be enabled in the collector configuration:
Link to tracking issue
Fixes #49065
Testing
Unit tests added in
scraper_test.go:TestScraper_ScrapeSessionJVMOSMetricsexercises all 7 new metrics end-to-end through the scraper using the existing fake DB client, asserting one expected value per data point (7 data points per scrape across the 7 metrics).queryResponses[statsSQL]fixture is extended with 8 new fakev$sysstatrows (one per covered NAME), soTestScraper_Scrape,TestScraper_ScrapeOperationalMetrics, andTestScraper_ScrapeIOPerformanceMetricscontinue to pass unchanged.non-idle wait timeproduces 45.0 s onoracledb.session.wait.time.internal/metadata/generated_metrics_test.goandgenerated_config_test.goare regenerated bymake generateand cover the new metric configs / metric builders.Documentation
Auto-generated
documentation.mdupdated with descriptions and metadata for the 7 new metrics and the neworacledb.session.wait.stateattribute.internal/metadata/generated_*.goandinternal/metadata/testdata/config.yamlregenerated viamake generate.internal/metadata/config.schema.yamlwas updated for the 7 new metric stanzas, as that file is not produced bymake generate.Authorship