Log4j2最佳實踐

[TOC]

1. 版本選擇


  • 推薦使用log4j-2.11
  • 推薦使用slf4j作為日志門面

2. pom依賴配置和升級方案


pom配置

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.24</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-1.2-api</artifactId>
        <version>2.11.0</version>
    </dependency>

    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.11.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.11.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j-impl</artifactId>
        <version>2.11.0</version>
    </dependency>

注意辉阶,不可同時使用log4j-slf4j-impl和log4j-to-slf4j畏纲,否則會引發(fā)循環(huán)依賴。詳情見log4j官方文檔。

如果使用了upcommonlog,橋接也要替換為2.x版本

    <dependency>
        <groupId>com.unionpay.common.upcommon-log</groupId>
        <artifactId>uplog-bridge-log4j2.X</artifactId>
        <version>1.2.1</version>
    </dependency>

如果使用異步日志永毅,需要加入disruptor依賴

    <dependency>
        <groupId>com.lmax</groupId>
        <artifactId>disruptor</artifactId>
        <version>3.4.2</version>
    </dependency>

為了防止干擾,可以將其他組件引入的log4j 1的依賴exclude掉

3. log4j2配置最佳實踐


示例配置1——最簡配置

說明:在這種配置下人弓,應用日志全部打印在同一個日志文件中沼死,應用中使用的公共組件日志因為沒有配置logger所以不會打印(會打印在root logger配置的console中)。建議應用根據(jù)該文件作適當修改崔赌,以適配具體的應用日志需求

配置文件如下

<?xml version="1.0" encoding="UTF-8"?>
<!-- monitorInterval配置成一個正整數(shù)漫雕,則每隔這么久的時間(秒),log4j2會刷新一次配置峰鄙。如果不配置則不會動態(tài)刷新 -->
<Configuration status="INFO" monitorInterval="30">
    <Properties>
        <Property name="baseLogDir">logs</Property>
        <Property name="pattern">%d{yyyyMMdd-HHmmss.SSS} [%level] %c{1} - %msg%n</Property>
    </Properties>
    <!-- 先定義所有的appender -->
    <Appenders>
        <!-- 這個輸出控制臺的配置 -->
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout>
                <Pattern>${pattern}</Pattern>
            </PatternLayout>
        </Console>
        <!-- 應用info日志 -->
        <RollingRandomAccessFile name="APPINFO_APPENDER" fileName="${baseLogDir}/appinfo.log"
            filePattern="${baseLogDir}/appinfo.log.%d{yyyyMMddHH}.%i.gz">
            <PatternLayout>
                <Pattern>${pattern}</Pattern>
            </PatternLayout>
            <Policies>
                <SizeBasedTriggeringPolicy size="500MB" />
                <TimeBasedTriggeringPolicy interval="1" modulate="true" />
            </Policies>
            <Filters>
                <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY" />
            </Filters>
            <!-- max=20標識一小時內(nèi)最多產(chǎn)生20個日志文件 -->
            <DefaultRolloverStrategy max="20">
                <!-- 對于指定的路徑下的指定后綴的文件浸间,只保留3天的日志文件,那么最多會有3天*24小時*20個日志文件 -->
                <!-- 注意應用需要根據(jù)業(yè)務需求和磁盤大小評估需要保留的日志個數(shù)吟榴,對于500M的日志文件來說魁蒜,要根據(jù)應用日志的情況,觀察單個日志壓縮后文件大小吩翻,并計算總大小需要的空間 -->
                <Delete basePath="${baseLogDir}" maxDepth="1">
                    <IfFileName glob="*.gz" />
                    <IfLastModified age="3d" />
                </Delete>
            </DefaultRolloverStrategy>
        </RollingRandomAccessFile>
    </Appenders>
    <Loggers>
        <!-- root是默認的logger兜看,也是所有l(wèi)ogger的父級logger,如果需要狭瞎,可以在這里配置一個文件appender以打印外部組件日志 -->
        <AsyncRoot level="WARN">
            <AppenderRef ref="Console" />
        </AsyncRoot>
        <!-- 應用日志细移,采用異步模式,name根據(jù)實際的包名修改熊锭;生產(chǎn)環(huán)境中additivity建議設(shè)置為false以避免在root logger中重復打印 -->
        <AsyncLogger name="com.unionpay" level="INFO" includeLocation="false" additivity="false">
            <AppenderRef ref="APPINFO_APPENDER" />
        </AsyncLogger>
    </Loggers>
