Class McpMetrics
Why the generator has to tell it which database object a tool touches
At run time the server knows only the tool NAME — a lower-cased, punctuation-stripped form of
an Oracle name, with an overload number appended where one was needed. Going back from that to
APPSCHEMA.FIXTURE_PKG.GREET is not possible, and one Oracle object routinely yields several
tools (a table yields at least four). The generator is the only place that holds the mapping, so
it bakes it in through describe(java.lang.String, java.lang.String, java.lang.String) at start-up and every series carries the object as a
label. That is what makes sum by (db_object) work in a query.
What is measured, and over what window
Counts and byte totals are cumulative since start-up, which is what a Prometheus counter must be. The quantiles are over the last 2048 calls to that tool, computed exactly from a ring of retained samples rather than estimated — the same windowed spirit as a Prometheus summary, and the reason they are useful at all: a p90 over all of history stops moving after a day and stops answering "is it slow now?".
The maximum is deliberately NOT windowed. A windowed max silently discards the worst call the server ever served, which is the one an operator is looking for.
Cost
record(java.lang.String, java.lang.String, long, long, long) takes one uncontended lock per tool and writes a handful of longs. It sits
behind a database round trip, so it is noise. Nothing here is emitted unless the config sets
PROMETHEUS_SERVER=YES, so a server that does not want metrics does not pay for the
argument serialisation the byte counters need either.
Copyright 2003-2026 ATB Consultancy Services Ltd
(formerly Orinda Software Ltd, Dublin, Ireland)
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final StringOverrides the baked-in config name on every series.static final StringOverrides the detected host name on every series.static final Stringdescribe(java.lang.String, java.lang.String, java.lang.String)d object type for a tool nothing described.static final StringUsed for a call whose tool name was null or blank, so a bad request is still counted.static final intHow many recent latencies are retained per tool for the quantile calculation. -
Method Summary
Modifier and TypeMethodDescriptionvoidbindAuditSink(McpAuditSink theSinkValue) Report the audit sink, so a scrape carries the one number that says whether the trail can be relied on: how many records have been LOST.voidbindPool(DaoFactoryPool<?> thePoolValue) Report the connection pool, so a scrape carries its counters too.voidRecord which database object a tool reaches.static McpMetricsCreate the registry for one generated server.static McpMetricsAsforServer(String), naming the config this server was generated from.voidrecord(String theToolNameValue, String theOutcomeValue, long theDurationMicros, long theRequestBytes, long theResponseBytes) Record one completed tool call.scrape()The whole registry in Prometheus text exposition format (version 0.0.4).
-
Field Details
-
WINDOW
public static final int WINDOWHow many recent latencies are retained per tool for the quantile calculation.- See Also:
-
UNKNOWN_TOOL
Used for a call whose tool name was null or blank, so a bad request is still counted.- See Also:
-
UNKNOWN_OBJECT_TYPE
describe(java.lang.String, java.lang.String, java.lang.String)d object type for a tool nothing described.- See Also:
-
HOST_LABEL_VARIABLE
Overrides the detected host name on every series.- See Also:
-
CONFIG_LABEL_VARIABLE
Overrides the baked-in config name on every series.- See Also:
-
-
Method Details
-
forServer
Create the registry for one generated server.- Parameters:
theServerNameValue- the server class name, reported as theserverlabel so a scrape of several servers on one host can tell them apart
-
forServer
AsforServer(String), naming the config this server was generated from.- Parameters:
theConfigNameValue- the generation-time identity, typically the emitted package name.MCP_METRICS_CONFIG_LABELoverrides it at run time, which is how the web runtime substitutes the config's own name.
-
describe
Record which database object a tool reaches. Called once per tool at start-up, from a static initialiser the generator writes.Describing a tool does not make it appear in a scrape: a tool that has never been called has no series, which is correct — Prometheus counters should not be born at zero for thousands of tools that may never be used.
- Parameters:
theToolNameValue- the MCP tool name, as it appears intools/listtheDbObjectValue- the fully-qualified Oracle object, e.g.APPSCHEMA.FIXTURE_PKG.GREETtheObjectTypeValue-table,view,procedure,sequence,statement— what kind of thing the object is
-
bindPool
Report the connection pool, so a scrape carries its counters too.These are the numbers the
POOL-STATSlog line has always held. They were only ever recoverable by tailing a log file and parsing it, which is a poor channel for something a monitoring system wants every fifteen seconds.- Parameters:
thePoolValue- the pool, or null for an unpooled server
-
bindAuditSink
Report the audit sink, so a scrape carries the one number that says whether the trail can be relied on: how many records have been LOST.This is the metric worth alerting on. Everything else here describes how the server is performing; a non-zero drop count says the record of what it did is incomplete, and nothing else in the system will mention it — the sink counts and logs, and a log line is not something anyone watches for.
- Parameters:
theSinkValue- the sink in use, or null when the server is unaudited
-
record
public void record(String theToolNameValue, String theOutcomeValue, long theDurationMicros, long theRequestBytes, long theResponseBytes) Record one completed tool call. Called from the generatedcall(...)funnel'sfinally, so failures are measured as well as successes.- Parameters:
theToolNameValue- the tool that ran; null or blank is counted asUNKNOWN_TOOLtheOutcomeValue- one of theMcpCallRecordOUTCOME_constantstheDurationMicros- elapsed duration of the call in MICROSECONDS, and it must come fromSystem.nanoTime()rather than a wall clock — at a few milliseconds a call,currentTimeMilliscannot resolve the measurement and an NTP step can make it run backwardstheRequestBytes- size of the call's arguments as JSON, or 0 when there were nonetheResponseBytes- size of the response payload, or 0 when the call produced none
-
scrape
The whole registry in Prometheus text exposition format (version 0.0.4).Deterministically ordered — tools by name, outcomes by name — so a diff of two scrapes is readable and the tests can assert on whole blocks rather than fishing for lines.
-