aboutsummaryrefslogtreecommitdiffstats
path: root/man/el_print.3
blob: 23d9079923fe27931ff6df147dab0b25cc257165 (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
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
.TH "el_print" "3" "10 June 2019 (v9999)" "bofc.pl"
.SH NAME
.PP
.BR el_print ,
.BR el_vprint ,
.BR el_puts ,
.BR el_pmemory,
.BR el_pmemory_table,
.B el_perror
- prints message to previously configured outputs.
.SH SYNOPSIS
.PP
.B "#include <embedlog.h>"
.PP
.BI "int el_puts(const char *" message ")"
.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 ")
.PP
.BI "int el_oputs(struct el *" el ", const char *" message ")"
.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 ")"
.PP
.BI "#define ELF " __FILE__ ", " __LINE__ ", " EL_FUNC_NAME ", " EL_FATAL
.br
.BI "#define ELA " __FILE__ ", " __LINE__ ", " EL_FUNC_NAME ", " EL_ALERT
.br
.BI "#define ELC " __FILE__ ", " __LINE__ ", " EL_FUNC_NAME ", " EL_CRIT
.br
.BI "#define ELE " __FILE__ ", " __LINE__ ", " EL_FUNC_NAME ", " EL_ERROR
.br
.BI "#define ELW " __FILE__ ", " __LINE__ ", " EL_FUNC_NAME ", " EL_WARN
.br
.BI "#define ELN " __FILE__ ", " __LINE__ ", " EL_FUNC_NAME ", " EL_NOTICE
.br
.BI "#define ELI " __FILE__ ", " __LINE__ ", " EL_FUNC_NAME ", " EL_INFO
.br
.BI "#define ELD " __FILE__ ", " __LINE__ ", " EL_FUNC_NAME ", " EL_DBG
.PP
.BI "#define OELF " __FILE__ ", " __LINE__ ", " EL_FUNC_NAME ", " EL_FATAL ", " EL_OPTIONS_OBJECT
.br
.BI "#define OELA " __FILE__ ", " __LINE__ ", " EL_FUNC_NAME ", " EL_ALERT ", " EL_OPTIONS_OBJECT
.br
.BI "#define OELC " __FILE__ ", " __LINE__ ", " EL_FUNC_NAME ", " EL_CRIT ", " EL_OPTIONS_OBJECT
.br
.BI "#define OELE " __FILE__ ", " __LINE__ ", " EL_FUNC_NAME ", " EL_ERROR ", " EL_OPTIONS_OBJECT
.br
.BI "#define OELW " __FILE__ ", " __LINE__ ", " EL_FUNC_NAME ", " EL_WARN ", " EL_OPTIONS_OBJECT
.br
.BI "#define OELN " __FILE__ ", " __LINE__ ", " EL_FUNC_NAME ", " EL_NOTICE ", " EL_OPTIONS_OBJECT
.br
.BI "#define OELI " __FILE__ ", " __LINE__ ", " EL_FUNC_NAME ", " EL_INFO ", " EL_OPTIONS_OBJECT
.br
.BI "#define OELD " __FILE__ ", " __LINE__ ", " EL_FUNC_NAME ", " EL_DBG ", " EL_OPTIONS_OBJECT
.PP
.BI "#define EL_DEBUG(" ... ") el_print(ELD, __VA_ARGS__)
.PP
Feature Test Macro
.PP
.BR "#define EL_DEBUG" ()
.RS
__ISOC99_SOURCE
.RE
.SH DESCRIPTION
.PP
Functions print log into configured outputs.
.PP
.BR el_puts (3)
function prints
.I message
that is simple string,
.I message
is not altered in anyway - that means no automatic log levels, location of the
log nor timestamp is printed - even if they are enabled.
Logs printed with this functions are not filtered by log level, and will always
be printed. Prints can still be suppressed by disabling output.
.PP
.BR el_putb (3)
function works same as
.BR el_puts (3)
but binary data can be passed.
That binary data will not be printed in ASCII like it it with
.BR el_pmemory (3).
If
.I memory
contains
.B NULL
characters, they will be stored to file.
If
.I memory
is for example
.B char buf[] = { 0xb0, 0xfc, 0x13, 0x37 }
then exactly these bytes will be stored into file.
.PP
.BR el_print (3)
function behaves similar to standard
.BR printf ()
function from the standard library, but it adds (if enabled) additional
information, such as
.I file
name,
.I line
number or
.I func
name
from where log has been printed, log
.IR level ,
and timestamp of the message.
.I fmt
and variadic variables
.I ...
have the same role as it is described in
.BR printf ()
manual page.
.PP
.BR el_vprint (3)
function behaves just like
.BR el_print (3)
but it accepts argument pointer
.I ap
instead of variadic variables.
Check
.BR vprintf ()
for more information.
.PP
.BR el_perror (3)
works the same way as
.BR el_print (3)
but will also print information about current errno that was set.
If
.I fmt
is
.BR NULL ,
only information about errno will be printed.
It is similar to
.BR perror ()
function.
It is guaranteed that
.BR el_perror (3)
functions will not modify
.B errno
value.
.PP
.BR el_pmemory (3)
is designed to print memory location in a nice hex+ascii format.
Function accepts pointer to
.I memory
and
.I mlen
number of bytes caller wants to print.
If
.I mlen
is 0, function won't print anything and will return
.B EINVAL
error.
Function doesn't care what is under passed address, memory block may contain
strings with null characters '\\0', integers, floats or even
.B struct
objects.
.PP
Example output can look like this.
We print all ascii table, to present printing of printable and non-printable
values.
.PP
.nf
    0x0000  00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f  ................
    0x0010  10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f  ................
    0x0020  20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f   !"#$%&'()*+,-./
    0x0030  30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f  0123456789:;<=>?
    0x0040  40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f  @ABCDEFGHIJKLMNO
    0x0050  50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f  PQRSTUVWXYZ[\]^_
    0x0060  60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f  `abcdefghijklmno
    0x0070  70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f  pqrstuvwxyz{|}~.
.fi
.PP
.BR el_pmemory_table (3)
works just like
.BR el_pmemory (3)
but also prints table-like header and footer.
.PP
.nf
    ------  -----------------------------------------------  ----------------
    offset  hex                                              ascii
    ------  -----------------------------------------------  ----------------
    0x0000  00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f  ................
    0x0010  10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f  ................
    0x0020  20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f   !"#$%&'()*+,-./
    0x0030  30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f  0123456789:;<=>?
    0x0040  40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f  @ABCDEFGHIJKLMNO
    0x0050  50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f  PQRSTUVWXYZ[\]^_
    0x0060  60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f  `abcdefghijklmno
    0x0070  70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f  pqrstuvwxyz{|}~.
    ------  -----------------------------------------------  ----------------
.fi
.PP
.BR el_pbinary (3)
is used to log binary data into block device.
Both metadata and data itself are treated as binary data.
Such files cannot be read with text tools like
.BR less ,
but rather needs special program that will parse the file.
This may be usefull when you need, for example to log every message on CAN bus.
If there are a lot of messages, it may be better to store them in binary format
as this may save *a lot* of space.
.PP
.BR el_pbinary (3)
uses specific format to store metadata to save as much space as possible.
All numerical values in metadata are variadic in size. Order of fields are as
follows:
.PP
.nf
    +-------+------------+--------------+-------------+------+
    | flags | ts_seconds | ts_fractions | data_length | data |
    +-------+------------+--------------+-------------+------+
.fi
.PP
The only mandatory fields are
.BR flags ", " data_length " and " data .
.B flags
determin what fields are present.
.B flags
field is always 1 byte in size and its format is
.PP
.nf
    +------+-------+-----------------------------------------------------------+
    | bits | value | description                                               |
    +------+-------+-----------------------------------------------------------+
    |    0 |   0   | both ts_seconds and ts_fraction will not appear           |
    |      +-------+-----------------------------------------------------------+
    |      |   1   | at least ts_seconds will appear, ts_fraction appearance   |
    |      |       | depends on 1..2 bits values                               |
    +------+-------+-----------------------------------------------------------+
    | 1..2 |   0   | ts_fractions will not appear                              |
    |      +-------+-----------------------------------------------------------+
    |      |   1   | ts_fractions will hold milliseconds value                 |
    |      +-------+-----------------------------------------------------------+
    |      |   2   | ts_fractions will hold microseconds value                 |
    |      +-------+-----------------------------------------------------------+
    |      |   3   | ts_fractions will hold nanoseconds value                  |
    +------+-------+-----------------------------------------------------------+
    | 3..5 |  0..7 | severity of the log, 0 is the highest and 7 is the lowest |
    +------+-------+-----------------------------------------------------------+
    | 6..7 |  0..3 | reserved                                                  |
    +------+-------+-----------------------------------------------------------+
.fi
.PP
.BR ts_seconds ", " ts_fractions " and " data_length
are numerical values with dynamic size.
Each byte of a numerical value can hold number up to 127 and oldest bit is used
as continuation bit, if that bit is set, program should treat next byte as next
part of the same numerical value.
Below is table with example decimal values and it's encoded counterpart.
.PP
.nf
    +---------------+--------------------------+
    | decimal value | encoded hex value        |
    +---------------+--------------------------+
    |             0 | 0x00                     |
    |             1 | 0x01                     |
    |             2 | 0x02                     |
    |           127 | 0x7f                     |
    |           128 | 0x80 0x01                |
    |           129 | 0x81 0x01                |
    |           255 | 0xff 0x01                |
    |           256 | 0x80 0x02                |
    |           257 | 0x81 0x02                |
    |         16383 | 0xff 0x7f                |
    |         16384 | 0x80 0x80 0x01           |
    |         16385 | 0x81 0x80 0x01           |
    |     438478374 | 0xa6 0xcc 0x8a 0xd1 0x01 |
    |    2147483647 | 0xff 0xff 0xff 0xff 0x07 |
    |    4294967295 | 0xff 0xff 0xff 0xff 0x0f |
    +---------------+--------------------------+
.fi
.PP
Encoded number are always
.BR little-endian ,
that is first byte is always the least significant byte.
.PP
.B data
is be whatever you want of any size.
.BR el_pbinary (3)
uses only timestamp and log level, rest of the options in
.I el
are simply ignores.
.PP
.BR el_print (3),
.BR el_vprint (3),
.BR el_perror (3),
.BR el_pmemory_table (3)
and
.BR el_pmemory (3)
are filtered based on their
.IR level .
.PP
All of above functions have their counterpart that also accepts custom
.I el
object.
This is useful if we want for example, print logs into one file, and program
queries into another.
It can also be used to print every level into different file.
.PP
When user defines
.B EL_OPTIONS_OBJECT
macros with
.B OEL*
can be used to save yourself the trouble to type
.B &opt_obj
each time.
This macro should be defined to what normally would be passed to
.B el_oprint
functions familly.
It usually is used with
.B extern
keyword like
.PP
.nf
    extern struct el  log_foobar;
    #define EL_OPTIONS_OBJECT &log_foobar
.fi
.PP
It is real pain in the ass to provide information about file in every print
function. For that matter very simple macros have been provided.
.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
These macros comprese first 3 parameters
.IR file ,
.I line
and
.I level
into single, short parameter.
For example instead calling this
.PP
.nf
    el_print(__FILE__, __LINE__, EL_FUNC_NAME, EL_NOTICE, "notice message number %d", num);
.fi
.PP
you can simply call
.PP
.nf
    el_print(ELN, "notice message number %d", num);
.fi
.PP
This solution works both for
.B c89
and
.B c99
standards.
All side effects (like from calling function or incrementing variable in print
function call) will take effect always regardless of set logging level.
Also strings used in functions will be compiled and put into binary - always.
If user defines
.B NOFINFO
in his project, all
.B __FILE__
,
.B __LINE__
and
.B EL_FUNC_NAME
will be unconditionally set to
.B NULL
and
.B 0
and no file information will be printed - even if it was enabled with
.BR el_option (3).
.PP
If user has access to
.B c99
compiler, one can use
.B EL_DEBUG
for debuging messages only.
Later when application is compiled with NDEBUG, all side effects as well as
strings used will be stripped out from final binary - so no vital information
will be leaked in such way.
This is not possible on
.B c89
compiller due to absence of variadic variables in
preprocesor macros.
.PP
.B EL_FUNC_NAME
will work only on
.B c99
compilers, where
.B __func__
is defined, on
.B c89
compilers function name won't be printed, and setting
.B EL_FUNCINFO
won't help it.
.SH RETURN VALUE
.PP
All functions return 0 when whole message has been successfuly printed to all
configured outputs.
If message couldn't be printed, it was printed only partially, or was not send
to at least one configured output -1 is returned.
Note that only one error is returned even if there was multiple errors.
.SH ERRORS
.PP
All functions may return one of these on error
.TP
.B EINVAL
Any of the input parameters is invalid.
.TP
.B EBADF
Loggig to file is enabled and filename was not set with
.B EL_FPATH
option
.TP
.B EBADF
Logging to file is enabled, file was opened sucessfuly, but log cannot be stored
into file.
This usually happen that file was unlinked from the file system and
.B embedlog
couldn't create new file again (no access to directory or directory doesn't
exist at all).
Log is lost, but
.B embedlog
will try to recreate log file everytime
.BR el_print (3)
is called.
.TP
.B ENODEV
All possible outputs are disabled
.PP
.BR el_print (3),
.BR el_vprint (3),
.BR el_perror (3),
.BR el_pmemory_table (3)
and
.BR el_pmemory (3)
may also return:
.TP
.B ERANGE
Message will not be logged as message log level is lower than configured one.
.TP
.B ENOBUFS
Message is bigger than
.B EL_LOG_MAX
and will be truncated.
.PP
When logging to file is enabled, all functions may also return errors
from
.BR fwrite ()
and if file rotation is enabled also from
.BR fopen ()
.SH SEE ALSO
.PP
.BR el_overview (7),
.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_option (3).