-
Notifications
You must be signed in to change notification settings - Fork 0
/
logging.c
160 lines (143 loc) · 5.35 KB
/
logging.c
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
/* Copyright 2013 Alexander Weinert, Markus Joppich */
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License or under the
* terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* and the GNU Lesser General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*
* Dieses Programm ist Freie Software: Sie können es unter den Bedingungen
* der GNU General Public License oder unter den Bedingungen der GNU Lesser
* General Public License, wie von der Free Software Foundation, Version 3
* der Lizenz oder (nach Ihrer Option) jeder späteren veröffentlichten
* Version, weiterverbreiten und/oder modifizieren.
*
* Dieses Programm wird in der Hoffnung, dass es nützlich sein wird, aber
* OHNE JEDE GEWÄHRLEISTUNG, bereitgestellt; sogar ohne die implizite
* Gewährleistung der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.
* Siehe die GNU General Public License für weitere Details.
*
* Sie sollten eine Kopie der GNU General Public License und der GNU Lesser
* General Public License zusammen mit diesem Programm erhalten haben.
* Wenn nicht, siehe <http://www.gnu.org/licenses/>.
*/
/**
* \file logging.c
* \date June, 2013
* \brief Time measurement and logging
* \author Alexander Weinert, Markus Joppich
*/
#include "logging.h"
#include <stdio.h>
#include <stdarg.h>
#include <time.h>
/** The time at which logging_reset_timer was last called.
* This way we get a fixed time as a base for all timestamps */
static time_t tStartTime;
// ////////////
// PUBLIC FUNCTION DECLARATION
// ////////////
static const char * get_log_level_name(log_level level);
// ////////////
// PUBLIC FUNCTION DEFINITION
// ////////////
/** \brief Resets the timestamp to 0.0s.
* All future log messages will have the difference from this time as timestamp */
void logging_reset_timer(void) {
/* The current time is returned by time(...) as well as written into the
* object given as an argument. We simply use the return value here. */
tStartTime = time(NULL);
}
/**
* \brief Prints the given message to the appropriate log-sink
* \param pFile The name of the file from which the message originates
* \param iLine The line in the given file from which the message originates
* \param level The warning level of the given message. Can be used to highlight more important messages (not yet implemented)
* \param pMessage The printf-format string of the message to be logged
* \param ... The parameters for the given printf-format string
*
* The logged message will have the form
* [ LEVEL ] [ TIME ] message (at FILE:LINE)
*
* Currently all DEBUG- and STATUS-messages are written to stdout, all other
* messages to stderr. We may expose functions to adjust this in the future,
* log to files and maybe even ignore some levels entirely. */
void logging_log_message_file_line(const char* pFile, int iLine, log_level level, const char *pMessage, ...) {
// Get the difference between the current time and the last reset of the timer.
const time_t tCurrentTime = time(NULL);
const double dNow = difftime(tCurrentTime, tStartTime);
// Get the c-string representation of the given level
const char *pLevelName = get_log_level_name(level);
// Get the appropriate output sink
FILE *pOutput = NULL;
if(level <= WARNING) {
pOutput = stdout;
}
else {
pOutput = stderr;
}
// Get the arguments for the printf-format string
va_list arguments;
va_start(arguments, pMessage);
// Print log level and timestamp
fprintf(pOutput, "[ %s ] [ %.5f ] ", pLevelName, dNow);
// Print the actual message
vfprintf(pOutput, pMessage, arguments);
// Print the location where the message originated
fprintf(pOutput, " (at %s:%u)\n", pFile, iLine);
// Clean up
va_end(arguments);
}
/** \brief Print a naked timestamp, without logging level and point of origin
*
* Is currently only used at the end of the program to print the complete
* runtime for easier measurement. */
void logging_print_timestamp(void) {
const time_t tCurrentTime = time(NULL);
const double dNow = difftime(tCurrentTime, tStartTime);
fprintf(stdout, "%.5f\n", dNow);
}
// ////////////
// PRIVATE FUNCTION DEFINITION
// ////////////
/**
* \brief Returns a c-string representation of the given level.
*/
static const char * get_log_level_name(log_level level) {
// Get a c-string description of the given log-level
const char *pLevelName = NULL;
// TODO: Left align the levels, with leading whitespace
/* TODO: Find a workaround so that we do not have to list all names explicitely.
* Idea: C# has something like level.getName - maybe use some compiler magic for this? */
switch(level) {
case DEBUG: {
pLevelName = " DEBUG ";
break;
}
case STATUS: {
pLevelName = "STATUS ";
break;
}
case WARNING: {
pLevelName = "WARNING";
break;
}
case ERROR: {
pLevelName = " ERROR ";
break;
}
default : {
pLevelName = " ";
break;
}
}
return pLevelName;
}