I currently use the Python Script Advanced sensor for monitoring. I want to use the same scripts in the Script v2 sensors. What do I have to do to so that I can use my same scripts in the Script v2 sensor?
How can I make my Python scripts work with the Script v2 sensor?
Votes:
0
2 Replies
Votes:
0
This article applies to as of PRTG 24
Python scripts for the Script v2
With the upcoming discontinuation of the Python Script Advanced sensor, we created a script breakdown to help the transition to Python scripts that you can use with the Script v2 sensor.
The script breakdown covers the following topics:
- Parse input parameters: setup()
- Script logic: work()
- Error argument: fail()
- Main function
If you follow the example script in this article without making any changes, the resulting script accepts a parameter from PRTG and outputs one channel with a random value.
This script is based on the Script v2 example script: Example python script. In this example, we use a script that mimics rolling an n-sided die.
Parse input parameters: setup()
To parse the input parameters for our script, we use the argparse package from the standard python library.
In our case, we define the setup() function which contains the input handling where we define all required parameters.
Argument | Description |
---|---|
ArgumentParser | This sets the description displayed when invoking the script using --help. |
add_argument | This adds the --sides parameter with a default value. You can set the parameter on the Command Line Interface (CLI), for example, '--sides 20'. |
argparser = setup() | Calls the setup function to handle the script input. |
if sys.stdin.isatty() | Checks if the script is executed interactively. |
args = argparser.parse_args() | If the script is interactive, the script places the extracted data in a argparse.Namespace object. |
pipestring = sys.stdin.read().rstrip() | If there is no terminal detected, the script falls backs to read from sys.stdin. |
args = argparser.parse_args(shlex.split(pipestring)) | Parses stdin with argparse. |
except argparse.ArgumentError | In case of an argparse.Argument error, we suspect something is wrong with the parameters on invocation. |
Example
def setup():
argparser = argparse.ArgumentParser(
description="The script provides the result of rolling of an n-sided die."
)
argparser.add_argument(
"--sides", type=int, default=6, help="The number of sides the dice has."
)
args = argparser.parse_args()
try:
argparser = setup()
if sys.stdin.isatty():
args = argparser.parse_args()
else:
pipestring = sys.stdin.read().rstrip()
args = argparser.parse_args(shlex.split(pipestring))
except argparse.ArgumentError:
fail(
"Could not parse input parameter. Check configured parameters."
)
return vars(args)
2. Script logic: work()
The work() function defines the sensor logic and returns the result for the sensor. It accepts the parsed arguments defined in setup() and returns the result as a python dictionary.
The returned result adheres to the Script v2 JSON Schema. The Script v2 validates the result against the schema version specified.
Here, you define the result variable of your dice roll and how the sensor behaves as a result.
Return parameters
Parameter | Description |
---|---|
verison | The script output schema version |
status | The sensor status You can use any of the sensor states. Be aware that ok = Up and error = Down. |
message | The sensor message Hint: Use an f-string to be able to use placeholders. |
channels | The sensors channels Define the channel ID, name, type, and value. |
def work(args: argparse.Namespace): result = random.randrange(1, args["sides"] + 1) return { "version": 2, "status": "ok", "message": f"The dice rolled {result}.", "channels": [ { "id": 10, "name": "Last Roll", "type": "integer", "value": result, } ], }
3. Error argument: fail()
The fail() function takes a message and prints out a result that only contains an error and a sensor message. Use this function to handle error cases and stop your script early.
Best practices
- Only create errors and error messages for situations that a user can act on immediately. By default, allow all exceptions and use the sensor debug log for detailed error analysis.
- Do not include sensitive information in the message parameter. All messages defined in this script appear as the sensor message and you could potentially leak sensitive data if you pass an unfiltered exception.
- Make useful error messages. It does not help the user if the sensor message displays just the exception that triggered the error.
- Use fail() to define common ways for the script to fail. This reduces repetitive code.
def fail(message: str):
print(
json.dumps(
{
"version": 2,
"status": "error",
"message": message,
}
)
)
exit(0)
Note: Scripts always need to exit with EXITCODE=0. Otherwise, the sensor fails to recognize the script output and interprets the sensor run as failed.
4. Main function
Finally, the last part of the script defines the main function, or entry point, of the script.
Main function breakdown
The script runs through the functions in the order defined in the main function. In this example, the script first checks the setup function. If there is no error, the script executes the work function and finally prints the result. Then, the script closes on the exit code.
if __name__ == "__main__": # Retrieve script arguments args = setup() # Execute sensor logic sensor_result = work(args) # Format the result to JSON and print them to stdout. print(json.dumps(sensor_result)) # Scripts always need to exit with EXITCODE=0. exit(0)
More
Python Documentation
Created on Nov 4, 2024 10:13:50 AM by
Jacqueline Conforti [Paessler Support]
Last change on Dec 3, 2024 1:54:17 PM by
Felix Seethaler [Paessler Support]
Votes:
0
Example python script without comments
You can put this script into C:\Program Files (x86)\PRTG Network Monitor\Custom Sensors\scripts and create a Script v2 sensor using this python script.
#!/usr/bin/env python3 """This is an example Python script for the Script v2 sensor. The script provides the result of rolling of an n-sided die. The script uses the integer parameter '--sides' to determine the number of sides of the die. If the parameter is omitted, the number of sides default to 6. """ import argparse # needed to parse the script arguments import json # needed to construct the result message import random # needed for the random dice roll import shlex # needed to parse arguments passed via pipe to stdin (PRTG uses this invocation style) import sys # needed to check if script is invoked from a tty or through a pipe def fail(message: str): """ Return error message to PRTG and abort the sensor script. This function can be used to reduce code duplication by having a common way to fail the sensor script Be careful with the message you pass here. As the message will be shown in PRTG as the Sensor message. You could potentially leak sensitive data in the sensor message if you pass an unfiltered exception. It is recommended only catch errors on which the user immediately can act on. In general exceptions should not be caught and the sensor debug log on the probe should be checked for the detailed error. """ print( json.dumps( { "version": 2, "status": "error", "message": message, } ) ) """ Scripts always need to exit with EXITCODE=0. Otherwise the Sensor will fail to recognize your script output and interpret the sensor run as failed. """ exit(0) def setup(): """ Parse the arguments from stdin or cli when running interactive and return them as a dict. Construct the ArgumentParser without `exit_on_error`. This allows us to forward the error to PRTG. """ argparser = argparse.ArgumentParser( description="The script provides the result of rolling of an n-sided die", exit_on_error=False, ) """ Define your arguments here."""" argparser.add_argument( "--sides", type=int, default=6, help="The number of sides the dice has." ) try: """Check if script is executed interactively first. Otherwise expect arguments from stdin.""" if sys.stdin.isatty(): args = argparser.parse_args() else: pipestring = sys.stdin.read().rstrip() args = argparser.parse_args(shlex.split(pipestring)) """ In case of an argparse.Argument error we suspect something wrong with the parameters on invocation""" except argparse.ArgumentError: fail( "Could not parse input parameter. Check configured `Parameters` in `Script Settings`" ) return vars(args) def work(args: dict): """ The work function implements the sensor logic and returns the sensor result as a dict. Implement your sensor logic here. Read the sides parameter from args. This is the work the sensor performs. """ result = random.randrange(1, args["sides"] + 1) """ Construct your sensor result here Create a dict adhering to the expected JSON output format """" return { "version": 2, # The script output schema version to use "status": "ok", # The sensor status "message": f"The dice rolled {result}", # The sensor message "channels": [ { "id": 10, "name": "Last Roll", "type": "integer", "value": result, } ], } if __name__ == "__main__": args = setup() # Retrieve script arguments sensor_result = work(args) # Execute sensor logic print(json.dumps(sensor_result)) # Format the result to JSON and print them to stdout. exit(0)
Created on Dec 2, 2024 11:00:39 AM by
Jacqueline Conforti [Paessler Support]
Last change on Dec 3, 2024 11:48:02 AM by
Jacqueline Conforti [Paessler Support]
Add comment