Error handling in Uniface | Uniface 9 | Forum

Avatar

Please consider registering
guest

sp_LogInOut Log In sp_Registration Register

Register | Lost password?
Advanced Search

—  Results per page  —








— Match —





— Forum Options —





Minimum search word length is 3 characters - maximum search word length is 84 characters
For a group of consecutive words like 'end of support' use Match phrase

sp_Feed Topic RSS sp_TopicIcon
Error handling in Uniface
10 Jan 2018
9:11 am
Avatar
rjanszen
New Member
Forum Posts: 2
Member Since:
07 Aug 2017
sp_UserOfflineSmall Offline

Hello Uniface developers,

This is my first post in the forums. I would like to ask a question about error handling in Uniface. More specifically, how would error handling ideally look like. Most errors can be found in $procerror(context) after certain code executions, on which code can respond accordingly. But there may also be user-written functions and services, which can encounter errors (on a low level). How should one pass along (like ‘throws’ in C# for example) such errors.

I understand that it’s the programmers responsibility to handle expected errors in their code. What I am looking for however, is a solution which is as simple and generic as possible. For example, the many possible $procerror’s (-1 to -1799) can, when encountered be returned back to a function or service’s caller in the $status. Then one can always tell what errors have occurred, and many errors can always be handled in a similar fashion (logging, notification, etc.). 

What would be the most clean and effective solution in your opinion: Is there a golden standard?

 

Thanks in advance, and kind regards,

Roel

10 Jan 2018
3:26 pm
Avatar
gianni
Member
Forum Posts: 297
Member Since:
01 Oct 2012
sp_UserOfflineSmall Offline

Hi Roel,

A gold question asking for a golden standard… 🙂

Back to reality: I think you could get many different answers to your question, each one being valuable.

The approach I am taking and have proposed to Uniface customers in the last N years (with N = 28!) is always been the following:
– Uniface is providing us an application infrastructure and when something is going wrong is giving back technological errors
– We develop application and each application should know and manage as much as possible application errors

How this logic is implemented? I’ve seen applied three modes:
– Using same $function either for Uniface and at application level, example: $status > 10000 for application errors
– Using generically $status = -1 for all application errors, together with a dedicated variable to specify which application error is happened
– Completely split the two levels: using $status for technical errors and a dedicated variable to specify which application error is happened 

This last mode is what I am currently using in my code; let’s give you an example with a service activation:
param1 = “value1”
param2 = “value2”
activate “MYSERVICE”.myoper(param1, param2, paramError)
if ($status < 0)
; Here technological errors are managed using $procerror, $procerrorcontext and so on…
endif
if (paramError != “”)
; Here application errors are managed based on string returned
endif

Usually a string returned for application errors is “CODE – Description” or only “Description”; NULL means no errors.

Hope it answers your question and helps somehow…

Regards,
Gianni

10 Jan 2018
3:35 pm
Avatar
Knut
Member
Forum Posts: 190
Member Since:
01 Oct 2012
sp_UserOfflineSmall Offline

Hi Roel – and welcome!

Based on personal experience;

You’ll need to divide your error handling into at least 3 sections;
1) Syntax errors (such as wrong format of dates / illegal characters in a numeric field)
2) DBMS/runtime errors (records don’t exist, locked by other users, columns / tables missing, wrong profile characters)
3) Business logic errors (DOB cannot be after today, DOB being mandatory or not etc etc).

Once you have these in place, then you’ll have to decide what to do…
In other words, it depends on your application and UI (PC, web, mobile app et al).
Applications created by a VAR / ISV would typically have a ‘standard’ service layer for messages – maybe
even one for each UI. Again, it depends on your application.

I personally think it’s overkill (and to be honest, ‘too big a task’) to create a ‘generic’ solution because
techology today is different from what it was 3-5-10 years ago (think ChUI and VT220) – what will it
be in 3-5 years from today…

Only my two cents worth – I’m sure other old-timers have different views. Wink

Regards,
Knut

11 Jan 2018
9:42 am
Avatar
istiller
Member
Forum Posts: 233
Member Since:
01 Oct 2012
sp_UserOfflineSmall Offline

Hi

gianni said
How this logic is implemented? I’ve seen applied three modes:
– Using same $function either for Uniface and at application level, example: $status > 10000 for application errors
– Using generically $status = -1 for all application errors, together with a dedicated variable to specify which application error is happened
– Completely split the two levels: using $status for technical errors and a dedicated variable to specify which application error is happened 

Using $status=-1 is not a good idea Wink
-1 ist the generic error of Uniface itself and will thrown e.g when a RUN went wrong

