When the user receives a message in the infolog, he is interrupted in his work. It is crucial for the user to be guided in the best possible manner, so he can continue his work.

Use short informative messages

Give the user a message he can use. Do not use error codes or similar and do not use long, hard-to-read, time-consuming-to-read messages. Give the user a message to help him along, not to disturb him unnecessary. 

Set the right level

Most important of all is it to set the right exception level of the message. You have 3 levels to choose from: Info, warning and error.

Info is used to give the user important information not requiring any action to be taken. They are shown with a blue "i" (for information)
is used to warn the user when critical situation occurs. They are shown with a yellow expression sign.
is used when a fatal error occurs that and the user has to take action. The symbol used is a red stop sign.

You must also set the right context of the message. The message itself should not contain any context information, it should be placed as a header for the messages. To set the message you use the SetPrefix method. It automatically keeps track of the context using the execution stack - in other words just set the prefix in top of your job and you should be fine.


static void TheRightLevel(Args _args)

    real x;
    setPrefix("1 / x");
    for (x=-1; x<=1; x+=0.1)
        setprefix(strfmt("x = %1", x));
        if (x == 0)
            error ("Division by zero");
            if (abs(1/x) > 3)
                warning ("Close to tangent");
            info (strfmt("1/x = %1",1 / x));

Link to the help system

The first step is to deliver the right message to the user. The next step will be to give further information. This is why you can supply a help system url to each message. When the user double clicks at the message he will be taken to the help system and given further information. The help topic should contain problem-solving or background information.

The url is the second parameter of the message methods:

static Exception info(
    SysInfoLogStr txt,
    url helpUrl = '',
    SysInfoAction _sysInfoAction = null);

static Exception warning(
    SysInfoLogStr txt,
    url helpUrl = '',
    SysInfoAction _sysInfoAction = null);

static Exception error(
    SysInfoLogStr txt,
    url helpUrl = '',
    SysInfoAction _sysInfoAction = null);

A url could be: "ApplDoc:\\Forms\CustTable". When editing a help topic, you can see the topic's url in the caption.


error("Function SubStr called with wrong parameters", 'KernDoc:\\\\Functions\\substr');

Use actions

The final step is to actually help the user solve his problem. It could either be by directing his focus at the problem or by solving it - if possible. An example could be the message: "You password expires today". The appropriate action would be: "Click here to change your password". 

To create an action you must first create a class that extends SysInfoAction (or use one of the classes that already does). The class must at least have these methods:

Description which gives the action a name, which is used in the context menu of a message. It could be: "Change Password".
returns a container. This must contain all necessary information about the action. It could be the user id.
which takes the container above and re-instantiate the class. Just like in RunBase. It could be: userId = conpeek(packedClass, 1)
Run which performs the action. If could be: Change_Password (userId)

The standard have action classes for:

  • Opening the source editor, used e.g. in best practice
  • Opening the property editor, used e.g. in best practice
  • Opening a formRun, used e.g. when not filling out a mandatory field.
  • And more.

If an action is supplied with the message it will overrule the link to the help. So all the user has to do is double click the message and the action will be carried out. If he wants the help information instead, he will have to right click on the message and choose Help.


error("Function SubStr called with wrong parameters",
    new SysInfoAction_Editor('Classes\\Global\\str2capital',3,19));

Limit the number of messages

If you are in a situation where you can drown the user in messages, you might consider to use:

int errorsPerBatch(int number = errorsPerBatch)

This will limit the number under each header.

It is extremely useful e.g. during a data import, where several thousand errors could occur on just one table if it already contained the record. The user would be no wiser, if we showed him 1000 messages saying: "Record already exists". Instead we should show him only the ten first for each table. He would have to take a look at these tables anyway, because data not is complete.

There is also the memory usage aspect of this feature. A message in the infolog allocates memory, this is a way to avoid running out of memory.

Note, that you do not have to reset the value, as it is done when the infolog is displayed.


static void LimitTheNumber(Args _args)
    Dictionary dictionary = new Dictionary();
    DictTable dictTable;
    TableId tableId;
    int i,j;
    setprefix("Data Import");
    for (i=1; i<=dictionary.tableCnt(); i++)
        dictTable = dictionary.tableObject(dictionary.tableCnt2Id(i));
        for (j=1;j<=15; j++)
            error("Record already exists");


It does not stop here. With a little practice you can make the infolog a part of the dialog flow. Like in the change password example, the message and the action had become a part of the users periodically workflow.

The final words of this article must be a kind request to all developers. Please help the user solve his problem, instead of just dumping it in his lap !