Log.hh 4.42 KB
Newer Older
Robert Menzel's avatar
Robert Menzel committed
1
2
3
4
5
////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2011, Computer Graphics Group RWTH Aachen University         //
// All rights reserved.                                                       //
////////////////////////////////////////////////////////////////////////////////

Robert Menzel's avatar
Robert Menzel committed
6
7
8
#ifndef ACGL_UTILS_LOG_HH
#define ACGL_UTILS_LOG_HH

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
/*
 * Some classes, typedefs and defines to create a simple logging system:
 *
 * Can be used excactly like std::cout
 *
 * message stream:   log()     << "foo " << "bar" << var << std::endl;
 * warning stream:   warning() << "memory low" << std::endl;
 * error stream:     error()   << "shader compile failed: " << getErrorMsg() << std::endl;
 * debug stream:     debug()   << "i = " << i << std::endl;
 *
 * Streams can get muted and unmuted at runtime:
 *  debug().mute();
 *  debug() << "you will never see me!" << std::endl;
 *  debug().unmute();
 *
 * The Application can create own streams and set own prefixes:
 *
 *  log<6>().setPrefix("app specific: ");
 *  log<6>() << "logging" << std::endl;
 *
 * If no prefix was set, the number will be used as a prefix:
 *
 *  log<11>() << "up to 11!" << std::endl;
 */

Robert Menzel's avatar
Robert Menzel committed
34
#include <ACGL/ACGL.hh>
Robert Menzel's avatar
Robert Menzel committed
35
36
37
38
39
40
41
42
43
44
45
46
#include <ACGL/Base/Singleton.hh>

#include <string>
#include <cstdarg>
#include <iostream>
#include <fstream>
#include <sstream>

namespace ACGL{
namespace Utils{

/*
47
 * The stream buffer is internally used in the CoutLikeStream (see below).
Robert Menzel's avatar
Robert Menzel committed
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
 */
class CoutLikeStreamBuffer : public std::basic_streambuf<char, std::char_traits<char> >
{
    typedef std::basic_streambuf<char, std::char_traits<char> > base_type;

public:
    CoutLikeStreamBuffer();

    ~CoutLikeStreamBuffer();

    void setPrefix( const std::string &_prefix );

private:

    //virtual std::streamsize xsputn(const base_type::char_type* s, std::streamsize n)
    //{
        // TODO: implement me for better performance
    //}

    virtual base_type::int_type overflow(base_type::int_type ch);

    // for each endl:
    virtual int sync();

private:
Robert Menzel's avatar
Robert Menzel committed
73
74
75
76
    char  *mBuffer;
	std::string mPrefix;
    size_t mBufferSize;    // how many bytes are used
    size_t mBufferMaxSize; // size of the buffer
Robert Menzel's avatar
Robert Menzel committed
77
78
79
80

    bool  mNewLineIsAboutToStart;
};

81
82
83
84
/*
 * This is the stream itself that behaves like an std::ostream with some custom
 * extensions (like adding the debug level prefix).
 */
Robert Menzel's avatar
Robert Menzel committed
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
template < unsigned int DEBUG_LEVEL >
class CoutLikeStream : public std::ostream, public Base::Singleton<CoutLikeStream<DEBUG_LEVEL> >
{
public:
    CoutLikeStream() : std::ostream( NULL ), mStreamBuffer(NULL) {
        mStreamBuffer = new CoutLikeStreamBuffer();
        switch (DEBUG_LEVEL) {
            case 0: mStreamBuffer->setPrefix("Debug:   ");
            break;
            case 1: mStreamBuffer->setPrefix("Message: ");
            break;
            case 2: mStreamBuffer->setPrefix("Warning: ");
            break;
            case 3: mStreamBuffer->setPrefix("Error:   ");
            break;
            default: {
                mStreamBuffer->setPrefix("> ");
                std::ostringstream streamName;

                streamName << DEBUG_LEVEL << ": ";
                mStreamBuffer->setPrefix( streamName.str() );
            }
        }

        unmute();
    }

    ~CoutLikeStream() {
        delete mStreamBuffer;
    }

    void setPrefix( const std::string &_prefix ) {
        if (mStreamBuffer) {
            mStreamBuffer->setPrefix(_prefix);
        }
    }
    void mute()   { rdbuf( NULL ); }
    void unmute() { rdbuf( mStreamBuffer ); }
private:
    CoutLikeStreamBuffer *mStreamBuffer;
};

127
128
129
/*
 * Defines the stream functions that should be used:
 */
Robert Menzel's avatar
Robert Menzel committed
130
131
132
133
134
inline CoutLikeStream<0>& debug()   { return (*CoutLikeStream<0>::the()); }
inline CoutLikeStream<1>& message() { return (*CoutLikeStream<1>::the()); }
inline CoutLikeStream<2>& warning() { return (*CoutLikeStream<2>::the()); }
inline CoutLikeStream<3>& error()   { return (*CoutLikeStream<3>::the()); }

135
136
137
138
139
140
141
/*
 * Generic streams: this way application specific streams can be created:
 */
template < unsigned int N >
inline CoutLikeStream<N>& log() { return (*CoutLikeStream<N>::the()); }

// alternative syntax
Robert Menzel's avatar
Robert Menzel committed
142
143
144
145
146
147
148
149
150
151
152
#define ACGL_DEBUG(STREAM)   ACGL::Utils::debug() << STREAM;
#define ACGL_MESSAGE(STREAM) ACGL::Utils::message() << STREAM;
#define ACGL_WARNING(STREAM) ACGL::Utils::warning() << STREAM;
#define ACGL_ERROR(STREAM)   ACGL::Utils::error() << STREAM;

#define ACGL_LOG(N,STREAM) ACGL::Utils::log<N>() << STREAM;

} // Utils
} // ACGL

#endif // ACGL_UTILS_LOG_HH