Skip to content

Commit 19434ab

Browse files
authored
Reading Stacktraces and debugging Plugins (#187)
1 parent 85fd487 commit 19434ab

File tree

9 files changed

+181
-0
lines changed

9 files changed

+181
-0
lines changed

config/sidebar.paper.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,19 @@ const paper: SidebarsConfig = {
120120
"dev/api/custom-inventory-holder",
121121
],
122122
},
123+
{
124+
type: "category",
125+
label: "Miscellaneous",
126+
collapsed: true,
127+
link: {
128+
type: "doc",
129+
id: "dev/misc/README",
130+
},
131+
items: [
132+
"dev/misc/reading-stacktraces",
133+
"dev/misc/debugging",
134+
],
135+
},
123136
],
124137
},
125138
],

docs/paper/dev/misc/README.mdx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import DocCardList from "@theme/DocCardList";
2+
import { useCurrentSidebarCategory } from "@docusaurus/theme-common";
3+
4+
# Miscellaneous Development Guides
5+
6+
These guides are for helping developers with parts of the development process that don't fit into the other categories.
7+
8+
---
9+
10+
<DocCardList items={useCurrentSidebarCategory().items} />
4.14 KB
Loading
23.3 KB
Loading
3.67 KB
Loading
2.17 KB
Loading
40.4 KB
Loading

