Objectively 1.0.0
Ultra-lightweight object oriented framework for GNU C.
Log.c
Go to the documentation of this file.
1/*
2 * Objectively: Ultra-lightweight object oriented framework for GNU C.
3 * Copyright (C) 2014 Jay Dolan <jay@jaydolan.com>
4 *
5 * This software is provided 'as-is', without any express or implied
6 * warranty. In no event will the authors be held liable for any damages
7 * arising from the use of this software.
8 *
9 * Permission is granted to anyone to use this software for any purpose,
10 * including commercial applications, and to alter it and redistribute it
11 * freely, subject to the following restrictions:
12 *
13 * 1. The origin of this software must not be misrepresented; you must not
14 * claim that you wrote the original software. If you use this software
15 * in a product, an acknowledgment in the product documentation would be
16 * appreciated but is not required.
17 *
18 * 2. Altered source versions must be plainly marked as such, and must not be
19 * misrepresented as being the original software.
20 *
21 * 3. This notice may not be removed or altered from any source distribution.
22 */
23
24#include <assert.h>
25#include <stdarg.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <time.h>
30
31#include "Config.h"
32
33#if HAVE_UNISTD_H
34#include <unistd.h>
35#endif
36
37#include "Log.h"
38
39#define _Class _Log
40
41#pragma mark - Object
42
46static void dealloc(Object *self) {
47
48 Log *this = (Log *) self;
49
50 if (!isatty(fileno(this->file))) {
51 const int err = fclose(this->file);
52 assert(err == 0);
53 }
54
55 free(this->name);
56
57 super(Object, self, dealloc);
58}
59
60#pragma mark - Log
61
66static void debug(const Log *self, const char *fmt, ...) {
67
68 va_list args;
69 va_start(args, fmt);
70
71 $(self, log, LogLevelDebug, fmt, args);
72
73 va_end(args);
74}
75
80static void error(const Log *self, const char *fmt, ...) {
81
82 va_list args;
83 va_start(args, fmt);
84
85 $(self, log, LogLevelError, fmt, args);
86
87 va_end(args);
88}
89
94static void fatal(const Log *self, const char *fmt, ...) {
95
96 va_list args;
97 va_start(args, fmt);
98
99 $(self, log, LogLevelFatal, fmt, args);
100
101 va_end(args);
102}
103
108static void flush(const Log *self) {
109
110 assert(self->file);
111 fflush(self->file);
112}
113
118static void info(const Log *self, const char *fmt, ...) {
119
120 va_list args;
121 va_start(args, fmt);
122
123 $(self, log, LogLevelInfo, fmt, args);
124
125 va_end(args);
126}
127
132static Log *init(Log *self) {
133
134 return $(self, initWithName, NULL);
135}
136
141static Log *initWithName(Log *self, const char *name) {
142
143 self = (Log *) super(Object, self, init);
144 if (self) {
145 self->name = strdup(name ?: "default");
146 self->level = LogLevelInfo;
148 self->file = stdout;
149 }
150
151 return self;
152}
153
158static void _log(const Log *self, LogLevel level, const char *fmt, va_list args) {
159
160 const char *levels[] = { "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" };
161 assert(level < lengthof(levels));
162
163 if (level < self->level) {
164 return;
165 }
166
167 assert(self->file);
168
169 const time_t date = time(NULL);
170 const struct tm *localDate = localtime(&date);
171
172 char buffer[128];
173 strftime(buffer, sizeof(buffer), self->format, localDate);
174
175 char *c = buffer;
176 while (*c) {
177
178 if (*c == '%') {
179 _Bool token = true;
180
181 if (*(c + 1) == 'n') {
182 fputs(self->name, self->file);
183 } else if (*(c + 1) == 'l') {
184 fputs(levels[level], self->file);
185 } else if (*(c + 1) == 'm') {
186 vfprintf(self->file, fmt, args);
187 } else {
188 token = false;
189 }
190
191 if (token) {
192 c++;
193 c++;
194 continue;
195 }
196 }
197
198 fputc(*c, self->file);
199 c++;
200 }
201
202 fputc('\n', self->file);
203 fflush(self->file);
204}
205
207
212static Log *sharedInstance(void) {
213
214 static Once once;
215
216 do_once(&once, {
218 });
219
220 return _sharedInstance;
221}
222
227static void trace(const Log *self, const char *fmt, ...) {
228
229 va_list args;
230 va_start(args, fmt);
231
232 $(self, log, LogLevelTrace, fmt, args);
233
234 va_end(args);
235}
236
241static void warn(const Log *self, const char *fmt, ...) {
242
243 va_list args;
244 va_start(args, fmt);
245
246 $(self, log, LogLevelWarn, fmt, args);
247
248 va_end(args);
249}
250
251#pragma mark - Class lifecycle
252
256static void initialize(Class *clazz) {
257
258 ((ObjectInterface *) clazz->interface)->dealloc = dealloc;
259
260 ((LogInterface *) clazz->interface)->debug = debug;
261 ((LogInterface *) clazz->interface)->error = error;
262 ((LogInterface *) clazz->interface)->fatal = fatal;
263 ((LogInterface *) clazz->interface)->flush = flush;
264 ((LogInterface *) clazz->interface)->info = info;
265 ((LogInterface *) clazz->interface)->init = init;
266 ((LogInterface *) clazz->interface)->initWithName = initWithName;
267 ((LogInterface *) clazz->interface)->log = _log;
268 ((LogInterface *) clazz->interface)->trace = trace;
269 ((LogInterface *) clazz->interface)->sharedInstance = sharedInstance;
270 ((LogInterface *) clazz->interface)->warn = warn;
271}
272
276static void destroy(Class *clazz) {
277
279}
280
285Class *_Log(void) {
286 static Class *clazz;
287 static Once once;
288
289 do_once(&once, {
290 clazz = _initialize(&(const ClassDef) {
291 .name = "Log",
292 .superclass = _Object(),
293 .instanceSize = sizeof(Log),
294 .interfaceOffset = offsetof(Log, interface),
295 .interfaceSize = sizeof(LogInterface),
297 .destroy = destroy,
298 });
299 });
300
301 return clazz;
302}
303
304#undef _Class
ident release(ident obj)
Atomically decrement the given Object's reference count. If the resulting reference count is 0,...
Definition: Class.c:196
Class * _initialize(const ClassDef *def)
Initializes the given Class.
Definition: Class.c:91
#define alloc(type)
Allocate and initialize and instance of type.
Definition: Class.h:159
#define super(type, obj, method,...)
static void destroy(Class *clazz)
Definition: Log.c:276
static void _log(const Log *self, LogLevel level, const char *fmt, va_list args)
Definition: Log.c:158
static void initialize(Class *clazz)
Definition: Log.c:256
static Log * _sharedInstance
Definition: Log.c:206
A Log4J-inspired log appender.
#define LOG_FORMAT_DEFAULT
The default Log format.
Definition: Log.h:52
LogLevel
Every Log has a threshold for generating messages.
Definition: Log.h:40
@ LogLevelFatal
Definition: Log.h:46
@ LogLevelError
Definition: Log.h:45
@ LogLevelTrace
Definition: Log.h:41
@ LogLevelWarn
Definition: Log.h:44
@ LogLevelDebug
Definition: Log.h:42
@ LogLevelInfo
Definition: Log.h:43
Immutable UTF-8 strings.
#define lengthof(array)
Definition: Types.h:145
long Once
The Once type.
Definition: Once.h:37
#define do_once(once, block)
Executes the given block at most one time.
Definition: Once.h:43
ClassDefs are passed to _initialize via an archetype to initialize a Class.
Definition: Class.h:41
The runtime representation of a Class.
Definition: Class.h:95
ident interface
The interface of the Class.
Definition: Class.h:105
Condition * init(Condition *self)
Initializes this Condition.
Definition: Condition.c:67
Date * date(void)
Returns a new Date with the current Time.
Definition: Date.c:98
A Log4J-inspired log appender.
Definition: Log.h:61
Log * initWithName(Log *self, const char *name)
Initializes this Log with the specified name.
Definition: Log.c:141
void warn(const Log *self, const char *fmt,...)
Log a warn message.
Definition: Log.c:241
void info(const Log *self, const char *fmt,...)
Log an info message.
Definition: Log.c:118
const char * format
The format string, defaults to LOG_FORMAT_DEFAULT. This string is post-processed after date substitut...
Definition: Log.h:82
Log * sharedInstance(void)
Definition: Log.c:212
void flush(const Log *self)
Flushes and pending output to this Log's file.
Definition: Log.c:108
void trace(const Log *self, const char *fmt,...)
Log a trace message.
Definition: Log.c:227
Class * _Log(void)
The Log archetype.
Definition: Log.c:285
FILE * file
The file descriptor (defaults to stdout).
Definition: Log.h:88
void fatal(const Log *self, const char *fmt,...)
Log a fatal message.
Definition: Log.c:94
void log(const Log *self, LogLevel level, const char *fmt, va_list args)
Write a message to the Log.
LogLevel level
The LogLevel of this Log.
Definition: Log.h:93
char * name
The name of this Log.
Definition: Log.h:98
void debug(const Log *self, const char *fmt,...)
Log a debug message.
Definition: Log.c:66
void error(const Log *self, const char *fmt,...)
Log an error message.
Definition: Log.c:80
Object is the root Class of The Objectively Class hierarchy.
Definition: Object.h:46
Class * _Object(void)
The Object archetype.
Definition: Object.c:136
void dealloc(Object *self)
Frees all resources held by this Object.
Definition: Array.c:50