nfengine
nfengine copied to clipboard
Rewrite logger
Redesign logger API and provide new functionalities:
- [x] Two log message styles:
- [x] printf style (more important, needs to be fast)
- [x] std::ostream style (slower, but probably more convenient, to use outside nfCore)
- [x] Basic types of logs (DEBUG, INFO, ERROR, FATAL):
- [x] DEBUG, INFO, ERROR logs just print an info, each with different coloring
- [x] FATAL log prints an error and aborts programs execution
- [x] Configurable multiple logger backends
- [x] abstract class
- [x] Raw TXT file
- [x] OutputDebugString(...)
- [x] HTML
- [x] std::cout/std::cerr
- [x] XML
- [ ] Log file should have the following information included in a header:
- [x] build and launch time stamp
- [ ] engine version (number + commit SHA1)
- [x] basic hardware information: CPU and GPU name and capabilities, available RAM
- [x] basic software information: OS version, compiler version
- [x] Flushing logs (reseting log files). Will be helpfull for performance tests.
- [ ] Printing Thread ID (#138 must be done first).
- [ ] Log file buffering. Currently for each
LOG_XXX
a write system call is called (which is not efficient for short log messages). All writes to log files should be buffered (expect error messages - error should flush the buffer). - [ ] Keeping old logs (remember about removing the oldest logs so that the total space occupied by Log directory does not exceed some threshold). Logs files should have timestamp in their names.
- [x] Selecting active logger backends and logging level at the runtime.
- [x] Grouping logger messages (currently, multithreading makes a mess - see texture loading logs) - this could be done by introducing helper class which aggregates multiple log messages and output is sorted by group ID.
Lower priority features (some may be backend-specific):
- [ ] [needs discussion] Log() calls should be asynchronous to improve performance - we don't want to wait until a message is written to a hard drive (unless it's a critical error and an application will close soon). Maybe just use operating system's async I/O?
- [x] Additional types of logs:
- [x] SCOPE logs (for debugging, print a message when entering and leaving the scope)
- [ ] Improved HTML output layout:
- [x] Filtering (by type, priority, file, thread, etc.).
- [ ] Clicking a message should jump to a source code (at line in which the message was commited).
Logger API should be implemented as a regular class, but global functions / singleton should be also provided to manipulate a log without passing logger object reference between DLLs.
https://review.gerrithub.io/#/c/243457/
This issue:
SCOPE logs (for debugging, print a message when entering and leaving the scope)
is quite easy and was discussed on chat. Instead of making it from scratch, which would result in code redundancy, we should use code from nfCore/Profiler.
I suggest creating a ScopeInterface or Scopeable class that would hold virtual methods called in ctor and dtor. Then in any other use we would just implement this interface and define methods to be used.
@LKostyra is that somehow similar to Your idea? I think that there was a rule to keep nfCore and nfCommon apart - what should we do in this case?
@mkulagowski on one hand I do agree we should not duplicate functions, on the other hand I don't like the fact of Interface-like implementation in Scopes.
Profiler's performance is crucial, as it must generate an absolutely minimal overhead for the Engine to gather accurate statistics. Using polymorphism would be contrary to its goals (especially that start/stop scope functions do not do much - relatively speaking, vptr table and late binding would generate enough overhead to actually matter for these functions).
Scope's code is really not that big code chunk to replicate. I think you can safely write it from scratch, for Logger purposes (without making a common interface in nfCommon).
DONE:
- XML backend
- basic hardware information
- backends can be switched on & off in runtime