![](http://habrastorage.org/getpro/habr/avatars/146/1be/bbe/1461bebbe474eed6dac6943a15efb0ab.jpg)
Another logger for SAP
Every programmer in his life should at least once write his own logger.Today I would like to tell you how to use the application log in my developments, and also offer the community another bike designed to make life a little more comfortable.
Popular saying
Thus, Application Log, also known as
SLG0
, and SLG1
...SAP standard
The application log is a great help in debugging and supporting new developments, especially background tasks, web services and interfaces using WebDynpro technologies, that is, in cases where it is not always possible or simply inconvenient to use the debugger. Magazine is standard SAP functionality, so it is always at your service.
You can view the log in a transaction
SLG1
: At the top, logs for the specified period are displayed, at the bottom - messages recorded in the selected log.
Logging
Each log has two main attributes: an object and a subobject . This allows you to share the entire mass of magazines created in the system by development area and specific application, for example: an object
Z_WEB_SERVICES
and a subobject EXCHANGE_RATE
for a service for receiving exchange rates.To maintain objects and subobjects, transaction SLG0 is used.
Step 1. The record is added in two steps: on the first screen the name of the object is determined:
![](https://habrastorage.org/files/581/9a4/c5f/5819a4c5f1334cacba06128adbe48b4d.jpg)
Step 2. Then for the new object, in the tree on the left, “Subobjects” are selected, and a subobject is created:
![](https://habrastorage.org/files/5bc/d2b/bc9/5bcd2bbc9c504a02926c16a44fc70006.JPG)
![](https://habrastorage.org/files/581/9a4/c5f/5819a4c5f1334cacba06128adbe48b4d.jpg)
Step 2. Then for the new object, in the tree on the left, “Subobjects” are selected, and a subobject is created:
How to use it
To add log support to your application, it is enough to use the following functional modules:
BAL_LOG_CREATE
- creates a new journal and returns its identifierBAL_LOG_MSG_ADD
- adds a message to the log by identifierBAL_DB_SAVE
- saves logs with the specified identifiers in the database
By the way, it
BAL_DB_SAVE
accepts a list of identifiers as input and allows you to save several logs at once.Sample code and result in SLG1 (View Log)
More about messages
In the previous examples, the log is not much different from a simple text file. However, in SAP logs, a message has a larger set of properties than date and text, and each of them can be used to filter and group records when viewing a journal, some of which are presented in the diagram:
![](https://habrastorage.org/files/68d/dc1/1b0/68ddc11b0b2349a58f46d038de74aa1e.jpg)
- Message type - the icon color when viewing the log depends on this parameter
- Importance level - entries are automatically divided into categories by this attribute
- Sorting criteria - a three-character word, a sign for grouping and sorting messages
- Level of detail - a number from 1 to 9 inclusive, can participate in filters
- Additional information - an arbitrary set of parameters and a link to a functional module or procedure for displaying it. It can be used, for example, to attach the HTTP response header of a server to a data transmission error message, or to invoke a transaction with parameters
When viewing it, it looks as follows![](https://habrastorage.org/files/39a/01b/9ca/39a01b9ca2d04aeda7aa04dfa42d5bbc.png)
![](https://habrastorage.org/files/39a/01b/9ca/39a01b9ca2d04aeda7aa04dfa42d5bbc.png)
Another logger
The more message properties are used, the more logging code grows, which is essentially secondary. To solve this problem, and just for the sake of convenience, developers often create auxiliary routines in separate inclusions or write their own functional modules and classes.
When designing my bike, I tried to find the optimal combination of functionality and convenience. It turned out to implement:
- Writing messages from classes and just text from a string
- Separation by importance, level of detail, specification of sorting criteria
- Filter messages with a specified level of detail before logging
- An easy way to define your own logic for displaying message details
Using
First you need to get an instance of the object using the static method
INSTANTIATE
. Arguments - object, subobject and external identifier:
CALL METHOD zbc_cl_log=>instantiate
EXPORTING
iv_object = gc_object
iv_subobject = gc_subobject
iv_external_id = gc_external_id
RECEIVING
ro_log = go_log.
The external identifier parameter is displayed as text in a separate column of the list of magazines and helps you find the right one with your eyes.
Logging of messages is done by the method
WRITE
:CALL METHOD go_log->write
EXPORTING
iv_type = zbc_cl_log=>info
iv_text = 'Document Source (XML)'
iv_class = zbc_cl_log=>class_additional_information
iv_level = zbc_cl_log=>level_info
iv_sort = 'XML'
iv_details = gv_xml_b
iv_viewer = 'ZBC_LOG_VIEWER_XML_XSTRING'.
The level of the message filter before writing to the log is determined using the method
THRESHOLD
, the only parameter of which can take any value from certain constants LEVEL_*
or LEVEL_NO_THRESHOLD
- in this case, all messages will be recorded. According to my observations, there are always a lot of magazines, and sooner or later there comes a moment when their mass affects the overall system performance. The level filter allows you to disable the recording of "superfluous" parts at the moment. For the transmission of message details is used
IV_DETAILS
, and the name of the functional module that is responsible for displaying the display of this data on demand - IV_VIEWER
. Inside the method WRITE
, the data transferred toIV_DETAILS TYPE ANY
, in XML with the help of transformation ID
, and at the time of accessing them when viewing, the data is unpacked and transferred to the specified function module. This approach gives rise to several features:
- the
WRITE
value supplied to the method must be of a dictionary or elementary type; - the viewing function module must declare a parameter of the same type;
- this parameter should be called
I_DATA
.
Example
If it
GV_XML_B
is of type XString, then the interface of the function module will be as follows:FUNCTION zbc_log_viewer_xml_xstring .
*"----------------------------------------------------------------------
*"*"Local Interface:
*" IMPORTING
*" REFERENCE(I_DATA) TYPE XSTRING
*"----------------------------------------------------------------------
CALL FUNCTION 'DISPLAY_XML_STRING'
EXPORTING
xml_string = i_data
EXCEPTIONS
OTHERS = 0.
ENDFUNCTION.
Instead of a conclusion
So far I have not had to try this solution on my project, and almost certainly there are bugs, shortcomings or even errors that have not yet been noticed, and I will be grateful for any comments on the development code and design. Sources are available on GitHub in the form of Nugget and Slinkee files - you can install yourself using SAPlink, an ABAP code exchange tool.
GitHub repository: https://github.com/yaruson/ZBC_LOG_UTILS
SAPlink homepage: https://www.assembla.com/spaces/saplink/wiki