Logging Guidelines for Developers

Overview

You should utilize logging APIs frequently throughout your components. This will aid in localizing problems if a bug is reported. We recommend that you carefully select where you place logging calls, keep your code readable, and put only useful and necessary information into log messages.

The log message text, module source, and severity come directly from you through the coding of the APIs. These three fields cannot be changed or amended other than through the code, so aim to make the information as informative and concise as possible.

As a developer, you only need familiarize yourself with a few APIs and the six severities. Call the appropriate API and pass in the following three fields:

All other fields are automatically populated by the APIs.

APIs

The following APIs are used to write log messages to the database:

When the APIs write to the database, they typically communicate with the package FND_LOG_REPOSITORY. This package is what actually writes the messages. When debugging middle-tier edge cases, log messages can be sent to a file.

Handling Errors

Use the following procedure to handle errors in your code:

Step 1: Log internal error details (for example: Exception Stack Trace, relevant state information). These details will be used by system administrators, support personnel, etcetera to diagnose the issue.

Step 2: If the error is severe, then raise a System Alert to notify the system administrator.

Step 3: If the error affects the end user, report the error to the end user through the UI (or through a Request Log in the case of a concurrent program). The message should be a translatable user-friendly message, and should not contain any internal error details.

Performance Standards

For performance reasons, you are required to check if logging is enabled for the severity of your message. This should happen before you create any objects or concatenate any strings that form your log message. Checking the value of an integer is less costly than allocating objects or concatenating strings. Remember that function arguments are constructed before the function call. That is, a string concatenation would occur before the Log write*(..) call is made! You should explicitly check if logging is enabled to prevent string creation when logging is disabled.

Sample Java Code

if( AppsLog.isEnabled(Log.EVENT) )
  AppsLog.write("fnd.common.WebAppsContext", str1 + str2, Log.EVENT);  

Sample PL/SQL Code

