2010-04-14 14 views
24

पर syslog पर क्लोग करें मैं एक सी ++ प्रोग्राम पर यूनिक्स पर काम करता हूं जो syslog को संदेश भेजता है।रीडायरेक्ट सी ++ std :: यूनिक्स

वर्तमान कोड syslog सिस्टम कॉल का उपयोग करता है जो printf की तरह काम करता है।

अब मैं उस उद्देश्य के लिए एक धारा का उपयोग करना पसंद करूंगा, आमतौर पर निर्मित std :: clog। लेकिन क्लोग केवल आउटपुट को रीडरर पर रीडायरेक्ट करता है, सिसलॉग के लिए नहीं और यह मेरे लिए बेकार है क्योंकि मैं अन्य प्रयोजनों के लिए stderr और stdout का भी उपयोग करता हूं।

मैं another answer कि यह rdbuf() का उपयोग कर एक फ़ाइल में पुनर्निर्देशित करने के लिए काफी आसान है में देखा है, लेकिन मुझे लगता है कि विधि syslog कॉल करने के लिए लागू करने के लिए openlog एक फ़ाइल हैंडलर वापस नहीं करता है के रूप में कोई रास्ता नहीं देख मैं एक टाई इस्तेमाल कर सकते हैं उस पर धारा।

क्या ऐसा करने का कोई और तरीका है? (यूनिक्स प्रोग्रामिंग के लिए बहुत बुनियादी दिखता है)?

संपादित करें: मैं ऐसे समाधान की तलाश में हूं जो बाहरी पुस्तकालय का उपयोग न करे। @Chris क्या प्रस्तावित कर रहा है एक अच्छी शुरुआत हो सकती है लेकिन स्वीकार्य उत्तर बनने के लिए अभी भी थोड़ा अस्पष्ट है।

संपादित करें: Boost.IOStreams का उपयोग ठीक है क्योंकि मेरी परियोजना पहले से ही बूस्ट का उपयोग करती है।

बाहरी पुस्तकालय के साथ लिंक करना संभव है लेकिन यह चिंता भी है क्योंकि यह जीपीएल कोड है। निर्भरता भी एक बोझ है क्योंकि वे अन्य घटकों के साथ संघर्ष कर सकते हैं, मेरे लिनक्स वितरण पर उपलब्ध नहीं हो सकते हैं, तीसरे पक्ष की बग, आदि पेश कर सकते हैं। यदि यह एकमात्र समाधान है तो मैं पूरी तरह से धाराओं से बचने पर विचार कर सकता हूं ... (एक करुणा)।

+0

सिर्फ एक संदेश स्ट्रिंग की तुलना में अधिक की आवश्यकता है, इसे 'त्रुटि स्तर' और इसी तरह की भी आवश्यकता होती है। मुझे यकीन नहीं है कि धाराओं का उपयोग करना संभव है या नहीं। शायद मैनिपुलेटर्स के साथ (बस 'std :: हेक्स' की तरह)? – ereOn

+2

उपलब्ध लॉगिंग पुस्तकालयों पर एक नज़र डालें। कई लोग आपको अपना संदेश लिखने के लिए अपने स्वयं के बैकएंड लिखने की अनुमति देंगे जहां भी आप उन्हें लिखना चाहते हैं। कई अंतर्निर्मित फ़िल्टरिंग और अन्य अच्छी सुविधाओं के साथ भी आते हैं। केवल कुछ हल्के वजन वाले लोग हैं जो केवल छोटे सामान के साथ आते हैं, लेकिन यदि आप चाहें तो उन्हें पा सकते हैं। मैं इसका उपयोग कर रहा हूं: http://www.templog.org/ यह केवल कुछ स्रोत फ़ाइल है, लगभग सभी शीर्षकों में, और संकलन-समय (समय-महत्वपूर्ण कोड के लिए) के साथ-साथ रन- पहर। लेकिन आप किसी और को पसंद कर सकते हैं। बस पहिया का पुन: आविष्कार न करें। – sbi

+0

यदि यह अंतर्निर्मित क्लोग का उपयोग करके नहीं किया जा सकता है, तो एक अन्य उपयोगकर्ता परिभाषित विशेष धारा लगभग उतनी ही अच्छी होगी, अगर मैनिपुलेटर्स या सदस्य फ़ंक्शन का उपयोग करके स्तर सेट किया गया है तो मुझे बहुत परवाह नहीं है। – kriss

उत्तर

27

मैं भी कुछ इस तरह सरल की जरूरत है, तो मैं बस यह एक साथ रखा:

log.h:

enum LogPriority { 
    kLogEmerg = LOG_EMERG, // system is unusable 
    kLogAlert = LOG_ALERT, // action must be taken immediately 
    kLogCrit = LOG_CRIT, // critical conditions 
    kLogErr  = LOG_ERR,  // error conditions 
    kLogWarning = LOG_WARNING, // warning conditions 
    kLogNotice = LOG_NOTICE, // normal, but significant, condition 
    kLogInfo = LOG_INFO, // informational message 
    kLogDebug = LOG_DEBUG // debug-level message 
}; 

std::ostream& operator<< (std::ostream& os, const LogPriority& log_priority); 

class Log : public std::basic_streambuf<char, std::char_traits<char> > { 
public: 
    explicit Log(std::string ident, int facility); 

protected: 
    int sync(); 
    int overflow(int c); 

private: 
    friend std::ostream& operator<< (std::ostream& os, const LogPriority& log_priority); 
    std::string buffer_; 
    int facility_; 
    int priority_; 
    char ident_[50]; 
}; 

log.cc:

Log::Log(std::string ident, int facility) { 
    facility_ = facility; 
    priority_ = LOG_DEBUG; 
    strncpy(ident_, ident.c_str(), sizeof(ident_)); 
    ident_[sizeof(ident_)-1] = '\0'; 

    openlog(ident_, LOG_PID, facility_); 
} 

int Log::sync() { 
    if (buffer_.length()) { 
     syslog(priority_, buffer_.c_str()); 
     buffer_.erase(); 
     priority_ = LOG_DEBUG; // default to debug for each message 
    } 
    return 0; 
} 

int Log::overflow(int c) { 
    if (c != EOF) { 
     buffer_ += static_cast<char>(c); 
    } else { 
     sync(); 
    } 
    return c; 
} 

std::ostream& operator<< (std::ostream& os, const LogPriority& log_priority) { 
    static_cast<Log *>(os.rdbuf())->priority_ = (int)log_priority; 
    return os; 
} 

main() में मैं रोकना प्रारंभ :

std::clog.rdbuf(new Log("foo", LOG_LOCAL0)); 

इसके बाद जब भी मैं प्रवेश करना चाहते हैं, यह आसान है:

std::clog << kLogNotice << "test log message" << std::endl; 

std::clog << "the default is debug level" << std::endl; 
+0

यह एक उत्कृष्ट है!धन्यवाद। – wollud1969

13

आप एक स्ट्रीमबफ को परिभाषित कर सकते हैं जो syslog को कॉल करता है। उदाहरण के लिए:

clog.rdbuf(new syslog_streambuf); 

कुछ और कार्यों आप शायद ओवरराइड करने के लिए होता है, यहाँ एक अच्छा reference to the streambuf api है:

// Pseudo-code 
class syslog_streambuf : public streambuf { 
private: 
    void internal_log(string& log) { 
     syslog(..., log, ...); 
    } 
public: 
    int sputc (char c) { 
     internal_log(...); 
    } 
    streamsize sputn (const char * s, streamsize n) { 
     internal_log(...); 
    } 
} 

तो आप बस रोकना रीडायरेक्ट करने के लिए निम्न लिखेंगे।

+3

यहां कार्य उदाहरण: http://pastebin.org/184922 – Basilevs

+1

मुझे लगता है कि इस विशिष्ट कार्य के लिए एक अलग ओस्ट्रीम ऑब्जेक्ट बनाने के लिए यह एक अच्छा अभ्यास है। सावधान रहें http://www.cplusplus.com/reference/iostream/ios_base/sync_with_stdio/। – Basilevs

+0

