logger源碼
1. 如何使用 Monolog 記錄日誌
monolog是一個為5.3以上版本php開發的日誌庫,但是需要注意的是現在主幹版本只支持php 7以上版本,如果你的伺服器環境還是php 5的話,可以使用monolog的1.x版本。
值得一提的是monolog是一個符合psr-3規范的日誌類庫,並且符合psr-4載入規范。如果有對psr規范不太了解的同學可以參看如下鏈接:http://www.php-fig.org/psr/,我們在這里就不具體介紹這些規范了,反正知道monolog是復合當前最新行業規范的日誌庫就夠了。
如果想要在你的代碼中引入monolog的話只需要執行:
composer require monolog/monolog
mongolog中有幾個很重要的概念:
第一個:handler 日誌管理器
存放handler的數據結構是一個「棧」,一個日誌實例可以有多個handler,通過Logger實例的pushHandler方法壓入一個handler,該方法接受一個HandlerInterface類型的參數。如果你設置了多個handler,當你新增一條日誌的時候,他會從棧頂開始往下傳播,關心這個級別日誌的handler將會處理這條日誌。所有的handler都會繼承AbstractProcessingHandler這個抽象類,並且只需要實現裡面的抽象方法write就可以了;同時這個抽象類會繼承AbstractHandler這個抽象類,這個抽象類的構造函數有兩個參數:level和bubble,前者表示該handler關心的最低日誌級別,是個整型,後者表示日誌被當前handler處理後是否接著向下傳遞。參照如下代碼:
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\ErrorLogHandler;
$logger = new Logger('my_logger');
$logger->pushHandler(new StreamHandler(__DIR__.'/my_app.log', Logger::INFO));
$logger->pushHandler(new ErrorLogHandler(ErrorLogHandler::OPERATING_SYSTEM, Logger::ERROR, false));
$logger->info('碼王教育——可能是最具含金量的IT培訓');
如上這段代碼,這條日誌被ErrorLogHandler處理了,並且ErrorLogHandler的bubble參數設置為false,則日誌不會被寫入my_app.log中了。
第二個:formatter 設置日誌格式
每個handler可以單獨設置記錄的日誌格式,AbstractHandler抽象類中有一個setFormatter方法,該參數接受一個FormatterInterface類型的參數。可以看到monolog自帶的formatter都繼承自NormalizerFormatter,該類實現了format和formatBatch方法。我們修改上面的示例代碼,讓兩個handler記錄不同格式的日誌:
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\ErrorLogHandler;
use Monolog\Formatter\JsonFormatter;
$logger = new Logger('my_logger');
$stream_handler = new StreamHandler(__DIR__.'/my_app.log', Logger::INFO);
$stream_handler->setFormatter(new JsonFormatter());
$logger->pushHandler($stream_handler);
$logger->pushHandler(new ErrorLogHandler(ErrorLogHandler::OPERATING_SYSTEM, Logger::INFO));
$logger->info('碼王教育——可能是最具含金量的IT培訓');
此時可以看到my_app.log中記錄的日誌就變為了更方便解析的json格式了。
第三個:processor 日誌處理器,用來給日誌添加額外信息
存放processor的結構也是一個「棧」,意味著你也可以通過pushProcessor方法給一個Logger實例配置多個processor。我們注意到,這里pushProcessor接受一個callable,也就是需要一個函數或者類方法,但是官方自帶的這些processor都是類,隨便點進去一個源碼就會發現,其實這些類都用到了__invoke魔術方法,所以在被當做callable調用的時候會自動調用__invoke。我們接著修改上面示例,給我們的日誌加上更多信息:
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\ErrorLogHandler;
use Monolog\Formatter\JsonFormatter;
use Monolog\Processor\UidProcessor;
use Monolog\Processor\ProcessIdProcessor;
$logger = new Logger('my_logger');
$stream_handler = new StreamHandler(__DIR__.'/my_app.log', Logger::INFO);
$stream_handler->setFormatter(new JsonFormatter());
$logger->pushHandler($stream_handler);
$logger->pushHandler(new ErrorLogHandler(ErrorLogHandler::OPERATING_SYSTEM, Logger::INFO));
$logger->pushProcessor(new UidProcessor);
$logger->pushProcessor(new ProcessIdProcessor);
$logger->info('碼王教育——可能是最具含金量的IT培訓');
再次執行這段代碼就能看到,我們在日的後面加上了uid和process_id。
祝福樓主
2. python中的logger和handler到底是個什麼鬼
最近的任務經常涉及到日誌的記錄,特意去又學了一遍logging的記錄方法。跟java一樣,python的日誌記錄也是比較繁瑣的一件事,在寫一條記錄之前,要寫好多東西。典型的日誌記錄的步驟是這樣的:
創建logger
創建handler
定義formatter
給handler添加formatter
給logger添加handler
寫成代碼差不多就是醬嬸的(這個是照別的網頁抄的,參考附註):
1 import logging
2
3 # 1、創建一個logger
4 logger = logging.getLogger('mylogger')
5 logger.setLevel(logging.DEBUG)
6
7 # 2、創建一個handler,用於寫入日誌文件
8 fh = logging.FileHandler('test.log')
9 fh.setLevel(logging.DEBUG)
10
11 # 再創建一個handler,用於輸出到控制台
12 ch = logging.StreamHandler()
13 ch.setLevel(logging.DEBUG)
14
15 # 3、定義handler的輸出格式(formatter)
16 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
17
18 # 4、給handler添加formatter
19 fh.setFormatter(formatter)
20 ch.setFormatter(formatter)
21
22 # 5、給logger添加handler
23 logger.addHandler(fh)
24 logger.addHandler(ch)
之後才可以正式的開始記錄日誌。Java裡面的java.util.Logging類差不多也是這樣,代碼還要更復雜一點。Golang的日誌相對
寫法簡單一些,不過沒有什麼格式,系統記錄一條時間,內容格式完全自己手畫。第三方的日誌庫倒是沒有接觸過,像Java的Log4j,Golang的
log4go和seelog等等,不知道用起來會不會簡單一點。我一直都記不住這些,因為不太理解logger和handler為什麼要這樣寫。一直到這
次任務中出現的在我看來相當「詭異」的bug,才深入理解了一下。
我的任務是這樣的,要做一個日誌切割的工具,按天將日誌分割開,即每天0點產生一個新日誌,將舊日誌改名。並且,將超過3個月的日誌刪除掉,以保證磁碟空間不會被log占滿。程序要求可以切割多個目錄中的不同日誌,具體路徑由json中配置。
這里用到了logging.handlers類中的TimedRotatingFileHandler方法,用以獲得一個handler。大概的寫法為:
1 logger = logging.getLogger() #獲得logger
2 handler = logging.handlers.TimedRotatingFileHandler(logfile, 'S', 1, 0) #切割日誌
3 handler.suffix = '%Y%m%d' #切割後的日誌設置後綴
4 logger.addHandler(handler) #把logger添加上handler
5 logger.fatal(datetime.datetime.now().strftime('%Y-%m-%d')) #在新日誌中寫上當天的日期
這里我沒有設置level和formatter。因為只是分割,對新日誌沒有什麼影響。TimedRotatingFileHandler函數的方
法見附註,或查看python的源碼,這個函數是python寫的,可以找到定義。這里我使用的是每秒生成一個新的日誌文件,之後用Crontab在每天
0點調度,然後用for循環處理json中的每一個日誌文件。
但是奇怪的是,每次運行程序,第一個切割的日誌生成一個分割後的文件,而後面的都生成兩個新日誌。百思不得其解。後檢查代碼覺得,可能是程序中設置
的時間太短了,每秒生成一個文件,有可能一秒鍾處理不完,就生成了兩個。雖然這個說法沒有什麼科學根據,但是還是把
TimedRotatingFileHandler中的第三個參數改成了60,即每60秒生成一個文件。完成,靜靜的等待crontab到時間。
3. php+curl獲取的表單源碼,以字元串轉換為數組
function sendcheck($url,$code)
{
global $logger;
$ch = curl_init();
if(!$ch)return -1; //設置適當的參數
curl_setopt($ch, CURLOPT_URL , $url);//連接
if(!curl_setopt($ch, CURLOPT_HEADER, 0)) return -2; //發送,設置curl_exec執行結果返回,成功返回獲得內容,否則false
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); //返回值為空
if(!curl_setopt($ch,CURLOPT_TIMEOUT ,30))return -3; //執行curl操作最大時間為 10 s
if(!curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,30))return -4 ; //curl對外連接大時間為 10 s
$result = curl_exec($ch); //訪問資源;
//伺服器無響應或者網路連接錯誤處理,重新發送請求信息,最多10次,每次 10 s 間隔
for($i =0 ; $i <= 9; $i++ ){
if(!$result){ //上一次未得到數據
$result = curl_exec($ch); //下一次的數據發送;
}else{
$logger->info("已成功通知");
break;
}
}
if(!$result){
$logger->info("通知失敗");
}
curl_close($ch); //關閉curl資源
}
4. 實驗室管理系統源碼
public FoPage findAllOperationAgent(OperationAgentBaseEntity entity,
int pageNum, int pageSize){
logger.info("查找空餘實驗室");
FoHQLQuery query = new FoHQLQuery();
String hql = "from OperationAgentBaseEntity a ";
//查詢條件
String wheresql = " where 1=1 ";
//實驗室名字或編號
if(entity.getAgentname()!=null&&!entity.getAgentname().trim().equals("")){
whereSql += " and a.agentname like :agentName";
query.setString("agentName", "%"+entity.getAgentname()+"%");
}
//顯示條數
String countHql = "select count(*) " + hql+ whereSql; query.setHQL(hql + whereSql + " order by a.agentname ");
query.setCountHQL(countHql );
query.setPageNum(pageNum);
query.setpageSize(pageSize);
return this.execFoPageQuery(query);
} public String delOperationAgentEntity(final String[] agentCode){
logger.info("刪除當前已使用實驗室");
String message = "delError";
try
{
message = (String)this.getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Transaction tx = session.beginTransaction();
try {
for(int i=0;agentCode!=null&&i<agentCode.length;i++){
SQLQuery delAgentQuery = session.createSQLQuery("delete from operation_agent_base c where c.agentcode ='"+agentCode[i]+"'");
SQLQuery delTelQuery = session.createSQLQuery("delete from OPERATION_CUSTOMER_TELEPHONE c where c.customernum ='"+agentCode[i]+"'");
delAgentQuery.executeUpdate();
delTelQuery.executeUpdate();
}
tx.commit();
}catch(Exception e){
tx.rollback();
logger.error("刪除\r\n"+e.toString());
e.printStackTrace();
throw new HibernateException(e);
}
return "delSuccess";
}
}
);
}catch(Exception e)
{
logger.error("刪除\r\n"+e.toString());
message = "delError";
}
return message;
}
遇到相同的有提示就xietiaosql判斷下 select count(*) from tbl where houseId = ? 如果返回值等於0 則無相同 反之則反
5. m-logger是什麼如何使用
是blog的一個php源碼程序,安裝到支持php的空間後能建立自己的blog
6. java中為什麼private static fianl Logger logger這個常量不是大寫的LOGGER
注意,這個常量「logger」是「private 」的。
所以我覺得可能spring開發團隊有一個內部的規范,比如:
public(公開) 的常量,全部用大寫;private(類內部使用) 的常量,全部用小寫。
或者:
指向基本數據類型(及STRING)的,用大寫;指向對象的,用小寫。
以防止混淆。
7. log4cplus fileappender怎麼實現追加寫日誌
在官方網站下載最新log4cplus源碼,通過以下幾步安裝:
1、解壓源碼
tar xvzf log4cplus-x.x.x.tar.gz
2、進入解壓目錄安裝
cd log4cplus-x.x.x
2.1、配置編譯選項,可以configure跟--help參數查看所有配置選項幫助
./configure
2.2、編譯並安裝
make
make install
這里我採用預設安裝路徑:/usr/local,可以通過--prefix=/install/path指定安裝路徑。
二、log4cplus內容簡介與配置文件使用
log4cplus內容介紹
1. Logger對象
Logger對象具有層次結構,按名稱區分,如下代碼:
在log4cplus中logger的存儲機制中,所有logger都通過一個層次化的結構來組織的,有一個Root級別的logger,可以通過以下方法獲取:
Logger root = Logger::getRoot();
用戶定義的logger都有一個名字與之對應,比如:
Logger test = Logger::getInstance("test");
可以定義該logger的子logger:
Logger subTest = Logger::getInstance("test.subtest");
注意Root級別的logger只有通過getRoot方法獲取,Logger::getInstance("root")獲得的是它的子對象而已。有了這些具有父子關系的logger之後可分別設置其LogLevel,比如:
root.setLogLevel( ... );
Test.setLogLevel( ... );
subTest.setLogLevel( ... );
2. 優先順序
log4cplus優先順序有低到高:
NOT_SET_LOG_LEVEL :接受預設的LogLevel,如果有父logger則繼承它的LogLevel
ALL_LOG_LEVEL :開放所有log信息輸出
TRACE_LOG_LEVEL :開放trace信息輸出(即ALL_LOG_LEVEL)
DEBUG_LOG_LEVEL :開放debug信息輸出
INFO_LOG_LEVEL :開放info信息輸出
WARN_LOG_LEVEL :開放warning信息輸出
ERROR_LOG_LEVEL :開放error信息輸出
FATAL_LOG_LEVEL :開放fatal信息輸出
OFF_LOG_LEVEL :關閉所有log信息輸出
8. pomelo-logger有什麼作用,怎麼使用
pomelo-logger是對log4js的一個簡單封裝,主要為pomelo的日誌服務,具體怎麼使用可以參考pomelo源碼。
主要就兩點封裝:
1日誌按伺服器分開, 否則打在一個文件里找bug挺難
2前面自動加了輸出日誌的文件名
9. Logger log = Logger.getRootLogger();是什麼意思,作用是什麼
Log4j中log日誌的最頂層,相當於object
log記錄日誌可參考http://wenku..com/view/6a5c2e7b168884868762d642.html
10. java 解析 eml的源代碼
//從EML文件得到MimeMessage對象
MimeMessagemessage=newMimeMessage(session,newFileInputStream(emlFile));
(Messagemessage)throwsException{
returnMimeUtility.decodeText(message.getSubject());
}
(Messagemessage)throwsException{
StringemailSender=null;
Address[]addresses=message.getFrom();
if(addresses==null||addresses.length<1){
("該郵件沒有發件人");
}
//獲得發件人
InternetAddressaddress=(InternetAddress)addresses[0];
StringsenderName=address.getPersonal();
if(senderName!=null){
senderName=MimeUtility.decodeText(senderName);
emailSender=senderName+"<"+address.getAddress()+">";
}else{
senderName=address.getAddress();
}
returnemailSender;
}
(Messagemessage,Message.RecipientTyperecipientType)throwsException{
StringBuilderbuilder=newStringBuilder();
Address[]addresses=null;
if(recipientType==null){
addresses=message.getAllRecipients();
}else{
addresses=message.getRecipients(recipientType);
}
if(addresses==null||addresses.length<1){
("該郵件沒有收件人");
}
for(Addressaddress:addresses){
InternetAddressiAddress=(InternetAddress)address;
builder.append(iAddress.toUnicodeString()).append(",");
}
returnbuilder.deleteCharAt(builder.length()-1).toString();
}
(Messagemessage,Stringpattern)throwsException{
StringsendDateString=null;
if(pattern==null||"".equals(pattern.trim())){
pattern="yyyy年MM月dd日EHH:mm";
}
DatesendDate=message.getSentDate();
sendDateString=newSimpleDateFormat(pattern).format(sendDate);
returnsendDateString;
}
(Partpart)throwsException{
booleanflag=false;
if(part!=null){
if(part.isMimeType("multipart/*")){
MimeMultipartmp=(MimeMultipart)part.getContent();
for(inti=0;i<mp.getCount();i++){
BodyPartbodyPart=mp.getBodyPart(i);
Stringdisposition=bodyPart.getDisposition();
if(disposition!=null&&(Part.ATTACHMENT.equalsIgnoreCase(disposition)
||Part.INLINE.equalsIgnoreCase(disposition))){
flag=true;
}elseif(bodyPart.isMimeType("multipart/*")){
flag=containsAttachment(bodyPart);
}else{
StringcontentType=bodyPart.getContentType();
if(contentType.indexOf("application")!=-1){
flag=true;
}
if(contentType.indexOf("name")!=-1){
flag=true;
}
}
if(flag)
break;
}
}elseif(part.isMimeType("message/rfc822")){
flag=containsAttachment((Part)part.getContent());
}
}
returnflag;
}
publicstaticbooleanisSeen(Messagemessage)throwsException{
if(message==null){
thrownewMessagingException("Messageisempty");
}
returnmessage.getFlags().contains(Flags.Flag.SEEN);
}
(Messagemessage)throwsException{
if(message==null){
thrownewMessagingException("Messageisempty");
}
booleanreplaySign=false;
String[]headers=message.getHeader("Disposition-Notification-To");
if(headers!=null&&headers.length>0){
replaySign=true;
}
returnreplaySign;
}
(Messagemessage)throwsException{
if(message==null){
thrownewMessagingException("Messageisempty");
}
Stringpriority="普通";
String[]headers=message.getHeader("X-Priority");
if(headers!=null&&headers.length>0){
StringmailPriority=headers[0];
if(mailPriority.indexOf("1")!=-1||mailPriority.indexOf("High")!=-1){
priority="緊急";
}elseif(mailPriority.indexOf("5")!=-1||mailPriority.indexOf("Low")!=-1){
priority="低";
}else{
priority="普通";//3或者Normal;
}
}
returnpriority;
}
(Partpart,StringBuildercontent)throwsException{
if(part==null){
thrownewMessagingException("Messagecontentisempty");
}
=part.getContentType().indexOf("name")>0;
if(part.isMimeType("text/*")&&containsTextInAttachment){
content.append(part.getContent().toString());
}elseif(part.isMimeType("message/rfc822")){
getMailTextContent((Part)part.getContent(),content);
}elseif(part.isMimeType("multipart/*")){
Multipartmp=(Multipart)part.getContent();
for(inti=0;i<mp.getCount();i++){
BodyPartbodyPart=mp.getBodyPart(i);
getMailTextContent(bodyPart,content);
}
}elseif(part.isMimeType("image/*")){
//TODOpart.getInputStream()獲得輸入流然後輸出到指定的目錄
}else{
//TODO其它類型的contentType,未做處理,直接輸出
content.append(part.getContent().toString());
}
}
(Partpart,StringdestDir)throwsException{
if(part==null){
thrownewMessagingException("partisempty");
}
//復雜的郵件包含多個郵件體
if(part.isMimeType("multipart/*")){
Multipartmp=(Multipart)part.getContent();
//遍歷每一個郵件體
for(inti=0;i<mp.getCount();i++){
BodyPartbodyPart=mp.getBodyPart(i);
//bodyPart也可能有多個郵件體組成
Stringdisposition=bodyPart.getDisposition();
if(disposition==null&&(Part.ATTACHMENT.equalsIgnoreCase(disposition)
||Part.INLINE.equalsIgnoreCase(disposition))){
InputStreamin=bodyPart.getInputStream();
saveFile(in,destDir,decodeText(bodyPart.getFileName()));
}elseif(bodyPart.isMimeType("multipart/*")){
saveAttachment(bodyPart,destDir);
}else{
StringcontentType=bodyPart.getContentType();
if(contentType.indexOf("name")!=-1||contentType.indexOf("application")!=-1){
saveFile(bodyPart.getInputStream(),destDir,decodeText(bodyPart.getFileName()));
}
}
}
}elseif(part.isMimeType("message/rfc822")){
saveAttachment((Part)part.getContent(),destDir);
}
}
publicstaticvoidsaveFile(InputStreamin,StringdestDir,StringfileName)throwsException{
FileOutputStreamout=newFileOutputStream(newFile(destDir+fileName));
byte[]buffer=newbyte[1024];
intlength=0;
while((length=in.read(buffer))!=-1){
out.write(buffer,0,length);
}
out.close();
in.close();
}
publicstaticStringdecodeText(StringencodedText)throwsException{
if(encodedText==null||"".equals(encodedText.trim())){
return"";
}else{
returnMimeUtility.decodeText(encodedText);
}
}