MetricsHub
MetricsHub Community Connectors 1.0.22
-
Home
- Connector Developer Guide Connector Structure 6
Reuse and Configuration
This page covers the connector-level building blocks that let connectors share logic (extends, constants, translations) and let users configure behavior (connector variables, sudo commands).
Load-Time Resolution Order
When a connector is parsed, the engine resolves its building blocks in this order:
extends— parent connectors are merged in${var::name}— connector variables are substituted (defaults or user-configured values)${source::...}and other references are resolved to absolute paths${constant::name}— constants are inlined, then theconstantssection is dropped
All of the above happens once, at load time. Runtime credential macros (%{USERNAME}, %{PASSWORD}, …) are different: they are resolved at execution time, per request — see References and Expressions[1].
extends: Connector Inheritance
A connector can inherit from one or more parent connectors:
extends:
- ../../semconv/Hardware # metric metadata dictionary
- ../MIB2-header/MIB2-header # shared detection + monitors
Paths are resolved relative to the connector's own directory, and .yaml is appended automatically. Parents may themselves extend other connectors (chained inheritance is fully resolved). The extends key is stripped from the compiled connector.
Merge Rules
Parents are merged in list order, then the child is merged last — the child always wins over all parents, and a later parent wins over an earlier one. The merge is a structural deep merge:
| Node kind | Merge behavior |
|---|---|
Objects (maps: monitors, metrics, translations, sources, mapping.attributes, …) |
Deep-merged key by key. Redefining one key overrides that entry only; sibling keys survive. |
Arrays of objects (detection.criteria, computes, …) |
Child items are appended after the parent's items. |
Arrays of scalars (keys, appliesTo, sudoCommands, …) |
Child array replaces the parent's array entirely. |
| Scalars | Child value overrides the parent's. |
Arrays of objects are appended, never replaced: if a parent source defines computes, your child's computes run in addition to the parent's — you cannot remove or reorder inherited criteria or computes, only add after them. If you need a genuinely different pipeline, do not inherit that subtree.
Semconv Connectors
The files under src/main/connector/semconv/ (Hardware, System, Storage, Database) contain only a metrics: map — no detection, no monitors. They are metric metadata dictionaries: unit, description, and instrument type for each standard metric name, aligned with OpenTelemetry semantic conventions.
Extend the relevant one so your metrics automatically carry the official metadata; only declare a local metrics: entry when you introduce a metric the semconv file does not define. See Mapping, Metrics, and Semconv[2].
Header Connectors
When several connectors share the same collection logic (e.g. the same SNMP tables or the same command parsing), factor it into a header connector — a partial connector holding the shared detection.criteria, monitors, and translations, not usable on its own. Each real connector then extends the header and adds only its identity and detection targeting:
# MIB2.yaml
extends:
- ../../semconv/Hardware
- ../MIB2-header/MIB2-header
connector:
displayName: MIB-2 Standard SNMP Agent
platforms: SNMP
detection:
appliesTo: [ Network ]
supersedes: [ ... ]
Headers are best parameterized with constants: the header references ${constant::...} placeholders and each child supplies the values (see below). This is cleaner than overriding inherited sources.
Community examples: MIB2-header[3] with MIB2[4]; LinuxNetwork-header[5] with LinuxIPNetwork[6].
constants
Top-level map of reusable literals, referenced as ${constant::name} anywhere in the connector:
constants:
GLOBAL_COMMAND_LINE: /sbin/ip a
COLLECT_COMMAND_LINE: /sbin/ip -s link show dev ${attribute::id}
Constants are inlined at load time by plain text substitution, and the constants section is then removed from the compiled connector.
The flagship use case is parameterizing a header connector: LinuxNetwork-header runs ${constant::GLOBAL_COMMAND_LINE}, and each child (LinuxIPNetwork with ip, LinuxIfConfigNetwork with ifconfig) supplies its own command through constants.
Constant substitution is a single, non-recursive pass: do not chain constants (a constant referencing another constant) and do not expect ${var::...} inside a constant value to be expanded — variables are resolved before constants.
connector.variables
Variables make a connector user-configurable. Declare them under connector.variables, each with a description and a defaultValue, and reference them as ${var::name} anywhere in the connector or its embedded files:
connector:
displayName: Linux - Processes
variables:
matchName:
description: Regular expression pattern to match process names for monitoring.
defaultValue: .*
detection:
disableAutoDetection: true
...
monitors:
process:
simple:
sources:
processes:
type: commandLine
commandLine: /usr/bin/ps -e -o comm,args | grep -E "${var::matchName}"
Variables are resolved once, at connector load time:
- A default instance of the connector always exists with the
defaultValues applied, so forcing the connector (connectors: [ +LinuxProcess ]) works without any variable configuration. - Users create additional configured instances in
metricshub.yamlwithadditionalConnectors:
resources:
prod-web:
attributes: { host.name: prod-web, host.type: linux }
protocols:
ssh: { username: monitor, password: "..." }
additionalConnectors:
systemdProcess: # new connector instance id
uses: LinuxProcess # base connector
variables:
matchName: systemd
Always provide a defaultValue. A variable with no default and no user-configured value is not substituted — the literal ${var::name} string survives into the connector and typically breaks at runtime.
Community examples: LinuxProcess[7], LinuxService[8], LinuxFile[9]. Note that all of them pair variables with disableAutoDetection: true: a connector whose behavior depends on user input is usually meant to be selected explicitly.
translations
Top-level map of translation tables, consumed by the translate[10], arrayTranslate[11], and perBitTranslation[12] computes via ${translation::TableName}:
translations:
PhysicalDiskStatusTranslationTable:
"3": ok
"4": degraded
"5": failed
default: UNKNOWN
Authoring rules:
- Keys are matched case-insensitively against the cell value; quote numeric keys so YAML treats them as strings.
- The
defaultkey is the fallback for unmatched values (translateandarrayTranslatehonor it;perBitTranslationignores it). - Translate into the exact state names your metric's
stateSetdeclares (ok,degraded,failed), so mapping can use the column directly. - Declare each table once and reference it from every source that needs it; tables inherited via
extendsmerge key by key.
sudoCommands
Some Linux/Unix commands need elevation. Declare the commands under top-level sudoCommands and prefix their invocations with the %{SUDO:command} macro:
sudoCommands:
- /usr/bin/sensors
monitors:
temperature:
simple:
sources:
sensors:
type: commandLine
commandLine: "%{SUDO:/usr/bin/sensors} /usr/bin/sensors"
At runtime, %{SUDO:/usr/bin/sensors} expands to the configured sudo command (sudo by default) only if the user enabled sudo in their OS-command protocol configuration (useSudo: true) and whitelisted the command. Otherwise the macro silently expands to an empty string and the command runs without elevation — so the command line must remain valid without the prefix (note the pattern above: the macro is a prefix, the real command follows).
Community examples: lmsensors[13], LinuxMultipath[14], SmartMonLinux[15].
Common Mistakes
- Expecting a child connector to remove a parent's detection criterion or compute — object-arrays only append; restructure the hierarchy instead.
- Chaining constants or embedding
${var::}in a constant value — substitution is a single pass. - Declaring a variable without
defaultValue, leaving${var::name}unresolved for users who force the connector without configuration. - Forgetting to whitelist a command in
sudoCommandswhile using%{SUDO:...}— the macro silently disappears and the command runs unprivileged. - Duplicating metric definitions locally instead of extending the right
semconv/*dictionary.
- [1] references-and-expressions.html
- [2] mapping-metrics-semconv.html
- [3] https://github.com/metricshub/community-connectors/blob/main/src/main/connector/hardware/MIB2-header/MIB2-header.yaml
- [4] https://github.com/metricshub/community-connectors/blob/main/src/main/connector/hardware/MIB2/MIB2.yaml
- [5] https://github.com/metricshub/community-connectors/blob/main/src/main/connector/hardware/LinuxNetwork/LinuxNetwork-header/LinuxNetwork-header.yaml
- [6] https://github.com/metricshub/community-connectors/blob/main/src/main/connector/hardware/LinuxNetwork/LinuxIPNetwork/LinuxIPNetwork.yaml
- [7] https://github.com/metricshub/community-connectors/blob/main/src/main/connector/system/LinuxProcess/LinuxProcess.yaml
- [8] https://github.com/metricshub/community-connectors/blob/main/src/main/connector/system/LinuxService/LinuxService.yaml
- [9] https://github.com/metricshub/community-connectors/blob/main/src/main/connector/system/LinuxFile/LinuxFile.yaml
- [10] computes/translate.html
- [11] computes/array-translate.html
- [12] computes/translate-per-bit.html
- [13] https://github.com/metricshub/community-connectors/blob/main/src/main/connector/hardware/lmsensors/lmsensors.yaml
- [14] https://github.com/metricshub/community-connectors/blob/main/src/main/connector/hardware/LinuxMultipath/LinuxMultipath.yaml
- [15] https://github.com/metricshub/community-connectors/blob/main/src/main/connector/hardware/SmartMonLinux/SmartMonLinux.yaml