</Configuration>

示例配置2——日志分類

說明:在這種配置下弧轧,應用的info日志打印在appinfo.log中,應用的warn及以上日志打印在apperror.log中碗殷,其他公共組件的日志打印在server.log中精绎。建議應用根據(jù)該配置作適當修改,以適配具體的應用日志需求

配置文件如下

<?xml version="1.0" encoding="UTF-8"?>
<!-- monitorInterval配置成一個正整數(shù)锌妻,則每隔這么久的時間(秒)代乃,log4j2會刷新一次配置。如果不配置則不會動態(tài)刷新 -->
<Configuration status="INFO" monitorInterval="30">
    <Properties>
        <!-- 應用需要修改為合適的log路徑 -->
        <Property name="baseLogDir">logs</Property>
        <Property name="pattern">%d{yyyyMMdd-HHmmss.SSS} [%level] %c{1} - %msg%n</Property>
    </Properties>
    <!-- 先定義所有的appender -->
    <Appenders>
        <!-- 這個輸出控制臺的配置 -->
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout>
                <Pattern>${pattern}</Pattern>
            </PatternLayout>
        </Console>
        <!-- 系統(tǒng)日志仿粹,可以作為root logger的appender搁吓,供打印一些中間件的日志 -->
        <RollingRandomAccessFile name="SYS_APPENDER" fileName="${baseLogDir}/server.log"
            filePattern="${baseLogDir}/server.log.%d{yyyyMMddHH}.%i.gz">
            <PatternLayout>
                <Pattern>${pattern}</Pattern>
            </PatternLayout>
            <Policies>
                <SizeBasedTriggeringPolicy size="200MB" />
                <TimeBasedTriggeringPolicy interval="1" modulate="true" />
            </Policies>
            <Filters>
                <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY" />
            </Filters>
            <!-- max=6標識一小時內(nèi)最多產(chǎn)生6個日志文件 -->
            <DefaultRolloverStrategy max="6">
                <!-- 對于指定的路徑下的指定后綴的文件原茅,只保留1天的日志文件,那么最多會有24小時*6個日志文件 -->
                <Delete basePath="${baseLogDir}" maxDepth="1">
                    <IfFileName glob="*.gz" />
                    <IfLastModified age="1d" />
                </Delete>
            </DefaultRolloverStrategy>
        </RollingRandomAccessFile>
        <!-- 應用info日志 -->
        <RollingRandomAccessFile name="APPINFO_APPENDER" fileName="${baseLogDir}/appinfo.log"
            filePattern="${baseLogDir}/appinfo.log.%d{yyyyMMddHH}.%i.gz">
            <PatternLayout>
                <Pattern>${pattern}</Pattern>
            </PatternLayout>
            <Policies>
                <SizeBasedTriggeringPolicy size="500MB" />
                <TimeBasedTriggeringPolicy interval="1" modulate="true" />
            </Policies>
            <Filters>
                <!-- 當前appender只打印info日志堕仔,warn及以上日志忽略员咽,由后面的appender決定是否需要打印 -->
                <ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL" />
                <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY" />
            </Filters>
            <!-- max=20標識一小時內(nèi)最多產(chǎn)生20個日志文件 -->
            <DefaultRolloverStrategy max="20">
                <!-- 對于指定的路徑下的指定后綴的文件,只保留3天的日志文件贮预,那么最多會有3天*24小時*20個日志文件 -->
                <!-- 注意應用需要根據(jù)業(yè)務需求和磁盤大小評估需要保留的日志個數(shù),對于500M的日志文件來說契讲,要根據(jù)應用日志的情況仿吞,觀察單個日志壓縮后文件大小,并計算總大小需要的空間 -->
                <Delete basePath="${baseLogDir}" maxDepth="1">
                    <IfFileName glob="*.gz" />
                    <IfLastModified age="3d" />
                </Delete>
            </DefaultRolloverStrategy>
        </RollingRandomAccessFile>
        <!-- 應用錯誤日志 -->
        <RollingRandomAccessFile name="APPERROR_APPENDER" fileName="${baseLogDir}/apperror.log"
            filePattern="${baseLogDir}/apperror.log.%d{yyyyMMddHH}.%i.gz">
            <PatternLayout>
                <Pattern>${pattern}</Pattern>
            </PatternLayout>
            <Policies>
                <SizeBasedTriggeringPolicy size="500MB" />
                <TimeBasedTriggeringPolicy interval="1" modulate="true" />
            </Policies>
            <Filters>
                <ThresholdFilter level="WARN" onMatch="ACCEPT" onMismatch="DENY" />
            </Filters>
            <!-- max=10標識一小時內(nèi)最多產(chǎn)生10個日志文件 -->
            <DefaultRolloverStrategy max="10">
                <!-- 對于指定的路徑下的指定后綴的文件捡偏,只保留3天的日志文件唤冈,那么最多會有3*24小時*10個日志文件 -->
                <Delete basePath="${baseLogDir}" maxDepth="1">
                    <IfFileName glob="*.gz" />
                    <IfLastModified age="3d" />
                </Delete>
            </DefaultRolloverStrategy>
        </RollingRandomAccessFile>
    </Appenders>

    <Loggers>
        <!-- root是默認的logger厦幅,也就是公共的logger五督,供記錄一些不常打印的系統(tǒng)參數(shù)或者其他組件參數(shù) -->
        <AsyncRoot level="WARN">
            <AppenderRef ref="Console" />
            <AppenderRef ref="SYS_APPENDER" />
        </AsyncRoot>
        <!-- 常打印的應用日志心墅,建議獨立配置宜狐,并采用異步模式丰辣。name根據(jù)實際的包名修改剂癌,生產(chǎn)環(huán)境中additivity建議設(shè)置為false以避免在root logger中重復打印 -->
        <AsyncLogger name="com.unionpay" level="INFO" includeLocation="false" additivity="false">
            <AppenderRef ref="APPINFO_APPENDER" />
            <AppenderRef ref="APPERROR_APPENDER" />
        </AsyncLogger>
    </Loggers>