if( FND_LOG.LEVEL_PROCEDURE >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
    FND_LOG.STRING(FND_LOG.LEVEL_PROCEDURE, 
        'fnd.plsql.MYSTUFF.FUNCTIONA.begin', 'Hello, world!' );
end if;

Furthermore, you can use a local variable when inside a tight loop or branch of code that is not sensitive to a context switch for the life of the branch. This avoids accessing a package global variable, which is more expensive than a local variable. See the following example:

procedure process_rows () 
  l_debug_level number:=FND_LOG.G_CURRENT_RUNTIME_LEVEL; 
  l_proc_level number:=FND_LOG.LEVEL_PROCEDURE; 
   begin 
          for loop 
              validation... 
              other calls... 
               if ( l_proc_level >= l_debug_level ) then 
                   fnd_log.... 
              end if; 
          end loop; 
    end; 

Use a similar optimization for Java and C code wherever possible.

Note: Changes in the Oracle Application Object Library Session (for example, switching responsibilities) can cause the Log Profile values to change. In such scenarios, the Oracle Application Object Library will correctly update FND_LOG.G_CURRENT_RUNTIME_LEVEL, and corresponding values in C and Java as well. However, if you have cached the value in your code, you may not see this change.

Module Source

The Module Source is a hierarchical identifier for a particular code block. The main purpose of the Module Source is to:

For consistency, all module names must be constructed according to the following rules. The module name identifier syntax is as follows:

<application short name>.<directory>.<file>.<routine>.<label>

Each syntax component is described in detail below.

<application short name>

Indicates the owner application of the code block, specified in lowercase. For example: fnd, jtf, wf, sqlgl, inv.

<directory> | <package>

Indicates the directory or package where the file lives. In general, this is the actual file system directory name. Usually the directory has just one component, but in some cases, it may have two or more components. In Java, this is the full package name. See the following table for examples with their languages and formats.

Examples of File Locations
Language Format Example
Java dir[.subdir] commonfunctionSecurity.client
C <src>.dir Src.flex
Library PL/SQL Resource Resource
Forms PL/SQL Forms Forms
Reports PL/SQL Reports Reports
Server PL/SQL Plsql Plsql
Loaders Loaders Loaders

<file> | <Class>

Indicates the patchable entity (file) that contains the code. In the case of server PL/SQL, this is the package name rather than the file name. In Java, it is the class name. See the following table for examples with their languages and formats.

Code Entity Examples
Language Format Example
Java <ClassName> WebAppsContext
C <filename> Fndval
Library PL/SQL <library name> FNDSQF
Forms PL/SQL <form filename> FNDSCAPP
Reports PL/SQL <report filename> FNDMNMNU
Server PL/SQL <packagename> FND_GLOBAL
Loader <section> Afsload

<routine>

Indicates the code routine, procedure, method, or function. In the case of Oracle Forms or Oracle Reports code where there is no routine name, this may be the trigger name. See the following table for examples with their languages and formats..

Routine Examples
Language Format Example
Java <method> ValidateSession
C <function> Fdfgvd
Library PL/SQL <package.function> FND_UTILITIES.OPEN_URL
Forms PL/SQL <package.function> BLOCK_HANDLER.VALIDATE_NAME
Forms PL/SQL <function> DETERMINE_NEXT_BLOCK
Forms PL/SQL <trigger> PRE-FORM
Reports PL/SQL <function> LOOKUP_DISPLAY_VALUE
Reports PL/SQL <trigger> BEFORE_REPORT
Server PL/SQL <function> INITIALIZE
Loader <action>_<entity> UPLOAD_FUNCTION

<label>

Is a descriptive name for the part within the routine. The major reason for providing the label is to make a module name uniquely identify exactly one log call. This allows support analysts or programmers to know exactly which piece of code produced your message, without needing to look at the message (which may be translated). Therefore, you should make labels for each log statement unique within a routine.

For grouping a number of log calls from different routines and files that can be enabled or disabled automatically, a two-part label can be used. The first part is the functional group name, and the second part is the unique code location.

For example, Oracle Application Object Library (FND) descriptive flexfield validation code might have several log calls in different places with labels, such as:

These could all be enabled by setting the module as "fnd.%.desc_flex_val.%", even though they may be in different locations in the code.

Messages logged at the PROCEDURE level should use the label "begin" for the message logged upon entering and "end" or some variation thereof (like "end_exception") for the message logged upon exiting. For example: begin, end, lookup_app_id, parse_sql_failed, or myfeature.done_exec.

Module Name Standards

Use the guidelines below to ensure that your code meets the requirement for unique module names across all applications.

Module Name Examples

Severities

For a table that summarizes the available log severities and their usage, refer to the section AFLOG_LEVEL.

STATEMENT and PROCEDURE are intended for debugging by internal Oracle development only. The higher severities, EVENT, EXCEPTION, ERROR and UNEXPECTED, have a broader audience. We encourage you to monitor and attempt to resolve ERROR and UNEXPECTED messages.

Log all internal and external failure messages at EXCEPTION, ERROR, or UNEXPECTED. ERROR and UNEXPECTED messages should be translatable Message Dictionary messages.

Determining where to insert log messages can be an iterative process. As you learn more about your code usage, you gain a better understanding of where to insert log messages that would quickly help isolate the root cause of the error. At a minimum, you should log messages for scenarios described in the next sections.

UNEXPECTED

This severity indicates an unhandled internal software failure which typically requires a code or environment fix.

Log any unrecoverable errors that could occur in as UNEXPECTED. Be very selective in using the UNEXPECTED severity in Message Dictionary-based messages, as messages logged with this severity can be automatically propagated to system administrators as System Alerts. While all log messages should be concise and meaningful, UNEXPECTED messages in particular should be thoughtfully created and reviewed so system administrators can quickly understand the error.

ERROR

This severity indicates an external end user error which typically requires an end user fix.

Log all user error conditions as ERROR. System administrators may choose to enable logging for ERROR messages to see the errors their users are encountering.

ERROR messages should use the Message Dictionary and be seeded in FND_NEW_MESSAGES. If the corresponding error is encountered during runtime, the message must be logged, and if applicable, displayed appropriately. For details, please see the section Automatic Logging and Alerting for Seeded Message Dictionary Messages.

Include the following in ERROR and UNEXPECTED messages:

EXCEPTION

This severity indicates a handled internal software failure which typically requires no fix.

Java exceptions should always be logged. Java exceptions are never part of the normal code flow, and hence should never be ignored. Exceptions should be handled appropriately in your code, and logged for debugging purposes. Whenever you raise an exception, log the cause of the exception first. Convenience log APIs are provided to allow you to pass an exception object in place of the message text. If no severity is passed, then Java exceptions are by default logged at severity EXCEPTION.

Severe exceptions that prevent your product from functioning should be logged at severity UNEXPECTED. For example, log a SQLException when a user places a new order as UNEXPECTED.

EVENT

This severity is used for high-level progress reporting. These apply to application milestones, such as completing a step in a flow, or starting a business transaction.

Whenever your application code reads configurable values, the configured values must be logged. The value may be obtained from profiles, already known attributes of an object (for example, the customer's primary address), defaulting rules, and so on. Log the source, name, and value. For consistency, the label within the module field of such messages should be appended with ".config". For example, "fnd.common.MyClass.MyAPI.config"

PROCEDURE

This severity is used for API-level progress reporting.

Log key functions and APIs as PROCEDURE. The module name for such messages should contain the function or API name, "begin" at the beginning of the procedure, and "end" at the end. For example, the validateSession(..) API is a key API that logs a message at the beginning of the API with module name, "fnd.common.WebAppsContext.validateSession.begin", and the end, "fnd.common.WebAppsContext.validateSession.end".

Whenever you override any base class methods, you must log a message in your derived class's implementation.

The message body should contain the key input values, state values, and return values. For example, log input and output for all controllers, Request, FormRequest, FormData methods.

Log messages at integration points, especially when calling another application's API. Also, use logging when calling procedures across application layers. For example, when calling a PL/SQL API from the Java layer.

STATEMENT

This severity is used for low-level progress reporting.

If you generate SQL (dynamic SQL), it must be logged.

Log all bind variables.

Any user interface choice or dynamic modification of the user interface must be logged. For example, use of "switcher" beans, or page forwards.

Where appropriate, include relevant state variables.

Large Text and Binary Message Attachments

You can use Message Attachment APIs to add additional context information to log messages and/or System Alerts. This feature provides efficient buffered writing APIs for logging large attachments. The seeded message text for such attachments should contain a brief description of the error, and the attachment should contain all relevant context details.

Currently attachments are stored in a database LOB. You can view attachments through Oracle Applications Manager.

Java Code

oracle.apps.fnd.common.AppsLog:
    getAttachmentWriter(String, Message, int); // For text data
    getBinaryAttachmentWriter)String, Message, int, ...); // For binary data

