![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() | ![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Developing exteNd Director Applications
CHAPTER 15
This chapter provides information about logging information in exteNd Director applications. It has the following sections:
exteNd Director provides a runtime logging facility that writes information in one of several standard logs or in your own custom logs. You decide what level of detail you want in the logs. The output of the logs displays on the server console.
In addition to the standard logging facility, exteNd Director includes two logging providers that let you generate:
For more information, see Using the XML and IPDR Logging Providers.
In your application code, you can log all kinds of information. Uses for logging include:
Recording errors and the application details when they occur
Auditing application usage to determine what parts of your site are most successful
Logging timing data to determine how long portions of the application take to run
Logging transactions that are also stored in your database to provide an audit trail of sales or other agreements made with users
If you use analysis tools to study your Web site usage, you can write the log in a format expected by the tools.
Various classes in exteNd Director send status and information about errors to one of the standard logs. In addition, in your code you can instantiate a log variable for one of the standard logs or for your own log and write information to it.
exteNd Director provides a log for each of the main packages. You can create additional logs in your application code when you get a log from EboLogFactory by specifying your own log identifier. The messages for all the logs are sent to the server console.
exteNd Director supports four detail levels that determine how much information is written to the log. These detail levels are defined as constants on the EbiLog interface. Framework classes only send messages to the log that are at or below the current detail level. When you write the log you specify a detail level—and if the log's detail level is lower than the message being logged, the message does not appear.
You can change the detail level for a log in the DAC or in your exteNd Director application. For information about code that changes the level, see Setting the detail level.
The information in the logs has this format:
logname | detail-level | time | thread | message
Here the separator is a vertical bar. You can change the separator character. For example, if you want to export the log to a spreadsheet, you could create a tab-delimited or comma-delimited log.
In the DAC, you can specify the detail level for each of the logs, including your custom logs. You can also define your own custom logs by adding several entries to the config.xml for the target subsystem. For example, you could add a custom log called MyLog to the Portal Web tier by adding the following property settings to the config.xml for your custom Web application:
<property> <key>MyLog.LoggingLevel</key> <value>3</value> </property> <property> <key>MyLog.LogFieldSeparator</key> <value>|</value> </property> <property> <key>MyLog.LoggingProvider</key> <value>com.sssw.fw.log.EboStandardOutLoggingProvider</value> </property>
You can also change log settings in code. For information, see com.sssw.fw.api.EbiLog and Using logs in your application next.
Some of the file generation wizards in exteNd Director include logging code. For example, when you create a new portlet using the Portlet Wizard, logging code is automatically added to the source code. The code gets a log object and writes messages at the trace level for each method. You can modify this code to get a different log. You can add logging statements that report exceptions that have been caught or that log information about the application's status. This section describes the code you would use.
You can use the exteNd Director scoped paths feature to access logs within pageflow and workflow applications.
For more information, see Working with Scoped Paths and XPaths.
The Logging API includes these classes:
com.sssw.fw.log.EboLogFactory—Use this class to get log objects
com.sssw.fw.api.EbiLog—The log object, which has methods for getting and setting the log's detail level and writing messages in the log
To get a log object for one of the standard logs, use code like this:
import com.sssw.fw.log.*; EbiLog log = EboLogFactory.getLog(EboLogFactory.PORTAL);
To create a unique log of your own, specify the log name as the argument:
import com.sssw.fw.log.*; EbiLog log = EboLogFactory.getLog("WebAppLog");
It will use the default settings, which you can change with EbiLog methods:
At any point in your code you can check or change the logging level for a log. Any changes affect future logging until the setting is changed again in code or in the DAC. For example, to set the logging level to trace, you would need to add this line of code:
log.setLoggingLevel(EbiLog.TRACE_LEVEL);
NOTE: The logging level must be set to trace if you want to see logging messages for a portlet that is generated by the Portlet Wizard, or any other wizard that generates logging code.
You can check the current level with isLevel() or one of the methods that check specific levels:
boolean traceOn = log.isLevel(EbiLog.TRACE_LEVEL); boolean traceOn = log.isTrace();
For efficiency, it is useful to check the level before logging a message, described next.
When you write code that sends a message to the log at a particular detail level, the message is logged only if the current detail is at that level or lower. If the detail level is CRITICAL_ERROR_LEVEL, when the application runs and calls trace() the message won't be logged.
Because messages won't always be logged, you can avoid the inefficiency of instantiating strings that won't be used by checking the detail level for logging the message.
For example, log.isCritical(), the lowest logging level, returns true for this logging level and higher, so critical messages are always written to the log unless logging is off.
log.isError() returns true for ERROR_LEVEL and higher, so error-level messages are logged unless the level is set to CRITICAL_ERROR_LEVEL.
To accept all logging, set the level to TRACE_LEVEL, the highest and most verbose logging level.
To log a message at a specific detail level, you can call the method for that level:
if (log.isTrace() ) { log.trace("Portlet returned content type: " + request.getContentType() ); }
In a catch block, you could log the error like this:
catch (EboException e) { log.error("General portal exception:" + e.printStackTrace(context.getLocale()) ); }
You can also call the generic logString() method and specify the level:
log.logString("message", EbiLog.ERROR_LEVEL);
You can send a message to all logs with the broadcast() method of EboLogFactory. You might use this when you want to set a mark in logs when conditions change so that you can note changes in application behavior:
EboLogFactory.broadcast("Application going into production now!");
The broadcast is sent at the critical error level so it will appear unless logging is deactivated. The message will appear once for each log.
You can identify individual sessions by including the user's ID as part of the log message. For example:
log.error(request.getUserPrincipal(getName() + log.getLogFieldSeparator() + "General portal exception: " + e.printStackTrace(context.getLocale()) );
This section shows some sample logging code that could be used in a portlet application.
If you want to use logging to observe the execution of your portlet application, you might instantiate a PORTAL log like this:
EbiLog log = com.sssw.fw.log.EboLogFactory.getLog( com.sssw.fw.log.EboLogFactory.PORTLET);
The portlet code can generate content at the trace level and can log any caught exceptions at the error level. This example shows logging in the portlet doView() method:
public void doView( RenderRequest request, RenderResponse response ) throws PortletException, java.io.IOException { try { PortletURL renderUrl = response.createRenderURL(); renderUrl.setPortletMode( PortletMode.VIEW ); PrintWriter writer = response.getWriter(); response.setContentType( EbiPortletConstants.MIME_TYPE_HTML ); // Build the screen of HTML, set it as the content StringBuffer sb = new StringBuffer(); // Output code goes here sb.append( "View Mode" ); sb.append( "<br></br>" ); writer.print( sb.toString() ); } catch (EboUnrecoverableSystemException e) { ... // code to respond to error // Error string replaces portlet content sb.replace(0, sb.length(), "msg describing what user should do"); if (log.isCritical()) { log.criticalError(this.getPortletName() + " : Bad system error \n" + e.printStackTrace() ); } } catch (EboApiException e) { ... // code to respond to error if (log.isError()) { log.error(this.getPortletName() + " : framework error \n" + e.printStackTrace() ); } } catch (EboFactoryException e) { ... // code to respond to error if (log.isError()) { log.error(this.getPortletName() + " : factory exception \n" + e.printStackTrace() ); } } catch (RuntimeException e) { ... // code to respond to error if (log.isWarning()) { log.warning(this.getPortletName() + " : runtime exception \n" + e.printStackTrace() ); } } catch ( Throwable e ) { // Log other errors generated log.error(e); new PortletException( e ); } }
If you want to collect data about the clients your users use and the pages they access, you could add this information to an APP_USAGE log, as shown in this example:
// Instantiate the log EbiLog log = com.sssw.fw.log.EboLogFactory.getLog(APP_USAGE); // log data in this format: // currentpage!browsername!browserversion!platform!callingpage java.util.Map browserinfo = context.getBrowserInfo(); StringBuffer sb = new StringBuffer(); sb.append(context.getURI() ); sb.append("!"); sb.append(getMapValue(browserinfo, EboRequestHelper.BROWSER_NAME)); sb.append("!"); sb.append(getMapValue(browserinfo, EboRequestHelper.BROWSER_MAJOR_VER)); sb.append("!"); sb.append(getMapValue(browserinfo, EboRequestHelper.PLATFORM)); sb.append("!"); sb.append(context.getCallingPage() ); if (log.isInfo()) { log.info(sb.toString() ); } // Private method to get browser information from the Map object: private String getMapValue(Map map, String key) { String val; if (map.containsKey(key)) { val = (String) map.get(key); } else { val = ""; } return val; }
Copyright © 2003 Novell, Inc. All rights reserved. Copyright © 1997, 1998, 1999, 2000, 2001, 2002, 2003 SilverStream Software, LLC. All rights reserved. more ...