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:
-
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.
-
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.
-
Find the corresponding classloader for this class
sc -d *xxxService | grep classLoadHash
classLoadHash 6bc26251
Here we get the class loader hash of 6bc26251
-
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.
-
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.
- Locate the label for the code on the line and pull the modify file branch.
- Check out the branch, make changes to specific files, and use it directly
idea
Tools to compile files. That’s when you can get throughtarget
Folder to obtain the corresponding modified file.class
File. - Will this
.class
Files are uploaded to the corresponding server. - Hot update the file directly. (Also known as Step 5 above)
Example 2.
- 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
-
After compiling the entire service through IDEA, the. Class file of the file is obtained.
-
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.
-
Move from mount directory to simple directory. (Test using a long mount directory path, move to a simpler directory such as/TMP)
-
Re-define success after running the re-define command, see RE-define success, size: 1 indicates success
-
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.