For example:

if(alog.isEnabled(Log.UNEXPECTED)) 
{ 
  AttachmentWriter attachment = null;
  Message Msg = new Message("FND", "LOGIN_ERROR"); 
  Msg.setToken("ERRNO", sqle.getErrorCode(), false); 
  Msg.setToken("REASON", sqle.getMessage(), false); 
  try 
  { 
    // 'alog' is instance of AppsLog (not anonymous) 
    attachment = alog.getAttachmentWriter(
"fnd.security.LoginManager.authenticate", Msg, Log.UNEXPECTED); 
    if ( attachment != null ) 
    { 
      // Write out your attachment 
      attachment.println("line1"); 
      attachment.println("line2"); 
      attachment.println("line3"); 
    } 
  } catch (Exception e) 
  { 
    // Handle the error 
  } finally 
  {
    // You must close the attachment!
    if ( attachment != null )
      try { attachment.close(); } catch (Exception e) { }
  } 
}

PL/SQL Code

FND_LOG.MESSAGE_WITH_ATTACHMENT(..);
FND_LOG_ATTACHMENT.WRITE(..); // For text data
FND_LOG_ATTACHMENT.WRITE_RAW(..); // For binary data

For example:

if( FND_LOG.LEVEL_UNEXPECTED >=
    FND_LOG.G_CURRENT_RUNTIME_LEVEL) then
  FND_MESSAGE.SET_NAME('FND', 'LOGIN_ERROR'); -- Seeded Message
  -- Runtime Information
  FND_MESSAGE.SET_TOKEN('ERRNO', sqlcode); 
  FND_MESSAGE.SET_TOKEN('REASON', sqlerrm); 
  ATTACHMENT_ID := ND_LOG.MESSAGE_WITH_ATTACHMENT(FND_LOG.LEVEL_UNEXPECTED, 'fnd.plsql.Login.validate', TRUE); 
  if ( ATTACHMENT_ID <> -1 ) then
    FND_LOG_ATTACHMENT.WRITELN(ATTACHMENT_ID, "line1");
    FND_LOG_ATTACHMENT.WRITELN(ATTACHMENT_ID, "line2");
    FND_LOG_ATTACHMENT.WRITELN(ATTACHMENT_ID, "line3");
    -- You must call CLOSE
    FND_LOG_ATTACHMENT.CLOSE(ATTACHMENT_ID);
  end if;
