Overview
The Process event handler runs an external program whenever a Mango by Radix IoT event is raised or returns to normal. This gives you the power to trigger actions outside of Mango — restart a service, toggle a relay through a command-line tool, send a notification through a custom channel, write to an external log, or run any executable available on the host operating system.
Process commands are launched directly by the Mango server process, so they run with the same OS-level permissions as the Mango user account. This is a powerful feature that requires careful attention to security.
Warning
Mango launches the command with Java’s Runtime.exec(String), which splits the string on whitespace and runs the first token as the program. There is no /bin/sh and no cmd.exe in the picture unless you put one there yourself, so redirection with >>, pipes, $(...) substitution, background & and wildcard expansion are not interpreted. Quotation marks are not interpreted either. They are ordinary characters, which means you cannot group a value containing spaces into a single argument from this field. A command that works when you paste it into a terminal can fail or behave unexpectedly here.
Prerequisites
- Mango 4.x or 5.x
- The
superadminrole — the Event handlers page is restricted to it - At least one event detector configured (to trigger the handler)
- Shell access to the Mango server (for creating and testing scripts)
event-handlers.process.enabled=trueinmango.properties(see Step 1)event-handlers.process.interpolation-enabled=trueas well, if the command needs event data (see Step 4)
Step 1: Enable Process Event Handlers
Process event handlers are disabled by default for security. You must explicitly enable them in mango.properties; there is no system-settings page for this.
- Open the
mango.propertiesin your Mango data directory, the one configuration file Mango reads at startup. Create it if it doesn’t exist. Amango.propertiesunderoverrides/properties/is never read, so a setting there does nothing:
# Linux, installed with bin/install-mango.sh (data directory /opt/mango-data)
sudo nano /opt/mango-data/mango.properties
# Linux, unzipped without the installer (data directory = installation directory)
sudo nano /opt/mango/mango.properties
# Windows
notepad C:\mango\mango.properties
- Add or update the following properties:
# Enable the process event handler (ships as false)
event-handlers.process.enabled=true
# Enable interpolation of event data into the command (ships as false).
# Only needed if a handler uses the "Interpolate commands" option - see Step 4.
event-handlers.process.interpolation-enabled=false
- Restart Mango for the change to take effect:
sudo systemctl restart mango
Note
These two properties are independent gates. With event-handlers.process.enabled=false, a handler that fires logs a warning and runs nothing at all. With it enabled but interpolation disabled, plain commands run normally while any handler that asks for interpolation logs a warning and is skipped — which looks like a handler that silently does nothing. Check ma.log for those warnings when a handler appears inert.
Warning
Enabling process events allows Mango admin users to execute arbitrary commands on the host system. Only enable this on servers where all admin users are trusted. Consider using the principle of least privilege for the Mango service account.
Step 2: Create a Process Event Handler
- Go to Event Management > Event handlers
- In the Select event handler list, click New (or the + button on that row)
- On the Event handler tab, set Event handler type to Process
- Give the handler a descriptive Name (e.g., “Restart HVAC Controller” or “Log Alarm to Syslog”)
- Set the XID or leave the auto-generated value
The handler needs at least one command before it will save: Mango rejects an empty pair with “At least one process command must be provided”.
Step 3: Configure the Command
The handler has two command fields, each with its own timeout:
- Active process command — runs when the event is raised (alarm goes active)
- Inactive process command — runs when the event returns to normal (alarm clears)
Write the command as a program path followed by arguments. Because Mango does not hand the string to a shell, the whole string is parsed into a program and its arguments and executed directly.
Simple Examples
Run a script directly (Linux):
/opt/scripts/handle_alarm.sh
Run a batch file (Windows):
C:\scripts\handle_alarm.bat
Restart a service (Linux):
/usr/bin/systemctl restart my-equipment-service
Note the absolute path. Without a shell there is no PATH lookup you can rely on, so name the executable in full.
When You Need Shell Features
Anything involving redirection, pipes, command substitution, or chaining needs a shell — and you cannot hand one a quoted command string from this field. This does not do what it looks like:
/bin/sh -c "echo alarm raised >> /var/log/mango-alarms.log"
Because quotes are not parsed, the tokenizer hands sh the arguments -c and "echo, and the remaining words become positional parameters. sh runs "echo as its command and the redirection never happens.
The reliable pattern — really the only one — is to put the logic in a script file and let Mango invoke the script:
#!/bin/bash
# /opt/scripts/handle_alarm.sh
printf '%s: %s\n' "$(date -Is)" "$*" >> /var/log/mango-alarms.log
The script runs under a real shell, because the kernel honours its #! line, so redirection and $(date) behave normally inside it. Mango only has to launch one whitespace-free path: /opt/scripts/handle_alarm.sh.
Note
The Mango process user must have permission to execute the command, and the script must be executable (chmod +x) with a valid shebang line.
Step 4: Pass Event Data as Arguments
A handler can substitute event data into its command, but this is off unless you turn it on in two places:
- Per handler: enable Interpolate commands (access event properties) on the handler itself.
- Globally: set
event-handlers.process.interpolation-enabled=trueinmango.propertiesand restart.
If a handler requests interpolation while the global property is still false, Mango logs a warning and does not run the command at all. It does not fall back to running the command uninterpolated.
Placeholders use ${...} and resolve against an event object — the event instance that fired the handler. Anything you reference must be a readable property of that object.
Commonly Used Event Properties
| Placeholder | Description | Example Value |
|---|---|---|
${event.id} |
Internal event ID | 42 |
${event.eventType.eventType} |
Event type category | DATA_POINT |
${event.eventType.eventSubtype} |
Event subtype. Null for event types that have none | POINT_EVENT_DETECTOR |
${event.activeTimestamp} |
When the event was raised (ms) | 1704067200000 |
${event.rtnTimestamp} |
When the event returned to normal (ms). Null while the event is active | 1704070800000 |
${event.alarmLevel} |
Alarm level of the event | URGENT |
${event.message} |
The message object, not its rendered text — see the warning below | TranslatableMessage{key='event.detector.highLimit', args=[...]} |
Warning
Three things to know before you rely on a placeholder.
There is no placeholder for the readable event message. event.message is a TranslatableMessage object and interpolation stringifies whatever it finds, so you get the debug form TranslatableMessage{key=..., args=[...]} rather than “High temperature alarm”. The rendered text is produced by a method that interpolation cannot reach. If your command needs the message text, have the script fetch the event by its ID through the REST API.
A missing property and a null property behave differently. Naming a property the event object does not have raises an error and the command does not run. Naming one that exists but is null — rtnTimestamp on a still-active event, or eventSubtype on a type that has none — leaves the placeholder in the command as literal text.
Point values are not exposed. Interpolation resolves bean properties of the event object only; there are no top-level point-value placeholders.
Example: Pass Event Data to a Script
/opt/scripts/handle_alarm.sh ${event.id} ${event.eventType.eventType} ${event.alarmLevel}
No quotes, and only values that cannot contain spaces. Quotes would arrive as literal characters, and because the interpolated string is tokenized on whitespace afterwards, any value containing a space becomes several arguments. event.id, event.activeTimestamp and event.alarmLevel are safe on both counts.
Your script then processes these as ordinary positional arguments:
#!/bin/bash
# /opt/scripts/handle_alarm.sh
EVENT_ID="$1"
EVENT_TYPE="$2"
MESSAGE="$3"
printf '%s: Event %s (%s) - %s\n' "$(date -Is)" "$EVENT_ID" "$EVENT_TYPE" "$MESSAGE" \
>> /var/log/mango-alarms.log
Passing event data to a script is safer than building a shell string, because the values are never re-parsed as shell syntax — but they are still split on whitespace, so a multi-word value silently becomes several arguments. Anything that might contain spaces or punctuation belongs nowhere near this field: pass the event ID and let the script look the rest up.
Step 5: Link the Handler to Event Detectors
- In the event handler editor, open the Event types tab. Its label carries a running count, as in Event types (3 checked)
- The tab holds a three-pane picker with checkboxes. Work left to right, from the event type category down to the individual source. You select event types, not alarm levels — there is no “fire for anything URGENT and above” option here
- Tick the event types that should trigger this handler:
- Data Point Events — alarms from point-level event detectors (high limit, low limit, binary state, etc.)
- Data Source Events — data source errors (poll failures, connection issues)
- System Events — system-level events (disk full, license expiry, etc.)
- For data point events, drill into the child panes to pick specific data points or event detectors, or tick a whole category
- Save the event handler
Step 6: Handle Timeouts
Each command has its own configurable timeout, set on the handler as Active process timeout (s) and Inactive process timeout (s). Both default to 15 seconds and must be greater than zero. When the timeout elapses, Mango destroys the process.
The first thing to try for a slow command is simply raising that handler’s timeout to a realistic value. Reach for backgrounding only when the work genuinely does not belong in the handler’s lifetime.
Detach Long-Running Work
Because there is no shell, a trailing & in the command field does nothing useful. Detaching has to happen inside a script:
#!/bin/bash
# /opt/scripts/launcher.sh
# Mango waits only for this launcher, which returns immediately.
setsid /opt/scripts/long_task.sh "$@" </dev/null >>/var/log/mango-long-task.log 2>&1 &
exit 0
Then set the handler command to /opt/scripts/launcher.sh ${event.id} — unquoted, as always.
Tip
Detached work loses the handler’s error reporting: Mango sees the launcher exit cleanly and never learns whether the real task succeeded. Have the detached task write its own log and, where it matters, report back into Mango through a data point or the REST API.
Step 7: Test the Handler
Before relying on the handler in production:
- Create a test script that writes output to a known file:
#!/bin/bash
# /opt/scripts/test_handler.sh
printf '%s: handler fired with args: %s\n' "$(date -Is)" "$*" \
>> /tmp/mango-handler-test.log
- Make it executable:
chmod +x /opt/scripts/test_handler.sh
- Set your process handler’s active command to:
/opt/scripts/test_handler.sh ${event.id} ${event.alarmLevel}
- Use the Test command button beside the command field to run it immediately, without waiting for an event. It posts the command to
/rest/latest/server/execute-command, which returns the command’s standard output in the UI and surfaces any standard error as an error message — by far the fastest way to catch a bad path or a permissions problem. Two caveats: the test runs the command exactly as typed, with no interpolation, so placeholders go through literally; and it bypasses theevent-handlers.process.enabledgate, so a successful test does not prove the handler itself will fire - Then trigger the event detector for a real end-to-end check (e.g., set a data point above its high limit)
- Check
/tmp/mango-handler-test.logfor output - To see the command’s own output, raise Mango’s logging for the process executor to TRACE. Standard output and standard error are captured and logged at trace level, so at default log levels they are not written to
ma.logat all. Failures to start the process are separate: they raise a Mango system event rather than appearing only in the log.
Tip
Test with interpolation exactly as production will have it. A handler that works with interpolation off and stops working with it on — or the reverse — is the single most common surprise with this handler type.
Warning
Mango’s own in-product help for this handler says the command “can be any shell command appropriate to the host” and that commands “should be specified as they would be from a terminal command prompt”. At 5.7.4 that is not what the code does — the command goes to Runtime.exec(String), which uses no shell and does not parse quotes. The same help page also says standard output is logged at information level and error output at error level; both are actually logged at trace. Follow this article’s guidance over the help page on those two points.
Common Use Cases
Every command below is a direct program invocation with no quotes and no space-bearing values, since no shell is involved.
| Use Case | Active Command | Notes |
|---|---|---|
| Log alarms to syslog | /opt/scripts/log_alarm.sh ${event.id} |
Let the script call logger. A message passed directly would split on its spaces |
| Restart equipment | /usr/bin/ssh controller@192.168.1.100 reboot |
Requires SSH key auth for the Mango user |
| Send SMS via CLI tool | /opt/sms/send.sh ${event.id} ${event.alarmLevel} |
The script composes the text and calls the gateway |
| Toggle GPIO pin | /usr/bin/gpio write 7 1 |
Raspberry Pi or similar |
| Write to external DB | /opt/scripts/insert_alarm.sh ${event.id} ${event.activeTimestamp} |
Both values are digits, so tokenizing is harmless |
| Append to a log file | /opt/scripts/append_alarm.sh ${event.id} |
Do the >> redirection inside the script |
Security Considerations
Process event handlers are one of the most powerful features in Mango, but they come with significant security implications:
- Least privilege — Run Mango under a dedicated service account with minimal OS permissions. Do not run Mango as root.
- Script ownership — Ensure scripts called by handlers are owned by root (or a trusted user) and are not writable by the Mango user. This prevents privilege escalation.
- Pass identifiers, not text — any interpolated value can carry text you did not author, and because the interpolated string is then tokenized on whitespace, attacker-influenced text does not stay in one argument. Pass
event.idand have the script retrieve what it needs, and validate the values inside the script. Do not try to smuggle free text through this field. - Keep interpolation off unless needed —
event-handlers.process.interpolation-enabledships disabled. Leave it that way on systems where no handler needs event data. - Audit trail — Log all handler executions and review them periodically.
- Restrict admin access — Only grant admin permissions to users who should be able to create process handlers.
Verification
Confirm your process handler is working:
-
event-handlers.process.enabled=trueis set inmango.propertiesand Mango has been restarted - If any handler uses Interpolate commands,
event-handlers.process.interpolation-enabled=trueis set as well - The handler appears in the Event handlers list with the correct type
- Each command names an absolute path to an executable, with no unquoted reliance on shell features
- The active and inactive timeouts are long enough for the work each command does
- The handler is linked to the correct event types
- A test event triggers the command and output appears in the expected location
- With the process executor at TRACE level, the captured stdout and stderr appear in
ma.log -
ma.logcontains no “process event handler is disabled” or “interpolation is disabled” warnings after a test event
Troubleshooting
Handler does not fire when the event triggers
Verify the handler is linked to the correct event type and specific detector, and that the event detector itself is working (look for the event in the Events list). Then confirm event-handlers.process.enabled=true in mango.properties. When the feature is disabled, Mango logs a warning naming the command and event, and runs nothing.
Handler is enabled but silently does nothing
This is the signature of the interpolation gate. A handler with Interpolate commands ticked, on a system where event-handlers.process.interpolation-enabled is still false, is skipped with a warning in ma.log and never executes. Either enable the global property and restart, or untick the option on the handler.
Command works in a terminal but not from the handler
Almost always a shell assumption. Redirection (>>), pipes, $(...), trailing &, wildcards, and PATH lookup are all shell behaviour, and Mango does not use a shell. Move the logic into a script and call the script by its absolute path.
“Process failed to start” system event
The command path is incorrect or the Mango user does not have execute permission. Test by switching to the Mango user (su - mango) and running the command directly.
Process runs but output is missing
Captured stdout and stderr are logged at trace level, so nothing appears at default log levels. Raise the log level for the process executor to TRACE, or have the script write to its own file.
Process is killed before it finishes
The handler’s timeout elapsed. Raise Active process timeout (s) or Inactive process timeout (s) on that handler, or detach the work using a launcher script as shown in Step 6.
Interpolation throws an error instead of substituting
Referencing a property the event object does not expose fails the substitution and the command does not run — it does not quietly become an empty string. Check the placeholder spelling, and confirm the property genuinely exists for that event type by testing against a real event.