2009-07-16 13 views
7

मैं एक सी ++ साझा लाइब्रेरी लिख रहा हूं जिसका उद्देश्य अन्य लाइब्रेरी या निष्पादन योग्य द्वारा उपयोग किया जाना है। मेरी लाइब्रेरी में जेनेरिक लॉगिंग जोड़ने का सबसे अच्छा तरीका क्या है? आदर्श रूप से मैं पुस्तकालय के उपयोगकर्ता द्वारा चुने गए कार्यक्षमता को लॉगिंग करने के लिए अपनी लाइब्रेरी को अनुकूलित करना चाहता हूं। मान लीजिए मैं अपने पुस्तकालयसी ++ साझा लाइब्रेरी में जेनेरिक लॉगिंग समर्थन जोड़ना

class A { 
    public: 
    void method(string param1, int param2); 
} 

void A::method(string param1, int param2){ 
    /* i want to log values of param1 and param2, 
    but actual logging method must be defined outside of my library. 
    Maybe some kind of macro should help here. */ 
    /*e.g.*/ GENERICLOG_DEBUG("param1=" + param1+ " param2="+param1); 
    /*if so, what that macro body should look like ? */ 
} 

मैं अपने पुस्तकालय किसी भी log4XXX विशिष्ट API से बंधा बनाने के लिए नहीं करना चाहती में एक वर्ग है।

उत्तर

8

आप लाइब्रेरी की उपयोगकर्ता उनके प्रवेश में एक एडाप्टर के साथ अपने पुस्तकालय प्रदान करने के लिए अनुमति देने के लिए एक कॉलबैक तंत्र प्रदान कर सकते हैं।

यानी, आपकी पुस्तकालय में एक सार प्रवेश इंटरफ़ेस वर्ग, जैसे प्रदान करते हैं: के साथ एक लॉगर regster को

class Logger 
{ 
public: 
    virtual ~Logger() {} 
    virtual void log (const std::string& message) = 0; 
}; 

और एक वर्ग:

class Log 
{ 
private: 
    static Logger* logger_; 
public: 
    static void registerLogger (Logger& logger) 
    { logger_ = &logger; } 

    static void log (const std::string& message) 
    { if (logger_ != 0) logger_->log (message); } 
}; 

आपका पुस्तकालय तो की तरह कुछ के साथ लॉग:

Log::log ("My log message"); 

आपकी लाइब्रेरी का उपयोग करने वाले एप्लिकेशन को लॉगर का कार्यान्वयन प्रदान करना चाहिए (अर्थात। एक ठोस उपclass) और इसे अपने लॉग वर्ग के साथ पंजीकृत करें। उनके लॉगर इत्यादि लॉगिंग को कार्यान्वित करेंगे क्योंकि वे फिट दिखाई देते हैं।

यह आपकी लाइब्रेरी को उन अनुप्रयोगों द्वारा उपयोग करने की अनुमति देता है जो विभिन्न लॉगिंग लाइब्रेरी का उपयोग करते हैं।

नोट करें उपरोक्त कोड मूल और अवांछित है। अभ्यास में आप लॉगिंग स्तर पैरामीटर, आदि शामिल करने के लिए लॉग विधियों को बदलना चाह सकते हैं।

+0

धन्यवाद, अच्छा समाधान! मैं डिफ़ॉल्ट libging (उदा। Syslog) भी प्रदान कर सकता हूं यदि मेरे lib में कोई उपयोगकर्ता-लॉगर पंजीकृत नहीं था। –

+0

हां। –

0

syslog - तो आप जो भी syslog सुविधा इसका उपयोग कर सकते हैं।

या उपयोगकर्ता को कॉलबैक निर्दिष्ट करने की अनुमति दें।

0

यदि आप मौजूदा लॉगिंग lib का उपयोग नहीं करना चाहते हैं, तो आप मैक्रोज़ का उपयोग करने का प्रयास कर सकते हैं। मैं आपकी खुद की lib प्रदान करने और प्रारूपण तंत्र जैसे printf के साथ मैक्रोज़ के साथ उपलब्ध कराने की सलाह दूंगा।

मैंने पहले ऐसा कुछ किया है। मैक्रो ने एक लॉग ऑब्जेक्ट कहा जो वास्तविक लॉगिंग को समाहित करता है जो प्लगइन के माध्यम से विस्तार करना संभव था।

लेकिन मुझे लगता है कि लॉग 4xxx द्वारा कुछ ऐसा ही किया जा चुका है, तो शायद इसे देखना अच्छा लगे।

 
#ifdef _MYAPI_IMPL 
#define MY_API __declspec(dllexport) 
#else 
#define MY_API __declspec(dllimport) 
#endif 

class MY_API Log 
{ 
public: 
    enum Level {Error, Warning, Info, Debug}; 
    Log(Level level, const char* file, int line); 
    void operator()(const char* Format, ...); 
private: 
     const char* m_file; 
     Level m_level; 
     int m_line; 
}; 

#define __LOG(lvl) (Log(lvl, __FILE__, __LINE__)) 

#define LOG_ERR __LOG(Log::Error) 
#define LOG_WRN __LOG(Log::Warning) 
#define LOG_INF __LOG(Log::Info) 
#define LOG_DBG __LOG(Log::Debug) 

class My_API Logger 
{ 
public: 
    virtual void log(const char* message)=0; 
}; 

class MY_API LoggerManager 
{ 
private: 
    static LoggerManager* s_inst; 
    LoggerManager() {} 
     virtual ~LoggerManager() {} 
public: 
    static LoggerManager* Instance(); 
    static void Clean(); 
    addLogger(Logger* newLogger, Log::Level minlevel = Log::Info); 
     log(const char* file, int line, Log::Level level, const char* message); 
}; 

CPP::

 

Log::Log(Level level, const char* file, int line) 
: m_file(file), m_level(level), m_line(line) 
{ 
} 

void Log::operator()(const char* format, ...) 
{ 
    va_list va; 
    va_start(va, format); 
    char message[LENGTH+1]={0}; 

    _vsnprintf(message, LENGTH, format, va); 

    va_end(va); 

    LoggerManager::Instance()->log(m_file, m_line, m_level, message); 


}; 

अन्य libs और exe में सक्षम होना चाहिए

यहाँ एक प्रस्ताव (खेद परीक्षण करने के लिए कोई समय नहीं, मुझे आशा है कि यह काम करता है)

शीर्षक है इस तरह बुलाओ। उन्हें सिर्फ .h और lib के साथ लिंक शामिल करना होगा।

 
LOG_INF("Hello %s!", "world"); 

अद्यतन: मैंने लॉगिंग तंत्र के लिए आवश्यक स्पष्टीकरण जोड़ा है। एक तरीका है सिंगलटन का उपयोग करना और वास्तविक लॉगिंग के लिए उप-वर्गीकृत होने के लिए इंटरफ़ेस प्रदान करना।

मैक्रोज़ का उपयोग करने का लाभ यह है कि यह आपको लॉग के स्थान को प्राप्त करने की क्षमता देता है जो कुछ मामलों में बहुत ही रोचक जानकारी हो सकती है। जब आप सभी लॉगिंग तंत्र को लागू नहीं करना चाहते हैं तो मैक्रोज़ को नियमित प्रिंटफ़ में बदलना भी संभव है।

+0

शून्य लॉग :: ऑपरेटर() (कॉन्स char * प्रारूप, ...); इस फ़ंक्शन में, आप कैसे गारंटी दे सकते हैं कि संदेश की लंबाई "LENGTH" से ग्रेटर नहीं हो सकती है? – bbg

+0

मुझे लगता है कि आप सही हैं और आपको इस तरह के समाधान का उपयोग करने में इस बिंदु का ख्याल रखना चाहिए। – luc

1

आप Google-glog का उपयोग कर सकते हैं। मुझे इसका उपयोग करना अच्छा लगता है।

https://github.com/google/glog

यह प्रति फ़ाइल डिबग मूल्यों अन्य अच्छा सुविधाओं का भार का समर्थन करता है,, syslog में लॉग इन करें आप ईमेल कर सकते हैं, और। अपने पुस्तकालय में प्रवेश समारोह के

1

प्रचार प्रोटोटाइप:

extern void __cdecl UserLog(char* stText);

अपने पुस्तकालय में इसे लागू न करें। आपकी लाइब्रेरी का उपयोगकर्ता इस फ़ंक्शन को कार्यान्वित करना चाहिए और आपकी लाइब्रेरी उपयोगकर्ता के कार्यान्वयन का उपयोग करेगी।

उपयोगकर्ता की कार्यान्वयन ऐसा दिखाई दे सकता है (कि सिर्फ एक नमूना है):

void __cdecl UserLog(char* stText) 
{ 
    std::cout << stText << std::endl; 
}

कि वैध है कि अगर अपने पुस्तकालय स्थिर पुस्तकालय है।

अपने कोड में आप निम्नलिखित तरीके से उपयोग करने के लिए सक्षम हो जाएगा:

class A { 
    public: 
    void method(string param1, int param2); 
} 

void A::method(string param1, int param2){ 
    string formatted = str(boost::format("param1=%s param2=%d") % param1 % param2); 
    UserLog(formatted.c_str()); 
}
संबंधित मुद्दे