阅读更多

14顶
2踩

编程语言

原创新闻 JDK Logger出了什么问题?

2008-10-30 16:31 by 副主编 QQbyte 评论(25) 有15198人浏览
Ryan de Laplante 说道:我曾经使用log4j作为日志打印工具,因为它是最流行的,但是最近,我决定在我的新项目中尝试JDK logger。我喜欢这种logger放入JDK的方式,因为不需要管理.jar的依赖,处理版本冲突等。所有我需要做的只是写一个磁盘文件,定义我需要的格式化字符串,在logs超过多少KB以后轮转,只需要保留唯一y存档文件。我使用JDK logger和使用log4j一样满意。

之前我阅读了一些logger日志框架的历史,试图去理解为什么很多开发者并不使用JDK logger。log4j是第一个最普遍受到广泛欢迎的Java日志框架。然后,它的主要API进入JDK 1.4标准。一些名称做了改变,但是概念是一样的。现在有很多开发者不想应用“新的”java 1.4,继续使用log4j。直到现在Java 1.7,许多开发者依然使用log4j或者通用的日志工具,而不是使用JDK logger。

我的问题就是JDK logger到底出了什么问题?为什么很多人说它是一个灾难?你为什么不使用它呢?我不是试图责难,而是对此无法理解。难道因为log4j拥有更多内建附加功能,比如 NTEventLogAppender, JMSAppender, 和 SMTPAppender?

这篇文章在DZone上争论激烈,你能说说你的看法吗?
来自: java.dzone.com
14
2
评论 共 25 条 请登录后发表评论
25 楼 bribin 2008-11-09 11:49
跟着牛人的方向走,一般错不了,要搞个流行又好用的框架,哪有那么容易。标准一般会落后一些或者迟出。
24 楼 cats_tiger 2008-11-05 13:55
最近slf4j很火,和log4j的作者是一个人。提供了更简介的使用方法
23 楼 lbfhappy 2008-10-31 17:15
public class LogManagerextends Object存在一个单一的全局 LogManager 对象,它可用于维护 Logger 和日志服务的一组共享状态。

此 LogManager 对象:

管理 Logger 对象的层次结构名称空间。所有指定的 Logger 均存储在此名称空间中。
管理一组日志控制属性。这些是供 Handler 及其他日志对象用于自我配置的简单键-值对。
可以使用 LogManager.getLogManager() 获取全局 LogManager 对象。LogManager 对象是在类初始化过程中创建的,过后便不能更改。

在启动时,使用 java.util.logging.manager 系统属性定位 LogManager 类。

默认情况下,LogManager 从 JRE 目录的属性文件 "lib/logging.properties" 中读取其初始配置。如果编辑该属性文件,则可更改此 JRE 的所有用户的默认日志配置。

另外,LogManager 使用两个可选的允许更好地控制初始配置读取的系统属性:

"java.util.logging.config.class"
"java.util.logging.config.file"
这两个属性可以通过 Preferences API 来设置,既可作为 "java" 命令的命令行属性定义,也可作为传递到 JNI_CreateJavaVM 的系统属性定义。
如果设置了 "java.util.logging.config.class" 属性,则会把属性值当作类名。给定的类将会被加载,并会实例化一个对象,该对象的构造方法负责读取初始配置。(此对象可以使用其他系统属性来控制自己的配置。)此备用配置类可使用 readConfiguration(InputStream) 来定义 LogManager 中的属性。

如果未设置 "java.util.logging.config.class" 属性,则会使用 "java.util.logging.config.file" 系统属性来指定一个属性文件(以 java.util.Properties 格式)。从此文件读取初始日志配置。

如果这两个属性都没有定义,则如上所述,LogManager 将从 JRE 目录的属性文件 "lib/logging.properties" 中读取其初始配置。

Logger 和 Handler 的属性名称是以圆点分隔的 Logger 或 Handler 的名称开头。

全局日志属性可以包括:

属性 "handlers"。该属性为 handler 类定义类名的空白或逗号分隔列表,以便作为处理程序在根 Logger(该 Logger 名为 "")中加载和注册。每个类名必须用于具有默认构造方法的 Handler 类。注意,刚开始使用这些 Handler 时,它们可能是以延迟方式创建的。
属性 "<logger>.handlers"。该属性为 handler 类定义空白分隔或逗号分隔的列表,以便作为处理程序加载和注册到指定的 logger。每个类名必须用于一个具有默认构造方法的 Handler 类。注意,刚开始使用这些 Handler 时,它们可能是以延迟方式创建的。
属性 "<logger>.useParentHandlers"。该属性定义一个 boolean 值。默认情况下,每个 logger 除了自己处理日志消息外,还可能调用其父级来处理,这往往也会导致根 logger 来处理消息。将此属性设置为 false 时,需要为此 logger 配置 Handler,否则不传递任何消息。
属性 "config"。此属性允许运行任意配置代码。该属性定义类名的空白或逗号分隔的列表。为每个指定类创建新实例。每个类的默认构造方法都可以执行任意代码来更新日志配置,如设置 logger 级别、添加处理程序、添加过滤器,等等。
注意,在 LogManager 配置期间加载的所有类,其搜索顺序是先从系统类路径中搜索,然后才从用户类中搜索。这包括 LogManager 类、任何 config 类和任何 handler 类。

Logger 是按其圆点分隔的名称被组织到命名层次结构中的。因此,"a.b.c" 是 "a.b" 的子级,但 "a.b1" 和 a.b2" 属于同一级。

假定所有以 ".level" 结尾的名称的属性为 Logger 定义日志级别。因此,"foo.level" 就为名称为 "foo" 的 logger 定义了日志级别,进而为指定层次结构中它的所有子级也逐个定义了日志级别。日志级别是按其在属性文件中的定义顺序应用的。因此,树中子节点的级别设置应该迟于其父级设置。属性名 ".level" 可用于设置树的根级。

LogManager 对象上的所有方法都是多线程安全的。
22 楼 lbfhappy 2008-10-31 17:13
to derickkoo:
你说的确实有道理,我是错的。你是对的。
21 楼 AllenZhang 2008-10-31 12:52
用log4j仅仅是因为习惯了。还有,为了以前代码可用,拿过来懒得修改了。
20 楼 mapgis 2008-10-31 12:32
呵呵 让专业的人做专业的事,对于开源的东西我总是喜欢人气旺的产品,而不是去死抠技术上问题。除非满足不了我的需要的前提下。。。。
19 楼 derickkoo 2008-10-31 10:14
elmar 写道

土土的问:commons的logging和log4j什么关系?

log4j是一个具体的logging系统,也是目前最成熟的logging系统
其他logging系统还有java.util.logging, Avalon LogKit等

而commons-logging跟slf4j一样,可以简单得认为是个wrapper,这样我们在开发一些middleware, plugin时就可以不用考虑具体用户使用的underlying logging system了,让它们根据运行环境去选择,像commons-logging先看classpath里有没log4j或LogKit,再检测是不是用jdk1.4+来自动选择底层logging
18 楼 derickkoo 2008-10-31 10:08
瀚 愚 写道

需要指定JVM启动参数:-Djava.util.logging.config.file=/home/xxxx/logging.properties
没法单独为每个app指定配置文件


是的,也可以指定-Djava.util.logging.config.class=xx.xx.xx 但这个class必须是在系统classpath里的,就是因为jul是jdk自带的要用System ClassLoader去加载.所以jul配置是JVM-wide

to lbfhappy:找到办法实现我提的要求了吗?
17 楼 derickkoo 2008-10-31 10:02
xijinn 写道

sun有时候就是做的太绝了
用log4j不就完了嘛,非得自己搞一套让大家抛弃log4j,出一套标准去兼容当时的log4j还说的过去
当初jsp就是这样把velocity给埋没的,当大家发现jsp恶心的时候已经来不及了上了sun的贼船了
偶现在见很多开源项目都用slf4j这套日志标准,而且在各种日志之间切换也挺方便

slf4j是一个不错的选择,弥补了commons-logging的不足
16 楼 xijinn 2008-10-31 09:56
sun有时候就是做的太绝了
用log4j不就完了嘛,非得自己搞一套让大家抛弃log4j,出一套标准去兼容当时的log4j还说的过去
当初jsp就是这样把velocity给埋没的,当大家发现jsp恶心的时候已经来不及了上了sun的贼船了
偶现在见很多开源项目都用slf4j这套日志标准,而且在各种日志之间切换也挺方便
15 楼 无聊神灯 2008-10-31 09:55
elmar 写道

