Skip to content

Metrics API

API reference for the metrics subsystem: the service/emitter type and its methods, the MetricBuilder, the Metric and Measure value types, the target abstraction with its concrete target names, and the dimension-cap constant. Signatures below are taken from source and reflect each SDK’s exact names.

For conceptual explanation — how a target is chosen, the Prometheus pull lifecycle, the durable CloudWatch buffer, and EMF timestamp units — see the Metrics guide. This page is the signature reference.

The accessor name and the returned type differ per language.

// getMetrics() returns a MetricEmitter instance.
MetricEmitter metrics = gg.getMetrics();

The type names map across SDKs as follows: Java MetricEmitter (concrete class), Python MetricEmitter (returned as the class, static methods), Rust MetricService trait behind Arc<dyn MetricService>, TypeScript MetricService interface (the concrete impl is also named MetricEmitter).

The emitting surface. defineMetric registers a metric definition by name; emitMetric records measure values through the target’s buffer; emitMetricNow bypasses batching and delivers immediately; isMetricDefined reports whether a name is registered; flush/shutdown drain and release the target.

The measure-value container type is language-specific: Map<String, Float> (Java — note Float, not double), a dict of str -> float (Python), HashMap<String, f64> (Rust), and Record<string, number> (TypeScript, aliased as MeasureValues).

void defineMetric(Metric metric);
boolean isMetricDefined(String name);
void emitMetric(String name, Map<String, Float> measureValues); // buffered
void emitMetricNow(String name, Map<String, Float> measureValues); // immediate
void flushMetrics(); // force-drain the buffer
void close(); // release the target on shutdown (call flushMetrics() first to drain)
MetricConfiguration getMetricConfig();
String getThingName();
String getComponentName();

Defines a metric: a name, one or more measures (each with a unit and a storage resolution), and optional dimensions. withConfig/with_config populates identity fields from the active config. Storage resolution is 1 (high resolution, 1-second) or 60 (standard, 1-minute).

static MetricBuilder create(String name);
MetricBuilder withNamespace(String namespace);
MetricBuilder withThingName(String thingName); // -> coreName dimension
MetricBuilder withComponentName(String componentName); // -> component dimension
MetricBuilder withConfig(ConfigManager config); // fills thing + component + namespace
MetricBuilder addMeasure(String name, String unit, int storageResolution);
MetricBuilder addMeasure(Measure measure);
MetricBuilder addDimension(String key, String value); // throws if > 10 dimensions
Metric build(); // throws IllegalStateException if namespace unset / no measures
Metric build(MetricEmitter emitter); // fills namespace/thing/component from the emitter

These differences are load-bearing — they change what valid code looks like per language:

  • withConfig and namespace. Java, Rust, and TypeScript fill thing + component + namespace. Python with_config fills thing + component only — set with_namespace(...) yourself or build() substitutes GGCommons/Metrics.
  • Storage resolution. Java, Rust, and TypeScript silently coerce (< 60 becomes 1, otherwise 60). Python’s add_measure rejects anything not exactly 1 or 60 with a ValueError. (The Measure value object still coerces if constructed directly — see below.)
  • build() overloads. Java has both build() (requires namespace, else throws) and build(MetricEmitter). Python, Rust, and TypeScript have a single build().
  • Dimension-cap behavior. Java, Python, and TypeScript throw when more than 10 dimensions are present; Rust trims the excess custom dimensions and logs a tracing::warn! (its build() is infallible).
  • Empty dimension value. Python raises ValueError for an empty value; Java, Rust, and TypeScript accept it.

A Measure is a named value type within a metric (its name, unit, and storageResolution). The Measure value object itself coerces storage resolution to 1 or 60 (< 60 becomes 1) in every language.

// record Measure(String name, String unit, int storageResolution)
Measure(String name, String unit, int storageResolution); // coerces: storageResolution < 60 ? 1 : 60
Measure(String name, String unit); // convenience — defaults to 60
String name();
String unit();
int storageResolution();

A Metric is what MetricBuilder.build() returns and what defineMetric registers. You normally build it rather than construct it directly. Its read accessors:

String getName();
String getNamespace();
Map<String, Measure> getMeasures();
Measure getMeasure(String name);
Map<String, String> getDimensions();
void addMeasure(...); // adds (or replaces) a measure
void addDimension(String key, String value); // enforces the 10-dimension cap

Three dimensions are injected automatically at build() time (they count toward the 10-dimension cap):

Dimension Value Source
category the metric’s name set by the Metric constructor
coreName the IoT Thing name from withThingName / config
component the component name from withComponentName / config
Constant Value Meaning
MAX_DIMENSIONS 10 CloudWatch’s per-metric dimension cap (incl. the 3 injected).
Prometheus port 9090 Default listener port for the prometheus target.
Prometheus path /metrics Default scrape path for the prometheus target.

MAX_DIMENSIONS is exposed as a named public constant only in Python (Metric.MAX_DIMENSIONS) and TypeScript (Metric.MAX_DIMENSIONS). In Java the cap is a hard-coded literal 10 in Metric.addDimension and MetricBuilder.addDimension; in Rust it is a module-private const MAX_DIMENSIONS: usize = 10 (not part of the public API). The value is 10 in all four.

A target is the destination metrics are written to. Each SDK has a target abstraction that the concrete targets implement; the active target is selected by config (metricEmission.target) and the three-tier precedence described in the Metrics guide.

The abstraction:

// abstract class MetricTarget
abstract void emitMetric(Metric metric, Map<String, Float> measureValues);
abstract void emitMetricNow(Metric metric, Map<String, Float> measureValues);
abstract boolean onConfigurationChanged();
void flush(); // default no-op
void close(); // default no-op

The selectable metricEmission.target values, and the source file that implements each:

target value Java Python Rust (feature) TypeScript
log Log.java metric_log.py target/log.rs target/log.ts
messaging Messaging.java messaging.py target/messaging.rs target/messaging.ts
cloudwatch CloudWatch.java cloudwatch.py target/cloudwatch.rs (cloudwatch) target/cloudwatch.ts
cloudwatchcomponent CloudWatchComponent.java cloudwatch_component.py target/cloudwatch_component.rs target/cloudwatch_component.ts
prometheus Prometheus.java prometheus.py target/prometheus.rs (metrics-prometheus) target/prometheus.ts

A complete define-then-emit cycle in all four languages.

MetricEmitter metrics = gg.getMetrics();
metrics.defineMetric(
MetricBuilder.create("performance")
.withConfig(config) // fills thing / component / namespace
.addMeasure("replyLatency", "Milliseconds", 1)
.build());
Map<String, Float> values = new HashMap<>();
values.put("replyLatency", 12.5f); // Map<String, Float>
metrics.emitMetric("performance", values); // buffered