aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/fstring.h1
-rw-r--r--src/logger.cpp123
-rw-r--r--src/logger.h112
-rw-r--r--src/tests/logger.cpp28
4 files changed, 264 insertions, 0 deletions
diff --git a/src/fstring.h b/src/fstring.h
index 9d88bd4..fe34804 100644
--- a/src/fstring.h
+++ b/src/fstring.h
@@ -128,6 +128,7 @@ namespace Bu
128 */ 128 */
129 void append( const chr *pData ) 129 void append( const chr *pData )
130 { 130 {
131 if( !pData ) return;
131 long nLen; 132 long nLen;
132 for( nLen = 0; pData[nLen] != (chr)0; nLen++ ); 133 for( nLen = 0; pData[nLen] != (chr)0; nLen++ );
133 if( nLen == 0 ) 134 if( nLen == 0 )
diff --git a/src/logger.cpp b/src/logger.cpp
new file mode 100644
index 0000000..848dfb1
--- /dev/null
+++ b/src/logger.cpp
@@ -0,0 +1,123 @@
1#include "bu/logger.h"
2#include <stdarg.h>
3#include <time.h>
4#include <stdio.h>
5
6Bu::Logger::Logger()
7{
8}
9
10Bu::Logger::~Logger()
11{
12}
13
14void Bu::Logger::log( int nLevel, const char *sFile, const char *sFunction, int nLine, const char *sFormat, ...)
15{
16 if( (nLevel&nLevelMask) == 0 )
17 return;
18
19 va_list ap;
20 va_start( ap, sFormat );
21 char *text;
22 vasprintf( &text, sFormat, ap );
23 va_end(ap);
24
25 time_t t = time(NULL);
26
27 char *line = NULL;
28 struct tm *pTime;
29 pTime = localtime( &t );
30 asprintf(
31 &line,
32 sLogFormat.getStr(),
33 pTime->tm_year+1900,
34 pTime->tm_mon+1,
35 pTime->tm_mday,
36 pTime->tm_hour,
37 pTime->tm_min,
38 pTime->tm_sec,
39 nLevel,
40 sFile,
41 nLine,
42 text,
43 sFunction
44 );
45 write( fileno(stdout), line, strlen(line) );
46 free( text );
47 free( line );
48}
49
50void Bu::Logger::setFormat( const Bu::FString &str )
51{
52 sLogFormat = "";
53
54 static char fmts[][4]={
55 {'y', 'd', '0', '1'},
56 {'m', 'd', '0', '2'},
57 {'d', 'd', '0', '3'},
58 {'h', 'd', '0', '4'},
59 {'M', 'd', '0', '5'},
60 {'s', 'd', '0', '6'},
61 {'L', 'd', '0', '7'},
62 {'f', 's', '0', '8'},
63 {'l', 'd', '0', '9'},
64 {'t', 's', '1', '0'},
65 {'F', 's', '1', '1'},
66 {'\0', '\0', '\0', '\0'},
67 };
68
69 for( const char *s = str.getStr(); *s; s++ )
70 {
71 if( *s == '%' )
72 {
73 sLogFormat += '%';
74 s++;
75 for( int l = 0;; l++ )
76 {
77 if( fmts[l][0] == '\0' )
78 {
79 sLogFormat += *s;
80 break;
81 }
82 else if( *s == fmts[l][0] )
83 {
84 sLogFormat += fmts[l][2];
85 sLogFormat += fmts[l][3];
86 sLogFormat += '$';
87 sLogFormat += fmts[l][1];
88 break;
89 }
90 }
91 }
92 else
93 {
94 sLogFormat += *s;
95 }
96 }
97 sLogFormat += '\n';
98
99 write( fileno(stdout), sLogFormat.getStr(), sLogFormat.getSize() );
100}
101
102void Bu::Logger::setMask( int n )
103{
104 nLevelMask = n;
105}
106
107void Bu::Logger::setLevel( int n )
108{
109 int j;
110 for( j = 31; j > 0; j-- )
111 {
112 if( (n&(1<<j)) )
113 {
114 for(; j >= 0; j-- )
115 {
116 n |= (1<<j);
117 }
118 nLevelMask = n;
119 return;
120 }
121 }
122}
123
diff --git a/src/logger.h b/src/logger.h
new file mode 100644
index 0000000..f8e1692
--- /dev/null
+++ b/src/logger.h
@@ -0,0 +1,112 @@
1#ifndef BU_LOGGER_H
2#define BU_LOGGER_H
3
4#include "bu/singleton.h"
5#include "bu/fstring.h"
6
7namespace Bu
8{
9 /**
10 * Simple logging facility. All output goes straight to stdout, unlike the
11 * old multi-log system. Generally we expect any program complex enough to
12 * want to use this will have other facilities for processing the logging
13 * output, but if we need it we can add other output methods.
14 *
15 * Currently implemented as a singleton to avoid clutter with globals, you
16 * generally never want to use the logging system directly, it's annoying.
17 * Instead use the handy macros lineLog, setLogMask, setLogFormat, and
18 * setLogLevel. They do all the real work for you.
19 *
20 * In the log format, you can specify extra information that will be written
21 * to the log with every message, and extras in printf style. Use %X flags
22 * where X is one of the following:
23 * - L - Logging level of the log message (not the current mask)
24 * - y - Full year
25 * - m - Month
26 * - d - Day of month
27 * - h - Hour (24-hour format)
28 * - M - Minutes
29 * - s - Seconds
30 * - f - Source file
31 * - l - Line number
32 * - F - function name
33 * - t - Text of message (usually important)
34 *
35 * You can include anything extra that you would like, a newline will always
36 * be added automatically, so no need to worry about that. You can also
37 * include any extra printf style formatting that you would like, for
38 * example: "%h:%02M:%02s" for the time 4:02:09 instead of 4:2:9.
39 *
40 * It's generally handy to create an enum of values you use as levels during
41 * program execution (such as error, warning, info, debug, etc). These
42 * levels should be treated as bitflags, and the most desirable messages,
43 * i.e. serious errors and the like should be low order (0x01), and the much
44 * less desirable messages, like debugging info, should be higher order
45 * (0xF0). During operation you can then set either an explicit mask,
46 * selecting just the levels that you would like to see printed, or set the
47 * mask using the setLevel helper function, which simulates verbosity
48 * levels, enabling every flag lower order than the highest order set bit
49 * passed. I.E. if you had the following enumerated levels:
50 *
51 *@code
52 enum {
53 logError = 0x01,
54 logWarning = 0x02,
55 logInfo = 0x04,
56 logDebug = 0x08
57 };
58 @endcode
59 * And you set the mask with setMask( logInfo ) the only messages you would
60 * see are the ones catagorized logInfo. However, if you used
61 * setLevel( logInfo ) then you would see logInfo, logWarning, and logError
62 * type messages, since they are lower order.
63 */
64 class Logger : public Bu::Singleton<Bu::Logger>
65 {
66 friend class Bu::Singleton<Bu::Logger>;
67 private:
68 Logger();
69 virtual ~Logger();
70
71 public:
72 void log( int nLevel, const char *sFile, const char *sFunction, int nLine, const char *sFormat, ...);
73
74 void setFormat( const Bu::FString &str );
75 void setMask( int n );
76 void setLevel( int n );
77
78 private:
79 Bu::FString sLogFormat;
80 int nLevelMask;
81 };
82}
83
84/**
85 * Use Bu::Logger to log a message at the given level and with the given message
86 * using printf style formatting, and include extra data such as the current
87 * file, line number, and function.
88 */
89#define lineLog( nLevel, sFrmt, ...) \
90 Bu::Logger::getInstance().log( nLevel, __FILE__, __PRETTY_FUNCTION__, __LINE__, sFrmt, ##__VA_ARGS__ )
91
92/**
93 * Set the Bu::Logger logging mask directly. See Bu::Logger::setMask for
94 * details.
95 */
96#define setLogMask( nLevel ) \
97 Bu::Logger::getInstance().setMask( nLevel )
98
99/**
100 * Set the Bu::Logger format. See Bu::Logger::setFormat for details.
101 */
102#define setLogFormat( sFrmt ) \
103 Bu::Logger::getInstance().setFormat( sFrmt )
104
105/**
106 * Set the Bu::Logger logging mask simulating levels. See Bu::Logger::setLevel
107 * for details.
108 */
109#define setLogLevel( nLevel ) \
110 Bu::Logger::getInstance().setLevel( nLevel )
111
112#endif
diff --git a/src/tests/logger.cpp b/src/tests/logger.cpp
new file mode 100644
index 0000000..a271443
--- /dev/null
+++ b/src/tests/logger.cpp
@@ -0,0 +1,28 @@
1#include "bu/logger.h"
2#include <errno.h>
3#include <stdlib.h>
4
5class Thing
6{
7 public:
8 Thing()
9 {
10 lineLog( 2, "Want a thing?");
11 }
12
13 void go( int i )
14 {
15 lineLog( 1, "GO!!!!");
16 }
17};
18
19int main()
20{
21 setLogLevel( 4 );
22 setLogFormat("%L: %y-%m-%d %h:%M:%s %f:%l:%F: %t");
23 lineLog( 5, "Hey, error: %s", strerror( errno ) );
24
25 Thing gh;
26 gh.go( 6);
27}
28