为 Eclipse 插件添加日志框架[1]

为什么要采用日志?
良好的开发人员都知道精心设计、测试和调试的重要性。虽然 Eclipse 可以帮助开发人员实现这些任务,但是它怎样处理日志呢?很多开发人员相信对于良好的软件开发实践来说,日志是不可或缺的一部分。如果您曾经修正过他人部署过的程序,您无疑也会同意这一点。幸运的是,日志对于性能的影响很小,大部分情况下甚至根本不会对性能产生任何影响,而且由于日志工具非常简单易用,因此学习曲线也非常平滑。因此,对于现有的优秀工具,我们没有理由不在应用程序中添加日志功能。

可以使用的工具
如果您正在编写一个 Eclipse 插件,那么您可以使用 org.eclipse.core.runtime.ILog 所提供的服务,它可以通过 Plug 类的 getLog() 方法进行访问。只需要使用正确的信息创建一个 org.eclipse.core.runtime.Status 的实例,并调用 ILog 的 log() 方法即可。

这个日志对象可以接收多个日志监听器实例。Eclipse 添加了两个监听器:

  • 一个监听器向 "Error Log(错误日志)" 视图中写入日志。
  • 一个监听器向位于 “${workspace}/.metadata/.log" 的日志文件中写入日志。

您也可以创建自己的日志监听器,只需实现 org.eclipse.core.runtime.ILogListener 接口并使用 addLogListener() 方法将其添加到日志对象中即可。这样,每个日志事件都可以调用这个类的 logging() 方法。

虽然所有的内容都非常简单,但是这种方法存在一些问题。如果您希望修改一个已部署好的插件目标,那么应该如何处理?或者说要如何控制记录下来的日志信息的数量?还有,这种实现可能会对性能造成影响,因为它总是要向所有的监听器发送日志事件。这就是为什么我们通常只在极端的情况(例如错误条件)中才会看到要记录日志的原因。

另一方面,还有两个专门用于日志的杰出的工具。一个来自 Java 2 SDK 1.4 的 java.util.logging 包;另外一个来自 Apache,名为 Log4j。

这两个工具都采用了日志对象的层次结构的概念,都可以将日志事件发送到任意数目的处理程序(Handler,在 Log4j 中称为 Appender)中,它代表了发送给格式化程序(Formatter,在 Log4j 中称为 Layout)进行格式化的消息。这两个工具都可以通过属性文件进行配置。 Log4j 还可以使用 xml 文件进行配置。

记录器可以有一个名称并与某一级别相关联。记录器可以继承父母的设置(级别,处理程序)。名为“org”的记录器会自动成为另外一个名为“org.eclipse” 的记录器的父母;因此不管您在配置文件中怎样对“org”进行设置,这些设置都可以被“org.eclipse”记录器继承。

我更喜欢哪一个工具?这两个工具我都曾经用过,不过我比较喜欢 Log4j。只有在非常简单的程序中我才使用 java.util.logging,我并不想在这样的程序中添加 log4j.jar。关于这两个工具的详细介绍,请参阅 Java 文档和 Apache 的站点(请参阅参考资料中的链接)。

一种改进的日志
如果存在改进 Eclipse 日志体验的方法,那不是很棒吗?但这样做有两个问题:

  • 缺少外部配置文件。
  • 性能问题,同时还有缺乏对日志行为进行细粒度控制。

给出这个难题之后,我开始考虑将日志工具集成到 Eclipse 中的方法。我可以使用的第一个选择是 java.util.logging,原因非常简单:在 JSDK1.4 发行版中已经包含了这个包。

我想采用一个编辑器,通过配置文件对日志行为进行定制,从而允许将日志事件发送到任何可用的处理程序中。我计划另外创建两个处理程序:一个负责将日志事件发送到“Error Log”视图中,另外一个将日志写入插件所在的位置:“${workspace}/.metadata/.plugins/${plugin.name}"。

所有的内容都将包含在一个日志管理器插件(Plug-in Log Manager)中。您只能将其加入插件从属关系中,并从中获得日志对象。

然而,根据我的经验,我不推荐使用 java.util.logging 来实现这项功能。因为实现的代码将很长,而且只能保留一个 LogManager 实例;它使用系统类装载程序来达到这个目的。这样,所有的用户只有一个层次结构,您会失去隔离性。因此,如果很多应用程序都在使用这个记录器,那么它们将共享设置,一个应用程序的记录器实例可以继承其他应用程序记录器的设置。

既然如此,为什么我们不对 LogManager 进行扩充,并自己实现一个记录器呢?这种方法的问题是 LogManager 实例使用了系统类的装载程序从配置文件中对类进行实例化。这种插件的优点之一是通过使用不同的类装载程序提供隔离性。如果您的日志管理程序需要隔离性,那么由于架构的限制, java.util.logging 可能不适合您的要求。

另一方面,Log4j 已经证明是非常有用的。不管您相信与否,Log4j 的记录器的层次结构保留在一个称为 Hierarchy 的对象中。因此,您可以为每个插件都创建一个层次结构,这样问题就解决了。您还可以创建一个定制的 appender (处理程序)将事件发送给 "Error Log" 视图,再创建一个将事件发送到插件所在的位置。这样生活就变得美好起来了。

现在让我们回顾一下整个过程是如何实现的,我们从插件编辑器的角度入手,创建插件,并将 com.tools.logging 添加到从属类型列表中,然后创建一个 Log4j 配置文件。对 PluginLogManager 进行实例化,并使用配置文件对其进行配置。由于这个过程只需要做一次,因此您只需要在启动插件时执行这项操作即可。对于日志语句,只需像在 Log4j 中那样使用它即可。 清单 1 给出了一个例子:

清单 1. TestPlugin 插件类中 PluginLogManager 的配置

private static final String LOG_PROPERTIES_FILE = "logger.properties";public void start(BundleContext context) throws Exception { super.start(context); configure();}private void configure() { try { URL url = getBundle().getEntry("/" LOG_PROPERTIES_FILE); InputStream propertiesInputStream = url.openStream(); if (propertiesInputStream != null) { Properties props = new Properties(); props.load(propertiesInputStream); propertiesInputStream.close(); this.logManager = new PluginLogManager(this, props); this.logManager.hookPlugin( TestPlugin.getDefault().getBundle().getSymbolicName(), TestPlugin.getDefault().getLog()); } } catch (Exception e) { String message = "Error while initializing log properties." e.getMessage(); IStatus status = new Status(IStatus.ERROR, getDefault().getBundle().getSymbolicName(), IStatus.ERROR, message, e); getLog().log(status); throw new RuntimeException( "Error while initializing log properties.",e); } }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值