Debugging Your Code

Logging Exceptions

We just took a rather long detour to talk about Exceptions, and now you're very knowledgeable about them. But how do we use them in our code?

The upshot of this lesson is that there's a special wyvern.lib.Kernel method devoted to printing out Exception stack traces, and it's called wyvern.lib.Kernel.throwing(). If you want to catch an Exception in your code and print it out, you can using throwing() just like the other Kernel logging methods.

A common example is when you're trying to instantiate a particular archetype in your code. For example, here's a simple Monster Dispenser — just a subclass of Lever that creates an Orc when you pull it:

<span class='string'>"""</span> <span class='keyword'></span>monster_dispenser<span class='keyword'></span>.<span class='keyword'></span>py<span class='keyword'></span>:<br><span class='keyword'></span>A<span class='keyword'></span> <span class='keyword'></span>lever<span class='keyword'></span> <span class='keyword'></span>that<span class='keyword'></span> <span class='keyword'></span>creates<span class='keyword'></span> <span class='keyword'></span>an<span class='keyword'></span> <span class='keyword'></span>Orc<span class='keyword'></span> <span class='keyword'></span>whenever<span class='keyword'></span> <span class='keyword'></span>you<span class='keyword'></span> <span class='keyword'></span>apply<span class='keyword'></span> <span class='keyword'></span>it<span class='keyword'></span>.<br><span class='string'>"""</span><br><span class='keyword'></span>from<span class='keyword'></span> <span class='keyword'></span>wyvern<span class='keyword'></span>.<span class='keyword'></span>lib<span class='keyword'></span>.<span class='keyword'></span>classes<span class='keyword'></span>.<span class='keyword'></span>construct<span class='keyword'></span> <span class='keyword'></span>import<span class='keyword'></span> <span class='keyword'></span>Lever<span class='keyword'></span><br><span class='keyword'></span>from<span class='keyword'></span> <span class='keyword'></span>wyvern<span class='keyword'></span>.<span class='keyword'></span>lib<span class='keyword'></span> <span class='keyword'></span>import<span class='keyword'></span> <span class='keyword'></span>Kernel<span class='keyword'></span><br><br><span class='keyword'>class</span> <span class='function'>monster_dispenser</span>(Lever):<br>	<span class='keyword'>def</span> <span class='function'>apply</span>(self, agent):<br>		<span class='keyword'></span>mon<span class='keyword'></span> = <span class='keyword'></span>Kernel<span class='keyword'></span>.<span class='keyword'></span>instantiate<span class='keyword'></span>('<span class='keyword'></span>monsters<span class='keyword'></span>/<span class='keyword'></span>goblin<span class='keyword'></span>/<span class='keyword'></span>orc<span class='keyword'></span>')<br>		<span class='keyword'></span>map<span class='keyword'></span> = <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>getMap<span class='keyword'></span>()<br>		<span class='keyword'></span>ref<span class='keyword'></span> = <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>getReferenceLoc<span class='keyword'></span>()<br>		<span class='keyword'></span>mon<span class='keyword'></span>.<span class='keyword'></span>setMap<span class='keyword'></span>(<span class='keyword'></span>map<span class='keyword'></span>, <span class='keyword'></span>ref<span class='keyword'></span>.<span class='keyword'></span>x<span class='keyword'></span>, <span class='keyword'></span>ref<span class='keyword'></span>.<span class='keyword'></span>y<span class='keyword'></span>)<br>		<span class='keyword'></span>mon<span class='keyword'></span>.<span class='keyword'></span>start<span class='keyword'></span>()

If, for some reason, it failed to instantiate the Orc, it would throw an Exception that you'd never see, because it would be passed up to the ApplyCommand and be out of your reach. If you had logging statements like this:

