You are browsing the archive for 2008 十一月.

创建ADFLogger配置文件

十一月 30, 2008 in Oracle 融合中间件

 

 

前面的文章记录了怎么使用ADFLogger日志记录器来记录和调试业务组件,但是在ADF应用开发中,很多代码是无法通过业务组件浏览器来进行测试的,

如控制层的代码,因此就无法通过前面介绍的方法来进行调试。

 

代码中使用ADFLogger来记录日志信息后,需要做如下的配置才可以将日志信息输出到JDeveloper控制台或者日志文件:

 

1,查找logging.xml文件的路径,logging.xml文件的位置找起来稍微有点麻烦

 

如果设置了环境变量JDEV_HOME,在JDEV_HOME目录下面会有一个system<version>的文件夹,如system11.1.1.0.31.51.56

如果没有设置环境变量JDEV_HOME,在JDeveloper的安装目录下有一个sytem/system<version>的文件夹,如system/system11.1.1.0.31.51.56

在system<version>目录下的DefaultDomain\config下就有是logging.xml文件了

 

2,修改logging.xml文件内容,配置哪些java 包中的日志信息需要打印

在此文件中配置哪些java包什么级别的日志信息将被打印,如下例子:

1
 

 

<logger name="oracleseeker.demo" level="INFO"/> 代表java包oracleseeker.demo中的级别高于INFO的日志信息都将被输出

<logger name="oracleseeker.sample" level="WARNING"/> 代码java包oracleseeker.sample中级别高于WARNING的日志信息将被输出

按照上面的语法,可以将自己开发的java包添加进去,当然最简单的一种方式是开启所有java包的日志,这是一种简便的方式,但不推荐使用。

<logger name="" level="WARNING"> 这样的就是将所有包的日志都打印出来

 

如果想输出ADF标准模块中的日志信息,可以添加如下的项即可

1
 

 

 

3,添加运行配置器的JVM选项

 

运行配置器的JVM选项中添加如下的选项

-Djbo.debugoutput=adflogger -Djbo.adflogger.level=FINE

添加了这个选项之后,JDeveloper控制台中也会打印出日志信息,如果希望将日志信息输出到一个日志文件,可以配置logging.xml文件,添加 log_handler 来输出重定向,具体可以看上面给出的示例

 

 

 

ADFLogger记录日志和调试ADF业务组件

十一月 20, 2008 in Oracle 融合中间件

 

Oracle ADF 11g

 

 

一、基本知识

 

下面一段是摘自域于java.util.logging JDK说明文档中关于使用日志的四个主要目标:

  1. 由最终用户和系统管理员进行问题诊断。这由简单的常见问题日志组成,可在本地解决或跟踪这些问题,如资源不足、安全失败和简单的配置错误。
  2. 由现场服务工程师进行问题诊断。现场服务工程师使用的日志信息可以相当复杂和冗长,远超过系统管理员的要求。通常,这样的信息需要特定子系统中的额外日志记录。
  3. 由开发组织进行问题诊断。在现场出现问题时,必须将捕获的日志信息返回到原开发团队以供诊断。此日志信息可能非常详细,并且相当费解。这样的信息可能包括对特定子系统进行内部执行的详细跟踪。
  4. 由开发人员进行问题诊断。Logging API 还可以用来帮助调试正在开发的应用程序。这可能包括由目标应用程序产生的日志信息,以及由低级别的库产生的日志信息。但是要注意,虽然这样使用非常合理,但是 Logging API 并不用于代替开发环境中已经存在的调试和解析工具

 

本文主要基于第四点来描述如何利用JDeveloper 11g和ADFLogger来调试ADF应用中的业务组件。ADFLogger是ADF基于Java Logging API (java.util.logging.Logger)包装的日志工具。

 

 

java.util.logging.Level类中定义了一组可用来控制日志输出的标准日志级别。日志 Level 对象是有序的,并且是通过有序的整数来指定。

在给定的级别上启用日志记录也就启用了所有较高级别的日志记录,如下面的级别中,如果启用了INFO级别,那更高级别的SEVERE和WARNING也被启用了。

 

日志按严重性由高到低的顺序提供了如下的级别

  1. SEVERE 严重的错误,导致系统中止。期望这类信息能立即显示在状态控制台上
  2. WARNING 潜在问题的级别,它是不符合预期的状态但还不至于成为“错误”,例如使用了废弃的API等等。期望这类信息能立即显示在状态控制台上
  3. INFO 运行时产生的有意义的一些信息,主要用于报告消息的目的。期望这类信息能立即显示在状态控制台上
  4. CONFIG 静态配置消息,用来输出一些系统配置信息。期望这类信息仅被写入日志文件中
  5. FINE 指示提供跟踪信息,简单输出一些跟踪信息。期望这类信息仅被写入日志文件中
  6. FINER 指示提供一条相当详细的跟踪消息。期望这类信息仅被写入日志文件中
  7. FINEST 指示提供一条最详细的跟踪消息。期望这类信息仅被写入日志文件中

 

 