</Configuration>

4. log4j調(diào)優(yōu)和注意事項


4.1 日志模式-同步/異步

log4j2提供了AsyncAppender和AsyncLogger以及全局異步怖现,開啟方式如下

  • 同步模式:默認配置即為同步模式蕴茴,即沒有使用任何AsyncAppender和AsyncLogger
  • 全局異步:配置按照同步方式配琉预,通過添加jvm啟動參數(shù)即可開啟全局異步董饰,無需修改配置和應用
  • 混合異步:使用異步Logger和同步Logger的混合配置,且不開啟全局異步圆米,即Logger配置中部分AsyncLogger卒暂,部分Logger

日志模式使用注意事項

  • 如果使用異步,建議使用AsyncLogger實現(xiàn)而不是AsyncAppender
  • 如果使用同步娄帖,AsyncLogger也祠、AsyncAppender和全局異步只能使用一種,不可以同時配置AsyncAppender和AsyncLogger近速,或者配置了異步的情況下啟用了全局異步

4.2 日志滾動和清除策略

log4j2提供了基于文件大小的滾動策略和基于時間的滾動策略诈嘿,也可以二者并用,這里給出基于大小的滾動策略配置和基于大小/時間雙滾動策略配置削葱。

基于大小的滾動策略

  • 按照大小滾動永淌,啟用壓縮,并最多保留N個文件

      <!--此處舉例為每500M滾動一個文件佩耳,且最多保留20個文件遂蛀,具體需要根據(jù)應用的日志量和希望保留日志大小以及磁盤空間進行評估-->
      <RollingRandomAccessFile name="APPINFO_APPENDER" fileName="${baseLogDir}/appinfo.log"
          filePattern="${baseLogDir}/appinfo.log.%i.gz">
          <PatternLayout>
              <Pattern>${pattern}</Pattern>
          </PatternLayout>
          <Policies>
              <SizeBasedTriggeringPolicy size="500MB" />
          </Policies>
          <Filters>
              <!-- 當前appender只打印info日志,warn及以上日志忽略干厚,由后面的錯誤日志記錄 -->
              <ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL" />
              <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY" />
          </Filters>
          <!-- max=20表示最多保留20個日志文件 -->
          <DefaultRolloverStrategy max="20"/>
      </RollingRandomAccessFile>
    

