This is the 12th day of my participation in the First Challenge 2022

background

Recently, there was an accident in the formal environment. After some business logic, the business end used the wkhtmlTopdf tool to convert HTML to PDF, but after the generation was completed (the normal end, no exception occurred), when the business end obtained the PDF file again, there was no problem with the file.

screening

SaveAsDirect (ftpDir + “/” + path); saveAsDirect(ftpDir + “/” + path); Generated PDF, but did not judge the returned results, so guess that there is no GENERATED PDF file.

private boolean uploadToPdfDirect(WrapperConfig config, String sourceString, String path) {
    try {
        Pdf pdf = new Pdf(config);
        pdf.setAllowMissingAssets();
        pdf.addPageFromString(sourceString);
        pdf.addParam(pageInfo);
        pdf.saveAsDirect(ftpDir + "/" + path);
    } catch (IOException | InterruptedException e) {
        log.error(WkHtmlToPdf exception: {}, e.getMessage());
        // Restore the interrupted status after catching InterruptedException
        Thread.currentThread().interrupt();
        throw new RuntimeException("WkHtmlToPdf exception:" + e.getMessage());
    }
    return true;
}
Copy the code

According to my guess, I hope to modify the code as follows :(I intended to modify the following code with the help of Arthas, but due to the continuous data generation on line and the increasing accident area, there was no time to study the use of Arthas, so I had to go through the tedious process of sending packages to replace the packages in the formal environment)

private boolean uploadToPdfDirect(WrapperConfig config, String sourceString, String path) {
    try {
        Pdf pdf = new Pdf(config);
        pdf.setAllowMissingAssets();
        pdf.addPageFromString(sourceString);
        pdf.addParam(pageInfo);
        // Check whether the generated file is generated
        File file = pdf.saveAsDirect(ftpDir + "/" + path);
        if(! file.exists()){throw new BusinessException("File generation failed"); }}catch (IOException | InterruptedException e) {
        log.error(WkHtmlToPdf exception: {}, e.getMessage());
        // Restore the interrupted status after catching InterruptedException
        Thread.currentThread().interrupt();
        throw new RuntimeException("WkHtmlToPdf exception:" + e.getMessage());
    }
    return true;
}
Copy the code

To the chase

After a long wait for the release process, it is already midnight to wait for the official environment replacement package. After testing, it is true that the PDF file was not generated (if you were using Arthas, the problem should have been resolved by this point). It is important to note that, so far, it is only known that the build fails in this way, and it is not known under what circumstances the build fails, as the development environment, test environment, and pre-release environment are all built normally. I decided to learn about Arthas.

1. Use

Simple use process:

  1. Find the class full path to which you want to add code and decompile it into a folder.

    jad –source-only com.xxx.service.v3.xxxService > /tmp/xxxService.java

    This is a.class decompilation to a.java file, so it’s not that friendly to read, actually I thought of using Arthas when the problem first arose, but was dissuaded by the decompilation code, which even had instructions reordered and didn’t dare to modify the decompilation file.

  2. Modify the decompilation file

    vim /tmp/UserController.java

    In this case, you need to exit arthas. When you first use arthas, you think you can manipulate files directly from the arthas command line. In fact, you should exit Arthas and use Linux commands to modify files.

  3. Find the corresponding classloader for this class

    sc -d *xxxService | grep classLoadHash

    classLoadHash 6bc26251

    Here we get the class loader hash of 6bc26251

  4. Use this classloader to compile the modified file as a.class file

    mc -c 6bc26251 /tmp/xxxService.java -d /tmp

    A.class file with the package structure as the file path will be generated in the/TMP folder.

  5. Hot update

    redefine /tmp/com/xxx/service/v3/xxxService.class

    Re-define success, size: 1

In this way, the probability of problems is very high, because the decompilation file needs to be modified, and some instructions seem to be rearranged in the decompilation file, which makes it difficult to read. In fact, the first four steps above are to get the modified. Class file, so in fact we can use IDEA to process.

  1. Locate the label for the code on the line and pull the modify file branch.
  2. Check out the branch, make changes to specific files, and use it directlyideaTools to compile files. That’s when you can get throughtargetFolder to obtain the corresponding modified file.classFile.
  3. Will this.classFiles are uploaded to the corresponding server.
  4. Hot update the file directly. (Also known as Step 5 above)

Example 2.

  1. Adds a log print to the service layer of an interface.
public RequireFileVo getFiles(ParamVo ParamVo, Integer pageNum, Integer pageSize) {
        // Add this line of log to print page number
        log.info("pageSize:{}", pageSize);
        // The following is a very complex business logic
}
Copy the code
  1. After compiling the entire service through IDEA, the. Class file of the file is obtained.

  2. Upload to the server. Since the service runs in docker, move the file to the mount directory of docker and the host after uploading to the server.

  3. Move from mount directory to simple directory. (Test using a long mount directory path, move to a simpler directory such as/TMP)

  4. Re-define success after running the re-define command, see RE-define success, size: 1 indicates success

  5. Test, called by Postman

    2021-11-18 10:43:30.491 [TraceId=92aeb19c3e8ce62b,SpanId=92aeb19c3e8ce62b,ParentSpanId=] [http-nio-20065-exec-5] INFO  c.b.g.b.s.v.s.xxxService-pageSize:10
    
    Copy the code

conclusion

Arthas is used to troubleshoot production services non-stop, eliminating some of the tedious process of raising and testing. Arthas also provides many other features for troubleshooting production problems, such as viewing memory conditions, JVM parameters, interface call chains, parameter types, and more.