Debugging Script
DocOrigin Merge provides a number of options and functions to assist in debugging scripts:
- the -trace command line option.
This causes the program to write a detailed trace log of its execution steps as the script is being executed. Note that the trace file is overwritten on each run (whereas the log file is appended to). Use this command option as follows:
... -trace "C:/DocOrigin/User/test/trace.log" ...
- the _tracef function call.
This can be used within your script to write information directly to the trace file specified in the -trace command line option. If -trace is not specified it does nothing. Well, not quite nothing. If you are tracing out values that require work to create (a favorite is ._fullName,
which is fairly expensive to come up with) then that effort/time will be expended even though no trace output will be generated. As of 3.1.002.03, you can use conditional commenting, by prefacing the _tracef
line with !!
, to fully remove any processing costs.
- the _message function call (Windows only).
This is a variation of the _message function that will display a message as a Windows popup message box. It has effect only when the -debug
command-line option has been specified. That means that you can leave it in during production (where -debug
is not set!). Well, see the conditional commenting remarks above. That applies here too. By the way, there is a _dlogf()
function as well. Log output occurs only when -debug
is specified.
For example:
_dmessage("my var='%s'", myvar); // display myvar
Techniques
See all Command-Line Options
Sometimes you just want to know what the command line options were and any other information that has been provided to your script. The following is a fine way to see everything in _job
.
if (typeof _job != "undefined") { for (var prop in _job) _logf("_job.%s = '%s'\n", prop, _job[prop]); if (typeof _job.command != "undefined") for (var prop in _job.command) _logf("_job.command.%s = '%s'\n", prop, _job.command[prop]); if (typeof _job.options != "undefined") for (var prop in _job.options) _logf("_job.options.%s = '%s'\n", prop, _job.options[prop]); if (typeof _job.filter != "undefined") for (var prop in _job.filter) _logf("_job.filter.%s = '%s'\n", prop, _job.filter[prop]); }
In general, it is good to become friends with the standard JavaScript features of:
typeof variable
and for (var prop in object) ... object[prop]
Note: As of 3.1.001.24 the function _job.logf(["context string"])
was added to all of the above logging of the _job
object. The context string
is optional. It simply helps to identify where in the script you are dumping out this info.
Also in 3.1.001.24, a similar function, _cache.logf(["context string"])
was introduced to easily log all the _cache
settings defined at the time of the call.
Traverse the DOM
Well, suppose you just want to know your whole world, perhaps wanting to see what the names really are as opposed to what you think is out there:
_logf("\n%E -- The entire document DOM..\n"); for (var r=_document; r; r=r._nextNode) { _logf(".. '%s'\n", r._fullName); } _logf("\n\n");
It's a great habit to put single quotes around strings that you are debugging. You might be surprised how often there is a trailing (or leading) character that you did not expect.
Of course, you can traverse other DOMs than the _document DOM, e.g. the _data dom
, or an individual page's _page DOM
. And you can start at some level other than the root of the DOM
.
Sometimes you may be surprised by what doesn't show up. A bit of reflection can then lead to an 'Ahah' moment.
Note the use of _fullName
. It's a wonderful thing.
What pages do I have
At Pagination Completed time it is often desirable just to 'traverse' through all the pages. This can be true at Data Merged time too, but less often, in my experience.
_logf("\n%E -- All my pages..\n"); for (var pg=_document._firstChild; pg; pg=pg._nextSibling) { _logf(".. '%s'\n", pg._fullName); } _logf("\n\n");
The trick here is that page objects are always the immediate children of the top-level _document object
. That makes the above loop far faster than using the entire _nextNode
loop depicted farther up.
Naturally, you might want to look at more than the names of the pages, and you might want to predicate your logging with whether pg._visible
is true
. It's all available at your property's fingertips.
Note that %E
is a special format specifier. It requires no parameter. It reports the name of the event that this script is in, e.g. "Data Merged" or "Pagination Completed". Use it. It might tweak you to the fact that you put your script in the wrong event.
What panes do I have
Suppose you are on a page object and you want to know what panes have been instantiated for this page [instance]. You could use:
_logf("\n%E -- All panes of '%s'..\n", this._fullName); for (var pn=this._firstChild; pn; pn=pn._nextNode) { if (pn._type == "Pane") _logf(".. '%s'\n", pn._fullName); if (pn._type == "Page") break; }
Because panes can be nested, you can't use just _nextSibling. Instead, use _nextNode. But now you have way too many nodes. Use the _type property to select only the type of object that you want. It happens that you will be surprised at all the instances that it reports, or perhaps more so, doesn't report. It's very helpful to know these things.
See Also
-phase
_cache (Scripting Object)