摘要:在中對(duì)一個(gè)實(shí)例命名非常的簡(jiǎn)單,在每一個(gè)類中可以有一個(gè)靜態(tài)的實(shí)例對(duì)象,可以用類的完全限定名作為實(shí)例的名字。但不管怎樣,用類的完全限定名作為實(shí)例的名字是一個(gè)非常好的方式。
本文是對(duì)log4j官網(wǎng)Introduction部分的翻譯,原文鏈接地址:http://logging.apache.org/log...。
Introduction:幾乎每個(gè)大型應(yīng)用都包含自己的日志API。1996年,為了整個(gè)項(xiàng)目的一致性,E.U.?SEMPER項(xiàng)目團(tuán)隊(duì)決定開發(fā)自己的日志API。經(jīng)過(guò)無(wú)數(shù)次的改進(jìn),這款日志API成為了Java領(lǐng)域非常流行的日志package,這就是log4j。
在代碼中加日志進(jìn)行調(diào)試是一種低級(jí)的方式。但因?yàn)檎{(diào)試工具并不總是可以使用,所以打日志有時(shí)候是唯一的調(diào)試方法。例如多線程應(yīng)用和分布式應(yīng)用。
有經(jīng)驗(yàn)表明在軟件開發(fā)周期中,日志組件占有重要的地位。加入日志有許多好處??梢酝ㄟ^(guò)日志精確了解應(yīng)用運(yùn)行的狀態(tài)。加入代碼中的日志,無(wú)需人們手工干預(yù)就可自動(dòng)生成輸出結(jié)果。日志的輸出結(jié)果可以保存在永久存儲(chǔ)介質(zhì)上,方便今后對(duì)其進(jìn)行查看。此外,在軟件開發(fā)周期中,充足豐富的日志也可以當(dāng)做審計(jì)材料使用。
日志也有缺點(diǎn),它會(huì)使應(yīng)用程序變慢。如果日志過(guò)多,還會(huì)導(dǎo)致屏幕閃動(dòng)。為了緩和這些缺點(diǎn),log4j被設(shè)計(jì)成可靠的、快速的和可擴(kuò)展的。由于日志很少是一個(gè)應(yīng)用中關(guān)注的重點(diǎn),所以log4j的API盡可能設(shè)計(jì)的簡(jiǎn)單易懂。
log4j主要有三大組件——loggers、appenders和layouts。這三大組建共同協(xié)作,使開發(fā)者可以根據(jù)不同的日志級(jí)別和日志類型輸出信息,并且可以指定信息輸出的格式和信息輸出的目的地。
Logger hierarchy相比于使用簡(jiǎn)單的System.out.println語(yǔ)句,日志API最大的優(yōu)勢(shì)就是它可以禁止某一類型的日志輸出,同時(shí)又不影響其它類型的日志輸出。要實(shí)現(xiàn)這種能力,需要開發(fā)人員根據(jù)某種條件,將日志劃分為不同的類型。老版本的log4j將Category類作為核心就是由于上面這個(gè)原因。但log4j到1.2版本時(shí),已經(jīng)使用Logger類代替了原來(lái)的Category類。對(duì)于那些熟悉老版本log4j的人,可以簡(jiǎn)單把Logger類當(dāng)做Category類的一個(gè)別名。
Loggers是被命名的實(shí)體,Logger的名稱是大小寫敏感的,并且遵循層次命名規(guī)則。
舉個(gè)例子,命名為“com.foo”的logger是命名為“com.foo.Bar”的logger的父親。命名為“java”的logger是命名為“java.util”的logger的父親,是命名為“java.util.Vector”的祖先。這種命名規(guī)則應(yīng)該被許多研發(fā)人員所熟悉。
root logger位于整個(gè)logger繼承體系的最頂端,相比于普通logger它有兩個(gè)特別之處:
root logger總是存在。
root logger不能通過(guò)名稱獲取。
可以通過(guò)調(diào)用Logger類的靜態(tài)方法getRootLogger獲取root logger對(duì)象。其它普通logger的實(shí)例可以通過(guò)Logger類的另一個(gè)靜態(tài)方法getLogger獲取。getLogger方法接受一個(gè)參數(shù)作為logger的名字。
Logger類中的其它一些基本方法如下所示:
package org.apache.log4j; public class Logger { // Creation & retrieval methods: public static Logger getRootLogger(); public static Logger getLogger(String name); // printing methods: public void trace(Object message); public void debug(Object message); public void info(Object message); public void warn(Object message); public void error(Object message); public void fatal(Object message); // generic printing method: public void log(Level l, Object message); }
Loggers可以被分配日志級(jí)別,可以分配的級(jí)別如下:
TRACE
DEBUG
INFO
WARN
ERROR和
FATAL
這些級(jí)別被定義在org.apache.log4j.Level類中。雖然你也可以通繼承Level類定義你自己的專有級(jí)別,但是我們不鼓勵(lì)你這樣做。
如果一個(gè)logger沒(méi)有指定任何level,那么這個(gè)logger會(huì)從它的父親那里繼承l(wèi)evel。
為了保證所有的logger可以最終被指定一個(gè)level,root logger總是被分配一個(gè)level。
下面四個(gè)表是上面規(guī)則的例子:
Example 1
在第一個(gè)例子中,只有root logger被分配了一個(gè)level值Proot,Proot會(huì)被其它所有的logger——x、x.y、x.y.z繼承。
Example 2
在第二個(gè)例子中,所有的logger都被分配了一個(gè)level值,就不需要繼承l(wèi)evel了。
Example 3
在第三個(gè)例子中,root、x和x.y.z三個(gè)logger分別被分配了Proot、Px和Pxyz三個(gè)level值,x.y這個(gè)logger從它的父親那里繼承l(wèi)evel值。
Example 4
在第四個(gè)例子中,root和x兩個(gè)logger分別被分配了Proot和Px這兩個(gè)level值。x.y和x.y.z兩個(gè)logger則從離自己最近的祖先x繼承l(wèi)evel值。
可以調(diào)用logger實(shí)例的printing方法輸入日志。printing方法包括debug、info、warn、error、fatal和log。
按照定義,printing方法決定了日志請(qǐng)求的等級(jí)。例如,c是一個(gè)logger實(shí)例,c.info("..")語(yǔ)句請(qǐng)求輸出INFO級(jí)別的日志。
只有日志請(qǐng)求級(jí)別大于等于日志級(jí)別的時(shí)候,日志請(qǐng)求才會(huì)被準(zhǔn)許輸出信息。否則,日志請(qǐng)求會(huì)被禁止。這條規(guī)則是log4j的核心。日志的level是有序的。對(duì)于標(biāo)準(zhǔn)的日志級(jí)別:DEBUG
// get a logger instance named "com.foo" Logger logger = Logger.getLogger("com.foo"); // Now set its level. Normally you do not need to set the // level of a logger programmatically. This is usually done // in configuration files. logger.setLevel(Level.INFO); Logger barlogger = Logger.getLogger("com.foo.Bar"); // This request is enabled, because WARN >= INFO. logger.warn("Low fuel level."); // This request is disabled, because DEBUG < INFO. logger.debug("Starting search for nearest gas station."); // The logger instance barlogger, named "com.foo.Bar", // will inherit its level from the logger named // "com.foo" Thus, the following request is enabled // because INFO >= INFO. barlogger.info("Located nearest gas station."); // This request is disabled, because DEBUG < INFO. barlogger.debug("Exiting gas station search");
用相同的名字參數(shù)調(diào)用getLogger方法總是會(huì)返回同一個(gè)logger對(duì)象的引用,例如在下面兩行代碼中:
Logger x = Logger.getLogger("wombat"); Logger y = Logger.getLogger("wombat");
x和y引用的是同一個(gè)logger對(duì)象。
這樣在配置好一個(gè)logger實(shí)例之后,可以很方便的在代碼的其它地方獲取到這個(gè)logger實(shí)例,而無(wú)需傳遞logger實(shí)例的引用。
與生物學(xué)中的父子關(guān)系不同,log4j中的父親不一定總是早于它的孩子出生。log4j中的logger實(shí)例可以以任意的順序被構(gòu)造或配置。一個(gè)parent logger即使在它的后代之后被實(shí)例化,它們也依然可以建立起父子關(guān)系。
log4j的配置通常會(huì)在應(yīng)用初始化時(shí)被完成。最常用的方式是通過(guò)讀取配置文件完成配置。稍后會(huì)討論這個(gè)過(guò)程。
在log4j中對(duì)一個(gè)logger實(shí)例命名非常的簡(jiǎn)單,在每一個(gè)類中可以有一個(gè)靜態(tài)的logger實(shí)例對(duì)象,可以用類的完全限定名作為logger實(shí)例的名字。這對(duì)于定義一個(gè)logger非常有用,由于在輸出日志的時(shí)候可以帶有l(wèi)ogger實(shí)例的名字,所以這種用類的完全限定名作為logger實(shí)例的名字可以很容易看出日志發(fā)生的位置。當(dāng)然這只是一種通用做法,log4j對(duì)此并沒(méi)有限制,開發(fā)人員可以隨意指定logger實(shí)例的名字。但不管怎樣,用類的完全限定名作為logger實(shí)例的名字是一個(gè)非常好的方式。
禁止和允許日志輸出的能力只是全部功能的一部分。log4j允許將日志輸出到多個(gè)目的地。在log4j的術(shù)語(yǔ)中,日志輸出目的地被稱為appender。目前,存在的appender包括命令行、文件、GUI組件、遠(yuǎn)程socket服務(wù)器、JMS、NT事件日志和遠(yuǎn)程UNIX Syslog后臺(tái)進(jìn)程。并且可以支持異步的方式記錄日志。
一個(gè)logger實(shí)例可以同時(shí)掛載多個(gè)appender。
addAppender方法向logger實(shí)例添加一個(gè)appender。對(duì)于每一個(gè)被允許的日志輸出請(qǐng)求,logger實(shí)例不僅將該請(qǐng)求轉(zhuǎn)發(fā)到自己所有的appender上,而且還將日志輸出請(qǐng)求轉(zhuǎn)發(fā)到它祖先上的所有appender上。例如,如果一個(gè)命令行appender被添加到root logger上,那么所有被允許的日志請(qǐng)求至少會(huì)輸出到命令行中。如果在這個(gè)基礎(chǔ)上再向C logger中添加一個(gè)文件appender,那么對(duì)于C和它的后代,被允許的日志會(huì)同時(shí)輸出到命令行和文件。通過(guò)將additivity flag設(shè)置為false,可以覆蓋這種默認(rèn)行為。
Appender Additivity:對(duì)C logger的日志輸出請(qǐng)求會(huì)轉(zhuǎn)發(fā)到C自己和它祖先們的全部appender。這種行為用術(shù)語(yǔ)“appender additivity”表示。如果 P是C的祖先,P將additivity flag設(shè)置為false。那么C的日志會(huì)輸出到它自己的appender和C到P之間(包括P)每個(gè)logger的appender,而不會(huì)輸出到P以上祖先的appender。對(duì)于每個(gè)logger,它的additivity flag默認(rèn)是設(shè)置為true的。
下面的表格是這樣的一個(gè)例子:
通常,研發(fā)不僅希望指定日志輸出的目的地,而且希望能夠指定日志輸出的格式??梢栽赼ppender上關(guān)聯(lián)一個(gè)layout用于指定日志輸出格式。layout會(huì)按照用戶的意愿輸出一定格式的日志信息。
PatternLayout可以讓用戶像使用C語(yǔ)言中的printf那樣使用格式化表達(dá)式定制日志輸出的格式。
例如,使用PatternLayout的表達(dá)式"%r [%t] %-5p %c - %m%n”可以包含下面日志信息:
176 [main] INFO org.foo.Bar - Located nearest gas station.
第一個(gè)字段是程序啟動(dòng)到現(xiàn)在經(jīng)過(guò)的毫秒數(shù),第二個(gè)字段是輸出日志的線程,第三個(gè)字段是日志的級(jí)別,第四個(gè)字段是logger的名字?!?’后面的文本是日志輸出信息。%n是換行。
log4j會(huì)按照用戶指定的具體條件輸出日志內(nèi)容。例如,如果你頻繁的需要輸出Orange類對(duì)象的日志,那么一可以注冊(cè)一個(gè)OrangeRenderer,每當(dāng)輸出orange的日志時(shí),它都會(huì)被調(diào)用。
Object rendering follows the class hierarchy. For example, assuming oranges are fruits, if you register a?FruitRenderer, all fruits including oranges will be rendered by the?FruitRenderer, unless of course you registered an orange specific?OrangeRenderer.
Object renderers have to implement the?ObjectRenderer?interface.
在現(xiàn)有應(yīng)用中加入日志需要大量的工作。調(diào)研表明,大約有接近4%的代碼跟日志有關(guān)。因此,即使不是那么大的應(yīng)用也會(huì)有成千上萬(wàn)行的日志代碼。Given their number, it becomes imperative to manage these log statements without the need to modify them manually.
og4j環(huán)境是完全可以通過(guò)寫程序進(jìn)行配置的。然而,使用配置文件對(duì)log4j進(jìn)行配置會(huì)更加的靈活。目前,配置文件可以采用XML和properties兩種格式的文件。
import com.foo.Bar; // Import log4j classes. import org.apache.log4j.Logger; import org.apache.log4j.BasicConfigurator; public class MyApp { // Define a static logger variable so that it references the // Logger instance named "MyApp". static Logger logger = Logger.getLogger(MyApp.class); public static void main(String[] args) { // Set up a simple configuration that logs on the console. BasicConfigurator.configure(); logger.info("Entering application."); Bar bar = new Bar(); bar.doIt(); logger.info("Exiting application."); } }
MyApp在導(dǎo)入了log4j相關(guān)的類,然后用MyApp的全限定類名定義了一個(gè)靜態(tài)的logger實(shí)例變量。
MyApp中使用的Bar類:
package com.foo; import org.apache.log4j.Logger; public class Bar { static Logger logger = Logger.getLogger(Bar.class); public void doIt() { logger.debug("Did it again!"); } }
調(diào)用BasicConfigurator.configure方法創(chuàng)建了一個(gè)非常簡(jiǎn)單的log4j配置。它以硬編碼的方式向root logger中添加了一個(gè)ConsoleAppender,日志輸出會(huì)使用PatternLayout的模板"%-4r [%t] %-5p %c %x - %m%n”進(jìn)行格式化。注意默認(rèn)情況下,root logger被分配的日志級(jí)別是Level.DEBUG。
上面程序輸入的日志為:
0 [main] INFO MyApp - Entering application. 36 [main] DEBUG com.foo.Bar - Did it again! 51 [main] INFO MyApp - Exiting application.
下面的圖形是MyApp在調(diào)用完BasicConfigurator.configure方法之后的對(duì)象圖:
前面的這種方式只能一直輸出同一種配置模式的日志信息,可以很容易的在MyApp啟動(dòng)時(shí)修改日志配置信息,使其輸出不同配置模式的日志。
import com.foo.Bar; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; public class MyApp { static Logger logger = Logger.getLogger(MyApp.class.getName()); public static void main(String[] args) { // BasicConfigurator replaced with PropertyConfigurator. PropertyConfigurator.configure(args[0]); logger.info("Entering application."); Bar bar = new Bar(); bar.doIt(); logger.info("Exiting application."); } }
這個(gè)版本的MyApp使用PropertyConfigurator解析文件并對(duì)日志進(jìn)行配置。
下面這個(gè)配置文件產(chǎn)生的配置結(jié)果與之前使用BasicConfigurator產(chǎn)生的結(jié)果完全相同。
# Set root logger level to DEBUG and its only appender to A1. log4j.rootLogger=DEBUG, A1 # A1 is set to be a ConsoleAppender. log4j.appender.A1=org.apache.log4j.ConsoleAppender # A1 uses PatternLayout. log4j.appender.A1.layout=org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
如果我們不再對(duì)com.foo包中任何組件輸出的日志感興趣,下面的配置文件可以實(shí)現(xiàn)這一點(diǎn):
log4j.rootLogger=DEBUG, A1 log4j.appender.A1=org.apache.log4j.ConsoleAppender log4j.appender.A1.layout=org.apache.log4j.PatternLayout # Print the date in ISO 8601 format log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p %c - %m%n # Print only messages of level WARN or above in the package com.foo. log4j.logger.com.foo=WARN
現(xiàn)在MyApp的日志輸出如下:
2000-09-07 14:07:41,508 [main] INFO MyApp - Entering application. 2000-09-07 14:07:41,529 [main] INFO MyApp - Exiting application.
由于logger com.foo.Bar沒(méi)有被指定任何的日志級(jí)別,所以它會(huì)從com.foo上繼承,在配置文件中指定com.foo的日志級(jí)別是WARN,而代碼Bar.doIt中的log語(yǔ)句日志請(qǐng)求輸出的是DEBUG級(jí)別,要比WARN級(jí)別低,所以doIt方法中的日志請(qǐng)求不會(huì)被響應(yīng)。
下面是另一個(gè)配置文件,它使用了多個(gè)appenders:
log4j.rootLogger=debug, stdout, R log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout # Pattern to output the caller"s file name and line number. log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n log4j.appender.R=org.apache.log4j.RollingFileAppender log4j.appender.R.File=example.log log4j.appender.R.MaxFileSize=100KB # Keep one backup file log4j.appender.R.MaxBackupIndex=1 log4j.appender.R.layout=org.apache.log4j.PatternLayout log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n
使用這個(gè)配置文件會(huì)向命令行輸出如下日志信息:
INFO [main] (MyApp2.java:12) - Entering application. DEBUG [main] (Bar.java:8) - Doing it again! INFO [main] (MyApp2.java:15) - Exiting application.
此外,root logger被分配的第二個(gè)appender,是將日志信息直接輸出到example.log文件中的。當(dāng)example.log文件到達(dá)100KB時(shí),會(huì)發(fā)生roll-over。這時(shí)老版本的example.log會(huì)自動(dòng)移動(dòng)到example.log.1。
注意到要改變?nèi)罩拘袨闊o(wú)需重新編譯代碼。我們可以改變配置文件讓其日志輸出到UNIX Syslog daemon、將所有的com.foo輸出的日志都重定向到NT Event logger、或者將日志事件轉(zhuǎn)發(fā)到遠(yuǎn)程的log4j服務(wù)器。
log4j庫(kù)沒(méi)有對(duì)它的運(yùn)行環(huán)境做過(guò)任何的假設(shè)。也就是說(shuō),log4j沒(méi)有任何默認(rèn)的appender。然而在一些環(huán)境下,日志類的靜態(tài)初始化器會(huì)自動(dòng)嘗試配置log4j。Java從語(yǔ)言層面保證在類加載的時(shí)候,靜態(tài)初始化器會(huì)被調(diào)用一次且僅被調(diào)用一次。但是要額外留意不同的classloader可能會(huì)對(duì)同一個(gè)類加載多個(gè)副本。
The default initialization is very useful in environments where the exact entry point to the application depends on the runtime environment. For example, the same application can be used as a stand-alone application, as an applet, or as a servlet under the control of a web-server.
The exact default initialization algorithm is defined as follows:
設(shè)置log4j.defaultInitOverride系統(tǒng)屬性為非false值會(huì)導(dǎo)致log4j略過(guò)默認(rèn)的初始化過(guò)程
設(shè)置log4j.configuration系統(tǒng)屬性的字符串值。通過(guò)設(shè)置log4j.configuration系統(tǒng)屬性的值指定默認(rèn)初始化文件是最常用的方式。如果系統(tǒng)屬性log4j.configuration沒(méi)有被明確定義,則為它分配默認(rèn)值為log4j.properties。log4j.configuration的值記為resource變量。
嘗試將resource變量轉(zhuǎn)換為url。
如果resource變量無(wú)法轉(zhuǎn)化為url,比如在轉(zhuǎn)化url時(shí)發(fā)生MalformedURLException異常,那么調(diào)用org.apache.log4j.helpers.Loader.getResource(resource, Logger.class)在classpath中尋找resource并返回一個(gè)url。
如果找不到url,終止默認(rèn)初始化,否則使用url對(duì)log4j進(jìn)行配置。
如果url不是以“.xml”為后綴,那么將會(huì)使用PropertyConfigurator解析url并對(duì)log4j進(jìn)行配置。如果url的后綴是“.xml”,那么將會(huì)使用DOMConfigurator完成上述工作。你可以隨意指定一個(gè)定制的配置器(configurator)。log4j.configuratorClass系統(tǒng)屬性的值就是你定制配置器的全限定類名。你自己定制的配置器必須實(shí)現(xiàn)Configurator這個(gè)接口。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/67570.html
摘要:本文要來(lái)分享給大家程序員最常用的日志框架組件。沒(méi)有基礎(chǔ)的同學(xué)也不要著急,這套教程覆蓋了目前所有的日志框架,只要你學(xué),就一定用得到,先收藏,以備不時(shí)之需。 作為一名Java程序員,我們開發(fā)了很多Java應(yīng)用程序,包括桌面應(yīng)用、WEB應(yīng)用以及移動(dòng)應(yīng)用。然而日志系統(tǒng)是一個(gè)成熟Java應(yīng)用所必不可少的。在開發(fā)和調(diào)試階段,日志可以幫...
摘要:項(xiàng)目介紹在之前的整合項(xiàng)目之后,新增日志簡(jiǎn)單集成,之前的代碼不予展示與介紹,想了解的請(qǐng)參考整合項(xiàng)目項(xiàng)目代碼獲取項(xiàng)目結(jié)構(gòu)代碼控制層,,主要包含登錄及幾個(gè)頁(yè)面跳轉(zhuǎn)會(huì)跳到我們自定義的中登錄用戶名或密碼錯(cuò)誤業(yè)務(wù)處理層,包含一個(gè)包,以接口類型存在 spring-springmvc-mybatis-shiro項(xiàng)目介紹 在之前的mybatis整合項(xiàng)目之后,新增日志、簡(jiǎn)單集成shiro,之前的代碼不予展...
摘要:作為一個(gè)實(shí)用主義者,我喜歡在理解基本原理后快速的搭建系統(tǒng),當(dāng)系統(tǒng)運(yùn)行起的時(shí)候有那種愉悅和興奮。,著手搭建,我用的是進(jìn)行的。要使用日志系統(tǒng),就需要進(jìn)行相關(guān)配置,這個(gè)不用我多說(shuō)了叁。 作為一個(gè)實(shí)用主義者,我喜歡在理解基本原理后快速的搭建系統(tǒng),當(dāng)系統(tǒng)運(yùn)行起的時(shí)候有那種愉悅和興奮。最近在完善公司框架,從最基本的日志系統(tǒng)開始。 java日志系統(tǒng)比較流行的是log4j,slf4j和logbac...
摘要:但是考慮到各不相同,所以出現(xiàn)了等日志框架。日志框架只是統(tǒng)一的,其底層的具體的日志記錄工作還是由等承擔(dān)。如何選擇和搭配日志系統(tǒng)目前來(lái)說(shuō),新應(yīng)用使用是首選,一些老系統(tǒng)中很可能使用的是等。所以若日志沖突時(shí),使用的三方庫(kù)只需要相應(yīng)的實(shí)現(xiàn)庫(kù)即可。 日志系統(tǒng)的發(fā)展 我們?nèi)粘=佑|到的日志系統(tǒng)有很多種,log4j,JUL(jdk自帶),logback等,我們可以直接根據(jù)對(duì)象的日志API進(jìn)行使用。但是考...
摘要:今天在配置日志的時(shí)候,發(fā)現(xiàn)日志重復(fù)打印的問(wèn)題。把配置文件修改成如下日志控制臺(tái)日志級(jí)別日志級(jí)別日志級(jí)別日志通過(guò)以上配置模板即可解決各級(jí)別日志重復(fù)打印的問(wèn)題。 今天在配置Log4j日志的時(shí)候,發(fā)現(xiàn)日志重復(fù)打印的問(wèn)題。網(wǎng)上查了很多資料,發(fā)現(xiàn)介紹Log4j配置的文章數(shù)量不少,但提到這個(gè)問(wèn)題的文章卻寥寥,解決了自己的問(wèn)題以后,趕緊記錄一下。 原文地址:http://www.jianshu.com...
閱讀 2143·2021-10-14 09:43
閱讀 2204·2019-08-30 15:55
閱讀 736·2019-08-30 14:23
閱讀 2028·2019-08-30 13:21
閱讀 1244·2019-08-30 12:50
閱讀 2207·2019-08-29 18:46
閱讀 2289·2019-08-29 17:28
閱讀 2373·2019-08-29 17:21