此種策略的空間占用計算公式為(這里計算的是最大空間需求)

日志空間需求=日志滾動閾值(例如500M)+日志留存?zhèn)€數(shù)*日志滾動閾值*1/壓縮比(對于gz壓縮比一般會是幾十李滴,具體根據(jù)應用日志壓縮后計算)

例如假設(shè)壓縮比為50螃宙,則500M的文件壓縮后只有10M,那么上述配置總空間大小是

日志空間需求=500M+20*500*1/50=700M

基于大小/時間雙滾動滾動策略

  • 按照大小和時間滾動所坯,啟用壓縮谆扎,單位時間內(nèi)控制最多保留日志個數(shù)并控制總的日志留存時間

      <!--此處舉例為每小時滾動一個文件且每500M滾動一個文件,控制每小時最多保留20個文件芹助,總的文件保留3天-->
      <!--具體需要根據(jù)應用的日志量和希望保留日志大小以及磁盤空間進行評估-->
      <RollingRandomAccessFile name="APPINFO_APPENDER" fileName="${baseLogDir}/appinfo.log"
          filePattern="${baseLogDir}/appinfo.log.%d{yyyyMMddHH}.%i.gz">
          <PatternLayout>
              <Pattern>${pattern}</Pattern>
          </PatternLayout>
          <Policies>
              <SizeBasedTriggeringPolicy size="500MB" />
              <TimeBasedTriggeringPolicy interval="1" modulate="true" />
          </Policies>
          <Filters>
              <!-- 當前appender只打印info日志堂湖,warn及以上日志忽略,由后面的錯誤日志記錄 -->
              <ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL" />
              <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY" />
          </Filters>
          <!-- max=20表示一小時內(nèi)最多保留20個日志文件 -->
          <DefaultRolloverStrategy max="20">
              <!-- 對于指定的路徑下的指定后綴的文件状土,只保留3天的日志文件无蜂,那么最多會有3天*24小時*20個日志文件 -->
              <!-- 注意應用需要根據(jù)業(yè)務需求和磁盤大小評估需要保留的日志個數(shù),對于500M的日志文件來說蒙谓,要根據(jù)應用日志的情況斥季,觀察單個日志壓縮后文件大小,并計算總大小需要的空間 -->
              <Delete basePath="${baseLogDir}" maxDepth="1">
                  <IfFileName glob="*.gz" />
                  <IfLastModified age="3d" />
              </Delete>
          </DefaultRolloverStrategy>
      </RollingRandomAccessFile>
    

此種策略的空間占用計算公式為(這里計算的是最大空間需求)

