1/*
2 * Copyright 2017-2022, Andrew Lindesay <apl@lindesay.co.nz>.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
5#ifndef LOGGER_H
6#define LOGGER_H
7
8#include <String.h>
9#include <File.h>
10#include <Path.h>
11
12#include <ctype.h>
13#include <stdio.h>
14#include <stdlib.h>
15
16
17#define MILLIS_IN_DAY 86400000L
18
19#define HDLOGLEVELCHAR(L) ( \
20	L == LOG_LEVEL_INFO ? 'I' \
21	: L == LOG_LEVEL_DEBUG ? 'D' \
22	: L == LOG_LEVEL_TRACE ? 'T' \
23	: L == LOG_LEVEL_ERROR ? 'E' \
24	: '?')
25
26// These macros allow for standardized logging to be output.
27// The use of macros in this way means that the use of the log is concise where
28// it is used and also because the macro unwraps to a block contained with a
29// condition statement, if the log level is not sufficient to trigger the log
30// line then there is no computational cost to running over the log space.  This
31// is because the arguments will not be evaluated.  Avoiding all of the
32// conditional clauses in the code to prevent this otherwise would be
33// cumbersome.
34
35// The time element @<time> is presented in milliseconds on the current day.
36
37#define HDLOGPREFIX(L) printf("@%08" B_PRId64 " {%c} <t:%" B_PRIu32 "> ", \
38	((system_time() / 1000L) % MILLIS_IN_DAY), \
39	HDLOGLEVELCHAR(L), \
40	Logger::CurrentThreadIndicator() \
41);
42
43#define HDLOG(L, M...) do { if (Logger::IsLevelEnabled(L)) { \
44	HDLOGPREFIX(L) \
45	printf(M); \
46	putchar('\n'); \
47} } while (0)
48
49#define HDINFO(M...) HDLOG(LOG_LEVEL_INFO, M)
50#define HDDEBUG(M...) HDLOG(LOG_LEVEL_DEBUG, M)
51#define HDTRACE(M...) HDLOG(LOG_LEVEL_TRACE, M)
52#define HDERROR(M...) HDLOG(LOG_LEVEL_ERROR, M)
53
54#define HDFATAL(M...) do { \
55	printf("{!} (failed @ %s:%d) ", __FILE__, __LINE__); \
56	printf(M); \
57	putchar('\n'); \
58	exit(EXIT_FAILURE); \
59} while (0)
60
61typedef enum log_level {
62	LOG_LEVEL_OFF		= 1,
63	LOG_LEVEL_ERROR		= 2,
64	LOG_LEVEL_INFO		= 3,
65	LOG_LEVEL_DEBUG		= 4,
66	LOG_LEVEL_TRACE		= 5
67} log_level;
68
69
70class Logger {
71public:
72	static	log_level			Level();
73	static	void				SetLevel(log_level value);
74	static	bool				SetLevelByName(const char *name);
75
76	static	const char*			NameForLevel(log_level value);
77
78	static	bool				IsLevelEnabled(log_level value);
79	static	bool				IsInfoEnabled();
80	static	bool				IsDebugEnabled();
81	static	bool				IsTraceEnabled();
82
83	static	uint32				CurrentThreadIndicator();
84
85private:
86	static	log_level			fLevel;
87};
88
89
90#endif // LOGGER_H
91