]> mj.ucw.cz Git - libucw.git/blob - ucw/logstream.h
Logging: Fixed a typo.
[libucw.git] / ucw / logstream.h
1 #ifndef _UCW_LOGSTREAM_H_
2 #define _UCW_LOGSTREAM_H_
3
4 #include "ucw/clists.h"
5
6 /* user de/allocated program/process name for use in the logsystem */
7 extern char *ls_title;
8
9 struct log_stream
10 {
11   /* optional name, 0-term, de/allocated by constr./destr. or user */
12   char *name;
13   /* number for use with msg parameter (from LS_SET_STRNUM()), -1 for closed log_stream */
14   int regnum;
15   /* arbitrary data for filter/handler */
16   int idata;
17   void *pdata;
18   /* severity levels to accept - bitmask of (1<<LEVEL) */
19   int levels;
20   /* if filter returns nonzero, discard the message */
21   int (*filter)(struct log_stream* ls, const char *m, u32 cat);
22   /* pass the message to these streams (simple-list of pointers) */
23   struct clist substreams;
24   /* what kind of string to format to pass to the handler (bitmask of LSFMT_xxx ) */
25   int msgfmt;
26   /* what to do to commit the message (ret 0 on success, nonzero on error)
27    * msg is 0-term string, with desired info, one line, ending with "\n\0". */
28   int (*handler)(struct log_stream* ls, const char *m, u32 cat);
29   /* close the log_stream file/connection */
30   void (*close)(struct log_stream* ls);
31 };
32
33 /* the deafult logger */
34 extern const struct log_stream ls_default_log;
35
36 /* A message is processed as follows:
37  *  1. Discard if message level not in levels
38  *  2. Run filter (if any), discard if ret. nonzero
39  *  3. Pass the message to all log_streams in substreams
40  *  4. Format the message informaion acc. to msgfmt
41  *  5. Run the handler
42  */
43
44 /* log header verbosity specifying message passed to handler */
45 enum LS_FMT
46 {
47   LSFMT_LEVEL=1,       /* log severity level (one letter) */
48   LSFMT_TIME=2,        /* log time (date-seconds) */
49   LSFMT_USEC=4,        /* log also micro-seconds */
50   LSFMT_TITLE=8,       /* log program title (global string) */
51   LSFMT_PID=16,        /* log program PID */
52   LSFMT_LOGNAME=32,    /* log log_stream name */
53   LSFMT_NONE=0,
54   LSFMT_FULL=LSFMT_LEVEL+LSFMT_TIME+LSFMT_USEC+LSFMT_TITLE+LSFMT_PID+LSFMT_LOGNAME,
55   LSFMT_DEFAULT=LSFMT_LEVEL+LSFMT_TIME
56 };
57
58 enum LS_LEVELS
59 {
60   L_DEBUG=0,     /*  'D'  -  Debugging messages */
61   L_INFO,        /*  'I'  -  Informational */
62   L_INFO_R,      /*  'i'  -  xxx_R are messages caused by external events */
63   L_WARN,        /*  'W'  -  Warning */
64   L_WARN_R,      /*  'w'  */
65   L_ERROR,       /*  'E'  -  Error, but non-critical */
66   L_ERROR_R,     /*  'e'  */
67   L_FATAL,       /*  '!'  -  Error, from die() */
68 };
69
70 /* Mask of containing all existing levels. */
71 #define LS_ALL_LEVELS 0xfff
72
73 // return the letter associated with the severity level
74 #define LS_LEVEL_LETTER(level) ("DIiWwEe!###"[( level )])
75
76 ///// Macros for extracting parts of the flags parameter
77 // The division of the flags parameter is decided only here
78 // The current division is (for 32 bit flags):
79 // MSB <5 bits: any internal log flags> <8 bits: "user" flags> <10 bits: stream number>
80 //     <8 bits: severity level> LSB
81
82 // Bits per section
83 enum LS_FLAGBITS {
84   LS_LEVEL_BITS    = 8,
85   LS_STRNUM_BITS   = 16,
86   LS_FLAGS_BITS    = 5,
87   LS_INTERNAL_BITS = 4,
88 };
89
90 // Section shifts
91 enum LS_FLAGPOS {
92   LS_LEVEL_POS     = 0,
93   LS_STRNUM_POS    = LS_LEVEL_POS + LS_LEVEL_BITS,
94   LS_FLAGS_POS     = LS_STRNUM_POS + LS_STRNUM_BITS,
95   LS_INTERNAL_POS  = LS_FLAGS_POS + LS_FLAGS_BITS,
96 };
97
98 // Bitmasks
99 enum LS_FLAGMASKS {
100   LS_LEVEL_MASK    = (( 1 << LS_LEVEL_BITS ) - 1 ) << LS_LEVEL_POS,
101   LS_STRNUM_MASK   = (( 1 << LS_STRNUM_BITS ) - 1 ) << LS_STRNUM_POS,
102   LS_FLAGS_MASK    = (( 1 << LS_FLAGS_BITS ) - 1 ) << LS_FLAGS_POS,
103   LS_INTERNAL_MASK = (( 1 << LS_INTERNAL_BITS ) - 1 ) << LS_INTERNAL_POS,
104 };
105
106 // "Get" macros (break flags to parts)
107 #define LS_GET_LEVEL(flags)     ((( flags ) & LS_LEVEL_MASK ) >> LS_LEVEL_POS )
108 #define LS_GET_STRNUM(flags)    ((( flags ) & LS_STRNUM_MASK ) >> LS_STRNUM_POS )
109 #define LS_GET_FLAGS(flags)     ((( flags ) & LS_FLAGS_MASK ) >> LS_FLAGS_POS )
110 #define LS_GET_INTERNAL(flags)  ((( flags ) & LS_INTERNAL_MASK ) >> LS_INTERNAL_POS )
111
112 // "Set" macros (parts to flags)
113 #define LS_SET_LEVEL(level)     (( level ) << LS_LEVEL_POS )
114 #define LS_SET_STRNUM(strnum)   (( strnum ) << LS_STRNUM_POS )
115 #define LS_SET_FLAGS(flags)     (( flags ) << LS_FLAGS_POS )
116 #define LS_SET_INTERNAL(intern) (( intern ) << LS_INTERNAL_POS )
117
118 // Internal flags of the logsystem
119 // Avoid operations that are unsafe in signal handlers
120 #define LSFLAG_SIGHANDLER LS_SET_INTERNAL(0x001)
121
122 // The module is initialized when a first stream is created.
123 // Before that only the default log exists.
124
125 // Initial number of streams to allocate (must be >=2)
126 #define LS_INIT_STREAMS 8
127
128 /* Return pointer a new (xmalloc()-ated) stream with no handler and an empty substream list. */
129 struct log_stream *ls_new(void);
130
131 /* Close and xfree() given log_stream */
132 /* Does not affect substreams */
133 void ls_close(struct log_stream *ls);
134
135 /* close all open streams, un-initialize the module, free all memory,
136  * use only ls_default_log */
137 void ls_close_all(void);
138
139 /* add a new substream, malloc()-ate a new simp_node */
140 void ls_add_substream(struct log_stream *where, struct log_stream *what);
141
142 /* remove all occurences of a substream, free() the simp_node */
143 /* return number of deleted entries */
144 int ls_rm_substream(struct log_stream *where, struct log_stream *what);
145
146 /* get a stream by its number (regnum) */
147 /* returns NULL for free numbers */
148 /* defaults to ls_default_stream for 0 when stream number 0 not set */
149 struct log_stream *ls_bynum(int num);
150
151 /* The proposed alternative to original vmsg() */
152 void ls_vmsg(unsigned int cat, const char *fmt, va_list args);
153
154 /* The proposed alternative to original msg() */
155 void ls_msg(unsigned int cat, const char *fmt, ...);
156
157 /* The proposed alternative to original die() */
158 void ls_die(const char *fmt, ...);
159
160 /* process a message (string) (INTERNAL) */
161 /* depth prevents undetected looping */
162 /* returns 1 in case of loop detection or other fatal error
163  *         0 otherwise */
164 int ls_passmsg(int depth, struct log_stream *ls, const char *stime, const char *sutime,
165     const char *msg, u32 cat);
166
167 /* Maximal depth of ls_passmsg recursion */
168 #define LS_MAX_DEPTH 64
169
170 /********* Individual handler types (constructors, handlers, destructors) */
171
172 /**** standard (filedes) files */
173
174 // NOTE:
175 // under unix, for ordinary files open in append mode, the writes
176 // are atomic (unless you meet the quota or other bad things happen),
177 // so using a single log_stream is thread-safe and the file can be shared
178 // among multiple processes
179
180 /* assign log to a file descriptor */
181 /* initialize with the default formatting, does NOT close the descriptor */
182 struct log_stream *ls_fdfile_new(int fd);
183
184 /* open() a file (append mode) */
185 /* initialize with the default formatting */
186 struct log_stream *ls_file_new(const char *path);
187
188
189 /**** syslog */
190
191 // NOTE:
192 // The syslog uses a bit different severity levels, for details, see
193 // ls_syslog_convert_level().
194 // syslog also prepends it's own time and severity info, so the default
195 // messaging passes only clean message
196
197 /* assign log to a syslog facility */
198 /* initialize with no formatting (syslog adds these inforamtion) */
199 /* name is optional prefix (NULL for none) */
200 struct log_stream *ls_syslog_new(int facility, const char *name);
201
202 #endif