logback官方文檔中文翻譯第十二章:Groovy 配置

第十二章:Groovy 配置

領(lǐng)域特定語言或者 DSL 更加普遍。logback 基于 XML 的配置可以看做 DSL 的實例厂榛。由于 XML 的本質(zhì)粤策,基于 XML 的配置文件變得非常的啰嗦以及臃腫。另外湿故,logback 中的 Joran 有一個相對龐大的代碼蟆炊,用來專門處理基于 XML 的配置文件稽莉。Joran 支持一些非常好的特性,例如變量替換涩搓,條件處理污秆,以及動態(tài)擴展。但是昧甘,不但 Joran 非常復(fù)雜良拼,而且給用戶的體驗非常的不好,或者至少不直觀充边。

本章敘述基于 Groovy 的 DSL 致力于一致性庸推,直觀性,以及非常強大浇冰。任何你可以使用 XML 配置的文件贬媒,你都可以用更加簡短的符號使用 Groovy 來實現(xiàn)。

常規(guī)建議

一般來說肘习,logback.groovy 文件是 Groovy 程序际乘。因為 Groovy 是 Java 的超集,所以無論你在 Java 執(zhí)行什么配置操作漂佩,你都可以在 logback.groovy 文件中做同樣的事情脖含。但是,在 Java 中投蝉,使用變成的方式配置 logback 有點笨重养葵,所以我們增加了一些 logback 特有的擴展來減輕你的負(fù)擔(dān)。我們嘗試限制 logback 特有的拓展符號盡量的少瘩缆。如果你已經(jīng)熟悉了 Groovy关拒,那么你應(yīng)該更加容易去讀,去理解甚至去寫你自己的 logback.groovy 文件。那么不熟悉 Groovy 的人依然會發(fā)現(xiàn) logback.groovy 中的語法比 logback.xml 中的語法更加容易使用夏醉。

logback.groovy 文件是 Groovy 程序,具有最小的 logback 特定的拓展涌韩。所有常用的 groovy 結(jié)構(gòu)畔柔,例如類的導(dǎo)入,變量定義臣樱,字符串 (GString) 中包含 ${..} 評估表達式靶擦,以及 if-else 語句在 logback.grooby 文件中都是可用的。

自動導(dǎo)入

1.0.10 版本以后 為了減少不必要的引用雇毫,一些共同的類以及包會被自動導(dǎo)入玄捕。因此,只要你只是配置了內(nèi)置的 appender棚放,layout 等等枚粘,你不需要在你的腳本中添加相對應(yīng)的導(dǎo)入語句。當(dāng)然飘蚯,對于默認(rèn)導(dǎo)入不會涉及到類馍迄,你需要自己導(dǎo)入。

下面是默認(rèn)導(dǎo)入的列表:

  • import ch.qos.logback.core.*;
  • import ch.qos.logback.core.encoder.*;
  • import ch.qos.logback.core.read.*;
  • import ch.qos.logback.core.rolling.*;
  • import ch.qos.logback.core.status.*;
  • import ch.qos.logback.classic.net.*;
  • import ch.qos.logback.classic.encoder.PatternLayoutEncoder;

另外局骤,ch.qos.logback.classic.Level 中的所有常量 (大寫) 都會被靜態(tài)導(dǎo)入,以及小寫的別名峦甩。也就是說在你的腳本中可以引用 INFO 以及 info赘来,而不需要使用靜態(tài)導(dǎo)入語句。

不再支持 SiftingAppender

1.0.12 版本以后 在 groovy 配置文件中不再支持 SiftingAppender凯傲。但是犬辰,如果有需要,可以重新引進泣洞。

logback.groovy 特定的拓展

本質(zhì)上忧风,logback.groovy 語法包含以下所說的六個方法;按照它們習(xí)慣上相反的順序出現(xiàn)球凰。嚴(yán)格來說狮腿,這些方法的調(diào)用順序并重要,但是有一個例外:appender 附加到 logger 之前必須**被定義呕诉。

  • root(Level level, List<String> appenderNames = [])

