কোটলিনে লগিনের আইডোমেটিক উপায়


164

কোটলিনের জাভাতে ব্যবহৃত স্ট্যাটিক ক্ষেত্রগুলির একই ধারণা নেই। জাভাতে, লগিংয়ের সাধারণত গৃহীত উপায় হ'ল:

public class Foo {
    private static final Logger LOG = LoggerFactory.getLogger(Foo.class);
}

প্রশ্নটি হ'ল কোটলিনে লগিংয়ের মূ ?় উপায় কী?


1
এটি জাভা উপায় থেকে অনেক দূরের একটি কারণ হিসাবে এটি পোস্ট করা নয়, তবে আমি লগিংয়ের জন্য যেকোনটিতে একটি এক্সটেনশন ফাংশন লেখার বিষয়টি বিবেচনা করেছি। আপনার অবশ্যই লগারদের ক্যাশে করা দরকার, তবে আমি মনে করি এটি করার এটি একটি দুর্দান্ত উপায়।
mhlz

1
@ এমএইচএলজ কি সেই এক্সটেনশন ফাংশনটি স্থিতিশীলভাবে সমাধান করা হবে না? যেমনটি রয়েছে, এটি সমস্ত ধরণের ক্ষেত্রে প্রয়োগ করা হবে না, কেবল Anyটাইপযুক্তগুলিতে (সুতরাং একটি castালাই প্রয়োজন)?
Jire

1
@ এমএইচএলজ একটি এক্সটেনশন ফাংশনটি বোঝায় না কারণ এটিতে কোনও লগার রাখার মতো অবস্থা থাকবে না। এটি কোনও লগার ফেরত দেওয়ার জন্য একটি এক্সটেনশন হতে পারে, তবে কেন এটি সিস্টেমের প্রতিটি জ্ঞাত শ্রেণীতে রয়েছে? যেকোনোটির উপরে এক্সটেনশানগুলি পরে রাখার পরে আইডিইতে ম্লান শব্দ হয় noise @ জায়ার এক্সটেনশনটি যে কোনওর সকল বংশধরের জন্য প্রযোজ্য হবে, তারপরেও this.javaClassপ্রতিটিটির জন্য সঠিক ফিরিয়ে দেবে । তবে আমি সমাধান হিসাবে এটি সুপারিশ করছি না।
জেইসন মিনার্ড

উত্তর:


250

বেশিরভাগ পরিপক্ক কোটলিন কোডে, আপনি নীচে এই নিদর্শনগুলির একটি খুঁজে পাবেন। প্রপার্টি ডেলিগেটস ব্যবহার করার পদ্ধতিটি কোটলিনের ক্ষুদ্রতম কোড তৈরির ক্ষমতার সুযোগ নেয়।

দ্রষ্টব্য: এখানে কোডটির জন্য java.util.Loggingতবে একই তত্ত্বটি কোনও লগিং লাইব্রেরিতে প্রয়োগ হয়

স্ট্যাটিক-মত (সাধারণ, প্রশ্নে আপনার জাভা কোডের সমতুল্য)

আপনি যদি লগিং সিস্টেমের মধ্যে সেই হ্যাশ লুকের পারফরম্যান্সে বিশ্বাস রাখতে না পারেন, তবে আপনার জাভা কোডের সাথে আপনি এমন কোনও সহকর্মী অবজেক্ট ব্যবহার করতে পারেন যা একটি ঘটনা ধরে রাখতে পারে এবং আপনার কাছে একটি স্ট্যাটিকের মতো বোধ করতে পারে।

class MyClass {
    companion object {
        val LOG = Logger.getLogger(MyClass::class.java.name) 
    }

    fun foo() {
        LOG.warning("Hello from MyClass")
    }
}  

আউটপুট তৈরি:

26 ডিসেম্বর, 2015 11:28:32 এএমএম ফু org.stackoverflow.kotlin.test.MyClassইনফো: মাই ক্লাস থেকে হ্যালো

এখানে সাহাবী অবজেক্টগুলির জন্য আরও: কম্বিয়ান অবজেক্টস ... এছাড়াও নোট করুন যে উপরের নমুনায় লগারের জন্য MyClass::class.javaটাইপের উদাহরণ পাওয়া যায় Class<MyClass>, যেখানে this.javaClassটাইপের উদাহরণ পাওয়া যায় Class<MyClass.Companion>

প্রতি শ্রেণীর ইনস্ট্যান্স (সাধারণ)

তবে, উদাহরণস্বরূপ স্তরে কল করা এবং লগার পাওয়া এড়ানোর কোনও কারণ নেই। আপনার উল্লিখিত অডিও জাভা পদ্ধতিটি পুরানো এবং পারফরম্যান্সের ভয়ের ভিত্তিতে, যেখানে ক্লাস প্রতি লগার ইতিমধ্যে গ্রহের প্রায় কোনও যুক্তিসঙ্গত লগিং সিস্টেম দ্বারা ক্যাশে হয়েছে। লগার অবজেক্টটি ধরে রাখতে কেবল সদস্য তৈরি করুন।

class MyClass {
  val LOG = Logger.getLogger(this.javaClass.name)

  fun foo() {
        LOG.warning("Hello from MyClass")
  }
} 

আউটপুট তৈরি:

26 ডিসেম্বর, 2015 11:28:44 এএম org.stackoverflow.kotlin.test.MyClass foo তথ্য: মাইক্লাস থেকে হ্যালো

আপনি উদাহরণস্বরূপ এবং প্রতি শ্রেণীর পার্থক্য উভয়ই পারফরম্যান্স পরীক্ষা করতে পারেন এবং বেশিরভাগ অ্যাপ্লিকেশনের জন্য কোনও বাস্তবসম্মত পার্থক্য রয়েছে কিনা তা দেখতে পারেন।

সম্পত্তি প্রতিনিধি (সাধারণ, সবচেয়ে মার্জিত)

আরেকটি পদ্ধতির, যা @ জাইরের অন্য উত্তরে প্রস্তাবিত, একটি সম্পত্তি প্রতিনিধি তৈরি করা, যা আপনি চাইলে অন্য যে কোনও শ্রেণিতে যুক্তিযুক্তভাবে অবিচ্ছিন্নভাবে ব্যবহার করতে পারেন। এটি করার একটি সহজ উপায় আছে যেহেতু কোটলিন Lazyইতিমধ্যে একটি প্রতিনিধি সরবরাহ করে, আমরা কেবল এটি কোনও ফাংশনে গুটিয়ে রাখতে পারি । এখানে একটি কৌশলটি হ'ল যদি আমরা বর্তমানে প্রতিনিধি ব্যবহার করে ক্লাসের ধরণটি জানতে চাই তবে আমরা এটিকে যে কোনও ক্লাসে একটি এক্সটেনশন ফাংশন হিসাবে দেখি:

fun <R : Any> R.logger(): Lazy<Logger> {
    return lazy { Logger.getLogger(unwrapCompanionClass(this.javaClass).name) }
}
// see code for unwrapCompanionClass() below in "Putting it all Together section"

এই কোডটি এটিও নিশ্চিত করে যে আপনি যদি এটি কোনও কম্পেনিয়ান অবজেক্টে ব্যবহার করেন তবে লগারের নাম একই হবে যেমন আপনি নিজেই এটি ক্লাসে ব্যবহার করেছেন। এখন আপনি কেবল:

class Something {
    val LOG by logger()

    fun foo() {
        LOG.info("Hello from Something")
    }
}

প্রতি শ্রেণীর উদাহরণের জন্য, বা আপনি যদি প্রতি ক্লাসে একটি উদাহরণ সহ আরও স্থিতিশীল হতে চান:

class SomethingElse {
    companion object {
        val LOG by logger()

    }

    fun foo() {
        LOG.info("Hello from SomethingElse")
    }
}

এবং foo()এই উভয় ক্লাসে কল করা থেকে আপনার আউটপুটটি হ'ল :

26 ডিসেম্বর, 2015 11:30:55 পূর্বাহ্নে org.stackoverflow.kotlin.test. কিছু কথা ফুটিয়ে তুলেছে তথ্য: হ্যালো কিছু থেকে

26 ডিসেম্বর, 2015 11:30:55 এএম org.stackoverflow.kotlin.test.SomethingEll foo তথ্য: হ্যমথ সামথিংহেলস থেকে

এক্সটেনশন ফাংশন (কোনও নাম স্থানের "দূষণ" এর কারণে এক্ষেত্রে অস্বাভাবিক)

কোটলিনের কয়েকটি গোপন কৌশল রয়েছে যা আপনাকে এই কোডটির কিছুটিকে আরও ছোট করে তুলতে দেয়। আপনি ক্লাসে এক্সটেনশন ফাংশন তৈরি করতে পারেন এবং তাই তাদের অতিরিক্ত কার্যকারিতা দিতে পারেন। উপরের মন্তব্যে একটি পরামর্শ ছিল Anyলগার ফাংশন সহ প্রসারিত করা । এটি যে কোনও সময় কোনও ক্লাসে তাদের আইডিইতে কোড-সমাপ্তি ব্যবহার করার সাথে সাথে শব্দটি তৈরি করতে পারে। তবে সম্প্রসারণ Anyবা অন্য কোনও মার্কার ইন্টারফেসের একটি গোপন সুবিধা রয়েছে : আপনি বোঝাতে পারেন যে আপনি নিজের শ্রেণিটি প্রসারিত করছেন এবং তাই আপনার মধ্যে যে শ্রেণিটি রয়েছে তা সনাক্ত করুন। তাই না? কম বিভ্রান্ত হওয়ার জন্য, এখানে কোডটি দেওয়া হয়েছে:

// extend any class with the ability to get a logger
fun <T: Any> T.logger(): Logger {
     return Logger.getLogger(unwrapCompanionClass(this.javaClass).name)
}

এখন একটি শ্রেণীর মধ্যে (বা সহকর্মী অবজেক্ট), আমি কেবল নিজের ক্লাসে এই এক্সটেনশনটিকে কল করতে পারি:

class SomethingDifferent {
    val LOG = logger()

    fun foo() {
        LOG.info("Hello from SomethingDifferent")
    }
}

উত্পাদন আউটপুট:

26 ডিসেম্বর, 2015 11:29:12 এএম org.stackoverflow.kotlin.test.SomeomingDifferent foo তথ্য: হ্যালো সামথিংডিফারেন্স থেকে

মূলত, কোডটি এক্সটেনশনের কল হিসাবে দেখা হয় Something.logger()। সমস্যাটি হ'ল নিম্নলিখিত শ্রেণিগুলিতে অন্যান্য শ্রেণিতে "দূষণ" তৈরি করা সত্য হতে পারে:

val LOG1 = "".logger()
val LOG2 = Date().logger()
val LOG3 = 123.logger()

মার্কার ইন্টারফেসে এক্সটেনশন ফাংশন (কীভাবে সাধারণ, "বৈশিষ্ট্যগুলি" তবে সাধারণ মডেল তা নিশ্চিত নয়)

এক্সটেনশানগুলির ব্যবহার পরিষ্কার এবং "দূষণ" হ্রাস করতে, আপনি প্রসারিত করতে একটি মার্কার ইন্টারফেস ব্যবহার করতে পারেন:

interface Loggable {} 

fun Loggable.logger(): Logger {
     return Logger.getLogger(unwrapCompanionClass(this.javaClass).name)
}    

অথবা এমনকি ডিফল্ট প্রয়োগের মাধ্যমে পদ্ধতিটিকে ইন্টারফেসের অংশ হিসাবে তৈরি করুন:

interface Loggable {
    public fun logger(): Logger {
        return Logger.getLogger(unwrapCompanionClass(this.javaClass).name)
    }
}

এবং আপনার শ্রেণিতে এই বৈচিত্রগুলির যে কোনও একটি ব্যবহার করুন:

class MarkedClass: Loggable {
    val LOG = logger()
}

উত্পাদন আউটপুট:

26 ডিসেম্বর, 2015 11:41:01 এএম org.stackoverflow.kotlin.test.MarkedClass foo তথ্য: মার্কডক্লাস থেকে হ্যালো

আপনি যদি লগার ধরে রাখার জন্য অভিন্ন ক্ষেত্র তৈরি করতে বাধ্য করতে চান, তবে এই ইন্টারফেসটি ব্যবহার করার সময় আপনাকে সহজেই প্রয়োগকারীকে একটি ক্ষেত্রের প্রয়োজন হতে পারে যেমন LOG:

interface Loggable {
    val LOG: Logger  // abstract required field

    public fun logger(): Logger {
        return Logger.getLogger(unwrapCompanionClass(this.javaClass).name)
    }
}

এখন ইন্টারফেসের প্রয়োগকারীকে অবশ্যই এর মতো দেখতে হবে:

class MarkedClass: Loggable {
    override val LOG: Logger = logger()
}

অবশ্যই, একটি বিমূর্ত বেস শ্রেণি একই কাজ করতে পারে, ইন্টারফেস উভয় বিকল্প থাকা এবং একটি ইন্টারফেস ক্লাস যে ইন্টারফেস প্রয়োগ করে নমনীয়তা এবং অভিন্নতা দেয়:

abstract class WithLogging: Loggable {
    override val LOG: Logger = logger()
}

// using the logging from the base class
class MyClass1: WithLogging() {
    // ... already has logging!
}

// providing own logging compatible with marker interface
class MyClass2: ImportantBaseClass(), Loggable {
    // ... has logging that we can understand, but doesn't change my hierarchy
    override val LOG: Logger = logger()
}

// providing logging from the base class via a companion object so our class hierarchy is not affected
class MyClass3: ImportantBaseClass() {
    companion object : WithLogging() {
       // we have the LOG property now!
    }
}

এটি একসাথে রাখা (একটি ছোট সহায়ক লাইব্রেরি)

উপরের যে কোন বিকল্পটি ব্যবহার করা সহজ করার জন্য এখানে একটি ছোট সহায়ক লাইব্রেরি রয়েছে। কোটলিনে এটিকে আপনার পছন্দমতো করে তুলতে এপিআই প্রসারিত করা সাধারণ। হয় এক্সটেনশন বা শীর্ষ স্তরের ফাংশনগুলিতে। লগার কিভাবে তৈরি করবেন তার বিকল্পগুলির জন্য এখানে একটি মিশ্রণ এবং সমস্ত বৈচিত্র দেখানো একটি নমুনা:

// Return logger for Java class, if companion object fix the name
fun <T: Any> logger(forClass: Class<T>): Logger {
    return Logger.getLogger(unwrapCompanionClass(forClass).name)
}

// unwrap companion class to enclosing class given a Java Class
fun <T : Any> unwrapCompanionClass(ofClass: Class<T>): Class<*> { 
   return ofClass.enclosingClass?.takeIf { 
      ofClass.enclosingClass.kotlin.companionObject?.java == ofClass 
   } ?: ofClass 
}

// unwrap companion class to enclosing class given a Kotlin Class
fun <T: Any> unwrapCompanionClass(ofClass: KClass<T>): KClass<*> {
   return unwrapCompanionClass(ofClass.java).kotlin
}

// Return logger for Kotlin class
fun <T: Any> logger(forClass: KClass<T>): Logger {
    return logger(forClass.java)
}

// return logger from extended class (or the enclosing class)
fun <T: Any> T.logger(): Logger {
    return logger(this.javaClass)
}

// return a lazy logger property delegate for enclosing class
fun <R : Any> R.lazyLogger(): Lazy<Logger> {
    return lazy { logger(this.javaClass) }
}

// return a logger property delegate for enclosing class
fun <R : Any> R.injectLogger(): Lazy<Logger> {
    return lazyOf(logger(this.javaClass))
}

// marker interface and related extension (remove extension for Any.logger() in favour of this)
interface Loggable {}
fun Loggable.logger(): Logger = logger(this.javaClass)

// abstract base class to provide logging, intended for companion objects more than classes but works for either
abstract class WithLogging: Loggable {
    val LOG = logger()
}

আপনি যে কোনওটিকে রাখতে চান তা চয়ন করুন এবং এখানে সমস্ত বিকল্পের ব্যবহার রয়েছে:

class MixedBagOfTricks {
    companion object {
        val LOG1 by lazyLogger()          // lazy delegate, 1 instance per class
        val LOG2 by injectLogger()        // immediate, 1 instance per class
        val LOG3 = logger()               // immediate, 1 instance per class
        val LOG4 = logger(this.javaClass) // immediate, 1 instance per class
    }

    val LOG5 by lazyLogger()              // lazy delegate, 1 per instance of class
    val LOG6 by injectLogger()            // immediate, 1 per instance of class
    val LOG7 = logger()                   // immediate, 1 per instance of class
    val LOG8 = logger(this.javaClass)     // immediate, 1 instance per class
}

val LOG9 = logger(MixedBagOfTricks::class)  // top level variable in package

// or alternative for marker interface in class
class MixedBagOfTricks : Loggable {
    val LOG10 = logger()
}

// or alternative for marker interface in companion object of class
class MixedBagOfTricks {
    companion object : Loggable {
        val LOG11 = logger()
    }
}

// or alternative for abstract base class for companion object of class
class MixedBagOfTricks {
    companion object: WithLogging() {} // instance 12

    fun foo() {
       LOG.info("Hello from MixedBagOfTricks")
    }
}

// or alternative for abstract base class for our actual class
class MixedBagOfTricks : WithLogging() { // instance 13
    fun foo() {
       LOG.info("Hello from MixedBagOfTricks")
    }
}

এই নমুনায় তৈরি লগারের সমস্ত 13 টি উদাহরণ একই লগারের নাম এবং আউটপুট উত্পাদন করবে:

26 ডিসেম্বর, ২০১৫ 11:39:00 এএম org.stackoverflow.kotlin.test. মিক্সডব্যাগঅফট্রিক্স ফাঁস ইনফো: মিক্সডব্যাগঅফট্রিক্স থেকে হ্যালো

দ্রষ্টব্য: দ্যunwrapCompanionClass() পদ্ধতি নিশ্চিত করে যে আমরা সহচর বস্তুর বরং এনক্লোজিং ক্লাস নামাঙ্কিত এটির উৎপন্ন হবে না। সহকর্মী অবজেক্টটি সহ ক্লাসটি সন্ধান করার এটি বর্তমান প্রস্তাবিত উপায়। নামটি ব্যবহার করে " $ কম্পায়েনিয়ান" কেটে ফেলা removeSuffix()কাজ করে না, কারণ সহযোদ্ধা অবজেক্টগুলিকে কাস্টম নাম দেওয়া যেতে পারে।


