Logback配置文件這么寫,還愁不會整理日志侣颂?

摘要:

1.日志輸出到文件并根據(jù)LEVEL級別將日志分類保存到不同文件

2.通過異步輸出日志減少磁盤IO提高性能

3.異步輸出日志的原理

1、配置文件logback-spring.xml

SpringBoot工程自帶logback和slf4j的依賴枪孩,所以重點放在編寫配置文件上憔晒,需要引入什么依賴,日志依賴沖突統(tǒng)統(tǒng)都不需要我們管了蔑舞。

logback框架會默認(rèn)加載classpath下命名為logback-spring.xml或logback.xml的配置文件拒担。

如果將所有日志都存儲在一個文件中,文件大小也隨著應(yīng)用的運行越來越大并且不好排查問題攻询,正確的做法應(yīng)該是將error日志和其他日志分開从撼,并且不同級別的日志根據(jù)時間段進行記錄存儲。

配置文件:

<?xml version="1.0" encoding="UTF-8"?> <configuration debug="true"> <!-- 項目名稱 --> <property name="PROJECT_NAME" value="project-api" /> <!--定義日志文件的存儲地址 勿在 LogBack 的配置中使用相對路徑--> <property name="LOG_HOME" value="logs" /> <!-- 控制臺輸出 --> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <withJansi>true</withJansi> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <!-- 格式化輸出: %d: 日期; %-5level: 級別從左顯示5個字符寬度; %thread: 線程名; %logger: 類名; %M: 方法名; %line: 行號; %msg: 日志消息; %n: 換行符 --> <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] [%logger{50}] [%M] [%line] - %msg%n</pattern> <charset>UTF-8</charset> </encoder> </appender> <!-- ERROR日志文件,記錄錯誤日志 --> <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_HOME}/${PROJECT_NAME}/error.log</file> <!-- 過濾器钧栖,只打印ERROR級別的日志 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <!--日志文件輸出的文件名--> <FileNamePattern>${LOG_HOME}/${PROJECT_NAME}/%d{yyyy-MM-dd}/error.%i.zip</FileNamePattern> <!--日志文件保留天數(shù)--> <MaxHistory>3650</MaxHistory> <!--日志文件最大的大小--> <MaxFileSize>100MB</MaxFileSize> </rollingPolicy> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <!-- 格式化輸出: %d: 日期; %-5level: 級別從左顯示5個字符寬度; %thread: 線程名; %logger: 類名; %M: 方法名; %line: 行號; %msg: 日志消息; %n: 換行符 --> <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] [%logger{50}] [%M] [%line] - %msg%n</pattern> <charset>UTF-8</charset> </encoder> </appender> <!-- INFO日志文件低零,用于記錄重要日志信息 --> <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_HOME}/${PROJECT_NAME}/info.log</file> <!-- 過濾器,只打印INFO級別的日志 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFO</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <!--日志文件輸出的文件名--> <FileNamePattern>${LOG_HOME}/${PROJECT_NAME}/%d{yyyy-MM-dd}/info.%i.zip</FileNamePattern> <!--日志文件保留天數(shù)--> <MaxHistory>3650</MaxHistory> <!--日志文件最大的大小--> <MaxFileSize>100MB</MaxFileSize> </rollingPolicy> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <!-- 格式化輸出: %d: 日期; %-5level: 級別從左顯示5個字符寬度; %thread: 線程名; %logger: 類名; %M: 方法名; %line: 行號; %msg: 日志消息; %n: 換行符 --> <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] [%logger{50}] [%M] [%line] - %msg%n</pattern> <charset>UTF-8</charset> </encoder> </appender> <!-- 打印的SQL日志文件拯杠,用于執(zhí)行的SQL語句和參數(shù)信息 --> <appender name="SQL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_HOME}/${PROJECT_NAME}/sql.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <!--日志文件輸出的文件名--> <FileNamePattern>${LOG_HOME}/${PROJECT_NAME}/%d{yyyy-MM-dd}/sql.%i.zip</FileNamePattern> <!--日志文件保留天數(shù)--> <MaxHistory>3650</MaxHistory> <!--日志文件最大的大小--> <MaxFileSize>100MB</MaxFileSize> </rollingPolicy> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <!-- 格式化輸出: %d: 日期; %-5level: 級別從左顯示5個字符寬度; %thread: 線程名; %logger: 類名; %M: 方法名; %line: 行號; %msg: 日志消息; %n: 換行符 --> <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] [%logger{50}] [%M] [%line] - %msg%n</pattern> <charset>UTF-8</charset> </encoder> </appender> <!-- API請求被訪問的日志文件掏婶,記錄請求的URL和攜帶的參數(shù) --> <appender name="REQUEST_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_HOME}/${PROJECT_NAME}/request.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <!--日志文件輸出的文件名--> <FileNamePattern>${LOG_HOME}/${PROJECT_NAME}/%d{yyyy-MM-dd}/request.%i.zip</FileNamePattern> <!--日志文件保留天數(shù)--> <MaxHistory>3650</MaxHistory> <!--日志文件最大的大小--> <MaxFileSize>100MB</MaxFileSize> </rollingPolicy> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <!-- 格式化輸出: %d: 日期; %-5level: 級別從左顯示5個字符寬度; %thread: 線程名; %logger: 類名; %M: 方法名; %line: 行號; %msg: 日志消息; %n: 換行符 --> <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] [%logger{50}] [%M] [%line]- %msg%n</pattern> <charset>UTF-8</charset> </encoder> </appender> <!-- 異步輸出INFO_FILE --> <appender name="ASYNC_INFO_FILE" class="ch.qos.logback.classic.AsyncAppender"> <!-- 更改默認(rèn)的隊列的深度,該值會影響性能.默認(rèn)值為256 --> <queueSize>256</queueSize> <!-- 默認(rèn)情況下,當(dāng)阻塞隊列的剩余容量為20%時潭陪,它將丟棄TRACE雄妥,DEBUG和INFO級別的事件最蕾,僅保留WARN和ERROR級別的事件。要保留所有事件茎芭,請將discardingThreshold設(shè)置為0揖膜。 --> <discardingThreshold>0</discardingThreshold> <!-- 添加附加的appender,使用前面定義的name,最多只能添加一個 --> <appender-ref ref="INFO_FILE"/> </appender> <!-- 異步輸出ERROR_FILE --> <appender name="ASYNC_ERROR_FILE" class="ch.qos.logback.classic.AsyncAppender"> <!-- 更改默認(rèn)的隊列的深度,該值會影響性能.默認(rèn)值為256 --> <queueSize>256</queueSize> <!-- 默認(rèn)情況下,當(dāng)阻塞隊列的剩余容量為20%時梅桩,它將丟棄TRACE壹粟,DEBUG和INFO級別的事件,僅保留WARN和ERROR級別的事件宿百。要保留所有事件趁仙,請將discardingThreshold設(shè)置為0。 --> <discardingThreshold>0</discardingThreshold> <!-- 添加附加的appender,使用前面定義的name,最多只能添加一個 --> <appender-ref ref="ERROR_FILE"/> </appender> <!-- 異步輸出SQL_FILE --> <appender name="ASYNC_SQL_FILE" class="ch.qos.logback.classic.AsyncAppender"> <!-- 更改默認(rèn)的隊列的深度,該值會影響性能.默認(rèn)值為256 --> <queueSize>256</queueSize> <!-- 默認(rèn)情況下垦页,當(dāng)阻塞隊列的剩余容量為20%時雀费,它將丟棄TRACE,DEBUG和INFO級別的事件痊焊,僅保留WARN和ERROR級別的事件盏袄。要保留所有事件,請將discardingThreshold設(shè)置為0薄啥。 --> <discardingThreshold>0</discardingThreshold> <!-- 添加附加的appender,使用前面定義的name,最多只能添加一個 --> <appender-ref ref="SQL_FILE"/> </appender> <!-- 異步輸出REQUEST_FILE --> <appender name="ASYNC_REQUEST_FILE" class="ch.qos.logback.classic.AsyncAppender"> <!-- 更改默認(rèn)的隊列的深度,該值會影響性能.默認(rèn)值為256 --> <queueSize>256</queueSize> <!-- 默認(rèn)情況下辕羽,當(dāng)阻塞隊列的剩余容量為20%時,它將丟棄TRACE垄惧,DEBUG和INFO級別的事件刁愿,僅保留WARN和ERROR級別的事件。要保留所有事件到逊,請將discardingThreshold設(shè)置為0铣口。 --> <discardingThreshold>0</discardingThreshold> <!-- 添加附加的appender,使用前面定義的name,最多只能添加一個 --> <appender-ref ref="REQUEST_FILE"/> </appender> <!-- 輸出error信息到文件--> <logger name="error" additivity="true"> <appender-ref ref="ERROR_FILE"/> </logger> <!-- 輸出info信息到文件--> <logger name="info" additivity="true"> <appender-ref ref="INFO_FILE"/> </logger> <!-- 輸出request信息到文件--> <logger name="request" level="INFO" additivity="false"> <appender-ref ref="REQUEST_FILE" /> </logger> <!-- 輸出SQL到控制臺和文件--> <logger name="org.hibernate.SQL" additivity="false"> <level value="DEBUG" /> <appender-ref ref="SQL_FILE" /> </logger> <!-- 輸出SQL的參數(shù)到控制臺和文件--> <logger name="org.hibernate.type.descriptor.sql.BasicBinder" additivity="false" level="TRACE"> <level value="TRACE" /> <appender-ref ref="SQL_FILE" /> </logger> <!-- 開發(fā)環(huán)境下的日志配置 --> <springProfile name="dev"> <root level="INFO"> <appender-ref ref="CONSOLE" /> <appender-ref ref="ERROR_FILE" /> <appender-ref ref="INFO_FILE" /> </root> </springProfile> <!-- 測試環(huán)境下的日志配置 --> <springProfile name="test"> <root level="INFO"> <appender-ref ref="CONSOLE" /> <appender-ref ref="ERROR_FILE" /> <appender-ref ref="INFO_FILE" /> </root> </springProfile> <!-- 生產(chǎn)環(huán)境下的日志配置 --> <springProfile name="prod"> <root level="INFO"> <appender-ref ref="CONSOLE" /> <appender-ref ref="ERROR_FILE" /> <appender-ref ref="INFO_FILE" /> </root> </springProfile> </configuration>

