sofastack / sofa-rpc

SOFARPC is a high-performance, high-extensibility, production-level Java RPC framework.
https://www.sofastack.tech/sofa-rpc/docs/Home
Apache License 2.0
3.81k stars 1.17k forks source link

业务代码抛出异常之后,框架没有打印异常信息 #513

Closed OrezzerO closed 5 years ago

OrezzerO commented 5 years ago

Your question

业务代码抛出异常之后,框架没有打印异常堆栈

Rest 协议异常请求流程

  1. netty 客户端接收网络请求
  2. resteasy 交给具体处理类
  3. 处理方法抛出异常
  4. MethodInjectorImpl 包装成 ApplicationException
  5. dispatcher 处理异常,将异常对应的 response 写入返回流中
  6. 如果不能处理这个异常,抛出 UnhandledException
  7. SofaRestRequestHandler 兜底处理异常,打印异常堆栈

SofaRestRequestHandler 兜底处理异常,打印异常堆栈

然而,SofaRestRequestHandler 中的 logger 是由 org.jboss.resteasy.logging.Logger这个特殊的 Logger 构造出来的. 如果不指定日志实现, 这个 Logger 的日志实现是由以下代码指定的:

static
 {
    LoggerType type = LoggerType.JUL;

    if (classInClasspath("org.apache.log4j.Logger"))
    {
       type = LoggerType.LOG4J;
    }
    else if (classInClasspath("org.slf4j.Logger"))
    {
       type = LoggerType.SLF4J;
    }

    setLoggerType(type);
 }

可以看出,Log4j 的优先级是高于 SLF4j 的. 我们很难在依赖中完全去除org.apache.log4j.Logger这就导致了我们整体上使用 Logback,SofaRestRequestHandler这个类以及 resteasy 相关类中的日志依然使用log4j打印.

解决方案

显示指定 resteasy 使用的日志框架:

   Logger.setLoggerType(Logger.LoggerType.SLF4J);

Environment

JervyShi commented 5 years ago

@OrezzerO 这里使用 SOFA RPC 自己内置的 com.alipay.sofa.rpc.log.Logger 更合适,内置 Logger 的实现会通过用户环境内依赖的日志实现 jar 来自动选择,这里应该是漏掉了,可以提个 PR Fix 这个问题么?

OrezzerO commented 5 years ago

@JervyShi 我觉得这么处理还是不够的, 因为 resteasy 内部是用org.jboss.resteasy.logging.Logger,光改掉这个类是不够的.

我的想法是把 com.alipay.sofa.rpc.log.Loggerorg.jboss.resteasy.logging.Logger使用的具体的日志实现类指定成一样的

JervyShi commented 5 years ago

@OrezzerO 是说框架主动做 Logger.setLoggerType(Logger.LoggerType.SLF4J); 吗?这种方式对用户不太友好,选择权还是应该在用户手中,按照 org.jboss.resteasy.logging.Logger 的实现逻辑,只有应用内有 org.apache.log4j.Logger 时才会启用,所以可以主动排除掉项目中 log4j 的依赖吧,然后就走到 SLF4J 了。

OrezzerO commented 5 years ago

@JervyShi 并不是说直接指定SLF4J而是说,org.jboss.resteasy.logging.Loggercom.alipay.sofa.rpc.log.Logger行为一致, com.alipay.sofa.rpc.log.Logger指定slf4j,那么org.jboss.resteasy.logging.Logger也是指定 slf4j. com.alipay.sofa.rpc.log.Logger指定log4j,那么org.jboss.resteasy.logging.Logger也是指定 log4j.

作为框架的提供者,我们不应该规定用户用什么日志实现,同样的,我们也不能保证用户是否同时依赖多个日志框架/(ㄒoㄒ)/~~

leizhiyuan commented 5 years ago

refer to https://github.com/sofastack/sofa-rpc/issues/513