PO (Process Orchestration) message monitoring could be time consuming, annoying and difficult-to-do for most SAP users, especially as PO runs on JAVA stack and there is no ABAP stack to view message logs anymore. Therefore, most users may find it difficult to access the message monitor available on the JAVA stack and also it may be very confusing to read and understand. However, it is important to monitor PO messages, to identify issues that occur during data transfers between SAP to SAP, SAP to Non-SAP and Non-SAP to Non-SAP applications, with the help of SAP PO as a middleware.
Read More: SAP PO Certification Preparation Guide
The following blog will take you through a process, to implement an ABAP program that will enable you to get the required message monitoring details from SAP PO. This program will enable SAP users to simply enter a t-code, where they will be able to view all PO success and error logs in a detailed manner.
Two API’s provided by SAP PO, a SOAP API to get the list of error messages/detailed error messages and another REST API to get the number of success, failed and scheduled messages on SAP PO.
Given below are some of the information that the program will provide you.
- Number of failed, success and scheduled messages per day.
- Detailed log on all success and error messaged logged on SAP PO.
- Reason for error.
- Time and date.
- For File and IDOC scenarios, the file name and IDOC number.
- PO message monitoring ID.
- Sender/Receiver Details.
Now let’s see as to how we could implement the above process, with the help of the two API’s given by SAP PO.
Step 1 – View list of Actions available in the SOAP API
1. Open the WS Navigator to view and test web services available on PO. The WS Navigator allows you to test a Web service without a client. Use the following URL to get into WS Navigator.
http:// <host>:<port>/wsnavigator
2. Click radio button Provider System and select “Local Java AS” from the given drop down. And enter “AdapterMessageMonitoringVi” in the search bar.
Figure 1
Once searched, select the AdapterMessageMonitoringVi interface and click “Next”.
3. The next page will display a list of Operations/Methods that we could use in the API to get the monitoring details we need.
Here, we will be using Methods getMessageList and getLogEntries to demonstrate as to how we could retrieve PO monitoring data from an outside third party application.
Figure 2
Figure 3
Step 2 – Implementation of the SOAP API
1. Standard SAP has a default proxy that is provided to get the above data from PO’s Enterprise Service Builder. Enter T-code SPROXY and find the below namespace.
Under objects, you will be able to see the following service consumer.
Figure 5
2. However, the proxy class under this standard service consumer object will not give you the methods I have mentioned above (getMessageList, getLogEntries). Therefore, we need to create a new proxy using the standard SOAP API provided by SAP, to create a new service consumer (Same objects as above). Given below is the WSDL URL to create the service consumer.
http://<host>:<port>/AdapterMessageMonitoring/basic?wsdl&mode=ws_policy&style=document
Implementation of the above service consumer will enable the two proxy methods I have mentioned earlier.
Step 3 – Implementation of the REST API
We will be consuming the REST API with the help of SAP PO itself. Given below are the steps to configure the REST API on SAP PO with the help of the REST adapter.
1. First we need to build the ESR objects to consume the REST API. For this we need to know the request and response message structure for the REST API. Given below is the link for the XSD to import the request and response structures.
http://<host>:<port>/mdt/messageoverviewqueryservlet?componen
Once imported, the external definition should look like this.
Figure 6
2. Now create an inbound service interface for the receiver with the help of the above external definition. The service interface should be as follows.
Figure 7
3. Our next step would be to create objects for SAP, who will be the sender for the request and also the receiver of the response from the REST API.
Figure 8
Figure 9
Similar to the previous step, we need to create an outbound service interface for the sender, but for the sender we need to create a message type in addition.
Figure 10
4. Now we should map the request message and response message as follows.
Figure 11
Figure 12
Here I have implemented the following UDF (Figure 14) to get value from the component. There are seven components (Figure 13) return from the API, which will be as follows under node . Component values can be accessed from 1 to 7.
Figure 13
Figure 14
5. Now create the operation mapping for the request and response message mapping.
Figure 15
6. Now let’s consume the REST API from the integration builder. Here we will be using the SR_ENTRY_OVERVIEW_XPI view to get the required data.
The component name will be different from system to system. It can be viewed using the following URL.
http://<host>:<port>/mdt/messageovervi
- R_ENTRY_VIEW_XPI – Message sorted by Receiver.
- S_ENTRY_VIEW_XPI – Message sorted by Sender.
- SR_ENTRY_VIEW_XP – Detail Message sorted by sender and Receiver.
- SR_ENTRY_OVERVIEW_XPI – Overview Message sorted by Sender and Receiver.
The URL for the REST API is as follows.
http://<host>:<port>/mdt/messageoverviewqueryservlet?component=<XIComponentName>&view=SR_ENTRY_OVERVIEW_XPI&begin={begin}&end={end}
7. Now let’s create the receiver communication channel for the REST API.
Figure 16
As visible above, the REST API URL should be inserted under the REST URL tab. Then the Pattern Variable Replacement should be entered as shown above.
NOTE: The XPath Expression should be same as the request element given in the message mapping.
Figure 17
Next, the rest operation should be set to GET.
Figure 18
Finally, enter the PO username and password for basic authentication.
Figure 19
8. Rest of the steps would be similar to a normal scenario where a SOAP communication channel needs to be created for the receiver (SAP) and integration configuration needs to be created to link all objects.
Step 4 – Consuming both API’s from ABAP
The ABAP program will consume both APIs and create the following internal table using deep structures. As you see below, it will show the number of error, success and still processing messages in the PO monitor. It also gives the sender, receiver details.
Figure 20
The “DETAIL_MESSAGE” deep structure will provide the PI message ID and the file name/IDOC number respectively.
Figure 21
The “SUB_MESSAGE” deep structure will contain log details, if there are any errors logged in.
Figure 22
Attached below is the ABAP code I have written to consume results from both API’s, into ABAP internal tables.
class lcl_pimoni definition final.
public section.
constants: gc_error type char1 value 'E',
gc_success type char1 value 'S',
gc_ricef_id type zvariable_name value 'PI_MONI_INTERFACE',
gc_maxcount type int4 value 999999999,
gc_filteridoc type string value 'Processing IDoc document with number' ##NO_TEXT,
gc_filterfile type string value 'FILE_SUC_029' ##NO_TEXT,
gc_proxy type srt_lp_proxyclass value 'ZCO_ADAPTER_MESSAGE_MONITORING'.
methods:
constructor importing iv_fdate type sydats
iv_tdate type sydats.
private section.
types: begin of ty_log,
sender_interface type zmessage_interface,
message_key type string,
message_id type string,
sender_name type string,
receiver_name type string,
end of ty_log.
methods:
prepare_data importing iv_fdate type sydats
iv_tdate type sydats
returning value(re_data) type zget_message_list_in_doc,
get_message_count importing iv_fdate type sydats
iv_tdate type sydats
returning value(re_logcount) type zmt_moni_message_count_res,
get_date importing iv_date type sydats
returning value(re_date) type xsddatetime_z,
determine_idoc_file importing it_log type zaudit_log_entry_data_tab
iv_messageid type string
returning value(re_msgid) type string,
conver_time_stamp importing iv_timestamp type xsddatetime_z
returning value(re_time) type syst_uzeit.
endclass.
class lcl_pimoni implementation.
method constructor.
data: is_out type zmt_monitor_log_out,
lt_maindata type table of ty_log,
lt_outputdata type zdt_monitor_log_out_detail_tab.
"Get Sender Interface names from Parameter table
zcl_nka_util=>get_ricef_variables( exporting iv_ricef = gc_ricef_id
importing et_db_vars = data(lt_interface) ).
try.
"Retrive logical port name to get list of messages
data(proxy) = cl_srt_wsp_ws_admin_manager=>get_mapping_targetlp_valuehelp( i_target_proxy = gc_proxy
i_mapping_name = gc_proxy ).
"Instantiate new object to get list of messages
data(lo_monilog) = new zco_adapter_message_monitoring( logical_port_name = value #( proxy[ 1 ]-lp_name optional ) ).
"Retrieve all Error message details from PI, between from date and to date
lo_monilog->get_message_list( exporting input = prepare_data( iv_fdate = iv_fdate
iv_tdate = iv_tdate )
importing output = data(lt_data) ).
"Get only required elements for message processing
lt_maindata = corresponding #( lt_data-response-list-adapter_framework_data ).
if lt_maindata is initial.
message text-003 type gc_success.
return.
endif.
"Get log count details from PI, between from date and to date
loop at get_message_count( iv_fdate = iv_fdate
iv_tdate = iv_tdate )-mt_moni_message_count_res-row_data assigning field-symbol(<lfs_logcount>).
loop at lt_maindata assigning field-symbol(<lfs_data>) where sender_interface-name = <lfs_logcount>-interface
and receiver_name = <lfs_logcount>-receiver_component
and sender_name = <lfs_logcount>-sender_component.
"Get details message for each message
lo_monilog->get_log_entries( exporting input = value zget_log_entries_in_doc( message_key = <lfs_data>-message_key
archive = space
older_than = get_date( iv_tdate ) )
importing output = data(lt_log) ).
"$. Region Filter only error messages and remove duplicate messages
sort lt_log-response-audit_log_entry_data ascending by text_key.
delete adjacent duplicates from lt_log-response-audit_log_entry_data comparing text_key.
"$. Endregion Filter only error messages and remove duplicate messages
"Add details error message to internal table, to be passed as a deep structure
append value zdt_monitor_log_out_detail_mes( msg_key = <lfs_data>-message_id
uid = determine_idoc_file( it_log = lt_log-response-audit_log_entry_data
iv_messageid = <lfs_data>-message_id )
sub_message = value zdt_monitor_log_out_sub_me_tab( for ls_output in lt_log-response-audit_log_entry_data
where ( status = gc_error )
( textkey = ls_output-text_key
msg_type = ls_output-status
msg_text = ls_output-localized_text
date = iv_fdate
time = conver_time_stamp( ls_output-time_stamp ) ) ) ) to lt_outputdata.
endloop.
"Add final data to outbound structure
append value zdt_monitor_log_out_monitorlog( interface_id = value #( lt_interface[ val1 = conv zselection_val1( <lfs_logcount>-interface ) ]-val2 optional )
sender = <lfs_logcount>-sender_component
receiver = <lfs_logcount>-receiver_component
si_name = <lfs_logcount>-interface
error = <lfs_logcount>-error
success = <lfs_logcount>-successfull
schedule = <lfs_logcount>-scheduled
detail_message = lt_outputdata ) to is_out-mt_monitor_log_out-monitorlog.
refresh: lt_outputdata.
endloop.
catch cx_ai_system_fault into data(lv_exc).
message lv_exc->get_text( ) type gc_success.
endtry.
endmethod.
method determine_idoc_file.
"Retrieve IDOC number
loop at it_log assigning field-symbol(<lfs_log>) where text_key cs gc_filteridoc.
re_msgid = <lfs_log>-text_key+37(16).
return.
endloop.
"Retrive File name in file scenario
loop at it_log assigning <lfs_log> where text_key cs gc_filterfile.
re_msgid = <lfs_log>-localized_text+18(40).
return.
endloop.
"If IDOC number or File Name not available, return PI message ID
if re_msgid is initial.
re_msgid = iv_messageid.
endif.
endmethod.
method prepare_data.
"Preperation of input parameters to get message list
re_data = value zget_message_list_in_doc( filter-archive = abap_false
filter-date_type = 4
filter-node_id1 = 0
filter-only_faulty_messages = abap_false
filter-retries = 0
filter-retry_interval = 0
filter-times_failed = 0
filter-was_edited = abap_false
max_messages = gc_maxcount
filter-from_time = get_date( iv_fdate )
filter-to_time = get_date( iv_tdate ) ).
endmethod.
method get_date.
call function 'CACS_DATE_GET_TIMESTAMP'
exporting
i_date = iv_date
importing
e_timestamp = re_date
exceptions
date_not_filled_but_time = 1
date_has_no_valid_format = 2
others = 3.
if sy-subrc <> 0 ##NEEDED.
"This is unlikely to occur.
endif.
endmethod.
method get_message_count.
try .
data(lo_rest) = new zco_si_moni_message_count_out( ).
"Get Error, Success and Schedule message count from PI server
lo_rest->si_moni_message_count_out( exporting output = value zmt_moni_message_count_out( mt_moni_message_count_out-start_time_stamp = iv_fdate
mt_moni_message_count_out-end_time_stamp = iv_tdate )
importing input = re_logcount ).
catch cx_ai_system_fault into data(lv_error).
message lv_error->get_text( ) type gc_success.
endtry.
endmethod.
method conver_time_stamp.
convert time stamp iv_timestamp time zone sy-zonlo
into time re_time.
endmethod.
endclass.
By looking at the above SAP ABAP and SAP PO Integration API’s, we can see how easily we could develop a simple but detailed custom PI Monitoring log. Both API’s could also be called by an external system where an external application will have access to SAP PO message monitoring.