end if;

Automatic Logging and Alerting for Seeded Message Dictionary Messages

Seeded Oracle Application Object Library Message Dictionary messages can be made automatically loggable and automatically alertable by setting the corresponding message metadata attributes.

At runtime, when the Oracle Application Object Library Message Dictionary APIs are invoked to retrieve these messages in translated format, they will also be internally logged or alerted if the current log configuration permits it.

To be automatically logged, the seeded message's "Log Severity" attribute must be greater than or equal to the configured log level.

To be automatically alerted, the seeded message's "Alert Category" and "Alert Severity" attributes must be defined, and the log configuration should be enabled at least at the 6-UNEXPECTED level.

General Logging Tips

How to Log from Java

AppsLog is the class that provides core logging functionality. The Oracle CRM Technology Foundation provides convenient wrapper APIs around AppsLog. This section describes how to use AppsLog and the wrapper APIs.

Core AppsLog

In Java, the core Oracle Application Object Library (FND) logging functionality is provided by the oracle.apps.fnd.common.AppsLog class. A number of convenience wrappers are available.

AppsLog is a thread-safe class that allows multiple users and threads to log messages concurrently. AppsLog objects are typically created and configured based on a user's log profile settings during the initialization of a user's Oracle Application Object Library session. Note that AppsLog is not a static singleton class. As different users can have different log profile settings, multiple AppsLog objects will exist within a JVM.

Take care to use the correct AppsLog instance, as there can be multiple concurrent threads and users. Try first to use the current user's AppsContext, and call getLog() on it to get the AppsLog instance. AppsContext's AppsLog is fully initialized based on the current user's log profile settings and Java system properties. Depending on its configuration, it can log to either the database or a file. Do not create static references to this fully initialized AppsLog. Use APIs to get the appropriate AppsContext's AppsLog instance every time.

In edge-case scenarios (for example, before an Oracle Application Object Library session is fully initialized and there is no AppsContext available), you can call static AppsLog.getAnonymousLog() to get a standalone AppsLog that is anonymous, initialized only based on Java system properties, and can log only to a file.

Code Sample

