Using exception classes with application log – an approach
I would like to share my approach of using exception classes and transport t100 messages inside of them. For one single message, there is nothing to talk about, you simply include the t100 interface and pass the message to the exception class. But what if you would like to pass a list of messages to the caller?
Using an application log (BAL)
In the past, I often proceeded like this: I created an object that manages the message list (the BAL_ functions). The SAP class CL_RECA_MESSAGE_LIST is great in doing this job. Then, I passed this object to the classes I invoke so these classes can collect messages there. In case of an error, I just had to use the message list to show a popup with all the messages.
The problem here is, that each caller of the class must provide a log object and all classes involved must have this global object for logging. That’s not a really big thing, but I wasn’t satisfied with the solution. So I came to a new approach, which is including the log in the exception class and passing it in this way.
The logged exception class
To try it yourself, you first need an exception class that contains a log object (based on CL_RECA_MESSAGE_LIST). Let’s go:
Add the attribute for the log. The referenced type is IF_RECA_MESSAGE_LIST
And create a getter method for the log:
Activate the class.
Demo Application
The demo application has a controller and a model class. On running, the controller instantiates the model and calls the read method. Here an error is provocated and the message is being captured in the log. Then the log is passed to the exception object.
The main controller catches the exception and uses the log object to display the error in a popup.
Here is the code:
*&———————————————————————*
*& Report ZP_TOOL_TEST_LOGGED_EXC
*&
*&———————————————————————*
*&
*&
*&———————————————————————*
report zp_tool_test_logged_exc.
class lcl_controller definition.
public section.
methods run.
private section.
methods error
importing io_log type ref to if_reca_message_list.
endclass.
class lcl_model definition.
public section.
methods read raising zcx_tool_logged.
endclass.
start-of-selection.
new lcl_controller( )->run( ).
class lcl_controller implementation.
method run.
” create model.
data(lo_model) = new lcl_model( ).
try.
lo_model->read( ).
catch zcx_tool_logged into data(lo_err).
” call error handling (which shows the log)
error( lo_err->get_log( ) ).
” show the log
endtry.
endmethod.
method error.
call function ‘RECA_GUI_MSGLIST_POPUP’
exporting
io_msglist = io_log
.
io_log->clear( ).
endmethod.
endclass.
class lcl_model implementation.
method read.
data lo_messages type ref to if_reca_message_list.
lo_messages = cf_reca_message_list=>create( ).
” provocate an error
message e000(0k) with ‘Some application error’ into sy–msgli.
lo_messages->add_symsg( ).
raise exception type zcx_tool_logged exporting mo_log = lo_messages.
endmethod.
endclass.
Some notes
The log is kept local in the model here. If your model is more complex. it might be that you collect messages in various methods. In this case, it could make sense to create a class-global log. Make sure to clear the log after having displayed the message, so no previous messages will show up (see io_log->clear( ) in method error).
As you see in read the message is created with a standard MESSAGE statement, which captures the text in a dummy variable. This makes it simple to code the message and it will also update the where-used list of the message id in your system. I find this very useful. After the MESSAGE statement, a simple call of lo_messages->add_symsg( ) puts the values of SY-MSGNO, SY-MSGID and so on into the log. Afterwards the exception is raised passing the log into the exeption object.
If you do not know yet CL_RECA_MESSAGE_LIST, it’s worth a look. It’s full of useful methods!
I've tried you approach ("local" version). Very quick to implement and also very useful.
Thank you very much for sharing.
Did you have a look at What Would a Developer-Friendly Application Log Look Like?.
The problem with the RECA wrapper is that it doesn't belong to the SAP_BASIS component, which means that not all SAP installations might have this class.
Also, if i remember correctly, the RECA wrapper doesn't have the functionality for filling up the context information.
BR,
Suhas
Oops.... 😯
Thank you for the hint! I didn't know about this fact. Infact, I created a wrapper for the application log myself, but it's polluted with much company-specific stuff, so I cannot share it here.
So this remains useful only for those who have access to this class. All readers be aware!
Hi,
I'm little confused.
What is the reason behind coupling of exception and log display?
Hello Shai,
this depends of course on your own programmng style. I normally use the application log to collect messages during the run of a program and in case of an exception (like the SAP enjoy transactions - i.e. ME21N, MIGO and others - do), I present the log to the user in order to make him understand what went wrong. Since normally multiple classes are in charge, they have to pass the selection of messages somehow. This is what the described mechanism does.
Hi Jörg,
I undestand the motive for using application log.
However, I don't understand why log display and messages handling are coupled together (e.g. method error is responsible for both log display and log/messages initialization).
How do you save your exceptions/messages in application log DB (in case you don't want to just display them to user), for example?
The model detects a problem and has to signal it to the caller. I am just using the logger class to be able to pass more than one message to the caller. The use case I intended to demonstrate is a dialogue program, where there is no need to save the log. The log is just a vehicle that can carries messages that are to be shown but not saved on DB.
OK.
At the end of the day, I guess that our different point of view is basically semantic: I prefer that the exception class will have a simple messages list and the log display will be handled by a separate object.
I go with Shai ....