आपकी सर्वश्रेष्ठ शर्त इंटरफ़ेस को यथासंभव सरल बनाना है। लॉगिंग वास्तव में लागू होने के तरीके से लॉगिंग उपयोगकर्ता के इंटरफ़ेस को पूरी तरह से अलग करें।
क्रॉस-कटिंग चिंताओं को हमेशा बनाए रखने के लिए महंगी होती है, इसलिए चीजों को और अधिक जटिल बनाने से आपको जीवन से नफरत होगी।
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()
का उपयोग अगर वे नहीं करना चाहता था, लेकिन आप सुविधा दे दी है।
क्या आपको * वास्तव में * एक रैपर चाहिए? खुद से पूछो। क्या वास्तव में संभावना है कि आप अपने लॉगर (कई बार, शायद) स्विच करने जा रहे हैं या आप एकाधिक लॉगिंग फ्रेमवर्क का उपयोग करेंगे? एक रैपर लिखना संसाधन (समय) लेता है, और यदि आपको * वास्तव में * रैपर की आवश्यकता नहीं है, तो उन्हें अन्य चीजों में रखा जा सकता है। – Xeo
धन्यवाद, आप भरोसा कर सकते हैं कि मैं वास्तव में करता हूं। सादगी के लिए मैं टैगिंग फीचर के साथ लॉग के एक बहुत ही अलग संस्करण के लिए बसने के लिए तैयार हूं। – Leo