18.调试信息输出
概述
在URule Pro提供的所有类型的规则文件中,在它们的属性里都有一个名为“允许调试信息输出”的属性,我们需要做的就是添加这个属性同时设置属性值为“是”,这样规则在运行时默认就会向控制台打印出包含条件匹配信息、动作执行情况等所有日志信息,通过这些信息我们可以跟踪规则执行情况,在规则出现错误或与预期不一致时通过调试信息的输出就可快速定位问题所在。
下图展示的就是添加了“允许调试信息输出”的属性并设置为“是”后的效果。
在URule Pro中还提供了一个名为urule.debug的系统属性,该属性值默认为true,这时所有调试信息默认都会直接在控制台上打印,当将产品部署到生产环境中时,我们需要将urule.debug属性设置为false,这样所有调试信息都不会再输出,这其中也包括URule规则集里提供的名为“打印内容到控制台”的动作,这样就可以快速完成项目上线,而不用担心项目中因有大量调试信息输出而需要重新修改规则属性的问题。如下图所示:
在向导式规则集文件当中,为了更好的统一控制日志开关,在设计器上方的配置按钮菜单下提供了一个针对当前文件级的日志开关控制的菜单项,如下图所示:
一旦我们配置了这个菜单项里的日志开关,那么当前规则文件中没有显示配置是否允许日志输出的规则将采用这里配置的日志开关属性,如果单个规则中配置了日志输出属性,那么将覆盖工具栏中统一配置的日志开关属性。
调试信息输出目的地配置
在代码中调用规则时,如果也要在本地查看调试信息,那么首先需要将urule.debug属性设置为true,接下来为urule.defaultHtmlFileDebugPath属性设置一个具体的已存在的目录值即可。 设置好urule.defaultHtmlFileDebugPath属性后,默认会向这个属性对应的目录中输出以HTML格式的日志文件(默认情况下urule.defaultHtmlFileDebugPath属性值为空,不会输出任何日志文件), 输出的HTML日志文件采用的是时间戳命名方式,在生产环境下建议清空urule.defaultHtmlFileDebugPath属性,以免调试信息输出对性能产生影响。
在规则调用时需要在session.fireRules()或session.startProcess(...)方法后加上session.writeLogFile()方法,这样才会执行日志写入操作。
在某些情况下,为了方便查看,我们可能需要将这些调试信息输出到一个具体的文件,对于这一点,URule Pro也提供了相应的支持。 我们需要做的就是实现一个com.bstek.urule.runtime.log.LogWriter接口的实现类,并将其配置在Spring当中,让其成为一个标准的Spring Bean,这个引擎就可以发现并在日志输出的时候调用, com.bstek.urule.runtime.log.LogWriter接口源码如下:
package com.bstek.urule.runtime.log;
import java.io.IOException;
import java.util.List;
/**
* @author Jacky.gao
* @since 2018年12月11日
*/
public interface LogWriter {
void write(List<Log> logs) throws IOException;
}
在这个LogWriter接口中,要输出的是一个Log接口,如果要实现自己的LogWriter实现类,那么可以对这里的Log接口进行迭代,下面是系统内置的默的输出到控制台的ConsoleLogWriter类源码,实际使用时可以依照此代码来迭代日志信息。
package com.bstek.urule.console.servlet.console;
import java.io.IOException;
import java.util.List;
import com.bstek.urule.runtime.log.DataLog;
import com.bstek.urule.runtime.log.Log;
import com.bstek.urule.runtime.log.LogWriter;
import com.bstek.urule.runtime.log.UnitLog;
/**
* @author Jacky.gao
* @since 2017年11月28日
*/
public class ConsoleLogWriter implements LogWriter {
private DebugMessageHolder debugMessageHolder;
@Override
public void write(List<Log> logs) throws IOException {
StringBuilder sb=new StringBuilder();
buildLogs(sb, logs);
String key=debugMessageHolder.generateKey();
System.out.println("Console key : "+key);
ConsoleKeyHolder.setKey(key);
debugMessageHolder.putDebugMessage(key, sb.toString());
}
private void buildLogs(StringBuilder msg,List<Log> logs) {
for(Log log:logs){
if(log instanceof UnitLog) {
msg.append("<div style=\"margin:8px;border:dashed 1px #cccccc\">");
UnitLog unit=(UnitLog)log;
List<Log> unitLogs=unit.getLogs();
buildLogs(msg, unitLogs);
msg.append("</div>");
}else if(log instanceof DataLog) {
DataLog dataLog=(DataLog)log;
String htmlMsg=dataLog.getHtmlMsg();
msg.append(htmlMsg);
}
}
}
public void setDebugMessageHolder(DebugMessageHolder debugMessageHolder) {
this.debugMessageHolder = debugMessageHolder;
}
}
LogWriter接口实现后配置到Spring上下文环境里,在代码中调用要生效同样需要在session.fireRules()或session.startProcess(...)方法后加上session.writeLogFile()方法, 否则将不会触发执行。
上面介绍的通过配置urule.defaultHtmlFileDebugPath属性就会在指定目录生成日志文件的操作,实际上就是系统提供的一个默认的LogWriter接口实现类,该实现类在运行前会判断urule.defaultHtmlFileDebugPath属性值是否为空, 如果为空,则不做任何操作,不为空,那么就认为这个值是一个目录,并尝试在这个目录中生成HTML格式的日志文件。
最后,再次强调,如果要将项目部署到生产环境,一定要将urule.debug属性设置为false,否则因为有调试信息产生会影响系统性能,urule.debug属性设置为false后,所有的调试信息都将不再输出,包括“打印内容到控制台”的内置动作也不再执行。