<span class='string'>"""</span> <span class='keyword'></span>monster_dispenser<span class='keyword'></span>.<span class='keyword'></span>py<span class='keyword'></span>:<br><span class='keyword'></span>A<span class='keyword'></span> <span class='keyword'></span>lever<span class='keyword'></span> <span class='keyword'></span>that<span class='keyword'></span> <span class='keyword'></span>creates<span class='keyword'></span> <span class='keyword'></span>an<span class='keyword'></span> <span class='keyword'></span>Orc<span class='keyword'></span> <span class='keyword'></span>whenever<span class='keyword'></span> <span class='keyword'></span>you<span class='keyword'></span> <span class='keyword'></span>apply<span class='keyword'></span> <span class='keyword'></span>it<span class='keyword'></span>.<br><span class='keyword'></span>This<span class='keyword'></span> <span class='keyword'></span>version<span class='keyword'></span> <span class='keyword'></span>uses<span class='keyword'></span> <span class='keyword'></span>Logging<span class='keyword'></span> <span class='keyword'></span>to<span class='keyword'></span> <span class='keyword'></span>try<span class='keyword'></span> <span class='keyword'></span>to<span class='keyword'></span> <span class='keyword'></span>figure<span class='keyword'></span> <span class='keyword'></span>out<span class='keyword'></span> <span class='keyword'></span>the<span class='keyword'></span> <span class='keyword'></span>problem<span class='keyword'></span>.<br><span class='string'>"""</span><br><span class='keyword'></span>from<span class='keyword'></span> <span class='keyword'></span>wyvern<span class='keyword'></span>.<span class='keyword'></span>lib<span class='keyword'></span>.<span class='keyword'></span>classes<span class='keyword'></span>.<span class='keyword'></span>construct<span class='keyword'></span> <span class='keyword'></span>import<span class='keyword'></span> <span class='keyword'></span>Lever<span class='keyword'></span><br><span class='keyword'></span>from<span class='keyword'></span> <span class='keyword'></span>wyvern<span class='keyword'></span>.<span class='keyword'></span>lib<span class='keyword'></span> <span class='keyword'></span>import<span class='keyword'></span> <span class='keyword'></span>Kernel<span class='keyword'></span><br><br><span class='keyword'>class</span> <span class='function'>monster_dispenser</span>(Lever):<br><br>	<span class='keyword'>def</span> <span class='function'>initialize</span>(self):<br>		<span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>super__initialize<span class='keyword'></span>()<br>		<span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>logname<span class='keyword'></span> = '<span class='keyword'></span>wiz<span class='keyword'></span>/<span class='keyword'></span>rhialto<span class='keyword'></span>/<span class='keyword'></span>python<span class='keyword'></span>/<span class='keyword'></span>monster_dispenser<span class='keyword'></span>.<span class='keyword'></span>py<span class='keyword'></span>'<br><br>	<span class='keyword'>def</span> <span class='function'>apply</span>(self, agent):<br>		<span class='keyword'></span>Kernel<span class='keyword'></span>.<span class='keyword'></span>fine<span class='keyword'></span>(<span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>logname<span class='keyword'></span>, '<span class='keyword'></span>apply<span class='keyword'></span>', '<span class='keyword'></span>instantiating<span class='keyword'></span> <span class='keyword'></span>an<span class='keyword'></span> <span class='keyword'></span>Orc<span class='keyword'></span>')<br>		<span class='keyword'></span>mon<span class='keyword'></span> = <span class='keyword'></span>Kernel<span class='keyword'></span>.<span class='keyword'></span>instantiate<span class='keyword'></span>('<span class='keyword'></span>monsters<span class='keyword'></span>/<span class='keyword'></span>groblin<span class='keyword'></span>/<span class='keyword'></span>orc<span class='keyword'></span>')<br>		<span class='keyword'></span>Kernel<span class='keyword'></span>.<span class='keyword'></span>fine<span class='keyword'></span>(<span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>logname<span class='keyword'></span>, '<span class='keyword'></span>apply<span class='keyword'></span>', '<span class='keyword'></span>got<span class='keyword'></span> <span class='keyword'></span>Orc<span class='keyword'></span>!')<br>		<span class='keyword'></span>map<span class='keyword'></span> = <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>getMap<span class='keyword'></span>()<br>		<span class='keyword'></span>ref<span class='keyword'></span> = <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>getReferenceLoc<span class='keyword'></span>()<br>		<span class='keyword'></span>mon<span class='keyword'></span>.<span class='keyword'></span>setMap<span class='keyword'></span>(<span class='keyword'></span>map<span class='keyword'></span>, <span class='keyword'></span>ref<span class='keyword'></span>.<span class='keyword'></span>x<span class='keyword'></span>, <span class='keyword'></span>ref<span class='keyword'></span>.<span class='keyword'></span>y<span class='keyword'></span>)<br>		<span class='keyword'></span>mon<span class='keyword'></span>.<span class='keyword'></span>start<span class='keyword'></span>()