কিছু নির্ভরতা ইনজেকশন ফ্রেমওয়ার্কগুলি এখানে অন্য উত্তরে আপনি দেখতে যেমন প্রতিনিধি ব্যবহার করেন। এগুলি দেখতে `ভাল লগ: ইনজেকশনলগার () by দ্বারা লগার এবং লগিং সিস্টেমটি ইনজেকশনের অনুমতি দেয় এবং ব্যবহারের কোডটির সাথে অজানা। (এটি দেখানোর জন্য আমার ইনজেকশন কাঠামোটি github.com/kohesive/injektরয়েছে )
মিনার্ড

10
বিস্তৃত উত্তরের জন্য ধন্যবাদ। খুবই তথ্যবহুল. আমি বিশেষত সম্পত্তি প্রতিনিধিদের (সাধারণ, সবচেয়ে মার্জিত) বাস্তবায়ন পছন্দ করি।
mchlstckl

6
আমি মনে করি কোটলিন সিনট্যাক্সে কোনও পরিবর্তন হয়েছিল। এবং ofClass.enclosingClass.kotlin.objectInstance?.javaClassofClass.enclosingClass.kotlin.companionObject?.java
মোড়কটি

1
আহ, কিছু মনে করবেন না, যেমন এখানে বলা হয়েছে kotlinlang.org/docs/references/reflection.html প্রতিফলিত জারটি stdlib থেকে আলাদাভাবে প্রেরণ করা হয়, গ্রেডের জন্য আমাদের এটি দরকার:compile 'org.jetbrains.kotlin:kotlin-reflect:1.0.2'
হোয়াং ট্রান

1
'সম্পত্তি প্রতিনিধি' এবং 'এক্সটেনশান ফাংশন' তৈরির কোডটি রিটার্নের ধরণ বাদে একই বলে মনে হয়। প্রপার্টি ডেলিগেটের ( public fun <R : Any> R.logger(): Lazy<Logger> { return lazy{Logger.getLogger(unwrapCompanionClass(this.javaClass).name)}}) কোডের নমুনায় কোনও এক্সটেনশান ফাংশন তৈরি হতে দেখা যায় "".logger()যা এখন একটি জিনিস, এটি কি এইরকম আচরণ করে?
মাইক রাইল্যান্ডার

32

কটাক্ষপাত আছে kotlin-লগিং গ্রন্থাগার।
এটি এর মতো লগিংয়ের অনুমতি দেয়:

private val logger = KotlinLogging.logger {}

class Foo {
  logger.info{"wohoooo $wohoooo"}
}

বা এর মতো:

class FooWithLogging {
  companion object: KLogging()
  fun bar() {
    logger.info{"wohoooo $wohoooo"}
  }
}

আমি এর সাথে তুলনা করে একটি ব্লগ পোস্টও লিখেছিলাম AnkoLogger: কোটলিন ও অ্যান্ড্রয়েডে লগিং: আনকোলগার বনাম কোটলিন-লগিং

দাবি অস্বীকার: আমি সেই লাইব্রেরির রক্ষণাবেক্ষণকারী।

সম্পাদনা করুন: কোটলিন-লগিংয়ের এখন মাল্টিপ্লাটফর্ম সমর্থন রয়েছে: https://github.com/MicroUtils/kotlin-logging/wiki/M


আমি আপনাকে পরামর্শ দিচ্ছি থাকতে পারে আপনাকে দেখাতে আপনার উত্তর সম্পাদনা আউটপুট এর logger.info()কল হিসাবে জেসন তার গৃহীত উত্তরে করেনি।
পাওলো মেরসন

7

লগিং প্রয়োগের একটি ভাল উদাহরণ হিসাবে আমি আনকো উল্লেখ করতে চাই যা একটি বিশেষ ইন্টারফেস ব্যবহার করেAnkoLogger যা লগিংয়ের প্রয়োজন এমন শ্রেণীর প্রয়োগ করা উচিত। ইন্টারফেসের ভিতরে কোড রয়েছে যা শ্রেণীর জন্য একটি লগিং ট্যাগ তৈরি করে। লগিং এর পরে এক্সটেনশন ফাংশনগুলির মাধ্যমে সম্পন্ন করা হয় যা উপক্রমগুলি বা এমনকি লগার উদাহরণ তৈরি না করে ইন্টারেস প্রয়োগের অভ্যন্তরে বলা যেতে পারে।

আমি মনে করি না এটি মূ .় , তবে এটি একটি ভাল পদ্ধতির বলে মনে হচ্ছে কারণ এটির জন্য ন্যূনতম কোড প্রয়োজন, কেবলমাত্র একটি শ্রেণীর ঘোষণায় ইন্টারফেস যুক্ত করা হয় এবং আপনি বিভিন্ন শ্রেণীর জন্য বিভিন্ন ট্যাগ দিয়ে লগিং পান।


নীচের কোডটি মূলত আনকোলগার , অ্যানড্রয়েড- ব্যবহারের জন্য সরলীকৃত এবং পুনরায় লেখা।

প্রথমত, একটি ইন্টারফেস রয়েছে যা মার্কার ইন্টারফেসের মতো আচরণ করে:

interface MyLogger {
    val tag: String get() = javaClass.simpleName
}

এটি এর বাস্তবায়নটি MyLoggerকেবল তাদের কল করার জন্য তাদের কোডের ভিতরে এক্সটেনশন ফাংশন ব্যবহার করতে দেয় this। এবং এটিতে লগিং ট্যাগও রয়েছে।

এরপরে, বিভিন্ন লগিং পদ্ধতির জন্য একটি সাধারণ প্রবেশ পয়েন্ট রয়েছে:

private inline fun log(logger: MyLogger,
                       message: Any?,
                       throwable: Throwable?,
                       level: Int,
                       handler: (String, String) -> Unit,
                       throwableHandler: (String, String, Throwable) -> Unit
) {
    val tag = logger.tag
    if (isLoggingEnabled(tag, level)) {
        val messageString = message?.toString() ?: "null"
        if (throwable != null)
            throwableHandler(tag, messageString, throwable)
        else
            handler(tag, messageString)
    }
}

এটি লগিং পদ্ধতি দ্বারা কল করা হবে। এটি MyLoggerবাস্তবায়ন থেকে একটি ট্যাগ পায় , লগিং সেটিংস পরীক্ষা করে এবং তারপরে দুটি হ্যান্ডলারের মধ্যে একটিতে কল করে, একটিটি Throwableযুক্তিযুক্ত এবং একটি ছাড়া।

তারপরে আপনি নিজের পছন্দমতো লগিং পদ্ধতিগুলি এইভাবে সংজ্ঞায়িত করতে পারেন:

fun MyLogger.info(message: Any?, throwable: Throwable? = null) =
        log(this, message, throwable, LoggingLevels.INFO,
            { tag, message -> println("INFO: $tag # $message") },
            { tag, message, thr -> 
                println("INFO: $tag # $message # $throwable");
                thr.printStackTrace()
            })

এগুলি কেবল একটি বার্তা লগইন এবং Throwableপাশাপাশি লগ ইন উভয়ের জন্য সংজ্ঞায়িত করা হয় , এটি thisচ্ছিক throwableপরামিতি দিয়ে সম্পন্ন হয় ।

বিভিন্ন লগিং পদ্ধতির জন্য যে ফাংশনগুলি পাস হয়ে যায় handlerএবং throwableHandlerবিভিন্ন হতে পারে, উদাহরণস্বরূপ, তারা ফাইলটি লগ করতে বা এটি কোথাও আপলোড করতে পারে। isLoggingEnabledএবংLoggingLevels ব্রেভিটি জন্য বাদ দেওয়া হয়, কিন্তু এগুলি ব্যবহার করা আরও আরও নমনীয়তা সরবরাহ করে।


এটি নিম্নলিখিত ব্যবহারের জন্য অনুমতি দেয়:

class MyClass : MyLogger {
    fun myFun() {
        info("Info message")
    }
}

একটি ছোট ত্রুটি রয়েছে: প্যাকেজ-স্তরের ফাংশনে লগ করার জন্য একটি লগার বস্তুর প্রয়োজন হবে:

private object MyPackageLog : MyLogger

fun myFun() {
    MyPackageLog.info("Info message")
}

এই উত্তরটি অ্যান্ড্রয়েড নির্দিষ্ট, এবং প্রশ্নটিতে অ্যান্ড্রয়েড ট্যাগের উল্লেখ নেই বা নেই।
জেসন মিনার্ড

@ জয়নমিনার্ড এটি কেন? এই পদ্ধতির সাধারণ উদ্দেশ্য, উদাহরণস্বরূপ, প্রতিটি শ্রেণীর জন্য একটি অনন্য লগিং ট্যাগ থাকা অ অ্যান্ড্রয়েড প্রকল্পগুলিতেও কার্যকর।
হটকি

1
এটি পরিষ্কার নয় যে আপনি "আঙ্কো যা করেছিলেন তার অনুরূপ কিছু বাস্তবায়ন করছেন" এবং এর পরিবর্তে "ব্যবহার আঁকো" এর মতো মনে হচ্ছে ... যার পরে অ্যানকো নামে একটি অ্যান্ড্রয়েড লাইব্রেরি প্রয়োজন। যার ইন্টারফেস রয়েছে যার এক্সটেনশন ফাংশন রয়েছে যা android.util.Logলগিং করতে ডাকে । আপনার উদ্দেশ্য কোনটি ছিল? আনকো ব্যবহার করবেন? আনকোকে উদাহরণ হিসাবে ব্যবহার করার সময় অনুরূপ কিছু তৈরি করার বিষয়ে (যদি আপনি কেবল প্রস্তাবিত কোডটি ইনলাইন রেখে নন-অ্যান্ড্রয়েডের জন্য এটি ঠিক করেন তবে এটি "নন-অ্যান্ড্রয়েডে পোর্ট করুন, এখানে লিঙ্কটি আছে" বলার পরিবর্তে এটি ভাল। আনকোকে কল করা)
জয়সন মিনার্ড

1
@ জয়নমিনার্ড, আপনার মন্তব্যের জন্য ধন্যবাদ, আমি পোস্টটি আবার লিখেছি যাতে এটি এখন অঙ্কের উল্লেখের পরিবর্তে পদ্ধতির ব্যাখ্যা দেয়।
হটকি

6

KISS: জাভা টিমের জন্য কোটলিনে স্থানান্তরিত

যদি আপনি লগারের প্রতিটি ইনস্ট্যান্টেশনে (ঠিক জাভা এর মতো) ক্লাসের নাম সরবরাহ করতে আপত্তি না করেন, তবে আপনি আপনার প্রকল্পের কোথাও একটি শীর্ষ-স্তরের ফাংশন হিসাবে এটি সংজ্ঞায়িত করে এটিকে সহজ রাখতে পারবেন:

import org.slf4j.LoggerFactory

inline fun <reified T:Any> logger() = LoggerFactory.getLogger(T::class.java)

এটি একটি কোটলিন রিফাইড টাইপ প্যারামিটার ব্যবহার করে

এখন, আপনি নিম্নলিখিত হিসাবে এটি ব্যবহার করতে পারেন:

class SomeClass {
  // or within a companion object for one-instance-per-class
  val log = logger<SomeClass>()
  ...
}

এই পদ্ধতিরটি অতি-সহজ এবং জাভা সমতুল্যের কাছাকাছি, তবে কিছু সংশ্লেষযুক্ত চিনি যুক্ত করেছে।

পরবর্তী পদক্ষেপ: এক্সটেনশন বা প্রতিনিধিরা

আমি ব্যক্তিগতভাবে এক ধাপ এগিয়ে যেতে এবং এক্সটেনশানগুলি বা প্রতিনিধিদের পদ্ধতির ব্যবহার পছন্দ করি। এটি @ জেমনমিনার্ডের উত্তরে সুন্দরভাবে সংক্ষিপ্ত করা হয়েছে, তবে এখানে লগ 4 জ 2 এপিআই ( আপডেট) : এই কোডটি নিজে আর লেখার দরকার নেই, কারণ এটি অফিসিয়াল মডিউল হিসাবে প্রকাশিত হয়েছে বলে টিএল; ডিআর রয়েছে লগ 4 জ 2 প্রকল্প, নীচে দেখুন)। যেহেতু লগ 4j2, slf4j এর বিপরীতে লগইন সমর্থন Supplierকরে, এই পদ্ধতিগুলি আরও সহজ করে তুলতে আমি একটি প্রতিনিধি যুক্ত করেছি।

import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Logger
import org.apache.logging.log4j.util.Supplier
import kotlin.reflect.companionObject

/**
 * An adapter to allow cleaner syntax when calling a logger with a Kotlin lambda. Otherwise calling the
 * method with a lambda logs the lambda itself, and not its evaluation. We specify the Lambda SAM type as a log4j2 `Supplier`
 * to avoid this. Since we are using the log4j2 api here, this does not evaluate the lambda if the level
 * is not enabled.
 */
class FunctionalLogger(val log: Logger): Logger by log {
  inline fun debug(crossinline supplier: () -> String) {
    log.debug(Supplier { supplier.invoke() })
  }

  inline fun debug(t: Throwable, crossinline supplier: () -> String) {
    log.debug(Supplier { supplier.invoke() }, t)
  }

  inline fun info(crossinline supplier: () -> String) {
    log.info(Supplier { supplier.invoke() })
  }

  inline fun info(t: Throwable, crossinline supplier: () -> String) {
    log.info(Supplier { supplier.invoke() }, t)
  }

  inline fun warn(crossinline supplier: () -> String) {
    log.warn(Supplier { supplier.invoke() })
  }

  inline fun warn(t: Throwable, crossinline supplier: () -> String) {
    log.warn(Supplier { supplier.invoke() }, t)
  }

  inline fun error(crossinline supplier: () -> String) {
    log.error(Supplier { supplier.invoke() })
  }

  inline fun error(t: Throwable, crossinline supplier: () -> String) {
    log.error(Supplier { supplier.invoke() }, t)
  }
}

/**
 * A delegate-based lazy logger instantiation. Use: `val log by logger()`.
 */
@Suppress("unused")
inline fun <reified T : Any> T.logger(): Lazy<FunctionalLogger> =
  lazy { FunctionalLogger(LogManager.getLogger(unwrapCompanionClass(T::class.java))) }

// unwrap companion class to enclosing class given a Java Class
fun <T : Any> unwrapCompanionClass(ofClass: Class<T>): Class<*> {
  return if (ofClass.enclosingClass != null && ofClass.enclosingClass.kotlin.companionObject?.java == ofClass) {
    ofClass.enclosingClass
  } else {
    ofClass
  }
}

লগ 4 জ 2 কোটলিন লগিং এপিআই

পূর্ববর্তী অংশটির বেশিরভাগই সরাসরি কোটলিন লগিং এপিআই মডিউল উত্পাদন করতে অভিযোজিত হয়েছে , যা এখন লগ 4 জ 2 এর একটি আনুষ্ঠানিক অংশ (দাবি অস্বীকার: আমি প্রাথমিক লেখক)। আপনি এটি সরাসরি অ্যাপাচি থেকে বা মাভেন সেন্ট্রালের মাধ্যমে ডাউনলোড করতে পারেন ।

ব্যবহারটি মূলত উপরোক্ত বর্ণনা অনুসারে, তবে মডিউল উভয় ইন্টারফেস-ভিত্তিক লগার অ্যাক্সেস, যেখানে সংজ্ঞায়িত হয়েছে সেখানে ব্যবহারের জন্য একটি loggerএক্সটেনশন ফাংশন এবং যেখানে কোনও সংজ্ঞায়িত হয়নি এমন কোনও নামযুক্ত লগার ফাংশন সমর্থন করে (যেমন শীর্ষ স্তরের ফাংশন)।Anythisthis


1
যদি আমি ঠিকই বলে থাকি তবে আপনি পদ্ধতিটির স্বাক্ষরটি টি.লগার ()
আইপ্যাট

1
@ আইপ্যাট হ্যাঁ, প্রথম সমাধানটি "জাভা পথে" কাছাকাছি থাকার জন্য ইচ্ছাকৃতভাবে তা করে না। উত্তরের দ্বিতীয় অংশটি এক্সটেনশনের কেসটি জুড়ে T.logger()- কোড নমুনার নীচে দেখুন see
রমন

5

Anko

Ankoএটি করতে আপনি লাইব্রেরি ব্যবহার করতে পারেন । আপনার নীচের মত কোড থাকবে:

class MyActivity : Activity(), AnkoLogger {
    private fun someMethod() {
        info("This is my first app and it's awesome")
        debug(1234) 
        warn("Warning")
    }
}

kotlin-লগিং

কোটলিন-লগিং ( গিথুব প্রকল্প - কোটলিন-লগিং ) লাইব্রেরি আপনাকে নীচের মতো লগিং কোড লিখতে দেয়:

class FooWithLogging {
  companion object: KLogging()
  fun bar() {
    logger.info{"Item $item"}
  }
}

StaticLog

অথবা আপনি কোটলিন লাইব্রেরিতে লিখিত এই ছোট্ট লেখাটি ব্যবহার করতে পারেন StaticLogতারপরে আপনার কোডটি দেখে মনে হবে:

Log.info("This is an info message")
Log.debug("This is a debug message")
Log.warn("This is a warning message","WithACustomTag")
Log.error("This is an error message with an additional Exception for output", "AndACustomTag", exception )

Log.logLevel = LogLevel.WARN
Log.info("This message will not be shown")\

দ্বিতীয় সমাধানটি আরও ভাল হতে পারে যদি আপনি লগিং পদ্ধতির জন্য আউটপুট ফর্ম্যাটটি নির্ধারণ করতে চান তবে:

Log.newFormat {
    line(date("yyyy-MM-dd HH:mm:ss"), space, level, text("/"), tag, space(2), message, space(2), occurrence)
}

বা ফিল্টার ব্যবহার করুন, উদাহরণস্বরূপ:

Log.filterTag = "filterTag"
Log.info("This log will be filtered out", "otherTag")
Log.info("This log has the right tag", "filterTag")

timberkt

আপনি যদি ইতিমধ্যে জ্যাক ওয়ার্টনের Timberলগিং লাইব্রেরি চেক ব্যবহার করেন timberkt

এই লাইব্রেরি টিম্বারের উপর এমন একটি এপিআই তৈরি করে যা কোটলিন থেকে সহজেই ব্যবহার করা যায়। বিন্যাসকরণের পরামিতিগুলি ব্যবহার করার পরিবর্তে, আপনি একটি ল্যাম্বডা পাস করেন যা কেবলমাত্র বার্তাটি লগ করা থাকলে তা মূল্যায়ন করা হয়।

কোড উদাহরণ:

// Standard timber
Timber.d("%d %s", intVar + 3, stringFun())

// Kotlin extensions
Timber.d { "${intVar + 3} ${stringFun()}" }
// or
d { "${intVar + 3} ${stringFun()}" }

এছাড়াও চেক করুন: কোটলিন ও অ্যান্ড্রয়েডে লগিং: আনকোলগার বনাম কোটলিন-লগিং

আশা করি এটি সাহায্য করবে


4

আপনার জন্য এই কাজ কিছু চাই?

class LoggerDelegate {

    private var logger: Logger? = null

    operator fun getValue(thisRef: Any?, property: KProperty<*>): Logger {
        if (logger == null) logger = Logger.getLogger(thisRef!!.javaClass.name)
        return logger!!
    }

}

fun logger() = LoggerDelegate()

class Foo { // (by the way, everything in Kotlin is public by default)
    companion object { val logger by logger() }
}

1
এই উত্তরের আরও ব্যাখ্যার প্রয়োজন, যদি জিজ্ঞাসা করা ব্যক্তি যদি সহকর্মী অবজেক্টগুলি বুঝতে না পারে তবে তারা সম্ভবত প্রতিনিধিদের কাছে পৌঁছায়নি, এবং তাই এটি জানেন না যে এটি কী করছে। এছাড়াও এই মডেলটি ব্যবহার করে কোডের খুব কম সঞ্চয় রয়েছে is এবং আমি সন্দেহ করি যে সহযোগী অবজেক্টে থাকা ক্যাচিংটি অ্যান্ড্রয়েডের মতো ছোট সিপিইউ সহ একটি সীমাবদ্ধ ব্যবস্থার চেয়ে অন্য কোনও পারফরম্যান্স লাভ।
জেইসন মিনার্ড

1
উপরের এই কোডটি যা দেখায় তা হ'ল একটি শ্রেণি তৈরি করা যা ডেলিগেট হিসাবে কাজ করে (দেখুন কোটলিংলং.আর.ডোকস / রেফারেন্স / ডেলিগেটেড- প্রপার্টি.চটিএমএল ) যা প্রথম শ্রেণি LoggerDelegate এবং তারপরে এটি একটি শীর্ষ স্তরের ফাংশন তৈরি করছে যা তৈরি করছে প্রতিনিধিটির উদাহরণ তৈরি করা সহজ (খুব সহজ নয়, তবে কিছুটা)। এবং যে ফাংশন হতে হবে পরিবর্তন করা উচিত inline। তারপরে এটি কোনও প্রতিনিধি যখনই চাইবে কোনও লগার সরবরাহ করতে প্রতিনিধি ব্যবহার করে। তবে এটি সঙ্গীর Foo.Companionজন্য সরবরাহ করে এবং ক্লাসের জন্য নয় Fooতাই উদ্দেশ্য অনুসারে নয়।
জেইসন মিনার্ড

@ জয়নমিনার্ড আমি সম্মত তবে আমি উত্তরটি ভবিষ্যতের দর্শকদের জন্য ছেড়ে দেব যারা "দ্রুত সমাধান" বা তাদের নিজস্ব প্রকল্পগুলিতে কীভাবে এটি প্রয়োগ করতে পারে তার একটি উদাহরণ চাই। কোনও ল্যাম্বডাস উপস্থিত logger()না inlineথাকলে ফাংশনটি কেন হওয়া উচিত তা আমি বুঝতে পারি না । : IntelliJ এই ক্ষেত্রে ইনলাইনিং পরামর্শ অপ্রয়োজনীয় i.imgur.com/YQH3NB1.png
Jire

1
আমি আপনার উত্তরটি আমার মধ্যে অন্তর্ভুক্ত করেছি এবং কাস্টম প্রতিনিধি শ্রেণি সরিয়ে এটি সরল করে দিয়েছি এবং এর Lazyপরিবর্তে একটি মোড়ক ব্যবহার করেছি। এটি কোন শ্রেণীর মধ্যে রয়েছে তা এটি জানতে একটি কৌশল সহ।
জেইসন মিনার্ড

1

আমি এই বিষয়ে কোন বুদ্ধিমান কথা শুনেছি। আরও সহজতর, তাই আমি একটি শীর্ষ স্তরের সম্পত্তি ব্যবহার করব

val logger = Logger.getLogger("package_name")

এই অনুশীলনটি পাইথনে ভালভাবে কাজ করে, এবং কোটলিন এবং পাইথন যতই আলাদা হতে পারে, আমি বিশ্বাস করি তারা সেখানে "স্পিরিট" (মূর্খতার কথা বলার ক্ষেত্রে) সাথে বেশ মিল রয়েছে।


শীর্ষ-স্তরটি প্যাকেজ-স্তর হিসাবেও পরিচিত।
Caelum

একটি শীর্ষ স্তরের ভেরিয়েবলটি "গ্লোবাল ভেরিয়েবলগুলি ব্যবহার করুন" বলার মতো এবং আমি মনে করি কেবলমাত্র তখনই প্রযোজ্য হবে যদি আপনার অন্য শীর্ষ স্তরের ফাংশন থাকে যা লগার ব্যবহার করার প্রয়োজন ছিল। যদিও এই মুহুর্তে, লগ-ইন করতে চাইলে যে কোনও ইউটিলিটি ফাংশনে লগারে প্রবেশ করা ভাল।
জেইসন মিনার্ড

1
@ জেসনমিনার্ড আমি মনে করি পরামিতি হিসাবে লগারটি পাস করা একটি অ্যান্টি-প্যাটার্ন হতে পারে, কারণ আপনার লগিং কখনই আপনার এপিআই, বাহ্যিক বা অভ্যন্তরীণকে প্রভাবিত করবে না
ভদদান

ঠিক আছে, তারপরে আমার পয়েন্টে ফিরে আসুন, ক্লাস স্তরের লগিংয়ের জন্য লগারটি ক্লাসে রাখুন, কোনও শীর্ষ স্তরের ফাংশন নয়।
জেইসন মিনার্ড

1
@ ভোডদান কমপক্ষে আপনি কোন ধরণের লগার তৈরি করছেন তার একটি সম্পূর্ণ উদাহরণ সরবরাহ করুন। val log = what?!? ... নাম দিয়ে লগার তৈরি করছেন? প্রশ্নটি উপেক্ষা করে দেখা গেল যে তিনি একটি নির্দিষ্ট শ্রেণির জন্য একটি লগার তৈরি করতে চেয়েছিলেনLoggerFactory.getLogger(Foo.class);
জয়সন মিনার্ড

1

পরিবর্তে ক্লাসে একটি এক্সটেনশন ফাংশন সম্পর্কে কী? এইভাবে আপনি শেষ:

public fun KClass.logger(): Logger = LoggerFactory.getLogger(this.java)

class SomeClass {
    val LOG = SomeClass::class.logger()
}

দ্রষ্টব্য - আমি এটি মোটেও পরীক্ষা করে দেখিনি, তাই এটি সম্ভবত সঠিক নাও হতে পারে।


1

প্রথমত, আপনি লগার তৈরির জন্য এক্সটেনশন ফাংশন যুক্ত করতে পারেন।

inline fun <reified T : Any> getLogger() = LoggerFactory.getLogger(T::class.java)
fun <T : Any> T.getLogger() = LoggerFactory.getLogger(javaClass)

তারপরে আপনি নীচের কোডটি ব্যবহার করে লগার তৈরি করতে সক্ষম হবেন।

private val logger1 = getLogger<SomeClass>()
private val logger2 = getLogger()

দ্বিতীয়ত, আপনি একটি ইন্টারফেস সংজ্ঞায়িত করতে পারেন যা একটি লগার এবং এর মেশিন বাস্তবায়ন সরবরাহ করে।

interface LoggerAware {
  val logger: Logger
}

class LoggerAwareMixin(containerClass: Class<*>) : LoggerAware {
  override val logger: Logger = LoggerFactory.getLogger(containerClass)
}

inline fun <reified T : Any> loggerAware() = LoggerAwareMixin(T::class.java)

এই ইন্টারফেসটি নিম্নলিখিত উপায়ে ব্যবহার করা যেতে পারে।

class SomeClass : LoggerAware by loggerAware<SomeClass>() {
  // Now you can use a logger here.
}

1

সহযোগী অবজেক্ট তৈরি করুন এবং @ জভিএমস্ট্যাটিক টীকা সহ উপযুক্ত ক্ষেত্রগুলি চিহ্নিত করুন


1

এখানে ইতিমধ্যে অনেক দুর্দান্ত উত্তর রয়েছে, তবে এগুলির সমস্তই ক্লাসে লগার যুক্ত করার বিষয়ে উদ্বেগ প্রকাশ করে, তবে শীর্ষ স্তরের ফাংশনে লগিং করতে আপনি কীভাবে তা করবেন?

এই পদ্ধতির জেনেরিক এবং উভয় শ্রেণিতে, সহচর অবজেক্ট এবং শীর্ষ স্তরের ক্রিয়াকলাপে ভাল কাজ করার জন্য যথেষ্ট সহজ:

package nieldw.test

import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Logger
import org.junit.jupiter.api.Test

fun logger(lambda: () -> Unit): Lazy<Logger> = lazy { LogManager.getLogger(getClassName(lambda.javaClass)) }
private fun <T : Any> getClassName(clazz: Class<T>): String = clazz.name.replace(Regex("""\$.*$"""), "")

val topLog by logger { }

class TopLevelLoggingTest {
    val classLog by logger { }

    @Test
    fun `What is the javaClass?`() {
        topLog.info("THIS IS IT")
        classLog.info("THIS IS IT")
    }
}

0

সাধারনত জিনিসগুলির জন্য এটি সাধারণভাবে: স্থির স্টাফগুলি প্রতিস্থাপন।


কোনও সহকর্মী অবজেক্ট স্ট্যাটিক নয়, এটি এমন একক সিঙ্গল যা সদস্যদের ধরে রাখতে পারে যা আপনি JvmStaticটীকা ব্যবহার করলে স্থির হয়ে উঠতে পারে । এবং ভবিষ্যতে একাধিকের অনুমতি থাকতে পারে। প্লাস এই উত্তরটি আরও তথ্য বা নমুনা ছাড়াই খুব সহায়ক নয়।
জেইসন মিনার্ড

আমি এটি স্থির ছিল না। আমি বলেছিলাম এটি স্ট্যাটিক্স প্রতিস্থাপনের জন্য। এবং কেন সেখানে একাধিক অনুমতি দেওয়া হবে? এটা বোঝা যায় না। শেষ অবধি, আমি খুব তাড়াহুড়ো করেছিলাম এবং আমি ভেবেছিলাম যে সঠিক দিকে নির্দেশ করা যথেষ্ট সহায়ক হবে।
জ্যাকব জিমারম্যান

1
কোনও সহযোগী অবজেক্ট স্ট্যাটিক্স প্রতিস্থাপনের জন্য নয়, তবে এটি এর উপাদানগুলিও স্থিতিশীল করতে পারে। কোটলিন এক সময়ের জন্য সহচরদের চেয়ে বেশি সমর্থন করেছিল এবং তাদের অন্য নাম রাখতে দেয়। একবার আপনি তাদের নামকরণ শুরু করলে তারা স্ট্যাটিক্সের মতো কম কাজ করে। এবং ভবিষ্যতে এটি একাধিক নামী সহকর্মী থাকা খোলা রয়েছে। উদাহরণস্বরূপ, একজন হতে পারে Factoryএবং অন্যটি হতে পারেHelpers
জয়সন মিনার্ড

0

Slf4j উদাহরণ, অন্যদের জন্য একই। এটি প্যাকেজ স্তর লগার তৈরি করার জন্যও কাজ করে

/**  
  * Get logger by current class name.  
  */ 

fun getLogger(c: () -> Unit): Logger = 
        LoggerFactory.getLogger(c.javaClass.enclosingClass)

ব্যবহার:

val logger = getLogger { }

0
fun <R : Any> R.logger(): Lazy<Logger> = lazy { 
    LoggerFactory.getLogger((if (javaClass.kotlin.isCompanion) javaClass.enclosingClass else javaClass).name) 
}

class Foo {
    val logger by logger()
}

class Foo {
    companion object {
        val logger by logger()
    }
}

0

এটি এখনও ডব্লিউআইপি (প্রায় সমাপ্ত) তাই আমি এটি ভাগ করতে চাই: https://github.com/leandronunes85/log-format-enforcer#kotlin-soon-to-come-in-version-14

এই লাইব্রেরির মূল লক্ষ্যটি কোনও প্রকল্প জুড়ে একটি নির্দিষ্ট লগ স্টাইল প্রয়োগ করা। এটি কোটলিন কোড উত্পন্ন করার মাধ্যমে আমি এই প্রশ্নে উল্লিখিত কিছু সমস্যা সমাধানের চেষ্টা করছি। মূল প্রশ্নটির সাথে আমি সাধারণত যা করি তা হ'ল সহজভাবে:

private val LOG = LogFormatEnforcer.loggerFor<Foo>()
class Foo {

}

0

আপনি সহজেই ইউটিলিটিগুলির নিজস্ব "গ্রন্থাগার" তৈরি করতে পারেন। এই কাজের জন্য আপনার একটি বৃহত লাইব্রেরির দরকার নেই যা আপনার প্রকল্পটিকে ভারী এবং জটিল করে তুলবে।

উদাহরণস্বরূপ, আপনি কোনও শ্রেণীর সম্পত্তির নাম, প্রকার এবং মান পেতে কোটলিন প্রতিচ্ছবি ব্যবহার করতে পারেন।

প্রথমত, আপনার বিল্ডড্র্যাডলে মেটা-নির্ভরতা স্থির হয়েছে তা নিশ্চিত করুন:

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
}

এরপরে, আপনি কেবল আপনার প্রকল্পে এই কোডটি অনুলিপি করে কাস্ট করতে পারেন:

import kotlin.reflect.full.declaredMemberProperties

class LogUtil {
    companion object {
        /**
         * Receives an [instance] of a class.
         * @return the name and value of any member property.
         */
        fun classToString(instance: Any): String {
            val sb = StringBuilder()

            val clazz = instance.javaClass.kotlin
            clazz.declaredMemberProperties.forEach {
                sb.append("${it.name}: (${it.returnType}) ${it.get(instance)}, ")
            }

            return marshalObj(sb)
        }

        private fun marshalObj(sb: StringBuilder): String {
            sb.insert(0, "{ ")
            sb.setLength(sb.length - 2)
            sb.append(" }")

            return sb.toString()
        }
    }
}

ব্যবহারের উদাহরণ:

data class Actor(val id: Int, val name: String) {
    override fun toString(): String {
        return classToString(this)
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.