Even though I aborted my adventures into Windows ETW logging, I still wanted a logging mechanism to support future experimentation into Universal Windows Platform. This turned into an educational project in itself, learning about other system interfaces of this platform.
Where do I put this log file?
UWP applications are not allowed arbitrary access to the file system, so if I wanted to write out a log file without explicit user interaction, there are only a few select locations available. I found the
KnownFolders enumeration but those were all user data folders, I didn’t want these log files clogging up “My Documents” and such. I ended up putting the log file in
ApplicationData.TemporaryFolder. This folder is subject to occasional cleanup by the operating system, which is fine for a log file.
When do I open and close this log file?
This required a trip into the world of UWP application lifecycle. I check if the log file existed and, if not, create and open the log file from three places:
OnResuming. In practice it looks like I mostly see
OnLaunched. The flipside is
OnSuspending, where the application template has already set up a suspension deferral buying me time to write out and close the log file.
How do I write data out to this log file?
There is a helpful Getting Started with file input/output document. In it, the standard recommendation is to use the
FileIO class. It links to a section in the UWP developer’s guide titled Files, folders, and libraries. The page Create, write, and read a file was helpful for me to see how these differ from classic C file I/O API.
FileIO classes promise to take care of all the complicated parts, including async/await methods so the application is not blocked on file access. This way the user interface doesn’t freeze until the load or save operation completes, instead remaining responsive while file access was in process.
But when I used the
FileIO API naively, writing upon every line of the log file, I received a constant stream of exceptions. Digging into the call stack of the exception (actually several levels deep in the chain) told me there was a file access collision problem. It was the page Best practices for writing to files that cleared things up for me: these async
FileIO libraries create temporary files for each asynchronous action and copy over the original file upon success. When I was writing once per line, too many operations were happening in too short of a time resulting in the temporary files colliding with each other.
The solution was to write less frequently, buffer up a set of log messages so I write a larger set of them with each
FileIO access, rather than calling once per log entry. Reducing the frequency of write operations resolved my collision issue.
[This simple text file logging class is available on GitHub.]