root 方法可以用來設(shè)置 root logger 的日志級別缘厢。第二個可選參數(shù)的類型為 List<String>,可以用來添加之前定義的 appender 的名字甩挫。如果你不想指定 appenderNames贴硫,那么就是一個空 (empty) 的列表。在 Groovy 中,用 [] 表示一個空的列表英遭。

設(shè)置 root logger 的級別為 WARN间护,你可以這樣寫:

root(WARN)

設(shè)置 root logger 的級別為 INFO,并且將名為 "CONSOLE" 與 "FILE" 的 appender 附加到 root 上挖诸,你可以這樣寫:

root(INFO, ["CONSOLE", "FILE"])

在前面的例子中汁尺,假設(shè)名為 "CONSOLE" 與 "FILE" 的 appender 已經(jīng)被定義好了。很快將會討論有關(guān) appender 的定義多律。

  • logger(String name, Level level, List<String> appenderNames = [], Boolean additivity = null)

logger() 方法接收四個參數(shù)痴突,最后兩個是可選的。第一個參數(shù)表示配置 logger 的名字狼荞。第二參數(shù)表示指定 logger 的級別辽装。設(shè)置 logger 的級別為 null 將強制它從它最近的祖先那里繼承級別。第三個參數(shù)的類型為 List<String>相味,是可選的拾积,默認(rèn)為空列表。列表中 appender 會被附加到指定的 logger 上去攻走。第四個參數(shù)的類型為 Boolean殷勘,也是可選的,用來控制疊加性昔搂。如果忽略玲销,默認(rèn)值為 null

例如摘符,下面這個腳本設(shè)置 "com.foo" 這個 logger 的級別為 INFO:

logger("com.foo", INFO)

下個腳本設(shè)置 "com.foo" 這個 logger 的級別為 DEBUG贤斜,并且將名為 "CONSOLE" 的 appender 附加到其上:

logger("com.foo", DEBUG, ["CONSOLE"])

下個腳本跟上一個類似,只是這個還設(shè)置了 "com.foo" 這個 logger 的疊加性為 false:

logger("com.foo", DEBUG, ["CONSOLE"]逛裤,false)
  • appender(String name, Class clazz, Closure closure = null)

appender 方法的第一個參數(shù)接收 appender 的名字進行配置瘩绒。第二個參數(shù)是強制的,表示 appender 實例化的類带族。第三個參數(shù)包含更多的配置信息锁荔。如果忽略,默認(rèn)為 null蝙砌。

大部分 appender 都需要設(shè)置屬性阳堕,并且注入子組件才能正常工作。屬性通過 '=' 進行設(shè)置择克。子組件的注入通過調(diào)用以屬性命名的方法恬总,并且將實例化的類作為參數(shù)傳遞給該方法。這個約定可以被遞歸的應(yīng)用到配置的屬性以及任何 appender 子組件的子組件中肚邢。這個方法是 logback.groovy 的核心壹堰,可能是唯一需要去學(xué)習(xí)的約定拭卿。

例如,接下來的腳本實例化一個 FileAppender 命名為 "FILE"贱纠,設(shè)置它的 file 屬性為 "testFile.log"峻厚,以及它的 append 屬性設(shè)置為 false。類型為 PatternLayoutEncoder 的 encoder 被注入到這個 appender 中谆焊。encoder 的模式屬性設(shè)置為 "%level %logger - %msg%n"目木。然后將這個 appender 附加到 root logger 上。

appender("FILE", FileAppender) {
    file = "testFile.log"
    append = false
    encoder(PatternLayoutEncoder) {
        pattern = "%level %logger - %msg%n"
    }
}

root(DEBUG, ["FILE"])
  • timestamp(String datePattern, long timeReference = -1)

timestamp() 方法根據(jù) datePatterntimeReference 參數(shù)格式化懊渡,返回一個對應(yīng)的字符串。datePattern 參數(shù)應(yīng)該尊村SimpleDateFormat中定義的約定军拟。如果 timeReference 沒有指定剃执,那么默認(rèn)為 -1。在這種情況下懈息,當(dāng)解析配置文件時肾档,當(dāng)前時間作為 timeReference 參數(shù)的值。

