# MetricMapping

Source: /reference/metricmappings/

How one component's metrics become part of the modelplane_* surface. Modelplane renders every MetricMapping into each inference cluster's collector, so a mapping is written once on the control plane and reaches the whole fleet.
A mapping naming a component Modelplane already provides renames for is additive: its renames run after the built-in ones, and a later rename of the same metric wins.

Apply instances as `apiVersion: modelplane.ai/v1alpha1`, `kind: MetricMapping`.

[Concept guide: Monitor the Fleet](/platform/telemetry/index.md)

## Definition

The CompositeResourceDefinition this reference is generated from, with the complete OpenAPI schema, validation rules, and defaults:

```yaml
apiVersion: apiextensions.crossplane.io/v2
kind: CompositeResourceDefinition
metadata:
  name: metricmappings.modelplane.ai
spec:
  group: modelplane.ai
  names:
    categories: [crossplane, modelplane, platform]
    kind: MetricMapping
    plural: metricmappings
    shortNames: [mm]
  scope: Cluster
  versions:
  - name: v1alpha1
    served: true
    referenceable: true
    additionalPrinterColumns:
    - name: CLUSTERS
      type: integer
      jsonPath: .status.clusters
    - name: AGE
      type: date
      jsonPath: .metadata.creationTimestamp
    schema:
      openAPIV3Schema:
        type: object
        required: [spec]
        properties:
          spec:
            type: object
            required: [metrics]
            description: >-
              How one component's metrics become part of the modelplane_*
              surface. Modelplane renders every MetricMapping into each
              inference cluster's collector, so a mapping is written once on
              the control plane and reaches the whole fleet.

              A mapping naming a component Modelplane already provides
              renames for is additive: its renames run after the built-in
              ones, and a later rename of the same metric wins.
            properties:
              metrics:
                type: array
                minItems: 1
                maxItems: 128
                description: >-
                  The metrics this component emits, and what Modelplane calls
                  them.

                  Rename only where the measurements agree. Two engines'
                  histograms sharing a name are worth less than nothing if
                  their buckets disagree, because a quantile across them is
                  wrong rather than approximate.
                items:
                  type: object
                  required: [from, to, acrossReplicas]
                  properties:
                    from:
                      type: string
                      maxLength: 255
                      pattern: '^[a-zA-Z_:][a-zA-Z0-9_:]*$'
                      description: >-
                        The metric's name as the component emits it, matched
                        exactly. Nothing here declares which engine a
                        deployment runs: a name that no component emits simply
                        matches nothing.

                        Held to the characters a metric name can contain. The
                        name is matched inside the collector's own query
                        language, so a quote here would end the comparison
                        early and rename whatever the rest of the line
                        matched.
                    to:
                      type: string
                      maxLength: 255
                      pattern: '^modelplane_[a-z0-9_]*[a-z0-9]$'
                      description: >-
                        What Modelplane calls it. Only modelplane_* leaves a
                        cluster, so a metric with no name here is one nobody
                        downstream can read.
                    acrossReplicas:
                      type: string
                      enum: [Sum, Mean, Max]
                      description: >-
                        How this metric combines over a deployment's replicas.

                        Every pod publishes its own series, told apart by the
                        replica it belongs to and the instance it was scraped
                        from, and a query over a deployment combines them. This says which combination is the right
                        one: Sum for anything counted - requests, tokens,
                        joules, a queue's depth. Mean for a ratio, where
                        summing reads two replicas at half capacity as one at
                        full. Max for a saturation figure an alert fires on,
                        where a mean hides the replica in trouble.

                        Modelplane does not combine them in the collector. A
                        scrape of one replica is one batch, so a collector that
                        added them up would be adding readings taken at
                        different moments, and two readings of one cumulative
                        counter sum to twice the traffic that happened. The
                        backend holds every replica's series and combines them
                        at query time, where the arithmetic is right.

                        Required, with no default, because the wrong
                        combination is silent: a deployment reports a number
                        that looks entirely plausible.
                    part:
                      type: string
                      enum: [Count, Sum]
                      description: >-
                        Take a part of a histogram as a counter of its own,
                        rather than the histogram itself. Count is how many
                        observations it holds, which is a request count where
                        the histogram measures request duration. Sum is their
                        total.

                        The histogram carries on unchanged under its own name.
                        This adds a series beside it.
                    labels:
                      type: array
                      maxItems: 16
                      description: >-
                        Labels to set on the series, for folding several
                        metrics into one that a label tells apart - tokens in
                        and out under one name with a direction, responses
                        under one name with the reason they ended.

                        Two mappings writing the same `to` with a different
                        fixed value is how the fold is expressed: each renames
                        its own source and stamps its own value.
                      items:
                        type: object
                        required: [name]
                        x-kubernetes-validations:
                        - rule: "has(self.value) != has(self.from)"
                          message: set either value, for a fixed label, or from, to carry one the component already emits.
                        properties:
                          name:
                            type: string
                            maxLength: 63
                            pattern: '^[a-zA-Z_][a-zA-Z0-9_]*$'
                            description: The label to set.
                          value:
                            type: string
                            maxLength: 253
                            description: >-
                              A fixed value, the same on every series this
                              mapping produces. This is what tells two folded
                              metrics apart.
                          from:
                            type: string
                            maxLength: 63
                            pattern: '^[a-zA-Z_][a-zA-Z0-9_]*$'
                            description: >-
                              A label the component already emits, carried onto
                              the new name and dropped from the series under
                              its old one.
                          values:
                            type: object
                            maxProperties: 32
                            additionalProperties:
                              type: string
                              maxLength: 253
                            description: >-
                              What each of that label's values becomes, for
                              putting an engine's own vocabulary into
                              Modelplane's. A value with no entry here is left
                              as the component wrote it.

                              Only meaningful alongside `from`.
                    fromUnit:
                      type: string
                      enum: [Millijoules, Mebibytes, Milliseconds, Nanoseconds]
                      description: >-
                        What the component measures this in, when that isn't
                        the unit the name claims. Modelplane converts to the
                        base unit: millijoules and milliseconds are divided by
                        a thousand, nanoseconds by a billion, and mebibytes
                        multiplied out to bytes.

                        Say it whenever the source disagrees with the target,
                        even where the factor looks obvious. A name ending in
                        _bytes that holds mebibytes is the kind of thing
                        nobody notices until a capacity review, and stating
                        the source unit is what makes the conversion happen at
                        all.
          status:
            type: object
            properties:
              clusters:
                type: integer
                description: >-
                  How many inference clusters have taken these statements.
              conditions:
                type: array
                items:
                  type: object
```
