JUL of java log

definition:

JUL, the full name of Java util logging, is a java Native logging framework. It does not need to introduce a third-party class library. Compared with other frameworks, JUL is easy to use, easy to learn, and can be used flexibly in small applications.

framework:

Application: our application.
LogManager: manages the Logger, which is a singleton Bean.
Logger: logger. Our application obtains the logger object and calls its API to publish log information. Logger is usually the entrance for the application to access the logging system.
Handler: log processor. Each Logger will hold multiple handlers. The Logger will hand over the logs to the handler for processing, and the handler is responsible for logging. Handler is an abstraction here. Its concrete implementation determines the location of log output, such as console, file, etc.
Formatter: log format converter, which is responsible for processing the log format. Determines the final form of the output log.
Level: each log information has an associated log level, which guides the importance of log information. We can use level on Logger and Handler. So that we can filter messages.
Filter: filter, which filters out some log information according to rules.
Overall process:

Initialize LogManager, load the logging.properties configuration file, and add Logger to LogManager.
Get the Logger from the singleton Bean LogManager.
Set the log Level level.
Handler handles log output.
The Formatter handles the log format.
Log level:
The JUL log level is recorded by the class java.util.logging.Level. There are seven log levels in total, from high to low:

Sever / / an error message. It is usually the message that causes the system to terminate.
WARNING / / a WARNING message. It generally records the problem of the program. This problem will not cause the system to terminate, but it deserves our attention.
INFO / / general information. Generally, some connection information and access information are recorded. (this is the default level of JUL)
CONFIG / / generally, log information such as loading configuration files is recorded.
FINE // Debug log information, which generally records the running status of the program. Information such as the transfer of process parameters executed.
FINER / / similar to FINE, except that the recorded granularity is higher.
FINEST / / similar to the above two, but the recorded granularity is higher.

There are two special levels:
OFF: can be used to turn OFF log information without outputting logs of any level.
ALL: log information at ALL levels

Logger.getLogger

LogManager manager = LogManager.getLogManager();
return manager.demandLogger(name, resourceBundleName, caller);

Creation of LogManager

Ignore some permission checks
LogManager namely java.util.logging.manager

static {
        manager = AccessController.doPrivileged(new PrivilegedAction<LogManager>() {
            @Override
            public LogManager run() {
                LogManager mgr = null;
                String cname = null;
                try {
                    cname = System.getProperty("java.util.logging.manager");
                    if (cname != null) {
                        try {
                            @SuppressWarnings("deprecation")
                            Object tmp = ClassLoader.getSystemClassLoader()
                                .loadClass(cname).newInstance();
                            mgr = (LogManager) tmp;
                        } catch (ClassNotFoundException ex) {
                            @SuppressWarnings("deprecation")
                            Object tmp = Thread.currentThread()
                                .getContextClassLoader().loadClass(cname).newInstance();
                            mgr = (LogManager) tmp;
                        }
                    }
                } catch (Exception ex) {
                    System.err.println("Could not load Logmanager \"" + cname + "\"");
                    ex.printStackTrace();
                }
                if (mgr == null) {
                    mgr = new LogManager();
                }
                return mgr;

            }
        });
    }

Initialization of LogManager

final void ensureLogManagerInitialized() {
        final LogManager owner = this;
        //Exit directly after initialization
        if (initializationDone || owner != manager) {
            return;
        }
		//lock
        configurationLock.lock();
        try {

            final boolean isRecursiveInitialization = (initializedCalled == true);
			
			//If it is called or has been executed, an error will be reported directly
            assert initializedCalled || !initializationDone
                    : "Initialization can't be done if initialized has not been called!";
                    
			//Return directly after execution
            if (isRecursiveInitialization || initializationDone) {
                return;
            }
			//The code that ignores permissions is to set RootLogger, whose name is an empty string and is the system log
            initializedCalled = true;
            try {
                AccessController.doPrivileged(new PrivilegedAction<Object>() {
                    @Override
                    public Object run() {
                        assert rootLogger == null;
                        assert initializedCalled && !initializationDone;

                        // create root logger before reading primordial
                        // configuration - to ensure that it will be added
                        // before the global logger, and not after.
                        final Logger root = owner.rootLogger = owner.new RootLogger();

                        // Read configuration.
                        owner.readPrimordialConfiguration();

                        // Create and retain Logger for the root of the namespace.
                        owner.addLogger(root);

                        // Initialize level if not yet initialized
                        if (!root.isLevelInitialized()) {
                            root.setLevel(defaultLevel);
                        }

                        // Adding the global Logger.
                        // Do not call Logger.getGlobal() here as this might trigger
                        // subtle inter-dependency issues.
                        @SuppressWarnings("deprecation")
                        final Logger global = Logger.global;

                        // Make sure the global logger will be registered in the
                        // global manager
                        owner.addLogger(global);
                        return null;
                    }
                });
            } finally {
            //initializationDone is set to true
                initializationDone = true;
            }
        } finally {
            configurationLock.unlock();
        }
    }

getLogger

