External Metrics, Actions, and Data Providers
This guide covers how to extend the NetXMS agent with custom metrics, actions, and data providers. For agent configuration file syntax and parameter reference, see Agent Configuration.
External Metrics
External metrics allow the agent to execute commands and return their output as metric values. This is the primary mechanism for collecting custom metrics. Only the first line of command output is returned as the metric value.
The ExternalParameter directive is a deprecated alias for ExternalMetric. Both work identically, but ExternalMetric is the preferred name.
|
Shell Form vs Exec Form
External commands (ExternalMetric, ExternalList, ExternalTable, and Action) support two execution forms:
Shell form passes the command through the system shell (/bin/sh -c on UNIX, cmd.exe /C on Windows):
ExternalMetric = Disk.UsedPercent(*): df --output=pcent $1 | tail -1 | tr -d ' %'
ExternalMetric = Process.Memory(*): ps -o rss= -p $1
Shell form supports pipes, redirections, variable expansion, and command substitution.
Exec form launches the executable directly without a shell:
ExternalMetric = Disk.UsedPercent(*): ["/usr/bin/df", "--output=pcent", "$1"]
ExternalMetric = MyCheck: ["/opt/scripts/check.sh", "param1", "param2"]
Exec form requires the full path to the executable: it is resolved without a PATH search on any platform, and on Windows the file extension (e.g., .exe) must be included. On Windows, the elements are joined with spaces and re-split by the started program, so an element containing spaces reaches it as several arguments unless the value is wrapped in extra quotes (for example '"some text"').
When command arguments come from untrusted sources (e.g., DCI parameters passed as $1, $2), use exec form to prevent command injection. Shell form is vulnerable because parameter values undergo full shell expansion — a value like $(rm -rf /) would be executed by the shell. Exec form passes arguments directly to the executable without shell interpretation. This does not apply when the executable is a .bat or .cmd file: Windows runs such files through cmd.exe, which parses the command line by its own rules.
|
The parameter name follows the standard NetXMS naming convention.
Arguments passed from the DCI are substituted as $1 to $9; a number with no matching argument becomes an empty string.
Any other $ is dropped, so write $$ for a literal $, for example $$HOME or awk '{print $$3}'.
Exit Code Metric
Each ExternalMetric automatically provides a companion metric with the .ExitCode suffix that returns the exit code of the executed command:
ExternalMetric = MyCheck: /opt/scripts/health_check.sh
# This creates two metrics:
# MyCheck - first line of command output
# MyCheck.ExitCode - exit code (0 = success)
For parameterized metrics, the .ExitCode suffix works the same way:
ExternalMetric = Service.Status(*): /opt/scripts/check_service.sh $1
# Creates: Service.Status(*) and Service.Status(*).ExitCode
The .ExitCode metric is not available for ExternalList, BackgroundExternalMetric, ExternalMetricProvider, or ExternalDataProvider.
Background External Metrics
For metrics where you want to avoid blocking the data collection thread, use BackgroundExternalMetric. The command runs asynchronously at the given interval and the cached result is returned immediately:
BackgroundExternalMetric = Slow.Check:300:/opt/scripts/slow_check.sh
The format is name:interval:command, with the execution interval in seconds.
All three parts are required — an entry without an interval is not registered.
External Metric Providers
For metrics that are expensive to compute, use an external metric provider. The provider script runs periodically in the background and caches results for multiple metrics:
ExternalMetricProvider = /opt/scripts/collect_all.sh:60
The format is command:interval[,timeout].
The interval is in seconds and defaults to 60 when omitted; the optional timeout is in milliseconds.
The script must output key-value pairs, one per line:
CPU.Temperature=62
Memory.Available=4096
Disk.Health(sda)=OK
Disk.Health(sdb)=WARNING
Metrics from the provider are accessed by their names as printed by the script.
Parameterized metrics are also supported (as shown with Disk.Health(sda) above).
When no per-provider timeout is given, ExternalMetricProviderTimeout applies (30000 ms by default).
Setting it to 0 selects DefaultExecutionTimeout (5000 ms by default).
External Checks (Nagios Plugins)
Since 6.2.4
External checks run monitoring plugins written for Nagios and compatible systems (the check_* family from the Monitoring Plugins project, or your own scripts that follow the same conventions) and make their results available as agent metrics.
Use them to reuse existing plugins without rewriting each one as an external metric.
The agent reads three things from a plugin run:
-
the exit code — by plugin convention 0 (OK), 1 (WARNING), 2 (CRITICAL), or 3 (UNKNOWN); the agent reports the exit code as-is, so other values are passed through unchanged
-
the status text — the first line of output, up to the
|character -
performance data — the
label=value[UOM];[warn];[crit];[min];[max]entries after the|on the first line, and, for multi-line output, everything after the next|on a later line
Long text output (lines after the first that are not performance data) is ignored.
Configuration
Define each check with ExternalCheck = name: command.
The part before the first : is the check name, the rest is the command, in shell form or exec form (see Shell Form vs Exec Form).
The directive can be repeated; NagiosPlugin is an alias with the same syntax.
ExternalCheck = disk: /usr/lib/nagios/plugins/check_disk -w 20% -c 10% -p / -p /var
ExternalCheck = web: ["/usr/lib/nagios/plugins/check_http", "-H", "www.example.com", "-S"]
Check names are not case-sensitive. Arguments cannot be passed from the DCI: put all plugin options in the command line and define a separate check for each set of options.
The plugin runs when one of its metrics is requested, not in the background.
One run serves all metrics of the check: the result, including a failed run, is reused for ExternalCheckCacheTimeout seconds (default 5), so several DCIs on the same check collected in the same polling cycle start the plugin once.
ExternalCheckTimeout limits the run time in milliseconds; when it is 0 or not set, ExternalMetricTimeout applies.
The cache lifetime counts from the moment the plugin starts, not from when it finishes.
A plugin that runs for ExternalCheckCacheTimeout seconds or longer stores a result that has already expired, and each DCI on the check starts it again, one after another.
Set ExternalCheckCacheTimeout above the plugin’s run time and above ExternalCheckTimeout; with the defaults (5 s cache, 5 s timeout) a timed-out run is not reused.
If the plugin cannot be started or does not finish in time, all metrics of the check return an error until the cached result expires.
In shell form the shell itself always starts, so a missing or non-executable plugin is not an error: it shows up as the shell’s exit code (127 or 126 from /bin/sh, 9009 from CMD.EXE) in ExternalCheck.Status, with the shell’s error message as the status text.
In exec form the agent returns an error on Linux and Windows; on other UNIX systems the status is 127.
Metrics
| Metric | Type | Description |
|---|---|---|
|
Integer |
Plugin exit code |
|
String |
Status text (first line of output before |
|
Float |
Value of the performance data entry |
|
List |
Names of all configured checks |
|
Table |
All performance data entries, one row per label: |
An unknown check name, or a label that is not in the plugin’s performance data, returns "no such instance".
Performance data entries without a numeric value, such as U (unknown), are skipped.
Full entries are in Agent Internal Metrics and List and Table Metrics.
Example
With the disk check above, check_disk prints a line like:
DISK OK - free space: / 3325 MB (56% inode=99%); /var 845 MB (68% inode=99%);| /=2643MB;4774;5371;0;5968 /var=403MB;998;1123;0;1248
Useful DCIs on the node:
-
ExternalCheck.Status(disk), Integer, with a threshold Last polled value Greater than or equal2to generate an event when the plugin reports CRITICAL or UNKNOWN (3), or exits with any higher code, such as 127 when the plugin is missing; add a second threshold Equal1for WARNING if needed -
ExternalCheck.StatusText(disk), String, to show the plugin’s message on dashboards or in the event message -
ExternalCheck.Value(disk, /var), to collect used space on/var(in MB, the plugin’s unit) as a time series -
ExternalCheck.PerfData(disk)as a table DCI, to collect all mount points in one request -
ExternalCheck.Status({instance})with instance discovery method Agent List and listExternalCheck.Checks, to cover every configured check from one template
External Data Providers
External data providers execute a command periodically and cache its structured output (JSON, XML, or plain text). Individual values are then extracted from the cached output using jq expressions (JSON), XPath queries (XML), or PCRE regular expressions (plain text).
This is useful when a single command produces multiple related metrics — the command runs once and all metrics are extracted from the cached result.
Configuration
External data providers use INI-style section syntax:
[ExternalDataProvider/myApp]
Command = /opt/scripts/app_status.sh
PollingInterval = 300
Timeout = 30000
Description = Application status information
| Parameter | Default | Description |
|---|---|---|
|
(required) |
Command to execute (shell form or exec form) |
|
60 |
Execution interval in seconds |
|
(see description) |
Execution timeout in milliseconds. If not set, |
|
(none) |
Text description for this provider |
|
false |
Force plain text parsing even if output looks like JSON or XML |
The agent auto-detects the output format:
-
Output starting with
{or[is parsed as JSON (extracted with jq syntax) -
Output starting with
<is parsed as XML (extracted with XPath) -
All other output is parsed as plain text (extracted with PCRE regex containing one capture group)
Set ForcePlainTextParser = true to override auto-detection.
Generic Metric Access
Without any additional configuration, the provider name itself becomes a parameterized metric. Pass the extraction query as the parameter:
Suppose the command outputs:
{
"version": "1.2.5",
"queues": { "in": 10, "out": 42 }
}
You can query values directly:
-
myApp(.version)returns1.2.5 -
myApp(.queues.out)returns42 -
myApp(.queues | add)returns52
Any valid jq expression can be used as the parameter (for JSON output), or XPath query (for XML), or regex (for text).
Named Metrics
Define named metrics to create fixed metric names with predefined extraction queries:
[ExternalDataProvider/myApp/Metrics]
myApp.Version = .version
myApp.Queue.Inbound = .queues.in
myApp.Queue.Outbound = .queues.out
myApp.Queue.Outbound.description = Number of files in outbound queue
myApp.Queue.Outbound.dataType = int32
Each metric entry maps a metric name to an extraction query.
Optional .description and .dataType suffixes set the metric description and data type respectively.
Parameterized named metrics are supported (v6.1+):
[ExternalDataProvider/myApp/Metrics]
myApp.Queue(*) = .queues.$1
myApp.Queue(*).description = Number of files in given queue
myApp.Queue(*).dataType = int32
List Metrics
Define list metrics to extract arrays from the cached output:
[ExternalDataProvider/myApp/Lists]
myApp.QueueNames = .queues | keys[]
myApp.QueueNames.description = List of available queue names
Each entry maps a list name to an extraction query that returns multiple values.
Data Types
The following data types can be used in .dataType and ColumnType settings:
| Type | Description |
|---|---|
|
Text string (default for metrics) |
|
32-bit signed integer |
|
32-bit unsigned integer |
|
64-bit signed integer |
|
64-bit unsigned integer |
|
Floating-point number |
|
32-bit counter (monotonically increasing, wraps at 232) |
|
64-bit counter (monotonically increasing, wraps at 264) |
The type name null (no data type) is also accepted, as are the legacy aliases int and uint for int32 and uint32.
Complete Example
A script /opt/scripts/app_metrics.sh outputs JSON:
{
"version": "3.1.0",
"uptime": 86421,
"connections": { "active": 150, "idle": 23, "max": 500 },
"queues": { "inbound": 42, "outbound": 7, "failed": 0 }
}
Agent configuration:
[ExternalDataProvider/appMetrics]
Command = /opt/scripts/app_metrics.sh
PollingInterval = 60
[ExternalDataProvider/appMetrics/Metrics]
App.Version = .version
App.Version.dataType = string
App.Uptime = .uptime
App.Uptime.dataType = uint64
App.Connections.Active = .connections.active
App.Connections.Active.dataType = int32
App.Connections(*) = .connections.$1
App.Connections(*).dataType = int32
App.Queue(*) = .queues.$1
App.Queue(*).dataType = int32
[ExternalDataProvider/appMetrics/Lists]
App.QueueNames = .queues | keys[]
App.ConnectionTypes = .connections | keys[]
This creates metrics like App.Version, App.Uptime, App.Connections.Active, App.Connections(idle), App.Queue(inbound), and lists like App.QueueNames.
Execution Timeouts
# Global timeout for all external executions (milliseconds)
DefaultExecutionTimeout = 30000
# Override for external metrics only
ExternalMetricTimeout = 15000
# Override for metric providers
ExternalMetricProviderTimeout = 60000
# Override for external checks (Nagios plugins); keep the cache longer than the timeout
ExternalCheckTimeout = 10000
ExternalCheckCacheTimeout = 15
# Override for actions
ExternalCommandTimeout = 120000
Environment Variables
The EnvironmentFile directive loads environment variables for the agent process from a separate file. Since 6.2.1
EnvironmentFile = /etc/nxagentd/agent.env
Use one KEY=VALUE per line in the environment file. Leading and trailing whitespace is trimmed; blank lines and lines starting with # are ignored. Values are read literally, without quoting or expansion. Repeat EnvironmentFile to load multiple files. Configuration dumps show only the file paths. Protect files containing secrets with filesystem permissions.
The server can push environment variables to the agent for use by externally executed commands.
The AcceptedEnvironmentVariables parameter defines which server-provided variables the agent accepts, as a repeatable name pattern:
AcceptedEnvironmentVariables = NX_*
AcceptedEnvironmentVariables = MYAPP_*
When no patterns are configured, the defaults are NX_* and NETXMS_*.
The literal value none clears the list, so no server-provided variables are accepted.
This parameter only filters variables pushed by the server — it does not sanitize the environment that child processes inherit from the agent process.
External Lists
External lists return multi-line output where each line is a list item:
ExternalList = System.ActiveUsers: who | cut -d' ' -f1 | sort -u
Exec form is also supported:
ExternalList = System.Mounts: ["/usr/bin/findmnt", "-rno", "TARGET"]
ExternalList = Dir.Contents(*): ["/usr/bin/ls", "$1"]
External lists can be used as an instance source for instance discovery DCIs.
External Tables
External tables return tabular data from command output. The command must print column names on the first line and data rows on subsequent lines, with columns separated by a delimiter.
Section-Based Configuration
The preferred configuration format uses INI-style sections:
[ExternalTable/Disk.Usage]
Command = df -P | tail -n +2
Separator = \s
MergeSeparators = true
InstanceColumns = mount_point
Description = Disk space usage
| Parameter | Default | Description |
|---|---|---|
|
(required) |
Command to execute (shell form or exec form) |
|
|
Column separator character |
|
false |
Treat consecutive separators as one (v6.1+) |
|
(none) |
Comma-separated list of columns that uniquely identify each row |
|
(none) |
Table description |
|
(none) |
If set, run command in background at this interval (seconds). If not set, run synchronously on each request. |
|
(see description) |
Execution timeout in milliseconds. If not set, |
|
(none) |
Column data type in format |
|
|
Default data type for columns without an explicit |
Parameterized tables use (*) in the section name:
[ExternalTable/File.Data(*)]
Command = ["/usr/bin/cat", "/data/files/$1"]
Separator = ;
InstanceColumns = id
Separator Special Characters
The Separator parameter supports escape sequences:
| Sequence | Meaning |
|---|---|
|
Space |
|
Tab |
|
Newline |
|
Carriage return |
|
Unicode character by decimal code point |
Legacy One-Line Configuration
The older single-line format is still supported:
ExternalTable = Disk.Usage::df -P
ExternalTable = Disk.Usage:instanceColumns=mount_point;separator=\s;mergeSeparators=true:df -P | tail -n +2
The format is Name:options:command where options is a semicolon-separated list of key=value pairs. Supported option keys: instanceColumns, separator, description, mergeSeparators, backgroundPolling, pollingInterval, timeout, defaultColumnDataType.
Example
A script outputs comma-separated data with a header row:
name,pid,cpu,memory
httpd,1234,2.5,150000
postgres,5678,8.1,524288
java,9012,15.3,1048576
Configuration:
[ExternalTable/Process.Stats]
Command = /opt/scripts/process_stats.sh
Separator = ,
InstanceColumns = name
ColumnType = name:string
ColumnType = cpu:float
ColumnType = memory:uint64
Description = Process resource usage
PollingInterval = 30
Actions
Actions define commands that the server can execute on the agent remotely. They are used in event processing policy rules, as alarm responses, or triggered manually:
Action = RestartService: systemctl restart $1
Action = CleanLogs: find /var/log -name "*.log" -mtime +30 -delete
The server calls actions through the management console, EPP rules, or NXSL scripts using the AgentExecuteCommand() and AgentExecuteCommandWithOutput() functions.
Action commands treat $ differently from external metrics: only $1 to $9 with a supplied argument are replaced, and every other $ stays in the command, so $HOME reaches the shell unchanged and $$ stays $$.
Actions run with the same permissions as the agent process.
Restrict the MasterServers and ControlServers lists to trusted servers only.
|
Built-in Core Actions
The following actions are available when EnableActions = yes (the default):
| Action | Purpose |
|---|---|
|
Restart the agent |
|
Rotate the agent log |
|
Terminate a process (UNIX only) |
|
Enable or disable an external data provider |
|
Transfer a file to a remote TFTP server |
|
Execute a system command; requires |
|
Execute a command in all user sessions (Windows only); requires |
Platform Actions
Platform subagents also register the following actions:
| Actions | Platforms |
|---|---|
|
Windows (also provided by the core on UNIX) |
|
Linux, Windows |
|
Linux |
|
Windows |
|
Linux, Windows |
|
Linux |
|
Windows |
Runtime Management
Complete Configuration Example
# Server access control
MasterServers = 10.0.0.1
ControlServers = 10.0.1.0/24
# Security
RequireEncryption = yes
RequireAuthentication = yes
SharedSecret = MyS3cretPhrase
# Logging
LogFile = /var/log/nxagentd.log
LogRotationMode = 2
MaxLogSize = 33554432
DebugLevel = 0
DebugTags = tunnel:4
# Network
ListenAddress = *
ListenPort = 4700
# Tunnel connection to server
ServerConnection = server.example.com
# Proxy functions
EnableSNMPProxy = yes
EnableSNMPTrapProxy = yes
SNMPTrapPort = 162
# Zone assignment
ZoneUIN = 3
# Subagents (platform subagent is loaded automatically)
SubAgent = logwatch.nsm
SubAgent = filemgr.nsm
# Custom metrics
ExternalMetric = Hardware.SerialNumber: dmidecode -s system-serial-number
ExternalMetric = Disk.UsedPercent(*): df --output=pcent $1 | tail -1 | tr -d ' %'
# Actions
Action = RestartService: systemctl restart $1
Additional configuration files can be placed in the configuration include directory (nxagentd.conf.d) — see Configuration Include Directory.