docs/paper/dev/misc/debugging.md

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
---
2+
slug: /dev/debugging
3+
---
4+
5+
# Debugging your plugin
6+
7+
Debugging your plugin is vital to being able to fix bugs and issues in your plugin. This page will cover some of the most common debugging techniques.
8+
9+
### Printing to the console
10+
11+
One of the most common debugging techniques is to print to the console. This is likely something you've done before, as it's very simple.
12+
This has a few downsides, though. It can be hard to find the print statements in the console, and it can be hard to remove them all when you're done debugging. Most notably, you have to recompile your plugin and restart the server to add or remove debugging.
13+
14+
When debugging, you can use `System.out.println("");` to print to the console. It is recommended to use your plugin's logger instead though,
15+
as it will be easier to know which plugin the log has come from. This can be done simply with:
16+
17+
```java
18+
plugin.getComponentLogger().debug(Component.text("SuperDuperBad Thing has happened"));
19+
```
20+
21+
:::note[Logger Levels]
22+
23+
In some consoles, using the `warning` level will print the message in different colours.
24+
This can be useful for finding your print statements in the console.
25+
26+
:::
27+
28+
### Using a remote debugger
29+
30+
A debugger is a tool that allows you to pause your code at a certain point and inspect the values of variables.
31+
This can be very useful for finding out why your code isn't working as expected and also for finding out where your code is going wrong.
32+
33+
#### Setting up the debugger
34+
35+
To use a debugger, you need to set up your IDE to use it. This is different for each IDE, but for the sake of this guide, we will be using IntelliJ IDEA.
36+
37+
To set up a debugger in IntelliJ, you need to create a new run configuration.
38+
You can do this by clicking the dropdown next to the run button and clicking `Edit Configurations...`:
39+
40+
![](./assets/config_dropdown.png)
41+
42+
Then, click the `+` button in the top left and select `Remote JVM Debug`. You can then name the configuration whatever you want, and click `Apply`:
43+
44+
![](./assets/config_add.png)
45+
46+
Finally, copy the command line arguments from the window, and paste these into your server's startup script.
47+
These will go after the `java` command and before `-jar`. Once you have done this, you can click `OK`. For example:
48+
49+
```bash
50+
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 -jar paper-1.20.1.jar nogui
51+
```
52+
53+
Once your server is running, you can use the bug icon in the top right to connect your debugger to the server:
54+
55+
![](./assets/debugger_connect.png)
56+
57+
#### Using the debugger
58+
59+
Let's say we have this code:
60+
61+
```java
62+
@EventHandler
63+
public void onPlayerMove(PlayerMoveEvent event) {
64+
Player player = event.getPlayer();
65+
Location location = player.getLocation();
66+
67+
if (location.getWorld() == null)
68+
return;
69+
70+
if (location.getWorld().getEnvironment() == World.Environment.NETHER) {
71+
player.sendMessage("You are in the nether!");
72+
}
73+
}
74+
```
75+
76+
You can add a breakpoint to the line by clicking on the line number:
77+
78+
![](./assets/add_breakpoints.png)
79+
80+
This will pause the code when it reaches that line. You can then use the debugger to inspect the values of variables:
81+
82+
![](./assets/debugger_use.png)
83+
84+
You can inspect the values of each of the variables in the current scope.
85+
You can also use the buttons in the top to step from one breakpoint to the next.
86+
If needed, you can also use the text box at the top to evaluate expressions for debugging purposes.
87+
88+
### Using direct debugging
89+
90+
Direct debugging will allow you to run the server directly from your IDE, and will allow you to use breakpoints and step through your code.
91+
We can achieve this by using [JPenilla's Gradle plugin](https://github.com/jpenilla/run-task) to run the server directly from the IDE.
92+
See [here](https://github.com/jpenilla/run-task#basic-usage) for instructions on how to set up the plugin.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
---
2+
slug: /dev/reading-stacktraces
3+
---
4+
5+
# Reading Stacktraces
6+
7+
## What is a stacktrace?
8+
In Java, a stacktrace shows the call stack of a thread. The call stack is the path of execution that led to the current point in the program.
9+
Usually, the stacktrace will be printed to the console when an exception is not handled correctly.
10+
11+
Stacktraces are a useful tool for debugging your code. They show you the exact line of code that caused an error, and the
12+
line of code that called that line of code, and so on. This is useful because it allows you to see the exact path of execution that led to the error.
13+
14+
### Example:
15+
16+
Here is an example of a stacktrace which has been caused due to a `NullPointerException`:
17+
18+
```
19+
[15:20:42 ERROR]: Could not pass event PluginEnableEvent to TestPlugin v1.0
20+
java.lang.NullPointerException: Cannot invoke "Object.toString()" because "player" is null
21+
at io.papermc.testplugin.TestPlugin.onPluginEnable(TestPlugin.java:23) ~[TestPlugin-1.0-SNAPSHOT.jar:?]
22+
at com.destroystokyo.paper.event.executor.asm.generated.GeneratedEventExecutor1.execute(Unknown Source) ~[?:?]
23+
at org.bukkit.plugin.EventExecutor$2.execute(EventExecutor.java:77) ~[paper-api-1.20.1-R0.1-SNAPSHOT.jar:?]
24+
at co.aikar.timings.TimedEventExecutor.execute(TimedEventExecutor.java:81) ~[paper-api-1.20.1-R0.1-SNAPSHOT.jar:git-Paper-49]
25+
at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:70) ~[paper-api-1.20.1-R0.1-SNAPSHOT.jar:?]
26+
at io.papermc.paper.plugin.manager.PaperEventManager.callEvent(PaperEventManager.java:54) ~[paper-1.20.1.jar:git-Paper-49]
27+
at io.papermc.paper.plugin.manager.PaperPluginManagerImpl.callEvent(PaperPluginManagerImpl.java:126) ~[paper-1.20.1.jar:git-Paper-49]
28+
at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:615) ~[paper-api-1.20.1-R0.1-SNAPSHOT.jar:?]
29+
at io.papermc.paper.plugin.manager.PaperPluginInstanceManager.enablePlugin(PaperPluginInstanceManager.java:200) ~[paper-1.20.1.jar:git-Paper-49]
30+
at io.papermc.paper.plugin.manager.PaperPluginManagerImpl.enablePlugin(PaperPluginManagerImpl.java:104) ~[paper-1.20.1.jar:git-Paper-49]
31+
at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:507) ~[paper-api-1.20.1-R0.1-SNAPSHOT.jar:?]
32+
at org.bukkit.craftbukkit.v1_20_R1.CraftServer.enablePlugin(CraftServer.java:636) ~[paper-1.20.1.jar:git-Paper-49]
33+
at org.bukkit.craftbukkit.v1_20_R1.CraftServer.enablePlugins(CraftServer.java:547) ~[paper-1.20.1.jar:git-Paper-49]
34+
at net.minecraft.server.MinecraftServer.loadWorld0(MinecraftServer.java:636) ~[paper-1.20.1.jar:git-Paper-49]
35+
at net.minecraft.server.MinecraftServer.loadLevel(MinecraftServer.java:435) ~[paper-1.20.1.jar:git-Paper-49]
36+
at net.minecraft.server.dedicated.DedicatedServer.initServer(DedicatedServer.java:308) ~[paper-1.20.1.jar:git-Paper-49]
37+
at net.minecraft.server.MinecraftServer.runServer(MinecraftServer.java:1101) ~[paper-1.20.1.jar:git-Paper-49]
38+
at net.minecraft.server.MinecraftServer.lambda$spin$0(MinecraftServer.java:318) ~[paper-1.20.1.jar:git-Paper-49]
39+
at java.lang.Thread.run(Thread.java:833) ~[?:?]
40+
```
41+
42+
- Firstly, we can see that this certain error occurred when the `PluginEnableEvent` was being handled by the `TestPlugin`.
43+
44+
- Then we can see on the second line, the cause of the exception:
45+
> `java.lang.NullPointerException: Cannot invoke "Object.toString()" because "null" is null`
46+
47+
This tells us that the exception was caused by a `NullPointerException`,
48+
and that the exception was caused because we tried to call the `toString()` method on a null "player" object.
49+
50+
- From here, as we work down the stacktrace, we can see the exact path of execution that led to the error. In this case,
51+
the next line of the stacktrace is:
52+
> `at io.papermc.testplugin.TestPlugin.onPluginEnable(TestPlugin.java:23) ~[TestPlugin-1.0-SNAPSHOT.jar:?]`
53+
54+
Which tells us that the error was thrown at line 23 of `TestPlugin.java`.
55+
56+
- You can continue to work down the stacktrace, and see the exact path of execution that led to the error. In this case,
57+
it is server internals, so we can generally ignore it.
58+
59+
## Omitted Stacktraces
60+
61+
In JDK 5, the JVM started to omit stacktraces for certain exceptions. This was common when the JVM had optimised the code,
62+
and you could get `NullPointerException`s without a stacktrace. In order to fix this, you can pass the `-XX:-OmitStackTraceInFastThrow` flag to the JVM:
63+
64+
```bash
65+
java -XX:-OmitStackTraceInFastThrow -jar paper.jar
66+
```

0 commit comments

Comments
 (0)