Grails3下使用logback实现数据库日志功能

来源:互联网 发布:数据分析功能 编辑:程序博客网 时间:2024/06/04 00:26

      最近由于工作需要,开始使用Grails开发Web应用。Grails是“规则优于配置”的开发理念,熟悉以后,确实可以节省很多繁琐的配置工作,当然,新手还需一定的适应过程,毕竟是需要熟悉“规则”才能节省配置。

      今天主要写如何在Grails3下使用logback来实现数据库日志功能。按理说应该是简单的配置就能实现的,但是使用过程中出现了一些奇怪的问题,我就把这些问题以及解决办法在这里罗列一下,希望对遇到相同问题的同志们能有一定的帮助。当然,我其实也是Grails新手,如果有更好的解决问题的方法,还请前辈们多多指教。好了,废话不多说,下面开始~~

 

一、Grails官网

      首先,查看Grails官网的最新文档,地址是:http://docs.grails.org/latest/guide/conf.html#logging

 

      官网直接说Grails的日志功能由logback实现,你去看他的文档就行了,完事在我给你的logback.groovy配置文件修改一下配置就行。当然,他也说了,这个配置文件是Groovy格式的,可以直接更换成xml格式的,改个后缀名就行。

 

二、logback官网

      查看logback官网,地址是:https://logback.qos.ch/manual/groovy.html,这个网页(第12章)大概介绍了如何在Groovy下配置logback,然而,并没有具体介绍如何配置能够实现把日志写到数据库。

      于是,又来到第4章,这里就详细介绍了不同的Appender,比如说,FileAppender是写到日志文件的,ConsoleAppender是写到控制台的,所以,写到数据库的当然就是DBAppender,只要把这个BDAppender配置好,应该就能实现了。具体的介绍在这里:https://logback.qos.ch/manual/appenders.html#DBAppender。

      简单说明一下,要使用DBAppender,首先要在数据库里创建好三张表

      logging_event

      logging_event_property

      logging_event_exception

      数据库的格式在logback下载包里有,不一定是在网页所写的logback-classic/src/main/java/ch/qos/logback/classic/db/script文件夹,我的版本就是在logback-classic\src\main\resources\ch\qos\logback\classic\db\script下

      创建完数据表后,接着要配置DBAppender的数据源,网页上写的都是xml版本的配置文件,喜欢xml格式的可以直接用。我看到grails自带的是groovy格式的配置文件,所以想着还是用groovy格式比较好(一根筋啊。。。),然而,网页提供的所谓可以把xml自动转换成groovy格式的功能打不开(Service Unavailable)。

 

