In the (very loose) spirit of Log4j, here is a logging system for NWN that includes logging levels.
All variable options set at module level.
Set variable LOGGING_ENABLED (int) to 1.
Set variable LOGGING_LEVEL (int) to the desired logging level (0 - None, 1 - Error, 2 - Warn, 3 - Info, 4 - Debug, 5 - Trace)
Set variable LOGGING_ENABLED_FILENAMES (int) to 1 if you want to be able to control which script files get logged.
For each script file you want to log, you must set a varialble "log_" + filename in lowercase as an int to 1.
Turning on/off at the file level is touchy and will require dedication on your part during the coding process, For each file, every method must call LogEntry at the beginning of the method and one of the exit methods (LogExit, LogTraceExitString, LogTraceExitInt) at EVERY exit point of a method in order for it to work correctly. So if you're one of those coders who likes to throw returns in the middle of methods, you'll need to make sure to include an exit method at each point, or you'll need to restructure your code so your only exit point is at the bottom (which is better for maintenance imho). I recommend creating a string constant at the top of the file that stores the filename so if you should ever need to change it for a file, you'll only need to change it in one spot. The constant name must be differnt in each file to avoid collisions with includes. For the project I'm working on that necessitated this, I used the filename for the both the constant name and variable name.
If you want messages sent to a PC:
Set variable USE_PC_LOGGER (int) to 1.
Set varialble LOGGING_TARGET (object) to the PC. If this variable is not set, it will use GetFirstPC() by default.
Logging will use WriteTimestampedLogEntry to write to log files, and SendMessageToPC to use the PC "logger".
NOTE: Each of the logging level statements (LogTrace, LogDebug, LogInfo...) make calls to the respective Is...Enabled() function before determining if it should log the statements - HOWEVER - since we can't do parameterized stirngs ala SLF4j or Log4j2, if you are logging a giant string that has to be built and has multiple calls to string-type conversions, it is best to wrap those statements in if statements that check the logging level first so that you don't waste processing constructing a giant string you won't be writing out.
See the comments in the two nss files for further function/API description.
Zip file contains all nss files separately and an erf to import into modules. Simply include "ncm_in_log4nwn" in your script to use.
For those scripter/builders who aren't software developers that would be familiar with these type systems, this allows you to put in logging statements and control which statements write to the log through setting the logging level variable. You don't need to go back and comment out your logging statements - you just shut them off.
The levels work in a hierarchy. Your level setting only allows that level and levels that are higher in severity (but lower in value with the way I implemented it). So if you set your level to ERROR (highest severity), only ERROR statements will be logged. If you set TRACE (lowest severity) - ALL statements will be logged.
Below are the general ways to use the levels, in order of severity from lowest to highest.
TRACE - this level is generally used to log statements about where you are in your code - entering and exiting functions, the "I got to this section of my code" statements, etc.
DEBUG - this level is used to write variables and their values to the log
INFO - this level is used to provide informational statements that you want to see in the log if you shut off TRACE and DEBUG
WARN - used to provide warnings that aren't error level severity
ERROR - used to write errors to the log. We don't have a try/catch capability in NWScript to catch exceptions in code, so this level isn't really that different than WARN. I'm using it in else clauses to write out when an invalid object was passed into a function when one shouldn't be, etc.
Happy logging!
Update 7/13/2020: Sorry to the few of you who already download this package, but I've updated it to allow for file level specificaiton for logging - necessity and mother of invention and all that. You can choose to not call the new methods, but read above for how file level specification has to work. You may want to switch up before you get too far down the rabbit hole.
As an added bonus, in order to get the file level logging to work, I had to dust the cobwebs of some 12+ year old include files from my Grimoire project, so you also get ArrayLists that can be used as ArrayLists or stacks (method calls that make the ArrayList act like a stack), up to 3 dimenion lists of lists of lists, with included InsertionSort and QuickSort. Methods for Add, GetValueAt, SetValueAt, GetAndRemove, Insert, IndexOf, and Pop (for stacks - just implementation of GetAndRemove at the end of the list), one method for each variable type for each method type, With some method additions to control where you Insert and GetAndRemove, you could implement queues and deques too. Look at gr_in_arrlist and gr_ic_arrlist if you're interested. It's not documented that well with comments, but if you know enough about those data structures you should be able to figure it out from the method names.
Attachment | Size |
---|---|
![]() | 16.18 KB |