Skip to Content
The purpose of this document is to provide best practices in order to create useful Logging and Tracing messages.

1.    Definitions

1.1  Logs

Logs are targeting administrators when they encounter some problem. Therefore logs should describe the problem in an easily understandable form. Avoid using internal terms and abbreviations in log messages. Checking component versions
Example:
The network connection has been broken
Use com.sap.tc.logging.Category to log information, warnings or errors to an administrator of a customer system.

1.2  Trace Messages

Traces are meant for developers or support engineers trying to identify a problem. They should be as detailed as possible. There is no performance impact of having additional trace statements, since traces can be switched on or off based on severity. The goal: provide nearly the same amount of information what we can collect with debugging.
Example:
New change request cannot be created when there is one with status CR_CREATED, CR_INPROCESS, CR_ACCEPTED for the same sales order id and item id
Use com.sap.tc.logging.Location to emit trace messages.

2.    Implementation

1.3  Logging

In order to perform logging, the following steps should be followed:
1: Retrieve the Category Object for logging
private static final Category category = Category.getCategory(Category.APPLICATIONS, “<APPLICATION NAME>”)
For convenience and to avoid unnecessary object creation, the following static variables are defined:
  • –          com.sap.tc.logging.Category.SYS_DATABASE
  • –          com.sap.tc.logging.Category.SYS_NETWORK
  • –          com.sap.tc.logging.Category.SYS_SERVER
  • –          com.sap.tc.logging.Category.SYS_SECURITY
  • –          com.sap.tc.logging.Category.APPLICATIONS
  • –          com.sap.tc.logging.Category.SYS_USER_INTERFACE
Security related logging should be performed using Category.APPS_COMMON_SECURITY
2: Log the message using the one of the available methods, according to the severity (e.g. infoT, debugT, warningT, errorT, fatalT)
category.infoT(location, method, “User {0} logged in”, new Object[] { user });

1.4  Tracing

Proper tracing should be implemented as follows:
1. Create a reference to a location object for tracing like this
private static final Location location = Location.getLocation(<class name>.class);

String method = “<method name>”;

Create a String variable which contains the method name in order to enable filtering for the logs of a given method in log viewer. This must be the first statement in every method, and second in constructors. Don’t set multiple times the method name in a given method. If there are multiple methods with the same name distinguish them using parameter list like this:
String method = “<method name> (String)”;

String method = “<method name> (String, String)”;
2. Output the trace message using the one of the available methods, according to the severity (e.g. infoT, debugT, pathT, warningT, errorT)
location.infoT(method, “User {0} started a new transaction“, new Object[] { user });
Because of performance reasons for printing parameters an object array should be used. Elements of the array can be inserted to the text with the following way:
This is an example text. Parameter 1 is {0}, the next parameter is {1}, the last parameter is {1}, the last parameter is {2}“, new Object[] { variable1, variable2, variable3 }
3. Trace the entry and the exit of the method in nontrivial cases. For methods throwing exceptions place the exit in the finally{..} clause.
location.entering(method);
try {
    …
} finally{
    … location.exiting(method);
}
Entering exiting pair should be used for all methods which have main business role and for important utility methods as well. Methods with limited functionality, or methods with only 1 or 2 log entries can be skipped.

4. Exceptions should be traced using the traceThrowableT method of the Location class.

try {
    …
    <BUSINESS OPERATIONS>
    …
} catch (Exception e) {
    …
    location.traceThrowableT(Severity.ERROR, method, “Error occurred while calling business operation with parameter {0}“, new Object[] { variable}, e);
    …
}

Usually in productive systems only Error level is enabled. That’s why the log message should contain the most important values which were processed when the error occurred.
If the current class cannot handle the exception and it thrown it forward; it should be logged in all level. If we filter for a given class in the Log Viewer application which is part of a call chain we won’t be able to see the exception if we don’t log it on every level.
If the given exception is related to configuration or availability of a system component/another system in the landscape instead of location it should be reported to category, because this problem can be solved by a system administrator.

5. Input Parameter Checks


If the given method has input parameter check we can report result in a warning message.
if ( inputParameter_OrderID > 5) {
    location.warningT(method, “Wrong input parameter Order Id: {0}“, new Object[] {inputParameter_OrderId});

    return;

}

6. UI Navigation
If you navigate in the Web Dynpro UI layer between pages you can log it with path severity:
location.pathT(method, “Navigate to Clientselection component“);
wdThis.wdFireEventNavigationEvent(EventSources.ES_CLIENTSELECTION, eventId);
   
It other layer/application/system is called from the code it should be logged on Path level (Webservice calls, JCO calls, etc.). This way the connections between layers and components can be investigated. If the called component is in the same software Component Info level should be used.
7. Business Code
The developers should decide what are the important steps in the code which are could be interesting mainly for developers and support engineers. Some cases the messages could be important for administrators as well.
location.infoT(method, “Get identTypeDropDownKey from context“);

ISimpleTypeModifiable myType = wdThis.wdGetAPI().getContext().getModifiableTypeOf(“identTypeDropDownKey”);

IModifiableSimpleValueSet values = myType.getSVServices().getModifiableSimpleValueSet();

 
infoT for the important values/process steps for developers.  
location.debugT(method, „Put value {0} into the list with key {1} “, new Object[] {e.getAttributeValue(“value”), e.getAttributeValue(“key”)});

