2010-12-06 7 views
3

私はロガーを作ってるんだと私は上に行くストリームのような出来事のいくつかの種類を持っていることを望む、理想的CLogger << "Testing, " << 1 << ",2,3\n";を行う代わりにCLogger->log("Testing, %i,2,3", 1);C++のメソッドへのカスタムストリーム?

私の質問は、私はこれを行うだろうかありますか?私はファイルを書くことを含む私自身の方法を使いたいので、stdoutへのストリームを直接作成したくありません。私はメソッドに現在のストリームバッファをフラッシュする特定の構造体でオーバーロードを考慮しましたが、私は奇妙な種類のCLogger << flush << "Test!\n";をしなければならないでしょう。

誰でもこの方法を知っていますか?

答えて

12

必要なものがすべて特定のログメッセージをファイルに転送する場合は、std::ofstreamと考えていますか?

それ以外の場合、私はログのクラスをstd::ostreamから派生したいので、ストリームの良さをすべて得ます。このトリックは、関連するすべてのアプリケーション固有のコードを関連するstreambufクラスに入れることです。考えてみましょう:

#include <iostream> 
#include <sstream> 

class CLogger : public std::ostream { 
private: 
    class CLogBuf : public std::stringbuf { 
    private: 
     // or whatever you need for your application 
     std::string m_marker; 
    public: 
     CLogBuf(const std::string& marker) : m_marker(marker) { } 
     ~CLogBuf() { pubsync(); } 
     int sync() { 
      std::cout << m_marker << ": " << str(); 
      str(""); 
      return std::cout?0:-1; 
     } 

    }; 

public: 
    // Other constructors could specify filename, etc 
    // just remember to pass whatever you need to CLogBuf 
    CLogger(const std::string& marker) : std::ostream(new CLogBuf(marker)) {} 
    ~CLogger() { delete rdbuf(); } 
}; 

int main() 
{ 
    CLogger hi("hello"); 
    CLogger bye("goodbye"); 

    hi << "hello, world" << std::endl; 
    hi << "Oops, forgot to flush.\n"; 
    bye << "goodbye, cruel world\n" << std::flush; 
    bye << "Cough, cough.\n"; 
} 

注:

  • CLoggerコンストラクタは、あなたが使用する必要がどのようなパラメータ取ることができます - ファイル名、出力言語、基本的なログデータへのポインタ、何でも。データをCLogBufクラスに渡すだけです。
  • CLogBufのsync()は、std :: flushに対する応答として自動的に呼び出されます。
+0

ありがとうございます!これはまさに私が必要としていたものです! – Jookia

+0

@Robᵩ - 関数sync()からの戻り値を見逃しませんか? – Uri

+1

@Uri-Oops。はい。気づいてくれてありがとう。一定。 –

6

operator <<をチェックしてください。これは、STLのストリームが過負荷になっていることを確認します。

class CLogger 
{ 
public: 
    CLogger& operator << (const std::string& _rhs) 
    { 
     // work with it here 
     return *this; 
    }; // eo operator << 
}; // eo class CLogger 

EDIT:

がどのようにのstd :: ostreamには、さまざまな種類のoperator <<オーバーロード概説し、このページを参照してください:operator<<()機能のすべては、クラスostream上で定義されている

http://www.cplusplus.com/reference/iostream/ostream/operator%3C%3C/

+0

私は最初の投稿を明確にしました。私はフォーマットしたいと思います。 – Jookia

1

を、そのメソッドを継承して実装することができます。

+1

私は彼がostreamを全く使っていないと思っています。私は彼がストリームのような行動を求めていると思います。 –

+0

右 - 彼がostreamから継承するべきであることを示唆し、インターフェースを実装して、それを自分で実装するのではなく、誰もが自由に入手できるようにする。 –

+0

ああ!そうですか。いい答えだ! :) –

2

オペレータ< <を指定してプロキシオブジェクトを実装し、返されたプロキシオブジェクトに所有権マーカーを渡します。所有権マーカーのあるオブジェクトが消滅すると、ストリームをフラッシュします。

