स्काला में प्रवेश कर रहा है


168

स्केल एप्लिकेशन में लॉगिंग करने का एक अच्छा तरीका क्या है? भाषा दर्शन के अनुरूप कुछ, कोड को अव्यवस्थित नहीं करता है, और कम-रखरखाव और विनीत है। यहाँ एक बुनियादी आवश्यकता सूची है:

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

मुझे पता है कि मैं मौजूदा जावा लॉगिंग समाधानों का उपयोग कर सकता हूं, लेकिन वे अव्यवस्था और कॉन्फ़िगरेशन के ऊपर, कम से कम दो पर विफल होते हैं।

आपके उत्तर के लिए धन्यवाद।

जवाबों:


119

slf4j रैपर

जावा लॉगिंग फ्रेमवर्क (slf4j, log4j आदि) के आसपास स्काला की अधिकांश लॉगिंग लाइब्रेरी कुछ रैपर रही हैं, लेकिन मार्च 2015 तक, लॉग लॉग लाइब्रेरी सभी slf4j हैं। ये लॉग लाइब्रेरी कुछ प्रकार की logवस्तु प्रदान करते हैं info(...), जिस पर आप कॉल कर सकते हैं , debug(...)आदि। मैं slf4j का बहुत बड़ा प्रशंसक नहीं हूं, लेकिन अब यह मुख्य लॉगिंग फ्रेमवर्क प्रतीत होता है। यहाँ SLF4J का वर्णन है :

जावा या SLF4J के लिए सरल लॉगिंग मुखौटा विभिन्न लॉगिंग फ्रेमवर्क के लिए एक साधारण मुखौटा या अमूर्त के रूप में कार्य करता है, जैसे java.util.log, log4j और लॉगबैक, अंतिम उपयोगकर्ता को तैनाती के समय वांछित लॉगिंग फ्रेमवर्क में प्लग करने की अनुमति देता है।

तैनाती के समय अंतर्निहित लॉग लाइब्रेरी को बदलने की क्षमता, लॉगर के पूरे slf4j परिवार के लिए अद्वितीय विशेषता लाती है, जिसके बारे में आपको जानकारी होनी चाहिए:

  1. विन्यास दृष्टिकोण के रूप में क्लासपाथ । जिस तरह से slf4j को पता है कि आप किस लॉगिंग लाइब्रेरी का उपयोग कर रहे हैं, वह किसी नाम से एक वर्ग लोड करके है। मेरे पास ऐसे मुद्दे हैं जिनमें slf4j मेरे लकड़हारे को पहचान नहीं रहा है जब क्लास लोडर को अनुकूलित किया गया था।
  2. क्योंकि साधारण मुखौटा आम भाजक होने की कोशिश करता है, यह केवल वास्तविक लॉग कॉल तक सीमित है। दूसरे शब्दों में, कॉन्फ़िगरेशन कोड के माध्यम से नहीं किया जा सकता है।

एक बड़ी परियोजना में, यह वास्तव में सुविधाजनक हो सकता है कि यदि सभी लोग slf4j का उपयोग करते हैं तो सकर्मक निर्भरता के लॉगिंग व्यवहार को नियंत्रित करने में सक्षम हों।

स्केल लॉगिंग

स्काला लॉगिंग को हेइको सीबर्गर ने अपने slf4s के उत्तराधिकारी के रूप में लिखा है । यदि संभावित रूप से महंगी लॉग कॉल से बचने के लिए यह कॉल का विस्तार करने के लिए मैक्रो का उपयोग करता है।

स्काला लॉगिंग एक सुविधाजनक और प्रदर्शनकारी लॉगिंग लाइब्रेरी है जिसमें एसएलएफ 4 जे और संभावित अन्य जैसे लॉगिंग लाइब्रेरी शामिल हैं।

ऐतिहासिक लकड़हारे

  • लोगुला , कोडा हेल द्वारा लिखित एक Log4J आवरण। इस एक को पसंद करते थे, लेकिन अब इसे छोड़ दिया गया है।
  • config , एक java.util.log आवरण जो पहले स्केल के दिनों में लोकप्रिय हुआ करता था। अब छोड़ दिया।

1
कहते हैं, मैं लोगुला से प्यार करता हूं ... आखिरकार एक लकड़हारा जो मुझे अपना कान छिदवाना नहीं चाहता। कोई xml और कोई बीएस नहीं, बस स्टार्टअप पर एक स्कैला
कॉन्फिगरेशन

हेइको सीबर्गर का SLF4S अब नहीं बना हुआ है। मैंने अपना लक्ष्य स्कैला 2.10 और नवीनतम SLF4J बनाया। http://slf4s.org/
मैट रॉबर्ट्स

3
लोगुथ को इसके README के ​​अनुसार गितुब पर छोड़ दिया गया है।
एरिक कप्लून