values.put((String)e.getAttributeValue(“key”), (String)e.getAttributeValue(“value”));

debugT for the detailed information which can help find the exact reason of a problem. If you would like to print exact value of a variable please use location.debugT. There is one exception: calling other layers. Please follow the security restrictions as well! For example don’t insert highly confidential information into log and trace messages, for example passwords, PIN codes, etc. In ambiguous cases please contact the local security expert!

3.    Severity settings

Default severity settings should be:
–          INFO for categories (INFO and higher severity messages will be logged)
–          ERROR for locations (trace everything with severity ERROR or above)
Because of performance reasons ERROR level should be configured for categories as well in productive systems.

4.    Performance Considerations

If you have parameters, never build Strings yourself, always use the {n}-replacement:
location.infoT(method, “User {0} started transaction“, new Object[] { user });

If you have to make calculations for traces, check first if the tracing is active

if(location.beLogged(<severity>/* e.g. WARNING */) ) {  // perform calculations and do logging/tracing
}
In this case this check should be used (of course errorT should be used instead of traceThrowableT):
locationCheckIsNeeded.png

5.    Common mistakes regarding Logging and Tracing

Using Error level instead of Info:
/wp-content/uploads/2014/12/throwable_391927.jpg
Printing the content of a given variable is not an error message. Debug level trace should be used
Using Debug level instead of Error:
debugLevel.jpg
Exceptions must be logged with ERROR log level. If an exception is part of normal business behavior (for example it indicates that a function call has no result) it shouldn’t log as an exception.
Incorrect log messages:
Biplab.jpg
How this log message helps to understand what happened in the code? A good log message should be understandable for everybody even without source code.
The log message should contain as many information about the working of the program as possible. In this case Error Code and Error Description could be useful. The timestamp is by default part of the log message.
traceThrowable.png
Unhandled exceptions:
unhandledException.jpg
Unhandled exceptions will be written to System.err stream and is spams the log file. Always use traceThrowableT method with Error severity
Using wrong method to print exception details in the log:
printStackTrace.png
Using print stack trace is forbidden, because it prints the stack trace into the log in barely readable format.
/wp-content/uploads/2014/12/catching_391949.jpg
The method “catching” will report the exception to Warning level, furthermore entering of own error message is not possible.
In both cases use location.traceThrowableT method instead.
Using traceThrowableT method instead of errorT
traceThrowable.png
If there is no exception error should be reported with errorT method.
Calling exiting method in the middle of the method
/wp-content/uploads/2014/12/exiting_391951.png
Entering-exiting pair should be called only once at the very beginning and end of the method. During issue investigation the investigator will think that the method has ended.
Logging closely related data into several log entry
multiple log entries.jpg
If there are multiple variable to log which are related they should be logged into one log entry. We will see the related data in one place and the logging will be faster because the reduced number of I/O operations.
location.infoT(method, „System Number Reset \n Sales Order ID: {0}\n EOSE Plan: {1}\n Quote: {2}\n Quote Line Item: {3}\n Sales Order Item: {4}\n SEN: {5}\n SSI: {6}“, new Object[] {so.getID(), so.getPlan(), quoute.getName(), quote.getLineItem(), soItem.getId(), so.getSEN(), so.getSSI()});
Please note this is just an example code. Every value will be written into a new line so tit remains readable.
Method name abuse
methodNameAbuse.jpg
The method name should contain ONLY the method name, not the class name. In the Log Viewer application the location field will contain the class name and the method name. If the method name contains the class name as well this field won’t be readable anymore because it will be too long and contains the same data twice.
If there are more methods with the same name the parameter list can be added in order to distinguish between the methods.
Sensitive information in the log:
Printing sensitive personal data, like account balance or password is forbidden
Null pointer check is missing:
If a printed value is provided by a method of a class null pointer check for the class is mandatory.
Swallowed exception
try {
    …
} catch {
    //TODO write exception handling
}
In this case the exception won’t be visible in the log.

7.    Appendix

Official guide for Logging and Tracing
To report this post you need to login first.

6 Comments

You must be Logged on to comment or reply to a post.

  1. Kun Wu

    Very instructive blog for tracing and logging, which is actually always omitted in customer implementation…

    (0) 
  2. Matthew Vincent

    Thanks for the blog, some very useful bits of information in it.

    In some of your examples you are using location to log errors and others category. Could you clarify when you should use location and category?

    (0) 
    1. Szabolcs Menyhárt Post author

      Hi Vincent,

      you can read the purpose of Logging Categories and tracing Location in the first chapter.
      Categories should be used if your log item will be relevant for administrators, Locations should be used if you want to say something to the developers.
      So configuration changes, and issues which can be fixed by an administrator should be sent to Logging Categories.
      Not only error messages should be traced. Theoretically almost all the information should be logged what you can get via debugging, because sometimes it is not possible to debug a code on a productive system. Of course if your code is processing mass data or called really frequently chapter 4 should be taken into account.

      (0) 
  3. David Somerville

    A very useful blog. I’ve noticed a lot of developers still just use .printStackTrace().

    The Location logging ability is much more controllable and descriptive when used properly.

    (0) 

Leave a Reply