-
Notifications
You must be signed in to change notification settings - Fork 0
Avoid messages in business logic
Messages should only be sent by the main method that controls the processing.
If your code is throwing messages all over the place, you will run into issues using the logging API.
METHOD handle_use_case.
DATA(logger) = /usi/cl_bal_factory=>get_instance( )->create_new_logger( i_log_object = 'ZMY_REPORT'
i_sub_object = 'DO_SOMETHING'
i_external_id = i_input ).
DATA(token) = logger->claim_ownership( ).
some_bad_method( i_input ).
logger->save( token ).
logger->free( token ).
ENDMETHOD.
METHOD some_bad_method.
IF i_input IS INITIAL.
MESSAGE e000(38) WITH 'This message will break the log!'. " <----- BAD! DON'T DO THIS!
ENDIF.
[...]
ENDMETHOD.
As the message statement would stop PAI-processing, method handle_use_case( )
would not reach its regular end and the log would not be saved.
This would leave you with "some random error" message, but without a log.
If something should ever break the logging, the auto-save-feature might help analyzing the issue. If the package size is set to 1, the API will immediately save every message passed to the log writer.
The malicious statement will most likely be somewhere behind the code position, that created the last log message.
There are three ways to activate the feature:
Activation type | Link to documentation |
---|---|
Permanently / Transportable | Customizing -> Log Levels -> Product specific Log Level |
Temporarily / Current Setting | Customizing -> Log Levels -> User specific Log Level |
Temporarily / Current Setting | Customizing -> Log Levels -> Client specific Log Level |
The recommendation is to use User specific Log Level with package size 1 and log level 6 (Everything).
If you have to call legacy code or external APIs, that might send messages, you could encapsulate the call in a function module. If said function module has an exception 'ERROR_MESSAGE' will result in SY-SUBRC being <> 0. You can obtain the message text from the SY-MSG*-Fields in that case.
The following code avoids this issue by using object oriented exceptions.
METHOD handle_use_case.
DATA(logger) = /usi/cl_bal_factory=>get_instance( )->create_new_logger( i_log_object = 'ZMY_REPORT'
i_sub_object = 'DO_SOMETHING'
i_external_id = i_input ).
DATA(token) = logger->claim_ownership( ).
TRY.
some_better_method( i_input ).
CATCH zcx_my_exception INTO DATA(the_exception).
logger->save( token ).
logger->free( token ).
MESSAGE the_exception TYPE 'E'.
ENDTRY.
logger->save( token ).
logger->free( token ).
ENDMETHOD.
METHOD some_better_method.
IF i_input IS INITIAL.
TRY.
RAISE EXCEPTION TYPE zcx_my_exception
EXPORTING
textid = VALUE #( msgid = '38'
msgno = 000
attr1 = 'PARAM1' )
param1 = 'NOPE!'.
CLEANUP INTO DATA(exception).
usi/cl_bal_factory=>get_instance( )->get_existing_logger( )->add_exception( exception ).
ENDTRY.
ENDIF.
[...]
ENDMETHOD.
Method handle_use_case( ) is the one and only method that is allowed to use messages.
All methods, that are called by handle_use_case( ) are using object oriented exceptions instead.
This will ensure, that the regular end of method handle_use_case( ) will be reached, which gives it a fair chance to save the log.