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. |
def setup(): argparser = argparse.ArgumentParser( description="The script provides the result of rolling of an n-sided die.", exit_on_error=False, ) argparser.add_argument( "--sides", type=int, default=6, help="The number of sides the die has." ) try: 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)
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 die 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 die rolled {result}.", "channels": [ { "id": 10, "name": "Last Roll", "type": "integer", "value": result, } ], }
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.
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