V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
tiRolin
V2EX  ›  Java

本地调用没有问题,然而到生产环境就报错这种问题该怎么排查?

  •  
  •   tiRolin · 17 小时 5 分钟前 · 1077 次点击

    最近我负责的某个项目新增了功能,然而发版之后就报错,具体日志报下面的问题

    java.lang.NullPointerException
    	at java.util.regex.Matcher.getTextLength(Matcher.java:1283)
    	at java.util.regex.Matcher.reset(Matcher.java:309)
    	at java.util.regex.Matcher.<init>(Matcher.java:229)
    	at java.util.regex.Pattern.matcher(Pattern.java:1093)
    	at java.util.Formatter.parse(Formatter.java:2547)
    	at java.util.Formatter.format(Formatter.java:2501)
    	at java.util.Formatter.format(Formatter.java:2455)
    	at java.lang.String.format(String.java:2940)
    	at com.orgexample.common.core.exception.BusinessException.<init>(BusinessException.java:36)
    	at com.orgexample.common.core.exception.BusinessException.<init>(BusinessException.java:26)
    	at com.orgexample.tourism.tourism.util.DstZipUtil.compressFileList(DstZipUtil.java:46)
    	at com.orgexample.tourism.tourism.versionfile.service.VersionFileService.generateZipFile(VersionFileService.java:142)
    	at com.orgexample.tourism.tourism.versionfile.service.VersionFileService.generateVersionZipFile(VersionFileService.java:97)
    	at com.orgexample.tourism.tourism.support.ExecutionApiTimerTaskService.generateJsonOfflinePackage(ExecutionApiTimerTaskService.java:331)
    	at com.orgexample.tourism.tourism.support.ExecutionApiTimerTaskService.executeTimeTask(ExecutionApiTimerTaskService.java:212)
    	at com.orgexample.tourism.tourism.support.ExecutionApiTimerTaskService.updateDstApiManageVersion(ExecutionApiTimerTaskService.java:80)
    	at com.orgexample.tourism.tourism.support.ExecutionApiTimerTaskService$$FastClassBySpringCGLIB$$c7558311.invoke(<generated>)
    	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:746)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    	at org.springframework.aop.interceptor.AsyncExecutionInterceptor.lambda$invoke$0(AsyncExecutionInterceptor.java:115)
    	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    	at java.lang.Thread.run(Thread.java:750)
    
    

    根据异常,显然定位到发生问题的异常代码在下面的代码中

      /**
       * 批量压缩文件 v4.0
       *
       * @param fileNames  需要压缩的文件名称列表(包含相对路径)
       * @param zipOutName 压缩后的文件名称
       **/
      public static void compressFileList(String zipOutName, List<String> fileNameList) {
        ThreadFactory factory = new ThreadFactoryBuilder().setNameFormat("compressFileList-pool-").build();
    //    ExecutorService executor = new ThreadPoolExecutor(5, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(20), factory);
        ExecutorService executor = Executors.newFixedThreadPool(40, factory);
        ParallelScatterZipCreator parallelScatterZipCreator = new ParallelScatterZipCreator(executor);
        try (OutputStream outputStream = new FileOutputStream(zipOutName)) {
          ZipArchiveOutputStream zipArchiveOutputStream = new ZipArchiveOutputStream(outputStream);
          zipArchiveOutputStream.setEncoding("UTF-8");
          for (String fileName : fileNameList) {
            File file = new File(fileName);
            getFiles(parallelScatterZipCreator, file.getName(), file);
          }
          parallelScatterZipCreator.writeTo(zipArchiveOutputStream);
          zipArchiveOutputStream.close();
        } catch (IOException | ExecutionException | InterruptedException e) {
          throw new BusinessException(e.getMessage());
        }
      }
    
    

    这里麻烦各位先忽略这个代码的槽点吧,我也很想吐槽,但是这是 21 点的代码,不知道是哪位离职的同事写的,改是没法改了,只能将就着看了

    由于生产环境不能 Debug 调试,所以只能确定是这里出了空指针异常,但是不知道具体是哪里出了异常,又是因为什么出的异常

    我新增的功能联系了三张表,我尝试将这三张表都提取出来,在本地环境还原到没部署前的节点,此时在本地运行该接口,并不会报错,但是在生产环境就报错,而且该问题是在我新版本发版之后产生的,确定过好几遍,数据库是没问题的,几乎是保证和生产环境和本地环境一致了,然而在本地就是没问题,在生产就是有问题

    代码问题也排查过了,进入部署的 jar 包中查看发现本次发版部署的代码也存在

    生产环境的权限只有运维有权限操作,我一个开发尽可能就不想打印很多日志然后让生产部署上去再运行一遍查看效果就是,所以打印更详细的日志这个方法还没使用

    想问问各位知道出现这种问题有什么解决思路吗?我想先试试你们的解决方法,如果能解决就不搞这么麻烦了

    15 条回复    2025-01-09 20:41:49 +08:00
    wowo243
        1
    wowo243  
       17 小时 4 分钟前
    arthas 调试看下入参返回值之类的
    noobility
        2
    noobility  
       16 小时 56 分钟前
    异常发生在 com.orgexample.common.core.exception.BusinessException.<init>(BusinessException.java:26),看着是你的 BusinessException 会对传入的 e.getMessage()调用 String.format ,然而这个字符串为 null ,就抛 NPE 了
    zbatman
        3
    zbatman  
       16 小时 52 分钟前
    看样子像是 BusinessException 本身的异常
    liprais
        4
    liprais  
       16 小时 49 分钟前
    NPE 这么好查还不会么,看到哪断了就是那有问题
    niurougaodanbaid
        5
    niurougaodanbaid  
       16 小时 41 分钟前
    arthas
    pxiphx891
        6
    pxiphx891  
       16 小时 27 分钟前
    报的哪一行,就看哪一行不就行了吗
    label
        7
    label  
       16 小时 17 分钟前
    增加日志, 把每行结果都打印一下
    XXWHCA
        8
    XXWHCA  
       16 小时 16 分钟前
    #2 #3 楼正确答案,e.getMessage()返回值是可为空的,所以进行 format 之前需要判空。
    多种异常一起捕获,message 的内容更加不可控,这种情况先打印日志再抛出异常。
    chairuosen
        9
    chairuosen  
       16 小时 14 分钟前
    不知道 java 能不能打印 catch 的那个 e 的 stack ,能打印原始错误栈最好。
    另外,最土的办法,但也最实用,在 try catch 外面定义一个变量记录状态,try 里面每一行代码之后改变一下记录的值比如 stage=012345 ,在 catch 时打印这个 stage ,就知道报错时走到哪一步了,另外把中间变量也记住,就能知道具体报错的 fileName 或者 file 是咋回事。
    wolfie
        10
    wolfie  
       15 小时 54 分钟前
    没人吐槽线程池?
    调用一次,创建一个新的线程池,还不关闭。
    prosgtsr
        11
    prosgtsr  
       15 小时 19 分钟前
    BusinessException.<init>
    看看 new 方法

    话说:这是 21 点(年)的代码,不知道是哪位离职的同事写的,改是没法改了,只能将就着看了
    我的工作:这一块是 16 年的代码,但是还得改
    oliverCC
        12
    oliverCC  
       14 小时 45 分钟前
    throw new BusinessException(e.getMessage());
    从日志上看这行抛出了异常,原因是你的 try catch 中发生了空指针异常,但是你这行代码没有记录日志。
    正常写法应该是
    log.error(String.format("压缩文件出错%s",e.getMessage()),e);
    throw new BusinessException(e.getMessage(),e);

    从你现有代码来看,大概率是 循环中的 getFiles 方法内有问题导致的。

    之所以生产环境会报错,而本地自测不报错 那是因为程序运行时变量不同(变量包括不限于程序报错时的出入参、机器各项指标参数等 代码相同只是这些变量中的一个)

    对于已经出现的这个报错如果不能添加日志来排查,可以看下能否找到这个报错之前的一些出入参和打包的文件,所有变量和本地报错一致自测复现。
    如果日志这条路走不通,可以按照楼上说的 安装 arthas 或者 分布式链路追踪 pinpoint 、SkyWalking 、Zipkin 这些工具也可以作为排查的思路。
    sampeng
        13
    sampeng  
       14 小时 34 分钟前   ❤️ 1
    昨天还和同事聊 AI 的影响呢,现在就已经很多很多 3-5 年的程序员连怎么调试和分析日志都做不到,或者很慢了。
    如果 AI 编程变成非常普遍的工具,AI 能解决的,AI 会分析出来告诉你怎么搞。AI 不能解决的呢?这玩意真的是经验值,不是 AI 训练得出来的。个人感觉排 bug 有点俺寻思之力的味道,就是经验在那里,有时候突然灵光一闪,是和这个 bug 半毛钱关系的地方可能有影响,我不觉得 AI 能分析一个远大过他 token 数目的复杂项目。
    xuanbg
        14
    xuanbg  
       13 小时 14 分钟前
    可能是服务器上没有足够权限
    tiRolin
        15
    tiRolin  
    OP
       10 小时 3 分钟前
    @sampeng 这些事情只能靠经验吧,我还在实习,大学期间调过项目,但是基本都是本地的 Bug 很好解决,这种问题是第一次见,我不知道该如何快速解决,我的水平比较低,只能一步一步走
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1052 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 22:45 · PVG 06:45 · LAX 14:45 · JFK 17:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.