これを行う簡単な方法は、プロキシのauto_ptrにostringstreamをラップし、プロキシのdtorでauto_ptrがnullでないときにロガーにフラッシュすることです。

これはostreamで可能なフォーマットを提供しますが、あなたのロガーへの呼び出しは1つだけですが、これは本当の問題だと思っていました。このような何かの

思う:私はちょうど下記のこののコピー&ペースト、私の現在の実装に行くよ

class CLoggingProxy 
{ 
public: 
    template <class T> 
    CLoggingProxy operator<<(const T& rhs) 
    { 
    if (stream) 
     *stream << rhs; 
    return *this; 
    } 

    ~CLoggingProxy() 
    { 
    if (stream) 
     logger->log(stream->str()); 
    } 

private: 
    std::auto_ptr<std::ostringstream> stream; 
    CLogger* logger; 

    friend class CLogger; 
    CLoggingProxy(CLogger* logger) // call this e.g. from the logger to "start" input 
    : stream(new std::ostringstream), logger(logger) {} 
}; 
+0

素晴らしい、私はそれを2度読んだ。今あなたが言ったことを理解することに! – Jookia

+0

明確にするためにいくつかのコードを追加しました。これは、演算子<<が左から右に評価されるので動作します。したがって、<< << << bをログします。 ((log << a)<< b)となる。現在のロギング・エントリの「所有権」が外側のブロックに順次渡されます。最後に、最後の一時オブジェクトが範囲外になったときにエントリが送信されます。 – ltjax

0

は、それはあなたが必要なすべてのない(とstd::endlなどのようなものを処理します)。 AMBROSIA_DEBUGはデバッグビルドで定義されたマクロなので、理論的には、リリースビルドではこの出力クラスの呼び出しをすべて削除する必要があります(確認はしていませんが、論理オーバーヘッドは最小限に抑えられています)。 。あなたは、ランタイム・パラメータに応じて、あなたのコードに手でデバッグメッセージをフィルタリングすることが可能になる鉱山debugLevelの少しの追加は、今のところそれはまた、各メッセージの前にスペースの同じ量を追加

// C++ includes 
#include <iostream> 
#include <string> 

typedef std::ostream& (*STRFUNC)(std::ostream&); 

#ifdef AMBROSIA_DEBUG 
    static int debugLevel; 
    const static int maxDebugLevel = 9; 
#endif 

class Debug 
{ 
public: 

    #ifdef AMBROSIA_DEBUG 
    Debug(const int level = 0) 
    : m_output(level <= debugLevel), 
     m_outputSpaces(true), 
     m_spaces(std::string(level, ' ')) 
    #else 
    Debug(const int) 
    #endif // AMBROSIA_DEBUG 
    {} 

    template<typename T> 
    #ifdef AMBROSIA_DEBUG 
    Debug& operator<<(const T &output) 
    { 
     if(m_output) 
     { 
      if(m_outputSpaces) 
      { 
       m_outputSpaces = false; 
       std::cerr << m_spaces; 
      } 
      std::cerr << output; 
     } 
    #else 
    Debug& operator<<(const T &) 
    { 
    #endif // AMBROSIA_DEBUG 
     return *this; 
    } 
    // for std::endl and other manipulators 
    typedef std::ostream& (*STRFUNC)(std::ostream&); 
    #ifdef AMBROSIA_DEBUG 
    Debug& operator<<(STRFUNC func) 
    { 
     if(m_output) 
      func(std::cerr); 
    #else 
    Debug& operator<<(STRFUNC) 
    { 
    #endif // AMBROSIA_DEBUG 
     return *this; 
    } 
private: 
#ifdef AMBROSIA_DEBUG 
    bool m_output; 
    bool m_outputSpaces; 
    std::string m_spaces; 
#endif // AMBROSIA_DEBUG 
}; 

使用例:

int main() 
{ 
    debugLevel = 9; // highest allowed in my app... 
    Debug(4) << "This message should have an indentation of 4 spaces." << endl; 
    Debug(8) << "This is a level 8 debug message.\n"; 
    return 0; 
} 
関連する問題