精华内容
下载资源
问答
  • Logger

    2016-11-09 15:42:04
    https://github.com/orhanobut/logger ...Logger Simple, pretty and powerful logger for android Logger provides : Thread informationClass informationMethod informationPretty-print for json con

    https://github.com/orhanobut/logger

    Logger

    Simple, pretty and powerful logger for android

    Logger provides :

    • Thread information
    • Class information
    • Method information
    • Pretty-print for json content
    • Pretty-print for new line "\n"
    • Clean output
    • Jump to source

    Download

    compile 'com.orhanobut:logger:1.15'

    Current Log system

    Log.d(TAG,"hello");

    Logger

    Logger.d("hello");
    Logger.d("hello %s %d", "world", 5);   // String.format

    Logger.d("hello");
    Logger.e("hello");
    Logger.w("hello");
    Logger.v("hello");
    Logger.wtf("hello");
    Logger.json(JSON_CONTENT);
    Logger.xml(XML_CONTENT);
    Logger.log(DEBUG, "tag", "message", throwable);

    String format arguments are supported

    Logger.d("hello %s", "world");

    Array, Map, Set and List are supported

    Logger.d(list);
    Logger.d(map);
    Logger.d(set);
    Logger.d(new String[]);

    Change TAG

    All logs

    Logger.init(YOUR_TAG);

    Log based

    Logger.t("mytag").d("hello");

    Settings (optional)

    Change the settings with init. This should be called only once. Best place would be in application class. All of them are optional. You can just use the default settings if you don't init Logger.

    Logger
      .init(YOUR_TAG)                 // default PRETTYLOGGER or use just init()
      .methodCount(3)                 // default 2
      .hideThreadInfo()               // default shown
      .logLevel(LogLevel.NONE)        // default LogLevel.FULL
      .methodOffset(2)                // default 0
      .logAdapter(new AndroidLogAdapter()); //default AndroidLogAdapter
    }
    

    Note: Use LogLevel.NONE for the release versions.

    Use another log util instead of android.util.log

    • Implement LogAdapter
    • set it with init
    .logAdapter(new CustomLogAdapter())

    More log samples

    Logger.d("hello");
    Logger.e(exception, "message");
    Logger.json(JSON_CONTENT);

    Method info

    Observe the caller methods in the order they are invoked and also thread information.

    void methodA(){
       methodB();
    }
    void methodA(){
       Logger.d("hello");
    }

    Both method information will be shown in the order of invocation.

    Change method count (Default: 2)

    All logs

    Logger.init().methodCount(1);

    Log based

    Logger.t(1).d("hello");

    Change method stack offset (Default: 0)

    To integrate logger with other libraries, you can set the offset in order to avoid that library's methods.

    Logger.init().methodOffset(5);

    Hide thread information

    Logger.init().methodCount(1).hideThreadInfo();

    Only show the message

    Logger.init().methodCount(0).hideThreadInfo();

    Pretty print json, Logger.json

    Format the json content in a pretty way

    Logger.json(YOUR_JSON_DATA);

    Log exceptions in a simple way

    Show the cause of the exception

    Logger.e(exception,"message");

    Notes

    • Use the filter for a better result

    • Make sure that the wrap option is disabled

    Timber Integration

    You can also use logger along with Timber.

    Timber.plant(new Timber.DebugTree() {
      @Override protected void log(int priority, String tag, String message, Throwable t) {
        Logger.log(priority, tag, message, t);
      }
    });

    展开全文
  • logger

    2013-11-04 16:46:56
    刚从一个坑里跳出来.. 需要用的一个计算平台...static Logger log = Logger.getLogger(xx.class.getName()); log.info 但是发现这个计算平台并不输出日志 经过调试发现,它只认java.util.logging.Logger

    刚从一个坑里跳出来..

    需要用的一个计算平台,

    于是 import org.apache.log4j.Logger;

    static Logger log = Logger.getLogger(xx.class.getName());

    log.info


    但是发现这个计算平台并不输出日志


    经过调试发现,它只认java.util.logging.Logger




    展开全文
  • 在使用 Log4Qt 时,你会发现有一系列的 logger - rootLogger()、logLogger()、qtLogger(),简直傻傻分不清楚!为什么会有这么多 logger?各...

    在使用 Log4Qt 时,你会发现有一系列的 logger - rootLogger()logLogger()qtLogger(),简直傻傻分不清楚!

    • 为什么会有这么多 logger?

    • 各 logger 之间有什么关系?

    • 它们均适用于哪种场景?

    参考文档对这部分有一些简要的说明,但若要彻底理解细节,就必须从源码着手,正所谓“源码面前,了无秘密!”

    logger真实身份nameobjectName作用
    rootLogger()logger(QString())rootroot根 logger,是其它 logger(包括:logLogger、qtLogger)的 parentLogger。
    logLogger()logger("Log4Qt")Log4QtLog4Qt用于记录 Log4Qt 的内部消息
    qtLogger()logger("Qt")QtQt用于记录由 qDebug()、qWarning()、qCritical() 和 qFatal() 所创建的消息

    1

    关系链

    Logger 类开始,查看相关源码:

    Logger *Logger::rootLogger()
    {
        return LogManager::rootLogger();
    }
    
    Logger *Logger::logger(const QString &name)
    {
        return LogManager::logger(name);
    }
    

    在内部,它们调用的是 LogManager 类的相关接口:

    Logger *LogManager::rootLogger()
    {
        return instance()->mLoggerRepository->rootLogger();
    }
    
    Logger *LogManager::logger(const QString &name)
    {
        return instance()->mLoggerRepository->logger(name);
    }
    
    inline Logger *LogManager::logLogger()
    {
        return logger(QStringLiteral("Log4Qt"));
    }
    
    inline Logger *LogManager::qtLogger()
    {
        return logger(QStringLiteral("Qt"));
    }
    

    而这些最终都是由 Hierarchy 类来决定:

    inline Logger *Hierarchy::rootLogger() const
    {
        return mRootLogger;
    }
    
    Logger *Hierarchy::logger(const QString &name)
    {
        QWriteLocker locker(&mObjectGuard);
    
        return createLogger(name);
    }
    

    由于 rootLogger() 返回的是 mRootLogger,根据 Hierarchy 的构造函数:

    Hierarchy::Hierarchy() :
        mObjectGuard(QReadWriteLock::Recursive),
        mThreshold(Level::NULL_INT),
        mRootLogger(logger(QString()))
    {
    }
    

    可以发现,mRootLogger 最终也是调用了 Hierarchy::logger(const QString &name),只不过传递的是一个空字符串而已。

    到这里,可以很直观地得到这样一个调用关系:

    • Logger::rootLogger() -> LogManager::rootLogger() -> Hierarchy::logger(QString())

    • LogManager::logLogger() -> LogManager::logger("Log4Qt") -> Hierarchy::logger("Log4Qt")

    • LogManager::qtLogger() -> LogManager::logger("Qt") -> Hierarchy::logger("Qt")

    2

    等价调用

    通过上述调用关系,最终定位 Hierarchy::logger(const QString &name),而它内部则调用了 Hierarchy::createLogger(const QString &orgName)

    Logger *Hierarchy::createLogger(const QString &orgName)
    {
        static const QLatin1String binaryIndicator = QLatin1String("@@binary@@");
        static const QLatin1String name_separator = QLatin1String("::");
    
        QString name(OptionConverter::classNameJavaToCpp(orgName));
        bool needBinaryLogger = orgName.contains(binaryIndicator);
    
        if (needBinaryLogger)
            name.remove(binaryIndicator);
    
        Logger *logger = mLoggers.value(name, nullptr);
        if (logger != nullptr)
            return logger;
    
        if (name.isEmpty())
        {
            logger = new Logger(this, Level::DEBUG_INT, QStringLiteral("root"), nullptr);
            mLoggers.insert(QString(), logger);
            return logger;
        }
        QString parent_name;
        int index = name.lastIndexOf(name_separator);
        if (index >= 0)
            parent_name = name.left(index);
    
        if (needBinaryLogger)
            logger = new BinaryLogger(this, Level::NULL_INT, name, createLogger(parent_name));
        else
            logger = new Logger(this, Level::NULL_INT, name, createLogger(parent_name));
        mLoggers.insert(name, logger);
        return logger;
    }
    

    根据源码可知,logger 的创建是由形参 name 的值来决定的:

    • 空字符串:用于创建 rootLogger,其 name 被设置为了“root”,而 mLoggers(QHash 类型)中对应的 key 为 QString()。

    • 非空字符串:用于创建其他 logger(包括:logLogger、qtLogger),并将其 parentLogger 设置为 rootLogger(注意构造时的递归调用 createLogger(parent_name))。

    所以,最终得出以下结论:

    • rootLogger():等价于 logger(QString()),其 name() 和 objectName() 都是“root”

    • logLogger():等价于 logger(“Log4Qt”),其 name() 和 objectName() 都是“Log4Qt”

    • qtLogger():等价于logger(“Qt”),其 name() 和 objectName() 都是“Qt”

    rootLogger 是根 logger,而其他 logger(包括:logLoggerqtLogger)的 parentLoggerrootLogger

    3

    基本验证

    实践出真知,来验证一下!对各个 logger 分类,并进行输出:

    // main.cpp
    #include <QCoreApplication>
    #include <qDebug>
    #include <log4qt/basicconfigurator.h>
    #include <log4qt/logger.h>
    #include <log4qt/logmanager.h>
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        // 一个简单的基础配置
        Log4Qt::BasicConfigurator::configure();
    
        // 获取 rootLogger
        Log4Qt::Logger *rootLogger = Log4Qt::Logger::rootLogger();
        Log4Qt::Logger *rootLogger2 = Log4Qt::LogManager::rootLogger();
        Log4Qt::Logger *rootLogger3 = Log4Qt::Logger::logger("");
        Log4Qt::Logger *rootLogger4 = Log4Qt::LogManager::logger("");
        Log4Qt::Logger *rootParentLogger = rootLogger->parentLogger();
    
        qDebug() << "********** rootLogger **********";
        qDebug() << rootLogger << rootLogger2 << rootLogger3 << rootLogger4;
        qDebug() << "name:" << rootLogger->name() << "object name:" << rootLogger->objectName();
        qDebug() << "parent logger:" << rootParentLogger;
    
        // 获取 logLogger
        Log4Qt::Logger *logLogger = Log4Qt::LogManager::logLogger();
        Log4Qt::Logger *logLogger2 = Log4Qt::Logger::logger("Log4Qt");
        Log4Qt::Logger *logLogger3 = Log4Qt::LogManager::logger("Log4Qt");
        Log4Qt::Logger *logParentLogger = logLogger->parentLogger();
    
        qDebug() << "********** logLogger **********";
        qDebug() << logLogger << logLogger2 << logLogger3;
        qDebug() << "name:" << logLogger->name() << "object name:" << logLogger->objectName();
        qDebug() << "parent logger:" << logParentLogger;
    
        // 获取 qtLogger
        Log4Qt::Logger *qtLogger = Log4Qt::LogManager::qtLogger();
        Log4Qt::Logger *qtLogger2 = Log4Qt::Logger::logger("Qt");
        Log4Qt::Logger *qtLogger3 = Log4Qt::LogManager::logger("Qt");
        Log4Qt::Logger *qtParentLogger = qtLogger->parentLogger();
    
        qDebug() << "********** qtLogger **********";
        qDebug() << qtLogger << qtLogger2 << qtLogger3;
        qDebug() << "name:" << qtLogger->name() << "object name:" << qtLogger->objectName();
        qDebug() << "parent logger:" << qtParentLogger;
    
        return a.exec();
    }
    

    显然,和推断一样。通过各种方式获取到的 logger 其实都是等价的,而且一直存在一个 rootLogger,它是所有 logger 的 parentLogger

    4

    适用场景

    rootLogger 是根,而 logLoggerqtLogger 是基于特定的需求而诞生的,下面重点讲解 qtLogger

    logLogger

    logLogger:用于记录内部消息的 logger

    也就是说,Log4Qt 除了对外提供日志之外,它内部也用了自己的日志(即:logLogger)来记录消息。关于包内记录,官方有一个简单说明(http://log4qt.sourceforge.net/html/loglog.html)。

    既然是内部操作,这部分就不做过多赘述了,了解即可。

    qtLogger

    qtLogger:用于记录由 qDebug()、qWarning()、qCritical() 和 qFatal() 所创建的消息。

    默认情况下,这些消息处理是禁用的。可以通过调用 setHandleQtMessages(true) 来启用。一旦启用,所有的消息都将使用 qtLogger() 来记录。

    下面,将日志消息输出到文件中。除了使用 rootLogger 之外,我们额外再使用 qDebug() 输出一条消息:

    // main.cpp
    #include <QCoreApplication>
    #include <QtDebug>
    #include <log4qt/logger.h>
    #include <log4qt/logmanager.h>
    #include <log4qt/ttcclayout.h>
    #include <log4qt/fileappender.h>
    #include <log4qt/loggerrepository.h>
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        // 创建一个 TTCCLayout(输出时间、线程、Logger 以及消息内容)
        Log4Qt::Logger *logger = Log4Qt::Logger::rootLogger();
        Log4Qt::TTCCLayout *layout = new Log4Qt::TTCCLayout();
        layout->setName("My Layout");
        layout->activateOptions();
    
        // 创建一个 FileAppender(将日志内容输出到文件中)
        // true 以 Append 方式打开文件,false 以 Truncate 方式打开文件。
        QString file = QCoreApplication::applicationDirPath() + "/test.log";
        Log4Qt::FileAppender *appender = new Log4Qt::FileAppender(layout, file, true);
        appender->setName("My Appender");
        appender->activateOptions();
        // 在 rootLogger 上添加 fileAppender
        logger->addAppender(appender);
    
        // 设置级别为 DEBUG
        logger->setLevel(Log4Qt::Level::DEBUG_INT);
    
        // 允许处理 Qt 消息
        Log4Qt::LogManager::setHandleQtMessages(true);
    
        // 输出信息
        logger->debug("This is a debug message.");
        qDebug() << "This is a debug message too.";
    
        // 关闭 rootLogger
        logger->removeAllAppenders();
        logger->loggerRepository()->shutdown();
    
        return a.exec();
    }
    

    运行程序,会生成一个名为 test.log 的日志文件。打开你会发现,使用 qDebug() 生成的消息也被输出到文件里了。

    ·················· END ··················

    关注后回复「1024」,获取海量学习资源

    展开全文
  • Logger打印日志

    万次阅读 多人点赞 2018-03-22 14:14:36
    1. 一个最基本的例子使用Logging框架写Log基本上就三个步骤引入loggerg类和logger工厂类声明logger记录日志下面看一个例子//1. 引入slf4j接口的Logger和LoggerFactoryimport org.slf4j.Logger;import org.slf4j....

    1. 一个最基本的例子

    使用Logging框架写Log基本上就三个步骤
    1. 引入loggerg类和logger工厂类
    2. 声明logger
    3. 记录日志
    下面看一个例子
    //1. 引入slf4j接口的Logger和LoggerFactory
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;

    public class UserService {
      //2. 声明一个Logger,这个是static的方式,我比较习惯这么写。
      private final static Logger logger = LoggerFactory.getLogger(UserService.class);

      public boolean verifyLoginInfo(String userName, String password) {
        //3. log it,输出的log信息将会是:"Start to verify User [Justfly]
        logger.info("Start to verify User [{}]", userName);
        return false;
      }
    }
    其中的第二步,关于Logger对象是否要声明为静态的业界有过一些讨论,Logback的作者最早是推荐使用对象变量的方式来声明,后来他自己也改变了想法。想详细了解的同学可以去看一下: http://slf4j.org/faq.html#declared_static
    两种方式的优劣概述如下:
    • 静态Logger对象相对来说更符合语义,节省CPU,节省内存,不支持注入
    • 对象变量Logger支持注入,对于一个JVM中运行的多个引用了同一个类库的应用程序,可以在不同的应用程序中对同个类的Logger进行不同的配置。比如Tomcat上部署了俩个应用,他们都引用了同一个lib。

    2. Logger接口的方法

    Logger接口分为俩个版本,一个带Marker版本和一个没带Marker版本的。带Marker版本的我没用过就不介绍了。没带Marker版本的接口方法可以分为以下两组:

    2.1 判断Logger级别是否开启的方法

    • public boolean isTraceEnabled();
    • public boolean isDebugEnabled();
    • public boolean isInfoEnabled();
    • public boolean isWarnEnabled();
    • public boolean isErrorEnabled();
    这组方法的作用主要是避免没必要的log信息对象的产生,尤其是对于不支持参数化信息的Log框架(Log4j 1, commons-logging)。如下面的例子所示,如果没有加debug级别判断,在Debug级别被禁用的环境(生产环境)中,第二行的代码将没有必要的产生多个String对象。
    1 if(logger.isDebugEnabled()){
    2   logger.debug("["+resultCount+"]/["+totalCount+"] of users are returned");
    3 }
    如果使用了参数信息的方法,在如下代码中,即使没有添加debug级别(第一行)判断,在生产环境中,第二行代码只会生成一个String对象。
    1 if(logger.isDebugEnabled()){
    2   logger.debug("[{}]/[{}] of users in group are returned", resultCount,totalCount);
    3 }
    因此,为了代码的可读性,我一般情况下使用参数化信息的方法,并且不做Logger级别是否开启的判断,换句话说,这组方法我一般情况下不会用。

    2.2 log信息的方法

    2.2.1 方法说明

    Logger中有五个级别:track,debug,info,warn,error。对于每个级别,分别有五个log方法,以info级别为例子:
    • public void info(String msg);
    无参数的log方法,例子:
    logger.info("开始初始化配置文件读取模块");
    输出
    2014-08-11 23:36:17,783 [main] INFO  c.j.training.logging.service.UserService - 开始初始化配置文件读取模块
    • public void info(String format, Object arg);
    支持一个参数的参数化log方法,例子:
    logger.info("开始导入配置文件[{}]","/somePath/config.properties");
    输出
    2014-08-11 23:36:17,787 [main] INFO  c.j.training.logging.service.UserService - 开始导入配置文件[/somePath/config.properties]
    • public void info(String format, Object arg1, Object arg2);
    支持俩个参数的参数化log方法,例子:
    logger.info("开始从配置文件[{}]中读取配置项[{}]的值","/somePath/config.properties","maxSize");
    输出
    2014-08-11 23:36:17,789 [main] INFO  c.j.training.logging.service.UserService - 开始从配置文件[/somePath/config.properties]中读取配置项[maxSize]的值
    • public void info(String format, Object... arguments);
    支持多个参数的参数化log方法,对比上面的俩个方法来说,会多增加构造一个Object[]的开销。例子:
    logger.info("在配置文件[{}]中读取到配置项[{}]的值为[{}]","/somePath/config.properties","maxSize", 5);
    输出
    2014-08-11 23:36:17,789 [main] INFO  c.j.training.logging.service.UserService - 在配置文件[/somePath/config.properties]中读取到配置项[maxSize]的值为[5]
    • public void info(String msg, Throwable t);
    无参数化记录log异常信息
    logger.info("读取配置文件时出现异常",new FileNotFoundException("File not exists"));
    输出
    2014-08-11 23:36:17,794 [main] INFO  c.j.training.logging.service.UserService - 读取配置文件时出现异常
    java.io.FileNotFoundException: File not exists
      at cn.justfly.training.logging.service.UserServiceTest.testLogResult(UserServiceTest.java:31) ~[test-classes/:na]
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_45]
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_45]
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_45]
      at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_45]

    参数化说明
    在上面的例子中,我们可以看到log信息中的{}将会按照顺序被后面的参数所替换。这样带来了一个好处:如果在运行时不需要打印该Log,则不会重复产生String对象。

    2.2.2 如何Log Exception

    2.2.2.1 把Exception作为Log方法的最后一个参数

    上面讲的参数化Log方法的中的最后一个参数如果是一个Exception类型的对象的时候,logback将会打印该Exception的StackTrace信息。看下面的这个例子:
    logger.info("读取配置文件[{}]时出错。","/somePath/config.properties",new FileNotFoundException("File not exists"));
    上面的代码在执行的时候会输出如下内容:
    2014-08-12 00:22:49,167 [main] INFO  c.j.training.logging.service.UserService - 读取配置文件[/somePath/config.properties]时出错。
    java.io.FileNotFoundException: File not exists
      at cn.justfly.training.logging.service.UserServiceTest.testLogResult(UserServiceTest.java:30) [test-classes/:na]
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_45]
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_45]
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_45]
      at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_45]
      at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) [junit.jar:na]
      at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) [junit.jar:na]
      at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) [junit.jar:na]
      at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) [junit.jar:na]
      at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) [junit.jar:na]

    2.2.2.2 Exception不会替换log信息中的参数

    另外需要注意的时,该Exception不会作为参数化内容中的参数进行替换。比如下面的代码:
    logger.info("读取配置文件[{}]时出错。异常为[{}]","/somePath/config.properties",new FileNotFoundException("File not exists"));
    其执行结果如下所示,第二个参数没有进行替换
    2014-08-12 00:25:37,994 [main] INFO  c.j.training.logging.service.UserService - 读取配置文件[/somePath/config.properties]时出错。异常为[{}]
    java.io.FileNotFoundException: File not exists
      at cn.justfly.training.logging.service.UserServiceTest.testLogResult(UserServiceTest.java:30) [test-classes/:na]
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_45]
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_45]
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_45]
      at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_45]

    2.2.2.3 参数化Exception

    如果你就是不想要打印StackTrace,就是要将其参数化的话怎么弄?一般情况下不建议这么做,因为你把Exception中有用的东西吃掉了。但是如果你非要这么做的话,也不是不可以,有俩个方法:
    • 把Exception的toString()方法的返回值作为参数
    例子如下所示,注意我们不用ex.getMessage()而是用toString()方法,原因在于不是每个Message实例都有Message,但是默认的toString()方法里面包括有Message
    logger.info("读取配置文件[{}]时出错。异常为[{}]","/somePath/config.properties",new FileNotFoundException("File not exists").toString());
    执行结果为:
    2014-08-12 00:29:24,018 [main] INFO  c.j.training.logging.service.UserService - 读取配置文件[/somePath/config.properties]时出错。异常为[java.io.FileNotFoundException: File not exists]
    • 不要让Exception成为最后一个参数
    例子如下:
    logger.info("读取参数[{}]的时候出错:[{}], 请检查你的配置文件[{}]","maxSize",new FileNotFoundException("File not exists"),"/somePath/config.properties");
    执行结果为:
    2014-08-12 00:35:11,125 [main] INFO  c.j.training.logging.service.UserService - 读取参数[maxSize]的时候出错:[java.io.FileNotFoundException: File not exists], 请检查你的配置文件[/somePath/config.properties]

    3. Log什么

    前面讲了怎么使用Loggger的方法log日志,下面继续讲讲在什么地方需要记录什么级别的log,以及需要记录什么内容。

    3.1 如何使用不同级别的Log

    SLF4J把Log分成了Error,Warn,Info,Debug和Trace五个级别。我们可以把这俩个级别分成两组

    3.1.1 用户级别

    Error、Warn和Info这三个级别的Log会出现在生产环境上,他们必须是运维人员能阅读明白的

    3.1.1.1 Error

    • 影响到程序正常运行、当前请求正常运行的异常情况,例如:
      • 打开配置文件失败
      • 第三方应用网络连接异常
      • SQLException
    • 不应该出现的情况,例如:
      • 某个Service方法返回的List里面应该有元素的时候缺获得一个空List
      • 做字符转换的时候居然报错说没有GBK字符集

    3.1.1.2 Warn

    • 不应该出现但是不影响程序、当前请求正常运行的异常情况,例如:
      • 有容错机制的时候出现的错误情况
      • 找不到配置文件,但是系统能自动创建配置文件
    • 即将接近临界值的时候,例如:
      • 缓存池占用达到警告线

    3.1.1.3 Info

    • 系统运行信息
      • Service方法的出入口
      • 主要逻辑中的分步骤
    • 外部接口部分
      • 客户端请求参数和返回给客户端的结果
      • 调用第三方时的调用参数和调用结果

    3.1.2 开发级别

    Debug和Trace这俩个级别主要是在开发期间使用或者当系统出现问题后开发人员介入调试的时候用的,需要有助于提供详细的信息。

    3.1.2.1 Debug

    • 用于记录程序变量,例如:
      • 多次迭代中的变量
    • 用于替代代码中的注释
    如果你习惯在代码实现中写:
    //1. 获取用户基本薪资

    //2. 获取用户休假情况

    //3. 计算用户应得薪资
    不妨这么写试试
    logger.debug("开始获取员工[{}] [{}]年基本薪资",employee,year);

    logger.debug("获取员工[{}] [{}]年的基本薪资为[{}]",employee,year,basicSalary);
    logger.debug("开始获取员工[{}] [{}]年[{}]月休假情况",employee,year,month);

    logger.debug("员工[{}][{}]年[{}]月年假/病假/事假为[{}]/[{}]/[{}]",employee,year,month,annualLeaveDays,sickLeaveDays,noPayLeaveDays);
    logger.debug("开始计算员工[{}][{}]年[{}]月应得薪资",employee,year,month);

    logger.debug("员工[{}] [{}]年[{}]月应得薪资为[{}]",employee,year,month,actualSalary);

    3.1.2.2 Trace

    主要用于记录系统运行中的完整信息,比如完整的HTTP Request和Http Response

    3.2 Log中的要点

    3.2.1 Log上下文

    在Log中必须尽量带入上下文的信息,对比以下俩个Log信息,后者比前者更有作用
    • "开始导入配置文件"
    • "开始导入配置文件[/etc/myService/config.properties]"

    3.2.2 考虑Log的读者

    对于用户级别的Log,它的读者可能是使用了你的框架的其他开发者,可能是运维人员,可能是普通用户。你需要尽量以他们可以理解的语言来组织Log信息,如果你的Log能对他们的使用提供有用的帮助就更好了。
    下面的两条Log中,前者对于非代码维护人员的帮助不大,后者更容易理解。
    • "开始执行getUserInfo 方法,用户名[jimmy]"
    • "开始获取用户信息,用户名[jimmy]"
    下面的这个Log对于框架的使用者提供了极大的帮助
    • "无法解析参数[12 03, 2013],birthDay参数需要符合格式[yyyy-MM-dd]"

    3.2.3 Log中的变量用[]与普通文本区分开来

    把变量和普通文本隔离有这么几个作用
    • 在你阅读Log的时候容易捕捉到有用的信息
    • 在使用工具分析Log的时候可以更方便抓取
    • 在一些情况下不容易混淆
    对比以下下面的两条Log,前者发生了混淆:
    • "获取用户lj12月份发邮件记录数"
    • "获取用户[lj1][2]月份发邮件记录数"

    3.2.4 Error或者Warn级别中碰到Exception的情况尽量log 完整的异常信息

    Error和Warn级别是比较严重的情况,意味着系统出错或者危险,我们需要更多的信息来帮助分析原因,这个时候越多的信息越有帮助。这个时候最好的做法是Log以下全部内容:
    • 你是在做什么事情的时候出错了
    • 你是在用什么数据做这个事情的时候出错了
    • 出错的信息是什么
    对比下面三个Log语句,第一个提供了详尽的信息,第二个只提供了部分信息,Exception的Message不一定包含有用的信息,第三个只告诉你出错了,其他的你一无所知。
    • log.error("获取用户[{}]的用户信息时出错",userName,ex);
    • log.error("获取用户[{}]的用户信息时报错,错误信息:[{}]",userName,ex.getMessage());
    • log.error("获取用户信息时出错");

    3.2.5 对于Exception,要每次都Log StackTrace吗?

    在一些Exception处理机制中,我们会每层或者每个Service对应一个RuntimeException类,并把他们抛出去,留给最外层的异常处理层处理。典型代码如下:
    try{
      
    }catch(Exception ex){
      String errorMessage=String.format("Error while reading information of user [%s]",userName);
      logger.error(errorMessage,ex);
      throw new UserServiceException(errorMessage,ex);
    }
    这个时候问题来了,在最底层出错的地方Log了异常的StackTrace,在你把这个异常外上层抛的过程中,在最外层的异常处理层的时候,还会再Log一次异常的StackTrace,这样子你的Log中会有大篇的重复信息。
    我碰到这种情况一般是这么处理的:Log之!原因有以下这几个方面:
    • 这个信息很重要,我不确认再往上的异常处理层中是否会正常的把它的StackTrace打印出来。
    • 如果这个异常信息在往上传递的过程中被多次包装,到了最外层打印StackTrace的时候最底层的真正有用的出错原因有可能不会被打印出来。
    • 如果有人改变了LogbackException打印的配置,使得不能完全打印的时候,这个信息可能就丢了。
    • 就算重复了又怎么样?都Error了都Warning了还省那么一点空间吗?
    展开全文
  • 2.logger.debug < logger.info < logger.warn < logger.error < logger.fatal 设置成高等级的级别,低等级的就展示不了,需要调整日志级别 例如 设置成info级别,那么所有用debug的日志就输出不了,如果用sy...
  • logger log4j.Logger
  • 如果RootLogger的level是error,而Logger的level是debug且additivity是true,那么当Logger记录debug日志的时候,RootLogger也会记录debug日志,也就是说Logger的level把RootLogger里的level也覆盖了。 Case2: 如上...
  • logger.debug,logger.info,logger.warn,logger.error,logger.fatal的区别 标签: log4j 2012-03-19 10:24 10210人阅读 评论(0) 收藏 举报  分类: 笔记(80)  版权声明:本文为博主...
  • nodejs logger

    千次阅读 2016-11-14 10:49:18
    转自:... logger.debug,logger.info,logger.warn,logger.error,logger.fatal的区别 logger.debug,logger.info,logger.warn,logger.error,logger.fatal的作用
  • logger使用

    2017-10-13 16:46:29
    添加build.gradle依赖 compile 'com.orhanobut:logger:2.1.1' ...Logger.addLogAdapter(new AndroidLogAdapter()); 3 一般使用 Logger.d("debug");Logger.e("error");Logger.w("warning"); 打印jso
  • Logger文件

    2018-09-29 18:38:44
    #coding=utf-8 #!/usr/bin/python ...# 创建一个logger def getLogger(name):  logger = logging.getLogger(name)  logger.setLevel(logging.DEBUG)  # 创建一个handler,用于写入日志文件  fh = logging.F...
  • Logger创建

    2017-12-20 15:51:46
    private Logger logger = org.slf4j.LoggerFactory.getLogger(MobileController.class);
  • Logger日志

    2017-04-10 22:31:13
    1、导入jar包 <groupId>log4j <artifactId>log4j <version>1.2.17 </dependency>2、main方法private static Logger logger=Logger.getLogger(Log
  • Logger入门用法

    千次阅读 2019-05-30 16:19:50
    使用Logger的步骤 1.引入LoggerLogger工厂类 2.声明logger 3.记录日志 二.简单示例 //1. 引入slf4j接口的Logger和LoggerFactory import org.slf4j.Logger; import org.slf4j.LoggerFactory; public ...
  • com.orhanobut.logger.Logger

    2018-06-21 22:56:10
    package com.orhanobut.logger; /** * But more pretty, simple and powerful ...public final class Logger { public static final int VERBOSE = 2; public static final int DEBUG = 3; public static ...
  • muduo之Logger

    千次阅读 2019-10-29 20:38:56
    Logger用来记录和分析日志。 Logging.h // Use of this source code is governed by a BSD-style license // that can be found in the License file. // // Author: Shuo Chen (chenshuo at chenshuo dot com) ...
  • 因为有多个同名的Logger类,在测试的时候没注意就直接选了第一个,发现不能用,以为是JAR包的问题,重新导一遍也不能,配置文件检查过也不行,最后发现是类用错了。 要打印日志用的是log4j包里的Logger类...
  • tomcat控制台乱码 logger.info logger.error乱码解决tomcat控制台乱码 logger.info logger.error乱码解决logging.propertiescatalina.batlog4j.properties tomcat控制台乱码 logger.info logger.error乱码解决 ...
  • LoggerLogger.getLogger(CLass)

    万次阅读 2019-06-24 13:38:16
    之前一直在使用System.out.println()来调试.但是用这种方式开发项目部署到生产环境,会因为众多的控制台输出降低应用的性能... 在项目中使用Log4J并不是一件困难的事情,简单粗暴的方式就是在每个类A中声明一个Logger...
  • Logger级别

    2016-11-08 16:11:17
    日志记录器(Logger)是日志处理的核心组件。log4j具有5种正常级别(Level)。日志记录器(Logger)的可用级别Level (不包括自定义级别 Level), 以下内容就是摘自log4j API static Level DEBUG DEBUG Level指出细粒度...
  • logger的jar包

    2018-04-02 17:24:44
    logger,log日志清晰,支持保存到SD卡中继承方便。。。。。
  • Logger的使用

    万次阅读 2016-09-26 15:08:07
    引入包import org.apache.log4j.Logger; protected static Logger LOG=Logger.getLogger(myclass.class); 若是去掉static,那每个类对象就返回一个Logger类,增加了开销 getLogger(" ")中的字符串写什么...
  • Logger 基本用法

    万次阅读 2018-04-21 10:46:05
    Logger 基本用法 简介 Simple, pretty and powerful logger for android 为Android提供的,简单、强大而且格式美观的工具 本质就是封装系统提供的Log类,加上一些分割线易于查找不同的Log;logcat中显示的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 69,737
精华内容 27,894
关键字:

logger