標(biāo)簽說明:

<root>標(biāo)簽,必填標(biāo)簽觉壶,用來指定最基礎(chǔ)的日志輸出級別
<appender-ref>標(biāo)簽脑题,添加append
<append>標(biāo)簽,通過使用該標(biāo)簽指定日志的收集策略
<filter>標(biāo)簽铜靶,通過使用該標(biāo)簽指定過濾策略
<level>標(biāo)簽指定過濾的類型
<encoder>標(biāo)簽旭蠕,使用該標(biāo)簽下的<pattern>標(biāo)簽指定日志輸出格式
<rollingPolicy>標(biāo)簽指定收集策略,比如基于時間進行收集
<fileNamePattern>標(biāo)簽指定生成日志保存地址旷坦,通過這樣配置已經(jīng)實現(xiàn)了分類分日期收集日志的目標(biāo)了

name屬性指定appender命名
class屬性指定輸出策略,通常有兩種佑稠,控制臺輸出和文件輸出秒梅,文件輸出就是將日志進行一個持久化
ConsoleAppender將日志輸出到控制臺

部分截圖展示:

目錄:

error.log

info.log

sql.log

request.log

2、logback 高級特性異步輸出日志

如果不配置異步輸出規(guī)則舌胶,那么默認(rèn)日志配置方式是基于同步的捆蜀,每次日志輸出到文件都會進行一次磁盤IO。

