Important This documentation space contains information about PATROL Agents when deployed in a TrueSight Operations Management environment. If you are a BMC Helix Operations Management user, see PATROL Agent for BMC Helix Operations Management 23.4.

Understanding PATROL Script Language (PSL) and its design


This page provides an overview of the PSL language by going over design decisions. You are expected to know most of the PSL functions that are available. For information not covered in this section, see the PSL Reference Guide. This page contains the following topics:

PSL advantages

PSL was created with the following items as top priorities:

  • Easy to learn
  • Need for access to shared data. From within one script, one must be able to
  • Access data collected by another script
  • Easily execute on any OS by means of interpretation
  • The interpreter must support "multiple" scripts running at the same time, without the use of multiple threads.
  • A badly written script should not bring down all the other scripts.
  • Functions for communication with OS and execution of OS commands.
  • Fast enough with a small impact on the OS.

Why did BMC develop PSL rather than a more common language such as perl, C, or java? Because none of these languages address the previously mentioned "priorities".

Datatypes

To make it easier to learn the language, it was decided to stay away from explicit data types and the string datatype was chosen as the datatype. This has some implications, because some functions or operators require or work with integer or float values. For these functions, the input strings will be converted to the needed datatype for the operation and after the operation completes, stored again as a string. 

The function or operator will decide how the input should be cast. For example, bitwise instructions (such as shift left), need two integer values and the bitwise operator will take care of the conversion. An operation like +, -, x, / will work with double precision (like almost all the other arithmetic operations).

Comparisons

Since all this happens under the hood, you as a developer must normally not be aware that the internal datatype is actually a string and the PSL language will usually work the way you expect it to work. However the moment you should be aware how everything is stored is when you want to compare to variables. 

PSL will try to decide which type of comparison is necessary when you type: 

if (a == b) {...}

If a and b can be evaluated to numbers, the interpreter will do a numerical comparison. If one of them is not a number then a string comparison is used. In some special cases this can lead to confusion. Let's presume the PSL comparison: 

if (! a) { a = "EMPTY"; } 

If you really want to test for a non-empty string then this code might not do what you expect it to do. If a="00000000"; then this is considered a valid number and therefore the test if (!0) { a = "EMPTY"; } will succeed although the string is not empty. To force non-empty string comparison, one must do the following: 

if (a == "") { a = "EMPTY"; }

Which is a true empty string comparison. If you want to compare a certain null-prefixed number as a string you can do so by insuring the number is evaluated as a string 

like this: 

if ("X".a == "X0001") { ..}

Escape Characters

Inside a string you can specify some escape characters by preceding a regular character with a 'n'. These escaped characters will be recognized at compile/parse time of your PSL script, that means, even before the string is stored internally. 

There are only a few string literals supported: \t tab \n new-line \r return \b backspace \A..\Z Ctrl-A ... Ctrl-Z 
escaped backslash \" escaped quote 

The control characters can be very useful if you want to serialize data stored in a PSL variable (for example before storing them in a configuration variable). For example:

# Serialize variable for storage in pconfig()
# Replace all comma's with nC
ser_myvar=replace(myvar,",","\C");
# Now store the variable
pconfig("APPEND","/MYKM/myvar",ser_myvar);

When you read the variables, you could easily undo the serialization as a work around of the comma delimiter which is hardcoded in pconfig lists.

Special clearText Character Sequence

