summaryrefslogtreecommitdiffstats
path: root/doc/Diagnostic-Logging.md
blob: e71e737f031d59bcb661a48d051a9d3db1e20c07 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# The Hierarchical Log Library (`hlog`)

A program uses the hierarchical log library, `hlog`, to organize
its diagnostic messages into categories and subcategories and to
turn on and off message categories to produce the most useful
diagnostic trace.

A typical program will define one or more log *outlets*.  An outlet
is a named target for diagnostic messages.  Each outlet has a *state*
(*on*, *off*, or *pass*) and at most one *parent outlet*.  Usually, the
parent-child relationships between outlets form a tree rooted at the
outlet "all", which is supplied by the library.  Outlets may form a
"forest" if a program supplies its own root outlets.

A program sends messages to an outlet using `hlog` API calls.
Messages sent to an outlet that is *on* are copied to the error
stream.  Messages sent to an outlet that is *off* are discarded.
When a message is sent to an outlet in *pass* state, the `hlog`
uses the outlet ancestors to decide what to do with the message.

## Sending messages with `hlog_fast`
 
A program calls `hlog_fast(outlet name, format string, ...)` to
write a formatted message to the named outlet.  `hlog_fast` uses
the outlet state to do decide what to do with the message.  If the
outlet is *on*, then the message is written to the standard error
stream.  If the outlet is *off*, then the message is discarded.
If the outlet is in state *pass*, and the outlet has no parent,
then the message is discarded.  If the outlet does have a parent,
then `hlog_fast` looks at the parent state and decides whether to
discard, write, or recurse.

`hlog_fast` precedes each diagnostic message with a timestamp (decimal
seconds with 9 digits right of the decimal point), a colon, and a single
space.  Each message is followed with a newline ("\n").  The effective
timestamp resolution may be much less than one nanosecond.  Timestamps
increase monotonically.  The timestamp origin is currently unspecified.

## Defining log outlets

`hlog` provides macros for declaring outlets, and for statically
configuring an outlet, its parent, and its initial state.

Use `HLOG_OUTLET_DECL(name)` to declare shared outlets in header
files.  `HLOG_OUTLET_DECL(name)` declares an `extern` symbol.
There must not be any quotation marks on *name*.

Use `HLOG_OUTLET_SHORT_DEFN(name, parent)` to define an outlet with the
given name and parent in state *pass*.  There must not be any quotation
marks on *name*.

Use `HLOG_OUTLET_MEDIUM_DEFN(name, parent, state)` to define an outlet
with the given name, parent, and state.  The state is given by an
`hlog_outlet_state_t`, one of `HLOG_OUTLET_S_ON`, `HLOG_OUTLET_S_OFF`,
or `HLOG_OUTLET_S_PASS`.  There must not be any quotation marks on
*name*.

## Enabling and disabling outlets with the environment

An environment variable, `HLOG`, sets initial outlet states for a
program.  If `HLOG` may be set to the empty string, in which case
outlet states stay at their program defaults.  `HLOG` may also be
set to one or more *outlet name*=*state* pairs, separated by either
whitespace or commas. *state* is one of *pass*, *on*, or *off*,
and *outlet-name* is a string matching `[_a-zA-Z][_a-zA-Z0-9]*`.
For example, to enable the `tick` outlet and `pbrm` outlets while
the program `./vfd_swmr_zoo_writer` runs, you can use this command
in `csh` or Bourne shell:

```
env HLOG="tick=on pbrm=on" ./vfd_swmr_zoo_writer
```

# Implementation notes

`hlog_fast(outlet name, format string, ...)` is implemented as a
macro that only evaluates its format string or other arguments if
it decides to write the message to `stderr`.  `hlog_fast` avoids
repeatedly walking child-parent links by caching its decision to
write or discard in the named outlet.

# Future improvements

The timestamp origin is unspecified, now.  For the user's convenience,
the timestamp probably should be measured from `hlog` library
initialization.  Also, `hlog` should provide a routine for setting
the timestamp origin to the current time.