Small Yet Flexible Logger In C
This project is maintained by ehetherington
Rather than re-invent the wheel, the java.util.logging.XMLFormatter format was used. It has an official DTD. See Appendix A of Oracle’s [java-logging-overview] (https://docs.oracle.com/javase/10/core/java-logging-overview.htm).
Or, here
The millis element is the number of milliseconds since the epoch. The nanos element is number of nanoseconds to add to that.
So, to create them from a timespec:
struct timespec *ts;
long int time_millis;
long int time_nanos;
time_millis = ts->tv_sec * 1000 + ts->tv_nsec / 1000000;
time_nanos = ts->tv_nsec % 1000000;
To create the values for the millis and nanos element
The date element is in the same ISO 8601 format, except the millisecond fraction is added
<date>2020-06-14T10:48:35.634</date>
The millis element is the same.
<millis>1592146115634</millis>
The nanos element (added in JDK 9) is the same.
<nanos>587985</nanos>
The sequence element is the same.
<sequence>0</sequence>
The logger element, which is normally the name of the logger class, is filled with tinylogger.
<logger>tinylogger</logger>
The level element is filled with the standard Java labels when a log level from Java is used. When there is no corresponding Java pre-defined level, an integer representing its interpolated level is used.
<level>INFO</level>
The class element is filled with the source code file name instead of the class;
<class>formats.c</class>
The method element is filled with the function name.
<method>main</method>
The thread element is filled with the thread id returned by gettid(). This is different than the pthread_t thread id.
<thread>407953</thread>
And finally, the message element is filled with the actual message.
<message>this message uses the "≶xml>" format & it's easy!</message>
The following characters are replace with the corresponding xml entities:
character | entity | description ———-|———-|———— ‘<’ | “<” | less than ‘>’ | “>” | greater than ‘&’ | “&” | ampersand ‘'’ | “'” | apostrophe ‘"’ | “"” | quote (using c style notation for “char” and “string” - probably not appropriate)
The following program:
#include "tinylogger.h"
#define LOG_FILE "tinylogger.xml"
#define N_MSGS 3
int main(void) {
/*
* Print a series of xml formatted messages
* Use the xml formatter
* Use line buffered output
*/
LOG_CHANNEL *ch1 = log_open_channel_f(LOG_FILE, LL_INFO, log_fmt_xml, true);
(void) ch1; // quiet the "unused variable" warning
for (int n = 0; n < N_MSGS; n++) {
log_info("this message uses the \"<xml>\" format it's #%d", n);
}
log_done();
return 0;
}
produces:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE log SYSTEM "logger.dtd">
<log>
<record>
<date>2020-06-15T12:59:55.288</date>
<millis>1592240395288</millis>
<nanos>895371</nanos>
<sequence>0</sequence>
<logger>tinylogger</logger>
<level>INFO</level>
<class>xml.c</class>
<method>main</method>
<thread>488739</thread>
<message>this message uses the "<xml>" format it's #0</message>
</record>
<record>
<date>2020-06-15T12:59:55.289</date>
<millis>1592240395289</millis>
<nanos>103486</nanos>
<sequence>1</sequence>
<logger>tinylogger</logger>
<level>INFO</level>
<class>xml.c</class>
<method>main</method>
<thread>488739</thread>
<message>this message uses the "<xml>" format it's #1</message>
</record>
<record>
<date>2020-06-15T12:59:55.289</date>
<millis>1592240395289</millis>
<nanos>143152</nanos>
<sequence>2</sequence>
<logger>tinylogger</logger>
<level>INFO</level>
<class>xml.c</class>
<method>main</method>
<thread>488739</thread>
<message>this message uses the "<xml>" format it's #2</message>
</record>
</log>
When read by a java program that reads files produced with the java.util.logging.XMLForatter formatter:
Jun 15, 2020 12:59:55 PM xml.c main
INFO: this message uses the "<xml>" format it's #0
Jun 15, 2020 12:59:55 PM xml.c main
INFO: this message uses the "<xml>" format it's #1
Jun 15, 2020 12:59:55 PM xml.c main
INFO: this message uses the "<xml>" format it's #2