三、写DBAppender的groovy配置

      没办法,只好自己来写groovy格式的DBAppender配置了,网上没有找到任何资料,所以模仿FileAppender自己写了个DBAppender,代码如下:

      def cs = newDriverManagerConnectionSource()  //这里用了DriverManagerConnectionSource的配置

      cs.setUser("root")    //用户名

      cs.setPassword("123456")    //密码

      cs.setUrl("jdbc:mysql://localhost:3306/icut")   //url

     cs.setDriverClass("com.mysql.jdbc.Driver")  //DriverClass

 

      appender('DB', DBAppender){

          connectionSource = cs

      }

 

      root(ERROR, ['STDOUT'])

      root(Level.INFO, ['DB'])

 

      保存logback.groovy,没有提示错误,说明配置的格式没问题,ok,启动Grails项目,看看能不能成功?很遗憾,报错了:

      DBAppender cannot function if the JDBCdriver does not support getGeneratedKeys method *and* without a specific SQLdialect

      意思是由于没有设置SQL Dialect和是否支持getGeneratedKeys(默认不支持),DBAppender不能正常运行,看来还是要设置一下SQL Dialect或者getGeneratedKeys。然而。。。DriverManagerConnectionSource对象cs没有找到设置SQL Dialect和getGeneratedKeys的方法,这就奇怪了,一方面DBAppender需要你配置这两个属性,另一方面DriverManagerConnectionSource又不允许你去配置,这不是矛盾吗?肯定是自己哪里没搞对。。。

      于是,上网查这个报错的相关资料,得到的一致回答就是设置一下SQL Dialect就可以了,可是。。。可是。。。DriverManagerConnectionSource真的没有权限设置啊。于是,查看了它的源码:

      public classDriverManagerConnectionSource extends ConnectionSourceBase {

          private String driverClass = null;

          private String url = null;

      public void setUrl(String url) {

          this.url = url;

      }

      public void setDriverClass(StringdriverClass) {

          this.driverClass = driverClass;

      }

      以及父类ConnectionSourceBase的源码:

      public abstract classConnectionSourceBase extends ContextAwareBase implements ConnectionSource {

          private boolean started;

          private String user = null;

          private String password = null;

          // initially we have an unknowndialect

          private SQLDialectCode dialectCode = SQLDialectCode.UNKNOWN_DIALECT;

          private booleansupportsGetGeneratedKeys = false;

          private boolean supportsBatchUpdates= false;

      public final void setPassword(finalString password) {

          this.password = password;

      }

      public final void setUser(final Stringusername) {

          this.user = username;

      }

 

      确实只有driverClass、url、user和password这4个属性有set方法,dialectCode和supportsGetGeneratedKeys没有提供set方法,这该如何是好。。。于是,又去网上搜。。。搞了半天还是没解决这个问题。。。

 

四、修改代码

      没办法了,只能用终极大招了,既然你不让我set,我就改你的源代码。复制ConnectionSourceBase的源码,改个名字:MyConnectionSourceBase,增加一个设置dialectCode的public方法

      public final voidsetDialectCode(SQLDialectCode code){this.dialectCode = code;}

 

      接着复制DriverManagerConnectionSource的源码,改个名字MyDriverManagerConnectionSource,最后就是用MyDriverManagerConnectionSource去配置DBAppender,代码如下:

 

      def cs = newMyDriverManagerConnectionSource()  // 自定义的DriverManagerConnectionSource

      cs.setUser("root")    //用户名

      cs.setPassword("123456")    //密码

      cs.setUrl("jdbc:mysql://localhost:3306/icut")   //url

     cs.setDriverClass("com.mysql.jdbc.Driver")    //DriverClass

     cs.setDialectCode(SQLDialectCode.MYSQL_DIALECT)    //可以设置setDialectCode了

 

 

      appender('DB', DBAppender){

          connectionSource = cs

      }

 

      root(ERROR, ['STDOUT'])

      root(Level.INFO, ['DB'])

 

      ok,启动Grails,没有报错,DBAppender成功运行。

 

五、测试

      Grails为Controller注入了log功能,Controller里可以直接调用log来生成日志,例如,我在FunctionController的search函数添加日志功能,记录调用search这个Action的用户和两个search参数:

      log.info("search function :{user:" + u.username +",params:[name:" + name_s +",filename:" + filename_s + "]}")

 

 

 

      打开页面访问FunctionController的search功能,输入参数,点击查询。完成后查看数据库的logging_event数据表,成功记录了本次操作的日志。可以看到,logback自动将时间、日志消息、Conntroller名称、Action名称、代码行等信息记录到了数据库,功能相当阔以了。至此,logback的数据库日志功能已经成功实现,后续只要根据系统设计,在需要记录日志的地方调用log即可。

 

六、小结

      Grails在国内的相关开发资料不是很完善,“规则优于配置”的理念虽然能够提高开发效率,但新手往往对“规则”不了解,以至于很多强大的功能都没有得到有效的利用。Logback也是这样,一开始找不到groovy配置DBAppender的资料,花了很多时间去尝试,结果被一个需要设置又无权限设置参数的、非常奇怪而且矛盾的这么一个问题搞得头痛,好在最后还是搞定了。如果类似的Grails的资料能够多一些,相信就算是新手也能够很快上手,毕竟Grails确实是一款比较优秀的web开发框架。