OpenTESArena icon indicating copy to clipboard operation
OpenTESArena copied to clipboard

Log console output to a file

Open Thunderforge opened this issue 6 years ago • 14 comments

OpenTESArena writes warning messages, error reports, and other information to the console via the Debug class. This has several major downsides:

  • Console output is not visible when running as a macOS app
  • The information is not recoverable if the app is shut down before the user is finished reading it
  • It is more difficult for end users to submit information about what was happening before a bug was encountered

I recommend that we write all of this console output to a log file in order to solve these problems. We can still write to the console as well if desired.

Unfortunately, there isn't an SDL_GetLogPath() or anything. The recommended log locations for each platform are:

  • macOS: ~/Library/Logs
  • Linux: /var/logs/
  • Windows: AppData*\MyCompany\MyApp (where * is Roaming, Local, or LocalLow.

We would need to determine the proper location based on the platform.

Thunderforge avatar Jul 14 '17 02:07 Thunderforge

It could probably go next to the options folder via SDL_GetPrefPath(), but the problem with that is that it's a "global" file, so it's affected by all instances of the program, and it'd only be reliable for the most recently run instance. Unless... it would have a timestamp as a unique identifier. That might work.

afritz1 avatar Jul 14 '17 02:07 afritz1

Most apps that I see either clear the log out at the beginning of a session (this is what OpenMW does), so I'm not sure that timestamps are really necessary since I'm guessing you won't have two versions of OpenTESArena running simultaneously. I suppose we could use SDL_GetPrefPath() in a pinch, but the downside of using that is since it's not in an expected place, it won't be picked up by the Mac (and Linux?) console viewers.

Thunderforge avatar Jul 14 '17 03:07 Thunderforge

I'd like to avoid adding platform-specific paths to the program, and try to keep them based on user settings instead. I'm not sure a path in options.txt would work well though, because it would need to be edited for each platform both in the repository and in release builds.

afritz1 avatar Jul 14 '17 03:07 afritz1

Looks like there is already some preliminary work for logging in the Debug class, like an unused LOG_FILENAME String constant and the __file__ parameter. Would this system work with what you were planning?

Thunderforge avatar Jul 14 '17 03:07 Thunderforge

LOG_FILENAME was just something I thought would be needed eventually (like now, I guess). It's not used yet though.

The __file__ parameters are always just __FILE__ received from the debug macros. They say the name of the file the debug macro is in, so it isn't related to logging.

afritz1 avatar Jul 14 '17 03:07 afritz1

See Platform::getLogPath() in Platform.cpp, commit 914f7000925871900f2bc834b098ec76fea888e4.

I think the next step is to have the Debug methods that write to console also append to some new log.txt file. That log.txt file will be cleared on program start-up. If the user wants to store previous print-outs, then they can just copy the file.

afritz1 avatar Jul 27 '17 06:07 afritz1

Wouldn't it be easier to use some logging library? I had some bad times using custom logging solutions and then realizing that on top of writing to a file, you want it to be fast, thread safe, non blocking, etc..

abelsromero avatar Jul 27 '17 13:07 abelsromero

Oh, I didn't plan on having that big of a scope for message logging yet. Just for warnings and errors, which happen infrequently. Maybe when IO performance becomes a problem, then using a custom library will be necessary?

afritz1 avatar Jul 27 '17 16:07 afritz1

I've had similar experiences as @abelsromero and would prefer that we use a logging library from the start. As the project grows, be relying on log files more and more to diagnose bugs that users are having. If we need to add it in eventually, I'd rather just add it in now.

Thunderforge avatar Jul 27 '17 16:07 Thunderforge

I did some quick searching and found a couple C++ logging libraries. I'd like for it to be a single header file, preferably designed for C++11. I'll look more into it later today.

afritz1 avatar Jul 27 '17 16:07 afritz1

Easylogging++ seems to fit your requirement of being only a single header file and C++. Every other framework I see is multiple files, but have benefits by being very fast and/or crash-proof.

Thunderforge avatar Jul 27 '17 17:07 Thunderforge

Just found out that SDL has a built-in logging framework. Does that serve our purposes?

Thunderforge avatar Jul 27 '17 18:07 Thunderforge

Just found out that SDL has a built-in logging framework. Does that serve our purposes?

Seems like a good option

abelsromero avatar Jul 27 '17 19:07 abelsromero

Maybe. I see SDL_LogSetOutputFunction, which lets us override the default SDL logging function, but overall I don't see how it's different from my existing Debug class. I don't see any kind of extra features like speed, thread-safety, or anything. It looks like it just offers a basic interface for logging with different priorities, unless I'm missing something?

afritz1 avatar Jul 28 '17 03:07 afritz1

Added log file support to the Debug class in 0d7c9352b1f87ef3a29a2a69208a720261eb0bbf and checked that it works on Windows, macOS, and Linux. It also deletes the oldest log upon passing 10 files. It's blocking but the engine writes so little that I'm not worried, and if it does need improvement, I can add a std::thread.

afritz1 avatar Mar 19 '23 23:03 afritz1