Logger demandLogger(String name, String resourceBundleName, Module module) {
    //1. Get the log from the userContext. There is a map in the userContext. Weakhashmap < object, loggercontext > contextsmap
        Logger result = getLogger(name);
        if (result == null) {
            // There is no direct new one
            Logger newLogger = new Logger(name, resourceBundleName,
                                          module, this, false);
            do {
                //Join userContext
                if (addLogger(newLogger)) {
                    return newLogger;
                }
                result = getLogger(name);
            } while (result == null);
        }
        return result;
    }

log.info

public void log(Level level, String msg) {
    	//Inspection level
        if (!isLoggable(level)) {
            return;
        }
    	//LogRecord
        LogRecord lr = new LogRecord(level, msg);
        doLog(lr);
    }

//Some internationalization settings
private void doLog(LogRecord lr) {
        lr.setLoggerName(name);
        final LoggerBundle lb = getEffectiveLoggerBundle();
        final ResourceBundle  bundle = lb.userBundle;
        final String ebname = lb.resourceBundleName;
        if (ebname != null && bundle != null) {
            lr.setResourceBundleName(ebname);
            lr.setResourceBundle(bundle);
        }
        log(lr);
    }


doLog

public void log(LogRecord record) {
    //Insufficient level return
        if (!isLoggable(record.getLevel())) {
            return;
        }
    //Call the filter.isLoggable method
        Filter theFilter = config.filter;
        if (theFilter != null && !theFilter.isLoggable(record)) {
            return;
        }


		//
        Logger logger = this;
        while (logger != null) {
            final Handler[] loggerHandlers = isSystemLogger
                ? logger.accessCheckedHandlers()
                : logger.getHandlers();

            for (Handler handler : loggerHandlers) {
                //Execute the publish method of loggerHandlers
                handler.publish(record);
            }

            final boolean useParentHdls = isSystemLogger
                ? logger.config.useParentHandlers
                : logger.getUseParentHandlers();
			//Return directly without ParentHandler
            if (!useParentHdls) {
                break;
            }
			//Use ParentHandler and set logger to parent to continue printing logs. Here we can explain why some logs print several copies
            logger = isSystemLogger ? logger.parent : logger.getParent();
        }
    }

handler.publish(record);

handler.publish(record);
Take a brief look ConsoleHandler extends StreamHandler

    
    @Override
    public synchronized void publish(LogRecord record) {
        String msg;
        try {
            //Format component
            msg = getFormatter().format(record);
        } catch (Exception ex) {
            reportError(null, ex, ErrorManager.FORMAT_FAILURE);
            return;
        }
		//The write here is System.err, so the default log is red
        try {
            if (!doneHeader) {
                writer.write(getFormatter().getHead(this));
                doneHeader = true;
            }
            writer.write(msg);
        } catch (Exception ex) {
            // We don't want to throw an exception here, but we
            // report the exception to any registered ErrorManager.
            reportError(null, ex, ErrorManager.WRITE_FAILURE);
        }
    }
Formatter
 Take a brief look SimpleFormatter
    The core is to call String.format
@Override
    public String format(LogRecord record) {
        ZonedDateTime zdt = ZonedDateTime.ofInstant(
                record.getInstant(), ZoneId.systemDefault());
        String source;
        if (record.getSourceClassName() != null) {
            source = record.getSourceClassName();
            if (record.getSourceMethodName() != null) {
               source += " " + record.getSourceMethodName();
            }
        } else {
            source = record.getLoggerName();
        }
        String message = formatMessage(record);
        String throwable = "";
        if (record.getThrown() != null) {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            pw.println();
            record.getThrown().printStackTrace(pw);
            pw.close();
            throwable = sw.toString();
        }
        //System default format% 1 $TB% 1 $TD,% 1 $ty% 1 $TL:% 1 $Tm:% 1 $TS% 1 $TP% 2 $s% n% 4 $s:% 5 $s% 6 $s% n
        return String.format(format,
                             zdt,
                             source,
                             record.getLoggerName(),
                             record.getLevel().getLocalizedLevelName(),
                             message,
                             throwable);
    }

Extension point

1. Specify the configuration file or modify the default

2. Manually load the configuration file

LogManager logManager = LogManager.getLogManager();
logManager.readConfiguration(Own profile inputStreaqm);

3. Manually implement the following format and handler

public class MyConsoleHandler extends Handler {

    public MyConsoleHandler() {
        setFormatter(new MyFormatter());
    }

    @Override
    public void publish(LogRecord record) {
        if(record==null) return;
        String msg = getFormatter().format(record);
        if(record.getLevel().intValue()> Level.WARNING.intValue()){
            System.err.print(msg);
        }else{
            System.out.print(msg);
        }
    }
    
    @Override
    public void flush() {

    }

    @Override
    public void close() throws SecurityException {

    }
}
public class MyFormatter extends Formatter {