activate “MYSERVICE”.myoper(param1, param2, paramError)
if ($status < 0)
; Here technological errors are managed using $procerror, $procerrorcontext and so on…
endif
if (paramError != “”)
; Here application errors are managed based on string returned
endif

We are using both $status and $procerror:

ACTIVATE “ACOMP”.”AOPER”(v_VAL_IN,v_VAL_OUT,v_PARA,$GDA$)
IF($procerror<0)
  v_STATUS = $procerror
  call GP_ERR($procerrorcontext)  ; roughly  putmess “%%$procerrorcontext%%%”
  RETURN(v_STATUS)
ENDIF
IF($status<0)
  v_STATUS = $status
  call GP_ERR(“an Error %%v_STATUS%%% arised on activating ‘ACOMP’.’AOPER'()”)
  RETURN(v_STATUS)
ENDIF
(btw: $GDA$ stands for GlobalDataArea and will be hand over from instance to instance.)

If there is a need for extra error text, this can be done by v_PARA.
But as every error will call GP_ERR, we can log this error directly at the point of “failure”
I’m just reorganizing our error handling, so all “user defined” errors got number less then 9000
Sometimes, I do use UnifAce error numbers for logical errors like -303 for “(key) parameter is missing”.

BUT:
On think have to be considered: An error can arise at any statement in your code not only an ACTIVATE, RETRIEVE,STORE,…
Say, you retrieve a row from DBand modify some fields
CLEAR/e “ENTITY”
KEY.ENTITY/init=”akey”
RETRIEVE/e “ENTITY”  ; Assuming, the row exists
IF(xyz)
  FLD1.ENTITY=”hello”
ELSE
  FLD2.ENTITY=”hello”
ENDIF

So, where is the problem?
It’s the assignments to a field. In this very moment, UnifAce will issue a LOCK and this could fail.
Okay, the LOCK and ONERROR triggers will be called, but this did not help you to stop the program flow after the assignment.
The “proper” solution would be to add extra line after each statment to catch error.
A “workaround” could be to use READ/Lock but this is not a very good solution
Another idea is to fire LOCK at a defined position in your code, which on the other hand is sometime not easy to find

@UnifAce:
Forget about the newest “inventions” in UF 10, but  give as statements like TRY/CATCH or  ON_ERROR_GOTO

Ingo
 

11 Jan 2018
10:19 am
Avatar
Iain Sharp
Member
Forum Posts: 644
Member Since:
01 Oct 2012
sp_UserOfflineSmall Offline

We have standard input/output params on our calls (both locally and between components.)

call XXXX(v_inparams, v_outparams, v_outstatus, v_outcontext)

activate XXXX.YYY(v_inparams, v_outparams, v_outstatus, v_outcontext)

This is a hang over from the old deployment method, where changing the parameters required a new urr/dol, and ‘warm’ patching was impossible. 

inparams, outparams and context are string, and we use uniface lists to pass multiple parameters. 

outstatus is a numeric, and is basically a switch to make spotting an error simpler. 

We also test against $STATUS on activate, to ensure the component/signature is configured correctly. 

HOWEVER – our biggest problem is as Ingo says, there is no sane way to catch database locks where the program is modifying data in proc. 

It would make a lot more sense if there were try/catch or on_error_goto like settings. (Even a ‘standard’ operation like init and cleanup, we could parse the call stack to find the code involved….)

This reliance on the programmer coding in all fail states means we are vulnerable to getting bad code with no error checking in it. 

Iain

11 Jan 2018
2:07 pm
Avatar
rjanszen
New Member
Forum Posts: 2
Member Since:
07 Aug 2017
sp_UserOfflineSmall Offline

Thank you so much for your input!

@Gianni,
We can indeed make good use of what Uniface provides us with: the $procerror(context). Your method of error handling is something similar to what I have in mind. With the exception that I would like to try and simplify it a bit more. After a service activation or function call one could pass the $procerrorcontext to a global procedure. Based on the proc error (type/severity), and location of occurrence, the error can then logically be handled in one location. Moreover, with millions of lines of procscript, this is much easier to implement (or adjust in the future). I’ve tried to make an example at the bottom of this reply.

@Knut,
I absolutely agree with dividing error handling in different ‘types’ (of course again, depending on the application and it’s state). This is probably the most important reason why generic error handling will be difficult. Yet, I would still like to pursue the task, because (perhaps I should have elaborated this more) our current software has become so big, with so many high-risk calls which remain unhandled, not logged, user is not informed, etc. Even if the generic error handling will be ‘just good enough’, it would probably pay off within a short time(?)

@Ingo,
Yes! Using the Uniface error codes as service/function return code sounds like a great option. If something down the line would go wrong, pass along the error status all the way up, until it’s handled. Moreover, the locking problem you describe sounds recognizable. Without any form of error handling (e.g. log the $procerrorcontext), it becomes almost impossible to trace the root of this kind of problem, and makes the software very unstable.

@Iain,
That call structure is indeed what we are implementing more and more. I am just wondering, what advantage does the ‘outcontext’ bring? One reason I can think of, is that debugging will be much easier/faster(?). Either way, it sounds like in your situation there is a good standard definition and standard compliance. Here, that remains a challenge.

Again, thanks everyone for their thoughts on this topic. Please, feel free to give your opinion on this pseudo-code, which is how I would imagine how ‘simple and generic’ error handling would look like:

functionX :
varInteger = $date(varBoolean)
call globalErrorHandling($procerrorcontext)
return $status

functionY :
call functionX(listIn, listOut, returnCode)
if (returnCode < 0 & returnCode != -2)
.
else
.
endif

global function globalErrorHandling:
– determine severity
– (?) log(context)
– (?) inform user
– (?) …
– return $procerror

11 Jan 2018
4:31 pm
Avatar
gianni
Member
Forum Posts: 297
Member Since:
01 Oct 2012
sp_UserOfflineSmall Offline

Hi Roel,

YES! Agreed…
if ($status < 0)
; Here technological errors are managed…
listContext = “mySpecialization”
call globalErrorHandling(listContext, $procerrorcontext)
endif
if (paramError != “”)
; Here application errors are managed…
putitem/id myProcErrorContext, “ERROR”, “”
putitem/id myProcErrorContext, “MNEM”, “paramError 1st part of paramError”
putitem/id myProcErrorContext, “DESCRIPTION”, “paramError 2nd part of paramError”
putitem/id myProcErrorContext, “COMPONENT”, $componentname

listContext = “”
call globalErrorHandling(listContext, myProcErrorContext)
endif

Based on the example provided I would just add one more detail:
I agree on a generic error handling routine but for this routine as well as ALL others I suggest to have one parameter more: listContext
Both examples from Ingo and Iain are using this technique and I fully support it because:
– It will come the moment when you’ll need it… 🙂
– It is enabling to have a clear split between YOUR choices and ULAB choices when you reuse something provided from Uniface ($procerrorcontext in this example)

Gianni

25 Jan 2018
11:00 am
Avatar
sochaz
Member
Forum Posts: 173
Member Since:
01 Oct 2012
sp_UserOfflineSmall Offline

I’ll keep it very very very short…

We just use simple if ($status < 0) then…. you can then call a global error hangling proc or something to log the error, send it (email?) or anything.

As for our own statuses (error codes) we just use -1. 🙂 We have tried to use different codes, but it’s not worth the effort. And in Uniface -1 almost never happens (I mean, typical codes are -50 (activate), -7, -14 (primary key), -2 (no data), -3 (sql error) and some others).

There are 2 good things … 1) write a reasonable error message 2) include $status in the error message… Most end-users do not bother to read these messages anyway (they just press the OK button), but your support team and/or developers can read it and that status at the end of every message gives them a good hint (of what’s going wrong here).