土土的问:commons的logging和log4j什么关系?

就因为sun搞了个logger,所以才有了commons logging.
有log4j配置情况下,优先使用log4j,否则使用jdk嵌入的logger
14 楼 elmar 2008-10-31 09:47
土土的问:commons的logging和log4j什么关系?
13 楼 瀚愚 2008-10-31 09:41
需要指定JVM启动参数:-Djava.util.logging.config.file=/home/xxxx/logging.properties
没法单独为每个app指定配置文件
12 楼 Unmi 2008-10-31 09:40
什么叫做跟风,log4j就是比jdk logger 好用的得,就是因为 log4j 拥有更多内建附加功能,比如 NTEventLogAppender, JMSAppender, 和 SMTPAppender?

哪天你用 jdk logger 想输出日志到别处时,你就会后悔
11 楼 insiku 2008-10-31 09:20
觉得好的人 只是因为没有用过更好的
SUN的失败之处就是要自己搞个log框架出来
死活不肯接受log4j
10 楼 amonlei 2008-10-31 09:20
java.lang.Object 写道

同意楼主的看法,我就不喜欢用log4j,明明是JDK提供了的功能,还去用log4j,纯粹是吃饱了撑得要么就是跟风。用JDK的LOG连JAR包都不用附件,岂不是更好?

你撑了其实,log4j先出还是jdk logging先出你搞清楚了没?刚玩java?
9 楼 derickkoo 2008-10-31 09:10
呵呵!!你牛,请写个配置文件出来给我们看看!
我的要求很简单,
1)配一个com.foobar.test的logger,log文件写到test.log里(用内建的FileHandler好了),再配一另一个logger比如com.foobar2.fck 输入到fck.log文件里.
2)如果完成了1,ok,再请告诉我,我有两个webapps foo.war 与 bar.war我要一起deploy到tomcat里好了,要求更简单只要各自有自己的log文件好了.

就这样吧,请大师把这两个我们平时开发最最基本的要求用jdk内建的jul来配一下.你用简单的配置文件就搞定了,ok我会承认我这四年java白忙活了,还说什么SUN会不会这么..我都跟你说了jul只是个架构,你可以去根据自己要求去写一套实现呀,在JVM启动时指定一下java.util.logging.LogManager

P.S.我不只怀疑你到底用没用过jul,我甚至doubt你有没有看到过jul的配置文件logging.properties.
JDK里默认的配置文件在$JAVA_HOME/jre/lib/logging.properties
Tomcat的在$CATALINA_HOME/conf/logging.properties
8 楼 lbfhappy 2008-10-31 08:39
derickkoo 写道

大哥,我想问下你有没有亲身去用过JUL呀(java.util.logging),简单来说JUL现在更本不能用(useless at all)是因为它来自JDK所以它的配置是JVM-wide, 也就是说一个JVM用同一配置(现在哪个服务器一个JVM只跑一个webapp的?),还有一个JUL先天不足就是它的配置是配整个类, 比如我把log输出到一个文件用一个FileHandler, 那么整个JVM里的所以webapps只要是用FileHandler的都会log输到这一个文件去, 不能一个logger配独立的Handler而log4j就不一样了,因为它是classloader-wide的,一个JVN下即使有多个webapps,因为各个webapp用的classloader不同所以相互的配置没有任何影响。还有就是在log4j里一个不同的logger可以配多个同一类行的Appender。说实话我也不喜欢在lib里多加个log4j.jar,但现在没有其他更好的办法呀,怎么说呢java.util.logging只是JDK提供的一个logging架构,只是把自带了个默认在webapp方面基本没用的实现,当然在一般的swing程序里只要独门jvm的还是方便的。当然你也可以基于jul架构写一套自己的logging系统,启动时设下java.util.logging.LogManager等就行了,比如Tomcat就自己实现了个JULi (JUL Improved). 晕,快错过班车了,闪...