@ बेसिलव्स: नमूना के लिए धन्यवाद। यह अभी भी छोटा है और यह निश्चित रूप से ऐसी चीज है जिसे मैं ढूंढ रहा था। वैसे भी मुझे syslog के लिए कोड को अनुकूलित करने के लिए सॉकेट विशिष्ट सामान को सॉर्ट करना होगा ... ऐसा लगता है कि यह मुझे कम से कम दो दिन ले जाएगा :-( – kriss

2

मैं छोड़कर मेरी OStreamedLog वस्तुओं, एक मनमाना ostringstream वस्तु का उपयोग करने के लिए स्थापित कर रहे @Basilevs तरह का सुझाव दिया एक OStreamedLog वर्ग बहुत क्या ऊपर दिखाया गया था के समान है, बनाया गया है।

सबसे पहले, लॉग की कक्षा परिभाषा है, जो उपरोक्त वर्णित @eater और @Chris Kaminski के समान ही है।फिर, मेरे OStreamedLog वर्ग परिभाषा है, जो एक के लिए लॉग वस्तु शामिल हैं:

class OStreamedLog : public ostringstream 
{ 
    public: 
    OStreamedLog (const char* ident, int facility) 
    { 
      log = new Log (ident, facility); 
      (static_cast<ostream*>(this))->rdbuf (log); 
    } 
    private: 
    Log* log; 
}; 

अब, जब आप लॉग इन करने की जरूरत है, सिर्फ फोन:

OStreamedLog someLog ("MyOwnProgramThatNeedsLogging", LOG_LOCAL1); 
someLog << "Log testing" << endl; 
someLog << LOG_ERR << "some other error log" << endl; 
बेशक

, आप में पूरी लॉग परिभाषा पतन सकता है आपके OStreamedLog क्लास, लेकिन हो सकता है कि आप अपने बेस लॉग ऑब्जेक्ट में अन्य चीजें करना चाहें और विभिन्न प्रकार के लॉग को अलग करने के लिए उपरोक्त रैपर का उपयोग करें। उदाहरण के लिए आप मानव-पठनीय डायग्नोस्टिक लॉग (ASCII पाठ के रूप में भेजे गए), बाइनरी लॉग (बाद में प्रसंस्करण के लिए) या एक टीएलएस-स्ट्रीमिंग लॉग (उदाहरण के लिए उत्तरबाउंड सर्वर पर) हो सकते हैं।

3

ईटर द्वारा प्रेरित भाग में एक और संस्करण। यह std :: clog per se को रीडायरेक्ट नहीं करता है, लेकिन परिचित स्ट्रीम वाक्यविन्यास का उपयोग करता है।

#ifndef SYSLOG_HPP 
#define SYSLOG_HPP 

#include <ostream> 
#include <streambuf> 
#include <string> 

#include <syslog.h> 

namespace log 
{ 

enum level 
{ 
    emergency = LOG_EMERG, 
    alert  = LOG_ALERT, 
    critical = LOG_CRIT, 
    error  = LOG_ERR, 
    warning = LOG_WARNING, 
    notice = LOG_NOTICE, 
    info  = LOG_INFO, 
    debug  = LOG_DEBUG, 
}; 

enum type 
{ 
    auth = LOG_AUTH, 
    cron = LOG_CRON, 
    daemon = LOG_DAEMON, 
    local0 = LOG_LOCAL0, 
    local1 = LOG_LOCAL1, 
    local2 = LOG_LOCAL2, 
    local3 = LOG_LOCAL3, 
    local4 = LOG_LOCAL4, 
    local5 = LOG_LOCAL5, 
    local6 = LOG_LOCAL6, 
    local7 = LOG_LOCAL7, 
    print = LOG_LPR, 
    mail = LOG_MAIL, 
    news = LOG_NEWS, 
    user = LOG_USER, 
    uucp = LOG_UUCP, 
}; 

} 

class syslog_stream; 

class syslog_streambuf: public std::basic_streambuf<char> 
{ 
public: 
    explicit syslog_streambuf(const std::string& name, log::type type): 
     std::basic_streambuf<char>() 
    { 
     openlog(name.size() ? name.data() : nullptr, LOG_PID, type); 
    } 
    ~syslog_streambuf() override { closelog(); } 

protected: 
    int_type overflow(int_type c = traits_type::eof()) override 
    { 
     if(traits_type::eq_int_type(c, traits_type::eof())) 
      sync(); 
     else buffer += traits_type::to_char_type(c); 

     return c; 
    } 

    int sync() override 
    { 
     if(buffer.size()) 
     { 
      syslog(level, "%s", buffer.data()); 

      buffer.clear(); 
      level = ini_level; 
     } 
     return 0; 
    } 

    friend class syslog_stream; 
    void set_level(log::level new_level) noexcept { level = new_level; } 

private: 
    static constexpr log::level ini_level = log::info; 
    log::level level = ini_level; 

    std::string buffer; 
}; 

class syslog_stream: public std::basic_ostream<char> 
{ 
public: 
    explicit syslog_stream(const std::string& name = std::string(), log::type type = log::user): 
     std::basic_ostream<char>(&streambuf), 
     streambuf(name, type) 
    { } 

    syslog_stream& operator<<(log::level level) noexcept 
    { 
     streambuf.set_level(level); 
     return (*this); 
    } 

private: 
    syslog_streambuf streambuf; 
}; 

#endif // SYSLOG_HPP 

इसका इस्तेमाल करने के लिए आपको कुछ कर सकते हैं की तरह: syslog

syslog_stream clog; 

clog << "Hello, world!" << std::endl; 
clog << log::emergency << "foo" << "bar" << "baz" << 42 << std::endl; 
संबंधित मुद्दे