二、编写代码

 

在ADF代码中根据需求记录日志信息,确保日志信息在内容上和反应问题的严重程度上的准确而且恰当,是程序员需要做好的重要任务。

如下是在一个EO的实现类AfwkModulesVlEOImpl中记录日志信息的代码:

首先是创建一个日志记录器;然后输出日志信息。

 

1
2
3
private static ADFLogger logger = ADFLogger.createADFLogger(AfwkModulesVlEOImpl.class);
logger.log(Level.INFO,&quot;select language_code, installed_flag from afwk_languages where installed_flag in ('I', 'B')&quot;);
//logger.info(&quot;select language_code, installed_flag from afwk_languages where installed_flag in ('I', 'B')&quot;);

 

代码中记录日志信息可以采取两种办法:

  1. 使用log方法,通过指定Level参数来决定日志信息反映为哪个级别的严重程度。如上面代码中logger.log方法
  2. 使用日志级别的方法,什么严重程度的级别就使用什么样的输出方法。如上面代码中被注释掉的logger.info方法就是用来输出INFO级别的日志信息

 

日志记录方法划分为 5 个主要类别:

  1. 一系列的 "log" 方法,这种方法带有日志级别、消息字符串,以及可选的一些消息字符串参数。
  2. 一系列的 "logp" 方法(即 "log precise"),其与 "log" 方法相似,但是带有显式的源类名称和方法名称。
  3. 一系列的 "logrb" 方法(即 "log with resource bundle"),其与 "logp" 方法相似,但是带有显式的在本地化日志消息中使用的资源包名称。
  4. 还有跟踪方法条目("entering" 方法)、方法返回("exiting" 方法)和抛出异常("throwing" 方法)的便捷方法。
  5. 最后,还有一系列在非常简单的情况下(如开发人员只想为给定的日志级别记录一条简单的字符串)使用的便捷方法。这些方法按标准级别名称命名("severe"、"warning"、"info" 等等),并带有单个参数,即一个消息字符串。

 

如severe级别的方法有如下:

  1. severe(java.lang.String msg)
  2. severe(java.lang.String message, java.lang.Object param)
  3. severe(java.lang.String message, java.lang.Object[] params)
  4. severe(java.lang.String sourceClass, java.lang.String sourceMethod, java.lang.String msg)
  5. severe(java.lang.String sourceClass, java.lang.String sourceMethod, java.lang.String msg, java.lang.Object param1)
  6. severe(java.lang.String sourceClass, java.lang.String sourceMethod, java.lang.String msg, java.lang.Object[] params)
  7. severe(java.lang.String message, java.lang.Throwable t)
  8. severe(java.lang.Throwable t)

 

其它的方法和方法的详细信息可以查看Java Doc

 

 

三、调试程序

 

通过应用模块(Application Module)的上下文菜单选择Run或者Debug来测试运行业务组件,并根据实际组件进行数据操作:

 

obcb_test

 

操作之后查看Log Window的输出信息:

adflogger_log_window

 

注意上图中输出的日志信息:

1,绿色的日志信息属于系统运行输出的

2,红色字体的日志信息则是在程序代码中记录的。而红色的日志中,带日期时间、包名和方法的那行是我们程序中输出日志所属的上下文信息,

而以“信息:”打头的才是真正我们代码中输出的日志信息,如红色框所框住的信息就是第二部分示例代码所输出的日志信息。

 

注意:这种方式下,Log Window窗口中只输出消息级别高于INFO的日志信息,要查看低于这个级别的日志信息,需要配置ADFLogger的logging.xml文件

 

使用ADFLogger日志工具来进行程序的调试,这样避免了在程序中使用System.out.println方法来打印信息,也可以在产品交付的时候通过系统选项来控制

什么样级别的信息需要输出,而不是将任何程序的调试信息也一并输出。

 

如果我们希望除了看到程序中的日志信息,还希望查看一下运行时的诊断信息,可以启用诊断日志来输出相关信息。

在运行配置器的JVM选项中添加:

-Djbo.debugoutput=console

 

这样日志窗口中就会打印出很详细的诊断信息,主要包括

  1. 操作系统信息
  2. Java虚拟机信息
  3. 创建BindingContext信息
  4. 装载BC4J属性
  5. 创建数据库连接信息
  6. 创建业务实体信息

 