在下個例子中辫继,bySecond 變量表示被 "yyyyMMdd'T'HHmmss" 格式化之后的當(dāng)前時間怒见。之后,"bySecond" 變量被用于 file 屬性的定義中姑宽。

def bySecond = timestamp("yyyyMMdd'T'HHmmss")

appender("FILE", FileAppender) {
    file = "log-${bySecond}.txt"
    encoder(PatternLayoutEncoder) {
        pattern = "%logger{35} - %msg%n"
    }
}

root(DEBUG, ["FILE"])
  • conversionRule(String conversionWord, Class converterClass)

在創(chuàng)建了你自己的轉(zhuǎn)換說明符之后遣耍,你需要通知 logback 它的存在。下面這個簡單的 logback.groovy 文件告訴 logback 在遇到 %sample 轉(zhuǎn)換字符時使用 MySampleConverter炮车。

import chapters.layouts.MySampleConverter

conversionRule("sample", MySampleConverter)
appender("STDOUT", ConsoleAppender) {
    encoder(PatternLayoutEncoder) {
        pattern = "%-4relative [%thread] %sample - %msg%n"
    }
}

root(DEBUG, ["STDOUT"])
  • scan(String scanPeriod = null)

調(diào)用 scan() 方法告訴 logback 周期性的掃描 logback.groovy 文件的變化舵变。當(dāng)檢測到變化時,logback.groovy 文件會被重新加載瘦穆。

scan()

默認(rèn)情況下纪隙,一分鐘掃描一次配置文件。你可以通過 "scanPeriod" 來指定一個不同的掃描周期扛或。它的值可以被指定以 milliseconds, seconds, minutes 或者 hours 位單位绵咱。例如:

scan("30 seconds")

如果沒有指定時間單位,那么默認(rèn)的時間單位為 milliseconds熙兔,但是通常來說是不合適的 (既然不合適悲伶,為什么默認(rèn)還是毫秒,費解??)黔姜。如果你更改了默認(rèn)的掃描周期拢切,記得要指定時間單位。更多關(guān)于掃描工作的細(xì)節(jié)秆吵,請查看自動加載部分淮椰。

  • statusListener(Class listenerClass)

你可以通過調(diào)用 statusListener 方法,并給該方法傳遞一個監(jiān)聽器類,來添加一個狀態(tài)監(jiān)聽器主穗。例:

import chapters.layouts.MySampleConverter

// 強烈建議在最后一個導(dǎo)入語句之后泻拦,其它所有語句之前添加狀態(tài)監(jiān)聽器
statusListener(OnConsoleStatusListener)

關(guān)于狀態(tài)監(jiān)聽器請查看之前的章節(jié)。

  • jmxConfigurator(String name)

你可以通過該方法注冊一個 JMXConfigurator MBean忽媒。無參調(diào)用將會使用 logback 默認(rèn)的對象名 (ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator) 去注冊 MBean争拐。

jmxConfigurator()

要改變 Name 鍵的值,而不是 "default"晦雨,僅僅只需要給 jmxConfigurator 方法傳遞一個不同的名字參數(shù)就可以了架曹。

jmxConfigurator('MyName')

如果你想要完整的定義對象名,可以使用同樣的語法闹瞧,但是需要傳遞一個有效的對象名字符串作為參數(shù):

jmxConfigurator('myApp:type=LoggerManager')

該方法首先會去嘗試將該參數(shù)作為對象名绑雄,如果它不表示一個有效的對象名,則會把它當(dāng)作 "Name" 鍵的值奥邮。

內(nèi)置 DSL

logback.groovy 是一個內(nèi)置 DSL 的意思是万牺,它的內(nèi)容可以作為 Groovy 腳本執(zhí)行。因此洽腺,所有常用的 Groovy 指令脚粟,例如類的導(dǎo)入,GString蘸朋,變量的定義核无,包含字符串 (GString) 的 ${..} 評估表達式,if-else 語句這些在 logback.groovy 文件中都是可用的藕坯。在接下來的討論中厕宗,我們將會展示 Groovy 指令在 logback.groovy 文件中的典型用法。