public boolean authenticate(AppsContext ctx, String user, String passwd) 
    throws SQLException, NoSuchUserException {
    AppsLog alog = (AppsLog) ctx.getLog();
    if(alog.isEnabled(Log.PROCEDURE))  /*To avoid String Concat if not enabled */
    alog.write("fnd.security.LoginManager.authenticate.begin", 
        "User=" + user, Log.PROCEDURE);
    /* Never log plain-text security sensitive parameters like passwd! */
    try {
        validUser = checkinDB(user, passwd);
    } catch(NoSuchUserException nsue) {
        if(alog.isEnabled(Log.EXCEPTION))
        alog.write("fnd.security.LoginManager.authenticate",nsue, Log.EXCEPTION);
         throw nsue; // Allow the caller Handle it appropriately
        } catch(SQLException sqle) {
        if(alog.isEnabled(Log.UNEXPECTED)) { 
        alog.write("fnd.security.LoginManager.authenticate", sqle, Log.UNEXPECTED);
        Message Msg = new Message("FND", "LOGIN_ERROR"); /* System Alert */
          Msg.setToken("ERRNO", sqle.getErrorCode(), false);
          Msg.setToken("REASON", sqle.getMessage(), false);
          /* Message Dictionary messages should be logged using writeEncoded(..)
            * or write(..Message..), and never using write(..String..) */
        alog.write("fnd.security.LoginManager.authenticate", Msg, Log.UNEXPECTED);
    }
    throw sqle; // Allow the UI caller to handle it appropriately
    } // End of catch(SQLException sqle)
    if(alog.isEnabled(Log.PROCEDURE)) /* To avoid String Concat if not enabled */
        alog.write("fnd.security.LoginManager.authenticate.end", "validUser=" + validUser, Log.PROCEDURE);
    return success;
    }

OAPageContext and OADBTransaction APIs

The classes oracle.apps.fwk.util.OAPageContext and oracle.apps.fwk.util.OADBTransaction delegate log calls to the AppsLog class. To make logging calls in a UI controller, use OAPageContext. To make logging calls from an application module, use OADBTransaction.

The following are the main logging APIs provided:

isLoggingEnabled(int logLevel)

This returns true if logging is enabled for the given log level. In all cases, test that logging is enabled before creating a message and calling the writeDiagnostics method.

writeDiagnostics(Object module, String messageText, int logLevel)

This writes log messages to the database. Remember that each log message includes a log sequence, user ID, session ID, module identifier, level, and message.

CRM Technology Foundation APIs

The class oracle.apps.jtf.base.Logger delegates log calls to the AppsLog class. The following are the main logging APIs provided:

Logger.out(String message, int severity, Class module);

Use this API to log your message. The message length can be up to 4000 characters. For example:

public class MyClass {
…
public boolean myAPI() {
  …
  if(Logger.isEnabled(Logger.STATEMENT)) // Important check for Performance!
    Logger.out("My message", Logger.STATEMENT, MyClass.class);
}
}

Logger.out(String message, int severity, Object module);

In situations where the "Class" is not available (such as when writing a JSP), you can use this API and pass in a String. The message length can be up to 4,000 characters. For example:

<%  if(Logger.isEnabled(Logger.ERROR))  // Important check for Performance!
      Logger.out("In JSP land use the JSP Name", Logger.ERROR, 
"jtf.html.jtftest.jsp"); %>

Logger.out(Exception e, Class module);

Use this API to log an exception. If the "Class" is not available, you can pass in the String object. If the exception length is greater than 4,000 characters, then the exception is split and logged in multiple rows. By default, all exceptions are logged at severity EXCEPTION. If you would like to log an exception at a different severity, you can use the corresponding APIs that take the severity as one of the arguments.

For example:
Logger.out(Exception e, int severity, Class module);

Note: Do not specify integer values (1, 2, 3, etc.) in your calls to Logger APIs. Instead, refer to the severity level by the appropriate name:

Logger.STATEMENT

Logger.PROCEDURE

Logger.EVENT

Logger.EXCEPTION

Logger.ERROR

Logger.UNEXPECTED

AppletLog (Applet Client Desktop) Logging