这样的信息可以帮助我们进行一些疑难杂症的解决。

 

在Oracle ADF应该开发过程中,JDeveloper 11g开发工具提供了很多的调试方式和工具,随着后续学习的深入,将记录更多的调试方法。

 

 

InvalidOwnerException错误

十一月 19, 2008 in Oracle 融合中间件

 

Oralce ADF 11g

 

在使用Oracle ADFm 来开发master-detail关系的应用程序过程中,当试图往detail行集对象中插入新行的时候报错误信息:

oracle.jbo.InvalidOwnerException: JBO-25030: Failed to find or invalidate owning entity

 

这个错误信息的产生原因是由于创建实体对象关系的时候,关系的属性设置为了强连接,意味着在主记录不存在的时候

从纪录是不可能生成的,因此当王detail行集中插入新行的时候,由于它没有master纪录的上下文信息,所以报出找不到它的主实体。

 

对于在Oracle EBS环境下作过Form应用的开发人员对这点应该更加清楚,Form中数据块之间可以创建关系,关系上面有一个属性叫做:

防止无主操作。它的意思就是当主记录不存在的时候,不能创建从纪录,就和上面的ADFm错误是一样的道理。

 

存在这样控制的目的是防止一些无效数据的产生,保证数据的有效性,正如我们常见的订单和订单行这样的关系中,

如果订单都没有创建,何来订单行呢?因此需要来防止无效的订单行产生,基于这样的情况,Steve Muench也在他的博客中描述了如何

来避免这样问题的发生:Why Do I Get the InvalidOwnerException?

 

而在另外一些情况下,由于特殊的情况,需要在没有主记录存在的时候来创建从纪录,即需要将主从关系变为一种弱连接,允许进行

无主操作。

 

这个时候只要修改创建的实体关系的属性,将Composition Association选项去除即可,如下图:

 

entity_association

 

 

 

EBS开发中记录日志信息

十一月 17, 2008 in Oracle EBS二次开发

 

 

Oracle EBS 11i or higher

 

对于任何一个应用开发架构,提供一个灵活方便的日志消息记录机制都是必须的,Oracle EBS提供了一套完整的日志框架,它为调试、错误报告和错误提醒等提供了一个完整的机制。

我们在Oracle EBS环境中进行二次开发的时候,需要充分利用日志框架提供的功能来记录各种日志信息,方便程序的维护的调试。

 

本文主要描述在Oralce EBS环境下进行PLSQL程序开发时如何利用这套日志框架来进行日志信息的记录。

 

一、基本概念

 

1,日志的生命周期

 

记录日志:在程序代码中根据日志的级别记录日志信息

日志需求:程序产生错误或者问题,开发人员需要查看一些辅助信息

日志输出:在不更改程序的前提下,运行程序,将日志信息输出,根据日志信息定位或调试问题

清除日志:如果日志信息已使用结束,可以将其清除

 

 

2,日志的级别

 

在程序代码中,不同类型的日志信息可能表示不同严重性,开发人员也会给予不同的关注度,因此在程序中输出日志信息时需要将其分出不同的等级输出,

方便后续根据不同的需求进行必要的查看和调试

 

1-STATEMENT:很少使用这个级别来记录日志信息

2-PROCEDURE:一般在PLSQL程序中,如果希望打印一些参数值或者运行过程中的中间值都采用这个级别

3-EVENT:在PLSQL程序中很少使用

4-EXCEPTION:程序发生异常的时候,输出一些异常信息的时候使用,因此在PLSQL的Exception部分往往需要采用这个级别

5-ERROR:当发生某些可预知错误的时候使用这个级别,因此在PLSQL的Exception部分,一些可以预知的错误分支采用这个级别

6-UNEXPECTED:当发生某些不可预知错误的时候使用这个级别,因此在PLSQL的Exception部分,不可以预知的错误分支采用这个级别

 

数字越大代表问题的严重性越大,意味着这样的日志信息也越少,因此程序编码中需要根据情况输出不同级别的日志信息。

 

3,预制文件

 

Oracle EBS系统中,通过以下几个预制文件来控制是否开启日志记录、输出哪些级别的日志信息、输出哪些模块相关的日志信息等等。

 

AFLOG_ENABLED:用来指定是否开启日志记录功能,默认是NULL(不开启)

AFLOG_LEVEL:指定日志记录的级别,默认是NULL(Log.UNEXPECTED),这个值代表了日志输出的最低级别,只要是级别比它高的日志信息都将被输出

AFLOG_MODULE:指定要开启哪个模块的日志记录,默认是NULL(%,所有模块)

AFLOG_FILENAME:指定应用服务器的文件地址和名称,用来写入日志信息

 

 

