From 73860cdc8625b4f8443cb8531019d6f57f8b59ce Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Thu, 3 Aug 2017 16:03:24 -0400 Subject: Add a main document for libnslog --- docs/Doxyfile | 4 +- docs/mainpage.md | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 docs/mainpage.md diff --git a/docs/Doxyfile b/docs/Doxyfile index 29be490..870b8ad 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -655,7 +655,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = include +INPUT = include docs # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is @@ -773,6 +773,8 @@ FILTER_SOURCE_FILES = NO FILTER_SOURCE_PATTERNS = +USE_MDFILE_AS_MAINPAGE = mainpage.md + #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- diff --git a/docs/mainpage.md b/docs/mainpage.md new file mode 100644 index 0000000..1d29aee --- /dev/null +++ b/docs/mainpage.md @@ -0,0 +1,160 @@ +Lib NSLOG +========= + +The purpose of the NSLog library is to provide a flexible logging macro which +permits logging with categories, and at levels. Then the library can queue +log entries and permit filtering for log readers. + +Since logging may have to happen during static initialisation, or before the +logging library is fully initialised, categories are progressively added to +the logging system as they are encountered. Since, at their core, categories +are essentially just strings, we can write filters which will be resolved to +categories later as and when they are encountered. + +Libraries which use NSLog should *NOT* act as clients of the library excepting +in tools, and test drivers. By implementing a client in the test drivers, +libraries can verify the log messages sent. If a library might produce a lot +of logging then it must implement a client in its test drivers or it might run +out of RAM while running tests. + +How to log stuff +---------------- + +In order to log messages, you need to have a category to log under. We +recommend that you have one category per library or application, and that you +create sub-categories beneath that to divide the library (or app) into logical +units. + +Categories should be declared in headers, and defined in C files. You declare +a category thusly: + + NSLOG_DECLARE_CATEGORY(catname); + +In that `catname` is a valid suffix for a C identifier, and will be used as +the logical name of the category for the purpose of NSLOG statements. + +You define a category thusly: + + NSLOG_DEFINE_CATEGORY(catname, description); + +In that `catname` matches the above, and `description` is a C string (or +identifier to a C string) which describes the category. + +You define a subcategory thusly: + + NSLOG_DEFINE_SUBCATEGORY(parentcatname, catname, description); + +In that `parentcategory` is the `catname` of another category which will be +considered the parent of this subcategory. `catname` and `description` as +above. Subcategories are rendered with slashes between their names when shown +as text, so a category of `foo` with a subcategory of `bar` would result in +two categories, one `foo` and one `foo/bar`. + +Once you have categories, you can log stuff. Your categories don't have to be +entirely public, but you will need access to the symbol to be able to log +things with the given category. To log something, you use: + + NSLOG(catname, level, logmsg, args...); + +In that `catname` is a `catname` from the above, `level` is a bareword logging +level which will be prefixed with `NSLOG_LEVEL_` for use (e.g. you can use +`WARNING` directly). `logmsg` and `args...` are a `printf()` style log message +which will be rendered by the time `NSLOG()` returns, so you don't have to +worry about lifetimes. + +Lib NSLOG lets you define a minimum compiled-in logging level which can be used +to elide deep debugging in release builds. The `NSLOG()` macro expands to a +constant comparison which will be resolved at compile time (assuming +optimisations are turned on) to result in logging which doesn't need to be +compiled in, being compiled out (and thus is is basically zero-cost to sprinkle +deep debugging in your code). + +Being a libnslog client +----------------------- + +In order for code which uses `NSLOG()` to be hosted effectively, the client must +do two things. Firstly a callback must be provided. The simplest callback +would be: + + static nslog__client_callback(void *context, nslog_entry_context_t *ctx, + const char *fmt, va_list args) + { + (void)context; + (void)ctx; + (void)fmt; + va_start(args, fmt); + va_end(args); + } + +In that `context` is a `void*` which is passed through to the client code +directly, allowing a client to provide some struct or other through to the +logging client callback. `ctx` is an NSLOG context which you can find out more +about by reading the docs. It contains the information about the logging +*site* such as the filename, line number, function name, level, and category +used to make the log entry. `fmt` is the `logmsg` from above, and `args` +is the variadic argument set used to format the arguments. + +This callback is registered into Lib NSLOG with something like: + + nslog_set_render_callback(nslog__client_callback, NULL); + +If a callback is not set, then bad things will happen when the next thing is +run. The final thing which must happen before the client will receive log +statements is that the client must _uncork_ the logging library. Since logging +can occur **before** the client is ready, the library will render and store the +log messages in a list, awaiting the call to uncork. Once uncorked, log +messages will be passed through as flatly as possible to the client. To uncork +the library, call: + + nslog_uncork(); + +All corked messages will be passed to the client callback, in the order they +were logged, before the uncork call returns. + +Filtering logs +-------------- + +The primary way to filter logs is to simply compile out the logging levels you +do not wish to exist. Sadly this is a very coarse filter and is best used to +exclude deep debug (and possibly debug) from release builds. If you wish to +filter your logs more flexibly at runtime, then you need to set up a log +filter. You *can* build the filters "by hand" but much easier is to use the +text filter parser as such: + + nslog_filter_t *filter = NULL; + if (nslog_filter_from_text(my_filter_text, &output) == NSLOG_NO_ERROR) { + nslog_filter_set_active(filter, NULL); + nslog_filter_unref(filter); + } + +The filter syntax is fairly simple: + +* A `filter` is one of a `NOT` an `AND`, `OR`, or `XOR`, or a `simple` filter. +* a `NOT` filter is of the form `!filter` +* an `AND` filter is of the form `(filter && filter)` +* an `OR` filter is of the form `(filter || filter)` +* an `XOR` filter is of the form `(filter ^ filter)` +* A `simple` filter is one of a `level`, `category`, `filename`, `dirname`, + or `funcname` filter. +* a `level` filter is of the form `level: FOOLEVEL` where `FOOLEVEL` is one of + `DEEPDEBUG`, `DEBUG`, `VERBOSE`.... +* a `category` filter is of the form `cat: catname` where `catname` is a + category name. If it is of the form `foo` then it will match all categories + `foo` or `foo/*` but not `foobar` +* a `filename` filter is of the form `file: filename` and is essentially a + suffix match on the filename. `foo.c` will match `foo.c` and `bar/foo.c` + but not `barfoo.c` +* a `dirname` filter is of the form `dir: dirname` and is essentially a prefix + match on the filename. `foo` will match `foo/bar.c` and `foo/bar/baz.c` but + not `foobar.c` + +Between tokens, any amount of whitespace is valid, but canonically only a small +amount will be used. You can take any filter you have and re-render it in its +canonical text form by using `nslog_filter_sprintf()` which is documented. + +Filters are evaluated in standard order, with parentheses doing the obvious +thing. In addition, the `AND` and `OR` filters will short-circuit as you'd +expect, so you can use that to your advantage to make your filters efficient. +Internally, Lib NSLOG will cache filtering intermediates to make things as fast +as possible, but a badly designed filter will end up slowing things down +dramatically. -- cgit v1.2.3