變量定義與 GString

你可以在 logback.groovy 文件中的任何地方定義變量堕担,然后在 GString 中使用該變量已慢。例如:

def USER_HOME = System.getProperty("user.home")

appender("FILE", FileAppender) {
    // 使用 USER_HOME 變量
    file = "${USER_HOME}/myApp.log"
    encoder(PatternLayoutEncoder) {
        pattern = "%msg%n"
    }
}
root(DEBUG, ["FILE"])

在控制臺打印

通過調(diào)用 Groovy 的 println 方法在控制臺進行打印。例如:

def USER_HOME = System.getProperty("user.home");
println "USER_HOME=${USER_HOME}"

appender("FILE", FileAppender) {
    println "Setting [file] property to [${USER_HOME}/myApp.log]"
    file = "${USER_HOME}/myApp.log"
    encoder(PatternLayoutEncoder) {
        pattern = "%msg%n"
    }
}
root(DEBUG, ["FILE"])

自動輸出字段

'hostname' 變量

'hostname' 變量包含當(dāng)前 host 的名字霹购。但是由于作用域規(guī)則佑惠,所以作者不能完全解釋清楚 (??)。'hostname' 變量只在最上層的作用域中有效齐疙,但是在內(nèi)部的作用域中無效膜楷。下面的例子應(yīng)該可以解釋這一點:

// 如果當(dāng)前 host 的名字為 x,那么將會輸出 "hostname is x"
println "hostname is ${hostname}"

appender("STDOUT", ConsoleAppender) {
    // 將會輸出 "hostname is null"
    println "hostname is ${hostname}"
}

如果你想要在所有的作用域中使用 hostname 變量贞奋。那么你需要定義一個變量赌厅,并將 'hostname' 的值賦給它。如下:

// 將 hostname 的值賦給 HOSTNAME
def HOSTNAME = hostname

// 如果當(dāng)前 host 的名字為 x轿塔,那么將會輸出 "hostname is x"
println "hostname is ${HOSTNAME}"

appender("STDOUT", ConsoleAppender) {
    // 如果當(dāng)前 host 的名字為 x特愿,那么將會輸出 "hostname is x"
    println "hostname is ${HOSTNAME}"
}

任何對于當(dāng)前上下文的引用都是上下文感知的

logback.groovy 腳本是在 ContextAware 對象的范圍內(nèi)執(zhí)行完成的仲墨。因此,在當(dāng)前上下文的范圍內(nèi)揍障,你可以使用 'context'目养,并且可以通過 addInfo()addWarn()毒嫡、與 addError() 方法將狀態(tài)信息發(fā)送給上下文的 StatusManager癌蚁。

// 添加一個控制臺轉(zhuǎn)態(tài)監(jiān)聽器總是沒錯的
statusListener(OnConsoleStatusListener)

// 設(shè)置上下文的名字為 wombat
context.name = 'wombat'

// 添加一個關(guān)于上下文名字的狀態(tài)信息
addInfo("Context name has been set to ${context_name}")

def USER_HOME = System.getProperty("user.home")

// 添加關(guān)于 USRE_HOME 的狀態(tài)信息
addInfo("USER_HOME=${USER_HOME}")

appender("FILE", FileAppender) {
    addInfo("Setting [file] property to [${USER_NAME}/myApp.log]")
    file = "${USER_HOME}/myApp.log"
    encoder(PatternLayoutEncoder) {
        pattern = "%msg%n"
    }
}
root(DEBUG, ["FILE"])

條件配置

由于 Groovy 是一種完全成熟的編程語言,條件語句允許單一的 logback.groovy 文件用來適用不同的環(huán)境兜畸,例如開發(fā)努释,測試以及生產(chǎn)。

在下個腳本中咬摇,console appender 根據(jù) host 來激活洽洁,而不是我們的生產(chǎn)環(huán)境 pixie 或 orion。rolling file appender 的輸出目錄也是根據(jù) host 來確定菲嘴。

statusListener(OnConsoleStatusListener)

