Logging: Other log-files and output to console

I’m trying to direct all my logging to a single file, specified by me. Unfortunately, while much of my game’s output does indeed go to that file, I still seem to get some output directed to the console, and some to files named in the pattern “log.<date-and-time>”. And I’m not sure of what I’m doing wrong. :/

This is, roughly speaking, how I’m setting up logging. The code is a little more spread out than I’m depicting here, but this should give you the general idea of my approach:

In the “Common” class, which handles logging:

class Common():

    # An exit-handler designed to print crash-reports and the like to the log-file.
    # This seems to be somewhat hit-and-miss.
    @staticmethod
    def exitHandler():
        Common.nout.flush()

        if hasattr(sys, "last_traceback"):
            errorList = traceback.format_exception(sys.last_type, sys.last_value, sys.last_traceback)
            errorString = "".format(errorList)
            Common.warn(errorString)


    # Initial setup of logging.
    @staticmethod
    def setupLogging():
        filename = Filename(USER_DIR + "/logfile.txt")
        # Replace the file if it exists (so that it doesn't
        # append every run's output one after another)
        if filename.exists():
            filename.unlink()

        Common.nout = MultiplexStream()
        Notify.ptr().setOstreamPtr(Common.nout, 0)
        Common.nout.addFile(filename)

        atexit.register(Common.exitHandler)


    # Initialisation code general to this class,
    # part of which is a final bit of logging setup.
    @staticmethod
    def initialise(fadeBin):

        Common.notifier = DirectNotify().newCategory("GameMessages")
        if Common.nout is not None:
            Common.notifier.setLogging(True)
            base.notify.__class__.streamWriter = StreamWriter(Notify.out(), False)
      
        # Other logic follows that's unrelated.

In the game’s core-class:

    def __init__(self):
        Common.setupLogging()

        # A bit of code in-between...

        Common.initialise(GUI_BIN)

Does anyone see what the problem might be? :/

The only thing I find odd in your code is Common.warn in your exitHandler method;
Shouldn’t that be Common.notifier.warn instead?

Apart from that I wouldn’t really know. Perhaps the order in which ShowBase is instantiated and Common.setupLogging etc. is called, but I’m just guessing here.
The reason I mention this is that I recently adopted the use of Panda’s own logging system as well, and I found out that instantiating ShowBase resets a custom severity level (through a previous call to notifier.setSeverity or setDebug etc.) to its default value.

A more complete code sample might provide more insight, ideally one that leads to the creation of the unwanted log files, but if this cannot easily be reproduced, then that is more easily said than done of course, hmmm…

Ah, sorry–I have a convenience method in my “Common” class that allows me to use the same method-call whether or not I have logging enabled. (The full game uses logging, while the level-editor and other assorted utilities just output to the console, as I recall.)

Here’s the code for that method:

    @staticmethod
    def warn(warningText):
        if Common.notifier is not None:
            Common.notifier.warning(warningText)
        else:
            print (warningText)

As you can see, it calls “Common.notifier.warning” if “Common.notifier” has been assigned (and thus logging is enabled), and simply “prints” otherwise.

Fair enough–I appreciate the suggestions and reply nevertheless! And they may prove helpful, still. :slight_smile:

Perhaps–it might be worth investigating.

I think that I might try to put together some sort of minimal example (perhaps tomorrow, depending on how some other bug-hunting goes)–that might help to isolate the issue.

Fair enough.

However, a real (and actually rather obvious) mistake in that exitHandler method is in the preceding line of code: errorString = "".format(errorList).
That should of course be: errorString = "".join(errorList)

All tracebacks should now go into the log file as intended :slight_smile: .

EDIT
Aha! If I comment out Common.notifier.setLogging(True) in the initialise method, it looks like no additional log files of the form log.<date-and-time> are created anymore! That call also doesn’t seem necessary, as the logfile.txt file is still being created with the tracebacks in it.

Please try it out and see if you can verify this.

Ah, thank you for that! That may well be the key to the problem (if not the mystery of the “log.” files)! I don’t know how that happened–thank you for pointing it out. :slight_smile:

Ah, interesting! I will experiment with that, I do intend–thank you! :slight_smile: