2011-10-25 19 views
5

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

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

ऐसे रैपर के डिजाइन के लिए कोई सुझाव?

संपादित करें: इस रैपर में मेरे पास एक विशेषता घटक टैगिंग है। मैं चाहता हूं कि मेरी एल्गोरिदम कक्षा में "एक्स:" अपनी लॉग लाइनों से आगे दिखाई दे, और मेरे प्रबंधक वर्ग को "वाई:" दिखाई दे। इन टैग को अंडरलिंग लॉग पर कैसे प्रसारित करें और घटक टैग नामकरण तंत्र कैसे बनाएं, यहां एक प्रमुख डिज़ाइन प्रश्न है।

+2

क्या आपको * वास्तव में * एक रैपर चाहिए? खुद से पूछो। क्या वास्तव में संभावना है कि आप अपने लॉगर (कई बार, शायद) स्विच करने जा रहे हैं या आप एकाधिक लॉगिंग फ्रेमवर्क का उपयोग करेंगे? एक रैपर लिखना संसाधन (समय) लेता है, और यदि आपको * वास्तव में * रैपर की आवश्यकता नहीं है, तो उन्हें अन्य चीजों में रखा जा सकता है। – Xeo

+0

धन्यवाद, आप भरोसा कर सकते हैं कि मैं वास्तव में करता हूं। सादगी के लिए मैं टैगिंग फीचर के साथ लॉग के एक बहुत ही अलग संस्करण के लिए बसने के लिए तैयार हूं। – Leo

उत्तर

2

आपकी सर्वश्रेष्ठ शर्त इंटरफ़ेस को यथासंभव सरल बनाना है। लॉगिंग वास्तव में लागू होने के तरीके से लॉगिंग उपयोगकर्ता के इंटरफ़ेस को पूरी तरह से अलग करें।

क्रॉस-कटिंग चिंताओं को हमेशा बनाए रखने के लिए महंगी होती है, इसलिए चीजों को और अधिक जटिल बनाने से आपको जीवन से नफरत होगी।

void logDebug(const std::string &msg); 
void logWarning(const std::string &msg); 
void logError(const std::string &msg); 

वे जोड़ सकते हैं या किसी भी अधिक संदर्भ को निर्दिष्ट नहीं करना चाहिए:

कुछ पुस्तकालय केवल कुछ इस तरह सरल चाहता है। कोई भी जानकारी का उपयोग किसी भी तरह से नहीं कर सकता है, इसलिए इसे डिज़ाइन पर न करें।

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

यह आपके लॉगिंग कार्यान्वयन को मजबूर नहीं करता है (या यहां तक ​​कि लॉगिंग कार्यान्वयन इंटरफ़ेस भी अनुरूप है!) ताकि आप इसे किसी भी रूप में बदल सकें।

अद्यतन:

जहां तक ​​टैगिंग के रूप में, कि एक उच्च स्तर चिंता का विषय है। मैं अनुमान लगाने जा रहा हूं कि यह लॉग में नहीं है, लेकिन यह न तो यहां और न ही वहां है।

इसे लॉगिंग संदेश विनिर्देश से बाहर रखें। निम्न स्तर के कोड को एक उड़ान ट्रक नहीं देना चाहिए जो आप या आपका प्रबंधक है।

मुझे नहीं पता कि आप अपने उदाहरण में X या Y निर्दिष्ट करते हैं। आप यह कैसे करते हैं जो वर्णन हमें दिया गया है उससे वास्तव में स्पष्ट नहीं है। मैं सिर्फ प्रदर्शन के लिए एक स्ट्रिंग का उपयोग करने जा रहा हूं, लेकिन यदि संभव हो तो आपको इसे किसी प्रकार के सुरक्षित से बदलना चाहिए।

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

void setLoggingContext("X:"); 

यदि यह अमूर्तता के विभिन्न स्तरों पर परिवर्तन करता है, तो मैं एक स्टैक आधारित आरएआईआई कार्यान्वयन पर विचार करता हूं।

LoggingTag tag("X:"); 

मुझे यकीन नहीं है कि परिदृश्य में आपकी आवश्यकताएं क्या हैं जब अलग-अलग स्टैक फ्रेम अलग-अलग मानों में गुज़रते हैं। मैं देख सकता था कि स्टैक के शीर्ष या निचले हिस्से में अलग-अलग उपयोग मामलों के लिए उचित होगा।

void foo() { 
    LoggingTag tag("X:"); 
    logWarning("foo"); 
    bar(); 
    baz(); 
} 