ऑनक्यूफ़ जर्नल स्काला लॉगिंग की अवधारणा के समान है, लेकिन लॉग संदेश एक अभिनेता को भेजे जाते हैं, जो समर्पित थ्रेड पूल से SLF4J कहता है। सीपीयू समय (बहुत बेहतर) विलंबता के लिए। github.com/onoscope/journal
गैरी कूडी जूल

64

स्केला 2.10+ के साथ टाइपसेफ द्वारा स्कैलेगॉगिंग पर विचार करें। बहुत साफ एपीआई देने के लिए मैक्रोज़ का उपयोग करता है

https://github.com/typesafehub/scala-logging

उनकी विकि से उद्धरण:

सौभाग्य से स्काला मैक्रोज़ का उपयोग हमारे जीवन को आसान बनाने के लिए किया जा सकता है: स्लैलॉगिंग क्लास Loggerको हल्के लॉगिंग विधियों के साथ प्रदान करता है जो उपरोक्त मुहावरे तक विस्तारित होंगे। तो हम सब को लिखना है:

logger.debug(s"Some ${expensiveExpression} message!")

मैक्रो लागू होने के बाद, कोड को ऊपर वर्णित मुहावरे में बदल दिया गया होगा।

इसके अलावा, स्कैलागिंग विशेषता प्रदान करता है, Loggingजो आसानी से एक Loggerउदाहरण प्रदान करता है जिसे वर्ग के नाम के साथ आरंभ किया जाता है:

import com.typesafe.scalalogging.slf4j.LazyLogging

class MyClass extends LazyLogging {
  logger.debug("This is very convenient ;-)")
}

12
का उपयोग करें class MyClass with Logging
आंद्रेज जोजविक

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

1
इसका मतलब यह है कि MyClass के पास डिबग, जानकारी चेतावनी आदि के लिए सार्वजनिक तरीके हैं? यदि ऐसा है, तो मैं एक लकड़हारा निजी को कक्षा में लाने के लिए अतिरिक्त मैनुअल काम करता हूँ। लॉगिंग विधियों को एक वर्ग इंटरफ़ेस में लीक नहीं करना चाहिए।
चुक्का

2
आपको एक लकड़हारा क्षेत्र मिलता है, जिसका उपयोग आप अपने आराम से कर सकते हैं। देखें github.com/typesafehub/scalalogging/blob/master/... जानकारी के लिए
fracca

2
2.x को Scala 2.11 की आवश्यकता होती है; उम्मीद है कि बहुत व्यावहारिक अंतर नहीं है; Scala 2.10.x के लिए, वहाँ है "com.typesafe" %% "scalalogging-slf4j" % "1.1.0"
एरिक कपलुन

14

Slf4j और एक आवरण का उपयोग करना अच्छा है, लेकिन इसका उपयोग प्रक्षेप में निर्मित होता है, जब आपको प्रक्षेप करने के लिए दो से अधिक मान होते हैं, तब से आपको प्रक्षेप करने के लिए मानों का एक सरणी बनाने की आवश्यकता होती है।

समाधान की तरह एक अधिक स्काला त्रुटि संदेश के विलंब को रोकने के लिए एक थंक या क्लस्टर का उपयोग करना है। इसका एक अच्छा उदाहरण है लिफ्ट का लकड़हारा

Log.scala Slf4jLog.scala

जो इस तरह दिखता है:

class Log4JLogger(val logger: Logger) extends LiftLogger {
  override def trace(msg: => AnyRef) = if (isTraceEnabled) logger.trace(msg)
}

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

यदि आपके पास एक अलग विशेषता है जो इस Log4JLogger को आपकी कक्षा में मिलाती है, तो आप कर सकते हैं

