Kotlin में लॉगिंग: मुहावरेदार दृष्टिकोण और विधियों की तुलना

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

Kotlin में लॉगिंग एक समस्या क्यों है (और इसे कैसे ठीक करें)

\n\n

यदि आपने कभी Java में लिखा है, तो आप इस रिवाज़ को जानते हैं: प्रत्येक वर्ग की शुरुआत में आप private static final Logger logger = LoggerFactory.getLogger(MyClass.class); लिखते हैं। उबाऊ, नीरस, लेकिन काम करता है। Kotlin में आने पर कुछ अधिक सुरुचिपूर्ण चाहिए होता है — और यहीं से सबसे दिलचस्प शुरुआत होती है।

\n\n

Stack Overflow पर प्रश्न "Idiomatic way of logging in Kotlin" ने हज़ारों व्यूज़ और दर्जनों चर्चाएँ प्राप्त की हैं। पता चलता है कि आधुनिक Kotlin में भी लॉग करने का कोई एक "सही" तरीका नहीं है। इस लेख में हम तीन मुख्य दृष्टिकोणों का विश्लेषण करेंगे, उनके प्रदर्शन और पठनीयता की तुलना करेंगे, और उस Kotlin में लॉगिंग के मुहावरेदार तरीके का चयन करेंगे जो 90% परियोजनाओं के लिए उपयुक्त होगा।

\n\n

समस्या: Kotlin में Logger उतना सरल नहीं है

\n\n

Kotlin एक ऐसी भाषा है जो संक्षिप्तता को महत्व देती है। लेकिन SLF4J (Java/Kotlin दुनिया में सबसे लोकप्रिय लॉगिंग लाइब्रेरी) को प्रत्येक लॉगर के लिए वर्ग के स्पष्ट उल्लेख की आवश्यकता होती है। Java में इसे Lombok या IDE टेम्पलेट्स के माध्यम से हल किया जाता है। Kotlin में — भाषा की सुविधाओं के माध्यम से।

\n\n

हमारे सामने कई कार्य हैं:

\n\n
    \n
  • वर्ग के नाम की नकल न करें (यह कॉपी करने पर त्रुटियों का स्रोत है)
  • \n
  • प्रदर्शन के लिए भुगतान न करें (लॉगिंग एक सामान्य ऑपरेशन है)
  • \n
  • कोड की पठनीयता और संक्षिप्तता बनाए रखें
  • \n
  • लॉगर के आलसी आरंभीकरण का समर्थन करें
  • \n
\n\n

आइए देखें कि Kotlin समुदाय क्या समाधान प्रस्तुत करता है।

\n\n

दृष्टिकोण 1: "अनाड़ी" — Companion Object

\n\n

सबसे सीधा तरीका — वर्ग के companion object में लॉगर घोषित करना।

\n\n
class UserService {\n    companion object {\n        private val logger = LoggerFactory.getLogger(UserService::class.java)\n    }\n\n    fun createUser(name: String) {\n        logger.info("Creating user: $name")\n    }\n}
\n\n

लाभ:

\n
    \n
  • सरलता और स्पष्टता
  • \n
  • अतिरिक्त निर्भरता की आवश्यकता नहीं
  • \n
\n\n

नुकसान:

\n
    \n
  • वर्ग का मैन्युअल उल्लेख — गलती हो सकती है
  • \n
  • बहुत सारा बॉयलरप्लेट कोड
  • \n
  • इंटरफ़ेस और अमूर्त वर्गों के लिए उपयुक्त नहीं
  • \n
\n\n

यह दृष्टिकोण आधार है, जिससे अन्य सभी शुरू होते हैं। यह काम करता है, लेकिन यह Kotlin में लॉगिंग का मुहावरेदार तरीका नहीं है — बहुत अधिक बॉयलरप्लेट।

\n\n

दृष्टिकोण 2: एक्सटेंशन-फ़ंक्शंस — Kotlin शैली

\n\n

Kotlin एक्सटेंशन-फ़ंक्शंस के माध्यम से वर्गों का विस्तार करने की अनुमति देता है। क्यों न एक ऐसा फ़ंक्शन बनाया जाए जो किसी भी वर्ग के लिए लॉगर लौटाता है?

\n\n
inline fun <reified T : Any> T.logger(): Logger {\n    return LoggerFactory.getLogger(T::class.java)\n}\n\nclass OrderService {\n    private val logger = logger()\n\n    fun processOrder(id: String) {\n        logger.debug("Processing order: $id")\n    }\n}
\n\n

यहाँ हम इनलाइन फ़ंक्शन में reified टाइप-पैरामीटर का उपयोग करते हैं। यह रिफ्लेक्शन के बिना रनटाइम पर वर्ग प्राप्त करने की अनुमति देता है।

\n\n

लाभ:

\n
    \n
  • संक्षिप्त: private val logger = logger()
  • \n
  • सुरक्षित: वर्ग स्वचालित रूप से लिया जाता है
  • \n
  • इनलाइन फ़ंक्शन अतिरिक्त ऑब्जेक्ट नहीं बनाता
  • \n
\n\n

नुकसान:

\n
    \n
  • लॉगर ऑब्जेक्ट बनाते समय तुरंत आरंभ होता है, आलसी नहीं
  • \n
  • टॉप-लेवल फ़ंक्शंस (वर्ग के बाहर) के लिए उपयुक्त नहीं
  • \n
\n\n

यह मुहावरेदार समाधान के करीब है। लेकिन इसे और बेहतर बनाया जा सकता है।

\n\n

दृष्टिकोण 3: डेलिगेटेड प्रॉपर्टीज़ — Kotlin की सुंदरता

\n\n

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

\n\n
class LoggerDelegate<in T : Any> : ReadOnlyProperty<T, Logger> {\n    private var logger: Logger? = null\n\n    override fun getValue(thisRef: T, property: KPropert                

ब्लॉग

पुस्तक अनुशंसाएँ