The text parameter and system output window are a kind of a terminal window, and recognize a limited number of escape sequences. Actually the only escape sequence that will be properly handled are "clearscreen" character sequences for ANSI and VT100 terminals (Esc [H Esc 2J and Esc [;H Esc 2J). Sending this sequence will clear the window. 

Sequences to change the color, appearance, or any other VT100 terminal sequences will not be recognized.When you do a: 

print(get("/clearText")); 

you will print the ANSI terminal clearscreen escape sequence and this is recognized by the text output window. 

Just to show you, type the following in a system output window: 

%PSL printf("%c[H%c[2J",27,27); 

And you will see the screen will clear as well.

Variables

Before a variable is used in PSL, the interpreter will make sure the variable is initialized before it is used. All variables are automatically initialized to the empty string "". Although the PSL manual sometimes mentions that a certain function will return NULL, this is actually an impossible return value in PATROL. A variable can never contain NULL. The best PSL can do is an empty string. 

Some people wonder if there is a limitation to the datasize one can store in a variable. This size is limited to the memory the interpreter can get from the OS. Memory allocation for variables is dynamic and will automatically be released upon termination of the process. 

Since the storage of variables is a string, you will not be able to store 0 (null-byte characters). The interpreter will see a null-byte as a string terminator. This is something you have to be aware of when you are reading binary data from a file that can contain null-bytes. 

For every PSL process, 3 variables will be automatically defined. These are exit status, errno and PslDebug. We will explain these in later sections.

Functions

When calling functions, you will pass a copy of the value to the function (also known as call by value). There is only one exception to this, the PslExecute(); function will actually modify the arguments of the function. A function that returns data will always return a copy of the data. 

For each function one can define a set of local variables. The number of local variables is limited to 20 per function. 

If a main() function is defined then this main function is considered the starting point of execution. That means that all loose code will be ignored. If your loose code contains initializations then they will not be executed. This usually results in a lot of confusion and misunderstanding. 

A good coding style is to always have a main() function for every decent size PSL script. Don't forget to add your initialization routine to the main function in that case.

Standalone interpreter

Some people don't realize that the PSL language can be used outside of the PATROL Agent as well.Whenever you install an agent, you will see a standalone psl compiler and interpreter. This interpreter has a couple of limitations you must be aware of:

  • Can only run 1 PSL process at the same time
  • No access to the namespace
  • Some commands not available: popen, execute, system, snmp*, pconfig

Endless loop detection

There are two configuration variables that determine when the agent considers a process to be in an infinite loop:

  • pslInstructionMax
  • pslInstructionPeriod

Note

These variables and the endless loop detection not applicable for PATROL Agent versions 3.8.00 and later.

pslInstructionMax and pslInstructionPeriod work together. If a PSL process executes more than pslInstructionMax PSL instructions within pslInstructionPeriod seconds, the PSL process incurs internal scheduling delay. So both variables define the total PSL instructions a PSL process can run without the delay. 

The pslInstructionPeriod is a global timer for the agent. That means every pslInstructionPeriod seconds, all instruction counters for all PSL processes that haven't reached pslInstructionMax yet, will be reset to zero. However, if your process has reached pslInstructionMax already, it will not be reset, and the instruction counter will just continue to increase for that PSL process. 

When a process will be detuned, the agent will calculate the length of the delay in function of the total number of instructions, compared to the setting of Instruction Max. 

After a process gets on the "blacklist", it will not be removed again, so you should make sure you don't end up on that list. In case you have seen that one of your PSL process executes more than allowed on a typical agent, you have to find out if the logic of your process can't be changed, so it won't execute so much PSL functions. 

Before your program starts executing, the agent will not know if it contains an endless loop, but the agent will determine this at run time, because the instruction count was too high over the period of time. An instruction is any QUAD instruction. For example (ntharg(), cat(), ...) but also calls to user defined functions. Actually it is counting the number of virtual machine instructions, "executed" by the VM instruction set processor. (More about VM's later) 

To find out how many instructions are executed for a certain psl function, you can use the stand-alone psl compiler/interpreter: 

psl -O3P3 <your psl script> 

Then the last line from the output will be: 

[program name] [instruction count] quads, [total assigns] assigns

An Approach to KM Development

Although there are many other ways to approach KM development, the section describes the following three-step process for KM development:

  • Phase 1:
    The first step produces a self-sufficient KM and cover the primary aspects of KM development. To create a minimal, though functional KM you must develop the following:
    • Discovery - Develop the best way to find the components of the application and create an icon to represent it.
    • Parameters - Measure specific values about the application, such as its performance, capacity, and load metrics.
    • Alarm Ranges - Define numeric ranges that specify when a parameter will go into alarm because the parameter value is in a dangerous condition.
    • Menu Commands - Develop a minimal set of administrative actions that the user can perform from the console in an ad-hoc manner.
  • Phase 2:
    The second step adds polish to the KM and provide a commercial or production-level KM.
    • InfoBox commands - Define what you should display in the popup report available on the console.
    • Platform support - Make sure you check for simple requirements, such as whether the KM is running on the correct platform agent. Take the proper action in case a KM is not supported on the platform.
    • Recovery actions - Try to develop actions to correct problems that have been found. Verify if you want to have these recovery actions enabled out of the box. Usually, the KM developer will provide true diagnostic reports and offer options to run corrective actions automatically or operator driven.
  • Phase 3:
    The third and optional phase covers the harder to understand yet more powerful features a KM might have.

    • Command Types - Try to avoid the usage of system() commands. Use command types instead.
    • Channels - If it makes sense, channels can offer an efficient method of accessing data that is available through some interactive command such as an application-specific CLI
    • Libraries - Maybe you would like to eliminate duplicate code or group common user PSL functions into one file to be shared by all PSL scripts.
    • Online help - Must be provided for all KMs that will be resold

     

 

Tip: For faster searching, add an asterisk to the end of your partial query. Example: cert*