采用異步寫日志的方式而不讓此次寫日志發(fā)生磁盤IO,阻塞線程從而造成不必要的性能損耗辆它。

異步輸出日志的方式很簡單誊薄,添加一個基于異步寫日志的appender,并指向原先配置的appender即可锰茉。

異步輸出配置:

<!-- 異步輸出INFO_FILE --> <appender name="ASYNC_INFO_FILE" class="ch.qos.logback.classic.AsyncAppender"> <!-- 更改默認(rèn)的隊列的深度,該值會影響性能.默認(rèn)值為256 --> <queueSize>256</queueSize> <!-- 默認(rèn)情況下呢蔫,當(dāng)阻塞隊列的剩余容量為20%時,它將丟棄TRACE飒筑,DEBUG和INFO級別的事件片吊,僅保留WARN和ERROR級別的事件。要保留所有事件协屡,請將discardingThreshold設(shè)置為0俏脊。 --> <discardingThreshold>0</discardingThreshold> <!-- 添加附加的appender,使用前面定義的name,最多只能添加一個 --> <appender-ref ref="INFO_FILE"/> </appender> <!-- 異步輸出ERROR_FILE --> <appender name="ASYNC_ERROR_FILE" class="ch.qos.logback.classic.AsyncAppender"> <!-- 更改默認(rèn)的隊列的深度,該值會影響性能.默認(rèn)值為256 --> <queueSize>256</queueSize> <!-- 默認(rèn)情況下,當(dāng)阻塞隊列的剩余容量為20%時肤晓,它將丟棄TRACE爷贫,DEBUG和INFO級別的事件,僅保留WARN和ERROR級別的事件补憾。要保留所有事件漫萄,請將discardingThreshold設(shè)置為0。 --> <discardingThreshold>0</discardingThreshold> <!-- 添加附加的appender,使用前面定義的name,最多只能添加一個 --> <appender-ref ref="ERROR_FILE"/> </appender> <!-- 異步輸出SQL_FILE --> <appender name="ASYNC_SQL_FILE" class="ch.qos.logback.classic.AsyncAppender"> <!-- 更改默認(rèn)的隊列的深度,該值會影響性能.默認(rèn)值為256 --> <queueSize>256</queueSize> <!-- 默認(rèn)情況下余蟹,當(dāng)阻塞隊列的剩余容量為20%時卷胯,它將丟棄TRACE,DEBUG和INFO級別的事件威酒,僅保留WARN和ERROR級別的事件窑睁。要保留所有事件,請將discardingThreshold設(shè)置為0葵孤。 --> <discardingThreshold>0</discardingThreshold> <!-- 添加附加的appender,使用前面定義的name,最多只能添加一個 --> <appender-ref ref="SQL_FILE"/> </appender> <!-- 異步輸出REQUEST_FILE --> <appender name="ASYNC_REQUEST_FILE" class="ch.qos.logback.classic.AsyncAppender"> <!-- 更改默認(rèn)的隊列的深度,該值會影響性能.默認(rèn)值為256 --> <queueSize>256</queueSize> <!-- 默認(rèn)情況下担钮,當(dāng)阻塞隊列的剩余容量為20%時,它將丟棄TRACE尤仍,DEBUG和INFO級別的事件箫津,僅保留WARN和ERROR級別的事件。要保留所有事件宰啦,請將discardingThreshold設(shè)置為0苏遥。 --> <discardingThreshold>0</discardingThreshold> <!-- 添加附加的appender,使用前面定義的name,最多只能添加一個 --> <appender-ref ref="REQUEST_FILE"/> </appender>

