Log.hh 5.55 KB
Newer Older
1 2 3 4 5
/***********************************************************************
 * Copyright 2011-2012 Computer Graphics Group RWTH Aachen University. *
 * All rights reserved.                                                *
 * Distributed under the terms of the MIT License (see LICENSE.TXT).   *
 **********************************************************************/
Robert Menzel's avatar
Robert Menzel committed
6

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

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
/*
 * 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
35
#include <ACGL/ACGL.hh>
Robert Menzel's avatar
Robert Menzel committed
36 37 38 39 40 41 42 43
#include <ACGL/Base/Singleton.hh>

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

44 45 46 47 48
#ifdef __ANDROID__
#include <android/log.h>
#endif


Robert Menzel's avatar
Robert Menzel committed
49 50 51 52
namespace ACGL{
namespace Utils{

/*
53
 * The stream buffer is internally used in the CoutLikeStream (see below).
Robert Menzel's avatar
Robert Menzel committed
54 55 56 57 58 59 60 61 62 63 64
 */
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 );
65 66

    void setFilename( const std::string &_filename);
Robert Menzel's avatar
Robert Menzel committed
67 68 69 70 71 72 73 74 75 76 77 78
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();

79
    void mirrorToFile( const std::string &_token );
Robert Menzel's avatar
Robert Menzel committed
80
private:
Robert Menzel's avatar
Robert Menzel committed
81 82 83 84
    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
85 86

    bool  mNewLineIsAboutToStart;
87 88
    bool  mMirrorToFile;
    std::string mFilename;
89 90 91 92 93 94
    
#ifdef __ANDROID__
    android_LogPriority mAndroidPriority;
public:
    void setAndroidPriority( android_LogPriority _priority ) { mAndroidPriority = _priority; }
#endif
Robert Menzel's avatar
Robert Menzel committed
95 96
};

97 98 99 100
/*
 * 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
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
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() );
            }
        }
124 125 126 127 128 129 130 131 132
#ifdef __ANDROID__
        switch (DEBUG_LEVEL) {
            case 0: mStreamBuffer->setAndroidPriority( ANDROID_LOG_DEBUG); break;
            case 1: mStreamBuffer->setAndroidPriority( ANDROID_LOG_INFO); break;
            case 2: mStreamBuffer->setAndroidPriority( ANDROID_LOG_WARN); break;
            case 3: mStreamBuffer->setAndroidPriority( ANDROID_LOG_ERROR); break;
            default: mStreamBuffer->setAndroidPriority( ANDROID_LOG_UNKNOWN);
        }
#endif
Robert Menzel's avatar
Robert Menzel committed
133 134 135 136 137 138 139 140 141 142 143 144 145

        unmute();
    }

    ~CoutLikeStream() {
        delete mStreamBuffer;
    }

    void setPrefix( const std::string &_prefix ) {
        if (mStreamBuffer) {
            mStreamBuffer->setPrefix(_prefix);
        }
    }
146 147 148 149 150 151 152 153

    //! a filename of a text file to mirror all outputs into
    //! set a filename of "" to disable this
    void setFilename( const std::string &_filename ) {
        if (mStreamBuffer) {
            mStreamBuffer->setFilename(_filename);
        }
    }
Robert Menzel's avatar
Robert Menzel committed
154 155 156 157 158 159
    void mute()   { rdbuf( NULL ); }
    void unmute() { rdbuf( mStreamBuffer ); }
private:
    CoutLikeStreamBuffer *mStreamBuffer;
};

160 161 162
/*
 * Defines the stream functions that should be used:
 */
Robert Menzel's avatar
Robert Menzel committed
163 164 165 166 167
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()); }

168 169 170 171 172 173 174
/*
 * 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
175 176 177 178 179 180 181 182 183 184 185
#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