void bar() { 
    LoggingTag tag("Y:"); 
    logWarning("bar"); 
    baz(); 
} 

void baz() { 
    logWarning("baz"); 
} 

किसी भी तरह से यह लॉग को संदेश जोड़ने के तरीके को प्रभावित नहीं करेगा। baz फ़ंक्शन में LoggingTag निर्दिष्ट करने का संदर्भ नहीं है। यह बहुत महत्वपूर्ण है कि logWarning का उपयोग इस कारण से टैग के बारे में नहीं पता है।

यदि आप किसी प्रकार के आधार पर टैग करना चाहते हैं, तो आप इस तरह कुछ सरल कर सकते हैं।

struct LoggingTag { 
    LoggingTag(const std::string &tag_) : tag(tag_) {} 
    template<typename T> 
    static LoggingTag ByType() { 
     return LoggingTag(typeid(T).name()); 
    } 
    std::string tag; 
}; 

void foo() { 
    LoggingTag tag = LogginTag::ByType<int>(); 
} 

यह नहीं होगा बल किसी typeid(T).name() का उपयोग अगर वे नहीं करना चाहता था, लेकिन आप सुविधा दे दी है।

+0

एक चिंता मुझे अलग-अलग घटक टैगिंग के लिए जिम्मेदार है। – Leo

+0

मेरे मन में यह वाक्यविन्यास था: लॉग लॉग = GetLogger (MyClassName); log.Warn (...)। मुझे यकीन नहीं है कि MyClassName क्या होना चाहिए, अगर यह एक स्ट्रिंग है, तो मैं इसे कहां से प्राप्त करूं? यदि कक्षा के नाम को स्ट्रिंग में परिवर्तित करने के लिए कुछ चाल है, तो यह कैसे किया जा सकता है? – Leo

+0

@ user991339 मुझे समझ में नहीं आता कि आप क्या पूछ रहे हैं। क्या आप एक प्रकार से लॉग इन करने की कोशिश कर रहे हैं? –

1

मैं इस दृष्टिकोण की तरह है:

class Log { 
public: 
    virtual logString(const std::string&)=0; 
}; 

template <typename T> 
Log& operator<<(Log& logger, const T& object) { 
     std::stringstream converter; 
     converter << object; 
     logger.logString(converter.str()); 
     return logger; 
} 

सरल और त्वरित! आपको बस लॉगस्ट्रिंग विधि को पुन: कार्यान्वित करना है ...

+0

यह एक अच्छा विचार है। क्या आप टैगिंग सुविधा को लागू करने का एक तरीका सुझा सकते हैं? – Leo

+0

@CatPlusPlus यह टेम्पलेट्स का उपयोग करने के लिए आसानी से प्रभावशाली है ... –

+0

@ user991339 मैं लॉगर में एक टैग विशेषता जोड़ूंगा और एक बॉल को शुरू करने के लिए एक पंक्ति को इंगित करता हूं ताकि पहले लॉग पर टैग टैग स्टैंप हो। आप एंडल केस के लिए ऑपरेटर << विशेषज्ञ कर सकते हैं ताकि आप जान सकें कि अगला इनपुट लाइन की शुरुआत है। –

0

zf_log लाइब्रेरी पर एक नज़र डालें। यह बहुत छोटा है (~ 2000k लाइनें, ~ 10KB संकलित होने पर) और तेज़ (README.md में तुलना तालिका देखें)। यह रैपर के रूप में वर्णन करने के बहुत करीब है। यह आपको एक अमूर्त एपीआई देता है जिसे आप अपने प्रोजेक्ट में उपयोग कर सकते हैं और यह निर्दिष्ट करने की अनुमति देता है कि वास्तविक लॉगिंग कार्यान्वयन का उपयोग कैसे किया जाए। custom_output.c उदाहरण देखें जहां आउटसोर्स सुविधा के रूप में syslog का उपयोग किया जाता है। इस लाइब्रेरी का उपयोग करने वाले अन्य कोड के साथ संघर्ष में आने के जोखिम के बिना पुस्तकालयों के अंदर भी निजी तौर पर इसका इस्तेमाल किया जा सकता है (ZF_LOG_LIBRARY_PREFIX अधिक जानकारी के लिए परिभाषित करें)। भले ही यह ठीक नहीं है कि आप क्या खोज रहे हैं, मुझे लगता है कि यह आपके रैपर चीज़ के लिए एक अच्छा उदाहरण हो सकता है।

संबंधित मुद्दे