參數(shù)配置:

參數(shù)名稱 參數(shù)類型 建議值 說明queueSizeintqueueSize計算

example:假設(shè)IO影響30s,日志和qps比例是1:1赡模,單容器壓測值1500 qps則可以推算出queue size的值田炭,queueSize的設(shè)置公式:30 *1500=45000。阻塞隊列的最大容量漓柑。默認(rèn)情況下教硫,queueSize設(shè)置為256叨吮。discardingThresholdint

使用默認(rèn)值20,或者設(shè)置大于0瞬矩。

如果設(shè)置discardingThreshold=0茶鉴,表示queue 滿了,不丟棄景用,block線程涵叮。

默認(rèn)情況下,當(dāng)阻塞隊列剩余20%的容量時丛肢,它將丟棄級別跟蹤围肥、調(diào)試和信息事件,只保留級別警告和錯誤事件蜂怎。要保留所有事件穆刻,請將discardingThreshold設(shè)置為0。neverBlockbooleantrue如果為false(默認(rèn)值)杠步,則追加程序?qū)⒆柚棺芳拥酵暾犃星馕埃皇莵G失消息。設(shè)置為true時幽歼,附加程序只會丟棄消息朵锣,不會阻止您的應(yīng)用程序。




官方文檔鏈接:http://logback.qos.ch/manual/appenders.html#AsyncAppender