    String format = "%1$tF %1$tT.%1$tL %2$s%n%4$s: %5$s%6$s%n";
    @Override
    public String format(LogRecord record) {
        ZonedDateTime zdt = ZonedDateTime.ofInstant(
                record.getInstant(), ZoneId.systemDefault());
        String source;
        if (record.getSourceClassName() != null) {
            source = record.getSourceClassName();
            if (record.getSourceMethodName() != null) {
                source += " " + record.getSourceMethodName();
            }
        } else {
            source = record.getLoggerName();
        }
        String message = formatMessage(record);
        String throwable = "";
        if (record.getThrown() != null) {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            pw.println();
            record.getThrown().printStackTrace(pw);
            pw.close();
            throwable = sw.toString();
        }

        return String.format(format,
                zdt,
                source,
                record.getLoggerName(),
                record.getLevel().getLocalizedName(),
                message,
                throwable);
    }
}

Usage record

        Logger logger = Logger.getLogger("TestLog.class");
        //logger.addHandler(new MyConsoleHandler());
        //If user-defined is used, it can be considered that it is not applicable to the parent
        //logger.setUseParentHandlers(false);

        //2. Print log
        logger.info("hello jul");
        logger.log(Level.INFO,"jul level.info");
        logger.severe("Name: Li Si,Age:"+33);
        String name = "Zhang San";
        int age = 18;
        logger.log(Level.INFO,"full name:{0},Age:{1}",new Object[]{name,age});

After using custom

Conversion characterexplainExample
%sString type"mingrisoft"
%cCharacter type'm'
%bBoolean typetrue
%dInteger type (decimal)99
%xInteger type (HEX)FF
%oInteger type (octal)77
%fFloating point type99.99
%aHexadecimal floating point typeFF.35AE
%eIndex type9.38e+5
%gUniversal floating point type (shorter of f and e types)
%hHash code, Integer.toHexString(arg.hashCode())
%%Percentage type
%nNewline character
%txDate and time type (x represents different date and time converters)

Date formatting

Conversion characterexplainExample
cInclude all date and time informationSaturday October 27 14:21:20 CST 2007
F"Year Month Day" format2007-10-27
D"Month / day / year" format10/27/07
r"HH:MM:SS PM" format (12 hour system)02:25:51 PM
T"HH:MM:SS" format (24 hour system)14:28:16
R"HH:MM" format (24 hour system)14:28

Time formatting

Conversion characterexplainExample
H2-digit 24-hour system hours (less than 2 digits are preceded by 0)15
I2-digit 12 hour system (less than 2 digits are preceded by 0)03
K2-digit 24-hour hour system (0 is not added in front)15
L2-digit 12 hour system (0 is not added in front)3
M2-digit minutes (fill 0 in front of less than 2 digits)03
SSecond of 2 digits (less than 2 digits are preceded by 0)09
LMilliseconds of 3 digits (less than 3 digits are preceded by 0)015
NThe number of milliseconds of a 9-bit number (less than 9 bits are preceded by 0)562000000
pMorning or afternoon sign in lowercase lettersChinese: afternoon, English: pm
zOffset of RFC822 time zone relative to GMT+0800
ZTime zone abbreviation stringCST
SSeconds elapsed from 1970-1-00:00:00 to now1193468128
QNumber of milliseconds from 1970-1 00:00:00 to now1193468128984

%1 t b tb %1 tbtd, %1 t Y tY %1 tYtl:%1 t M : tM:%1 tM:tS %1 T p Tp %2 Tps%n%4 s : s: %5 s:s%6$s%n

String format = "%1$tF %1$tT.%1$tL %2$s%n%4$s: %5$s%6$s%n";

2021-11-29 16:34:25.177 com.git.log.TestLog testJUL
 information: hello jul

Standard Cprintf

Conversion charactermeaning
%AFloating point numbers, hexadecimal digits, and p-notation (C99)
%cOne character
%dSigned decimal integer
%eFloating point number, e-notation
%EFloating point number, E-notation
%fFloating point number, decimal notation
%gAutomatically select% f or% e according to different values
%GAutomatically select% f or% e according to different values
%iSigned decimal number (same as% d)
%oUnsigned octal integer
%pPointer
%scharacter string
%uUnsigned decimal integer
%xUnsigned hexadecimal integer using hexadecimal digit 0f
%XUnsigned hexadecimal integer using hexadecimal digit 0f
%%Print a percent sign

Symbolic function
──────────────────────────
%d decimal signed integer
%u decimal unsigned integer
%f floating point number
%s String
%c single character
%The value of the p pointer
%e floating point number in exponential form
%x. % x unsigned integer in hexadecimal
%0 is an unsigned integer in octal
%g automatically select the appropriate representation

\n line feed
\f screen clearing and page changing
\r enter
\t Tab
\xhh represents an ASCII code, represented by 16 characters,
Where hh is 1 to 2 hexadecimal numbers
━━━━━━━━━━━━━━━━━━━━━━━━━━

reference resources:

Detailed explanation of JUL (java util logging) of Java logging framework Quote some of these concepts

java string formatting

print formatting

Tags: Java

Posted on Mon, 29 Nov 2021 14:22:00 -0500 by LAEinc. Creations