2009-02-17 14 views
8

मैं अपने सी # एप्लिकेशन में लॉगिंग या ट्रेसिंग जोड़ना चाहता हूं, लेकिन मैं नहीं चाहता कि स्ट्रिंग या गणना मूल्यों को स्वरूपित करने का ओवरहेड लॉग हो, यदि लॉग वर्बोजिटी स्तर इतना कम सेट किया गया है कि संदेश होगा लॉग इन नहीं किया गयासी # सशर्त लॉगिंग/ट्रेसिंग

#define VLOG(level,expr) if (level >= g_log.verbosity) { g_log.output << expr; } 

इस तरह उपयोग किया::

VLOG(5,"Expensive function call returns " << ExpensiveFunctionCall()); 

कैसे आप ऐसा करते

सी ++ में, आप मैक्रो कि सभी इस तरह क्रियान्वित किया जा रहा से कोड पाएगा परिभाषित करने के लिए पूर्वप्रक्रमक उपयोग कर सकते हैं सी # में?

मैं ट्रेस और डीबग सुविधाओं here समझा माइक्रोसॉफ्ट डॉक्स पढ़ा है, और वे दावा करते हैं कि #undef डीबग और #undef ट्रेस का उपयोग कर निष्पादन का उत्पादन से सभी अनुरेखण और डिबगिंग कोड निकालता है, लेकिन यह वास्तव में पूरे कॉल को दूर करता है ? मतलब, अगर मैं

System.Diagnostics.Trace.WriteLineIf(g_log.verbosity>=5,ExpensiveFunctionCall()); 

यदि मैं ट्रेसी को परिभाषित करता हूं तो यह मेरा महंगा कार्य नहीं करेगा? या कॉल करता है, तो तय करता है कि यह कुछ भी पता नहीं लगाएगा?

वैसे भी, अगर यह इसे हटा देता है, तो यह सी ++ मैक्रो से भी कम है क्योंकि मैं उस बड़ी बदसूरत कॉल को सी ++ में अपने सरल VLOG() कॉल की तरह नहीं देख सकता और फिर भी पैरामीटर का मूल्यांकन करने से बच सकता हूं, क्या मैं कर सकता हूं? न ही मैं रनटाइम पर कम वर्बोजिटी को परिभाषित करके ओवरहेड से बच सकता हूं जैसे कि मैं सी ++ में कर सकता हूं, है ना?

उत्तर

1

इनमें से दो उत्तरों (एंड्रयू अरनॉट्स और ब्रायन के) ने मेरे प्रश्न का उत्तर दिया। ट्रेस और डीबग क्लास विधियों पर लागू होने वाली सशर्त एट्रिब्यूट, यदि महंगे पैरामीटर मूल्यांकन सहित TRACE या DEBUG # undef'd हैं, तो सभी विधियों को हटाया जा सकता है। धन्यवाद!

दूसरे भाग के लिए, चाहे आप रनटाइम पर सभी कॉल पूरी तरह से हटा सकते हैं, संकलन समय पर नहीं, मुझे log4net fac में उत्तर मिला। उनके अनुसार, यदि आप स्टार्टअप समय पर एक पठनीय संपत्ति सेट करते हैं, तो रनटाइम उन सभी कॉलों को संकलित करेगा जो परीक्षण पास नहीं करते हैं! यह स्टार्टअप के बाद इसे बदलने नहीं देता है लेकिन यह ठीक है, संकलन समय पर उन्हें हटाने से बेहतर है।

0

अपनी टिप्पणी

के लिए "क्योंकि मैं अपने सरल Vlog() सी में कॉल ++ जैसे कि बड़े बदसूरत कॉल नज़र नहीं कर सकते हैं" - आप नीचे दिए गए उदाहरण के रूप में एक का उपयोग कर बयान जोड़ सकते हैं।

 
using System.Diagnostics; 

.... 
Trace.WriteLineIf(.....) 

मैं समझता हूँ, यह, ट्रेस युक्त लाइनों को दूर करता है, तो आप ट्रेस प्रतीक परिभाषित करेगा।

+0

लंबे उपसर्ग बदसूरत हिस्सा नहीं है, लेकिन तथ्य यह है कि मुझे g_log.verbosity और यहां तक ​​कि फ़ंक्शन नाम WriteLine का खुलासा करना है। मैं अपना स्वयं का कार्य VLOG (5, ...) करना चाहता हूं। –

0

मुझे यकीन नहीं है, लेकिन आप स्वयं जवाब का पता लगा सकते हैं।

इसे एक वास्तविक महंगा कार्य करें (जैसे Thread.Sleep(10000)) और कॉल के समय। यदि इसमें बहुत लंबा समय लगता है, तो यह वैसे भी आपके फ़ंक्शन को कॉल कर रहा है।