日志留存?zhèn)€數(shù)=保留時間*單位時間內(nèi)最大日志個數(shù)
日志空間需求=日志滾動閾值(例如500M)+日志留存?zhèn)€數(shù)*日志滾動閾值*1/壓縮比(對于gz壓縮比一般會是幾十累驮,具體根據(jù)應用日志壓縮后計算)

例如假設(shè)壓縮比為50酣倾,則500M的文件壓縮后只有10M,那么上述配置總空間大小是

日志留存?zhèn)€數(shù)=3*24*20=1440
日志空間需求=500M+1440*500*1/50=15G

注意谤专,控制總的日志留存時間的機制躁锡,需要log4j-2.5及以上的版本支持,建議使用2.11版本

4.3 其他注意事項和調(diào)優(yōu)

  • 推薦在Configuration中添加monitorInterval以支持動態(tài)刷新
  • 推薦使用異步日志而不是同步日志置侍,可以是混合異步也可以是全局異步
  • 不推薦配置AsyncAppender稚铣,如果需要混合異步,使用AsyncLogger
  • PatternLayout不要使用%L墅垮、%C惕医、%method等含有“位置信息”的配置項,非常影響性能算色。同時logger配置中需要加上inclueLocation="false"抬伺,這樣即使配置了位置信息也會被忽略
  • 推薦使用RollingRandomAccessFile做為appender
  • 推薦基于大小和時間的雙重文件滾動策略,并配合壓縮

4.4 log4j-disruptor等待策略

log4j2的日志使用了disruptor灾梦,其內(nèi)部使用了基于ringbuffer的環(huán)形隊列峡钓,并且也有生產(chǎn)者消費者的概念。在消費者等待消息事件(也就是日志消息)時若河,其內(nèi)部有一處等待策略的配置能岩,配置項可以是Block/Timeout/Sleep/Yield,默認Timeout萧福,不同策略的含義如下

  • Block拉鹃,在I/O線程等待時使用鎖和條件觸發(fā)機制,當cpu的優(yōu)先級高于吞吐量和延遲的時候推建議使用。官方推薦在資源受限/虛擬化環(huán)境中使用
  • Timeout膏燕,是Block策略的變種钥屈,它將定期從等待中被喚醒,確保了如果錯過了通知坝辫,disruptor消費者不會被永久阻塞篷就,但會有較小的延遲(10ms)
  • Sleep,等待IO事件先自旋近忙,然后調(diào)用Thread.yield()竭业,最后park,在性能和cpu之間取得一個折中
  • Yield及舍,等待IO事件先自旋未辆,然后調(diào)用用Thread.yield()等待日志事件,相較于Sleep可能會消耗更多的cpu

log4j2默認策略是Timeout击纬,在實際測試中,我們嘗試測試出不同策略下的cpu占用和延遲時間情況钾麸,但測試結(jié)果并沒有明顯的數(shù)據(jù)對比更振,因此這里僅供參考,應用如果修改饭尝,需要結(jié)合場景做全面的測試肯腕。例如如果發(fā)現(xiàn)cpu占用較高,可以嘗試修改為Block或者其他策略并測試觀察钥平。

修改disruptor wait策略的方法為(以修改為Block為例)

-Dlog4j2.asyncLoggerWaitStrategy=Block

5. slf4j代碼優(yōu)化建議


此處針對的是使用了slf4j的代碼实撒,不適用于其它情況

我們知道,slf4j打印日志可以使用占位符的方式涉瘾,例如一般打印日志的代碼:

logger.debug("this is log4j2, current time:" + System.currentTimeMillis());

在使用了slf4j的情況下知态,該句的功能等價于