If you have a log, log other information as well… like $procerror or $procerrorcontext, or stack or anything.

As for you example:

varInteger = $date(varBoolean)
call globalErrorHandling($procerrorcontext)
return $status

I don’t want to star a flame here (or anything), but this is typical wrong code by the beginner. Be aware that “call” is a statement itself, so it returns its own $status. That means that your last “return $status” returns the status of that call globaErrorHandling() and not the status of that $date() function. There are several ways to handle this, but one of the most effecient ways is just to store the $status in a variable.

Just my 2 cents.

Forum Timezone: Europe/Amsterdam

Most Users Ever Online: 131

Currently Online: Arjen van Vliet
10 Guest(s)

Currently Browsing this Page:
1 Guest(s)

Top Posters:

ulrich-merkel: 1756

Iain Sharp: 644

Theo Neeskens: 353

gianni: 297

rogerw: 249

istiller: 233

lalitpct: 197

Knut: 190

Arjen van Vliet: 175

sochaz: 173

Member Stats:

Guest Posters: 3

Members: 8180

Moderators: 0

Admins: 8

Forum Stats:

Groups: 1

Forums: 62

Topics: 2147

Posts: 9289

Newest Members:

Coironquife, acshvwtrf, Agalasquife, HujloS, Brajindquife, kathrinezy1, Balakquife, StevenZoosy, MiguelBeade, Jamesaccop

Administrators: admin: 23, Adrian Gosbell: 302, diseli: 927, Bob Maier: 3, Nico Peereboom: 74, Michael Rabone: 4, richiet: 406, JanCees: 28