aboutsummaryrefslogtreecommitdiffstats
path: root/man/el_overview.7
blob: cf02472bf85ddb944d6ff5f88dd461ebf29f779d (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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
.TH "el_overview" "7" "10 June 2019 (v9999)" "bofc.pl"
.SH NAME
.PP
.B el_overview
- quick overview of
.B embedlog
logging library
.SH SYNOPSIS
.PP
.B embedlog
- is a highly portable
.B c89
complaint logger (with additional features for users with
.B c99
compilers and/or
.B POSIX
systems).
This library is designed mainly for embedded devices, but can also be
used in high level OSes like
.BR Linux .
.SH DESCRIPTION
.PP
Logger incorporates features like:
.PP
.RS
- printing to different outputs (simultaneously) like:
.RS
- stderr
.br
- syslog (very limited, works on *nuttx* for now)
.br
- directly to serial device (like /dev/ttyS0)
.br
- file (with optional rotating and syncing to prevent data loss)
.br
- automatic file reopening on unexpected events (file deletion, SD remount)
.br
- custom routine, can be anything, embedlog just calls your function with
string to print
.RE
- timestamping using following clocks:
.RS
- clock_t
.br
- time_t
.br
- CLOCK_REALTIME (requires POSIX)
.br
- CLOCK_MONOTONIC (requires POSIX)
.br
- configurable precision of fraction of seconds (mili, micro, nano)
.RE
- printing file and line information
.br
- 8 predefined log levels (total rip off from syslog(2) levels)
.br
- colorful output (for easy error spotting)
.br
- print memory block in wireshark-like output
.br
- fully binary logs with binary data (like CAN frames) to save space
.RE
.RE
.PP
Library implements following functions:
.PP
.BI "int el_init(void)"
.br
.BI "int el_cleanup(void)"
.br
.BI "int el_option(enum el_option " option ", ...)"
.br
.BI "int el_puts(const char *" string ")"
.br
.BI "int el_putb(const void *" memory ", size_t " mlen ")"
.br
.BI "int el_print(const char *" file ", size_t " line ", const char *" func ", \
enum el_level " level ", const char *" fmt ", " ... ")"
.br
.BI "int el_vprint(const char *" file ", size_t " line ", const char *" func ", \
enum el_level " level ", const char *" fmt ", va_list " ap ")"
.br
.BI "int el_perror(const char *" file ", size_t " line ", \
const char *" func ", enum el_level " level ", const char *" fmt ", " ... ")"
.br
.BI "int el_pmemory(const char *" file ", size_t " line ", \
const char *" func ", enum el_level " level ", const void *" memory ", \
size_t " mlen ")
.br
.BI "int el_pmemory_table(const char *" file ", size_t " line ", \
const char *" func ", enum el_level " level ", const void *" memory ", \
size_t " mlen ")
.br
.BI "int el_pbinary(enum el_level " level ", const void *" memory ", \
size_t " mlen ")
.br
.BI "int el_flush(void)"
.br
.B const struct el *el_get_el(void)
.PP
Each functions has its equivalent function that accepts
.I el
object as argument.
This is helpful if we want to have more than one, separated loggers in a single
program.
Please see
.BR el_option (3)
for more information.
.PP
.BI "int el_oinit(struct el *" el ")"
.br
.BI "int el_ocleanup(struct el *" el ")"
.br
.B struct el * el_new(void)
.br
.BI "int el_destroy(struct el *" el ")"
.br
.BI "int el_ooption(struct el *" el ", enum el_option " option ", \
\&...)"
.br
.BI "int el_oputs(struct el *" el ", const char *" string ")"
.br
.BI "int el_oputb(struct el *" el ", const void *" memory ", \
size_t " mlen ")"
.br
.BI "int el_oprint(const char *" file ", size_t " line ", \
const char *" func ", enum el_level " level ", struct el *" el ", \
const char *" fmt ", " ... ")"
.br
.BI "int el_ovprint(const char *" file ", size_t " line ", \
const char *" func ", enum el_level " level ", struct el *" el ", \
const char *" fmt ", va_list " ap ")"
.br
.BI "int el_operror(const char *" file ", size_t " line ", \
const char *" func ", enum el_level " level ", struct el *" el ", \
const char *" fmt ", " ... ")"
.br
.BI "int el_opmemory(const char *" file ", size_t " line ", \
const char *" func ", enum el_level " level ", struct el *" el ", \
const void *" memory ", size_t " mlen ")"
.br
.BI "int el_opmemory_table(const char *" file ", size_t " line ", \
const char *" func ", enum el_level " level ", struct el *" el ", \
const void *" memory ", size_t " mlen ")"
.br
.BI "int el_opbinary(enum el_level " level ", struct el *" el ", \
const void *" memory ", size_t " mlen ")"
.br
.BI "int el_oflush(struct el *" el ")"
.PP
For more information about a function open manual page with functions name from
section 3 (ie. for el_oputs, you'd open
.BR el_oputs (3))
.PP
Every function that accepts 3 parameters
.IR level ,
.I file
and
.I line
as its first arguments, can accept short macro that injects proper values into
function.
Awailable macros are:
.PP
.RS
.BR ELF "    Fatal errors, usually precedes application crash"
.br
.BR ELA "    Alert, vey major error that should be fixed as soon as possible"
.br
.BR ELC "    Critical"
.br
.BR ELE "    Error"
.br
.BR ELW "    Warning"
.br
.BR ELN "    Normal log, but of high importance"
.br
.BR ELI "    Information message, shouldn't spam too much here"
.br
.BR ELD "    Debug messages, can spam as much as you'd like"
.RE
.PP
So instead of calling
.PP
.nf
    el_print(__FILE__, __LINE__, EL_FUNC_NAME, EL_NOTICE, "Notice message");
.fi
.PP
You can simply call it like
.PP
.nf
    el_print(ELN, "Notice message");
.fi
.PP
There are also equivalent macros for use with functions that also provides
.I el
object, so the can be used with
.B el_o
function family.
To make these work, you need to provide
.B EL_OPTIONS_OBJECT
macro.
Check
.BR el_print (3)
for more info about that.
.PP
.RS
.BR OELF "    Fatal errors, usually precedes application crash"
.br
.BR OELA "    Alert, vey major error that should be fixed as soon as possible"
.br
.BR OELC "    Critical"
.br
.BR OELE "    Error"
.br
.BR OELW "    Warning"
.br
.BR OELN "    Normal log, but of high importance"
.br
.BR OELI "    Information message, shouldn't spam too much here"
.br
.BR OELD "    Debug messages, can spam as much as you'd like"
.RE
.PP
So instead of calling
.PP
.nf
    el_oprint(__FILE__, __LINE__, EL_FUNC_NAME, EL_NOTICE, &g_log_object, "Notice message");
.fi
or
.nf
    el_oprint(ELN, &g_log_object, "Notice message");
.fi
.PP
You can simply call it like
.PP
.nf
    el_oprint(OELN, "Notice message");
.fi
.SH "STABLE ABI CONSIDERATION"
.PP
Since
.B embedlog
is versatile and can work on both hardcore embedded systems (nuttx, freertos,
bare metals) and on big CPUs that can run Linux, library must provide a way
for user to use stack-allocated objects and stable ABI.
Unfortunately there is no way to provide both at the same time, so
.B embedlog
provides two solutions so everybody is happy.
.PP
Note that library versioning follows
.B STABLE ABI
way of using library.
So if feature is added that adds new field to
.BR "struct el",
then this will not be treated as ABI breakage, because if you are using
.BR el_new (3)
or
.BR el_init (3)
functions, ABI will not be broken.
Only when using
.BR el_oinit (3)
ABI will be broken.
.SS "STABLE ABI"
.PP
When stable ABI is required, user must initialize
.B embedlog
either with
.BR el_init (3)
or
.BR el_new (3)
function.
User also must not access internal fields directly and all operations on
.I el
object must be done through the API functions.
.BR el_new (3)
will malloc necessary memory for the user which must be freed with
.BR el_destroy (3)
function.
Under no circumstances use
.B sizeof
on the object nor struct.
Operation will succeed, but may return invalid results when library is updated.
To put it in as few word as possible - you don't know anything about internals
of
.BR "struct el" .
.SS "STACK ALLOCATED OBJECT"
.PP
When you use library in hardcore embedded environment, where there is not
dynamic linking involved, you are save to ignore any ABI changes, since
you always build your programs alongside the library.
But thanks to that you can avoid
.BR malloc ()
call and allocate everything on the stack.
To allocate object on stack you must use
.BR el_oinit (3)
function, and deinitialize object with
.BR el_ocleanup (3).
.PP
If you are using
.BR el_oinit (3)
on systems with dynamic library support you are suscible to ABI breakage and
undefined behaviour when only new features are added, or even when bugfix
introduces new field to
.BR "struct el" .
Heck, even recompilation with different flags can break ABI here.
Do not use this approach if your system have dynamic library support unless
you can rebuild all programs against new version of library.
.PP
.B You've been warned!
.SH EXAMPLE
.PP
Initial setup is very trivial.
One should call init function and it will print to stderr by default.
Output can also be customized with proper el object, see
.BR el_option (3)
for more details.
.PP
.nf
    #include <embedlog.h>

    int main(void)
    {
        /* initialize library, default output is stderr */
        el_init();

        /* print message with info severity */
        el_print(ELI, "answer is %d", 42);

        /* clean after ourselfs */
        el_cleanup();

        return 0;
    }
.fi
.SH SEE ALSO
.PP
.BR el_cleanup (3),
.BR el_destroy (3),
.BR el_flush (3),
.BR el_init (3),
.BR el_new (3),
.BR el_ocleanup (3),
.BR el_oflush (3),
.BR el_oinit (3),
.BR el_ooption (3),
.BR el_operror (3),
.BR el_opmemory (3),
.BR el_opmemory_table (3),
.BR el_oprint (3),
.BR el_option (3),
.BR el_oputs (3),
.BR el_ovprint (3),
.BR el_perror (3),
.BR el_pmemory (3),
.BR el_pmemory_table (3),
.BR el_print (3),
.BR el_puts (3),
.BR el_vprint (3).