Well, you'd be confused, because your first logging statement would get executed, but the second one wouldn't. The Exception would just shoot straight out of the method, up to the caller.

You can catch the Exception and print it out like this:

<span class='string'>"""</span> <span class='keyword'></span>monster_dispenser<span class='keyword'></span>.<span class='keyword'></span>py<span class='keyword'></span>:<br><span class='keyword'></span>A<span class='keyword'></span> <span class='keyword'></span>lever<span class='keyword'></span> <span class='keyword'></span>that<span class='keyword'></span> <span class='keyword'></span>creates<span class='keyword'></span> <span class='keyword'></span>an<span class='keyword'></span> <span class='keyword'></span>Orc<span class='keyword'></span> <span class='keyword'></span>whenever<span class='keyword'></span> <span class='keyword'></span>you<span class='keyword'></span> <span class='keyword'></span>apply<span class='keyword'></span> <span class='keyword'></span>it<span class='keyword'></span>.<br><span class='keyword'></span>This<span class='keyword'></span> <span class='keyword'></span>version<span class='keyword'></span> <span class='keyword'></span>has<span class='keyword'></span> <span class='keyword'></span>Exception<span class='keyword'></span> <span class='keyword'></span>handling<span class='keyword'></span>.<br><span class='string'>"""</span><br><span class='keyword'></span>from<span class='keyword'></span> <span class='keyword'></span>wyvern<span class='keyword'></span>.<span class='keyword'></span>lib<span class='keyword'></span>.<span class='keyword'></span>classes<span class='keyword'></span>.<span class='keyword'></span>construct<span class='keyword'></span> <span class='keyword'></span>import<span class='keyword'></span> <span class='keyword'></span>Lever<span class='keyword'></span><br><span class='keyword'></span>from<span class='keyword'></span> <span class='keyword'></span>wyvern<span class='keyword'></span>.<span class='keyword'></span>lib<span class='keyword'></span> <span class='keyword'></span>import<span class='keyword'></span> <span class='keyword'></span>Kernel<span class='keyword'></span><br><span class='keyword'></span>from<span class='keyword'></span> <span class='keyword'></span>java<span class='keyword'></span>.<span class='keyword'></span>lang<span class='keyword'></span> <span class='keyword'></span>import<span class='keyword'></span> <span class='keyword'></span>Exception<span class='keyword'></span><br><br><span class='keyword'>class</span> <span class='function'>monster_dispenser</span>(Lever):<br><br>    <span class='keyword'>def</span> <span class='function'>initialize</span>(self):<br>        <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>super__initialize<span class='keyword'></span>()<br>        <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>logname<span class='keyword'></span> = '<span class='keyword'></span>wiz<span class='keyword'></span>/<span class='keyword'></span>rhialto<span class='keyword'></span>/<span class='keyword'></span>python<span class='keyword'></span>/<span class='keyword'></span>monster_dispenser<span class='keyword'></span>.<span class='keyword'></span>py<span class='keyword'></span>'<br><br>    <span class='keyword'>def</span> <span class='function'>apply</span>(self, agent):<br>        <span class='keyword'></span>try<span class='keyword'></span>:<br>            <span class='keyword'></span>mon<span class='keyword'></span> = <span class='keyword'></span>Kernel<span class='keyword'></span>.<span class='keyword'></span>instantiate<span class='keyword'></span>('<span class='keyword'></span>monsters<span class='keyword'></span>/<span class='keyword'></span>groblin<span class='keyword'></span>/<span class='keyword'></span>orc<span class='keyword'></span>')<br>            <span class='keyword'></span>map<span class='keyword'></span> = <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>getMap<span class='keyword'></span>()<br>            <span class='keyword'></span>ref<span class='keyword'></span> = <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>getReferenceLoc<span class='keyword'></span>()<br>            <span class='keyword'></span>mon<span class='keyword'></span>.<span class='keyword'></span>setMap<span class='keyword'></span>(<span class='keyword'></span>map<span class='keyword'></span>, <span class='keyword'></span>ref<span class='keyword'></span>.<span class='keyword'></span>x<span class='keyword'></span>, <span class='keyword'></span>ref<span class='keyword'></span>.<span class='keyword'></span>y<span class='keyword'></span>)<br>            <span class='keyword'></span>mon<span class='keyword'></span>.<span class='keyword'></span>start<span class='keyword'></span>()<br><br>        <span class='keyword'></span>except<span class='keyword'></span> <span class='keyword'></span>Exception<span class='keyword'></span>, <span class='keyword'></span>xc<span class='keyword'></span>:<br>            <span class='keyword'></span>Kernel<span class='keyword'></span>.<span class='keyword'></span>throwing<span class='keyword'></span>(<span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>logname<span class='keyword'></span>, '<span class='keyword'></span>apply<span class='keyword'></span>', <span class='keyword'></span>xc<span class='keyword'></span>)

