博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Mule ESB Http项目转换为Tomcat项目(9) 日志问题处理
阅读量:6042 次
发布时间:2019-06-20

本文共 8008 字,大约阅读时间需要 26 分钟。

hot3.png

     Mule ESB项目的日志输出有两种方式,可以在流程中添加Logger组件输出日志,也可以在自定义的代码中添加日志输出。Mule ESB日志使用Log4j2库进行输出,Mule ESB 企业版使用的log4j2版本是2.1。

     我们在ESB项目中拖入一个Logger控件,输出经过Transformer转化后的Json 报文。

143002_c9Wn_237688.png

这里Logger控件里的Message内容为#[message.payloadAs(java.lang.String)],使用的是MEL(Mule Expression Language),等效于message.getPayloadAsString()

拖拽Logger控件后,在项目的src/main/resources目录下生成了log4j2.xml文件,用于配置Log4j2的日志输出

144558_9WrX_237688.png

log4j2.xml的内容如下:

可以看出Mule ESB的日志输出采用的是异步方式。

以Debug方式启动ESB项目, 调用ESB接口,控制台输出了Json报文日志

INFO  2016-06-29 15:15:33,335 [[testproject].HTTP_Listener_Configuration.worker.01] org.mule.api.processor.LoggerMessageProcessor: {"students":[{"name":"张三","id":"197","class":"1年1班"},{"name":"李四","id":"198","class":"1年2班"},{"name":"赵五","id":"199","class":"1年3班"}]}

同时查看项目对应的日志文件(位置在Anypoint Studio的workspace目录的.mule/logs子目录下)

152034_8fUa_237688.png

打开testproject.log文件,可以看到上述的日志信息也写入了日志文件。

从日志信息可以看出,Logger控件的日志是在org.mule.api.processor.LoggerMessageProcessor类中输出的,具体是在log(MuleEvent event)方法中输出的

