There are several options:
0. "Poor person's trace": Impure output
You can use impure predicates like format/2
to emit debug information from within your programs.
Example:
?- X = 4, format("X is now: ~w\n", [X]).
X is now: 4
This is is likely similar to traces you have produced in other languages.
This is the least advanced and worst debugging method, and also most popular.
1. Textual tracer: trace/0
Try it in your Prolog system with:
?- trace, your_goal.
Then painfully step through the code.
This is a sure way to go insane as fast as you can.
2. Graphical tracer
Some Prolog systems provide a graphical tracer.
For example, in SWI-Prolog, try:
?- gtrace, your_goal.
The graphical tracer is a quite complex program and has bugs on its own.
3. Declarative debugging highly recommended
In total, I strongly recommend to avoid tracing in Prolog. The two separate control flows make this language not very suitable to "stepping through". The good news is that this is also not very necessary: Instead, try declarative debugging by reasoning about generalizations and specializations of your programs. This lets you quickly determine the true causes of unintended failure and nontermination.
Invariably, tracing will lead you to think procedurally about your code, and you will have to wrestle with bugs in your code in addition to the bugs in the tracer, while gaining only little insight into the actual problems of your programs.
See for example program-slicing and failure-slice for more information.