(आप #if TRACE और #endif साथ Trace.WriteLineIf() कॉल लपेट कर सकते हैं और एक आधार की तुलना के लिए इसे फिर से परीक्षण करें।)

9

अपने प्रश्नों, सभी विधि कॉल है कि आदेश Trace.WriteLine कॉल करने के लिए में मूल्यांकन करना चाहिए में से एक उत्तर देने के लिए (या उसके भाई बहन/चचेरे भाई) ट्रेस। राइटलाइन को संकलित किया गया है तो बुलाया नहीं जाता है। तो आगे बढ़ें और अपनी महंगी विधि कॉल सीधे ट्रेस कॉल के पैरामीटर के रूप में रखें और इसे संकलित समय पर हटा दिया जाएगा यदि आप TRACE प्रतीक को परिभाषित नहीं करते हैं।

अब रनटाइम पर अपनी क्रियात्मकता को बदलने के बारे में आपके अन्य प्रश्न के लिए। यहां की चाल यह है कि Trace.WriteLine और इसी तरह के तरीके 'स्ट्रिंग स्वरूपण तर्कों के लिए' पैराम्स ऑब्जेक्ट [] args 'लेते हैं। केवल तभी जब स्ट्रिंग वास्तव में उत्सर्जित होती है (जब वर्बोजिटी पर्याप्त रूप से ऊंची होती है) क्या विधि उन ऑब्जेक्ट्स पर टॉस्ट्रिंग को कॉल करती है ताकि उनमें से एक स्ट्रिंग प्राप्त हो सके। इसलिए मैं एक चाल जो अक्सर खेलता हूं, इन तरीकों से पूरी तरह से इकट्ठे तारों की बजाय वस्तुओं को पारित करना है, और जिस वस्तु को मैं पास करता हूं उसके टॉस्ट्रिंग में स्ट्रिंग सृजन छोड़ देता हूं।इस तरह रनटाइम प्रदर्शन कर केवल तभी भुगतान किया जाता है जब लॉगिंग वास्तव में होती है, और यह आपको अपने ऐप को पुन: संकलित किए बिना वर्बोसिटी बदलने की आजादी देता है।

+0

तारों को भी क्यों संकलित नहीं किया जाएगा? – sharptooth

+0

यदि आप पूछ रहे हैं कि यह ऑब्जेक्ट ToString चाल क्यों संकलित नहीं होती है, तो यह करता है, यदि आप ट्रेस का उपयोग करते हैं और TRACE निरंतर परिभाषित नहीं करते हैं। यह चाल केवल तभी काम करती है जब आप ऐसी विधि का उपयोग करते हैं जो संकलित नहीं होता है। मैं और अधिक स्पष्ट हो सकता था। माफ़ कीजिये। –

+0

यह काफी मजेदार है लेकिन यह सच लगता है। परीक्षण: 'var i = 0; डीबग। राइटलाइन (i ++); कंसोल। राइटलाइन (" i = "+ i);' – gatopeich

2

ConditionalAttribute आपका सबसे अच्छा दोस्त है। #define सेट नहीं होने पर कॉल पूरी तरह से हटा दी जाएगी (जैसे कॉल साइट # if'd थी)।

संपादित करें: (! धन्यवाद) कोई व्यक्ति कोई टिप्पणी में रखते, लेकिन मुख्य जवाब शरीर में ध्यान देने योग्य:

सभी ट्रेस वर्ग के तरीकों सशर्त ("ट्रेस") के साथ सजाया जाता है। इसे परावर्तक का उपयोग करके देखा।

जिसका अर्थ है Trace.Blah (... महंगा ...) ट्रैस परिभाषित नहीं होने पर पूरी तरह से गायब हो जाता है।

+0

ट्रेस क्लास के सभी तरीकों को सशर्त ("ट्रेस") से सजाया गया है। इसे परावर्तक का उपयोग करके देखा। – shahkalpesh

+0

तो यह काम करता है! अब अगर मैं केवल रनटाइम पर ऐसा कर सकता हूं तो मैं बहुत खुश हूं। –

0

यह महंगी कॉल का आह्वान करेगा क्योंकि इसका दुष्प्रभाव वांछित हो सकता है।

आप क्या कर सकते हैं अपनी महंगी विधि [सशर्त ("ट्रेसी")] या [सशर्त ("DEBUG") विशेषता के साथ सजाने के लिए है। डीबीयूजी या ट्रेसी निरंतर परिभाषित नहीं किया गया है, और न ही महंगी विधि को निष्पादित करने के लिए कोई भी कॉल करेगा, तो विधि अंतिम निष्पादन योग्य में संकलित नहीं की जाएगी।

2

मेरे लिए काम किया गया एक समाधान singleton कक्षा का उपयोग कर रहा है। यह आपके लॉगिंग कार्यों का पर्दाफाश कर सकता है और आप अपने व्यवहार को कुशलता से नियंत्रित कर सकते हैं। आइए क्लास 'ऐपलॉगर' को कॉल करें। उसका एक उदाहरण

public class AppLogger 
{ 
    public void WriteLine(String format, params object[] args) 
    { 
     if (LoggingEnabled) 
     { 
      Console.WriteLine(format, args); 
     } 
    } 
} 

नोट, सिंगलटन सामान उपरोक्त उदाहरण से बाहर छोड़ा गया है। ट्यूबों के अच्छे उदाहरणों के टन हैं। कोई दिलचस्प बात यह नहीं है कि बहु-थ्रेडिंग का समर्थन कैसे करें। मैं इसे इस तरह से किया है: (, संक्षिप्तता के लिए संक्षिप्त हाहाहाहा)

public static void WriteLine(String format, params object[] args) 
{ 
    if (TheInstance != null) 
    { 
     TheInstance.TheCreatingThreadDispatcher.BeginInvoke( Instance.WriteLine_Signal, format, args); 
    } 
} 

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

+0

यह समाधान ट्रेस विधियों के सशर्त एट्रिब्यूट के बिना व्यर्थ और बेकार है। ट्रेसी परिभाषित किए बिना, ट्रेस में किसी विधि को कॉल करने के लिए किसी भी विधि को संकलित नहीं किया जाएगा और महंगी विधि कभी नहीं बुलाई जाएगी, जहां आपके भीतर, इसे हर बार बुलाया जाएगा। – Samuel

+2

नहीं, यह व्यर्थ और बेकार नहीं है (वह प्रीटी कठोर है)। ध्यान दें कि ConsoleWriteline (या जो भी लॉगिंग विधि आप चुनते हैं) को कॉल एक सशर्त कथन के अंदर है। इसलिए यदि लॉगिंग सक्षम है तो आप केवल कीमत का भुगतान करते हैं। – Foredecker

+0

मैं यहां फोरडेकर के साथ हूं, वह जो जवाब देता है वह ओपी उदाहरण के बराबर है जो ओपी अपने प्रश्न में देता है। ConditionalAttribute के साथ समस्या यह है कि ओपी रनटाइम पर इसे नियंत्रित करना चाहता है। यदि कंपाइलर द्वारा लाइन हटा दी गई है तो यह उत्पादन के तहत चालू होने के लिए उपलब्ध नहीं होगी। –

2

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

यदि आप ट्रेससोर्स का उपयोग कर रहे हैं (जो मुझे विश्वास है कि आपको ट्रेस को सीधे कॉल करने की बजाय, क्योंकि यह आपको रन-टाइम पर घटक-स्तर पर ट्रेसिंग पर अधिक बढ़िया नियंत्रण देता है), तो आप ऐसा कुछ कर सकते हैं :

if (Component1TraceSource.ShouldTrace(TraceEventType.Verbose)) 
    OutputExpensiveTraceInformation() 

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

इस दृष्टिकोण का लाभ यह है क्योंकि जेआईटीआर फ़ंक्शन-बाय-फ़ंक्शन आधार पर संकलित करता है, यदि "if" गलत होने का मूल्यांकन करता है, तो फ़ंक्शन न केवल कॉल किया जाएगा - यह भी नहीं होगा JITed हो। नकारात्मकता यह है कि (ए) आपने इस कॉल और फ़ंक्शन आउटपुटएक्सपेन्डेन्टट्रेस इंफॉर्मेशन के बीच ट्रेसिंग स्तर के ज्ञान को अलग कर दिया है (इसलिए यदि आप TraceEventType को TraceEventType.Information के रूप में बदलते हैं, उदाहरण के लिए, यह काम नहीं करेगा क्योंकि आप कभी नहीं करेंगे यहां तक ​​कि इसे तब तक कॉल करें जब तक कि इस उदाहरण में वर्बोज़ स्तर के ट्रेसिंग के लिए ट्रेससोर्स सक्षम नहीं है) और (बी) यह लिखने के लिए और कोड है।

यह एक ऐसा मामला है जहां ऐसा लगता है कि एक सी-जैसे प्रीप्रोसेसर मदद करेगा (उदाहरण के लिए, यह सुनिश्चित कर सकता है कि, कंधे के पैरामीटर और अंतिम ट्रेसवेन्ट कॉल के पैरामीटर समान हैं), लेकिन मैं समझता हूं कि क्यों सी # इसमें शामिल नहीं है।

एंड्रयू के महंगे संचालन को अलग करने के सुझाव। ट्रेससेन्ट को आपके द्वारा पारित वस्तुओं के टॉस्ट्रिंग विधियां भी एक अच्छा है; उस स्थिति में, आप उदाहरण के लिए एक ऑब्जेक्ट विकसित कर सकते हैं जिसका उपयोग ट्रेस के लिए किया जाता है, जिस पर आप उन ऑब्जेक्ट्स को पास करते हैं जिन्हें आप एक महंगी स्ट्रिंग प्रस्तुति बनाना चाहते हैं और ट्रेस ऑब्जेक्ट की ToString विधि में उस कोड को अलग करने के बजाय उस कोड को अलग करना चाहते हैं TraceEvent कॉल में पैरामीटर सूची (जो रन-टाइम पर ट्रेसलेवल सक्षम नहीं होने पर भी इसे निष्पादित किया जाएगा)।

उम्मीद है कि इससे मदद मिलती है।

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