protected void log(MuleEvent event) {    if (event == null)     {        logWithLevel(null);    }     else     {        if (StringUtils.isEmpty(message))         {            logWithLevel(event.getMessage());        } else         {            LogLevel logLevel = LogLevel.valueOf(level);            if (LogLevel.valueOf(level).isEnabled(logger))             {                logLevel.log(logger, expressionManager.parse(message, event));            }        }    }}public enum LogLevel{   INFO   {      @Override      public void log(Log logger, Object object)       {         logger.info(object);      }

而记录日志的logger对象是在ESB项目启动,加载Mule容器时调用LoggerMessageProcessor类的initLogger方法构造的,构造Logger的大致流程是这样的:

160752_AOPs_237688.png

这里的流程图只描绘了LoggerMessageProcessor的logger对象构建的几个主要类和方法,可以看出Logger控件的日志输出与Mule容器的启动和初始化密切相关。如果ESB项目迁移到Web项目,则实际运行环境变成了Tomcat环境,加载类变成了org.mule.config.builders.MuleXmlBuilderContextListener,而我们查看MuleXmlBuilderContextListener类的初始化方法

public void initialize(ServletContext context)    {        String config = context.getInitParameter(INIT_PARAMETER_MULE_CONFIG);        ....................        try        {            muleContext = createMuleContext(config, context);            context.setAttribute(MuleProperties.MULE_CONTEXT_PROPERTY, muleContext);            muleContext.start();        }        ....................

可以看出这里没有对MuleContainer的初始化方法调用,Logger Component使用的Logger对象没有被初始化,因此在Web项目里使用Logger组件将不会输出日志,无论是控制台还是文件,我们需要自定义Logger类输出日志。

我们在用于转换的Transformer类中添加Log4j2的Logger对象

private static Logger logger = LogManager.getLogger(CustomJsonTransformer.class);

再在json报文转换结束后使用这个logger对象输出转换后的json报文。

try {	            String jsonMessage = message.getPayloadAsString();		            //添加信息	            JSONObject jsonMap = updateStudentInfos(jsonMessage);	            transformJsonStr = jsonMap.toJSONString();	            if(!Strings.isBlank(transformJsonStr))	            {	            	logger.info("The json message after transformation is:" + transformJsonStr);	            }	        } catch (Exception e) {	        		e.printStackTrace();	        }

因为我们使用的是Log4j2在Tomcat容器中进行日志输出,根据查阅的资料,我们需要引入log4j-web这个jar包,因为Mule默认使用的log4j-core版本是2.1,我们引入的log4j-web也使用2.1版本,将这个jar文件拷贝到mule_libs/opt目录下。

此外我们需要修改log4j2.xml文件,ESB项目创建的log4j2.xml的日志文件输出到mule的workspace目录下,我们将其修改为输出到tomcat的logs目录下,修改后的log4j2.xml文件

${sys:catalina.home}/logs/

这里的${sys:catalina.home}指的是当前运行的tomcat根目录,另外基于我们自定义的代码包路径,我们添加了一个Logger。

需要注意的是在web项目中,log4j2.xml文件必须放置在WEB-INF根目录下,和web.xml同一级目录,为此我们需要将log4j2.xml文件移动到src/main/app目录下。

修改完成后,我们部署重新生成的web项目到tomcat环境,调用接口。

可以看到Tomcat的运行时窗口输出了日志信息:

174614_y7zq_237688.png

同时在tomcat的logs目录下生成了testproject.log文件,

174815_vEQo_237688.png

testproject.log文件中输出了控制台窗口输出的json报文日志

174914_Gs1b_237688.png

     使用自定义Logger,我们可以将需要的程序运行信息输出到控制台和日志文件,对于自定义代码中抛出的异常,我们可以直接输出日志,但如果是流程运行过程中抛出的异常信息,该如何捕捉异常信息,并将其输出呢?

      我们需要使用Mule的Catch Exception Strategy控件。

     我们在流程文件中加入Catch Exception Strategy控件,放置在Error Handling下

181957_DVZS_237688.png

 我们在这个控件中拖入两个控件,Set Payload和Logger控件,

    Set Payload控件将异常信息设置为Mule Message的Payload,返回给调用端(否则Mule Message的Payload仍然是请求的Payload),logger控件则将异常信息作为日志输出。

    #[message.cause.exception]同样是MEL表达式,表示异常的Root Cause信息。

   添加完异常处理控件后,我们修改自定义的Transformer类的transformMessage方法,将原先返回的转换好的json报文替换为null。这样当运行到Data Weaver数据映射时,流程将会抛出异常,我们可以查看异常信息是如何被Catch Exception Strategy控件捕捉并处理的。

   调用ESB接口后,系统输出的异常日志为:

ERROR 2016-06-29 18:20:30,035 [[testproject].HTTP_Listener_Configuration.worker.01] org.mule.api.processor.LoggerMessageProcessor: The object transformed is of type: "SimpleDataType{type=org.mule.transport.NullPayload, mimeType='*/*', encoding='null'}", but the expected return type is "SimpleDataType{type=java.lang.String, mimeType='application/json', encoding='UTF-8'}".

   调用端返回的响应消息是:

182306_YDIz_237688.png   这里输出的异常信息仅显示了异常的Root Cause信息,如果要详细的堆栈信息,我们需要修改#[message.cause.exception]为#[org.mule.util.ExceptionUtils.getFullStackTrace(exception)]

修改后再调用接口,异常的堆栈信息被输出到日志和调用端

183908_FcQp_237688.png

183948_ndbK_237688.png

由于添加了Catch Exception Strategy控件,流程运行过程中的异常被捕捉了,返回的响应状态代码变成了200,这显然不是服务器端真实的状态,因此我们需要重新设置响应的Status Code.

我们在Catch Exception Strategy控件中添加设置Status Code状态的代码

再次调用接口,可以看到返回的响应Status Code变成了500

103908_E99w_237688.png

在Web项目中,我们不能使用Logger输出日志,我们有三种方式输出日志:

1)自定义Transformer中添加Logger输出日志。

2)自定义Component中添加Logger输出日志。

3)自定义MessageProcessor在处理Mule Event时输出日志。

第一种方式上面已经提到了,这里不再赘述,重点说一下第二种和第三种方式。

从Mule 3.8起,自定义Component需要实现接口org.mule.api.lifecycle.Callable的onCall方法

我们自定义的Component类代码如下:

package com.mule.spring.components;import org.mule.api.MuleEventContext;import org.mule.api.lifecycle.Callable;import org.mule.util.ExceptionUtils;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;public class CustomComponent implements Callable {	private static Logger logger = LogManager.getLogger(CustomComponent.class);	@Override	public Object onCall(MuleEventContext eventContext) throws Exception {		String exceptionMessage = 				ExceptionUtils.getFullStackTrace(eventContext.getMessage().getExceptionPayload().getException());		logger.error(exceptionMessage);	        return eventContext.getMessage();	}}

在Catch Exception Strategy中引用这个Component如下:

自定义MessageProcessor如下:

package com.mule.spring.messageprocessors;import org.mule.api.MuleEvent;import org.mule.api.MuleException;import org.mule.api.processor.MessageProcessor;import org.mule.util.ExceptionUtils;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;public class LoggerMessageProcessor implements MessageProcessor {	private static Logger logger = LogManager.getLogger(LoggerMessageProcessor.class);		@Override	public MuleEvent process(MuleEvent event) throws MuleException 	{				String exceptionMessage =         		ExceptionUtils.getFullStackTrace(event.getMessage().getExceptionPayload().getException());        logger.error(exceptionMessage);			return event;	}}

在Catch Exception Strategy中引用这个Message Processor如下:

由于输出堆栈信息时引用了common-lang的ExceptionUtils类(org.mule.utils.ExceptionUtils的父类),我们需要在pom.xml中引入common-lang的jar包保证编译通过。

commons-lang
commons-lang
2.6
provided

Web项目最后的Catch Exception Strategy设置如下:

这里设置Content-Type为text/plain,因为返回的异常堆栈信息是纯文本形式,不是json或者xml形式。

重新编译web项目并部署,调用接口,可以看到返回的响应是500: Internal Server Error

180444_8WXj_237688.png

 

在testproject.log文件中也显示了异常堆栈信息

180646_flg1_237688.png

 

转载于:https://my.oschina.net/u/237688/blog/701740

你可能感兴趣的文章
【Visual C++】游戏开发笔记之九 游戏地图制作(一)平面地图贴图
查看>>
ACCP学习旅程之----- CSS样式库
查看>>
Apache日志Shell分析
查看>>
freemarker中日期的比较
查看>>
特殊用法
查看>>
Linux service管理自定义脚本
查看>>
mysql创建date数据类型
查看>>
linux开机图形界面和字符界面切换
查看>>
sphinx的安装
查看>>
scsi_cnmd.h
查看>>
ESXi5中win2003使用LSI logic SAS磁盘
查看>>
一个java对象占多少内存空间
查看>>
发快递激光焊接客服电话关机后发的
查看>>
MySQL 几种连接方式配置
查看>>
线上追踪类方法执行耗时
查看>>
恩布企业IM,协同办公平台发布V1.24版本
查看>>
媒体查询引入的三种方式
查看>>
Serv-U Passive被动模式端口设置
查看>>
字符编码的知识
查看>>
js的history.pushstate()作用
查看>>