到底是你没有用过还是我没有用过啊,这分明是可以分开配置的,你怎么会认为一个JVM一个配置呢,SUN怎么做也不会这么傻吧,JDK的LOG也是一样可以有一个外部的配置文件的啊,并且可以指定哪些类的LOG写到哪些文件里面去。唉,。。
7 楼 nmvr2600 2008-10-30 23:48
6 楼 ray_linn 2008-10-30 23:20
sun 出的东西都是破破烂烂的

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • 获取打印机状态Delphi

    用程序获取打印机状态 网络上的一些代码都不能成功 借鉴一下,查看API函数,一般是函数的参数使用不当造成 终于成功! 含源代码: Delphi6

  • delphi 连接网口打印机 发送指令打印二维码

    procedure getQRBitmap(printstr:string); var moduleSize: Integer; slength: Integer; Send: string; Send_Length:String; PicNamearray: array[0..50] of Byte; begin moduleSize := 8; slength:=Length(printstr); //存入二维码数据 Send_L.

  • DEVMODE 结构体

    typedef struct _devicemode { TCHAR dmDeviceName[CCHDEVICENAME]; //打印机(显示设备)名称 WORD dmSpecVersion; WORD dmDriverVersion; //驱动版本号 WORD dmSize; //结构体大小 WORD dmDriverExtra; DWORD dmField...

  • 打印机相关

    数据的传输与命令的传输可以采用Socket,这个很容易吧(找个黑客软件源码)对打印机的操作。Delphi中获取打印机设备名和端口名uses Printers;{$IFNDEF WIN32}const MAX_PATH = 144;{$ENDIF}procedure TForm1.Button1Click(Sender: TObject);var  pDevice : pChar;  pDriver

  • Delphi 中取本机的计算机名、IP地址、Windows登录的用户名

     几个在Delphi 中取本机的计算机名、IP地址、Windows登录的用户名的函数.uses Windows, WinSock;{ ComputerLocalIP }//取本机的 IP 地址function ComputerLocalIP: string;var  ch: array[1..32] of char;  wsData: TWSAData;  myHost: PHostE

  • Delphi 获取计算机名

    RAD Studio 10.2.3 测试√ procedure TForm_Tips.Button_GetComputerNameClick(Sender: TObject); {取得计算机名} function ComputerName: string; var CNameBuffer: PChar; fl_loaded: Boolean; CLen: ^DWord; begin GetMem(CNameBuffer, 255); New(CLen

  • Delphi获取默认打印机名称及端口

    在前段时间写的收银系统中由于目前市场上很多电脑主板上已经没有并口,而POS机却又需要并口,所以目前需要用PCI转接卡,这个就导致不同门店使用的端口就有可能不同,这就给我们程序中弹出钱箱的指令带来一定的难度。所以就通过获取Window自带的默认,得出打印机信息。 在Windows文件下有个win.ini,里面自带默认打印机的信息。通过调用API函数Getprofilestri...

  • Delphi中获取打印机设备名和端口名

    google_ad_client = "pub-2947489232296736";/* 728x15, 创建于 08-4-23MSDN */google_ad_slot = "3624277373";google_ad_width = 728;google_ad_height = 15;//<script type="text/javascript"

  • 获取设备的唯一标识符细解

    iOS中获取设备唯一标识符的方法随着ios版本的更新而变化,iOS 2.0版本以后UIDevice提供一个获取设备唯一标识符的方法uniqueIdentifier,通过该方法我们可以获取设备的序列号,这个也是目前为止唯一可以确认唯一的标示符。好景不长,因为该唯一标识符与手机一一对应,苹果觉得可能会泄露用户隐私,所以在 iOS 5.0之后该方法就被废弃掉了;iOS 6.0系统新增了两个用于替换uni...

  • delphi 中获取计算机名和IP

    function GetComputerName:String; //获取计算机名称 var wVersionRequested : WORD; wsaData : TWSAData; p : PHostEnt; s : array[0..128] of char; begin try wVersionRequested := MAKEWORD(1, 1);

  • 获得某一台网络打印机有几份等待打印的报表

    当我们要打印报表时,如果打印机是本机的打印机的话,当然马上就会将报表打印出来,反正打印机就只有您一个人在使用而已!但是如果是在一个人数很多的公司或企业时,往往就必须很多人来分享某一部打印机了,而且打印机也不一定就放在举目可及之处!当您将报表丢到网络打印机之后,由于不一定看得到打印机,您必须特别到摆放打印机的地方去拿报表,这时候您最关心的,就是报表印了没有,如果还没有的话,那还有几份还没打印的报

Global site tag (gtag.js) - Google Analytics