logger.debug("this is log4j2, current time:{}", System.currentTimeMillis());
  • 上面兩行的代碼功能相同,但是前一句在每次執(zhí)行時立叛,無論我們的日志級別是不是debug即以上负敏,每次都會生成一個新的字符串,字符串的字面值是前綴加上系統(tǒng)當前時間秘蛇。即使我們的日志級別配置成warn其做,該句也會產(chǎn)生一個新的字符串
  • 后一句,當我們?nèi)罩炯墑e是debug或者小于debug的時候赁还,才會真的創(chuàng)建一個完整的字符串妖泄,否則內(nèi)存中只會有包含了占位符的唯一一個字符串

如果這種情況非常多,那么直接拼接字符串的方式對于內(nèi)存的浪費就非常明顯了艘策,這時候使用占位符的方式蹈胡,可以明顯的改善字符串的生成數(shù)量。當然也不是說任何地方都要使用占位符,因為占位符拼接成字符串审残,也是有開銷的梭域,起碼要遍歷占位符后面的參數(shù)。因此一般建議:

  • 對于一定要打印的日志搅轿,使用字符串拼接的方式(必要時引入StringBuilder輔助而不是一直加)
  • 對于調(diào)整級別才需要打印的日志病涨,使用占位符的方式而不是直接拼接
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市璧坟,隨后出現(xiàn)的幾起案子既穆,更是在濱河造成了極大的恐慌,老刑警劉巖雀鹃,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件幻工,死亡現(xiàn)場離奇詭異,居然都是意外死亡黎茎,警方通過查閱死者的電腦和手機囊颅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來傅瞻,“玉大人踢代,你說我怎么就攤上這事⌒峤荆” “怎么了胳挎?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長溺森。 經(jīng)常有香客問我慕爬,道長,這世上最難降的妖魔是什么屏积? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任医窿,我火速辦了婚禮,結(jié)果婚禮上炊林,老公的妹妹穿的比我還像新娘留搔。我一直安慰自己,他們只是感情好铛铁,可當我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布隔显。 她就那樣靜靜地躺著,像睡著了一般饵逐。 火紅的嫁衣襯著肌膚如雪括眠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天倍权,我揣著相機與錄音掷豺,去河邊找鬼捞烟。 笑死,一個胖子當著我的面吹牛当船,可吹牛的內(nèi)容都是我干的题画。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼德频,長吁一口氣:“原來是場噩夢啊……” “哼苍息!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起壹置,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤竞思,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后钞护,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體盖喷,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年难咕,在試婚紗的時候發(fā)現(xiàn)自己被綠了课梳。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡余佃,死狀恐怖暮刃,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情咙冗,我是刑警寧澤沾歪,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布漂彤,位于F島的核電站雾消,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏挫望。R本人自食惡果不足惜立润,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望媳板。 院中可真熱鬧桑腮,春花似錦、人聲如沸蛉幸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽奕纫。三九已至提陶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間匹层,已是汗流浹背隙笆。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人撑柔。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓瘸爽,卻偏偏與公主長得像,于是被迫代替她去往敵國和親铅忿。 傳聞我的和親對象是個殘疾皇子剪决,可洞房花燭夜當晚...
    茶點故事閱讀 44,976評論 2 355

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

  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,822評論 6 342
  • 在應用程序中添加日志記錄總的來說基于三個目的:監(jiān)視代碼中變量的變化情況,周期性的記錄到文件中供其他應用進行統(tǒng)計分析...
    時待吾閱讀 4,988評論 0 6
  • 轉(zhuǎn)自:http://www.cnblogs.com/warking/p/5710303.html 一辆沦、logbac...
    chenzhong_閱讀 1,501評論 0 3
  • 1昼捍、通過CocoaPods安裝項目名稱項目信息 AFNetworking網(wǎng)絡(luò)請求組件 FMDB本地數(shù)據(jù)庫組件 SD...
    陽明先生_X自主閱讀 15,982評論 3 119
  • 在應用程序中添加日志記錄總的來說基于三個目的:監(jiān)視代碼中變量的變化情況,周期性的記錄到文件中供其他應用進行統(tǒng)計分析...
    時待吾閱讀 5,050評論 1 13