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);
}
}