trace("The foobar from " + a + " doesn't match the foobar from " +
      b + " and you should reset the baz from " + c")

के बजाय

info("The foobar from {0} doesn't match the foobar from {1} and you should reset the baz from {c},
     Array(a, b, c))

2
क्या scala classes में स्टेटमेंट लॉग करने के लिए सटीक लाइन नंबर प्राप्त करना संभव है ?????
jpswain

13

लोगुला का उपयोग न करें

मैंने वास्तव में यूजीन की सिफारिश का पालन किया है और इसकी कोशिश की है और पता चला है कि इसका एक अनाड़ी विन्यास है और यह बग के अधीन है, जो तय नहीं किया जाता है (जैसे कि यह एक )। यह अच्छी तरह से बनाए रखा नहीं दिखता है और यह स्कैला 2.10 का समर्थन नहीं करता है

Slf4s + slf4j-simple का प्रयोग करें

प्रमुख लाभ:

  • नवीनतम स्काला 2.10 का समर्थन करता है (आज तक यह M7 है)
  • कॉन्फ़िगरेशन बहुमुखी है, लेकिन सरल नहीं हो सकता। यह सिस्टम के गुणों के साथ किया जाता है , जिसे आप -Dorg.slf4j.simplelogger.defaultlog=traceअपनी स्क्रिप्ट में कमांड या हार्डकोड को निष्पादित करने के लिए कुछ करके जोड़ सकते हैं System.setProperty("org.slf4j.simplelogger.defaultlog", "trace"):। ट्रैश कॉन्फिग फाइल को मैनेज करने की जरूरत नहीं है!
  • IDEs के साथ अच्छी तरह से फिट बैठता है। उदाहरण "का पता लगाने" आईडिया में एक विशिष्ट रन विन्यास में करने के लिए लॉगिंग स्तर सेट करने के लिए बस के लिए जाना Run/Debug Configurationsऔर जोड़ने -Dorg.slf4j.simplelogger.defaultlog=traceके लिए VM options
  • आसान सेटअप: बस इस उत्तर के नीचे से निर्भरता में गिरावट

यहां आपको मावेन के साथ इसे चलाने की आवश्यकता है:

<dependency>
  <groupId>com.weiglewilczek.slf4s</groupId>
  <artifactId>slf4s_2.9.1</artifactId>
  <version>1.0.7</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-simple</artifactId>
  <version>1.6.6</version>
</dependency>

आपको slf4s कहाँ मिलता है जो 2.10 का समर्थन करता है? मैं github.com/weiglewilczek/slf4s देख रहा हूं और देखता हूं "समर्थित स्कैला संस्करण 2.8.0, 2.8.1, 2.9.0-1 और 2.9.1 हैं।" .. क्या मेरी तलाश गलत स्थान पर हो रही है?
नर्बव

@ ब्रायन 2.9.1 का उपयोग करें जैसा कि उत्तर में दिया गया है। मैंने इसे 2.10.0-M7 के साथ ठीक काम करने के लिए परीक्षण किया है
निकिता वोल्कोव

मैं 2.9.1 का उपयोग कर रहा हूं, मैं केवल हाइलाइट किए गए "महत्वपूर्ण लाभ" के बारे में उत्सुक था और इसका क्या मतलब है।
nairbv

लॉगिंग पुस्तकालयों के पेशेवरों और विपक्षों के जवाबों को ध्यान से खोजने के बाद, मैं वह चुनता हूं जो मुझे बताता है कि आयात करने के लिए क्या निर्भरता है। धन्यवाद महोदय।
टेओ

11

यह मेरे लिए स्कैला लॉगिंग का काम है

इसे अपने में रखें build.sbt:

libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.7.2",
libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.2.3"

फिर, एक करने के बाद sbt update, यह एक अनुकूल लॉग संदेश प्रिंट करता है:

import com.typesafe.scalalogging._
object MyApp extends App with LazyLogging {
  logger.info("Hello there")
}

यदि आप Play का उपयोग कर रहे हैं, तो आप बस import play.api.Loggerलॉग संदेश लिखने के लिए कर सकते हैं Logger.debug("Hi"):।

अधिक जानकारी के लिए डॉक्स देखें ।


log4j.propertiesप्रोजेक्ट संसाधन फ़ोल्डर के अंदर बनाने के बाद ही मेरे लिए काम किया ।
नदजीब ममी

7

मैं काम का एक सा फार्म खींच लिया Loggingकी विशेषता scalaxहै, और बनाया एक विशेषता है कि यह भी एक एकीकृतMessageFormat-based पुस्तकालय।

फिर सामान की तरह लग रहा है:

class Foo extends Loggable {
    info( "Dude, I'm an {0} with {1,number,#}", "Log message", 1234 )
}

हम अब तक के दृष्टिकोण को पसंद करते हैं।

कार्यान्वयन:

trait Loggable {

    val logger:Logger = Logging.getLogger(this)

    def checkFormat(msg:String, refs:Seq[Any]):String =
        if (refs.size > 0) msgfmtSeq(msg, refs) else msg 

    def trace(msg:String, refs:Any*) = logger trace checkFormat(msg, refs)

    def trace(t:Throwable, msg:String, refs:Any*) = logger trace (checkFormat(msg, refs), t)

    def info(msg:String, refs:Any*) = logger info checkFormat(msg, refs)

    def info(t:Throwable, msg:String, refs:Any*) = logger info (checkFormat(msg, refs), t)

    def warn(msg:String, refs:Any*) = logger warn checkFormat(msg, refs)

    def warn(t:Throwable, msg:String, refs:Any*) = logger warn (checkFormat(msg, refs), t)

    def critical(msg:String, refs:Any*) = logger error checkFormat(msg, refs)

    def critical(t:Throwable, msg:String, refs:Any*) = logger error (checkFormat(msg, refs), t)

}

/**
 * Note: implementation taken from scalax.logging API
 */
object Logging {  

    def loggerNameForClass(className: String) = {  
        if (className endsWith "$") className.substring(0, className.length - 1)  
        else className  
    }  

    def getLogger(logging: AnyRef) = LoggerFactory.getLogger(loggerNameForClass(logging.getClass.getName))  
}

प्यारा, हालांकि मुझे काम करने के लिए कुछ मुद्दे मिल रहे हैं - विशेष रूप से, आउटपुट (डिफ़ॉल्ट slf4j कॉन्फ़िगरेशन पर) हमेशा निम्न की तरह कुछ दिखता है, इसके बजाय वर्ग वास्तव में लॉगगबल का विस्तार कर रहा है: Jul 22, 2011 3:02:17 AM redacted.util.oggable $ वर्ग की जानकारी जानकारी: कुछ संदेश ... कोई मौका जो आप इस में भाग गए हैं?
तोमर गेबल

6

मैं SLF4J + लॉगबैक क्लासिक का उपयोग करता हूं और इसे इस तरह लागू करता हूं:

trait Logging {
  lazy val logger = LoggerFactory.getLogger(getClass)

  implicit def logging2Logger(anything: Logging): Logger = anything.logger
}

फिर आप इसका उपयोग कर सकते हैं, जो भी आपकी शैली को बेहतर बनाता है:

class X with Logging {
    logger.debug("foo")
    debug("bar")
}

लेकिन निश्चित रूप से यह दृष्टिकोण प्रति वर्ग उदाहरण एक लकड़हारा उदाहरण का उपयोग करता है।


4

आपको स्केलक्स लाइब्रेरी पर एक नजर डालनी चाहिए: http://scalax.scalaforge.org/ इस लाइब्रेरी में, बैकिंग के रूप में sl4j का उपयोग करते हुए, एक लॉगिंग विशेषता है। इस विशेषता का उपयोग करके, आप काफी आसानी से लॉग इन कर सकते हैं (बस गुण को प्राप्त करने वाले वर्ग में लकड़हारा क्षेत्र का उपयोग करें)।


4

Writer, Monoidऔर एक Monadकार्यान्वयन।


5
क्या आप समझा सकते हैं कि आपका क्या मतलब है?
डेविड जे।

उन लोगों का संयोजन आपके परिणाम के लिए एक अच्छा "लॉग" बना सकता है। IMO, यह थोड़ा अधिक ओवरकिल है। लेकिन अगर आप कुछ नया सीखने के लिए करना चाहते हैं blog.tmorris.net/the-writer-monad-using-scala-example
टीजी।

@Tg। आपकी टिप्पणी में लिंक मृत है। का प्रयोग करें blog.tmorris.net/posts/the-writer-monad-using-scala-example
jub0bs


3

त्वरित और आसान रूप।

स्केला 2.10 और पुराने:

import com.typesafe.scalalogging.slf4j.Logger
import org.slf4j.LoggerFactory
val logger = Logger(LoggerFactory.getLogger("TheLoggerName"))
logger.debug("Useful message....")

और build.sbt:

libraryDependencies += "com.typesafe" %% "scalalogging-slf4j" % "1.1.0"

स्केल 2.11+ और नया:

import import com.typesafe.scalalogging.Logger
import org.slf4j.LoggerFactory
val logger = Logger(LoggerFactory.getLogger("TheLoggerName"))
logger.debug("Useful message....")

और build.sbt:

libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.1.0"

2

थोड़ी देर के लिए slf4s और logula का उपयोग करने के बाद, मैंने लिखा loglady , slf4j को लपेटने वाला एक सरल लॉगिंग गुण।

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

http://github.com/dln/loglady/


2

मुझे कुछ प्रकार के जावा लॉगर का उपयोग करना बहुत सुविधाजनक लगता है, उदाहरण के लिए sl4j, सरल स्कैला आवरण के साथ, जो मुझे इस तरह के वाक्यविन्यास को लाता है।

val #! = new Logger(..) // somewhere deep in dsl.logging.

object User with dsl.logging {

  #! ! "info message"
  #! dbg "debug message"
  #! trace "var a=true"

}

मेरी राय में जावा साबित लॉगिंग फ्रेमवर्क और स्काला के फैंसी सिंटैक्स के बहुत उपयोगी मिश्रण।


@ चचा, ओह, हाँ। माफ़ करना। मैं लगभग भूल गया हूं। यह कुछ दिनों के लिए इस मुद्दे पर एक महान लड़ाई थी, लेकिन ऐसा लगता है कि यह वास्तव में असंभव है। मैंने # इस्तेमाल किया है! ! इसके बजाय "सूचना संदेश"। मैं अपना उत्तर संपादित करूँगा।
एलेक्स पोवर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.