For logging in Client-side Desktop Applets, you must use the FND AppletLog Class available in 'fndctx.jar'. Use of AppsLog in Applets is not supported.

AppletLog is a simple wrapper around System.out that logs to the Java console. You can control logging by setting 2 Java System Properties (AFLOG_ENABLED, AFLOG_LEVEL) in the Java Console.

You need to configure these values for the specific JRE version that is running the Applet. Navigate to Control Panel -> Java -> Java Tab -> Java Runtime Parameters (Double-click in the text area to enter values). You can also bring up the Java Console from the Windows Icon tray (in the Taskbar) by right-clicking on the Java icon while your Applet is running. The JRE version can be determined by double-clicking on the Java icon.

the picture is described in the document text

Code Sample:

import oracle.apps.fnd.common.logging.client.AppletLog;
...
...
AppletLog log = AppletLog.getAnonymousLog();
if (log.isEnabled(AppletLog.STATEMENT))
  log.write(TreeViewer.class, "Rendering node=" + leaf, AppletLog.STATEMENT);  

By default logging is enabled at the UNEXPECTED level.

Read the Developer Usage Guidelines, and ensure that you fully understand and follow the standards correctly. Do not use AppletLog for middle-tier logging.

Note: AppletLog has been tested to work correctly with Signed Applets (all Applets formally installed/patched as part of Ebiz Suite are Signed Applets) and default Browser Security settings. If you attempt to use AppletLog with unsigned Applets or with custom browser security settings, you may encounter a Java Security Exception when AppletLog attempts to read Java System Properties to configure itself. Adjusting your browser security settings may help you work around this. (Refer to the Microsoft IE Browser Java Security Settings at http://www.microsoft.com/technet/prodtechnol/windows2000serv/reskit/default.mspx?mfr=true)

How to Log from PL/SQL

PL/SQL APIs are a part of the FND_LOG Package. These APIs assume that appropriate application user session initialization APIs (for example, FND_GLOBAL.INITIALIZE(..)) have already been invoked for setting up the user session properties on the database session. These application user session properties (UserId, RespId, AppId, SessionId) are internally needed for the Log APIs. In general, all Oracle E-Business Suite frameworks invoke these session initialization APIs for you.

To log plain text messages, use FND_LOG.STRING(..),.

API Description

PACKAGE FND_LOG IS
   LEVEL_UNEXPECTED CONSTANT NUMBER  := 6;
   LEVEL_ERROR      CONSTANT NUMBER  := 5;
   LEVEL_EXCEPTION  CONSTANT NUMBER  := 4;
   LEVEL_EVENT      CONSTANT NUMBER  := 3;
   LEVEL_PROCEDURE  CONSTANT NUMBER  := 2;
   LEVEL_STATEMENT  CONSTANT NUMBER  := 1;

  /*
   **  Writes the message to the log file for the specified 
   **  level and module
   **  if logging is enabled for this level and module 
   */
   PROCEDURE STRING(LOG_LEVEL IN NUMBER,
                    MODULE    IN VARCHAR2,
                    MESSAGE   IN VARCHAR2);

   /*
   **  Writes a message to the log file if this level and module 
   **  are enabled.
   **  The message gets set previously with FND_MESSAGE.SET_NAME, 
   **  SET_TOKEN, etc. 
   **  The message is popped off the message dictionary stack, 
   **  if POP_MESSAGE is TRUE.  
   **  Pass FALSE for POP_MESSAGE if the message will also be 
   **  displayed to the user later.
   **  Example usage:
   **  FND_MESSAGE.SET_NAME(...);    -- Set message
   **  FND_MESSAGE.SET_TOKEN(...);   -- Set token in message
   **  FND_LOG.MESSAGE(..., FALSE);  -- Log message
   **  FND_MESSAGE.RAISE_ERROR;      -- Display message
   */
   PROCEDURE MESSAGE(LOG_LEVEL   IN NUMBER,
                     MODULE      IN VARCHAR2, 
                     POP_MESSAGE IN BOOLEAN DEFAULT NULL);

   /*
   ** Tests whether logging is enabled for this level and module, 
   ** to avoid the performance penalty of building long debug 
   ** message strings unnecessarily.
   */
   FUNCTION TEST(LOG_LEVEL IN NUMBER, MODULE IN VARCHAR2) 
RETURN BOOLEAN;

Example

Assuming Oracle Application Object Library session initialization has occurred and logging is enabled, the following calls would log a message:

begin
  
  /* Here is where you would call a routine that logs messages */
  /* Important performance check, see if logging is enabled */
  if( FND_LOG.LEVEL_PROCEDURE >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
    FND_LOG.STRING(FND_LOG.LEVEL_PROCEDURE, 
        'fnd.plsql.MYSTUFF.FUNCTIONA.begin', 'Hello, world!' );
  end if;
/

The FND_LOG.G_CURRENT_RUNTIME_LEVEL global variable allows callers to avoid a function call if a log message is not for the current level. It is automatically populated by the FND_LOG_REPOSITORY package.

if( FND_LOG.LEVEL_EXCEPTION >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
      dbg_msg := create_lengthy_debug_message(...);
      FND_LOG.STRING(FND_LOG.LEVEL_EXCEPTION, 
           'fnd.form.ABCDEFGH.PACKAGEA.FUNCTIONB.firstlabel', dbg_msg);
end if;

For Forms Client PL/SQL, the APIs are the same. However to check if logging is enabled, you should call FND_LOG.TEST(..).

For example, when logging Message Dictionary Messages:

if( FND_LOG.LEVEL_UNEXPECTED >=
    FND_LOG.G_CURRENT_RUNTIME_LEVEL) then
    FND_MESSAGE.SET_NAME('FND', 'LOGIN_ERROR'); -- Seeded Message
    -- Runtime Information
    FND_MESSAGE.SET_TOKEN('ERRNO', sqlcode); 
    FND_MESSAGE.SET_TOKEN('REASON', sqlerrm); 
    FND_LOG.MESSAGE(FND_LOG.LEVEL_UNEXPECTED, 'fnd.plsql.Login.validate', TRUE); 
end if;

How to Log from C

Use the following APIs to log from C:

#define  AFLOG_UNEXPECTED  6
#define  AFLOG_ERROR       5
#define  AFLOG_EXCEPTION   4
#define  AFLOG_EVENT       3
#define  AFLOG_PROCEDURE   2
#define  AFLOG_STATEMENT   1

/* 
** Writes a message to the log file if this level and module is 
** enabled 
*/
void aflogstr(/*_ sb4 level, text *module, text* message _*/);

/* 
** Writes a message to the log file if this level and module is 
** enabled. 
** If pop_message=TRUE, the message is popped off the message 
** Dictionary stack where it was set with afdstring() afdtoken(), 
** etc. The stack is not cleared (so messages below will still be 
** there in any case). 
*/
void aflogmsg(/*_ sb4 level, text *module, boolean pop_message _*/);

/* 
** Tests whether logging is enabled for this level and module, to
** avoid the performance penalty of building long debug message 
** strings 
*/
boolean aflogtest(/*_ sb4 level, text *module _*/);

/* 
** Internal
** This routine initializes the logging system from the profiles.
** It will also set up the current session and username in its state */
void afloginit();

How to Log in Concurrent Programs

The sections below describe how logging is used in concurrent programs.

Debug and Error Logging

Use a CP Request Log only for messages intended for end users. Log debug information and error details (intended for system administrators and support personnel) to FND_LOG.

PL/SQL, Java, or C code that could be invoked by both CPs and application code should only use Oracle Application Object Library (FND) Log APIs. If needed, the wrapper CP should perform appropriate batching and logging to the Request Log for progress reporting purposes.

For message correlation, CP Request Log APIs log messages to both the Request Log and FND Log at severity EVENT (only if logging is enabled at EVENT or a lower level).

In Java CPs, use AppsLog for debug and error logging. The AppsLog instance can be obtained from the CpContext Object by calling getLog().

Request Log

Caution: Do not use the Request Log for debug messages or internal error messages that are oriented to system administrators and/or Oracle Support. Such messages should only be logged to FND_LOG.

The Request Log is the end user UI for concurrent programs (CPs). When writing CP code, only translatable, end user-oriented messages should be logged to the Request Log.

For example, if an end user inputs a bad parameter to the CP, then log an error message to the Request Log so the end user can take corrective action. A code sample follows:

-- Seeded Message for End-User 
FND_MESSAGE.SET_NAME('FND', 'INVALID_PARAMETER'); 
-- Runtime Parameter Information
FND_MESSAGE.SET_TOKEN('PARAM_NAME', pName); 
FND_MESSAGE.SET_TOKEN('PARAM_VALUE', pValue); 
-- Useful for Auto-Logging Errors
FND_MESSAGE.SET_MODULE('fnd.plsql.mypackage.myfuntionA');
fnd_file.put_line( FND_FILE.LOG, FND_MESSAGE.GET );

However, if the CP fails due to an internal software error, then the detailed failure message should be logged to FND_LOG. Additionally, a high-level generic message such as "Your request could not be completed due to an internal error"should also be logged to the Request Log to inform the end user of the error.

Output File

Caution: Do not use the Output File for debug messages or internal error messages that are oriented to system administrators and/or Oracle Support. Such messages should only be logged to FND_LOG.

An output file is a formatted file generated by a CP that could be sent to a printer or viewed in a UI window. An invoice is an example of an output file, for example:

fnd_file.put_line( FND_FILE.OUTPUT, \******** XYZ Invoice ********' );

How to Raise System Alerts

Raise System Alerts to notify system administrators of serious problems or potentially serious problems. System Alerts are posted to the Oracle Applications Manager console, and are also sent to subscribed administrators through Workflow notifications. These messages should be used in cases where one of the following applies:

When a System Alert is posted, a variety of context information is automatically collected. This may include information about the end user, responsibility, product, component, OS process, database session, and so on. Oracle Applications Manager allows users to drill down from a System Alert message to view any collected context information, associated debug log messages, and other potentially relevant information.

Additionally, Oracle Applications Manager tracks multiple occurrences of the same alert message to prevent duplicate notifications from being sent.

All system alert messages must be defined in the Message Dictionary using the messages form under the system administration responsibility.

Raising a System Alert

PL/SQL Code Sample

...
Exception 
  when others then
    if( FND_LOG.LEVEL_UNEXPECTED >=
        FND_LOG.G_CURRENT_RUNTIME_LEVEL) then
    -- To be alertable, seeded message must have
    -- Alert Category & Serverity defined
    FND_MESSAGE.SET_NAME('FND', 'LOGIN_ERROR'); -- Seeded Message
    -- Runtime Information
    FND_MESSAGE.SET_TOKEN('ERRNO', sqlcode); 
    FND_MESSAGE.SET_TOKEN('REASON', sqlerrm); 
    FND_LOG.MESSAGE(FND_LOG.LEVEL_UNEXPECTED, 'fnd.plsql.Login.validate', TRUE); 
   end if;
...

Java Code Sample

if(alog.isEnabled(Log.UNEXPECTED)) { 
    // To be alertable, seeded Message MUST have Alert 
    // Category & Severity defined.    
        Message Msg = new Message("FND", "LOGIN_ERROR");
    Msg.setToken("ERRNO", sqle.getErrorCode(), false);
    Msg.setToken("REASON", sqle.getMessage(), false);
     alog.write("fnd.security.LoginManager.authenticate", Msg, Log.UNEXPECTED);
}

Guidelines for Defining System Alerts