def appenderList = ["ROLLING"]
def WEBAPP_DIR = "."
def consoleAppender = true;

// hostname 是否匹配 pixie 或 orion
if (hostname =~ /pixie|orion/) {
    WEBAPP_DIR = "/opt/myapp"
    consoleAppender = false
} else {
    appenderList.add("CONSOLE")
}

if (consoleAppender) {
    appender("CONSOLE", ConsoleAppender) {
        encoder(PatternLayoutEncoder) {
            pattern = "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
        }
    }
}

appender("ROLLING", RollingFileAppender) {
    encoder(PatternLayoutEncoder) {
        Pattern = "%d %level %thread %mdc %logger - %m%n"
    }
    rollingPolicy(TimeBasedRollingPolicy) {
        FileNamePattern = "${WEBAPP_DIR}/log/translator-%d{yyyy-MM}.zip"
    }
}

root(INFO, appenderList)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市汰翠,隨后出現(xiàn)的幾起案子龄坪,更是在濱河造成了極大的恐慌,老刑警劉巖复唤,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件健田,死亡現(xiàn)場離奇詭異,居然都是意外死亡佛纫,警方通過查閱死者的電腦和手機妓局,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來呈宇,“玉大人好爬,你說我怎么就攤上這事∩模” “怎么了存炮?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蜈漓。 經(jīng)常有香客問我穆桂,道長,這世上最難降的妖魔是什么融虽? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任享完,我火速辦了婚禮,結(jié)果婚禮上有额,老公的妹妹穿的比我還像新娘般又。我一直安慰自己彼绷,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布倒源。 她就那樣靜靜地躺著苛预,像睡著了一般。 火紅的嫁衣襯著肌膚如雪笋熬。 梳的紋絲不亂的頭發(fā)上热某,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天,我揣著相機與錄音胳螟,去河邊找鬼昔馋。 笑死,一個胖子當(dāng)著我的面吹牛糖耸,可吹牛的內(nèi)容都是我干的秘遏。 我是一名探鬼主播,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼嘉竟,長吁一口氣:“原來是場噩夢啊……” “哼邦危!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起舍扰,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤倦蚪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后边苹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體陵且,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年个束,在試婚紗的時候發(fā)現(xiàn)自己被綠了慕购。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡茬底,死狀恐怖沪悲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情阱表,我是刑警寧澤可训,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站捶枢,受9級特大地震影響握截,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜烂叔,卻給世界環(huán)境...
    茶點故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一谨胞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蒜鸡,春花似錦胯努、人聲如沸牢裳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蒲讯。三九已至,卻和暖如春灰署,著一層夾襖步出監(jiān)牢的瞬間判帮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工溉箕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留晦墙,地道東北人。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓肴茄,卻偏偏與公主長得像晌畅,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子寡痰,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,494評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 最近在學(xué)習(xí)使用同事開發(fā)的日志框架抗楔,感覺對于logback除了基本的使用并沒有很深刻的了解,遂對debug過程做大概...
    Eshin_Ye閱讀 2,551評論 0 2
  • 在logback學(xué)習(xí)筆記(上)中我們介紹了logback中的一些核心概念拦坠,在這篇文章中我們共同來學(xué)習(xí)一下如何利用配...
    阿龍的學(xué)與思閱讀 1,663評論 0 3
  • 第十四章:Receivers receiver 是 logback 的一個組件连躏,用于接收遠(yuǎn)程 appender 的...
    ChinaXieShuai閱讀 1,158評論 0 0
  • 我不太喜歡看小說總覺得虛構(gòu)類的作品沒太大意義大多是打發(fā)時間用說來慚愧知曉嚴(yán)歌苓是《金陵十三釵》電影上映而后是鞏俐陳...
    一頓要吃三兩肉閱讀 354評論 0 0
  • 第六章溫暖的旅程 “到昆明的旅客現(xiàn)在開始登機√巴瘢”廣播里面一遍遍播放著不同的語言。 起飛卢肃。 飛機升起的瞬間疲迂,突然覺得...
    林嘉瑞閱讀 571評論 8 5