3甸私、異步日志輸出原理

異步輸出日志中最關(guān)鍵的就是配置文件中ch.qos.logback.classic包下AsyncAppenderBase類中的append方法诚些,查看該方法的源碼:@Override protected void append(E eventObject) { if (isQueueBelowDiscardingThreshold() && isDiscardable(eventObject)) { return; } preprocess(eventObject); put(eventObject); }

通過隊列情況判斷是否需要丟棄日志,不丟棄的話將它放到阻塞隊列中皇型,通過查看代碼诬烹,這個阻塞隊列為queueSize,默認(rèn)大小為256弃鸦,可以通過配置文件進行修改绞吁。

/** * The default buffer size. */ public static final int DEFAULT_QUEUE_SIZE = 256; int queueSize = DEFAULT_QUEUE_SIZE;

Logger.info(...)到append(...)就結(jié)束了,只做了將日志塞入到阻塞隊列的事唬格,然后繼續(xù)執(zhí)行Logger.info(...)下面的語句了家破。在AsyncAppenderBase類中定義了一個Worker線程,run()方法中的代碼如下:

Worker worker = new Worker();class Worker extends Thread { public void run() { AsyncAppenderBase<E> parent = AsyncAppenderBase.this; AppenderAttachableImpl<E> aai = parent.aai; // loop while the parent is started while (parent.isStarted()) { try { E e = parent.blockingQueue.take(); aai.appendLoopOnAppenders(e); } catch (InterruptedException ie) { break; } } addInfo("Worker thread will flush remaining events before exiting. "); for (E e : parent.blockingQueue) { aai.appendLoopOnAppenders(e); parent.blockingQueue.remove(e); } aai.detachAndStopAllAppenders(); } }

從阻塞隊列中取出一個日志购岗,并調(diào)用AppenderAttachableImpl類中的appendLoopOnAppenders方法維護一個Append列表汰聋。

最主要的兩個方法就是encode和write方法,前一個法方會根據(jù)配置文件中encode指定的方式轉(zhuǎn)化為字節(jié)碼喊积,后一個方法將轉(zhuǎn)化成的字節(jié)碼寫入到文件中去烹困。

所以寫文件是通過新起一個線程去完成的,主線程將日志放到阻塞隊列中注服,然后又去執(zhí)行其他任務(wù)韭邓。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市溶弟,隨后出現(xiàn)的幾起案子女淑,更是在濱河造成了極大的恐慌,老刑警劉巖辜御,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鸭你,死亡現(xiàn)場離奇詭異,居然都是意外死亡擒权,警方通過查閱死者的電腦和手機袱巨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來碳抄,“玉大人愉老,你說我怎么就攤上這事∑市В” “怎么了嫉入?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長璧尸。 經(jīng)常有香客問我咒林,道長,這世上最難降的妖魔是什么爷光? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任垫竞,我火速辦了婚禮,結(jié)果婚禮上蛀序,老公的妹妹穿的比我還像新娘欢瞪。我一直安慰自己,他們只是感情好哼拔,可當(dāng)我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布引有。 她就那樣靜靜地躺著,像睡著了一般倦逐。 火紅的嫁衣襯著肌膚如雪譬正。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天檬姥,我揣著相機與錄音曾我,去河邊找鬼。 笑死健民,一個胖子當(dāng)著我的面吹牛抒巢,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播秉犹,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼蛉谜,長吁一口氣:“原來是場噩夢啊……” “哼稚晚!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起型诚,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤客燕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后狰贯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體也搓,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年涵紊,在試婚紗的時候發(fā)現(xiàn)自己被綠了傍妒。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡摸柄,死狀恐怖颤练,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情塘幅,我是刑警寧澤昔案,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站电媳,受9級特大地震影響踏揣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜匾乓,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一楞黄、第九天 我趴在偏房一處隱蔽的房頂上張望熊锭。 院中可真熱鬧茫经,春花似錦了嚎、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至继阻,卻和暖如春耻涛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瘟檩。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工抹缕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人墨辛。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓卓研,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子奏赘,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,512評論 2 359