Now when you clone the object, drop it, and apply it, you get — nothing! It doesn't work, but we're not seeing the Exception stack trace, either.

That's because Kernel.throwing() only prints the Exception stack trace if the log level is set to FINER. So we do this:

debug finer wiz/rhialto/python/monster_dispenser.py

You will start seeing log messages at level FINER for wiz/rhialto/python/monster_dispenser.py

apply dispenser

--wiz/rhialto/python/monster_dispenser.py.apply():
java.io.FileNotFoundException: \games\wyvern\arch\monsters\groblin\orc.arch
 (The system cannot find the path specified)
        at java.io.FileInputStream.open(Native Method)
        at java.io.FileInputStream.(FileInputStream.java:103)
        at java.io.FileInputStream.(FileInputStream.java:66)
        at wyvern.kernel.properties.XMLWrapper.parseArchetypeFile(XMLWrapper.j
        at wyvern.kernel.properties.ArchetypeManager.parseArchetypeFile(Archet
        at wyvern.kernel.properties.ArchetypeManager.parseSystemArchetype(Arch
        at wyvern.kernel.properties.ArchetypeManager.loadArchetype(ArchetypeMa
        at wyvern.kernel.properties.ArchetypeManager.instantiate(ArchetypeMana
        at wyvern.lib.Kernel.instantiate(Kernel.java:81)
        at sun.reflect.GeneratedMethodAccessor45.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcc
        at java.lang.reflect.Method.invoke(Method.java:324)
        at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.ja
        at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.ja
        at org.python.core.PyObject.__call__(PyObject.java)
        at org.python.core.PyObject.invoke(PyObject.java)
        at org.python.pycode._pyx81.apply$3(/games/wyvern/wiz/rhialto/python/m
        at org.python.pycode._pyx81.call_function(/games/wyvern/wiz/rhialto/py
        at org.python.core.PyTableCode.call(PyTableCode.java)
        at org.python.core.PyTableCode.call(PyTableCode.java)
        at org.python.core.PyTableCode.call(PyTableCode.java)
        at org.python.core.PyFunction.__call__(PyFunction.java)
        at org.python.core.PyMethod.__call__(PyMethod.java)
        at org.python.core.PyObject.__call__(PyObject.java)
        at org.python.core.PyObject._jcallexc(PyObject.java)
        at org.python.core.PyObject._jcall(PyObject.java)
        at org.python.proxies.main$monster_dispenser$41.apply(Unknown Source)
        at wyvern.lib.commands.ApplyCommand.execute(ApplyCommand.java:207)
        at wyvern.kernel.kernel.Executive.dispatchEvent(Executive.java:852)
        at wyvern.kernel.kernel.Executive.workerLoop(Executive.java:750)
        at wyvern.kernel.kernel.Executive.access$0(Executive.java:43)
        at wyvern.kernel.kernel.Executive$WorkerThread.run(Executive.java:71

That's great! The very first line told us the problem — namely, the game doesn't know what the heck this is:

\games\wyvern\arch\monsters\groblin\orc.arch

We just need to change "groblin" to "goblin", and we're all set.

It sure would be nice if we didn't have to have the rest of that stack trace printed, since the first line told us what we wanted to know (which happens a lot of the time.) Well, our wish is granted. Should've wished for a million bucks. But here's what you can do:

<span class='string'>"""</span> <span class='keyword'></span>monster_dispenser<span class='keyword'></span>.<span class='keyword'></span>py<span class='keyword'></span>:<br><span class='keyword'></span>A<span class='keyword'></span> <span class='keyword'></span>lever<span class='keyword'></span> <span class='keyword'></span>that<span class='keyword'></span> <span class='keyword'></span>creates<span class='keyword'></span> <span class='keyword'></span>an<span class='keyword'></span> <span class='keyword'></span>Orc<span class='keyword'></span> <span class='keyword'></span>whenever<span class='keyword'></span> <span class='keyword'></span>you<span class='keyword'></span> <span class='keyword'></span>apply<span class='keyword'></span> <span class='keyword'></span>it<span class='keyword'></span>.<br><span class='keyword'></span>This<span class='keyword'></span> <span class='keyword'></span>version<span class='keyword'></span> <span class='keyword'></span>has<span class='keyword'></span> <span class='keyword'></span>FINE<span class='keyword'></span>-<span class='keyword'></span>level<span class='keyword'></span> <span class='keyword'></span>Exception<span class='keyword'></span> <span class='keyword'></span>message<span class='keyword'></span> <span class='keyword'></span>printing<span class='keyword'></span>,<br><span class='keyword'></span>and<span class='keyword'></span> <span class='keyword'></span>FINER<span class='keyword'></span>-<span class='keyword'></span>level<span class='keyword'></span> <span class='keyword'></span>Exception<span class='keyword'></span> <span class='keyword'></span>stack<span class='keyword'></span> <span class='keyword'></span>trace<span class='keyword'></span> <span class='keyword'></span>printing<span class='keyword'></span>.<br><span class='string'>"""</span><br><span class='keyword'></span>from<span class='keyword'></span> <span class='keyword'></span>wyvern<span class='keyword'></span>.<span class='keyword'></span>lib<span class='keyword'></span>.<span class='keyword'></span>classes<span class='keyword'></span>.<span class='keyword'></span>construct<span class='keyword'></span> <span class='keyword'></span>import<span class='keyword'></span> <span class='keyword'></span>Lever<span class='keyword'></span><br><span class='keyword'></span>from<span class='keyword'></span> <span class='keyword'></span>wyvern<span class='keyword'></span>.<span class='keyword'></span>lib<span class='keyword'></span> <span class='keyword'></span>import<span class='keyword'></span> <span class='keyword'></span>Kernel<span class='keyword'></span><br><span class='keyword'></span>from<span class='keyword'></span> <span class='keyword'></span>java<span class='keyword'></span>.<span class='keyword'></span>lang<span class='keyword'></span> <span class='keyword'></span>import<span class='keyword'></span> <span class='keyword'></span>Exception<span class='keyword'></span><br><br><span class='keyword'>class</span> <span class='function'>monster_dispenser</span>(Lever):<br><br>    <span class='keyword'>def</span> <span class='function'>initialize</span>(self):<br>        <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>super__initialize<span class='keyword'></span>()<br>        <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>logname<span class='keyword'></span> = '<span class='keyword'></span>wiz<span class='keyword'></span>/<span class='keyword'></span>rhialto<span class='keyword'></span>/<span class='keyword'></span>python<span class='keyword'></span>/<span class='keyword'></span>monster_dispenser<span class='keyword'></span>.<span class='keyword'></span>py<span class='keyword'></span>'<br><br>    <span class='keyword'>def</span> <span class='function'>apply</span>(self, agent):<br>        <span class='keyword'></span>try<span class='keyword'></span>:<br>            <span class='keyword'></span>mon<span class='keyword'></span> = <span class='keyword'></span>Kernel<span class='keyword'></span>.<span class='keyword'></span>instantiate<span class='keyword'></span>('<span class='keyword'></span>monsters<span class='keyword'></span>/<span class='keyword'></span>groblin<span class='keyword'></span>/<span class='keyword'></span>orc<span class='keyword'></span>')<br>            <span class='keyword'></span>map<span class='keyword'></span> = <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>getMap<span class='keyword'></span>()<br>            <span class='keyword'></span>ref<span class='keyword'></span> = <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>getReferenceLoc<span class='keyword'></span>()<br>            <span class='keyword'></span>mon<span class='keyword'></span>.<span class='keyword'></span>setMap<span class='keyword'></span>(<span class='keyword'></span>map<span class='keyword'></span>, <span class='keyword'></span>ref<span class='keyword'></span>.<span class='keyword'></span>x<span class='keyword'></span>, <span class='keyword'></span>ref<span class='keyword'></span>.<span class='keyword'></span>y<span class='keyword'></span>)<br>            <span class='keyword'></span>mon<span class='keyword'></span>.<span class='keyword'></span>start<span class='keyword'></span>()<br><br>        <span class='keyword'></span>except<span class='keyword'></span> <span class='keyword'></span>Exception<span class='keyword'></span>, <span class='keyword'></span>xc<span class='keyword'></span>:<br><span class='comment'>            # print the Exception message at level FINE, and print</span><br><span class='comment'>            # the entire Exception stack trace at level FINER</span><br>            <span class='keyword'></span>Kernel<span class='keyword'></span>.<span class='keyword'></span>fine<span class='keyword'></span>(<span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>logname<span class='keyword'></span>, '<span class='keyword'></span>apply<span class='keyword'></span>', <span class='keyword'></span>xc<span class='keyword'></span>.<span class='keyword'></span>getMessage<span class='keyword'></span>())<br>            <span class='keyword'></span>Kernel<span class='keyword'></span>.<span class='keyword'></span>throwing<span class='keyword'></span>(<span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>logname<span class='keyword'></span>, '<span class='keyword'></span>apply<span class='keyword'></span>', <span class='keyword'></span>xc<span class='keyword'></span>)<br><br><span class='comment'>            # tell the agent an error occurred</span><br>            <span class='keyword'></span>agent<span class='keyword'></span>.<span class='keyword'></span>message<span class='keyword'></span>('<span class='keyword'></span>The<span class='keyword'></span> <span class='keyword'></span>dispenser<span class='keyword'></span> <span class='keyword'></span>appears<span class='keyword'></span> <span class='keyword'></span>to<span class='keyword'></span> <span class='keyword'></span>be<span class='keyword'></span> <span class='keyword'></span>broken<span class='keyword'></span>')

Now we can debug the class at level FINE, and we'll only see the first line of the stack trace:

debug fine wiz/rhialto/python/monster_dispenser.py

You will start seeing log messages at level FINE for wiz/rhialto/python/monster_dispenser.py

apply dispenser

--wiz/rhialto/python/monster_dispenser.py.apply():
\games\wyvern\arch\monsters\groblin\orc.arch (The system cannot find the path specified)

Ahhh, satisfaction at last. Everything is set up perfectly:

  1. We catch Exceptions in our code and handle them (in this case, by telling the agent that the dispenser is busted)

  2. We've got a FINE logging message that should tell us what's going wrong if there's a problem

  3. If the FINE message isn't good enough, we can get very detailed information at the FINER level.

And that, as they say, is that. Now you know all about logging Exceptions. You're also ready to start coding with logging!

<< Previous Chapter