二、PLSQL开发中记录日志信息的步骤

 

1,记录日志信息

 

在PLSQL代码中按照日志信息的级别输出日志信息,编写如下的PLSQL代码:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
G_MODULE_PREFIX     VARCHAR2(100) := 'cux.plsql.PACKAGE_NAME';
l_procedure_name    VARCHAR2(30):= 'PROCEDURE_NAME';
 
PROCEDURE log
(p_level   IN VARCHAR2
,p_module  IN VARCHAR2
,p_message IN VARCHAR2)
IS
BEGIN
  IF(p_level &gt;= FND_LOG.G_CURRENT_RUNTIME_LEVEL)
  THEN
  fnd_log.STRING(LOG_LEVEL =&gt; p_level
                ,MODULE    =&gt; p_module
                ,MESSAGE   =&gt; p_message
                );
  END IF;
END;
 
IF(FND_LOG.LEVEL_PROCEDURE &gt;= FND_LOG.G_CURRENT_RUNTIME_LEVEL)
THEN
  log(FND_LOG.LEVEL_PROCEDURE,G_MODULE_PREFIX || l_procedure_name, 'some logging information......');
END IF;

 

上面代码中fnd_log.string的三个参数:

  1. LOG_LEVEL:将日志信息记录为什么级别,只有开启日志级别比它高的时候才会打印出日志信息,否则不打印
  2. MODULE:将日志信息记录到哪个模块,模块的命名规范为:<模块简称>.<语言>.<包名>,如 cux.plsql.PACKAGE_NAME
  3. MESSAGE:需要输出的日志信息

 

FND_LOG.G_CURRENT_RUNTIME_LEVEL这个全局变量则是目前Oracle EBS环境启用的消息级别是多少?它的值来至于预知文件AFLOG_LEVEL的设置

 

 

2,输出日志信息

 

需要输出日志的时候,只要首先开启相关的预知文件,然后运行程序,根据设置察看日志信息即可。

 

设置相关的预制文件,设置预知文件的值最好遵循以下规则:

  1. 设置在用户层
  2. 日志级别尽量高,减少日志输出信息
  3. 指定日志输出模块,尽量少使用代表全部模块的(%)

 

曾经在我们的系统中,由于在系统层启用了所有模块的日志信息,发现第二天就将近2G的数据库空间吃光了!!!

 

如果设置了AFLOG_FILENAME,即日志信息写入的文件,那请查看文件的内容;

而如果没有没有设置日志文件路径,日志信息写入数据库表:FND_LOG_MESSAGES,而PLSQL程序最方便的方式就是将日志信息写入到数据库表中

如下的查询:

1
2
3
4
SELECT message_text
  FROM fnd_log_messages
 WHERE module LIKE 'fnd.framework.webui%'
 ORDER BY log_sequence

 

 

 

更多关于Oracle EBS 日志信息的内容可查看相关文档。

 

 

 

面试故事一则:”你说!!!我哪里不好啊?”

十一月 13, 2008 in 生活点滴/Enjoy Life

 

 

我和另外一位同事经常一起出去招聘面试,面试的时候往往会同时在一个教室中的不同角落同时对同学进行面试。

 

那天正在面试中,开始只感觉另一个角落的面试很激烈,声音感觉比较吵,但是后面只听有人拍桌子,大声地说“你说!!!我哪里不好啊?”。

一看是一位女同学在拍桌子,并大声地对我的那位同事提出质问,我心想“这位同学太牛了,竟然这样呼喝面试官,难道不是来面试的?”

 

事后和同事了解了情况,据同事描述,情况是这样,当时面试已结束

同学:你觉得我能进下一轮面试吗?

同事:我觉得有点困难哦

同学:为什么啊?你问我的问题都回答上来了阿!!!(有点不解)

同事:你回答的很多都是错的,这样很难通过的,不好意思

同学:那你再问我问题啊,我肯定能回答好(声音比较洪亮,有点愤怒了)

同事:我觉得已经没有这个必要了,该问的都已经问的差不多了

同学:我肯定不会比我同学差(她的一位同学已通知进入下一轮面试),你再问我问题!!!(愤怒加大了)

同事:没有这个必要了,就这样吧同学

同学:那你说!!!我哪里不好啊?(愤怒爆发,无法控制)

 

每每给大家讲起这个故事的时候,我们都会取笑这位同事说:“你怎么人家啦,搞得人家这样愤怒,你这样不好吧?”之类的,

更有旁边的同事或朋友还会添油加醋的加一句“他肯定对人家做了什么才这样的”,

搞得我们这位同事很郁闷,其实他什么也没有做,只是多问了那位同学几个问题,加上如实的回答了同学的问题而已。